aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/exec.c31
-rw-r--r--fs/nfsd/auth.c92
-rw-r--r--fs/nfsd/nfs4recover.c68
-rw-r--r--fs/nfsd/nfsfh.c11
-rw-r--r--fs/open.c31
5 files changed, 138 insertions, 95 deletions
diff --git a/fs/exec.c b/fs/exec.c
index a5330e1a2216..9bd3559ddece 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1007,13 +1007,12 @@ int flush_old_exec(struct linux_binprm * bprm)
1007 */ 1007 */
1008 current->mm->task_size = TASK_SIZE; 1008 current->mm->task_size = TASK_SIZE;
1009 1009
1010 if (bprm->e_uid != current_euid() || bprm->e_gid != current_egid()) { 1010 if (bprm->e_uid != current_euid() ||
1011 suid_keys(current); 1011 bprm->e_gid != current_egid()) {
1012 set_dumpable(current->mm, suid_dumpable); 1012 set_dumpable(current->mm, suid_dumpable);
1013 current->pdeath_signal = 0; 1013 current->pdeath_signal = 0;
1014 } else if (file_permission(bprm->file, MAY_READ) || 1014 } else if (file_permission(bprm->file, MAY_READ) ||
1015 (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { 1015 (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
1016 suid_keys(current);
1017 set_dumpable(current->mm, suid_dumpable); 1016 set_dumpable(current->mm, suid_dumpable);
1018 } 1017 }
1019 1018
@@ -1096,10 +1095,8 @@ void compute_creds(struct linux_binprm *bprm)
1096{ 1095{
1097 int unsafe; 1096 int unsafe;
1098 1097
1099 if (bprm->e_uid != current_uid()) { 1098 if (bprm->e_uid != current_uid())
1100 suid_keys(current);
1101 current->pdeath_signal = 0; 1099 current->pdeath_signal = 0;
1102 }
1103 exec_keys(current); 1100 exec_keys(current);
1104 1101
1105 task_lock(current); 1102 task_lock(current);
@@ -1709,8 +1706,9 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1709 struct linux_binfmt * binfmt; 1706 struct linux_binfmt * binfmt;
1710 struct inode * inode; 1707 struct inode * inode;
1711 struct file * file; 1708 struct file * file;
1709 const struct cred *old_cred;
1710 struct cred *cred;
1712 int retval = 0; 1711 int retval = 0;
1713 int fsuid = current_fsuid();
1714 int flag = 0; 1712 int flag = 0;
1715 int ispipe = 0; 1713 int ispipe = 0;
1716 unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; 1714 unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
@@ -1723,12 +1721,20 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1723 binfmt = current->binfmt; 1721 binfmt = current->binfmt;
1724 if (!binfmt || !binfmt->core_dump) 1722 if (!binfmt || !binfmt->core_dump)
1725 goto fail; 1723 goto fail;
1724
1725 cred = prepare_creds();
1726 if (!cred) {
1727 retval = -ENOMEM;
1728 goto fail;
1729 }
1730
1726 down_write(&mm->mmap_sem); 1731 down_write(&mm->mmap_sem);
1727 /* 1732 /*
1728 * If another thread got here first, or we are not dumpable, bail out. 1733 * If another thread got here first, or we are not dumpable, bail out.
1729 */ 1734 */
1730 if (mm->core_state || !get_dumpable(mm)) { 1735 if (mm->core_state || !get_dumpable(mm)) {
1731 up_write(&mm->mmap_sem); 1736 up_write(&mm->mmap_sem);
1737 put_cred(cred);
1732 goto fail; 1738 goto fail;
1733 } 1739 }
1734 1740
@@ -1739,12 +1745,16 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1739 */ 1745 */
1740 if (get_dumpable(mm) == 2) { /* Setuid core dump mode */ 1746 if (get_dumpable(mm) == 2) { /* Setuid core dump mode */
1741 flag = O_EXCL; /* Stop rewrite attacks */ 1747 flag = O_EXCL; /* Stop rewrite attacks */
1742 current->cred->fsuid = 0; /* Dump root private */ 1748 cred->fsuid = 0; /* Dump root private */
1743 } 1749 }
1744 1750
1745 retval = coredump_wait(exit_code, &core_state); 1751 retval = coredump_wait(exit_code, &core_state);
1746 if (retval < 0) 1752 if (retval < 0) {
1753 put_cred(cred);
1747 goto fail; 1754 goto fail;
1755 }
1756
1757 old_cred = override_creds(cred);
1748 1758
1749 /* 1759 /*
1750 * Clear any false indication of pending signals that might 1760 * Clear any false indication of pending signals that might
@@ -1835,7 +1845,8 @@ fail_unlock:
1835 if (helper_argv) 1845 if (helper_argv)
1836 argv_free(helper_argv); 1846 argv_free(helper_argv);
1837 1847
1838 current->cred->fsuid = fsuid; 1848 revert_creds(old_cred);
1849 put_cred(cred);
1839 coredump_finish(mm); 1850 coredump_finish(mm);
1840fail: 1851fail:
1841 return retval; 1852 return retval;
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 808fc03a6fbd..836ffa1047d9 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -27,55 +27,67 @@ int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
27 27
28int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) 28int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
29{ 29{
30 struct cred *act_as = current->cred ; 30 struct group_info *rqgi;
31 struct svc_cred cred = rqstp->rq_cred; 31 struct group_info *gi;
32 struct cred *new;
32 int i; 33 int i;
33 int flags = nfsexp_flags(rqstp, exp); 34 int flags = nfsexp_flags(rqstp, exp);
34 int ret; 35 int ret;
35 36
37 new = prepare_creds();
38 if (!new)
39 return -ENOMEM;
40
41 new->fsuid = rqstp->rq_cred.cr_uid;
42 new->fsgid = rqstp->rq_cred.cr_gid;
43
44 rqgi = rqstp->rq_cred.cr_group_info;
45
36 if (flags & NFSEXP_ALLSQUASH) { 46 if (flags & NFSEXP_ALLSQUASH) {
37 cred.cr_uid = exp->ex_anon_uid; 47 new->fsuid = exp->ex_anon_uid;
38 cred.cr_gid = exp->ex_anon_gid; 48 new->fsgid = exp->ex_anon_gid;
39 cred.cr_group_info = groups_alloc(0); 49 gi = groups_alloc(0);
40 } else if (flags & NFSEXP_ROOTSQUASH) { 50 } else if (flags & NFSEXP_ROOTSQUASH) {
41 struct group_info *gi; 51 if (!new->fsuid)
42 if (!cred.cr_uid) 52 new->fsuid = exp->ex_anon_uid;
43 cred.cr_uid = exp->ex_anon_uid; 53 if (!new->fsgid)
44 if (!cred.cr_gid) 54 new->fsgid = exp->ex_anon_gid;
45 cred.cr_gid = exp->ex_anon_gid;
46 gi = groups_alloc(cred.cr_group_info->ngroups);
47 if (gi)
48 for (i = 0; i < cred.cr_group_info->ngroups; i++) {
49 if (!GROUP_AT(cred.cr_group_info, i))
50 GROUP_AT(gi, i) = exp->ex_anon_gid;
51 else
52 GROUP_AT(gi, i) = GROUP_AT(cred.cr_group_info, i);
53 }
54 cred.cr_group_info = gi;
55 } else
56 get_group_info(cred.cr_group_info);
57
58 if (cred.cr_uid != (uid_t) -1)
59 act_as->fsuid = cred.cr_uid;
60 else
61 act_as->fsuid = exp->ex_anon_uid;
62 if (cred.cr_gid != (gid_t) -1)
63 act_as->fsgid = cred.cr_gid;
64 else
65 act_as->fsgid = exp->ex_anon_gid;
66 55
67 if (!cred.cr_group_info) 56 gi = groups_alloc(rqgi->ngroups);
68 return -ENOMEM; 57 if (!gi)
69 ret = set_groups(act_as, cred.cr_group_info); 58 goto oom;
70 put_group_info(cred.cr_group_info); 59
71 if ((cred.cr_uid)) { 60 for (i = 0; i < rqgi->ngroups; i++) {
72 act_as->cap_effective = 61 if (!GROUP_AT(rqgi, i))
73 cap_drop_nfsd_set(act_as->cap_effective); 62 GROUP_AT(gi, i) = exp->ex_anon_gid;
63 else
64 GROUP_AT(gi, i) = GROUP_AT(rqgi, i);
65 }
74 } else { 66 } else {
75 act_as->cap_effective = 67 gi = get_group_info(rqgi);
76 cap_raise_nfsd_set(act_as->cap_effective,
77 act_as->cap_permitted);
78 } 68 }
69
70 if (new->fsuid == (uid_t) -1)
71 new->fsuid = exp->ex_anon_uid;
72 if (new->fsgid == (gid_t) -1)
73 new->fsgid = exp->ex_anon_gid;
74
75 ret = set_groups(new, gi);
76 put_group_info(gi);
77 if (!ret)
78 goto error;
79
80 if (new->uid)
81 new->cap_effective = cap_drop_nfsd_set(new->cap_effective);
82 else
83 new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
84 new->cap_permitted);
85 return commit_creds(new);
86
87oom:
88 ret = -ENOMEM;
89error:
90 abort_creds(new);
79 return ret; 91 return ret;
80} 92}
81 93
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 632a50b4b371..9371ea12d7fa 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -54,20 +54,26 @@
54static struct path rec_dir; 54static struct path rec_dir;
55static int rec_dir_init = 0; 55static int rec_dir_init = 0;
56 56
57static void 57static int
58nfs4_save_user(uid_t *saveuid, gid_t *savegid) 58nfs4_save_creds(const struct cred **original_creds)
59{ 59{
60 *saveuid = current->cred->fsuid; 60 struct cred *new;
61 *savegid = current->cred->fsgid; 61
62 current->cred->fsuid = 0; 62 new = prepare_creds();
63 current->cred->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
66static void 73static void
67nfs4_reset_user(uid_t saveuid, gid_t savegid) 74nfs4_reset_creds(const struct cred *original)
68{ 75{
69 current->cred->fsuid = saveuid; 76 revert_creds(original);
70 current->cred->fsgid = savegid;
71} 77}
72 78
73static void 79static void
@@ -129,10 +135,9 @@ nfsd4_sync_rec_dir(void)
129int 135int
130nfsd4_create_clid_dir(struct nfs4_client *clp) 136nfsd4_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,20 +218,21 @@ nfsd4_build_dentrylist(void *arg, const char *name, int namlen,
211static int 218static int
212nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f) 219nfsd4_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 236
229 filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY, 237 filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY,
230 current_cred()); 238 current_cred());
@@ -250,7 +258,7 @@ out:
250 dput(child->dentry); 258 dput(child->dentry);
251 kfree(child); 259 kfree(child);
252 } 260 }
253 nfs4_reset_user(uid, gid); 261 nfs4_reset_creds(original_cred);
254 return status; 262 return status;
255} 263}
256 264
@@ -312,8 +320,7 @@ out:
312void 320void
313nfsd4_remove_clid_dir(struct nfs4_client *clp) 321nfsd4_remove_clid_dir(struct nfs4_client *clp)
314{ 322{
315 uid_t uid; 323 const struct cred *original_cred;
316 gid_t gid;
317 int status; 324 int status;
318 325
319 if (!rec_dir_init || !clp->cl_firststate) 326 if (!rec_dir_init || !clp->cl_firststate)
@@ -323,9 +330,13 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
323 if (status) 330 if (status)
324 goto out; 331 goto out;
325 clp->cl_firststate = 0; 332 clp->cl_firststate = 0;
326 nfs4_save_user(&uid, &gid); 333
334 status = nfs4_save_creds(&original_cred);
335 if (status < 0)
336 goto out;
337
327 status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); 338 status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
328 nfs4_reset_user(uid, gid); 339 nfs4_reset_creds(original_cred);
329 if (status == 0) 340 if (status == 0)
330 nfsd4_sync_rec_dir(); 341 nfsd4_sync_rec_dir();
331 mnt_drop_write(rec_dir.mnt); 342 mnt_drop_write(rec_dir.mnt);
@@ -402,16 +413,21 @@ nfsd4_recdir_load(void) {
402void 413void
403nfsd4_init_recdir(char *rec_dirname) 414nfsd4_init_recdir(char *rec_dirname)
404{ 415{
405 uid_t uid = 0; 416 const struct cred *original_cred;
406 gid_t gid = 0; 417 int status;
407 int status;
408 418
409 printk("NFSD: Using %s as the NFSv4 state recovery directory\n", 419 printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
410 rec_dirname); 420 rec_dirname);
411 421
412 BUG_ON(rec_dir_init); 422 BUG_ON(rec_dir_init);
413 423
414 nfs4_save_user(&uid, &gid); 424 status = nfs4_save_creds(&original_cred);
425 if (status < 0) {
426 printk("NFSD: Unable to change credentials to find recovery"
427 " directory: error %d\n",
428 status);
429 return;
430 }
415 431
416 status = kern_path(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, 432 status = kern_path(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
417 &rec_dir); 433 &rec_dir);
@@ -421,7 +437,7 @@ nfsd4_init_recdir(char *rec_dirname)
421 437
422 if (!status) 438 if (!status)
423 rec_dir_init = 1; 439 rec_dir_init = 1;
424 nfs4_reset_user(uid, gid); 440 nfs4_reset_creds(original_cred);
425} 441}
426 442
427void 443void
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index e67cfaea0865..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->cred->cap_effective = 189 struct cred *new = prepare_creds();
190 cap_raise_nfsd_set(current->cred->cap_effective, 190 if (!new)
191 current->cred->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/open.c b/fs/open.c
index f96eaab280a3..c0a426d5766c 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -425,30 +425,33 @@ out:
425 */ 425 */
426asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) 426asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
427{ 427{
428 struct cred *cred = current->cred; 428 const struct cred *old_cred;
429 struct cred *override_cred;
429 struct path path; 430 struct path path;
430 struct inode *inode; 431 struct inode *inode;
431 int old_fsuid, old_fsgid;
432 kernel_cap_t uninitialized_var(old_cap); /* !SECURE_NO_SETUID_FIXUP */
433 int res; 432 int res;
434 433
435 if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ 434 if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
436 return -EINVAL; 435 return -EINVAL;
437 436
438 old_fsuid = cred->fsuid; 437 override_cred = prepare_creds();
439 old_fsgid = cred->fsgid; 438 if (!override_cred)
439 return -ENOMEM;
440 440
441 cred->fsuid = cred->uid; 441 override_cred->fsuid = override_cred->uid;
442 cred->fsgid = cred->gid; 442 override_cred->fsgid = override_cred->gid;
443 443
444 if (!issecure(SECURE_NO_SETUID_FIXUP)) { 444 if (!issecure(SECURE_NO_SETUID_FIXUP)) {
445 /* Clear the capabilities if we switch to a non-root user */ 445 /* Clear the capabilities if we switch to a non-root user */
446 if (current->cred->uid) 446 if (override_cred->uid)
447 old_cap = cap_set_effective(__cap_empty_set); 447 cap_clear(override_cred->cap_effective);
448 else 448 else
449 old_cap = cap_set_effective(cred->cap_permitted); 449 override_cred->cap_effective =
450 override_cred->cap_permitted;
450 } 451 }
451 452
453 old_cred = override_creds(override_cred);
454
452 res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); 455 res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
453 if (res) 456 if (res)
454 goto out; 457 goto out;
@@ -485,12 +488,8 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
485out_path_release: 488out_path_release:
486 path_put(&path); 489 path_put(&path);
487out: 490out:
488 cred->fsuid = old_fsuid; 491 revert_creds(old_cred);
489 cred->fsgid = old_fsgid; 492 put_cred(override_cred);
490
491 if (!issecure(SECURE_NO_SETUID_FIXUP))
492 cap_set_effective(old_cap);
493
494 return res; 493 return res;
495} 494}
496 495