Index: qemu/exec.c =================================================================== --- qemu.orig/exec.c 2007-06-03 20:36:07.000000000 -0400 +++ qemu/exec.c 2007-06-03 20:36:27.000000000 -0400 @@ -1846,6 +1846,29 @@ spin_unlock(&tb_lock); } +int page_check_range(target_ulong start, target_ulong len, int flags) +{ + PageDesc *p; + target_ulong end; + target_ulong addr; + + end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */ + start = start & TARGET_PAGE_MASK; + + if( end < start ) return EFAULT; /* we've wrapped around */ + for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { + p = page_find(addr >> TARGET_PAGE_BITS); + if( !p ) return EFAULT; + if( !(p->flags & PAGE_VALID) ) return EFAULT; + + if (!(p->flags & PAGE_READ) && + (flags & PAGE_READ) ) return EFAULT; + if (!(p->flags & PAGE_WRITE) && + (flags & PAGE_WRITE) ) return EFAULT; + } + return 0; +} + /* called from signal handler: invalidate the code and unprotect the page. Return TRUE if the fault was succesfully handled. */ int page_unprotect(target_ulong address, unsigned long pc, void *puc) Index: qemu/cpu-all.h =================================================================== --- qemu.orig/cpu-all.h 2007-06-03 20:36:07.000000000 -0400 +++ qemu/cpu-all.h 2007-06-03 20:36:27.000000000 -0400 @@ -691,6 +691,7 @@ int page_get_flags(target_ulong address); void page_set_flags(target_ulong start, target_ulong end, int flags); void page_unprotect_range(target_ulong data, target_ulong data_size); +int page_check_range(target_ulong start, target_ulong len, int flags); #define SINGLE_CPU_DEFINES #ifdef SINGLE_CPU_DEFINES Index: qemu/linux-user/syscall.c =================================================================== --- qemu.orig/linux-user/syscall.c 2007-06-03 20:36:07.000000000 -0400 +++ qemu/linux-user/syscall.c 2007-06-03 20:37:36.000000000 -0400 @@ -402,12 +402,13 @@ #endif } -static inline void host_to_target_rusage(target_ulong target_addr, +static inline long host_to_target_rusage(target_ulong target_addr, const struct rusage *rusage) { + long ret = 0; struct target_rusage *target_rusage; - lock_user_struct(target_rusage, target_addr, 0); + if( (ret=lock_and_check_user_struct(&target_rusage,target_addr,sizeof(*target_rusage),0,PAGE_WRITE)) != 0 ) return -ret; target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec); target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec); target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec); @@ -429,23 +430,25 @@ unlock_user_struct(target_rusage, target_addr, 1); } -static inline void target_to_host_timeval(struct timeval *tv, +static inline long target_to_host_timeval(struct timeval *tv, target_ulong target_addr) { + long ret = 0; struct target_timeval *target_tv; - lock_user_struct(target_tv, target_addr, 1); + if( (ret=lock_and_check_user_struct(&target_tv,target_addr,sizeof(*target_tv),1,PAGE_READ)) != 0 ) return -ret; tv->tv_sec = tswapl(target_tv->tv_sec); tv->tv_usec = tswapl(target_tv->tv_usec); unlock_user_struct(target_tv, target_addr, 0); } -static inline void host_to_target_timeval(target_ulong target_addr, +static inline long host_to_target_timeval(target_ulong target_addr, const struct timeval *tv) { + long ret = 0; struct target_timeval *target_tv; - lock_user_struct(target_tv, target_addr, 0); + if( (ret=lock_and_check_user_struct(&target_tv,target_addr,sizeof(*target_tv),0,PAGE_WRITE)) != 0 ) return -ret; target_tv->tv_sec = tswapl(tv->tv_sec); target_tv->tv_usec = tswapl(tv->tv_usec); unlock_user_struct(target_tv, target_addr, 1); @@ -464,21 +467,21 @@ int ok; if (rfd_p) { - target_rfds = lock_user(rfd_p, sizeof(target_long) * n, 1); + if( (ret=lock_and_check_user_struct(&target_rfds,rfd_p,sizeof(target_long)*n,1,PAGE_READ)) != 0 ) return -ret; rfds_ptr = target_to_host_fds(&rfds, target_rfds, n); } else { target_rfds = NULL; rfds_ptr = NULL; } if (wfd_p) { - target_wfds = lock_user(wfd_p, sizeof(target_long) * n, 1); + if( (ret=lock_and_check_user_struct(&target_wfds,wfd_p,sizeof(target_long)*n,1,PAGE_READ)) != 0 ) return -ret; wfds_ptr = target_to_host_fds(&wfds, target_wfds, n); } else { target_wfds = NULL; wfds_ptr = NULL; } if (efd_p) { - target_efds = lock_user(efd_p, sizeof(target_long) * n, 1); + if( (ret=lock_and_check_user_struct(&target_efds,efd_p,sizeof(target_long)*n,1,PAGE_READ)) != 0 ) return -ret; efds_ptr = target_to_host_fds(&efds, target_efds, n); } else { target_efds = NULL; @@ -486,7 +489,7 @@ } if (target_tv) { - target_to_host_timeval(&tv, target_tv); + if( (ret=target_to_host_timeval(&tv, target_tv)) != 0 ) return ret; tv_ptr = &tv; } else { tv_ptr = NULL; @@ -500,7 +503,7 @@ host_to_target_fds(target_efds, efds_ptr, n); if (target_tv) { - host_to_target_timeval(target_tv, &tv); + if( (ret=host_to_target_timeval(target_tv, &tv)) != 0 ) return ret; } } if (target_rfds) @@ -513,28 +516,34 @@ return ret; } -static inline void target_to_host_sockaddr(struct sockaddr *addr, +static inline long target_to_host_sockaddr(struct sockaddr *addr, target_ulong target_addr, - socklen_t len) + socklen_t len, + int pg_access) { + long ret = 0; struct target_sockaddr *target_saddr; - target_saddr = lock_user(target_addr, len, 1); + if( (ret=lock_and_check_user_struct(&target_saddr,target_addr,len,1,pg_access)) != 0 ) return -ret; memcpy(addr, target_saddr, len); addr->sa_family = tswap16(target_saddr->sa_family); unlock_user(target_saddr, target_addr, 0); + return ret; } -static inline void host_to_target_sockaddr(target_ulong target_addr, +static inline long host_to_target_sockaddr(target_ulong target_addr, struct sockaddr *addr, - socklen_t len) + socklen_t len, + int pg_access) { + long ret = 0; struct target_sockaddr *target_saddr; - target_saddr = lock_user(target_addr, len, 0); + if( (ret=lock_and_check_user_struct(&target_saddr,target_addr,len,1,pg_access)) != 0 ) return -ret; memcpy(target_saddr, addr, len); target_saddr->sa_family = tswap16(addr->sa_family); unlock_user(target_saddr, target_addr, len); + return ret; } /* ??? Should this also swap msgh->name? */ @@ -895,18 +904,20 @@ static long do_bind(int sockfd, target_ulong target_addr, socklen_t addrlen) { + long ret = 0; void *addr = alloca(addrlen); - target_to_host_sockaddr(addr, target_addr, addrlen); + if( (ret=target_to_host_sockaddr(addr, target_addr, addrlen,PAGE_READ)) != 0 ) return -ret; return get_errno(bind(sockfd, addr, addrlen)); } static long do_connect(int sockfd, target_ulong target_addr, socklen_t addrlen) { + long ret = 0; void *addr = alloca(addrlen); - target_to_host_sockaddr(addr, target_addr, addrlen); + if( (ret=target_to_host_sockaddr(addr, target_addr, addrlen,PAGE_READ)) != 0 ) return -ret; return get_errno(connect(sockfd, addr, addrlen)); } @@ -920,12 +931,23 @@ struct iovec *vec; target_ulong target_vec; - lock_user_struct(msgp, target_msg, 1); + if( send ) { + if( (ret=lock_and_check_user_struct(&msgp,target_msg,sizeof(*msgp),1, + PAGE_READ)) != 0 ) return -ret; + } else { + if( (ret=lock_and_check_user_struct(&msgp,target_msg,sizeof(*msgp),1, + PAGE_WRITE)) != 0 ) return -ret; + } if (msgp->msg_name) { msg.msg_namelen = tswap32(msgp->msg_namelen); msg.msg_name = alloca(msg.msg_namelen); - target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name), - msg.msg_namelen); + if( send ) { + if( (ret=target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name), + msg.msg_namelen,PAGE_READ)) != 0 ) return -ret; + } else { + if( (ret=target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name), + msg.msg_namelen,PAGE_WRITE)) != 0 ) return -ret; + } } else { msg.msg_name = NULL; msg.msg_namelen = 0; @@ -958,11 +980,12 @@ { socklen_t addrlen = tget32(target_addrlen); void *addr = alloca(addrlen); - long ret; + long ret,ret2; ret = get_errno(accept(fd, addr, &addrlen)); if (!is_error(ret)) { - host_to_target_sockaddr(target_addr, addr, addrlen); + if( (ret2=host_to_target_sockaddr(target_addr, addr, addrlen, PAGE_WRITE)) != 0 ) return -ret2; + if( (ret2=page_check_range(target_addrlen,sizeof(socklen_t),PAGE_WRITE)) != 0 ) return -ret2; tput32(target_addrlen, addrlen); } return ret; @@ -971,13 +994,18 @@ static long do_getpeername(int fd, target_ulong target_addr, target_ulong target_addrlen) { - socklen_t addrlen = tget32(target_addrlen); - void *addr = alloca(addrlen); - long ret; + socklen_t addrlen; + void *addr; + long ret,ret2; + + if( (ret=page_check_range(target_addrlen,sizeof(socklen_t),PAGE_READ)) != 0 ) return -ret; + addrlen = tget32(target_addrlen); + addr = alloca(addrlen); ret = get_errno(getpeername(fd, addr, &addrlen)); if (!is_error(ret)) { - host_to_target_sockaddr(target_addr, addr, addrlen); + if( (ret2=host_to_target_sockaddr(target_addr, addr, addrlen, PAGE_WRITE)) != 0 ) return -ret2; + if( (ret2=page_check_range(target_addrlen,sizeof(socklen_t),PAGE_WRITE)) != 0 ) return -ret2; tput32(target_addrlen, addrlen); } return ret; @@ -986,13 +1014,17 @@ static long do_getsockname(int fd, target_ulong target_addr, target_ulong target_addrlen) { - socklen_t addrlen = tget32(target_addrlen); - void *addr = alloca(addrlen); - long ret; + socklen_t addrlen; + void *addr; + long ret,ret2; + + if( (ret=page_check_range(target_addrlen,sizeof(socklen_t),PAGE_WRITE)) != 0 ) return -ret; + addrlen = tget32(target_addrlen); + addr = alloca(addrlen); ret = get_errno(getsockname(fd, addr, &addrlen)); if (!is_error(ret)) { - host_to_target_sockaddr(target_addr, addr, addrlen); + if( (ret2=host_to_target_sockaddr(target_addr, addr, addrlen, PAGE_WRITE)) ) return -ret2; tput32(target_addrlen, addrlen); } return ret; @@ -1019,10 +1051,10 @@ void *host_msg; long ret; - host_msg = lock_user(msg, len, 1); + if( (ret=lock_and_check_user_struct(&host_msg,msg,len,1,PAGE_READ)) != 0 ) return -ret; if (target_addr) { addr = alloca(addrlen); - target_to_host_sockaddr(addr, target_addr, addrlen); + if( (ret=target_to_host_sockaddr(addr, target_addr, addrlen, PAGE_READ)) != 0 ) return -ret; ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen)); } else { ret = get_errno(send(fd, host_msg, len, flags)); @@ -1037,9 +1069,9 @@ socklen_t addrlen; void *addr; void *host_msg; - long ret; + long ret,ret2; - host_msg = lock_user(msg, len, 0); + if( (ret2=lock_and_check_user_struct(&host_msg,msg,len,0,PAGE_WRITE)) != 0 ) return -ret2; if (target_addr) { addrlen = tget32(target_addrlen); addr = alloca(addrlen); @@ -1050,7 +1082,7 @@ } if (!is_error(ret)) { if (target_addr) { - host_to_target_sockaddr(target_addr, addr, addrlen); + if( (ret2=host_to_target_sockaddr(target_addr, addr, addrlen, PAGE_WRITE)) != 0 ) return -ret2; tput32(target_addrlen, addrlen); } unlock_user(host_msg, msg, len); @@ -1257,13 +1289,15 @@ target_ulong __unused4; }; -static inline void target_to_host_ipc_perm(struct ipc_perm *host_ip, - target_ulong target_addr) +static inline long target_to_host_ipc_perm(struct ipc_perm *host_ip, + target_ulong target_addr, + int pg_access) { + long ret = 0; struct target_ipc_perm *target_ip; struct target_semid_ds *target_sd; - lock_user_struct(target_sd, target_addr, 1); + if( (ret=lock_and_check_user_struct(&target_sd,target_addr,sizeof(*target_sd),1,pg_access)) ) return -ret; target_ip=&(target_sd->sem_perm); host_ip->__key = tswapl(target_ip->__key); host_ip->uid = tswapl(target_ip->uid); @@ -1272,15 +1306,19 @@ host_ip->cgid = tswapl(target_ip->cgid); host_ip->mode = tswapl(target_ip->mode); unlock_user_struct(target_sd, target_addr, 0); + + return ret; } -static inline void host_to_target_ipc_perm(target_ulong target_addr, - struct ipc_perm *host_ip) +static inline long host_to_target_ipc_perm(target_ulong target_addr, + struct ipc_perm *host_ip, + int pg_access) { + long ret = 0; struct target_ipc_perm *target_ip; struct target_semid_ds *target_sd; - lock_user_struct(target_sd, target_addr, 0); + if( (ret=lock_and_check_user_struct(&target_sd,target_addr,sizeof(*target_sd),0,pg_access)) ) return -ret; target_ip = &(target_sd->sem_perm); target_ip->__key = tswapl(host_ip->__key); target_ip->uid = tswapl(host_ip->uid); @@ -1289,32 +1327,42 @@ target_ip->cgid = tswapl(host_ip->cgid); target_ip->mode = tswapl(host_ip->mode); unlock_user_struct(target_sd, target_addr, 1); + + return ret; } -static inline void target_to_host_semid_ds(struct semid_ds *host_sd, - target_ulong target_addr) +static inline long target_to_host_semid_ds(struct semid_ds *host_sd, + target_ulong target_addr, + int pg_access) { + long ret = 0; struct target_semid_ds *target_sd; - lock_user_struct(target_sd, target_addr, 1); - target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr); + if( (ret=lock_and_check_user_struct(&target_sd,target_addr,sizeof(*target_sd),1,pg_access)) != 0 ) return -ret; + if( (ret=target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr,pg_access)) != 0 ) return ret; host_sd->sem_nsems = tswapl(target_sd->sem_nsems); host_sd->sem_otime = tswapl(target_sd->sem_otime); host_sd->sem_ctime = tswapl(target_sd->sem_ctime); unlock_user_struct(target_sd, target_addr, 0); + + return ret; } -static inline void host_to_target_semid_ds(target_ulong target_addr, - struct semid_ds *host_sd) +static inline long host_to_target_semid_ds(target_ulong target_addr, + struct semid_ds *host_sd, + int pg_access) { + long ret = 0; struct target_semid_ds *target_sd; - lock_user_struct(target_sd, target_addr, 0); - host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)); + if( (ret=lock_and_check_user_struct(&target_sd,target_addr,sizeof(*target_sd),0,pg_access)) != 0 ) return -ret; + if( (ret=host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm),pg_access)) != 0 ) return ret; target_sd->sem_nsems = tswapl(host_sd->sem_nsems); target_sd->sem_otime = tswapl(host_sd->sem_otime); target_sd->sem_ctime = tswapl(host_sd->sem_ctime); unlock_user_struct(target_sd, target_addr, 1); + + return ret; } union semun { @@ -1329,67 +1377,75 @@ unsigned short int *array; }; -static inline void target_to_host_semun(unsigned long cmd, +static inline long target_to_host_semun(unsigned long cmd, union semun *host_su, target_ulong target_addr, - struct semid_ds *ds) + struct semid_ds *ds, + int pg_access) { + long ret = 0; union target_semun *target_su; switch( cmd ) { case IPC_STAT: case IPC_SET: - lock_user_struct(target_su, target_addr, 1); - target_to_host_semid_ds(ds,target_su->buf); + if( (ret=lock_and_check_user_struct(&target_su,target_addr,sizeof(*target_su),1,pg_access)) != 0 ) return -ret; + if( (ret=target_to_host_semid_ds(ds,target_su->buf, pg_access)) != 0 ) return -ret; host_su->buf = ds; unlock_user_struct(target_su, target_addr, 0); break; case GETVAL: case SETVAL: - lock_user_struct(target_su, target_addr, 1); + if( (ret=lock_and_check_user_struct(&target_su,target_addr,sizeof(*target_su),1,pg_access)) != 0 ) return -ret; host_su->val = tswapl(target_su->val); unlock_user_struct(target_su, target_addr, 0); break; case GETALL: case SETALL: - lock_user_struct(target_su, target_addr, 1); + if( (ret=lock_and_check_user_struct(&target_su,target_addr,sizeof(*target_su),1,pg_access)) != 0 ) return -ret; *host_su->array = tswap16(*target_su->array); unlock_user_struct(target_su, target_addr, 0); break; default: gemu_log("semun operation not fully supported: %d\n", (int)cmd); } + + return ret; } -static inline void host_to_target_semun(unsigned long cmd, +static inline long host_to_target_semun(unsigned long cmd, target_ulong target_addr, union semun *host_su, - struct semid_ds *ds) + struct semid_ds *ds, + int pg_access) { + long ret = 0; union target_semun *target_su; switch( cmd ) { case IPC_STAT: case IPC_SET: - lock_user_struct(target_su, target_addr, 0); - host_to_target_semid_ds(target_su->buf,ds); + if( (ret=lock_and_check_user_struct(&target_su,target_addr,sizeof(*target_su),0,pg_access)) != 0 ) return -ret; + if( (ret=host_to_target_semid_ds(target_su->buf,ds, pg_access)) != 0 ) return -ret; unlock_user_struct(target_su, target_addr, 1); break; case GETVAL: case SETVAL: - lock_user_struct(target_su, target_addr, 0); + if( (ret=lock_and_check_user_struct(&target_su,target_addr,sizeof(*target_su),0,pg_access)) != 0 ) return -ret; target_su->val = tswapl(host_su->val); unlock_user_struct(target_su, target_addr, 1); break; case GETALL: case SETALL: - lock_user_struct(target_su, target_addr, 0); + if( (ret=lock_and_check_user_struct(&target_su,target_addr,sizeof(*target_su),0,pg_access)) != 0 ) return -ret; *target_su->array = tswap16(*host_su->array); unlock_user_struct(target_su, target_addr, 1); break; default: gemu_log("semun operation not fully supported: %d\n", (int)cmd); } + + return ret; } static inline long do_semctl(long first, long second, long third, long ptr) @@ -1401,34 +1457,34 @@ switch( cmd ) { case GETVAL: - target_to_host_semun(cmd,&arg,ptr,&dsarg); + if( (ret=target_to_host_semun(cmd,&arg,ptr,&dsarg,PAGE_WRITE)) != 0 ) return -ret; ret = get_errno(semctl(first, second, cmd, arg)); - host_to_target_semun(cmd,ptr,&arg,&dsarg); + host_to_target_semun(cmd,ptr,&arg,&dsarg,PAGE_WRITE); break; case SETVAL: - target_to_host_semun(cmd,&arg,ptr,&dsarg); + if( (ret=target_to_host_semun(cmd,&arg,ptr,&dsarg,PAGE_READ)) != 0 ) return -ret; ret = get_errno(semctl(first, second, cmd, arg)); - host_to_target_semun(cmd,ptr,&arg,&dsarg); + host_to_target_semun(cmd,ptr,&arg,&dsarg,PAGE_READ); break; case GETALL: - target_to_host_semun(cmd,&arg,ptr,&dsarg); + if( (ret=target_to_host_semun(cmd,&arg,ptr,&dsarg,PAGE_WRITE)) != 0 ) return -ret; ret = get_errno(semctl(first, second, cmd, arg)); - host_to_target_semun(cmd,ptr,&arg,&dsarg); + host_to_target_semun(cmd,ptr,&arg,&dsarg,PAGE_WRITE); break; case SETALL: - target_to_host_semun(cmd,&arg,ptr,&dsarg); + if( (ret=target_to_host_semun(cmd,&arg,ptr,&dsarg,PAGE_READ)) != 0 ) return -ret; ret = get_errno(semctl(first, second, cmd, arg)); - host_to_target_semun(cmd,ptr,&arg,&dsarg); + host_to_target_semun(cmd,ptr,&arg,&dsarg,PAGE_READ); break; case IPC_STAT: - target_to_host_semun(cmd,&arg,ptr,&dsarg); + if( (ret=target_to_host_semun(cmd,&arg,ptr,&dsarg,PAGE_WRITE)) != 0 ) return -ret; ret = get_errno(semctl(first, second, cmd, arg)); - host_to_target_semun(cmd,ptr,&arg,&dsarg); + host_to_target_semun(cmd,ptr,&arg,&dsarg,PAGE_READ); break; case IPC_SET: - target_to_host_semun(cmd,&arg,ptr,&dsarg); + if( (ret=target_to_host_semun(cmd,&arg,ptr,&dsarg,PAGE_READ)) != 0 ) return -ret; ret = get_errno(semctl(first, second, cmd, arg)); - host_to_target_semun(cmd,ptr,&arg,&dsarg); + host_to_target_semun(cmd,ptr,&arg,&dsarg,PAGE_READ); break; default: ret = get_errno(semctl(first, second, cmd, arg)); @@ -1455,13 +1511,15 @@ target_ulong __unused5; }; -static inline void target_to_host_msqid_ds(struct msqid_ds *host_md, - target_ulong target_addr) +static inline long target_to_host_msqid_ds(struct msqid_ds *host_md, + target_ulong target_addr, + int pg_access) { + long ret = 0; struct target_msqid_ds *target_md; - lock_user_struct(target_md, target_addr, 1); - target_to_host_ipc_perm(&(host_md->msg_perm),target_addr); + if( (ret=lock_and_check_user_struct(&target_md,target_addr,sizeof(*target_md),1,pg_access)) != 0 ) return -ret; + if( (ret=target_to_host_ipc_perm(&(host_md->msg_perm),target_addr,pg_access)) != 0 ) return ret; host_md->msg_stime = tswapl(target_md->msg_stime); host_md->msg_rtime = tswapl(target_md->msg_rtime); host_md->msg_ctime = tswapl(target_md->msg_ctime); @@ -1471,15 +1529,18 @@ host_md->msg_lspid = tswapl(target_md->msg_lspid); host_md->msg_lrpid = tswapl(target_md->msg_lrpid); unlock_user_struct(target_md, target_addr, 0); + return ret; } -static inline void host_to_target_msqid_ds(target_ulong target_addr, - struct msqid_ds *host_md) +static inline long host_to_target_msqid_ds(target_ulong target_addr, + struct msqid_ds *host_md, + int pg_access) { + long ret = 0; struct target_msqid_ds *target_md; - lock_user_struct(target_md, target_addr, 0); - host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)); + if( (ret=lock_and_check_user_struct(&target_md,target_addr,sizeof(*target_md),0,pg_access)) != 0 ) return -ret; + if( (ret=host_to_target_ipc_perm(target_addr,&(host_md->msg_perm),pg_access)) != 0 ) return ret; target_md->msg_stime = tswapl(host_md->msg_stime); target_md->msg_rtime = tswapl(host_md->msg_rtime); target_md->msg_ctime = tswapl(host_md->msg_ctime); @@ -1489,6 +1550,8 @@ target_md->msg_lspid = tswapl(host_md->msg_lspid); target_md->msg_lrpid = tswapl(host_md->msg_lrpid); unlock_user_struct(target_md, target_addr, 1); + + return ret; } static inline long do_msgctl(long first, long second, long ptr) @@ -1498,10 +1561,15 @@ long ret = 0; switch( cmd ) { case IPC_STAT: + if( (ret=target_to_host_msqid_ds(&dsarg,ptr,PAGE_WRITE)) != 0 ) return -ret; + ret = get_errno(msgctl(first, cmd, &dsarg)); + host_to_target_msqid_ds(ptr,&dsarg,PAGE_WRITE); + break; case IPC_SET: - target_to_host_msqid_ds(&dsarg,ptr); + if( (ret=target_to_host_msqid_ds(&dsarg,ptr,PAGE_READ)) != 0 ) return -ret; ret = get_errno(msgctl(first, cmd, &dsarg)); - host_to_target_msqid_ds(ptr,&dsarg); + host_to_target_msqid_ds(ptr,&dsarg,PAGE_WRITE); + break; default: ret = get_errno(msgctl(first, cmd, &dsarg)); } @@ -1519,7 +1587,7 @@ struct msgbuf *host_mb; long ret = 0; - lock_user_struct(target_mb,msgp,0); + if( (ret=lock_and_check_user_struct(&target_mb,msgp,sizeof(long)+msgsz,1,PAGE_READ)) != 0 ) return -ret; host_mb = malloc(msgsz+sizeof(long)); host_mb->mtype = tswapl(target_mb->mtype); memcpy(host_mb->mtext,target_mb->mtext,msgsz); @@ -1536,7 +1604,7 @@ struct msgbuf *host_mb; long ret = 0; - lock_user_struct(target_mb, msgp, 0); + if( (ret=lock_and_check_user_struct(&target_mb,msgp,sizeof(long)+msgsz,0,PAGE_WRITE)) != 0 ) return -ret; host_mb = malloc(msgsz+sizeof(long)); ret = get_errno(msgrcv(msqid, host_mb, msgsz, 1, msgflg)); if (ret > 0) @@ -2016,6 +2084,7 @@ static int write_ldt(CPUX86State *env, target_ulong ptr, unsigned long bytecount, int oldmode) { + long ret = 0; struct target_modify_ldt_ldt_s ldt_info; struct target_modify_ldt_ldt_s *target_ldt_info; int seg_32bit, contents, read_exec_only, limit_in_pages; @@ -2024,7 +2093,7 @@ if (bytecount != sizeof(ldt_info)) return -EINVAL; - lock_user_struct(target_ldt_info, ptr, 1); + if( (ret=lock_and_check_user_struct(&target_ldt_info,ptr,sizeof(struct target_modify_ldt_ldt_s),1,PAGE_READ)) != 0 ) return -ret; ldt_info.entry_number = tswap32(target_ldt_info->entry_number); ldt_info.base_addr = tswapl(target_ldt_info->base_addr); ldt_info.limit = tswap32(target_ldt_info->limit); @@ -2223,7 +2292,7 @@ switch(cmd) { case TARGET_F_GETLK: - lock_user_struct(target_fl, arg, 1); + if( (ret=lock_and_check_user_struct(&target_fl,arg,sizeof(struct target_flock),1,PAGE_READ)) != 0 ) return -ret; fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswapl(target_fl->l_start); @@ -2232,6 +2301,7 @@ unlock_user_struct(target_fl, arg, 0); ret = fcntl(fd, cmd, &fl); if (ret == 0) { + if( (ret=lock_and_check_user_struct(&target_fl,arg,sizeof(struct target_flock),0,PAGE_WRITE)) != 0 ) return -ret; lock_user_struct(target_fl, arg, 0); target_fl->l_type = tswap16(fl.l_type); target_fl->l_whence = tswap16(fl.l_whence); @@ -2244,7 +2314,7 @@ case TARGET_F_SETLK: case TARGET_F_SETLKW: - lock_user_struct(target_fl, arg, 1); + if( (ret=lock_and_check_user_struct(&target_fl,arg,sizeof(struct target_flock),1,PAGE_READ)) != 0 ) return -ret; fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswapl(target_fl->l_start); @@ -2255,7 +2325,7 @@ break; case TARGET_F_GETLK64: - lock_user_struct(target_fl64, arg, 1); + if( (ret=lock_and_check_user_struct(&target_fl64,arg,sizeof(struct target_flock64),1,PAGE_READ)) != 0 ) return -ret; fl64.l_type = tswap16(target_fl64->l_type) >> 1; fl64.l_whence = tswap16(target_fl64->l_whence); fl64.l_start = tswapl(target_fl64->l_start); @@ -2264,7 +2334,7 @@ unlock_user_struct(target_fl64, arg, 0); ret = fcntl(fd, cmd >> 1, &fl64); if (ret == 0) { - lock_user_struct(target_fl64, arg, 0); + if( (ret=lock_and_check_user_struct(&target_fl64,arg,sizeof(struct target_flock64),0,PAGE_WRITE)) != 0 ) return -ret; target_fl64->l_type = tswap16(fl64.l_type) >> 1; target_fl64->l_whence = tswap16(fl64.l_whence); target_fl64->l_start = tswapl(fl64.l_start); @@ -2275,7 +2345,7 @@ break; case TARGET_F_SETLK64: case TARGET_F_SETLKW64: - lock_user_struct(target_fl64, arg, 1); + if( (ret=lock_and_check_user_struct(&target_fl64,arg,sizeof(struct target_flock64),1,PAGE_READ)) != 0 ) return -ret; fl64.l_type = tswap16(target_fl64->l_type) >> 1; fl64.l_whence = tswap16(target_fl64->l_whence); fl64.l_start = tswapl(target_fl64->l_start); @@ -2417,23 +2487,26 @@ } #endif -static inline void target_to_host_timespec(struct timespec *host_ts, +static inline long target_to_host_timespec(struct timespec *host_ts, target_ulong target_addr) { + long ret = 0; struct target_timespec *target_ts; - lock_user_struct(target_ts, target_addr, 1); + if( (ret=lock_and_check_user_struct(&target_ts,target_addr,sizeof(struct target_timespec),1,PAGE_READ)) != 0 ) return -ret; host_ts->tv_sec = tswapl(target_ts->tv_sec); host_ts->tv_nsec = tswapl(target_ts->tv_nsec); unlock_user_struct(target_ts, target_addr, 0); } -static inline void host_to_target_timespec(target_ulong target_addr, +static inline long host_to_target_timespec(target_ulong target_addr, struct timespec *host_ts) { + long ret = 0; struct target_timespec *target_ts; lock_user_struct(target_ts, target_addr, 0); + if( (ret=lock_and_check_user_struct(&target_ts,target_addr,sizeof(struct target_timespec),0,PAGE_WRITE)) != 0 ) return -ret; target_ts->tv_sec = tswapl(host_ts->tv_sec); target_ts->tv_nsec = tswapl(host_ts->tv_nsec); unlock_user_struct(target_ts, target_addr, 1); @@ -2442,7 +2515,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { - long ret; + long ret = 0; struct stat st; struct statfs stfs; void *p; @@ -2669,7 +2742,7 @@ struct utimbuf tbuf, *host_tbuf; struct target_utimbuf *target_tbuf; if (arg2) { - lock_user_struct(target_tbuf, arg2, 1); + if( (ret=lock_and_check_user_struct(&target_tbuf,arg2,sizeof(struct target_utimbuf),1,PAGE_READ)) != 0 ) return -ret; tbuf.actime = tswapl(target_tbuf->actime); tbuf.modtime = tswapl(target_tbuf->modtime); unlock_user_struct(target_tbuf, arg2, 0); @@ -2687,9 +2760,9 @@ { struct timeval *tvp, tv[2]; if (arg2) { - target_to_host_timeval(&tv[0], arg2); - target_to_host_timeval(&tv[1], - arg2 + sizeof (struct target_timeval)); + if( (ret=target_to_host_timeval(&tv[0], arg2)) != 0 ) return ret; + if( (ret=target_to_host_timeval(&tv[1], + arg2 + sizeof (struct target_timeval))) != 0 ) return ret; tvp = tv; } else { tvp = NULL; @@ -2858,7 +2931,7 @@ struct target_old_sigaction *old_act; struct target_sigaction act, oact, *pact; if (arg2) { - lock_user_struct(old_act, arg2, 1); + if( (ret=lock_and_check_user_struct(&old_act,arg2,sizeof(*old_act),1,PAGE_READ)) != 0 ) return -ret; act._sa_handler = old_act->_sa_handler; target_siginitset(&act.sa_mask, old_act->sa_mask); act.sa_flags = old_act->sa_flags; @@ -2870,7 +2943,7 @@ } ret = get_errno(do_sigaction(arg1, pact, &oact)); if (!is_error(ret) && arg3) { - lock_user_struct(old_act, arg3, 0); + if( (ret=lock_and_check_user_struct(&old_act,arg3,sizeof(*old_act),0,PAGE_WRITE)) != 0 ) return -ret; old_act->_sa_handler = oact._sa_handler; old_act->sa_mask = oact.sa_mask.sig[0]; old_act->sa_flags = oact.sa_flags; @@ -2881,7 +2954,7 @@ struct target_sigaction act, oact, *pact, *old_act; if (arg2) { - lock_user_struct(old_act, arg2, 1); + if( (ret=lock_and_check_user_struct(&old_act,arg2,sizeof(*old_act),1,PAGE_READ)) != 0 ) return -ret; act._sa_handler = old_act->_sa_handler; target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]); act.sa_flags = old_act->sa_flags; @@ -2894,7 +2967,7 @@ ret = get_errno(do_sigaction(arg1, pact, &oact)); if (!is_error(ret) && arg3) { - lock_user_struct(old_act, arg3, 0); + if( (ret=lock_and_check_user_struct(&old_act,arg3,sizeof(*old_act),0,PAGE_WRITE)) != 0 ) return -ret; old_act->_sa_handler = oact._sa_handler; old_act->sa_flags = oact.sa_flags; old_act->sa_mask.sig[0] = oact.sa_mask.sig[0]; @@ -2912,12 +2985,14 @@ struct target_sigaction *act; struct target_sigaction *oact; - if (arg2) - lock_user_struct(act, arg2, 1); + if (arg2) { + if( (ret=lock_and_check_user_struct(&act,arg2,sizeof(*act),1,PAGE_READ)) != 0 ) return -ret; + } else act = NULL; - if (arg3) - lock_user_struct(oact, arg3, 0); + if (arg3) { + if( (ret=lock_and_check_user_struct(&oact,arg2,sizeof(*oact),0,PAGE_WRITE)) != 0 ) return -ret; + } else oact = NULL; ret = get_errno(do_sigaction(arg1, act, oact)); @@ -3044,7 +3119,7 @@ sigset_t set; ret = get_errno(sigpending(&set)); if (!is_error(ret)) { - p = lock_user(arg1, sizeof(target_sigset_t), 0); + if( (ret=lock_and_check_user_struct(&p,arg1,sizeof(target_sigset_t),0,PAGE_WRITE)) != 0 ) return -ret; host_to_target_sigset(p, &set); unlock_user(p, arg1, sizeof(target_sigset_t)); } @@ -3054,7 +3129,7 @@ case TARGET_NR_sigsuspend: { sigset_t set; - p = lock_user(arg1, sizeof(target_sigset_t), 1); + if( (ret=lock_and_check_user_struct(&p,arg1,sizeof(target_sigset_t),1,PAGE_READ)) != 0 ) return -ret; target_to_host_old_sigset(&set, p); unlock_user(p, arg1, 0); ret = get_errno(sigsuspend(&set)); @@ -3064,7 +3139,7 @@ case TARGET_NR_rt_sigsuspend: { sigset_t set; - p = lock_user(arg1, sizeof(target_sigset_t), 1); + if( (ret=lock_and_check_user_struct(&p,arg1,sizeof(target_sigset_t),1,PAGE_READ)) != 0 ) return -ret; target_to_host_sigset(&set, p); unlock_user(p, arg1, 0); ret = get_errno(sigsuspend(&set)); @@ -3076,18 +3151,18 @@ struct timespec uts, *puts; siginfo_t uinfo; - p = lock_user(arg1, sizeof(target_sigset_t), 1); + if( (ret=lock_and_check_user_struct(&p,arg1,sizeof(target_sigset_t),1,PAGE_READ)) != 0 ) return -ret; target_to_host_sigset(&set, p); unlock_user(p, arg1, 0); if (arg3) { puts = &uts; - target_to_host_timespec(puts, arg3); + if( (ret=target_to_host_timespec(puts, arg3)) != 0 ) return ret; } else { puts = NULL; } ret = get_errno(sigtimedwait(&set, &uinfo, puts)); if (!is_error(ret) && arg2) { - p = lock_user(arg2, sizeof(target_sigset_t), 0); + if( (ret=lock_and_check_user_struct(&p,arg2,sizeof(target_sigset_t),0,PAGE_WRITE)) != 0 ) return -ret; host_to_target_siginfo(p, &uinfo); unlock_user(p, arg2, sizeof(target_sigset_t)); } @@ -3096,7 +3171,7 @@ case TARGET_NR_rt_sigqueueinfo: { siginfo_t uinfo; - p = lock_user(arg3, sizeof(target_sigset_t), 1); + if( (ret=lock_and_check_user_struct(&p,arg3,sizeof(target_sigset_t),1,PAGE_READ)) != 0 ) return -ret; target_to_host_siginfo(&uinfo, p); unlock_user(p, arg1, 0); ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo)); @@ -3151,7 +3226,7 @@ struct rusage rusage; ret = get_errno(getrusage(arg1, &rusage)); if (!is_error(ret)) { - host_to_target_rusage(arg2, &rusage); + if( (ret=host_to_target_rusage(arg2, &rusage)) != 0 ) return ret; } } break; @@ -3160,14 +3235,14 @@ struct timeval tv; ret = get_errno(gettimeofday(&tv, NULL)); if (!is_error(ret)) { - host_to_target_timeval(arg1, &tv); + if( (ret=host_to_target_timeval(arg1, &tv)) != 0 ) return ret; } } break; case TARGET_NR_settimeofday: { struct timeval tv; - target_to_host_timeval(&tv, arg1); + if( (ret=target_to_host_timeval(&tv, arg1)) != 0 ) return ret; ret = get_errno(settimeofday(&tv, NULL)); } break; @@ -3486,19 +3561,19 @@ if (arg2) { pvalue = &value; - target_to_host_timeval(&pvalue->it_interval, - arg2); - target_to_host_timeval(&pvalue->it_value, - arg2 + sizeof(struct target_timeval)); + if( (ret=target_to_host_timeval(&pvalue->it_interval, + arg2)) != 0 ) return ret; + if( (ret=target_to_host_timeval(&pvalue->it_value, + arg2 + sizeof(struct target_timeval))) != 0 ) return ret; } else { pvalue = NULL; } ret = get_errno(setitimer(arg1, pvalue, &ovalue)); if (!is_error(ret) && arg3) { - host_to_target_timeval(arg3, - &ovalue.it_interval); - host_to_target_timeval(arg3 + sizeof(struct target_timeval), - &ovalue.it_value); + if( (ret=host_to_target_timeval(arg3, + &ovalue.it_interval)) != 0 ) return ret; + if( (ret=host_to_target_timeval(arg3 + sizeof(struct target_timeval), + &ovalue.it_value)) != 0 ) return ret; } } break; @@ -3508,10 +3583,10 @@ ret = get_errno(getitimer(arg1, &value)); if (!is_error(ret) && arg2) { - host_to_target_timeval(arg2, - &value.it_interval); - host_to_target_timeval(arg2 + sizeof(struct target_timeval), - &value.it_value); + if( (ret=host_to_target_timeval(arg2, + &value.it_interval)) != 0 ) return ret; + if( (ret=host_to_target_timeval(arg2 + sizeof(struct target_timeval), + &value.it_value)) != 0 ) return ret; } } break; @@ -3532,7 +3607,7 @@ if (!is_error(ret)) { struct target_stat *target_st; - lock_user_struct(target_st, arg2, 0); + if( (ret=lock_and_check_user_struct(&target_st,arg2,sizeof(*target_st),9,PAGE_WRITE)) != 0 ) return -ret; #if defined(TARGET_MIPS) target_st->st_dev = tswap32(st.st_dev); #else @@ -3963,17 +4038,17 @@ struct timespec ts; ret = get_errno(sched_rr_get_interval(arg1, &ts)); if (!is_error(ret)) { - host_to_target_timespec(arg2, &ts); + if( (ret=host_to_target_timespec(arg2, &ts)) != 0 ) return ret; } } break; case TARGET_NR_nanosleep: { struct timespec req, rem; - target_to_host_timespec(&req, arg1); + if( (ret=target_to_host_timespec(&req, arg1)) != 0 ) return ret; ret = get_errno(nanosleep(&req, &rem)); if (is_error(ret) && arg2) { - host_to_target_timespec(arg2, &rem); + if( (ret=host_to_target_timespec(arg2, &rem)) != 0 ) return ret; } } break; @@ -4070,6 +4145,7 @@ #ifdef TARGET_NR_stat64 case TARGET_NR_stat64: p = lock_user_string(arg1); + if( ret=page_check_range(p,1,PAGE_READ) ) return -ret; ret = get_errno(stat(path(p), &st)); unlock_user(p, arg1, 0); goto do_stat64; @@ -4077,6 +4153,7 @@ #ifdef TARGET_NR_lstat64 case TARGET_NR_lstat64: p = lock_user_string(arg1); + if( ret=page_check_range(p,1,PAGE_READ) ) return -ret; ret = get_errno(lstat(path(p), &st)); unlock_user(p, arg1, 0); goto do_stat64; @@ -4090,7 +4167,7 @@ #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { struct target_eabi_stat64 *target_st; - lock_user_struct(target_st, arg2, 1); + if( (ret=lock_and_check_user_struct(&target_st,arg2,sizeof(*target_st),1,PAGE_WRITE)) != 0 ) return -ret; memset(target_st, 0, sizeof(struct target_eabi_stat64)); /* put_user is probably wrong. */ put_user(st.st_dev, &target_st->st_dev); @@ -4115,7 +4192,7 @@ #endif { struct target_stat64 *target_st; - lock_user_struct(target_st, arg2, 1); + if( (ret=lock_and_check_user_struct(&target_st,arg2,sizeof(*target_st),1,PAGE_WRITE)) != 0 ) return -ret; memset(target_st, 0, sizeof(struct target_stat64)); /* ??? put_user is probably wrong. */ put_user(st.st_dev, &target_st->st_dev); @@ -4581,7 +4658,7 @@ struct timespec ts; ret = get_errno(clock_gettime(arg1, &ts)); if (!is_error(ret)) { - host_to_target_timespec(arg2, &ts); + if( (ret=host_to_target_timespec(arg2, &ts)) != 0 ) return ret; } break; } @@ -4592,7 +4669,7 @@ struct timespec ts; ret = get_errno(clock_getres(arg1, &ts)); if (!is_error(ret)) { - host_to_target_timespec(arg2, &ts); + if( (ret=host_to_target_timespec(arg2, &ts)) != 0 ) return ret; } break; } Index: qemu/linux-user/qemu.h =================================================================== --- qemu.orig/linux-user/qemu.h 2007-06-03 20:36:54.000000000 -0400 +++ qemu/linux-user/qemu.h 2007-06-03 20:37:10.000000000 -0400 @@ -295,6 +295,15 @@ #define unlock_user_struct(host_ptr, guest_addr, copy) \ unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0) +static inline long lock_and_check_user_struct(void *host_addr, target_ulong guest_addr, long len, int copy, int pg_access) +{ + long *haddr, ret = 0; + haddr = (long *)host_addr; + if( (ret=page_check_range(guest_addr,len,pg_access)) != 0 ) return ret; + *haddr = (long)lock_user(guest_addr, len, copy); + return 0; +} + #define tget8(addr) ldub(addr) #define tput8(addr, val) stb(addr, val) #define tget16(addr) lduw(addr)