diff options
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r-- | linux-user/syscall.c | 985 |
1 files changed, 574 insertions, 411 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 07e84d9..656f78e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -504,12 +504,13 @@ static inline abi_long host_to_target_clock_t(long ticks) #endif } -static inline void host_to_target_rusage(abi_ulong target_addr, - const struct rusage *rusage) +static inline abi_long host_to_target_rusage(abi_ulong target_addr, + const struct rusage *rusage) { struct target_rusage *target_rusage; - lock_user_struct(target_rusage, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0)) + return -TARGET_EFAULT; 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); @@ -529,28 +530,36 @@ static inline void host_to_target_rusage(abi_ulong target_addr, target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw); target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw); unlock_user_struct(target_rusage, target_addr, 1); + + return 0; } -static inline void target_to_host_timeval(struct timeval *tv, - abi_ulong target_addr) +static inline abi_long target_to_host_timeval(struct timeval *tv, + abi_ulong target_addr) { struct target_timeval *target_tv; - lock_user_struct(target_tv, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_tv, target_addr, 1)) + return -TARGET_EFAULT; tv->tv_sec = tswapl(target_tv->tv_sec); tv->tv_usec = tswapl(target_tv->tv_usec); unlock_user_struct(target_tv, target_addr, 0); + + return 0; } -static inline void host_to_target_timeval(abi_ulong target_addr, - const struct timeval *tv) +static inline abi_long host_to_target_timeval(abi_ulong target_addr, + const struct timeval *tv) { struct target_timeval *target_tv; - lock_user_struct(target_tv, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_tv, target_addr, 0)) + return -TARGET_EFAULT; target_tv->tv_sec = tswapl(tv->tv_sec); target_tv->tv_usec = tswapl(tv->tv_usec); unlock_user_struct(target_tv, target_addr, 1); + + return 0; } @@ -567,21 +576,33 @@ static abi_long do_select(int n, int ok; if (rfd_p) { - target_rfds = lock_user(rfd_p, sizeof(abi_long) * n, 1); + target_rfds = lock_user(VERIFY_WRITE, rfd_p, sizeof(abi_long) * n, 1); + if (!target_rfds) { + ret = -TARGET_EFAULT; + goto end; + } 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(abi_long) * n, 1); + target_wfds = lock_user(VERIFY_WRITE, wfd_p, sizeof(abi_long) * n, 1); + if (!target_wfds) { + ret = -TARGET_EFAULT; + goto end; + } 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(abi_long) * n, 1); + target_efds = lock_user(VERIFY_WRITE, efd_p, sizeof(abi_long) * n, 1); + if (!target_efds) { + ret = -TARGET_EFAULT; + goto end; + } efds_ptr = target_to_host_fds(&efds, target_efds, n); } else { target_efds = NULL; @@ -606,38 +627,45 @@ static abi_long do_select(int n, host_to_target_timeval(target_tv, &tv); } } - if (target_rfds) - unlock_user(target_rfds, rfd_p, ok ? sizeof(abi_long) * n : 0); - if (target_wfds) - unlock_user(target_wfds, wfd_p, ok ? sizeof(abi_long) * n : 0); - if (target_efds) - unlock_user(target_efds, efd_p, ok ? sizeof(abi_long) * n : 0); + +end: + unlock_user(target_rfds, rfd_p, ok ? sizeof(abi_long) * n : 0); + unlock_user(target_wfds, wfd_p, ok ? sizeof(abi_long) * n : 0); + unlock_user(target_efds, efd_p, ok ? sizeof(abi_long) * n : 0); return ret; } -static inline void target_to_host_sockaddr(struct sockaddr *addr, - abi_ulong target_addr, - socklen_t len) +static inline abi_long target_to_host_sockaddr(struct sockaddr *addr, + abi_ulong target_addr, + socklen_t len) { struct target_sockaddr *target_saddr; - target_saddr = lock_user(target_addr, len, 1); + target_saddr = lock_user(VERIFY_READ, target_addr, len, 1); + if (!target_saddr) + return -TARGET_EFAULT; memcpy(addr, target_saddr, len); addr->sa_family = tswap16(target_saddr->sa_family); unlock_user(target_saddr, target_addr, 0); + + return 0; } -static inline void host_to_target_sockaddr(abi_ulong target_addr, - struct sockaddr *addr, - socklen_t len) +static inline abi_long host_to_target_sockaddr(abi_ulong target_addr, + struct sockaddr *addr, + socklen_t len) { struct target_sockaddr *target_saddr; - target_saddr = lock_user(target_addr, len, 0); + target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0); + if (!target_saddr) + return -TARGET_EFAULT; memcpy(target_saddr, addr, len); target_saddr->sa_family = tswap16(addr->sa_family); unlock_user(target_saddr, target_addr, len); + + return 0; } /* ??? Should this also swap msgh->name? */ @@ -941,35 +969,56 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, return ret; } -static void lock_iovec(struct iovec *vec, abi_ulong target_addr, - int count, int copy) +/* FIXME + * lock_iovec()/unlock_iovec() have a return code of 0 for success where + * other lock functions have a return code of 0 for failure. + */ +static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr, + int count, int copy) { struct target_iovec *target_vec; abi_ulong base; - int i; + int i, j; - target_vec = lock_user(target_addr, count * sizeof(struct target_iovec), 1); + target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); + if (!target_vec) + return -TARGET_EFAULT; for(i = 0;i < count; i++) { base = tswapl(target_vec[i].iov_base); vec[i].iov_len = tswapl(target_vec[i].iov_len); - vec[i].iov_base = lock_user(base, vec[i].iov_len, copy); + vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy); + if (!vec[i].iov_base) + goto fail; + } + unlock_user (target_vec, target_addr, 0); + return 0; + fail: + /* failure - unwind locks */ + for (j = 0; j < i; j++) { + base = tswapl(target_vec[j].iov_base); + unlock_user(vec[j].iov_base, base, 0); } unlock_user (target_vec, target_addr, 0); + return -TARGET_EFAULT; } -static void unlock_iovec(struct iovec *vec, abi_ulong target_addr, - int count, int copy) +static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr, + int count, int copy) { struct target_iovec *target_vec; abi_ulong base; int i; - target_vec = lock_user(target_addr, count * sizeof(struct target_iovec), 1); + target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); + if (!target_vec) + return -TARGET_EFAULT; for(i = 0;i < count; i++) { base = tswapl(target_vec[i].iov_base); unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0); } unlock_user (target_vec, target_addr, 0); + + return 0; } /* do_socket() Must return target values and target errnos. */ @@ -1033,7 +1082,12 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, struct iovec *vec; abi_ulong target_vec; - lock_user_struct(msgp, target_msg, 1); + /* FIXME */ + if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE, + msgp, + target_msg, + send ? 1 : 0)) + return -TARGET_EFAULT; if (msgp->msg_name) { msg.msg_namelen = tswap32(msgp->msg_namelen); msg.msg_name = alloca(msg.msg_namelen); @@ -1050,7 +1104,7 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, count = tswapl(msgp->msg_iovlen); vec = alloca(count * sizeof(struct iovec)); target_vec = tswapl(msgp->msg_iov); - lock_iovec(vec, target_vec, count, send); + lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send); msg.msg_iovlen = count; msg.msg_iov = vec; @@ -1063,6 +1117,7 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, host_to_target_cmsg(msgp, &msg); } unlock_iovec(vec, target_vec, count, !send); + unlock_user_struct(msgp, target_msg, send ? 0 : 1); return ret; } @@ -1137,7 +1192,9 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, void *host_msg; abi_long ret; - host_msg = lock_user(msg, len, 1); + host_msg = lock_user(VERIFY_READ, msg, len, 1); + if (!host_msg) + return -TARGET_EFAULT; if (target_addr) { addr = alloca(addrlen); target_to_host_sockaddr(addr, target_addr, addrlen); @@ -1159,7 +1216,9 @@ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags, void *host_msg; abi_long ret; - host_msg = lock_user(msg, len, 0); + host_msg = lock_user(VERIFY_WRITE, msg, len, 0); + if (!host_msg) + return -TARGET_EFAULT; if (target_addr) { addrlen = tget32(target_addrlen); addr = alloca(addrlen); @@ -1381,13 +1440,14 @@ struct target_semid_ds abi_ulong __unused4; }; -static inline void target_to_host_ipc_perm(struct ipc_perm *host_ip, - abi_ulong target_addr) +static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip, + abi_ulong target_addr) { struct target_ipc_perm *target_ip; struct target_semid_ds *target_sd; - lock_user_struct(target_sd, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) + return -TARGET_EFAULT; target_ip=&(target_sd->sem_perm); host_ip->__key = tswapl(target_ip->__key); host_ip->uid = tswapl(target_ip->uid); @@ -1396,15 +1456,17 @@ static inline void target_to_host_ipc_perm(struct ipc_perm *host_ip, host_ip->cgid = tswapl(target_ip->cgid); host_ip->mode = tswapl(target_ip->mode); unlock_user_struct(target_sd, target_addr, 0); + return 0; } -static inline void host_to_target_ipc_perm(abi_ulong target_addr, - struct ipc_perm *host_ip) +static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr, + struct ipc_perm *host_ip) { struct target_ipc_perm *target_ip; struct target_semid_ds *target_sd; - lock_user_struct(target_sd, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) + return -TARGET_EFAULT; target_ip = &(target_sd->sem_perm); target_ip->__key = tswapl(host_ip->__key); target_ip->uid = tswapl(host_ip->uid); @@ -1413,32 +1475,37 @@ static inline void host_to_target_ipc_perm(abi_ulong target_addr, target_ip->cgid = tswapl(host_ip->cgid); target_ip->mode = tswapl(host_ip->mode); unlock_user_struct(target_sd, target_addr, 1); + return 0; } -static inline void target_to_host_semid_ds(struct semid_ds *host_sd, - abi_ulong target_addr) +static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd, + abi_ulong target_addr) { struct target_semid_ds *target_sd; - lock_user_struct(target_sd, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) + return -TARGET_EFAULT; target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr); 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 0; } -static inline void host_to_target_semid_ds(abi_ulong target_addr, - struct semid_ds *host_sd) +static inline abi_long host_to_target_semid_ds(abi_ulong target_addr, + struct semid_ds *host_sd) { struct target_semid_ds *target_sd; - lock_user_struct(target_sd, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) + return -TARGET_EFAULT; host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)); 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 0; } union semun { @@ -1453,67 +1520,75 @@ union target_semun { unsigned short int *array; }; -static inline void target_to_host_semun(int cmd, - union semun *host_su, - abi_ulong target_addr, - struct semid_ds *ds) +static inline abi_long target_to_host_semun(int cmd, + union semun *host_su, + abi_ulong target_addr, + struct semid_ds *ds) { union target_semun *target_su; switch( cmd ) { case IPC_STAT: case IPC_SET: - lock_user_struct(target_su, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) + return -TARGET_EFAULT; target_to_host_semid_ds(ds,target_su->buf); 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 (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) + return -TARGET_EFAULT; 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 (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) + return -TARGET_EFAULT; *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 0; } -static inline void host_to_target_semun(int cmd, - abi_ulong target_addr, - union semun *host_su, - struct semid_ds *ds) +static inline abi_long host_to_target_semun(int cmd, + abi_ulong target_addr, + union semun *host_su, + struct semid_ds *ds) { union target_semun *target_su; switch( cmd ) { case IPC_STAT: case IPC_SET: - lock_user_struct(target_su, target_addr, 0); + if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) + return -TARGET_EFAULT; host_to_target_semid_ds(target_su->buf,ds); unlock_user_struct(target_su, target_addr, 1); break; case GETVAL: case SETVAL: - lock_user_struct(target_su, target_addr, 0); + if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) + return -TARGET_EFAULT; 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 (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) + return -TARGET_EFAULT; *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 0; } static inline abi_long do_semctl(int first, int second, int third, @@ -1580,12 +1655,13 @@ struct target_msqid_ds abi_ulong __unused5; }; -static inline void target_to_host_msqid_ds(struct msqid_ds *host_md, - abi_ulong target_addr) +static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md, + abi_ulong target_addr) { struct target_msqid_ds *target_md; - lock_user_struct(target_md, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1)) + return -TARGET_EFAULT; target_to_host_ipc_perm(&(host_md->msg_perm),target_addr); host_md->msg_stime = tswapl(target_md->msg_stime); host_md->msg_rtime = tswapl(target_md->msg_rtime); @@ -1596,14 +1672,16 @@ static inline void target_to_host_msqid_ds(struct msqid_ds *host_md, 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 0; } -static inline void host_to_target_msqid_ds(abi_ulong target_addr, - struct msqid_ds *host_md) +static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr, + struct msqid_ds *host_md) { struct target_msqid_ds *target_md; - lock_user_struct(target_md, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0)) + return -TARGET_EFAULT; host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)); target_md->msg_stime = tswapl(host_md->msg_stime); target_md->msg_rtime = tswapl(host_md->msg_rtime); @@ -1614,6 +1692,7 @@ static inline void host_to_target_msqid_ds(abi_ulong target_addr, 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 0; } static inline abi_long do_msgctl(int first, int second, abi_long ptr) @@ -1645,7 +1724,8 @@ static inline abi_long do_msgsnd(int msqid, abi_long msgp, struct msgbuf *host_mb; abi_long ret = 0; - lock_user_struct(target_mb,msgp,0); + if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0)) + return -TARGET_EFAULT; host_mb = malloc(msgsz+sizeof(long)); host_mb->mtype = tswapl(target_mb->mtype); memcpy(host_mb->mtext,target_mb->mtext,msgsz); @@ -1661,18 +1741,30 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp, int msgflg) { struct target_msgbuf *target_mb; + char *target_mtext; struct msgbuf *host_mb; abi_long ret = 0; - lock_user_struct(target_mb, msgp, 0); + if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0)) + return -TARGET_EFAULT; host_mb = malloc(msgsz+sizeof(long)); ret = get_errno(msgrcv(msqid, host_mb, msgsz, 1, msgflg)); - if (ret > 0) + if (ret > 0) { + abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong); + target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0); + if (!target_mtext) { + ret = -TARGET_EFAULT; + goto end; + } memcpy(target_mb->mtext, host_mb->mtext, ret); + unlock_user(target_mtext, target_mtext_addr, ret); + } target_mb->mtype = tswapl(host_mb->mtype); free(host_mb); - unlock_user_struct(target_mb, msgp, 0); +end: + if (target_mb) + unlock_user_struct(target_mb, msgp, 1); return ret; } @@ -1693,7 +1785,7 @@ static abi_long do_ipc(unsigned int call, int first, switch (call) { case IPCOP_semop: - ret = get_errno(semop(first,(struct sembuf *) ptr, second)); + ret = get_errno(semop(first,(struct sembuf *)g2h(ptr), second)); break; case IPCOP_semget: @@ -1723,13 +1815,14 @@ static abi_long do_ipc(unsigned int call, int first, case IPCOP_msgrcv: { + /* XXX: this code is not correct */ struct ipc_kludge { void *__unbounded msgp; long int msgtyp; }; - struct ipc_kludge *foo = (struct ipc_kludge *) ptr; + struct ipc_kludge *foo = (struct ipc_kludge *)g2h(ptr); struct msgbuf *msgp = (struct msgbuf *) foo->msgp; ret = do_msgrcv(first, (long)msgp, second, 0, third); @@ -1761,7 +1854,7 @@ static abi_long do_ipc(unsigned int call, int first, break; } } - if (put_user(raddr, (abi_ulong *)third)) + if (put_user(raddr, third, abi_ulong)) return -TARGET_EFAULT; ret = 0; break; @@ -1883,25 +1976,33 @@ static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg) case IOC_R: ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); if (!is_error(ret)) { - argptr = lock_user(arg, target_size, 0); + argptr = lock_user(VERIFY_WRITE, arg, target_size, 0); + if (!argptr) + return -TARGET_EFAULT; thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); unlock_user(argptr, arg, target_size); } break; case IOC_W: - argptr = lock_user(arg, target_size, 1); + argptr = lock_user(VERIFY_READ, arg, target_size, 1); + if (!argptr) + return -TARGET_EFAULT; thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); unlock_user(argptr, arg, 0); ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); break; default: case IOC_RW: - argptr = lock_user(arg, target_size, 1); + argptr = lock_user(VERIFY_READ, arg, target_size, 1); + if (!argptr) + return -TARGET_EFAULT; thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); unlock_user(argptr, arg, 0); ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); if (!is_error(ret)) { - argptr = lock_user(arg, target_size, 0); + argptr = lock_user(VERIFY_WRITE, arg, target_size, 0); + if (!argptr) + return -TARGET_EFAULT; thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); unlock_user(argptr, arg, target_size); } @@ -2138,8 +2239,10 @@ static int read_ldt(abi_ulong ptr, unsigned long bytecount) size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE; if (size > bytecount) size = bytecount; - p = lock_user(ptr, size, 0); - /* ??? Shoudl this by byteswapped? */ + p = lock_user(VERIFY_WRITE, ptr, size, 0); + if (!p) + return -EFAULT; + /* ??? Should this by byteswapped? */ memcpy(p, ldt_table, size); unlock_user(p, ptr, size); return size; @@ -2158,7 +2261,8 @@ static int write_ldt(CPUX86State *env, if (bytecount != sizeof(ldt_info)) return -EINVAL; - lock_user_struct(target_ldt_info, ptr, 1); + if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1)) + return -EFAULT; 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); @@ -2365,7 +2469,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) switch(cmd) { case TARGET_F_GETLK: - lock_user_struct(target_fl, arg, 1); + if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1)) + return -TARGET_EFAULT; fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswapl(target_fl->l_start); @@ -2374,7 +2479,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) unlock_user_struct(target_fl, arg, 0); ret = fcntl(fd, cmd, &fl); if (ret == 0) { - lock_user_struct(target_fl, arg, 0); + if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0)) + return -TARGET_EFAULT; target_fl->l_type = tswap16(fl.l_type); target_fl->l_whence = tswap16(fl.l_whence); target_fl->l_start = tswapl(fl.l_start); @@ -2386,7 +2492,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) case TARGET_F_SETLK: case TARGET_F_SETLKW: - lock_user_struct(target_fl, arg, 1); + if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1)) + return -TARGET_EFAULT; fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswapl(target_fl->l_start); @@ -2397,7 +2504,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) break; case TARGET_F_GETLK64: - lock_user_struct(target_fl64, arg, 1); + if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1)) + return -TARGET_EFAULT; 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); @@ -2406,7 +2514,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) unlock_user_struct(target_fl64, arg, 0); ret = fcntl(fd, cmd >> 1, &fl64); if (ret == 0) { - lock_user_struct(target_fl64, arg, 0); + if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0)) + return -TARGET_EFAULT; 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); @@ -2417,14 +2526,15 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) break; case TARGET_F_SETLK64: case TARGET_F_SETLKW64: - lock_user_struct(target_fl64, arg, 1); + if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1)) + return -TARGET_EFAULT; 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); fl64.l_len = tswapl(target_fl64->l_len); fl64.l_pid = tswap16(target_fl64->l_pid); unlock_user_struct(target_fl64, arg, 0); - ret = fcntl(fd, cmd >> 1, &fl64); + ret = fcntl(fd, cmd >> 1, &fl64); break; case F_GETFL: @@ -2577,23 +2687,25 @@ static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1, } #endif -static inline void target_to_host_timespec(struct timespec *host_ts, - abi_ulong target_addr) +static inline abi_long target_to_host_timespec(struct timespec *host_ts, + abi_ulong target_addr) { struct target_timespec *target_ts; - lock_user_struct(target_ts, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1)) + return -TARGET_EFAULT; 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(abi_ulong target_addr, - struct timespec *host_ts) +static inline abi_long host_to_target_timespec(abi_ulong target_addr, + struct timespec *host_ts) { struct target_timespec *target_ts; - lock_user_struct(target_ts, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0)) + return -TARGET_EFAULT; 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); @@ -2629,17 +2741,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; case TARGET_NR_read: page_unprotect_range(arg2, arg3); - p = lock_user(arg2, arg3, 0); + if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) + goto efault; ret = get_errno(read(arg1, p, arg3)); unlock_user(p, arg2, ret); break; case TARGET_NR_write: - p = lock_user(arg2, arg3, 1); + if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) + goto efault; ret = get_errno(write(arg1, p, arg3)); unlock_user(p, arg2, 0); break; case TARGET_NR_open: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) { + return -TARGET_EFAULT; + goto fail; + } ret = get_errno(open(path(p), target_to_host_bitmask(arg2, fcntl_flags_tbl), arg3)); @@ -2647,21 +2764,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #if defined(TARGET_NR_openat) && defined(__NR_openat) case TARGET_NR_openat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_openat(arg1, - path(p), - target_to_host_bitmask(arg3, fcntl_flags_tbl), - arg4)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_openat(arg1, + path(p), + target_to_host_bitmask(arg3, fcntl_flags_tbl), + arg4)); + unlock_user(p, arg2, 0); break; #endif case TARGET_NR_close: @@ -2685,7 +2794,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_creat /* not on alpha */ case TARGET_NR_creat: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(creat(p, arg2)); unlock_user(p, arg1, 0); break; @@ -2695,54 +2805,43 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, void * p2; p = lock_user_string(arg1); p2 = lock_user_string(arg2); - ret = get_errno(link(p, p2)); + if (!p || !p2) + ret = -TARGET_EFAULT; + else + ret = get_errno(link(p, p2)); unlock_user(p2, arg2, 0); unlock_user(p, arg1, 0); } break; #if defined(TARGET_NR_linkat) && defined(__NR_linkat) case TARGET_NR_linkat: - if (!arg2 || !arg4) { - ret = -TARGET_EFAULT; - goto fail; - } { void * p2 = NULL; + if (!arg2 || !arg4) + goto efault; p = lock_user_string(arg2); p2 = lock_user_string(arg4); - if (!access_ok(VERIFY_READ, p, 1) - || !access_ok(VERIFY_READ, p2, 1)) - /* Don't "goto fail" so that cleanup can happen. */ + if (!p || !p2) ret = -TARGET_EFAULT; else ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5)); - if (p2) - unlock_user(p, arg2, 0); - if (p) - unlock_user(p2, arg4, 0); + unlock_user(p, arg2, 0); + unlock_user(p2, arg4, 0); } break; #endif case TARGET_NR_unlink: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(unlink(p)); unlock_user(p, arg1, 0); break; #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat) case TARGET_NR_unlinkat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_unlinkat(arg1, p, arg3)); - if (p) - unlock_user(p, arg2, 0); - break; + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_unlinkat(arg1, p, arg3)); + unlock_user(p, arg2, 0); #endif case TARGET_NR_execve: { @@ -2771,7 +2870,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, addr = tgetl(gp); if (!addr) break; - *q = lock_user_string(addr); + if (!(*q = lock_user_string(addr))) { + ret = -TARGET_EFAULT; + goto execve_fail; + } } *q = NULL; @@ -2780,14 +2882,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, addr = tgetl(gp); if (!addr) break; - *q = lock_user_string(addr); + if (!(*q = lock_user_string(addr))) { + ret = -TARGET_EFAULT; + goto execve_fail; + } } *q = NULL; - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) { + ret = -TARGET_EFAULT; + goto execve_fail; + } ret = get_errno(execve(p, argp, envp)); unlock_user(p, arg1, 0); + execve_fail: for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) { addr = tgetl(gp); @@ -2801,7 +2910,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; case TARGET_NR_chdir: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(chdir(p)); unlock_user(p, arg1, 0); break; @@ -2816,28 +2926,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR_mknod: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(mknod(p, arg2, arg3)); unlock_user(p, arg1, 0); break; #if defined(TARGET_NR_mknodat) && defined(__NR_mknodat) case TARGET_NR_mknodat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_mknodat(arg1, p, arg3, arg4)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_mknodat(arg1, p, arg3, arg4)); + unlock_user(p, arg2, 0); break; #endif case TARGET_NR_chmod: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(chmod(p, arg2)); unlock_user(p, arg1, 0); break; @@ -2866,15 +2970,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, p = lock_user_string(arg1); p2 = lock_user_string(arg2); p3 = lock_user_string(arg3); - ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, (const void *)arg5)); - unlock_user(p, arg1, 0); - unlock_user(p2, arg2, 0); - unlock_user(p3, arg3, 0); + if (!p || !p2 || !p3) + ret = -TARGET_EFAULT; + else + /* FIXME - arg5 should be locked, but it isn't clear how to + * do that since it's not guaranteed to be a NULL-terminated + * string. + */ + ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5))); + unlock_user(p, arg1, 0); + unlock_user(p2, arg2, 0); + unlock_user(p3, arg3, 0); break; } #ifdef TARGET_NR_umount case TARGET_NR_umount: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(umount(p)); unlock_user(p, arg1, 0); break; @@ -2910,7 +3022,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct utimbuf tbuf, *host_tbuf; struct target_utimbuf *target_tbuf; if (arg2) { - lock_user_struct(target_tbuf, arg2, 1); + if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1)) + goto efault; tbuf.actime = tswapl(target_tbuf->actime); tbuf.modtime = tswapl(target_tbuf->modtime); unlock_user_struct(target_tbuf, arg2, 0); @@ -2918,7 +3031,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else { host_tbuf = NULL; } - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(utime(p, host_tbuf)); unlock_user(p, arg1, 0); } @@ -2935,7 +3049,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else { tvp = NULL; } - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(utimes(p, tvp)); unlock_user(p, arg1, 0); } @@ -2949,24 +3064,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto unimplemented; #endif case TARGET_NR_access: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(access(p, arg2)); unlock_user(p, arg1, 0); break; #if defined(TARGET_NR_faccessat) && defined(__NR_faccessat) case TARGET_NR_faccessat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_faccessat(arg1, p, arg3, arg4)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_faccessat(arg1, p, arg3, arg4)); + unlock_user(p, arg2, 0); break; #endif #ifdef TARGET_NR_nice /* not on alpha */ @@ -2990,57 +3098,46 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, void *p2; p = lock_user_string(arg1); p2 = lock_user_string(arg2); - ret = get_errno(rename(p, p2)); + if (!p || !p2) + ret = -TARGET_EFAULT; + else + ret = get_errno(rename(p, p2)); unlock_user(p2, arg2, 0); unlock_user(p, arg1, 0); } break; #if defined(TARGET_NR_renameat) && defined(__NR_renameat) case TARGET_NR_renameat: - if (!arg2 || !arg4) { - ret = -TARGET_EFAULT; - goto fail; - } { - void *p2 = NULL; + void *p2; p = lock_user_string(arg2); p2 = lock_user_string(arg4); - if (!access_ok(VERIFY_READ, p, 1) - || !access_ok(VERIFY_READ, p2, 1)) - /* Don't "goto fail" so that cleanup can happen. */ + if (!p || !p2) ret = -TARGET_EFAULT; else ret = get_errno(sys_renameat(arg1, p, arg3, p2)); - if (p2) - unlock_user(p2, arg4, 0); - if (p) - unlock_user(p, arg2, 0); + unlock_user(p2, arg4, 0); + unlock_user(p, arg2, 0); } break; #endif case TARGET_NR_mkdir: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(mkdir(p, arg2)); unlock_user(p, arg1, 0); break; #if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat) case TARGET_NR_mkdirat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_mkdirat(arg1, p, arg3)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_mkdirat(arg1, p, arg3)); + unlock_user(p, arg2, 0); break; #endif case TARGET_NR_rmdir: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(rmdir(p)); unlock_user(p, arg1, 0); break; @@ -3069,7 +3166,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct tms tms; ret = get_errno(times(&tms)); if (arg1) { - tmsp = lock_user(arg1, sizeof(struct target_tms), 0); + tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0); + if (!tmsp) + goto efault; tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime)); tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime)); tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime)); @@ -3088,13 +3187,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto unimplemented; #endif case TARGET_NR_acct: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(acct(path(p))); unlock_user(p, arg1, 0); break; #ifdef TARGET_NR_umount2 /* not on alpha */ case TARGET_NR_umount2: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(umount2(p, arg2)); unlock_user(p, arg1, 0); break; @@ -3128,7 +3229,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(umask(arg1)); break; case TARGET_NR_chroot: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(chroot(p)); unlock_user(p, arg1, 0); break; @@ -3155,7 +3257,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct target_old_sigaction *old_act; struct target_sigaction act, oact, *pact; if (arg2) { - lock_user_struct(old_act, arg2, 1); + if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) + goto efault; act._sa_handler = old_act->_sa_handler; target_siginitset(&act.sa_mask, old_act->sa_mask); act.sa_flags = old_act->sa_flags; @@ -3167,7 +3270,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } ret = get_errno(do_sigaction(arg1, pact, &oact)); if (!is_error(ret) && arg3) { - lock_user_struct(old_act, arg3, 0); + if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) + goto efault; old_act->_sa_handler = oact._sa_handler; old_act->sa_mask = oact.sa_mask.sig[0]; old_act->sa_flags = oact.sa_flags; @@ -3178,7 +3282,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct target_sigaction act, oact, *pact, *old_act; if (arg2) { - lock_user_struct(old_act, arg2, 1); + if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) + goto efault; 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; @@ -3191,7 +3296,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(do_sigaction(arg1, pact, &oact)); if (!is_error(ret) && arg3) { - lock_user_struct(old_act, arg3, 0); + if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) + goto efault; 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]; @@ -3209,18 +3315,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct target_sigaction *act; struct target_sigaction *oact; - if (arg2) - lock_user_struct(act, arg2, 1); - else + if (arg2) { + if (!lock_user_struct(VERIFY_READ, act, arg2, 1)) + goto efault; + } else act = NULL; - if (arg3) - lock_user_struct(oact, arg3, 0); - else + if (arg3) { + if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) { + ret = -TARGET_EFAULT; + goto rt_sigaction_fail; + } + } else oact = NULL; ret = get_errno(do_sigaction(arg1, act, oact)); - if (arg2) + rt_sigaction_fail: + if (act) unlock_user_struct(act, arg2, 0); - if (arg3) + if (oact) unlock_user_struct(oact, arg3, 1); } break; @@ -3270,7 +3381,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = -TARGET_EINVAL; goto fail; } - p = lock_user(arg2, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_old_sigset(&set, p); unlock_user(p, arg2, 0); set_ptr = &set; @@ -3280,7 +3392,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } ret = get_errno(sigprocmask(arg1, set_ptr, &oldset)); if (!is_error(ret) && arg3) { - p = lock_user(arg3, sizeof(target_sigset_t), 0); + if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0))) + goto efault; host_to_target_old_sigset(p, &oldset); unlock_user(p, arg3, sizeof(target_sigset_t)); } @@ -3307,7 +3420,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = -TARGET_EINVAL; goto fail; } - p = lock_user(arg2, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_sigset(&set, p); unlock_user(p, arg2, 0); set_ptr = &set; @@ -3317,7 +3431,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } ret = get_errno(sigprocmask(how, set_ptr, &oldset)); if (!is_error(ret) && arg3) { - p = lock_user(arg3, sizeof(target_sigset_t), 0); + if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0))) + goto efault; host_to_target_sigset(p, &oldset); unlock_user(p, arg3, sizeof(target_sigset_t)); } @@ -3329,7 +3444,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, sigset_t set; ret = get_errno(sigpending(&set)); if (!is_error(ret)) { - p = lock_user(arg1, sizeof(target_sigset_t), 0); + if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0))) + goto efault; host_to_target_old_sigset(p, &set); unlock_user(p, arg1, sizeof(target_sigset_t)); } @@ -3341,7 +3457,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, sigset_t set; ret = get_errno(sigpending(&set)); if (!is_error(ret)) { - p = lock_user(arg1, sizeof(target_sigset_t), 0); + if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0))) + goto efault; host_to_target_sigset(p, &set); unlock_user(p, arg1, sizeof(target_sigset_t)); } @@ -3351,7 +3468,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_sigsuspend: { sigset_t set; - p = lock_user(arg1, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_old_sigset(&set, p); unlock_user(p, arg1, 0); ret = get_errno(sigsuspend(&set)); @@ -3361,7 +3479,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_rt_sigsuspend: { sigset_t set; - p = lock_user(arg1, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_sigset(&set, p); unlock_user(p, arg1, 0); ret = get_errno(sigsuspend(&set)); @@ -3373,7 +3492,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct timespec uts, *puts; siginfo_t uinfo; - p = lock_user(arg1, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_sigset(&set, p); unlock_user(p, arg1, 0); if (arg3) { @@ -3384,7 +3504,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } ret = get_errno(sigtimedwait(&set, &uinfo, puts)); if (!is_error(ret) && arg2) { - p = lock_user(arg2, sizeof(target_sigset_t), 0); + if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_sigset_t), 0))) + goto efault; host_to_target_siginfo(p, &uinfo); unlock_user(p, arg2, sizeof(target_sigset_t)); } @@ -3393,7 +3514,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_rt_sigqueueinfo: { siginfo_t uinfo; - p = lock_user(arg3, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_siginfo(&uinfo, p); unlock_user(p, arg1, 0); ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo)); @@ -3410,7 +3532,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = do_rt_sigreturn(cpu_env); break; case TARGET_NR_sethostname: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(sethostname(p, arg2)); unlock_user(p, arg1, 0); break; @@ -3420,7 +3543,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, int resource = arg1; struct target_rlimit *target_rlim; struct rlimit rlim; - lock_user_struct(target_rlim, arg2, 1); + if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1)) + goto efault; rlim.rlim_cur = tswapl(target_rlim->rlim_cur); rlim.rlim_max = tswapl(target_rlim->rlim_max); unlock_user_struct(target_rlim, arg2, 0); @@ -3436,7 +3560,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(getrlimit(resource, &rlim)); if (!is_error(ret)) { - lock_user_struct(target_rlim, arg2, 0); + if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0)) + goto efault; rlim.rlim_cur = tswapl(target_rlim->rlim_cur); rlim.rlim_max = tswapl(target_rlim->rlim_max); unlock_user_struct(target_rlim, arg2, 1); @@ -3475,7 +3600,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_ulong inp, outp, exp, tvp; long nsel; - lock_user_struct(sel, arg1, 1); + if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) + goto efault; nsel = tswapl(sel->n); inp = tswapl(sel->inp); outp = tswapl(sel->outp); @@ -3491,31 +3617,26 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, void *p2; p = lock_user_string(arg1); p2 = lock_user_string(arg2); - ret = get_errno(symlink(p, p2)); + if (!p || !p2) + ret = -TARGET_EFAULT; + else + ret = get_errno(symlink(p, p2)); unlock_user(p2, arg2, 0); unlock_user(p, arg1, 0); } break; #if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat) case TARGET_NR_symlinkat: - if (!arg1 || !arg3) { - ret = -TARGET_EFAULT; - goto fail; - } { - void *p2 = NULL; + void *p2; p = lock_user_string(arg1); p2 = lock_user_string(arg3); - if (!access_ok(VERIFY_READ, p, 1) - || !access_ok(VERIFY_READ, p2, 1)) - /* Don't "goto fail" so that cleanup can happen. */ + if (!p || !p2) ret = -TARGET_EFAULT; else ret = get_errno(sys_symlinkat(p, arg2, p2)); - if (p2) - unlock_user(p2, arg3, 0); - if (p) - unlock_user(p, arg1, 0); + unlock_user(p2, arg3, 0); + unlock_user(p, arg1, 0); } break; #endif @@ -3527,32 +3648,27 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { void *p2; p = lock_user_string(arg1); - p2 = lock_user(arg2, arg3, 0); - ret = get_errno(readlink(path(p), p2, arg3)); + p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0); + if (!p || !p2) + ret = -TARGET_EFAULT; + else + ret = get_errno(readlink(path(p), p2, arg3)); unlock_user(p2, arg2, ret); unlock_user(p, arg1, 0); } break; #if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat) case TARGET_NR_readlinkat: - if (!arg2 || !arg3) { - ret = -TARGET_EFAULT; - goto fail; - } { - void *p2 = NULL; + void *p2; p = lock_user_string(arg2); - p2 = lock_user(arg3, arg4, 0); - if (!access_ok(VERIFY_READ, p, 1) - || !access_ok(VERIFY_READ, p2, 1)) - /* Don't "goto fail" so that cleanup can happen. */ + p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0); + if (!p || !p2) ret = -TARGET_EFAULT; else ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4)); - if (p2) - unlock_user(p2, arg3, ret); - if (p) - unlock_user(p, arg2, 0); + unlock_user(p2, arg3, ret); + unlock_user(p, arg2, 0); } break; #endif @@ -3562,7 +3678,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_swapon case TARGET_NR_swapon: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(swapon(p, arg2)); unlock_user(p, arg1, 0); break; @@ -3579,7 +3696,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { abi_ulong *v; abi_ulong v1, v2, v3, v4, v5, v6; - v = lock_user(arg1, 6 * sizeof(abi_ulong), 1); + if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1))) + goto efault; v1 = tswapl(v[0]); v2 = tswapl(v[1]); v3 = tswapl(v[2]); @@ -3650,7 +3768,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR_truncate: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(truncate(p, arg2)); unlock_user(p, arg1, 0); break; @@ -3662,18 +3781,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat) case TARGET_NR_fchmodat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_fchmodat(arg1, p, arg3, arg4)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_fchmodat(arg1, p, arg3, arg4)); + unlock_user(p, arg2, 0); break; #endif case TARGET_NR_getpriority: @@ -3690,25 +3801,26 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto unimplemented; #endif case TARGET_NR_statfs: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(statfs(path(p), &stfs)); unlock_user(p, arg1, 0); convert_statfs: if (!is_error(ret)) { struct target_statfs *target_stfs; - lock_user_struct(target_stfs, arg2, 0); - /* ??? put_user is probably wrong. */ - put_user(stfs.f_type, &target_stfs->f_type); - put_user(stfs.f_bsize, &target_stfs->f_bsize); - put_user(stfs.f_blocks, &target_stfs->f_blocks); - put_user(stfs.f_bfree, &target_stfs->f_bfree); - put_user(stfs.f_bavail, &target_stfs->f_bavail); - put_user(stfs.f_files, &target_stfs->f_files); - put_user(stfs.f_ffree, &target_stfs->f_ffree); - put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); - put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); - put_user(stfs.f_namelen, &target_stfs->f_namelen); + if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0)) + goto efault; + __put_user(stfs.f_type, &target_stfs->f_type); + __put_user(stfs.f_bsize, &target_stfs->f_bsize); + __put_user(stfs.f_blocks, &target_stfs->f_blocks); + __put_user(stfs.f_bfree, &target_stfs->f_bfree); + __put_user(stfs.f_bavail, &target_stfs->f_bavail); + __put_user(stfs.f_files, &target_stfs->f_files); + __put_user(stfs.f_ffree, &target_stfs->f_ffree); + __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); + __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); + __put_user(stfs.f_namelen, &target_stfs->f_namelen); unlock_user_struct(target_stfs, arg2, 1); } break; @@ -3717,26 +3829,27 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto convert_statfs; #ifdef TARGET_NR_statfs64 case TARGET_NR_statfs64: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(statfs(path(p), &stfs)); unlock_user(p, arg1, 0); convert_statfs64: if (!is_error(ret)) { struct target_statfs64 *target_stfs; - lock_user_struct(target_stfs, arg3, 0); - /* ??? put_user is probably wrong. */ - put_user(stfs.f_type, &target_stfs->f_type); - put_user(stfs.f_bsize, &target_stfs->f_bsize); - put_user(stfs.f_blocks, &target_stfs->f_blocks); - put_user(stfs.f_bfree, &target_stfs->f_bfree); - put_user(stfs.f_bavail, &target_stfs->f_bavail); - put_user(stfs.f_files, &target_stfs->f_files); - put_user(stfs.f_ffree, &target_stfs->f_ffree); - put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); - put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); - put_user(stfs.f_namelen, &target_stfs->f_namelen); - unlock_user_struct(target_stfs, arg3, 0); + if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0)) + goto efault; + __put_user(stfs.f_type, &target_stfs->f_type); + __put_user(stfs.f_bsize, &target_stfs->f_bsize); + __put_user(stfs.f_blocks, &target_stfs->f_blocks); + __put_user(stfs.f_bfree, &target_stfs->f_bfree); + __put_user(stfs.f_bavail, &target_stfs->f_bavail); + __put_user(stfs.f_files, &target_stfs->f_files); + __put_user(stfs.f_ffree, &target_stfs->f_ffree); + __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); + __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); + __put_user(stfs.f_namelen, &target_stfs->f_namelen); + unlock_user_struct(target_stfs, arg3, 1); } break; case TARGET_NR_fstatfs64: @@ -3839,7 +3952,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif case TARGET_NR_syslog: - p = lock_user_string(arg2); + if (!(p = lock_user_string(arg2))) + goto efault; ret = get_errno(sys_syslog((int)arg1, p, (int)arg3)); unlock_user(p, arg2, 0); break; @@ -3880,12 +3994,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; case TARGET_NR_stat: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(stat(path(p), &st)); unlock_user(p, arg1, 0); goto do_stat; case TARGET_NR_lstat: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(lstat(path(p), &st)); unlock_user(p, arg1, 0); goto do_stat; @@ -3896,7 +4012,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!is_error(ret)) { struct target_stat *target_st; - lock_user_struct(target_st, arg2, 0); + if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0)) + goto efault; #if defined(TARGET_MIPS) || (defined(TARGET_SPARC64) && !defined(TARGET_ABI32)) target_st->st_dev = tswap32(st.st_dev); #else @@ -3979,7 +4096,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #ifdef TARGET_NR_swapoff case TARGET_NR_swapoff: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(swapoff(p)); unlock_user(p, arg1, 0); break; @@ -3991,8 +4109,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(sysinfo(&value)); if (!is_error(ret) && arg1) { - /* ??? __put_user is probably wrong. */ - lock_user_struct(target_value, arg1, 0); + if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0)) + goto efault; __put_user(value.uptime, &target_value->uptime); __put_user(value.loads[0], &target_value->loads[0]); __put_user(value.loads[1], &target_value->loads[1]); @@ -4030,7 +4148,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR_setdomainname: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(setdomainname(p, arg2)); unlock_user(p, arg1, 0); break; @@ -4039,7 +4158,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct new_utsname * buf; - lock_user_struct(buf, arg1, 0); + if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0)) + goto efault; ret = get_errno(sys_uname(buf)); if (!is_error(ret)) { /* Overrite the native machine name with whatever is being @@ -4124,7 +4244,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, dirp = malloc(count); if (!dirp) { - ret = -TARGET_EFAULT; + ret = -TARGET_ENOMEM; goto fail; } @@ -4138,7 +4258,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, count1 = 0; de = dirp; - target_dirp = lock_user(arg2, count, 0); + if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) + goto efault; tde = target_dirp; while (len > 0) { reclen = de->d_reclen; @@ -4157,8 +4278,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, count1 += treclen; } ret = count1; + unlock_user(target_dirp, arg2, ret); } - unlock_user(target_dirp, arg2, ret); free(dirp); } #else @@ -4166,7 +4287,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct dirent *dirp; abi_long count = arg3; - dirp = lock_user(arg2, count, 0); + if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) + goto efault; ret = get_errno(sys_getdents(arg1, dirp, count)); if (!is_error(ret)) { struct dirent *de; @@ -4193,7 +4315,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct dirent64 *dirp; abi_long count = arg3; - dirp = lock_user(arg2, count, 0); + if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) + goto efault; ret = get_errno(sys_getdents64(arg1, dirp, count)); if (!is_error(ret)) { struct dirent64 *de; @@ -4229,7 +4352,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct pollfd *pfd; unsigned int i; - target_pfd = lock_user(arg1, sizeof(struct target_pollfd) * nfds, 1); + target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1); + if (!target_pfd) + goto efault; pfd = alloca(sizeof(struct pollfd) * nfds); for(i = 0; i < nfds; i++) { pfd[i].fd = tswap32(target_pfd[i].fd); @@ -4258,7 +4383,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct iovec *vec; vec = alloca(count * sizeof(struct iovec)); - lock_iovec(vec, arg2, count, 0); + lock_iovec(VERIFY_WRITE, vec, arg2, count, 0); ret = get_errno(readv(arg1, vec, count)); unlock_iovec(vec, arg2, count, 1); } @@ -4269,7 +4394,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct iovec *vec; vec = alloca(count * sizeof(struct iovec)); - lock_iovec(vec, arg2, count, 1); + lock_iovec(VERIFY_READ, vec, arg2, count, 1); ret = get_errno(writev(arg1, vec, count)); unlock_iovec(vec, arg2, count, 0); } @@ -4292,7 +4417,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct sched_param *target_schp; struct sched_param schp; - lock_user_struct(target_schp, arg2, 1); + if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1)) + goto efault; schp.sched_priority = tswap32(target_schp->sched_priority); unlock_user_struct(target_schp, arg2, 0); ret = get_errno(sched_setparam(arg1, &schp)); @@ -4304,7 +4430,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct sched_param schp; ret = get_errno(sched_getparam(arg1, &schp)); if (!is_error(ret)) { - lock_user_struct(target_schp, arg2, 0); + if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0)) + goto efault; target_schp->sched_priority = tswap32(schp.sched_priority); unlock_user_struct(target_schp, arg2, 1); } @@ -4314,7 +4441,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct sched_param *target_schp; struct sched_param schp; - lock_user_struct(target_schp, arg3, 1); + if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1)) + goto efault; schp.sched_priority = tswap32(target_schp->sched_priority); unlock_user_struct(target_schp, arg3, 0); ret = get_errno(sched_setscheduler(arg1, arg2, &schp)); @@ -4378,18 +4506,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_pread case TARGET_NR_pread: page_unprotect_range(arg2, arg3); - p = lock_user(arg2, arg3, 0); + if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) + goto efault; ret = get_errno(pread(arg1, p, arg3, arg4)); unlock_user(p, arg2, ret); break; case TARGET_NR_pwrite: - p = lock_user(arg2, arg3, 1); + if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) + goto efault; ret = get_errno(pwrite(arg1, p, arg3, arg4)); unlock_user(p, arg2, 0); break; #endif case TARGET_NR_getcwd: - p = lock_user(arg1, arg2, 0); + if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0))) + goto efault; ret = get_errno(sys_getcwd1(p, arg2)); unlock_user(p, arg1, ret); break; @@ -4400,9 +4531,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_sigaltstack: #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \ defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) - ret = do_sigaltstack((struct target_sigaltstack *)arg1, - (struct target_sigaltstack *)arg2, - get_sp_from_cpustate((CPUState *)cpu_env)); + ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUState *)cpu_env)); break; #else goto unimplemented; @@ -4429,7 +4558,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(getrlimit(arg1, &rlim)); if (!is_error(ret)) { struct target_rlimit *target_rlim; - lock_user_struct(target_rlim, arg2, 0); + if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0)) + goto efault; target_rlim->rlim_cur = tswapl(rlim.rlim_cur); target_rlim->rlim_max = tswapl(rlim.rlim_max); unlock_user_struct(target_rlim, arg2, 1); @@ -4439,7 +4569,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_truncate64 case TARGET_NR_truncate64: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = target_truncate64(cpu_env, p, arg2, arg3, arg4); unlock_user(p, arg1, 0); break; @@ -4451,14 +4582,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_stat64 case TARGET_NR_stat64: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(stat(path(p), &st)); unlock_user(p, arg1, 0); goto do_stat64; #endif #ifdef TARGET_NR_lstat64 case TARGET_NR_lstat64: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(lstat(path(p), &st)); unlock_user(p, arg1, 0); goto do_stat64; @@ -4472,52 +4605,53 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { struct target_eabi_stat64 *target_st; - lock_user_struct(target_st, arg2, 1); + + if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0)) + goto efault; memset(target_st, 0, sizeof(struct target_eabi_stat64)); - /* put_user is probably wrong. */ - put_user(st.st_dev, &target_st->st_dev); - put_user(st.st_ino, &target_st->st_ino); + __put_user(st.st_dev, &target_st->st_dev); + __put_user(st.st_ino, &target_st->st_ino); #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO - put_user(st.st_ino, &target_st->__st_ino); -#endif - put_user(st.st_mode, &target_st->st_mode); - put_user(st.st_nlink, &target_st->st_nlink); - put_user(st.st_uid, &target_st->st_uid); - put_user(st.st_gid, &target_st->st_gid); - put_user(st.st_rdev, &target_st->st_rdev); - /* XXX: better use of kernel struct */ - put_user(st.st_size, &target_st->st_size); - put_user(st.st_blksize, &target_st->st_blksize); - put_user(st.st_blocks, &target_st->st_blocks); - put_user(st.st_atime, &target_st->target_st_atime); - put_user(st.st_mtime, &target_st->target_st_mtime); - put_user(st.st_ctime, &target_st->target_st_ctime); - unlock_user_struct(target_st, arg2, 0); + __put_user(st.st_ino, &target_st->__st_ino); +#endif + __put_user(st.st_mode, &target_st->st_mode); + __put_user(st.st_nlink, &target_st->st_nlink); + __put_user(st.st_uid, &target_st->st_uid); + __put_user(st.st_gid, &target_st->st_gid); + __put_user(st.st_rdev, &target_st->st_rdev); + __put_user(st.st_size, &target_st->st_size); + __put_user(st.st_blksize, &target_st->st_blksize); + __put_user(st.st_blocks, &target_st->st_blocks); + __put_user(st.st_atime, &target_st->target_st_atime); + __put_user(st.st_mtime, &target_st->target_st_mtime); + __put_user(st.st_ctime, &target_st->target_st_ctime); + unlock_user_struct(target_st, arg2, 1); } else #endif { struct target_stat64 *target_st; - lock_user_struct(target_st, arg2, 1); + + if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0)) + goto efault; memset(target_st, 0, sizeof(struct target_stat64)); - /* ??? put_user is probably wrong. */ - put_user(st.st_dev, &target_st->st_dev); - put_user(st.st_ino, &target_st->st_ino); + __put_user(st.st_dev, &target_st->st_dev); + __put_user(st.st_ino, &target_st->st_ino); #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO - put_user(st.st_ino, &target_st->__st_ino); + __put_user(st.st_ino, &target_st->__st_ino); #endif - put_user(st.st_mode, &target_st->st_mode); - put_user(st.st_nlink, &target_st->st_nlink); - put_user(st.st_uid, &target_st->st_uid); - put_user(st.st_gid, &target_st->st_gid); - put_user(st.st_rdev, &target_st->st_rdev); + __put_user(st.st_mode, &target_st->st_mode); + __put_user(st.st_nlink, &target_st->st_nlink); + __put_user(st.st_uid, &target_st->st_uid); + __put_user(st.st_gid, &target_st->st_gid); + __put_user(st.st_rdev, &target_st->st_rdev); /* XXX: better use of kernel struct */ - put_user(st.st_size, &target_st->st_size); - put_user(st.st_blksize, &target_st->st_blksize); - put_user(st.st_blocks, &target_st->st_blocks); - put_user(st.st_atime, &target_st->target_st_atime); - put_user(st.st_mtime, &target_st->target_st_mtime); - put_user(st.st_ctime, &target_st->target_st_ctime); - unlock_user_struct(target_st, arg2, 0); + __put_user(st.st_size, &target_st->st_size); + __put_user(st.st_blksize, &target_st->st_blksize); + __put_user(st.st_blocks, &target_st->st_blocks); + __put_user(st.st_atime, &target_st->target_st_atime); + __put_user(st.st_mtime, &target_st->target_st_mtime); + __put_user(st.st_ctime, &target_st->target_st_ctime); + unlock_user_struct(target_st, arg2, 1); } } } @@ -4525,7 +4659,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef USE_UID16 case TARGET_NR_lchown: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3))); unlock_user(p, arg1, 0); break; @@ -4557,7 +4692,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, grouplist = alloca(gidsetsize * sizeof(gid_t)); ret = get_errno(getgroups(gidsetsize, grouplist)); if (!is_error(ret)) { - target_grouplist = lock_user(arg2, gidsetsize * 2, 0); + target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0); + if (!target_grouplist) + goto efault; for(i = 0;i < gidsetsize; i++) target_grouplist[i] = tswap16(grouplist[i]); unlock_user(target_grouplist, arg2, gidsetsize * 2); @@ -4572,7 +4709,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, int i; grouplist = alloca(gidsetsize * sizeof(gid_t)); - target_grouplist = lock_user(arg2, gidsetsize * 2, 1); + target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1); + if (!target_grouplist) { + ret = -TARGET_EFAULT; + goto fail; + } for(i = 0;i < gidsetsize; i++) grouplist[i] = tswap16(target_grouplist[i]); unlock_user(target_grouplist, arg2, 0); @@ -4584,18 +4725,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) case TARGET_NR_fchownat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5)); + unlock_user(p, arg2, 0); break; #endif #ifdef TARGET_NR_setresuid @@ -4639,7 +4772,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR_chown: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3))); unlock_user(p, arg1, 0); break; @@ -4659,7 +4793,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_lchown32 case TARGET_NR_lchown32: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(lchown(p, arg2, arg3)); unlock_user(p, arg1, 0); break; @@ -4705,7 +4840,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, grouplist = alloca(gidsetsize * sizeof(gid_t)); ret = get_errno(getgroups(gidsetsize, grouplist)); if (!is_error(ret)) { - target_grouplist = lock_user(arg2, gidsetsize * 4, 0); + target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0); + if (!target_grouplist) { + ret = -TARGET_EFAULT; + goto fail; + } for(i = 0;i < gidsetsize; i++) target_grouplist[i] = tswap32(grouplist[i]); unlock_user(target_grouplist, arg2, gidsetsize * 4); @@ -4722,7 +4861,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, int i; grouplist = alloca(gidsetsize * sizeof(gid_t)); - target_grouplist = lock_user(arg2, gidsetsize * 4, 1); + target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1); + if (!target_grouplist) { + ret = -TARGET_EFAULT; + goto fail; + } for(i = 0;i < gidsetsize; i++) grouplist[i] = tswap32(target_grouplist[i]); unlock_user(target_grouplist, arg2, 0); @@ -4773,7 +4916,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_chown32 case TARGET_NR_chown32: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(chown(p, arg2, arg3)); unlock_user(p, arg1, 0); break; @@ -4843,7 +4987,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_F_GETLK64: #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { - lock_user_struct(target_efl, arg3, 1); + if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) { + ret = -TARGET_EFAULT; + goto fail; + } fl.l_type = tswap16(target_efl->l_type); fl.l_whence = tswap16(target_efl->l_whence); fl.l_start = tswap64(target_efl->l_start); @@ -4853,7 +5000,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else #endif { - lock_user_struct(target_fl, arg3, 1); + if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) { + ret = -TARGET_EFAULT; + goto fail; + } fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswap64(target_fl->l_start); @@ -4865,7 +5015,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (ret == 0) { #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { - lock_user_struct(target_efl, arg3, 0); + if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0)) { + ret = -TARGET_EFAULT; + goto fail; + } target_efl->l_type = tswap16(fl.l_type); target_efl->l_whence = tswap16(fl.l_whence); target_efl->l_start = tswap64(fl.l_start); @@ -4875,7 +5028,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else #endif { - lock_user_struct(target_fl, arg3, 0); + if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) { + ret = -TARGET_EFAULT; + goto fail; + } target_fl->l_type = tswap16(fl.l_type); target_fl->l_whence = tswap16(fl.l_whence); target_fl->l_start = tswap64(fl.l_start); @@ -4890,7 +5046,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_F_SETLKW64: #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { - lock_user_struct(target_efl, arg3, 1); + if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) { + ret = -TARGET_EFAULT; + goto fail; + } fl.l_type = tswap16(target_efl->l_type); fl.l_whence = tswap16(target_efl->l_whence); fl.l_start = tswap64(target_efl->l_start); @@ -4900,7 +5059,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else #endif { - lock_user_struct(target_fl, arg3, 1); + if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) { + ret = -TARGET_EFAULT; + goto fail; + } fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswap64(target_fl->l_start); @@ -4998,8 +5160,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address) case TARGET_NR_set_tid_address: - ret = get_errno(set_tid_address((int *) arg1)); - break; + ret = get_errno(set_tid_address((int *)g2h(arg1))); + break; #endif #if defined(TARGET_NR_tkill) && defined(__NR_tkill) @@ -5028,14 +5190,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!arg2) ret = get_errno(sys_utimensat(arg1, NULL, ts, arg4)); else { - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ + if (!(p = lock_user_string(arg2))) { ret = -TARGET_EFAULT; - else - ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4)); - if (p) - unlock_user(p, arg2, 0); + goto fail; + } + ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4)); + unlock_user(p, arg2, 0); } } break; @@ -5050,11 +5210,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = -TARGET_ENOSYS; break; } - fail: +fail: #ifdef DEBUG gemu_log(" = %ld\n", ret); #endif if(do_strace) print_syscall_ret(num, ret); return ret; +efault: + ret = -TARGET_EFAULT; + goto fail; } |