aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLin Feng Shen <shenlinf@cn.ibm.com>2006-05-20 17:59:49 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-05-21 15:59:16 -0400
commitd64b1c878fc1e384ae53d1d40034239bc33848f4 (patch)
treefe31b26f2db18d021cf04181bd39e08b2beb17f1
parent84b3932bf0fd8cdc8c75a5be77e1dded1e6479c6 (diff)
[PATCH] NFS: fix error handling on access_ok in compat_sys_nfsservctl
Functions compat_nfs_svc_trans, compat_nfs_clnt_trans, compat_nfs_exp_trans, compat_nfs_getfd_trans and compat_nfs_getfs_trans, which are called by compat_sys_nfsservctl(fs/compat.c), don't handle the return value of access_ok properly. access_ok return 1 when the addr is valid, and 0 when it's not, but these functions have the reversed understanding. When the address is valid, they always return -EFAULT to compat_sys_nfsservctl. An example is to run /usr/sbin/rpc.nfsd(32bit program on Power5). It doesn't function as expected. strace showes that nfsservctl returns -EFAULT. The patch fixes this by correcting the error handling on the return value of access_ok in the five functions. Signed-off-by: Lin Feng Shen <shenlinf@cn.ibm.com> Cc: Trond Myklebust <trond.myklebust@fys.uio.no> Acked-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/compat.c177
1 files changed, 92 insertions, 85 deletions
diff --git a/fs/compat.c b/fs/compat.c
index 01f39f87f372..b1f64786a613 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -2030,109 +2030,115 @@ union compat_nfsctl_res {
2030 struct knfsd_fh cr32_getfs; 2030 struct knfsd_fh cr32_getfs;
2031}; 2031};
2032 2032
2033static int compat_nfs_svc_trans(struct nfsctl_arg *karg, struct compat_nfsctl_arg __user *arg) 2033static int compat_nfs_svc_trans(struct nfsctl_arg *karg,
2034{ 2034 struct compat_nfsctl_arg __user *arg)
2035 int err; 2035{
2036 2036 if (!access_ok(VERIFY_READ, &arg->ca32_svc, sizeof(arg->ca32_svc)) ||
2037 err = access_ok(VERIFY_READ, &arg->ca32_svc, sizeof(arg->ca32_svc)); 2037 get_user(karg->ca_version, &arg->ca32_version) ||
2038 err |= get_user(karg->ca_version, &arg->ca32_version); 2038 __get_user(karg->ca_svc.svc_port, &arg->ca32_svc.svc32_port) ||
2039 err |= __get_user(karg->ca_svc.svc_port, &arg->ca32_svc.svc32_port); 2039 __get_user(karg->ca_svc.svc_nthreads,
2040 err |= __get_user(karg->ca_svc.svc_nthreads, &arg->ca32_svc.svc32_nthreads); 2040 &arg->ca32_svc.svc32_nthreads))
2041 return (err) ? -EFAULT : 0; 2041 return -EFAULT;
2042 return 0;
2042} 2043}
2043 2044
2044static int compat_nfs_clnt_trans(struct nfsctl_arg *karg, struct compat_nfsctl_arg __user *arg) 2045static int compat_nfs_clnt_trans(struct nfsctl_arg *karg,
2045{ 2046 struct compat_nfsctl_arg __user *arg)
2046 int err; 2047{
2047 2048 if (!access_ok(VERIFY_READ, &arg->ca32_client,
2048 err = access_ok(VERIFY_READ, &arg->ca32_client, sizeof(arg->ca32_client)); 2049 sizeof(arg->ca32_client)) ||
2049 err |= get_user(karg->ca_version, &arg->ca32_version); 2050 get_user(karg->ca_version, &arg->ca32_version) ||
2050 err |= __copy_from_user(&karg->ca_client.cl_ident[0], 2051 __copy_from_user(&karg->ca_client.cl_ident[0],
2051 &arg->ca32_client.cl32_ident[0], 2052 &arg->ca32_client.cl32_ident[0],
2052 NFSCLNT_IDMAX); 2053 NFSCLNT_IDMAX) ||
2053 err |= __get_user(karg->ca_client.cl_naddr, &arg->ca32_client.cl32_naddr); 2054 __get_user(karg->ca_client.cl_naddr,
2054 err |= __copy_from_user(&karg->ca_client.cl_addrlist[0], 2055 &arg->ca32_client.cl32_naddr) ||
2055 &arg->ca32_client.cl32_addrlist[0], 2056 __copy_from_user(&karg->ca_client.cl_addrlist[0],
2056 (sizeof(struct in_addr) * NFSCLNT_ADDRMAX)); 2057 &arg->ca32_client.cl32_addrlist[0],
2057 err |= __get_user(karg->ca_client.cl_fhkeytype, 2058 (sizeof(struct in_addr) * NFSCLNT_ADDRMAX)) ||
2058 &arg->ca32_client.cl32_fhkeytype); 2059 __get_user(karg->ca_client.cl_fhkeytype,
2059 err |= __get_user(karg->ca_client.cl_fhkeylen, 2060 &arg->ca32_client.cl32_fhkeytype) ||
2060 &arg->ca32_client.cl32_fhkeylen); 2061 __get_user(karg->ca_client.cl_fhkeylen,
2061 err |= __copy_from_user(&karg->ca_client.cl_fhkey[0], 2062 &arg->ca32_client.cl32_fhkeylen) ||
2062 &arg->ca32_client.cl32_fhkey[0], 2063 __copy_from_user(&karg->ca_client.cl_fhkey[0],
2063 NFSCLNT_KEYMAX); 2064 &arg->ca32_client.cl32_fhkey[0],
2065 NFSCLNT_KEYMAX))
2066 return -EFAULT;
2064 2067
2065 return (err) ? -EFAULT : 0; 2068 return 0;
2066} 2069}
2067 2070
2068static int compat_nfs_exp_trans(struct nfsctl_arg *karg, struct compat_nfsctl_arg __user *arg) 2071static int compat_nfs_exp_trans(struct nfsctl_arg *karg,
2069{ 2072 struct compat_nfsctl_arg __user *arg)
2070 int err; 2073{
2071 2074 if (!access_ok(VERIFY_READ, &arg->ca32_export,
2072 err = access_ok(VERIFY_READ, &arg->ca32_export, sizeof(arg->ca32_export)); 2075 sizeof(arg->ca32_export)) ||
2073 err |= get_user(karg->ca_version, &arg->ca32_version); 2076 get_user(karg->ca_version, &arg->ca32_version) ||
2074 err |= __copy_from_user(&karg->ca_export.ex_client[0], 2077 __copy_from_user(&karg->ca_export.ex_client[0],
2075 &arg->ca32_export.ex32_client[0], 2078 &arg->ca32_export.ex32_client[0],
2076 NFSCLNT_IDMAX); 2079 NFSCLNT_IDMAX) ||
2077 err |= __copy_from_user(&karg->ca_export.ex_path[0], 2080 __copy_from_user(&karg->ca_export.ex_path[0],
2078 &arg->ca32_export.ex32_path[0], 2081 &arg->ca32_export.ex32_path[0],
2079 NFS_MAXPATHLEN); 2082 NFS_MAXPATHLEN) ||
2080 err |= __get_user(karg->ca_export.ex_dev, 2083 __get_user(karg->ca_export.ex_dev,
2081 &arg->ca32_export.ex32_dev); 2084 &arg->ca32_export.ex32_dev) ||
2082 err |= __get_user(karg->ca_export.ex_ino, 2085 __get_user(karg->ca_export.ex_ino,
2083 &arg->ca32_export.ex32_ino); 2086 &arg->ca32_export.ex32_ino) ||
2084 err |= __get_user(karg->ca_export.ex_flags, 2087 __get_user(karg->ca_export.ex_flags,
2085 &arg->ca32_export.ex32_flags); 2088 &arg->ca32_export.ex32_flags) ||
2086 err |= __get_user(karg->ca_export.ex_anon_uid, 2089 __get_user(karg->ca_export.ex_anon_uid,
2087 &arg->ca32_export.ex32_anon_uid); 2090 &arg->ca32_export.ex32_anon_uid) ||
2088 err |= __get_user(karg->ca_export.ex_anon_gid, 2091 __get_user(karg->ca_export.ex_anon_gid,
2089 &arg->ca32_export.ex32_anon_gid); 2092 &arg->ca32_export.ex32_anon_gid))
2093 return -EFAULT;
2090 SET_UID(karg->ca_export.ex_anon_uid, karg->ca_export.ex_anon_uid); 2094 SET_UID(karg->ca_export.ex_anon_uid, karg->ca_export.ex_anon_uid);
2091 SET_GID(karg->ca_export.ex_anon_gid, karg->ca_export.ex_anon_gid); 2095 SET_GID(karg->ca_export.ex_anon_gid, karg->ca_export.ex_anon_gid);
2092 2096
2093 return (err) ? -EFAULT : 0; 2097 return 0;
2094} 2098}
2095 2099
2096static int compat_nfs_getfd_trans(struct nfsctl_arg *karg, struct compat_nfsctl_arg __user *arg) 2100static int compat_nfs_getfd_trans(struct nfsctl_arg *karg,
2097{ 2101 struct compat_nfsctl_arg __user *arg)
2098 int err; 2102{
2099 2103 if (!access_ok(VERIFY_READ, &arg->ca32_getfd,
2100 err = access_ok(VERIFY_READ, &arg->ca32_getfd, sizeof(arg->ca32_getfd)); 2104 sizeof(arg->ca32_getfd)) ||
2101 err |= get_user(karg->ca_version, &arg->ca32_version); 2105 get_user(karg->ca_version, &arg->ca32_version) ||
2102 err |= __copy_from_user(&karg->ca_getfd.gd_addr, 2106 __copy_from_user(&karg->ca_getfd.gd_addr,
2103 &arg->ca32_getfd.gd32_addr, 2107 &arg->ca32_getfd.gd32_addr,
2104 (sizeof(struct sockaddr))); 2108 (sizeof(struct sockaddr))) ||
2105 err |= __copy_from_user(&karg->ca_getfd.gd_path, 2109 __copy_from_user(&karg->ca_getfd.gd_path,
2106 &arg->ca32_getfd.gd32_path, 2110 &arg->ca32_getfd.gd32_path,
2107 (NFS_MAXPATHLEN+1)); 2111 (NFS_MAXPATHLEN+1)) ||
2108 err |= __get_user(karg->ca_getfd.gd_version, 2112 __get_user(karg->ca_getfd.gd_version,
2109 &arg->ca32_getfd.gd32_version); 2113 &arg->ca32_getfd.gd32_version))
2114 return -EFAULT;
2110 2115
2111 return (err) ? -EFAULT : 0; 2116 return 0;
2112} 2117}
2113 2118
2114static int compat_nfs_getfs_trans(struct nfsctl_arg *karg, struct compat_nfsctl_arg __user *arg) 2119static int compat_nfs_getfs_trans(struct nfsctl_arg *karg,
2120 struct compat_nfsctl_arg __user *arg)
2115{ 2121{
2116 int err; 2122 if (!access_ok(VERIFY_READ,&arg->ca32_getfs,sizeof(arg->ca32_getfs)) ||
2117 2123 get_user(karg->ca_version, &arg->ca32_version) ||
2118 err = access_ok(VERIFY_READ, &arg->ca32_getfs, sizeof(arg->ca32_getfs)); 2124 __copy_from_user(&karg->ca_getfs.gd_addr,
2119 err |= get_user(karg->ca_version, &arg->ca32_version); 2125 &arg->ca32_getfs.gd32_addr,
2120 err |= __copy_from_user(&karg->ca_getfs.gd_addr, 2126 (sizeof(struct sockaddr))) ||
2121 &arg->ca32_getfs.gd32_addr, 2127 __copy_from_user(&karg->ca_getfs.gd_path,
2122 (sizeof(struct sockaddr))); 2128 &arg->ca32_getfs.gd32_path,
2123 err |= __copy_from_user(&karg->ca_getfs.gd_path, 2129 (NFS_MAXPATHLEN+1)) ||
2124 &arg->ca32_getfs.gd32_path, 2130 __get_user(karg->ca_getfs.gd_maxlen,
2125 (NFS_MAXPATHLEN+1)); 2131 &arg->ca32_getfs.gd32_maxlen))
2126 err |= __get_user(karg->ca_getfs.gd_maxlen, 2132 return -EFAULT;
2127 &arg->ca32_getfs.gd32_maxlen);
2128 2133
2129 return (err) ? -EFAULT : 0; 2134 return 0;
2130} 2135}
2131 2136
2132/* This really doesn't need translations, we are only passing 2137/* This really doesn't need translations, we are only passing
2133 * back a union which contains opaque nfs file handle data. 2138 * back a union which contains opaque nfs file handle data.
2134 */ 2139 */
2135static int compat_nfs_getfh_res_trans(union nfsctl_res *kres, union compat_nfsctl_res __user *res) 2140static int compat_nfs_getfh_res_trans(union nfsctl_res *kres,
2141 union compat_nfsctl_res __user *res)
2136{ 2142{
2137 int err; 2143 int err;
2138 2144
@@ -2141,8 +2147,9 @@ static int compat_nfs_getfh_res_trans(union nfsctl_res *kres, union compat_nfsct
2141 return (err) ? -EFAULT : 0; 2147 return (err) ? -EFAULT : 0;
2142} 2148}
2143 2149
2144asmlinkage long compat_sys_nfsservctl(int cmd, struct compat_nfsctl_arg __user *arg, 2150asmlinkage long compat_sys_nfsservctl(int cmd,
2145 union compat_nfsctl_res __user *res) 2151 struct compat_nfsctl_arg __user *arg,
2152 union compat_nfsctl_res __user *res)
2146{ 2153{
2147 struct nfsctl_arg *karg; 2154 struct nfsctl_arg *karg;
2148 union nfsctl_res *kres; 2155 union nfsctl_res *kres;