diff options
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/auth.c | 95 | ||||
-rw-r--r-- | fs/nfsd/nfs4recover.c | 72 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 11 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 9 |
4 files changed, 114 insertions, 73 deletions
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 294992e9bf69..0184fe9b514c 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c | |||
@@ -27,53 +27,70 @@ int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) | |||
27 | 27 | ||
28 | int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) | 28 | int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) |
29 | { | 29 | { |
30 | struct svc_cred cred = rqstp->rq_cred; | 30 | struct group_info *rqgi; |
31 | struct group_info *gi; | ||
32 | struct cred *new; | ||
31 | int i; | 33 | int i; |
32 | int flags = nfsexp_flags(rqstp, exp); | 34 | int flags = nfsexp_flags(rqstp, exp); |
33 | int ret; | 35 | int ret; |
34 | 36 | ||
37 | /* discard any old override before preparing the new set */ | ||
38 | revert_creds(get_cred(current->real_cred)); | ||
39 | new = prepare_creds(); | ||
40 | if (!new) | ||
41 | return -ENOMEM; | ||
42 | |||
43 | new->fsuid = rqstp->rq_cred.cr_uid; | ||
44 | new->fsgid = rqstp->rq_cred.cr_gid; | ||
45 | |||
46 | rqgi = rqstp->rq_cred.cr_group_info; | ||
47 | |||
35 | if (flags & NFSEXP_ALLSQUASH) { | 48 | if (flags & NFSEXP_ALLSQUASH) { |
36 | cred.cr_uid = exp->ex_anon_uid; | 49 | new->fsuid = exp->ex_anon_uid; |
37 | cred.cr_gid = exp->ex_anon_gid; | 50 | new->fsgid = exp->ex_anon_gid; |
38 | cred.cr_group_info = groups_alloc(0); | 51 | gi = groups_alloc(0); |
39 | } else if (flags & NFSEXP_ROOTSQUASH) { | 52 | } else if (flags & NFSEXP_ROOTSQUASH) { |
40 | struct group_info *gi; | 53 | if (!new->fsuid) |
41 | if (!cred.cr_uid) | 54 | new->fsuid = exp->ex_anon_uid; |
42 | cred.cr_uid = exp->ex_anon_uid; | 55 | if (!new->fsgid) |
43 | if (!cred.cr_gid) | 56 | new->fsgid = exp->ex_anon_gid; |
44 | cred.cr_gid = exp->ex_anon_gid; | ||
45 | gi = groups_alloc(cred.cr_group_info->ngroups); | ||
46 | if (gi) | ||
47 | for (i = 0; i < cred.cr_group_info->ngroups; i++) { | ||
48 | if (!GROUP_AT(cred.cr_group_info, i)) | ||
49 | GROUP_AT(gi, i) = exp->ex_anon_gid; | ||
50 | else | ||
51 | GROUP_AT(gi, i) = GROUP_AT(cred.cr_group_info, i); | ||
52 | } | ||
53 | cred.cr_group_info = gi; | ||
54 | } else | ||
55 | get_group_info(cred.cr_group_info); | ||
56 | |||
57 | if (cred.cr_uid != (uid_t) -1) | ||
58 | current->fsuid = cred.cr_uid; | ||
59 | else | ||
60 | current->fsuid = exp->ex_anon_uid; | ||
61 | if (cred.cr_gid != (gid_t) -1) | ||
62 | current->fsgid = cred.cr_gid; | ||
63 | else | ||
64 | current->fsgid = exp->ex_anon_gid; | ||
65 | 57 | ||
66 | if (!cred.cr_group_info) | 58 | gi = groups_alloc(rqgi->ngroups); |
67 | return -ENOMEM; | 59 | if (!gi) |
68 | ret = set_current_groups(cred.cr_group_info); | 60 | goto oom; |
69 | put_group_info(cred.cr_group_info); | 61 | |
70 | if ((cred.cr_uid)) { | 62 | for (i = 0; i < rqgi->ngroups; i++) { |
71 | current->cap_effective = | 63 | if (!GROUP_AT(rqgi, i)) |
72 | cap_drop_nfsd_set(current->cap_effective); | 64 | GROUP_AT(gi, i) = exp->ex_anon_gid; |
65 | else | ||
66 | GROUP_AT(gi, i) = GROUP_AT(rqgi, i); | ||
67 | } | ||
73 | } else { | 68 | } else { |
74 | current->cap_effective = | 69 | gi = get_group_info(rqgi); |
75 | cap_raise_nfsd_set(current->cap_effective, | ||
76 | current->cap_permitted); | ||
77 | } | 70 | } |
71 | |||
72 | if (new->fsuid == (uid_t) -1) | ||
73 | new->fsuid = exp->ex_anon_uid; | ||
74 | if (new->fsgid == (gid_t) -1) | ||
75 | new->fsgid = exp->ex_anon_gid; | ||
76 | |||
77 | ret = set_groups(new, gi); | ||
78 | put_group_info(gi); | ||
79 | if (!ret) | ||
80 | goto error; | ||
81 | |||
82 | if (new->uid) | ||
83 | new->cap_effective = cap_drop_nfsd_set(new->cap_effective); | ||
84 | else | ||
85 | new->cap_effective = cap_raise_nfsd_set(new->cap_effective, | ||
86 | new->cap_permitted); | ||
87 | put_cred(override_creds(new)); | ||
88 | return 0; | ||
89 | |||
90 | oom: | ||
91 | ret = -ENOMEM; | ||
92 | error: | ||
93 | abort_creds(new); | ||
78 | return ret; | 94 | return ret; |
79 | } | 95 | } |
96 | |||
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index b79ec930d9f1..0f9d6efaa62b 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
@@ -54,20 +54,26 @@ | |||
54 | static struct path rec_dir; | 54 | static struct path rec_dir; |
55 | static int rec_dir_init = 0; | 55 | static int rec_dir_init = 0; |
56 | 56 | ||
57 | static void | 57 | static int |
58 | nfs4_save_user(uid_t *saveuid, gid_t *savegid) | 58 | nfs4_save_creds(const struct cred **original_creds) |
59 | { | 59 | { |
60 | *saveuid = current->fsuid; | 60 | struct cred *new; |
61 | *savegid = current->fsgid; | 61 | |
62 | current->fsuid = 0; | 62 | new = prepare_creds(); |
63 | current->fsgid = 0; | 63 | if (!new) |
64 | return -ENOMEM; | ||
65 | |||
66 | new->fsuid = 0; | ||
67 | new->fsgid = 0; | ||
68 | *original_creds = override_creds(new); | ||
69 | put_cred(new); | ||
70 | return 0; | ||
64 | } | 71 | } |
65 | 72 | ||
66 | static void | 73 | static void |
67 | nfs4_reset_user(uid_t saveuid, gid_t savegid) | 74 | nfs4_reset_creds(const struct cred *original) |
68 | { | 75 | { |
69 | current->fsuid = saveuid; | 76 | revert_creds(original); |
70 | current->fsgid = savegid; | ||
71 | } | 77 | } |
72 | 78 | ||
73 | static void | 79 | static void |
@@ -129,10 +135,9 @@ nfsd4_sync_rec_dir(void) | |||
129 | int | 135 | int |
130 | nfsd4_create_clid_dir(struct nfs4_client *clp) | 136 | nfsd4_create_clid_dir(struct nfs4_client *clp) |
131 | { | 137 | { |
138 | const struct cred *original_cred; | ||
132 | char *dname = clp->cl_recdir; | 139 | char *dname = clp->cl_recdir; |
133 | struct dentry *dentry; | 140 | struct dentry *dentry; |
134 | uid_t uid; | ||
135 | gid_t gid; | ||
136 | int status; | 141 | int status; |
137 | 142 | ||
138 | dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); | 143 | dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); |
@@ -140,7 +145,9 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) | |||
140 | if (!rec_dir_init || clp->cl_firststate) | 145 | if (!rec_dir_init || clp->cl_firststate) |
141 | return 0; | 146 | return 0; |
142 | 147 | ||
143 | nfs4_save_user(&uid, &gid); | 148 | status = nfs4_save_creds(&original_cred); |
149 | if (status < 0) | ||
150 | return status; | ||
144 | 151 | ||
145 | /* lock the parent */ | 152 | /* lock the parent */ |
146 | mutex_lock(&rec_dir.dentry->d_inode->i_mutex); | 153 | mutex_lock(&rec_dir.dentry->d_inode->i_mutex); |
@@ -168,7 +175,7 @@ out_unlock: | |||
168 | clp->cl_firststate = 1; | 175 | clp->cl_firststate = 1; |
169 | nfsd4_sync_rec_dir(); | 176 | nfsd4_sync_rec_dir(); |
170 | } | 177 | } |
171 | nfs4_reset_user(uid, gid); | 178 | nfs4_reset_creds(original_cred); |
172 | dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status); | 179 | dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status); |
173 | return status; | 180 | return status; |
174 | } | 181 | } |
@@ -211,26 +218,29 @@ nfsd4_build_dentrylist(void *arg, const char *name, int namlen, | |||
211 | static int | 218 | static int |
212 | nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f) | 219 | nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f) |
213 | { | 220 | { |
221 | const struct cred *original_cred; | ||
214 | struct file *filp; | 222 | struct file *filp; |
215 | struct dentry_list_arg dla = { | 223 | struct dentry_list_arg dla = { |
216 | .parent = dir, | 224 | .parent = dir, |
217 | }; | 225 | }; |
218 | struct list_head *dentries = &dla.dentries; | 226 | struct list_head *dentries = &dla.dentries; |
219 | struct dentry_list *child; | 227 | struct dentry_list *child; |
220 | uid_t uid; | ||
221 | gid_t gid; | ||
222 | int status; | 228 | int status; |
223 | 229 | ||
224 | if (!rec_dir_init) | 230 | if (!rec_dir_init) |
225 | return 0; | 231 | return 0; |
226 | 232 | ||
227 | nfs4_save_user(&uid, &gid); | 233 | status = nfs4_save_creds(&original_cred); |
234 | if (status < 0) | ||
235 | return status; | ||
228 | INIT_LIST_HEAD(dentries); | 236 | INIT_LIST_HEAD(dentries); |
229 | 237 | ||
230 | filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY); | 238 | filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY, |
239 | current_cred()); | ||
231 | status = PTR_ERR(filp); | 240 | status = PTR_ERR(filp); |
232 | if (IS_ERR(filp)) | 241 | if (IS_ERR(filp)) |
233 | goto out; | 242 | goto out; |
243 | INIT_LIST_HEAD(dentries); | ||
234 | status = vfs_readdir(filp, nfsd4_build_dentrylist, &dla); | 244 | status = vfs_readdir(filp, nfsd4_build_dentrylist, &dla); |
235 | fput(filp); | 245 | fput(filp); |
236 | while (!list_empty(dentries)) { | 246 | while (!list_empty(dentries)) { |
@@ -249,7 +259,7 @@ out: | |||
249 | dput(child->dentry); | 259 | dput(child->dentry); |
250 | kfree(child); | 260 | kfree(child); |
251 | } | 261 | } |
252 | nfs4_reset_user(uid, gid); | 262 | nfs4_reset_creds(original_cred); |
253 | return status; | 263 | return status; |
254 | } | 264 | } |
255 | 265 | ||
@@ -311,8 +321,7 @@ out: | |||
311 | void | 321 | void |
312 | nfsd4_remove_clid_dir(struct nfs4_client *clp) | 322 | nfsd4_remove_clid_dir(struct nfs4_client *clp) |
313 | { | 323 | { |
314 | uid_t uid; | 324 | const struct cred *original_cred; |
315 | gid_t gid; | ||
316 | int status; | 325 | int status; |
317 | 326 | ||
318 | if (!rec_dir_init || !clp->cl_firststate) | 327 | if (!rec_dir_init || !clp->cl_firststate) |
@@ -322,9 +331,13 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) | |||
322 | if (status) | 331 | if (status) |
323 | goto out; | 332 | goto out; |
324 | clp->cl_firststate = 0; | 333 | clp->cl_firststate = 0; |
325 | nfs4_save_user(&uid, &gid); | 334 | |
335 | status = nfs4_save_creds(&original_cred); | ||
336 | if (status < 0) | ||
337 | goto out; | ||
338 | |||
326 | status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); | 339 | status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); |
327 | nfs4_reset_user(uid, gid); | 340 | nfs4_reset_creds(original_cred); |
328 | if (status == 0) | 341 | if (status == 0) |
329 | nfsd4_sync_rec_dir(); | 342 | nfsd4_sync_rec_dir(); |
330 | mnt_drop_write(rec_dir.mnt); | 343 | mnt_drop_write(rec_dir.mnt); |
@@ -401,16 +414,21 @@ nfsd4_recdir_load(void) { | |||
401 | void | 414 | void |
402 | nfsd4_init_recdir(char *rec_dirname) | 415 | nfsd4_init_recdir(char *rec_dirname) |
403 | { | 416 | { |
404 | uid_t uid = 0; | 417 | const struct cred *original_cred; |
405 | gid_t gid = 0; | 418 | int status; |
406 | int status; | ||
407 | 419 | ||
408 | printk("NFSD: Using %s as the NFSv4 state recovery directory\n", | 420 | printk("NFSD: Using %s as the NFSv4 state recovery directory\n", |
409 | rec_dirname); | 421 | rec_dirname); |
410 | 422 | ||
411 | BUG_ON(rec_dir_init); | 423 | BUG_ON(rec_dir_init); |
412 | 424 | ||
413 | nfs4_save_user(&uid, &gid); | 425 | status = nfs4_save_creds(&original_cred); |
426 | if (status < 0) { | ||
427 | printk("NFSD: Unable to change credentials to find recovery" | ||
428 | " directory: error %d\n", | ||
429 | status); | ||
430 | return; | ||
431 | } | ||
414 | 432 | ||
415 | status = kern_path(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, | 433 | status = kern_path(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, |
416 | &rec_dir); | 434 | &rec_dir); |
@@ -420,7 +438,7 @@ nfsd4_init_recdir(char *rec_dirname) | |||
420 | 438 | ||
421 | if (!status) | 439 | if (!status) |
422 | rec_dir_init = 1; | 440 | rec_dir_init = 1; |
423 | nfs4_reset_user(uid, gid); | 441 | nfs4_reset_creds(original_cred); |
424 | } | 442 | } |
425 | 443 | ||
426 | void | 444 | void |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index cd25d91895a1..f0da7d9c3a92 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -186,9 +186,14 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) | |||
186 | * access control settings being in effect, we cannot | 186 | * access control settings being in effect, we cannot |
187 | * fix that case easily. | 187 | * fix that case easily. |
188 | */ | 188 | */ |
189 | current->cap_effective = | 189 | struct cred *new = prepare_creds(); |
190 | cap_raise_nfsd_set(current->cap_effective, | 190 | if (!new) |
191 | current->cap_permitted); | 191 | return nfserrno(-ENOMEM); |
192 | new->cap_effective = | ||
193 | cap_raise_nfsd_set(new->cap_effective, | ||
194 | new->cap_permitted); | ||
195 | put_cred(override_creds(new)); | ||
196 | put_cred(new); | ||
192 | } else { | 197 | } else { |
193 | error = nfsd_setuser_and_check_port(rqstp, exp); | 198 | error = nfsd_setuser_and_check_port(rqstp, exp); |
194 | if (error) | 199 | if (error) |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 4433c8f00163..d1c5f787b365 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -671,6 +671,7 @@ __be32 | |||
671 | nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | 671 | nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, |
672 | int access, struct file **filp) | 672 | int access, struct file **filp) |
673 | { | 673 | { |
674 | const struct cred *cred = current_cred(); | ||
674 | struct dentry *dentry; | 675 | struct dentry *dentry; |
675 | struct inode *inode; | 676 | struct inode *inode; |
676 | int flags = O_RDONLY|O_LARGEFILE; | 677 | int flags = O_RDONLY|O_LARGEFILE; |
@@ -725,7 +726,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
725 | DQUOT_INIT(inode); | 726 | DQUOT_INIT(inode); |
726 | } | 727 | } |
727 | *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt), | 728 | *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt), |
728 | flags); | 729 | flags, cred); |
729 | if (IS_ERR(*filp)) | 730 | if (IS_ERR(*filp)) |
730 | host_err = PTR_ERR(*filp); | 731 | host_err = PTR_ERR(*filp); |
731 | out_nfserr: | 732 | out_nfserr: |
@@ -1169,7 +1170,7 @@ nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp, | |||
1169 | * send along the gid on create when it tries to implement | 1170 | * send along the gid on create when it tries to implement |
1170 | * setgid directories via NFS: | 1171 | * setgid directories via NFS: |
1171 | */ | 1172 | */ |
1172 | if (current->fsuid != 0) | 1173 | if (current_fsuid() != 0) |
1173 | iap->ia_valid &= ~(ATTR_UID|ATTR_GID); | 1174 | iap->ia_valid &= ~(ATTR_UID|ATTR_GID); |
1174 | if (iap->ia_valid) | 1175 | if (iap->ia_valid) |
1175 | return nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); | 1176 | return nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); |
@@ -2001,7 +2002,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, | |||
2001 | IS_APPEND(inode)? " append" : "", | 2002 | IS_APPEND(inode)? " append" : "", |
2002 | __mnt_is_readonly(exp->ex_path.mnt)? " ro" : ""); | 2003 | __mnt_is_readonly(exp->ex_path.mnt)? " ro" : ""); |
2003 | dprintk(" owner %d/%d user %d/%d\n", | 2004 | dprintk(" owner %d/%d user %d/%d\n", |
2004 | inode->i_uid, inode->i_gid, current->fsuid, current->fsgid); | 2005 | inode->i_uid, inode->i_gid, current_fsuid(), current_fsgid()); |
2005 | #endif | 2006 | #endif |
2006 | 2007 | ||
2007 | /* Normally we reject any write/sattr etc access on a read-only file | 2008 | /* Normally we reject any write/sattr etc access on a read-only file |
@@ -2044,7 +2045,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, | |||
2044 | * with NFSv3. | 2045 | * with NFSv3. |
2045 | */ | 2046 | */ |
2046 | if ((acc & NFSD_MAY_OWNER_OVERRIDE) && | 2047 | if ((acc & NFSD_MAY_OWNER_OVERRIDE) && |
2047 | inode->i_uid == current->fsuid) | 2048 | inode->i_uid == current_fsuid()) |
2048 | return 0; | 2049 | return 0; |
2049 | 2050 | ||
2050 | /* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */ | 2051 | /* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */ |