Index: qemu/linux-user/qemu.h =================================================================== --- qemu.orig/linux-user/qemu.h 2007-11-03 12:36:40.000000000 -0600 +++ qemu/linux-user/qemu.h 2007-11-05 14:24:17.000000000 -0700 @@ -251,24 +251,63 @@ 0;\ }) -#define put_user(x,ptr)\ -({\ - int __ret;\ - if (access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)))\ - __ret = __put_user(x, ptr);\ - else\ - __ret = -EFAULT;\ - __ret;\ +/* put_user()/get_user() take a guest address and check access */ +#define put_user(x, gaddr, target_type) \ +({ \ + abi_ulong __gaddr = (gaddr); \ + target_type __hptr; \ + abi_long __ret; \ + if (access_ok(VERIFY_WRITE, __gaddr, sizeof(target_type))) { \ + __hptr = lock_user(__gaddr, sizeof(target_type), 0); \ + __ret = __put_user((x), __hptr); \ + unlock_user(__hptr, __gaddr, sizeof(target_type)); \ + } else \ + __ret = -TARGET_EFAULT; \ + __ret; \ }) -#define get_user(x,ptr)\ -({\ - int __ret;\ - if (access_ok(VERIFY_READ, ptr, sizeof(*ptr)))\ - __ret = __get_user(x, ptr);\ - else\ - __ret = -EFAULT;\ - __ret;\ +#define get_user(x, gaddr, target_type) \ +({ \ + abi_ulong __gaddr = (gaddr); \ + target_type __hptr; \ + abi_long __ret; \ + if (access_ok(VERIFY_READ, __gaddr, sizeof(target_type))) { \ + __hptr = lock_user(__gaddr, sizeof(target_type), 1); \ + __ret = __get_user((x), __hptr); \ + unlock_user(__hptr, __gaddr, 0); \ + } else \ + __ret = -TARGET_EFAULT; \ + __ret; \ +}) + +#define copy_from_user(hptr, gaddr, len) \ +({ \ + abi_ulong __gaddr = (gaddr); \ + void *__hptr; \ + long __len = len; \ + abi_long __cfu_ret=0; \ + if (access_ok(VERIFY_READ, __gaddr, len)) { \ + __hptr = lock_user(__gaddr, len, 1); \ + memcpy((hptr), __hptr, len); \ + unlock_user(__hptr, __gaddr, 0); \ + } else \ + __cfu_ret = -TARGET_EFAULT; \ + __cfu_ret; \ +}) + +#define copy_to_user(gaddr, hptr, len) \ +({ \ + abi_ulong __gaddr = (gaddr); \ + void *__hptr; \ + long __len = len; \ + abi_long __ctu_ret=0; \ + if (access_ok(VERIFY_WRITE, __gaddr, len)) { \ + __hptr = lock_user(__gaddr, len, 0); \ + memcpy(__hptr, (hptr), len); \ + unlock_user(__hptr, __gaddr, len); \ + } else \ + __ctu_ret = -TARGET_EFAULT; \ + __ctu_ret; \ }) /* Functions for accessing guest memory. The tget and tput functions Index: qemu/linux-user/syscall.c =================================================================== --- qemu.orig/linux-user/syscall.c 2007-11-03 12:36:29.000000000 -0600 +++ qemu/linux-user/syscall.c 2007-11-05 14:36:54.000000000 -0700 @@ -1761,7 +1761,7 @@ break; } } - if (put_user(raddr, (abi_ulong *)third)) + if (put_user(raddr, third, abi_ulong *)) return -TARGET_EFAULT; ret = 0; break; @@ -3697,18 +3697,20 @@ if (!is_error(ret)) { struct target_statfs *target_stfs; + if (access_ok(VERIFY_WRITE, arg2, sizeof(*target_stfs))) + ret = -TARGET_EFAULT; + 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); + __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; @@ -3724,18 +3726,20 @@ if (!is_error(ret)) { struct target_statfs64 *target_stfs; + if (access_ok(VERIFY_WRITE, arg3, sizeof(*target_stfs))) + ret = -TARGET_EFAULT; + 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); + __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); } break; @@ -4472,51 +4476,56 @@ #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { struct target_eabi_stat64 *target_st; + + if (access_ok(VERIFY_WRITE, arg2, sizeof(*target_st))) + ret = -TARGET_EFAULT; + lock_user_struct(target_st, arg2, 1); 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); + __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); + __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, 0); } else #endif { struct target_stat64 *target_st; + + if (access_ok(VERIFY_WRITE, arg2, sizeof(*target_st))) + ret = -TARGET_EFAULT; + lock_user_struct(target_st, arg2, 1); 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); + __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); } }