diff options
41 files changed, 1603 insertions, 1239 deletions
@@ -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); |
1840 | fail: | 1851 | fail: |
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 | ||
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 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 | |||
87 | oom: | ||
88 | ret = -ENOMEM; | ||
89 | error: | ||
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 @@ | |||
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->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 | ||
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->cred->fsuid = saveuid; | 76 | revert_creds(original); |
70 | current->cred->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,20 +218,21 @@ 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 | 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: | |||
312 | void | 320 | void |
313 | nfsd4_remove_clid_dir(struct nfs4_client *clp) | 321 | nfsd4_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) { | |||
402 | void | 413 | void |
403 | nfsd4_init_recdir(char *rec_dirname) | 414 | nfsd4_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 | ||
427 | void | 443 | void |
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) |
@@ -425,30 +425,33 @@ out: | |||
425 | */ | 425 | */ |
426 | asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) | 426 | asmlinkage 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) | |||
485 | out_path_release: | 488 | out_path_release: |
486 | path_put(&path); | 489 | path_put(&path); |
487 | out: | 490 | out: |
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 | ||
diff --git a/include/linux/audit.h b/include/linux/audit.h index 6fbebac7b1bf..0b2fcb698a63 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
@@ -454,8 +454,10 @@ extern int __audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_pr | |||
454 | extern int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout); | 454 | extern int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout); |
455 | extern int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification); | 455 | extern int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification); |
456 | extern int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat); | 456 | extern int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat); |
457 | extern void __audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_cap_t *pE); | 457 | extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm, |
458 | extern int __audit_log_capset(pid_t pid, kernel_cap_t *eff, kernel_cap_t *inh, kernel_cap_t *perm); | 458 | const struct cred *new, |
459 | const struct cred *old); | ||
460 | extern int __audit_log_capset(pid_t pid, const struct cred *new, const struct cred *old); | ||
459 | 461 | ||
460 | static inline int audit_ipc_obj(struct kern_ipc_perm *ipcp) | 462 | static inline int audit_ipc_obj(struct kern_ipc_perm *ipcp) |
461 | { | 463 | { |
@@ -522,16 +524,20 @@ static inline int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat) | |||
522 | * | 524 | * |
523 | * -Eric | 525 | * -Eric |
524 | */ | 526 | */ |
525 | static inline void audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_cap_t *pE) | 527 | static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm, |
528 | const struct cred *new, | ||
529 | const struct cred *old) | ||
526 | { | 530 | { |
527 | if (unlikely(!audit_dummy_context())) | 531 | if (unlikely(!audit_dummy_context())) |
528 | __audit_log_bprm_fcaps(bprm, pP, pE); | 532 | return __audit_log_bprm_fcaps(bprm, new, old); |
533 | return 0; | ||
529 | } | 534 | } |
530 | 535 | ||
531 | static inline int audit_log_capset(pid_t pid, kernel_cap_t *eff, kernel_cap_t *inh, kernel_cap_t *perm) | 536 | static inline int audit_log_capset(pid_t pid, const struct cred *new, |
537 | const struct cred *old) | ||
532 | { | 538 | { |
533 | if (unlikely(!audit_dummy_context())) | 539 | if (unlikely(!audit_dummy_context())) |
534 | return __audit_log_capset(pid, eff, inh, perm); | 540 | return __audit_log_capset(pid, new, old); |
535 | return 0; | 541 | return 0; |
536 | } | 542 | } |
537 | 543 | ||
@@ -566,8 +572,8 @@ extern int audit_signals; | |||
566 | #define audit_mq_timedreceive(d,l,p,t) ({ 0; }) | 572 | #define audit_mq_timedreceive(d,l,p,t) ({ 0; }) |
567 | #define audit_mq_notify(d,n) ({ 0; }) | 573 | #define audit_mq_notify(d,n) ({ 0; }) |
568 | #define audit_mq_getsetattr(d,s) ({ 0; }) | 574 | #define audit_mq_getsetattr(d,s) ({ 0; }) |
569 | #define audit_log_bprm_fcaps(b, p, e) do { ; } while (0) | 575 | #define audit_log_bprm_fcaps(b, ncr, ocr) ({ 0; }) |
570 | #define audit_log_capset(pid, e, i, p) ({ 0; }) | 576 | #define audit_log_capset(pid, ncr, ocr) ({ 0; }) |
571 | #define audit_ptrace(t) ((void)0) | 577 | #define audit_ptrace(t) ((void)0) |
572 | #define audit_n_rules 0 | 578 | #define audit_n_rules 0 |
573 | #define audit_signals 0 | 579 | #define audit_signals 0 |
diff --git a/include/linux/capability.h b/include/linux/capability.h index 7f26580a5a4d..e22f48c2a46f 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h | |||
@@ -519,8 +519,6 @@ extern const kernel_cap_t __cap_empty_set; | |||
519 | extern const kernel_cap_t __cap_full_set; | 519 | extern const kernel_cap_t __cap_full_set; |
520 | extern const kernel_cap_t __cap_init_eff_set; | 520 | extern const kernel_cap_t __cap_init_eff_set; |
521 | 521 | ||
522 | kernel_cap_t cap_set_effective(const kernel_cap_t pE_new); | ||
523 | |||
524 | /** | 522 | /** |
525 | * has_capability - Determine if a task has a superior capability available | 523 | * has_capability - Determine if a task has a superior capability available |
526 | * @t: The task in question | 524 | * @t: The task in question |
diff --git a/include/linux/cred.h b/include/linux/cred.h index 62b9e532422d..eaf6fa695a04 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h | |||
@@ -84,6 +84,8 @@ struct thread_group_cred { | |||
84 | struct key *process_keyring; /* keyring private to this process */ | 84 | struct key *process_keyring; /* keyring private to this process */ |
85 | struct rcu_head rcu; /* RCU deletion hook */ | 85 | struct rcu_head rcu; /* RCU deletion hook */ |
86 | }; | 86 | }; |
87 | |||
88 | extern void release_tgcred(struct cred *cred); | ||
87 | #endif | 89 | #endif |
88 | 90 | ||
89 | /* | 91 | /* |
@@ -137,11 +139,30 @@ struct cred { | |||
137 | struct user_struct *user; /* real user ID subscription */ | 139 | struct user_struct *user; /* real user ID subscription */ |
138 | struct group_info *group_info; /* supplementary groups for euid/fsgid */ | 140 | struct group_info *group_info; /* supplementary groups for euid/fsgid */ |
139 | struct rcu_head rcu; /* RCU deletion hook */ | 141 | struct rcu_head rcu; /* RCU deletion hook */ |
140 | spinlock_t lock; /* lock for pointer changes */ | ||
141 | }; | 142 | }; |
142 | 143 | ||
143 | extern void __put_cred(struct cred *); | 144 | extern void __put_cred(struct cred *); |
144 | extern int copy_creds(struct task_struct *, unsigned long); | 145 | extern int copy_creds(struct task_struct *, unsigned long); |
146 | extern struct cred *prepare_creds(void); | ||
147 | extern struct cred *prepare_usermodehelper_creds(void); | ||
148 | extern int commit_creds(struct cred *); | ||
149 | extern void abort_creds(struct cred *); | ||
150 | extern const struct cred *override_creds(const struct cred *) __deprecated; | ||
151 | extern void revert_creds(const struct cred *) __deprecated; | ||
152 | extern void __init cred_init(void); | ||
153 | |||
154 | /** | ||
155 | * get_new_cred - Get a reference on a new set of credentials | ||
156 | * @cred: The new credentials to reference | ||
157 | * | ||
158 | * Get a reference on the specified set of new credentials. The caller must | ||
159 | * release the reference. | ||
160 | */ | ||
161 | static inline struct cred *get_new_cred(struct cred *cred) | ||
162 | { | ||
163 | atomic_inc(&cred->usage); | ||
164 | return cred; | ||
165 | } | ||
145 | 166 | ||
146 | /** | 167 | /** |
147 | * get_cred - Get a reference on a set of credentials | 168 | * get_cred - Get a reference on a set of credentials |
@@ -150,10 +171,9 @@ extern int copy_creds(struct task_struct *, unsigned long); | |||
150 | * Get a reference on the specified set of credentials. The caller must | 171 | * Get a reference on the specified set of credentials. The caller must |
151 | * release the reference. | 172 | * release the reference. |
152 | */ | 173 | */ |
153 | static inline struct cred *get_cred(struct cred *cred) | 174 | static inline const struct cred *get_cred(const struct cred *cred) |
154 | { | 175 | { |
155 | atomic_inc(&cred->usage); | 176 | return get_new_cred((struct cred *) cred); |
156 | return cred; | ||
157 | } | 177 | } |
158 | 178 | ||
159 | /** | 179 | /** |
@@ -166,6 +186,8 @@ static inline struct cred *get_cred(struct cred *cred) | |||
166 | static inline void put_cred(const struct cred *_cred) | 186 | static inline void put_cred(const struct cred *_cred) |
167 | { | 187 | { |
168 | struct cred *cred = (struct cred *) _cred; | 188 | struct cred *cred = (struct cred *) _cred; |
189 | |||
190 | BUG_ON(atomic_read(&(cred)->usage) <= 0); | ||
169 | if (atomic_dec_and_test(&(cred)->usage)) | 191 | if (atomic_dec_and_test(&(cred)->usage)) |
170 | __put_cred(cred); | 192 | __put_cred(cred); |
171 | } | 193 | } |
@@ -250,13 +272,13 @@ static inline void put_cred(const struct cred *_cred) | |||
250 | __groups; \ | 272 | __groups; \ |
251 | }) | 273 | }) |
252 | 274 | ||
253 | #define task_cred_xxx(task, xxx) \ | 275 | #define task_cred_xxx(task, xxx) \ |
254 | ({ \ | 276 | ({ \ |
255 | __typeof__(task->cred->xxx) ___val; \ | 277 | __typeof__(((struct cred *)NULL)->xxx) ___val; \ |
256 | rcu_read_lock(); \ | 278 | rcu_read_lock(); \ |
257 | ___val = __task_cred((task))->xxx; \ | 279 | ___val = __task_cred((task))->xxx; \ |
258 | rcu_read_unlock(); \ | 280 | rcu_read_unlock(); \ |
259 | ___val; \ | 281 | ___val; \ |
260 | }) | 282 | }) |
261 | 283 | ||
262 | #define task_uid(task) (task_cred_xxx((task), uid)) | 284 | #define task_uid(task) (task_cred_xxx((task), uid)) |
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 5e24c54b6dfd..08c3b24ad9a8 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
@@ -150,6 +150,8 @@ extern struct cred init_cred; | |||
150 | .sibling = LIST_HEAD_INIT(tsk.sibling), \ | 150 | .sibling = LIST_HEAD_INIT(tsk.sibling), \ |
151 | .group_leader = &tsk, \ | 151 | .group_leader = &tsk, \ |
152 | .cred = &init_cred, \ | 152 | .cred = &init_cred, \ |
153 | .cred_exec_mutex = \ | ||
154 | __MUTEX_INITIALIZER(tsk.cred_exec_mutex), \ | ||
153 | .comm = "swapper", \ | 155 | .comm = "swapper", \ |
154 | .thread = INIT_THREAD, \ | 156 | .thread = INIT_THREAD, \ |
155 | .fs = &init_fs, \ | 157 | .fs = &init_fs, \ |
diff --git a/include/linux/key.h b/include/linux/key.h index 0836cc838b0c..69ecf0934b02 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
@@ -73,6 +73,7 @@ struct key; | |||
73 | struct seq_file; | 73 | struct seq_file; |
74 | struct user_struct; | 74 | struct user_struct; |
75 | struct signal_struct; | 75 | struct signal_struct; |
76 | struct cred; | ||
76 | 77 | ||
77 | struct key_type; | 78 | struct key_type; |
78 | struct key_owner; | 79 | struct key_owner; |
@@ -181,7 +182,7 @@ struct key { | |||
181 | extern struct key *key_alloc(struct key_type *type, | 182 | extern struct key *key_alloc(struct key_type *type, |
182 | const char *desc, | 183 | const char *desc, |
183 | uid_t uid, gid_t gid, | 184 | uid_t uid, gid_t gid, |
184 | struct task_struct *ctx, | 185 | const struct cred *cred, |
185 | key_perm_t perm, | 186 | key_perm_t perm, |
186 | unsigned long flags); | 187 | unsigned long flags); |
187 | 188 | ||
@@ -249,7 +250,7 @@ extern int key_unlink(struct key *keyring, | |||
249 | struct key *key); | 250 | struct key *key); |
250 | 251 | ||
251 | extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, | 252 | extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, |
252 | struct task_struct *ctx, | 253 | const struct cred *cred, |
253 | unsigned long flags, | 254 | unsigned long flags, |
254 | struct key *dest); | 255 | struct key *dest); |
255 | 256 | ||
@@ -276,22 +277,12 @@ extern ctl_table key_sysctls[]; | |||
276 | /* | 277 | /* |
277 | * the userspace interface | 278 | * the userspace interface |
278 | */ | 279 | */ |
279 | extern void switch_uid_keyring(struct user_struct *new_user); | 280 | extern int install_thread_keyring_to_cred(struct cred *cred); |
280 | extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk); | ||
281 | extern void exit_keys(struct task_struct *tsk); | ||
282 | extern int suid_keys(struct task_struct *tsk); | ||
283 | extern int exec_keys(struct task_struct *tsk); | 281 | extern int exec_keys(struct task_struct *tsk); |
284 | extern void key_fsuid_changed(struct task_struct *tsk); | 282 | extern void key_fsuid_changed(struct task_struct *tsk); |
285 | extern void key_fsgid_changed(struct task_struct *tsk); | 283 | extern void key_fsgid_changed(struct task_struct *tsk); |
286 | extern void key_init(void); | 284 | extern void key_init(void); |
287 | 285 | ||
288 | #define __install_session_keyring(keyring) \ | ||
289 | ({ \ | ||
290 | struct key *old_session = current->cred->tgcred->session_keyring; \ | ||
291 | current->cred->tgcred->session_keyring = keyring; \ | ||
292 | old_session; \ | ||
293 | }) | ||
294 | |||
295 | #else /* CONFIG_KEYS */ | 286 | #else /* CONFIG_KEYS */ |
296 | 287 | ||
297 | #define key_validate(k) 0 | 288 | #define key_validate(k) 0 |
@@ -303,11 +294,6 @@ extern void key_init(void); | |||
303 | #define make_key_ref(k, p) NULL | 294 | #define make_key_ref(k, p) NULL |
304 | #define key_ref_to_ptr(k) NULL | 295 | #define key_ref_to_ptr(k) NULL |
305 | #define is_key_possessed(k) 0 | 296 | #define is_key_possessed(k) 0 |
306 | #define switch_uid_keyring(u) do { } while(0) | ||
307 | #define __install_session_keyring(k) ({ NULL; }) | ||
308 | #define copy_keys(f,t) 0 | ||
309 | #define exit_keys(t) do { } while(0) | ||
310 | #define suid_keys(t) do { } while(0) | ||
311 | #define exec_keys(t) do { } while(0) | 297 | #define exec_keys(t) do { } while(0) |
312 | #define key_fsuid_changed(t) do { } while(0) | 298 | #define key_fsuid_changed(t) do { } while(0) |
313 | #define key_fsgid_changed(t) do { } while(0) | 299 | #define key_fsgid_changed(t) do { } while(0) |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 2913252989b3..121d655e460d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1145,7 +1145,8 @@ struct task_struct { | |||
1145 | struct list_head cpu_timers[3]; | 1145 | struct list_head cpu_timers[3]; |
1146 | 1146 | ||
1147 | /* process credentials */ | 1147 | /* process credentials */ |
1148 | struct cred *cred; /* actual/objective task credentials */ | 1148 | const struct cred *cred; /* actual/objective task credentials (COW) */ |
1149 | struct mutex cred_exec_mutex; /* execve vs ptrace cred calculation mutex */ | ||
1149 | 1150 | ||
1150 | char comm[TASK_COMM_LEN]; /* executable name excluding path | 1151 | char comm[TASK_COMM_LEN]; /* executable name excluding path |
1151 | - access with [gs]et_task_comm (which lock | 1152 | - access with [gs]et_task_comm (which lock |
@@ -1720,7 +1721,6 @@ static inline struct user_struct *get_uid(struct user_struct *u) | |||
1720 | return u; | 1721 | return u; |
1721 | } | 1722 | } |
1722 | extern void free_uid(struct user_struct *); | 1723 | extern void free_uid(struct user_struct *); |
1723 | extern void switch_uid(struct user_struct *); | ||
1724 | extern void release_uids(struct user_namespace *ns); | 1724 | extern void release_uids(struct user_namespace *ns); |
1725 | 1725 | ||
1726 | #include <asm/current.h> | 1726 | #include <asm/current.h> |
@@ -1870,6 +1870,8 @@ static inline unsigned long wait_task_inactive(struct task_struct *p, | |||
1870 | #define for_each_process(p) \ | 1870 | #define for_each_process(p) \ |
1871 | for (p = &init_task ; (p = next_task(p)) != &init_task ; ) | 1871 | for (p = &init_task ; (p = next_task(p)) != &init_task ; ) |
1872 | 1872 | ||
1873 | extern bool is_single_threaded(struct task_struct *); | ||
1874 | |||
1873 | /* | 1875 | /* |
1874 | * Careful: do_each_thread/while_each_thread is a double loop so | 1876 | * Careful: do_each_thread/while_each_thread is a double loop so |
1875 | * 'break' will not work as expected - use goto instead. | 1877 | * 'break' will not work as expected - use goto instead. |
diff --git a/include/linux/security.h b/include/linux/security.h index 7e9fe046a0d1..68be11251447 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -53,24 +53,21 @@ extern int cap_settime(struct timespec *ts, struct timezone *tz); | |||
53 | extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode); | 53 | extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode); |
54 | extern int cap_ptrace_traceme(struct task_struct *parent); | 54 | extern int cap_ptrace_traceme(struct task_struct *parent); |
55 | extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); | 55 | extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); |
56 | extern int cap_capset_check(const kernel_cap_t *effective, | 56 | extern int cap_capset(struct cred *new, const struct cred *old, |
57 | const kernel_cap_t *inheritable, | 57 | const kernel_cap_t *effective, |
58 | const kernel_cap_t *permitted); | 58 | const kernel_cap_t *inheritable, |
59 | extern void cap_capset_set(const kernel_cap_t *effective, | 59 | const kernel_cap_t *permitted); |
60 | const kernel_cap_t *inheritable, | ||
61 | const kernel_cap_t *permitted); | ||
62 | extern int cap_bprm_set_security(struct linux_binprm *bprm); | 60 | extern int cap_bprm_set_security(struct linux_binprm *bprm); |
63 | extern void cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe); | 61 | extern int cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe); |
64 | extern int cap_bprm_secureexec(struct linux_binprm *bprm); | 62 | extern int cap_bprm_secureexec(struct linux_binprm *bprm); |
65 | extern int cap_inode_setxattr(struct dentry *dentry, const char *name, | 63 | extern int cap_inode_setxattr(struct dentry *dentry, const char *name, |
66 | const void *value, size_t size, int flags); | 64 | const void *value, size_t size, int flags); |
67 | extern int cap_inode_removexattr(struct dentry *dentry, const char *name); | 65 | extern int cap_inode_removexattr(struct dentry *dentry, const char *name); |
68 | extern int cap_inode_need_killpriv(struct dentry *dentry); | 66 | extern int cap_inode_need_killpriv(struct dentry *dentry); |
69 | extern int cap_inode_killpriv(struct dentry *dentry); | 67 | extern int cap_inode_killpriv(struct dentry *dentry); |
70 | extern int cap_task_post_setuid(uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags); | 68 | extern int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags); |
71 | extern void cap_task_reparent_to_init(struct task_struct *p); | ||
72 | extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | 69 | extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, |
73 | unsigned long arg4, unsigned long arg5, long *rc_p); | 70 | unsigned long arg4, unsigned long arg5); |
74 | extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp); | 71 | extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp); |
75 | extern int cap_task_setioprio(struct task_struct *p, int ioprio); | 72 | extern int cap_task_setioprio(struct task_struct *p, int ioprio); |
76 | extern int cap_task_setnice(struct task_struct *p, int nice); | 73 | extern int cap_task_setnice(struct task_struct *p, int nice); |
@@ -170,8 +167,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
170 | * Compute and set the security attributes of a process being transformed | 167 | * Compute and set the security attributes of a process being transformed |
171 | * by an execve operation based on the old attributes (current->security) | 168 | * by an execve operation based on the old attributes (current->security) |
172 | * and the information saved in @bprm->security by the set_security hook. | 169 | * and the information saved in @bprm->security by the set_security hook. |
173 | * Since this hook function (and its caller) are void, this hook can not | 170 | * Since this function may return an error, in which case the process will |
174 | * return an error. However, it can leave the security attributes of the | 171 | * be killed. However, it can leave the security attributes of the |
175 | * process unchanged if an access failure occurs at this point. | 172 | * process unchanged if an access failure occurs at this point. |
176 | * bprm_apply_creds is called under task_lock. @unsafe indicates various | 173 | * bprm_apply_creds is called under task_lock. @unsafe indicates various |
177 | * reasons why it may be unsafe to change security state. | 174 | * reasons why it may be unsafe to change security state. |
@@ -593,15 +590,18 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
593 | * manual page for definitions of the @clone_flags. | 590 | * manual page for definitions of the @clone_flags. |
594 | * @clone_flags contains the flags indicating what should be shared. | 591 | * @clone_flags contains the flags indicating what should be shared. |
595 | * Return 0 if permission is granted. | 592 | * Return 0 if permission is granted. |
596 | * @cred_alloc_security: | ||
597 | * @cred contains the cred struct for child process. | ||
598 | * Allocate and attach a security structure to the cred->security field. | ||
599 | * The security field is initialized to NULL when the task structure is | ||
600 | * allocated. | ||
601 | * Return 0 if operation was successful. | ||
602 | * @cred_free: | 593 | * @cred_free: |
603 | * @cred points to the credentials. | 594 | * @cred points to the credentials. |
604 | * Deallocate and clear the cred->security field in a set of credentials. | 595 | * Deallocate and clear the cred->security field in a set of credentials. |
596 | * @cred_prepare: | ||
597 | * @new points to the new credentials. | ||
598 | * @old points to the original credentials. | ||
599 | * @gfp indicates the atomicity of any memory allocations. | ||
600 | * Prepare a new set of credentials by copying the data from the old set. | ||
601 | * @cred_commit: | ||
602 | * @new points to the new credentials. | ||
603 | * @old points to the original credentials. | ||
604 | * Install a new set of credentials. | ||
605 | * @task_setuid: | 605 | * @task_setuid: |
606 | * Check permission before setting one or more of the user identity | 606 | * Check permission before setting one or more of the user identity |
607 | * attributes of the current process. The @flags parameter indicates | 607 | * attributes of the current process. The @flags parameter indicates |
@@ -614,15 +614,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
614 | * @id2 contains a uid. | 614 | * @id2 contains a uid. |
615 | * @flags contains one of the LSM_SETID_* values. | 615 | * @flags contains one of the LSM_SETID_* values. |
616 | * Return 0 if permission is granted. | 616 | * Return 0 if permission is granted. |
617 | * @task_post_setuid: | 617 | * @task_fix_setuid: |
618 | * Update the module's state after setting one or more of the user | 618 | * Update the module's state after setting one or more of the user |
619 | * identity attributes of the current process. The @flags parameter | 619 | * identity attributes of the current process. The @flags parameter |
620 | * indicates which of the set*uid system calls invoked this hook. If | 620 | * indicates which of the set*uid system calls invoked this hook. If |
621 | * @flags is LSM_SETID_FS, then @old_ruid is the old fs uid and the other | 621 | * @new is the set of credentials that will be installed. Modifications |
622 | * parameters are not used. | 622 | * should be made to this rather than to @current->cred. |
623 | * @old_ruid contains the old real uid (or fs uid if LSM_SETID_FS). | 623 | * @old is the set of credentials that are being replaces |
624 | * @old_euid contains the old effective uid (or -1 if LSM_SETID_FS). | ||
625 | * @old_suid contains the old saved uid (or -1 if LSM_SETID_FS). | ||
626 | * @flags contains one of the LSM_SETID_* values. | 624 | * @flags contains one of the LSM_SETID_* values. |
627 | * Return 0 on success. | 625 | * Return 0 on success. |
628 | * @task_setgid: | 626 | * @task_setgid: |
@@ -725,13 +723,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
725 | * @arg3 contains a argument. | 723 | * @arg3 contains a argument. |
726 | * @arg4 contains a argument. | 724 | * @arg4 contains a argument. |
727 | * @arg5 contains a argument. | 725 | * @arg5 contains a argument. |
728 | * @rc_p contains a pointer to communicate back the forced return code | 726 | * Return -ENOSYS if no-one wanted to handle this op, any other value to |
729 | * Return 0 if permission is granted, and non-zero if the security module | 727 | * cause prctl() to return immediately with that value. |
730 | * has taken responsibility (setting *rc_p) for the prctl call. | ||
731 | * @task_reparent_to_init: | ||
732 | * Set the security attributes in @p->security for a kernel thread that | ||
733 | * is being reparented to the init task. | ||
734 | * @p contains the task_struct for the kernel thread. | ||
735 | * @task_to_inode: | 728 | * @task_to_inode: |
736 | * Set the security attributes for an inode based on an associated task's | 729 | * Set the security attributes for an inode based on an associated task's |
737 | * security attributes, e.g. for /proc/pid inodes. | 730 | * security attributes, e.g. for /proc/pid inodes. |
@@ -1008,7 +1001,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
1008 | * See whether a specific operational right is granted to a process on a | 1001 | * See whether a specific operational right is granted to a process on a |
1009 | * key. | 1002 | * key. |
1010 | * @key_ref refers to the key (key pointer + possession attribute bit). | 1003 | * @key_ref refers to the key (key pointer + possession attribute bit). |
1011 | * @context points to the process to provide the context against which to | 1004 | * @cred points to the credentials to provide the context against which to |
1012 | * evaluate the security data on the key. | 1005 | * evaluate the security data on the key. |
1013 | * @perm describes the combination of permissions required of this key. | 1006 | * @perm describes the combination of permissions required of this key. |
1014 | * Return 1 if permission granted, 0 if permission denied and -ve it the | 1007 | * Return 1 if permission granted, 0 if permission denied and -ve it the |
@@ -1170,6 +1163,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
1170 | * @child process. | 1163 | * @child process. |
1171 | * Security modules may also want to perform a process tracing check | 1164 | * Security modules may also want to perform a process tracing check |
1172 | * during an execve in the set_security or apply_creds hooks of | 1165 | * during an execve in the set_security or apply_creds hooks of |
1166 | * tracing check during an execve in the bprm_set_creds hook of | ||
1173 | * binprm_security_ops if the process is being traced and its security | 1167 | * binprm_security_ops if the process is being traced and its security |
1174 | * attributes would be changed by the execve. | 1168 | * attributes would be changed by the execve. |
1175 | * @child contains the task_struct structure for the target process. | 1169 | * @child contains the task_struct structure for the target process. |
@@ -1193,19 +1187,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
1193 | * @inheritable contains the inheritable capability set. | 1187 | * @inheritable contains the inheritable capability set. |
1194 | * @permitted contains the permitted capability set. | 1188 | * @permitted contains the permitted capability set. |
1195 | * Return 0 if the capability sets were successfully obtained. | 1189 | * Return 0 if the capability sets were successfully obtained. |
1196 | * @capset_check: | 1190 | * @capset: |
1197 | * Check permission before setting the @effective, @inheritable, and | ||
1198 | * @permitted capability sets for the current process. | ||
1199 | * @effective contains the effective capability set. | ||
1200 | * @inheritable contains the inheritable capability set. | ||
1201 | * @permitted contains the permitted capability set. | ||
1202 | * Return 0 if permission is granted. | ||
1203 | * @capset_set: | ||
1204 | * Set the @effective, @inheritable, and @permitted capability sets for | 1191 | * Set the @effective, @inheritable, and @permitted capability sets for |
1205 | * the current process. | 1192 | * the current process. |
1193 | * @new contains the new credentials structure for target process. | ||
1194 | * @old contains the current credentials structure for target process. | ||
1206 | * @effective contains the effective capability set. | 1195 | * @effective contains the effective capability set. |
1207 | * @inheritable contains the inheritable capability set. | 1196 | * @inheritable contains the inheritable capability set. |
1208 | * @permitted contains the permitted capability set. | 1197 | * @permitted contains the permitted capability set. |
1198 | * Return 0 and update @new if permission is granted. | ||
1209 | * @capable: | 1199 | * @capable: |
1210 | * Check whether the @tsk process has the @cap capability. | 1200 | * Check whether the @tsk process has the @cap capability. |
1211 | * @tsk contains the task_struct for the process. | 1201 | * @tsk contains the task_struct for the process. |
@@ -1297,12 +1287,11 @@ struct security_operations { | |||
1297 | int (*capget) (struct task_struct *target, | 1287 | int (*capget) (struct task_struct *target, |
1298 | kernel_cap_t *effective, | 1288 | kernel_cap_t *effective, |
1299 | kernel_cap_t *inheritable, kernel_cap_t *permitted); | 1289 | kernel_cap_t *inheritable, kernel_cap_t *permitted); |
1300 | int (*capset_check) (const kernel_cap_t *effective, | 1290 | int (*capset) (struct cred *new, |
1301 | const kernel_cap_t *inheritable, | 1291 | const struct cred *old, |
1302 | const kernel_cap_t *permitted); | 1292 | const kernel_cap_t *effective, |
1303 | void (*capset_set) (const kernel_cap_t *effective, | 1293 | const kernel_cap_t *inheritable, |
1304 | const kernel_cap_t *inheritable, | 1294 | const kernel_cap_t *permitted); |
1305 | const kernel_cap_t *permitted); | ||
1306 | int (*capable) (struct task_struct *tsk, int cap, int audit); | 1295 | int (*capable) (struct task_struct *tsk, int cap, int audit); |
1307 | int (*acct) (struct file *file); | 1296 | int (*acct) (struct file *file); |
1308 | int (*sysctl) (struct ctl_table *table, int op); | 1297 | int (*sysctl) (struct ctl_table *table, int op); |
@@ -1314,7 +1303,7 @@ struct security_operations { | |||
1314 | 1303 | ||
1315 | int (*bprm_alloc_security) (struct linux_binprm *bprm); | 1304 | int (*bprm_alloc_security) (struct linux_binprm *bprm); |
1316 | void (*bprm_free_security) (struct linux_binprm *bprm); | 1305 | void (*bprm_free_security) (struct linux_binprm *bprm); |
1317 | void (*bprm_apply_creds) (struct linux_binprm *bprm, int unsafe); | 1306 | int (*bprm_apply_creds) (struct linux_binprm *bprm, int unsafe); |
1318 | void (*bprm_post_apply_creds) (struct linux_binprm *bprm); | 1307 | void (*bprm_post_apply_creds) (struct linux_binprm *bprm); |
1319 | int (*bprm_set_security) (struct linux_binprm *bprm); | 1308 | int (*bprm_set_security) (struct linux_binprm *bprm); |
1320 | int (*bprm_check_security) (struct linux_binprm *bprm); | 1309 | int (*bprm_check_security) (struct linux_binprm *bprm); |
@@ -1405,11 +1394,13 @@ struct security_operations { | |||
1405 | int (*dentry_open) (struct file *file, const struct cred *cred); | 1394 | int (*dentry_open) (struct file *file, const struct cred *cred); |
1406 | 1395 | ||
1407 | int (*task_create) (unsigned long clone_flags); | 1396 | int (*task_create) (unsigned long clone_flags); |
1408 | int (*cred_alloc_security) (struct cred *cred); | ||
1409 | void (*cred_free) (struct cred *cred); | 1397 | void (*cred_free) (struct cred *cred); |
1398 | int (*cred_prepare)(struct cred *new, const struct cred *old, | ||
1399 | gfp_t gfp); | ||
1400 | void (*cred_commit)(struct cred *new, const struct cred *old); | ||
1410 | int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags); | 1401 | int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags); |
1411 | int (*task_post_setuid) (uid_t old_ruid /* or fsuid */ , | 1402 | int (*task_fix_setuid) (struct cred *new, const struct cred *old, |
1412 | uid_t old_euid, uid_t old_suid, int flags); | 1403 | int flags); |
1413 | int (*task_setgid) (gid_t id0, gid_t id1, gid_t id2, int flags); | 1404 | int (*task_setgid) (gid_t id0, gid_t id1, gid_t id2, int flags); |
1414 | int (*task_setpgid) (struct task_struct *p, pid_t pgid); | 1405 | int (*task_setpgid) (struct task_struct *p, pid_t pgid); |
1415 | int (*task_getpgid) (struct task_struct *p); | 1406 | int (*task_getpgid) (struct task_struct *p); |
@@ -1429,8 +1420,7 @@ struct security_operations { | |||
1429 | int (*task_wait) (struct task_struct *p); | 1420 | int (*task_wait) (struct task_struct *p); |
1430 | int (*task_prctl) (int option, unsigned long arg2, | 1421 | int (*task_prctl) (int option, unsigned long arg2, |
1431 | unsigned long arg3, unsigned long arg4, | 1422 | unsigned long arg3, unsigned long arg4, |
1432 | unsigned long arg5, long *rc_p); | 1423 | unsigned long arg5); |
1433 | void (*task_reparent_to_init) (struct task_struct *p); | ||
1434 | void (*task_to_inode) (struct task_struct *p, struct inode *inode); | 1424 | void (*task_to_inode) (struct task_struct *p, struct inode *inode); |
1435 | 1425 | ||
1436 | int (*ipc_permission) (struct kern_ipc_perm *ipcp, short flag); | 1426 | int (*ipc_permission) (struct kern_ipc_perm *ipcp, short flag); |
@@ -1535,10 +1525,10 @@ struct security_operations { | |||
1535 | 1525 | ||
1536 | /* key management security hooks */ | 1526 | /* key management security hooks */ |
1537 | #ifdef CONFIG_KEYS | 1527 | #ifdef CONFIG_KEYS |
1538 | int (*key_alloc) (struct key *key, struct task_struct *tsk, unsigned long flags); | 1528 | int (*key_alloc) (struct key *key, const struct cred *cred, unsigned long flags); |
1539 | void (*key_free) (struct key *key); | 1529 | void (*key_free) (struct key *key); |
1540 | int (*key_permission) (key_ref_t key_ref, | 1530 | int (*key_permission) (key_ref_t key_ref, |
1541 | struct task_struct *context, | 1531 | const struct cred *cred, |
1542 | key_perm_t perm); | 1532 | key_perm_t perm); |
1543 | int (*key_getsecurity)(struct key *key, char **_buffer); | 1533 | int (*key_getsecurity)(struct key *key, char **_buffer); |
1544 | #endif /* CONFIG_KEYS */ | 1534 | #endif /* CONFIG_KEYS */ |
@@ -1564,12 +1554,10 @@ int security_capget(struct task_struct *target, | |||
1564 | kernel_cap_t *effective, | 1554 | kernel_cap_t *effective, |
1565 | kernel_cap_t *inheritable, | 1555 | kernel_cap_t *inheritable, |
1566 | kernel_cap_t *permitted); | 1556 | kernel_cap_t *permitted); |
1567 | int security_capset_check(const kernel_cap_t *effective, | 1557 | int security_capset(struct cred *new, const struct cred *old, |
1568 | const kernel_cap_t *inheritable, | 1558 | const kernel_cap_t *effective, |
1569 | const kernel_cap_t *permitted); | 1559 | const kernel_cap_t *inheritable, |
1570 | void security_capset_set(const kernel_cap_t *effective, | 1560 | const kernel_cap_t *permitted); |
1571 | const kernel_cap_t *inheritable, | ||
1572 | const kernel_cap_t *permitted); | ||
1573 | int security_capable(struct task_struct *tsk, int cap); | 1561 | int security_capable(struct task_struct *tsk, int cap); |
1574 | int security_capable_noaudit(struct task_struct *tsk, int cap); | 1562 | int security_capable_noaudit(struct task_struct *tsk, int cap); |
1575 | int security_acct(struct file *file); | 1563 | int security_acct(struct file *file); |
@@ -1583,7 +1571,7 @@ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages); | |||
1583 | int security_vm_enough_memory_kern(long pages); | 1571 | int security_vm_enough_memory_kern(long pages); |
1584 | int security_bprm_alloc(struct linux_binprm *bprm); | 1572 | int security_bprm_alloc(struct linux_binprm *bprm); |
1585 | void security_bprm_free(struct linux_binprm *bprm); | 1573 | void security_bprm_free(struct linux_binprm *bprm); |
1586 | void security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe); | 1574 | int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe); |
1587 | void security_bprm_post_apply_creds(struct linux_binprm *bprm); | 1575 | void security_bprm_post_apply_creds(struct linux_binprm *bprm); |
1588 | int security_bprm_set(struct linux_binprm *bprm); | 1576 | int security_bprm_set(struct linux_binprm *bprm); |
1589 | int security_bprm_check(struct linux_binprm *bprm); | 1577 | int security_bprm_check(struct linux_binprm *bprm); |
@@ -1660,11 +1648,12 @@ int security_file_send_sigiotask(struct task_struct *tsk, | |||
1660 | int security_file_receive(struct file *file); | 1648 | int security_file_receive(struct file *file); |
1661 | int security_dentry_open(struct file *file, const struct cred *cred); | 1649 | int security_dentry_open(struct file *file, const struct cred *cred); |
1662 | int security_task_create(unsigned long clone_flags); | 1650 | int security_task_create(unsigned long clone_flags); |
1663 | int security_cred_alloc(struct cred *cred); | ||
1664 | void security_cred_free(struct cred *cred); | 1651 | void security_cred_free(struct cred *cred); |
1652 | int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp); | ||
1653 | void security_commit_creds(struct cred *new, const struct cred *old); | ||
1665 | int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags); | 1654 | int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags); |
1666 | int security_task_post_setuid(uid_t old_ruid, uid_t old_euid, | 1655 | int security_task_fix_setuid(struct cred *new, const struct cred *old, |
1667 | uid_t old_suid, int flags); | 1656 | int flags); |
1668 | int security_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags); | 1657 | int security_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags); |
1669 | int security_task_setpgid(struct task_struct *p, pid_t pgid); | 1658 | int security_task_setpgid(struct task_struct *p, pid_t pgid); |
1670 | int security_task_getpgid(struct task_struct *p); | 1659 | int security_task_getpgid(struct task_struct *p); |
@@ -1683,8 +1672,7 @@ int security_task_kill(struct task_struct *p, struct siginfo *info, | |||
1683 | int sig, u32 secid); | 1672 | int sig, u32 secid); |
1684 | int security_task_wait(struct task_struct *p); | 1673 | int security_task_wait(struct task_struct *p); |
1685 | int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, | 1674 | int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, |
1686 | unsigned long arg4, unsigned long arg5, long *rc_p); | 1675 | unsigned long arg4, unsigned long arg5); |
1687 | void security_task_reparent_to_init(struct task_struct *p); | ||
1688 | void security_task_to_inode(struct task_struct *p, struct inode *inode); | 1676 | void security_task_to_inode(struct task_struct *p, struct inode *inode); |
1689 | int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag); | 1677 | int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag); |
1690 | void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid); | 1678 | void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid); |
@@ -1759,18 +1747,13 @@ static inline int security_capget(struct task_struct *target, | |||
1759 | return cap_capget(target, effective, inheritable, permitted); | 1747 | return cap_capget(target, effective, inheritable, permitted); |
1760 | } | 1748 | } |
1761 | 1749 | ||
1762 | static inline int security_capset_check(const kernel_cap_t *effective, | 1750 | static inline int security_capset(struct cred *new, |
1763 | const kernel_cap_t *inheritable, | 1751 | const struct cred *old, |
1764 | const kernel_cap_t *permitted) | 1752 | const kernel_cap_t *effective, |
1753 | const kernel_cap_t *inheritable, | ||
1754 | const kernel_cap_t *permitted) | ||
1765 | { | 1755 | { |
1766 | return cap_capset_check(effective, inheritable, permitted); | 1756 | return cap_capset(new, old, effective, inheritable, permitted); |
1767 | } | ||
1768 | |||
1769 | static inline void security_capset_set(const kernel_cap_t *effective, | ||
1770 | const kernel_cap_t *inheritable, | ||
1771 | const kernel_cap_t *permitted) | ||
1772 | { | ||
1773 | cap_capset_set(effective, inheritable, permitted); | ||
1774 | } | 1757 | } |
1775 | 1758 | ||
1776 | static inline int security_capable(struct task_struct *tsk, int cap) | 1759 | static inline int security_capable(struct task_struct *tsk, int cap) |
@@ -1837,9 +1820,9 @@ static inline int security_bprm_alloc(struct linux_binprm *bprm) | |||
1837 | static inline void security_bprm_free(struct linux_binprm *bprm) | 1820 | static inline void security_bprm_free(struct linux_binprm *bprm) |
1838 | { } | 1821 | { } |
1839 | 1822 | ||
1840 | static inline void security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) | 1823 | static inline int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) |
1841 | { | 1824 | { |
1842 | cap_bprm_apply_creds(bprm, unsafe); | 1825 | return cap_bprm_apply_creds(bprm, unsafe); |
1843 | } | 1826 | } |
1844 | 1827 | ||
1845 | static inline void security_bprm_post_apply_creds(struct linux_binprm *bprm) | 1828 | static inline void security_bprm_post_apply_creds(struct linux_binprm *bprm) |
@@ -2182,13 +2165,20 @@ static inline int security_task_create(unsigned long clone_flags) | |||
2182 | return 0; | 2165 | return 0; |
2183 | } | 2166 | } |
2184 | 2167 | ||
2185 | static inline int security_cred_alloc(struct cred *cred) | 2168 | static inline void security_cred_free(struct cred *cred) |
2169 | { } | ||
2170 | |||
2171 | static inline int security_prepare_creds(struct cred *new, | ||
2172 | const struct cred *old, | ||
2173 | gfp_t gfp) | ||
2186 | { | 2174 | { |
2187 | return 0; | 2175 | return 0; |
2188 | } | 2176 | } |
2189 | 2177 | ||
2190 | static inline void security_cred_free(struct cred *cred) | 2178 | static inline void security_commit_creds(struct cred *new, |
2191 | { } | 2179 | const struct cred *old) |
2180 | { | ||
2181 | } | ||
2192 | 2182 | ||
2193 | static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, | 2183 | static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, |
2194 | int flags) | 2184 | int flags) |
@@ -2196,10 +2186,11 @@ static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, | |||
2196 | return 0; | 2186 | return 0; |
2197 | } | 2187 | } |
2198 | 2188 | ||
2199 | static inline int security_task_post_setuid(uid_t old_ruid, uid_t old_euid, | 2189 | static inline int security_task_fix_setuid(struct cred *new, |
2200 | uid_t old_suid, int flags) | 2190 | const struct cred *old, |
2191 | int flags) | ||
2201 | { | 2192 | { |
2202 | return cap_task_post_setuid(old_ruid, old_euid, old_suid, flags); | 2193 | return cap_task_fix_setuid(new, old, flags); |
2203 | } | 2194 | } |
2204 | 2195 | ||
2205 | static inline int security_task_setgid(gid_t id0, gid_t id1, gid_t id2, | 2196 | static inline int security_task_setgid(gid_t id0, gid_t id1, gid_t id2, |
@@ -2286,14 +2277,9 @@ static inline int security_task_wait(struct task_struct *p) | |||
2286 | static inline int security_task_prctl(int option, unsigned long arg2, | 2277 | static inline int security_task_prctl(int option, unsigned long arg2, |
2287 | unsigned long arg3, | 2278 | unsigned long arg3, |
2288 | unsigned long arg4, | 2279 | unsigned long arg4, |
2289 | unsigned long arg5, long *rc_p) | 2280 | unsigned long arg5) |
2290 | { | ||
2291 | return cap_task_prctl(option, arg2, arg3, arg3, arg5, rc_p); | ||
2292 | } | ||
2293 | |||
2294 | static inline void security_task_reparent_to_init(struct task_struct *p) | ||
2295 | { | 2281 | { |
2296 | cap_task_reparent_to_init(p); | 2282 | return cap_task_prctl(option, arg2, arg3, arg3, arg5); |
2297 | } | 2283 | } |
2298 | 2284 | ||
2299 | static inline void security_task_to_inode(struct task_struct *p, struct inode *inode) | 2285 | static inline void security_task_to_inode(struct task_struct *p, struct inode *inode) |
@@ -2719,16 +2705,16 @@ static inline void security_skb_classify_flow(struct sk_buff *skb, struct flowi | |||
2719 | #ifdef CONFIG_KEYS | 2705 | #ifdef CONFIG_KEYS |
2720 | #ifdef CONFIG_SECURITY | 2706 | #ifdef CONFIG_SECURITY |
2721 | 2707 | ||
2722 | int security_key_alloc(struct key *key, struct task_struct *tsk, unsigned long flags); | 2708 | int security_key_alloc(struct key *key, const struct cred *cred, unsigned long flags); |
2723 | void security_key_free(struct key *key); | 2709 | void security_key_free(struct key *key); |
2724 | int security_key_permission(key_ref_t key_ref, | 2710 | int security_key_permission(key_ref_t key_ref, |
2725 | struct task_struct *context, key_perm_t perm); | 2711 | const struct cred *cred, key_perm_t perm); |
2726 | int security_key_getsecurity(struct key *key, char **_buffer); | 2712 | int security_key_getsecurity(struct key *key, char **_buffer); |
2727 | 2713 | ||
2728 | #else | 2714 | #else |
2729 | 2715 | ||
2730 | static inline int security_key_alloc(struct key *key, | 2716 | static inline int security_key_alloc(struct key *key, |
2731 | struct task_struct *tsk, | 2717 | const struct cred *cred, |
2732 | unsigned long flags) | 2718 | unsigned long flags) |
2733 | { | 2719 | { |
2734 | return 0; | 2720 | return 0; |
@@ -2739,7 +2725,7 @@ static inline void security_key_free(struct key *key) | |||
2739 | } | 2725 | } |
2740 | 2726 | ||
2741 | static inline int security_key_permission(key_ref_t key_ref, | 2727 | static inline int security_key_permission(key_ref_t key_ref, |
2742 | struct task_struct *context, | 2728 | const struct cred *cred, |
2743 | key_perm_t perm) | 2729 | key_perm_t perm) |
2744 | { | 2730 | { |
2745 | return 0; | 2731 | return 0; |
diff --git a/init/main.c b/init/main.c index 7e117a231af1..db843bff5732 100644 --- a/init/main.c +++ b/init/main.c | |||
@@ -669,6 +669,7 @@ asmlinkage void __init start_kernel(void) | |||
669 | efi_enter_virtual_mode(); | 669 | efi_enter_virtual_mode(); |
670 | #endif | 670 | #endif |
671 | thread_info_cache_init(); | 671 | thread_info_cache_init(); |
672 | cred_init(); | ||
672 | fork_init(num_physpages); | 673 | fork_init(num_physpages); |
673 | proc_caches_init(); | 674 | proc_caches_init(); |
674 | buffer_init(); | 675 | buffer_init(); |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index ae8ef88ade3f..bc1e2d854bf6 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -2546,18 +2546,17 @@ int __audit_signal_info(int sig, struct task_struct *t) | |||
2546 | 2546 | ||
2547 | /** | 2547 | /** |
2548 | * __audit_log_bprm_fcaps - store information about a loading bprm and relevant fcaps | 2548 | * __audit_log_bprm_fcaps - store information about a loading bprm and relevant fcaps |
2549 | * @bprm pointer to the bprm being processed | 2549 | * @bprm: pointer to the bprm being processed |
2550 | * @caps the caps read from the disk | 2550 | * @new: the proposed new credentials |
2551 | * @old: the old credentials | ||
2551 | * | 2552 | * |
2552 | * Simply check if the proc already has the caps given by the file and if not | 2553 | * Simply check if the proc already has the caps given by the file and if not |
2553 | * store the priv escalation info for later auditing at the end of the syscall | 2554 | * store the priv escalation info for later auditing at the end of the syscall |
2554 | * | 2555 | * |
2555 | * this can fail and we don't care. See the note in audit.h for | ||
2556 | * audit_log_bprm_fcaps() for my explaination.... | ||
2557 | * | ||
2558 | * -Eric | 2556 | * -Eric |
2559 | */ | 2557 | */ |
2560 | void __audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_cap_t *pE) | 2558 | int __audit_log_bprm_fcaps(struct linux_binprm *bprm, |
2559 | const struct cred *new, const struct cred *old) | ||
2561 | { | 2560 | { |
2562 | struct audit_aux_data_bprm_fcaps *ax; | 2561 | struct audit_aux_data_bprm_fcaps *ax; |
2563 | struct audit_context *context = current->audit_context; | 2562 | struct audit_context *context = current->audit_context; |
@@ -2566,7 +2565,7 @@ void __audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_ | |||
2566 | 2565 | ||
2567 | ax = kmalloc(sizeof(*ax), GFP_KERNEL); | 2566 | ax = kmalloc(sizeof(*ax), GFP_KERNEL); |
2568 | if (!ax) | 2567 | if (!ax) |
2569 | return; | 2568 | return -ENOMEM; |
2570 | 2569 | ||
2571 | ax->d.type = AUDIT_BPRM_FCAPS; | 2570 | ax->d.type = AUDIT_BPRM_FCAPS; |
2572 | ax->d.next = context->aux; | 2571 | ax->d.next = context->aux; |
@@ -2581,26 +2580,27 @@ void __audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_ | |||
2581 | ax->fcap.fE = !!(vcaps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE); | 2580 | ax->fcap.fE = !!(vcaps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE); |
2582 | ax->fcap_ver = (vcaps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT; | 2581 | ax->fcap_ver = (vcaps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT; |
2583 | 2582 | ||
2584 | ax->old_pcap.permitted = *pP; | 2583 | ax->old_pcap.permitted = old->cap_permitted; |
2585 | ax->old_pcap.inheritable = current->cred->cap_inheritable; | 2584 | ax->old_pcap.inheritable = old->cap_inheritable; |
2586 | ax->old_pcap.effective = *pE; | 2585 | ax->old_pcap.effective = old->cap_effective; |
2587 | 2586 | ||
2588 | ax->new_pcap.permitted = current->cred->cap_permitted; | 2587 | ax->new_pcap.permitted = new->cap_permitted; |
2589 | ax->new_pcap.inheritable = current->cred->cap_inheritable; | 2588 | ax->new_pcap.inheritable = new->cap_inheritable; |
2590 | ax->new_pcap.effective = current->cred->cap_effective; | 2589 | ax->new_pcap.effective = new->cap_effective; |
2590 | return 0; | ||
2591 | } | 2591 | } |
2592 | 2592 | ||
2593 | /** | 2593 | /** |
2594 | * __audit_log_capset - store information about the arguments to the capset syscall | 2594 | * __audit_log_capset - store information about the arguments to the capset syscall |
2595 | * @pid target pid of the capset call | 2595 | * @pid: target pid of the capset call |
2596 | * @eff effective cap set | 2596 | * @new: the new credentials |
2597 | * @inh inheritible cap set | 2597 | * @old: the old (current) credentials |
2598 | * @perm permited cap set | ||
2599 | * | 2598 | * |
2600 | * Record the aguments userspace sent to sys_capset for later printing by the | 2599 | * Record the aguments userspace sent to sys_capset for later printing by the |
2601 | * audit system if applicable | 2600 | * audit system if applicable |
2602 | */ | 2601 | */ |
2603 | int __audit_log_capset(pid_t pid, kernel_cap_t *eff, kernel_cap_t *inh, kernel_cap_t *perm) | 2602 | int __audit_log_capset(pid_t pid, |
2603 | const struct cred *new, const struct cred *old) | ||
2604 | { | 2604 | { |
2605 | struct audit_aux_data_capset *ax; | 2605 | struct audit_aux_data_capset *ax; |
2606 | struct audit_context *context = current->audit_context; | 2606 | struct audit_context *context = current->audit_context; |
@@ -2617,9 +2617,9 @@ int __audit_log_capset(pid_t pid, kernel_cap_t *eff, kernel_cap_t *inh, kernel_c | |||
2617 | context->aux = (void *)ax; | 2617 | context->aux = (void *)ax; |
2618 | 2618 | ||
2619 | ax->pid = pid; | 2619 | ax->pid = pid; |
2620 | ax->cap.effective = *eff; | 2620 | ax->cap.effective = new->cap_effective; |
2621 | ax->cap.inheritable = *eff; | 2621 | ax->cap.inheritable = new->cap_effective; |
2622 | ax->cap.permitted = *perm; | 2622 | ax->cap.permitted = new->cap_permitted; |
2623 | 2623 | ||
2624 | return 0; | 2624 | return 0; |
2625 | } | 2625 | } |
diff --git a/kernel/capability.c b/kernel/capability.c index a404b980b1bd..36b4b4daebec 100644 --- a/kernel/capability.c +++ b/kernel/capability.c | |||
@@ -15,12 +15,7 @@ | |||
15 | #include <linux/syscalls.h> | 15 | #include <linux/syscalls.h> |
16 | #include <linux/pid_namespace.h> | 16 | #include <linux/pid_namespace.h> |
17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
18 | 18 | #include "cred-internals.h" | |
19 | /* | ||
20 | * This lock protects task->cap_* for all tasks including current. | ||
21 | * Locking rule: acquire this prior to tasklist_lock. | ||
22 | */ | ||
23 | static DEFINE_SPINLOCK(task_capability_lock); | ||
24 | 19 | ||
25 | /* | 20 | /* |
26 | * Leveraged for setting/resetting capabilities | 21 | * Leveraged for setting/resetting capabilities |
@@ -128,12 +123,11 @@ static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy) | |||
128 | } | 123 | } |
129 | 124 | ||
130 | /* | 125 | /* |
131 | * If we have configured with filesystem capability support, then the | 126 | * The only thing that can change the capabilities of the current |
132 | * only thing that can change the capabilities of the current process | 127 | * process is the current process. As such, we can't be in this code |
133 | * is the current process. As such, we can't be in this code at the | 128 | * at the same time as we are in the process of setting capabilities |
134 | * same time as we are in the process of setting capabilities in this | 129 | * in this process. The net result is that we can limit our use of |
135 | * process. The net result is that we can limit our use of locks to | 130 | * locks to when we are reading the caps of another process. |
136 | * when we are reading the caps of another process. | ||
137 | */ | 131 | */ |
138 | static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, | 132 | static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, |
139 | kernel_cap_t *pIp, kernel_cap_t *pPp) | 133 | kernel_cap_t *pIp, kernel_cap_t *pPp) |
@@ -143,7 +137,6 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, | |||
143 | if (pid && (pid != task_pid_vnr(current))) { | 137 | if (pid && (pid != task_pid_vnr(current))) { |
144 | struct task_struct *target; | 138 | struct task_struct *target; |
145 | 139 | ||
146 | spin_lock(&task_capability_lock); | ||
147 | read_lock(&tasklist_lock); | 140 | read_lock(&tasklist_lock); |
148 | 141 | ||
149 | target = find_task_by_vpid(pid); | 142 | target = find_task_by_vpid(pid); |
@@ -153,34 +146,12 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, | |||
153 | ret = security_capget(target, pEp, pIp, pPp); | 146 | ret = security_capget(target, pEp, pIp, pPp); |
154 | 147 | ||
155 | read_unlock(&tasklist_lock); | 148 | read_unlock(&tasklist_lock); |
156 | spin_unlock(&task_capability_lock); | ||
157 | } else | 149 | } else |
158 | ret = security_capget(current, pEp, pIp, pPp); | 150 | ret = security_capget(current, pEp, pIp, pPp); |
159 | 151 | ||
160 | return ret; | 152 | return ret; |
161 | } | 153 | } |
162 | 154 | ||
163 | /* | ||
164 | * Atomically modify the effective capabilities returning the original | ||
165 | * value. No permission check is performed here - it is assumed that the | ||
166 | * caller is permitted to set the desired effective capabilities. | ||
167 | */ | ||
168 | kernel_cap_t cap_set_effective(const kernel_cap_t pE_new) | ||
169 | { | ||
170 | kernel_cap_t pE_old; | ||
171 | |||
172 | spin_lock(&task_capability_lock); | ||
173 | |||
174 | pE_old = current->cred->cap_effective; | ||
175 | current->cred->cap_effective = pE_new; | ||
176 | |||
177 | spin_unlock(&task_capability_lock); | ||
178 | |||
179 | return pE_old; | ||
180 | } | ||
181 | |||
182 | EXPORT_SYMBOL(cap_set_effective); | ||
183 | |||
184 | /** | 155 | /** |
185 | * sys_capget - get the capabilities of a given process. | 156 | * sys_capget - get the capabilities of a given process. |
186 | * @header: pointer to struct that contains capability version and | 157 | * @header: pointer to struct that contains capability version and |
@@ -208,7 +179,6 @@ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr) | |||
208 | return -EINVAL; | 179 | return -EINVAL; |
209 | 180 | ||
210 | ret = cap_get_target_pid(pid, &pE, &pI, &pP); | 181 | ret = cap_get_target_pid(pid, &pE, &pI, &pP); |
211 | |||
212 | if (!ret) { | 182 | if (!ret) { |
213 | struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S]; | 183 | struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S]; |
214 | unsigned i; | 184 | unsigned i; |
@@ -270,6 +240,7 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) | |||
270 | struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S]; | 240 | struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S]; |
271 | unsigned i, tocopy; | 241 | unsigned i, tocopy; |
272 | kernel_cap_t inheritable, permitted, effective; | 242 | kernel_cap_t inheritable, permitted, effective; |
243 | struct cred *new; | ||
273 | int ret; | 244 | int ret; |
274 | pid_t pid; | 245 | pid_t pid; |
275 | 246 | ||
@@ -284,8 +255,8 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) | |||
284 | if (pid != 0 && pid != task_pid_vnr(current)) | 255 | if (pid != 0 && pid != task_pid_vnr(current)) |
285 | return -EPERM; | 256 | return -EPERM; |
286 | 257 | ||
287 | if (copy_from_user(&kdata, data, tocopy | 258 | if (copy_from_user(&kdata, data, |
288 | * sizeof(struct __user_cap_data_struct))) | 259 | tocopy * sizeof(struct __user_cap_data_struct))) |
289 | return -EFAULT; | 260 | return -EFAULT; |
290 | 261 | ||
291 | for (i = 0; i < tocopy; i++) { | 262 | for (i = 0; i < tocopy; i++) { |
@@ -300,24 +271,23 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) | |||
300 | i++; | 271 | i++; |
301 | } | 272 | } |
302 | 273 | ||
303 | ret = audit_log_capset(pid, &effective, &inheritable, &permitted); | 274 | new = prepare_creds(); |
304 | if (ret) | 275 | if (!new) |
276 | return -ENOMEM; | ||
277 | |||
278 | ret = security_capset(new, current_cred(), | ||
279 | &effective, &inheritable, &permitted); | ||
280 | if (ret < 0) | ||
281 | goto error; | ||
282 | |||
283 | ret = audit_log_capset(pid, new, current_cred()); | ||
284 | if (ret < 0) | ||
305 | return ret; | 285 | return ret; |
306 | 286 | ||
307 | /* This lock is required even when filesystem capability support is | 287 | return commit_creds(new); |
308 | * configured - it protects the sys_capget() call from returning | 288 | |
309 | * incorrect data in the case that the targeted process is not the | 289 | error: |
310 | * current one. | 290 | abort_creds(new); |
311 | */ | ||
312 | spin_lock(&task_capability_lock); | ||
313 | |||
314 | ret = security_capset_check(&effective, &inheritable, &permitted); | ||
315 | /* Having verified that the proposed changes are legal, we now put them | ||
316 | * into effect. | ||
317 | */ | ||
318 | if (!ret) | ||
319 | security_capset_set(&effective, &inheritable, &permitted); | ||
320 | spin_unlock(&task_capability_lock); | ||
321 | return ret; | 291 | return ret; |
322 | } | 292 | } |
323 | 293 | ||
diff --git a/kernel/cred-internals.h b/kernel/cred-internals.h new file mode 100644 index 000000000000..2dc4fc2d0bf1 --- /dev/null +++ b/kernel/cred-internals.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* Internal credentials stuff | ||
2 | * | ||
3 | * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * user.c | ||
14 | */ | ||
15 | static inline void sched_switch_user(struct task_struct *p) | ||
16 | { | ||
17 | #ifdef CONFIG_USER_SCHED | ||
18 | sched_move_task(p); | ||
19 | #endif /* CONFIG_USER_SCHED */ | ||
20 | } | ||
21 | |||
diff --git a/kernel/cred.c b/kernel/cred.c index ac73e3617684..cb6b5eda978d 100644 --- a/kernel/cred.c +++ b/kernel/cred.c | |||
@@ -15,6 +15,10 @@ | |||
15 | #include <linux/keyctl.h> | 15 | #include <linux/keyctl.h> |
16 | #include <linux/init_task.h> | 16 | #include <linux/init_task.h> |
17 | #include <linux/security.h> | 17 | #include <linux/security.h> |
18 | #include <linux/cn_proc.h> | ||
19 | #include "cred-internals.h" | ||
20 | |||
21 | static struct kmem_cache *cred_jar; | ||
18 | 22 | ||
19 | /* | 23 | /* |
20 | * The common credentials for the initial task's thread group | 24 | * The common credentials for the initial task's thread group |
@@ -64,7 +68,7 @@ static void release_tgcred_rcu(struct rcu_head *rcu) | |||
64 | /* | 68 | /* |
65 | * Release a set of thread group credentials. | 69 | * Release a set of thread group credentials. |
66 | */ | 70 | */ |
67 | static void release_tgcred(struct cred *cred) | 71 | void release_tgcred(struct cred *cred) |
68 | { | 72 | { |
69 | #ifdef CONFIG_KEYS | 73 | #ifdef CONFIG_KEYS |
70 | struct thread_group_cred *tgcred = cred->tgcred; | 74 | struct thread_group_cred *tgcred = cred->tgcred; |
@@ -81,79 +85,322 @@ static void put_cred_rcu(struct rcu_head *rcu) | |||
81 | { | 85 | { |
82 | struct cred *cred = container_of(rcu, struct cred, rcu); | 86 | struct cred *cred = container_of(rcu, struct cred, rcu); |
83 | 87 | ||
84 | BUG_ON(atomic_read(&cred->usage) != 0); | 88 | if (atomic_read(&cred->usage) != 0) |
89 | panic("CRED: put_cred_rcu() sees %p with usage %d\n", | ||
90 | cred, atomic_read(&cred->usage)); | ||
85 | 91 | ||
92 | security_cred_free(cred); | ||
86 | key_put(cred->thread_keyring); | 93 | key_put(cred->thread_keyring); |
87 | key_put(cred->request_key_auth); | 94 | key_put(cred->request_key_auth); |
88 | release_tgcred(cred); | 95 | release_tgcred(cred); |
89 | put_group_info(cred->group_info); | 96 | put_group_info(cred->group_info); |
90 | free_uid(cred->user); | 97 | free_uid(cred->user); |
91 | security_cred_free(cred); | 98 | kmem_cache_free(cred_jar, cred); |
92 | kfree(cred); | ||
93 | } | 99 | } |
94 | 100 | ||
95 | /** | 101 | /** |
96 | * __put_cred - Destroy a set of credentials | 102 | * __put_cred - Destroy a set of credentials |
97 | * @sec: The record to release | 103 | * @cred: The record to release |
98 | * | 104 | * |
99 | * Destroy a set of credentials on which no references remain. | 105 | * Destroy a set of credentials on which no references remain. |
100 | */ | 106 | */ |
101 | void __put_cred(struct cred *cred) | 107 | void __put_cred(struct cred *cred) |
102 | { | 108 | { |
109 | BUG_ON(atomic_read(&cred->usage) != 0); | ||
110 | |||
103 | call_rcu(&cred->rcu, put_cred_rcu); | 111 | call_rcu(&cred->rcu, put_cred_rcu); |
104 | } | 112 | } |
105 | EXPORT_SYMBOL(__put_cred); | 113 | EXPORT_SYMBOL(__put_cred); |
106 | 114 | ||
115 | /** | ||
116 | * prepare_creds - Prepare a new set of credentials for modification | ||
117 | * | ||
118 | * Prepare a new set of task credentials for modification. A task's creds | ||
119 | * shouldn't generally be modified directly, therefore this function is used to | ||
120 | * prepare a new copy, which the caller then modifies and then commits by | ||
121 | * calling commit_creds(). | ||
122 | * | ||
123 | * Returns a pointer to the new creds-to-be if successful, NULL otherwise. | ||
124 | * | ||
125 | * Call commit_creds() or abort_creds() to clean up. | ||
126 | */ | ||
127 | struct cred *prepare_creds(void) | ||
128 | { | ||
129 | struct task_struct *task = current; | ||
130 | const struct cred *old; | ||
131 | struct cred *new; | ||
132 | |||
133 | BUG_ON(atomic_read(&task->cred->usage) < 1); | ||
134 | |||
135 | new = kmem_cache_alloc(cred_jar, GFP_KERNEL); | ||
136 | if (!new) | ||
137 | return NULL; | ||
138 | |||
139 | old = task->cred; | ||
140 | memcpy(new, old, sizeof(struct cred)); | ||
141 | |||
142 | atomic_set(&new->usage, 1); | ||
143 | get_group_info(new->group_info); | ||
144 | get_uid(new->user); | ||
145 | |||
146 | #ifdef CONFIG_KEYS | ||
147 | key_get(new->thread_keyring); | ||
148 | key_get(new->request_key_auth); | ||
149 | atomic_inc(&new->tgcred->usage); | ||
150 | #endif | ||
151 | |||
152 | #ifdef CONFIG_SECURITY | ||
153 | new->security = NULL; | ||
154 | #endif | ||
155 | |||
156 | if (security_prepare_creds(new, old, GFP_KERNEL) < 0) | ||
157 | goto error; | ||
158 | return new; | ||
159 | |||
160 | error: | ||
161 | abort_creds(new); | ||
162 | return NULL; | ||
163 | } | ||
164 | EXPORT_SYMBOL(prepare_creds); | ||
165 | |||
166 | /* | ||
167 | * prepare new credentials for the usermode helper dispatcher | ||
168 | */ | ||
169 | struct cred *prepare_usermodehelper_creds(void) | ||
170 | { | ||
171 | #ifdef CONFIG_KEYS | ||
172 | struct thread_group_cred *tgcred = NULL; | ||
173 | #endif | ||
174 | struct cred *new; | ||
175 | |||
176 | #ifdef CONFIG_KEYS | ||
177 | tgcred = kzalloc(sizeof(*new->tgcred), GFP_ATOMIC); | ||
178 | if (!tgcred) | ||
179 | return NULL; | ||
180 | #endif | ||
181 | |||
182 | new = kmem_cache_alloc(cred_jar, GFP_ATOMIC); | ||
183 | if (!new) | ||
184 | return NULL; | ||
185 | |||
186 | memcpy(new, &init_cred, sizeof(struct cred)); | ||
187 | |||
188 | atomic_set(&new->usage, 1); | ||
189 | get_group_info(new->group_info); | ||
190 | get_uid(new->user); | ||
191 | |||
192 | #ifdef CONFIG_KEYS | ||
193 | new->thread_keyring = NULL; | ||
194 | new->request_key_auth = NULL; | ||
195 | new->jit_keyring = KEY_REQKEY_DEFL_DEFAULT; | ||
196 | |||
197 | atomic_set(&tgcred->usage, 1); | ||
198 | spin_lock_init(&tgcred->lock); | ||
199 | new->tgcred = tgcred; | ||
200 | #endif | ||
201 | |||
202 | #ifdef CONFIG_SECURITY | ||
203 | new->security = NULL; | ||
204 | #endif | ||
205 | if (security_prepare_creds(new, &init_cred, GFP_ATOMIC) < 0) | ||
206 | goto error; | ||
207 | |||
208 | BUG_ON(atomic_read(&new->usage) != 1); | ||
209 | return new; | ||
210 | |||
211 | error: | ||
212 | put_cred(new); | ||
213 | return NULL; | ||
214 | } | ||
215 | |||
107 | /* | 216 | /* |
108 | * Copy credentials for the new process created by fork() | 217 | * Copy credentials for the new process created by fork() |
218 | * | ||
219 | * We share if we can, but under some circumstances we have to generate a new | ||
220 | * set. | ||
109 | */ | 221 | */ |
110 | int copy_creds(struct task_struct *p, unsigned long clone_flags) | 222 | int copy_creds(struct task_struct *p, unsigned long clone_flags) |
111 | { | 223 | { |
112 | struct cred *pcred; | 224 | #ifdef CONFIG_KEYS |
113 | int ret; | 225 | struct thread_group_cred *tgcred; |
226 | #endif | ||
227 | struct cred *new; | ||
228 | |||
229 | mutex_init(&p->cred_exec_mutex); | ||
114 | 230 | ||
115 | pcred = kmemdup(p->cred, sizeof(*p->cred), GFP_KERNEL); | 231 | if ( |
116 | if (!pcred) | 232 | #ifdef CONFIG_KEYS |
233 | !p->cred->thread_keyring && | ||
234 | #endif | ||
235 | clone_flags & CLONE_THREAD | ||
236 | ) { | ||
237 | get_cred(p->cred); | ||
238 | atomic_inc(&p->cred->user->processes); | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | new = prepare_creds(); | ||
243 | if (!new) | ||
117 | return -ENOMEM; | 244 | return -ENOMEM; |
118 | 245 | ||
119 | #ifdef CONFIG_KEYS | 246 | #ifdef CONFIG_KEYS |
120 | if (clone_flags & CLONE_THREAD) { | 247 | /* new threads get their own thread keyrings if their parent already |
121 | atomic_inc(&pcred->tgcred->usage); | 248 | * had one */ |
122 | } else { | 249 | if (new->thread_keyring) { |
123 | pcred->tgcred = kmalloc(sizeof(struct cred), GFP_KERNEL); | 250 | key_put(new->thread_keyring); |
124 | if (!pcred->tgcred) { | 251 | new->thread_keyring = NULL; |
125 | kfree(pcred); | 252 | if (clone_flags & CLONE_THREAD) |
253 | install_thread_keyring_to_cred(new); | ||
254 | } | ||
255 | |||
256 | /* we share the process and session keyrings between all the threads in | ||
257 | * a process - this is slightly icky as we violate COW credentials a | ||
258 | * bit */ | ||
259 | if (!(clone_flags & CLONE_THREAD)) { | ||
260 | tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL); | ||
261 | if (!tgcred) { | ||
262 | put_cred(new); | ||
126 | return -ENOMEM; | 263 | return -ENOMEM; |
127 | } | 264 | } |
128 | atomic_set(&pcred->tgcred->usage, 1); | 265 | atomic_set(&tgcred->usage, 1); |
129 | spin_lock_init(&pcred->tgcred->lock); | 266 | spin_lock_init(&tgcred->lock); |
130 | pcred->tgcred->process_keyring = NULL; | 267 | tgcred->process_keyring = NULL; |
131 | pcred->tgcred->session_keyring = | 268 | tgcred->session_keyring = key_get(new->tgcred->session_keyring); |
132 | key_get(p->cred->tgcred->session_keyring); | 269 | |
270 | release_tgcred(new); | ||
271 | new->tgcred = tgcred; | ||
133 | } | 272 | } |
134 | #endif | 273 | #endif |
135 | 274 | ||
136 | #ifdef CONFIG_SECURITY | 275 | atomic_inc(&new->user->processes); |
137 | pcred->security = NULL; | 276 | p->cred = new; |
138 | #endif | 277 | return 0; |
278 | } | ||
139 | 279 | ||
140 | ret = security_cred_alloc(pcred); | 280 | /** |
141 | if (ret < 0) { | 281 | * commit_creds - Install new credentials upon the current task |
142 | release_tgcred(pcred); | 282 | * @new: The credentials to be assigned |
143 | kfree(pcred); | 283 | * |
144 | return ret; | 284 | * Install a new set of credentials to the current task, using RCU to replace |
285 | * the old set. | ||
286 | * | ||
287 | * This function eats the caller's reference to the new credentials. | ||
288 | * | ||
289 | * Always returns 0 thus allowing this function to be tail-called at the end | ||
290 | * of, say, sys_setgid(). | ||
291 | */ | ||
292 | int commit_creds(struct cred *new) | ||
293 | { | ||
294 | struct task_struct *task = current; | ||
295 | const struct cred *old; | ||
296 | |||
297 | BUG_ON(atomic_read(&new->usage) < 1); | ||
298 | BUG_ON(atomic_read(&task->cred->usage) < 1); | ||
299 | |||
300 | old = task->cred; | ||
301 | security_commit_creds(new, old); | ||
302 | |||
303 | /* dumpability changes */ | ||
304 | if (old->euid != new->euid || | ||
305 | old->egid != new->egid || | ||
306 | old->fsuid != new->fsuid || | ||
307 | old->fsgid != new->fsgid || | ||
308 | !cap_issubset(new->cap_permitted, old->cap_permitted)) { | ||
309 | set_dumpable(task->mm, suid_dumpable); | ||
310 | task->pdeath_signal = 0; | ||
311 | smp_wmb(); | ||
145 | } | 312 | } |
146 | 313 | ||
147 | atomic_set(&pcred->usage, 1); | 314 | /* alter the thread keyring */ |
148 | get_group_info(pcred->group_info); | 315 | if (new->fsuid != old->fsuid) |
149 | get_uid(pcred->user); | 316 | key_fsuid_changed(task); |
150 | key_get(pcred->thread_keyring); | 317 | if (new->fsgid != old->fsgid) |
151 | key_get(pcred->request_key_auth); | 318 | key_fsgid_changed(task); |
319 | |||
320 | /* do it | ||
321 | * - What if a process setreuid()'s and this brings the | ||
322 | * new uid over his NPROC rlimit? We can check this now | ||
323 | * cheaply with the new uid cache, so if it matters | ||
324 | * we should be checking for it. -DaveM | ||
325 | */ | ||
326 | if (new->user != old->user) | ||
327 | atomic_inc(&new->user->processes); | ||
328 | rcu_assign_pointer(task->cred, new); | ||
329 | if (new->user != old->user) | ||
330 | atomic_dec(&old->user->processes); | ||
331 | |||
332 | sched_switch_user(task); | ||
333 | |||
334 | /* send notifications */ | ||
335 | if (new->uid != old->uid || | ||
336 | new->euid != old->euid || | ||
337 | new->suid != old->suid || | ||
338 | new->fsuid != old->fsuid) | ||
339 | proc_id_connector(task, PROC_EVENT_UID); | ||
152 | 340 | ||
153 | atomic_inc(&pcred->user->processes); | 341 | if (new->gid != old->gid || |
342 | new->egid != old->egid || | ||
343 | new->sgid != old->sgid || | ||
344 | new->fsgid != old->fsgid) | ||
345 | proc_id_connector(task, PROC_EVENT_GID); | ||
154 | 346 | ||
155 | /* RCU assignment is unneeded here as no-one can have accessed this | 347 | put_cred(old); |
156 | * pointer yet, barring us */ | ||
157 | p->cred = pcred; | ||
158 | return 0; | 348 | return 0; |
159 | } | 349 | } |
350 | EXPORT_SYMBOL(commit_creds); | ||
351 | |||
352 | /** | ||
353 | * abort_creds - Discard a set of credentials and unlock the current task | ||
354 | * @new: The credentials that were going to be applied | ||
355 | * | ||
356 | * Discard a set of credentials that were under construction and unlock the | ||
357 | * current task. | ||
358 | */ | ||
359 | void abort_creds(struct cred *new) | ||
360 | { | ||
361 | BUG_ON(atomic_read(&new->usage) < 1); | ||
362 | put_cred(new); | ||
363 | } | ||
364 | EXPORT_SYMBOL(abort_creds); | ||
365 | |||
366 | /** | ||
367 | * override_creds - Temporarily override the current process's credentials | ||
368 | * @new: The credentials to be assigned | ||
369 | * | ||
370 | * Install a set of temporary override credentials on the current process, | ||
371 | * returning the old set for later reversion. | ||
372 | */ | ||
373 | const struct cred *override_creds(const struct cred *new) | ||
374 | { | ||
375 | const struct cred *old = current->cred; | ||
376 | |||
377 | rcu_assign_pointer(current->cred, get_cred(new)); | ||
378 | return old; | ||
379 | } | ||
380 | EXPORT_SYMBOL(override_creds); | ||
381 | |||
382 | /** | ||
383 | * revert_creds - Revert a temporary credentials override | ||
384 | * @old: The credentials to be restored | ||
385 | * | ||
386 | * Revert a temporary set of override credentials to an old set, discarding the | ||
387 | * override set. | ||
388 | */ | ||
389 | void revert_creds(const struct cred *old) | ||
390 | { | ||
391 | const struct cred *override = current->cred; | ||
392 | |||
393 | rcu_assign_pointer(current->cred, old); | ||
394 | put_cred(override); | ||
395 | } | ||
396 | EXPORT_SYMBOL(revert_creds); | ||
397 | |||
398 | /* | ||
399 | * initialise the credentials stuff | ||
400 | */ | ||
401 | void __init cred_init(void) | ||
402 | { | ||
403 | /* allocate a slab in which we can store credentials */ | ||
404 | cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred), | ||
405 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); | ||
406 | } | ||
diff --git a/kernel/exit.c b/kernel/exit.c index bbc22530f2c1..c0711da15486 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -47,12 +47,14 @@ | |||
47 | #include <linux/blkdev.h> | 47 | #include <linux/blkdev.h> |
48 | #include <linux/task_io_accounting_ops.h> | 48 | #include <linux/task_io_accounting_ops.h> |
49 | #include <linux/tracehook.h> | 49 | #include <linux/tracehook.h> |
50 | #include <linux/init_task.h> | ||
50 | #include <trace/sched.h> | 51 | #include <trace/sched.h> |
51 | 52 | ||
52 | #include <asm/uaccess.h> | 53 | #include <asm/uaccess.h> |
53 | #include <asm/unistd.h> | 54 | #include <asm/unistd.h> |
54 | #include <asm/pgtable.h> | 55 | #include <asm/pgtable.h> |
55 | #include <asm/mmu_context.h> | 56 | #include <asm/mmu_context.h> |
57 | #include "cred-internals.h" | ||
56 | 58 | ||
57 | static void exit_mm(struct task_struct * tsk); | 59 | static void exit_mm(struct task_struct * tsk); |
58 | 60 | ||
@@ -338,12 +340,12 @@ static void reparent_to_kthreadd(void) | |||
338 | /* cpus_allowed? */ | 340 | /* cpus_allowed? */ |
339 | /* rt_priority? */ | 341 | /* rt_priority? */ |
340 | /* signals? */ | 342 | /* signals? */ |
341 | security_task_reparent_to_init(current); | ||
342 | memcpy(current->signal->rlim, init_task.signal->rlim, | 343 | memcpy(current->signal->rlim, init_task.signal->rlim, |
343 | sizeof(current->signal->rlim)); | 344 | sizeof(current->signal->rlim)); |
344 | atomic_inc(&(INIT_USER->__count)); | 345 | |
346 | atomic_inc(&init_cred.usage); | ||
347 | commit_creds(&init_cred); | ||
345 | write_unlock_irq(&tasklist_lock); | 348 | write_unlock_irq(&tasklist_lock); |
346 | switch_uid(INIT_USER); | ||
347 | } | 349 | } |
348 | 350 | ||
349 | void __set_special_pids(struct pid *pid) | 351 | void __set_special_pids(struct pid *pid) |
@@ -1085,7 +1087,6 @@ NORET_TYPE void do_exit(long code) | |||
1085 | check_stack_usage(); | 1087 | check_stack_usage(); |
1086 | exit_thread(); | 1088 | exit_thread(); |
1087 | cgroup_exit(tsk, 1); | 1089 | cgroup_exit(tsk, 1); |
1088 | exit_keys(tsk); | ||
1089 | 1090 | ||
1090 | if (group_dead && tsk->signal->leader) | 1091 | if (group_dead && tsk->signal->leader) |
1091 | disassociate_ctty(1); | 1092 | disassociate_ctty(1); |
diff --git a/kernel/fork.c b/kernel/fork.c index ded1972672a3..82a7948a664e 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1084,10 +1084,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1084 | goto bad_fork_cleanup_sighand; | 1084 | goto bad_fork_cleanup_sighand; |
1085 | if ((retval = copy_mm(clone_flags, p))) | 1085 | if ((retval = copy_mm(clone_flags, p))) |
1086 | goto bad_fork_cleanup_signal; | 1086 | goto bad_fork_cleanup_signal; |
1087 | if ((retval = copy_keys(clone_flags, p))) | ||
1088 | goto bad_fork_cleanup_mm; | ||
1089 | if ((retval = copy_namespaces(clone_flags, p))) | 1087 | if ((retval = copy_namespaces(clone_flags, p))) |
1090 | goto bad_fork_cleanup_keys; | 1088 | goto bad_fork_cleanup_mm; |
1091 | if ((retval = copy_io(clone_flags, p))) | 1089 | if ((retval = copy_io(clone_flags, p))) |
1092 | goto bad_fork_cleanup_namespaces; | 1090 | goto bad_fork_cleanup_namespaces; |
1093 | retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); | 1091 | retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); |
@@ -1252,8 +1250,6 @@ bad_fork_cleanup_io: | |||
1252 | put_io_context(p->io_context); | 1250 | put_io_context(p->io_context); |
1253 | bad_fork_cleanup_namespaces: | 1251 | bad_fork_cleanup_namespaces: |
1254 | exit_task_namespaces(p); | 1252 | exit_task_namespaces(p); |
1255 | bad_fork_cleanup_keys: | ||
1256 | exit_keys(p); | ||
1257 | bad_fork_cleanup_mm: | 1253 | bad_fork_cleanup_mm: |
1258 | if (p->mm) | 1254 | if (p->mm) |
1259 | mmput(p->mm); | 1255 | mmput(p->mm); |
@@ -1281,6 +1277,7 @@ bad_fork_cleanup_cgroup: | |||
1281 | bad_fork_cleanup_put_domain: | 1277 | bad_fork_cleanup_put_domain: |
1282 | module_put(task_thread_info(p)->exec_domain->module); | 1278 | module_put(task_thread_info(p)->exec_domain->module); |
1283 | bad_fork_cleanup_count: | 1279 | bad_fork_cleanup_count: |
1280 | atomic_dec(&p->cred->user->processes); | ||
1284 | put_cred(p->cred); | 1281 | put_cred(p->cred); |
1285 | bad_fork_free: | 1282 | bad_fork_free: |
1286 | free_task(p); | 1283 | free_task(p); |
diff --git a/kernel/kmod.c b/kernel/kmod.c index f044f8f57703..b46dbb908669 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
@@ -118,10 +118,10 @@ EXPORT_SYMBOL(request_module); | |||
118 | struct subprocess_info { | 118 | struct subprocess_info { |
119 | struct work_struct work; | 119 | struct work_struct work; |
120 | struct completion *complete; | 120 | struct completion *complete; |
121 | struct cred *cred; | ||
121 | char *path; | 122 | char *path; |
122 | char **argv; | 123 | char **argv; |
123 | char **envp; | 124 | char **envp; |
124 | struct key *ring; | ||
125 | enum umh_wait wait; | 125 | enum umh_wait wait; |
126 | int retval; | 126 | int retval; |
127 | struct file *stdin; | 127 | struct file *stdin; |
@@ -134,19 +134,20 @@ struct subprocess_info { | |||
134 | static int ____call_usermodehelper(void *data) | 134 | static int ____call_usermodehelper(void *data) |
135 | { | 135 | { |
136 | struct subprocess_info *sub_info = data; | 136 | struct subprocess_info *sub_info = data; |
137 | struct key *new_session, *old_session; | ||
138 | int retval; | 137 | int retval; |
139 | 138 | ||
140 | /* Unblock all signals and set the session keyring. */ | 139 | BUG_ON(atomic_read(&sub_info->cred->usage) != 1); |
141 | new_session = key_get(sub_info->ring); | 140 | |
141 | /* Unblock all signals */ | ||
142 | spin_lock_irq(¤t->sighand->siglock); | 142 | spin_lock_irq(¤t->sighand->siglock); |
143 | old_session = __install_session_keyring(new_session); | ||
144 | flush_signal_handlers(current, 1); | 143 | flush_signal_handlers(current, 1); |
145 | sigemptyset(¤t->blocked); | 144 | sigemptyset(¤t->blocked); |
146 | recalc_sigpending(); | 145 | recalc_sigpending(); |
147 | spin_unlock_irq(¤t->sighand->siglock); | 146 | spin_unlock_irq(¤t->sighand->siglock); |
148 | 147 | ||
149 | key_put(old_session); | 148 | /* Install the credentials */ |
149 | commit_creds(sub_info->cred); | ||
150 | sub_info->cred = NULL; | ||
150 | 151 | ||
151 | /* Install input pipe when needed */ | 152 | /* Install input pipe when needed */ |
152 | if (sub_info->stdin) { | 153 | if (sub_info->stdin) { |
@@ -185,6 +186,8 @@ void call_usermodehelper_freeinfo(struct subprocess_info *info) | |||
185 | { | 186 | { |
186 | if (info->cleanup) | 187 | if (info->cleanup) |
187 | (*info->cleanup)(info->argv, info->envp); | 188 | (*info->cleanup)(info->argv, info->envp); |
189 | if (info->cred) | ||
190 | put_cred(info->cred); | ||
188 | kfree(info); | 191 | kfree(info); |
189 | } | 192 | } |
190 | EXPORT_SYMBOL(call_usermodehelper_freeinfo); | 193 | EXPORT_SYMBOL(call_usermodehelper_freeinfo); |
@@ -240,6 +243,8 @@ static void __call_usermodehelper(struct work_struct *work) | |||
240 | pid_t pid; | 243 | pid_t pid; |
241 | enum umh_wait wait = sub_info->wait; | 244 | enum umh_wait wait = sub_info->wait; |
242 | 245 | ||
246 | BUG_ON(atomic_read(&sub_info->cred->usage) != 1); | ||
247 | |||
243 | /* CLONE_VFORK: wait until the usermode helper has execve'd | 248 | /* CLONE_VFORK: wait until the usermode helper has execve'd |
244 | * successfully We need the data structures to stay around | 249 | * successfully We need the data structures to stay around |
245 | * until that is done. */ | 250 | * until that is done. */ |
@@ -362,6 +367,9 @@ struct subprocess_info *call_usermodehelper_setup(char *path, char **argv, | |||
362 | sub_info->path = path; | 367 | sub_info->path = path; |
363 | sub_info->argv = argv; | 368 | sub_info->argv = argv; |
364 | sub_info->envp = envp; | 369 | sub_info->envp = envp; |
370 | sub_info->cred = prepare_usermodehelper_creds(); | ||
371 | if (!sub_info->cred) | ||
372 | return NULL; | ||
365 | 373 | ||
366 | out: | 374 | out: |
367 | return sub_info; | 375 | return sub_info; |
@@ -376,7 +384,13 @@ EXPORT_SYMBOL(call_usermodehelper_setup); | |||
376 | void call_usermodehelper_setkeys(struct subprocess_info *info, | 384 | void call_usermodehelper_setkeys(struct subprocess_info *info, |
377 | struct key *session_keyring) | 385 | struct key *session_keyring) |
378 | { | 386 | { |
379 | info->ring = session_keyring; | 387 | #ifdef CONFIG_KEYS |
388 | struct thread_group_cred *tgcred = info->cred->tgcred; | ||
389 | key_put(tgcred->session_keyring); | ||
390 | tgcred->session_keyring = key_get(session_keyring); | ||
391 | #else | ||
392 | BUG(); | ||
393 | #endif | ||
380 | } | 394 | } |
381 | EXPORT_SYMBOL(call_usermodehelper_setkeys); | 395 | EXPORT_SYMBOL(call_usermodehelper_setkeys); |
382 | 396 | ||
@@ -444,6 +458,8 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, | |||
444 | DECLARE_COMPLETION_ONSTACK(done); | 458 | DECLARE_COMPLETION_ONSTACK(done); |
445 | int retval = 0; | 459 | int retval = 0; |
446 | 460 | ||
461 | BUG_ON(atomic_read(&sub_info->cred->usage) != 1); | ||
462 | |||
447 | helper_lock(); | 463 | helper_lock(); |
448 | if (sub_info->path[0] == '\0') | 464 | if (sub_info->path[0] == '\0') |
449 | goto out; | 465 | goto out; |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index b9d5f4e4f6a4..f764b8806955 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -171,6 +171,14 @@ int ptrace_attach(struct task_struct *task) | |||
171 | if (same_thread_group(task, current)) | 171 | if (same_thread_group(task, current)) |
172 | goto out; | 172 | goto out; |
173 | 173 | ||
174 | /* Protect exec's credential calculations against our interference; | ||
175 | * SUID, SGID and LSM creds get determined differently under ptrace. | ||
176 | */ | ||
177 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); | ||
178 | if (retval < 0) | ||
179 | goto out; | ||
180 | |||
181 | retval = -EPERM; | ||
174 | repeat: | 182 | repeat: |
175 | /* | 183 | /* |
176 | * Nasty, nasty. | 184 | * Nasty, nasty. |
@@ -210,6 +218,7 @@ repeat: | |||
210 | bad: | 218 | bad: |
211 | write_unlock_irqrestore(&tasklist_lock, flags); | 219 | write_unlock_irqrestore(&tasklist_lock, flags); |
212 | task_unlock(task); | 220 | task_unlock(task); |
221 | mutex_unlock(¤t->cred_exec_mutex); | ||
213 | out: | 222 | out: |
214 | return retval; | 223 | return retval; |
215 | } | 224 | } |
diff --git a/kernel/signal.c b/kernel/signal.c index 84989124bafb..2a64304ed54b 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -180,7 +180,7 @@ int next_signal(struct sigpending *pending, sigset_t *mask) | |||
180 | /* | 180 | /* |
181 | * allocate a new signal queue record | 181 | * allocate a new signal queue record |
182 | * - this may be called without locks if and only if t == current, otherwise an | 182 | * - this may be called without locks if and only if t == current, otherwise an |
183 | * appopriate lock must be held to protect t's user_struct | 183 | * appopriate lock must be held to stop the target task from exiting |
184 | */ | 184 | */ |
185 | static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags, | 185 | static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags, |
186 | int override_rlimit) | 186 | int override_rlimit) |
@@ -194,7 +194,7 @@ static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags, | |||
194 | * caller must be holding the RCU readlock (by way of a spinlock) and | 194 | * caller must be holding the RCU readlock (by way of a spinlock) and |
195 | * we use RCU protection here | 195 | * we use RCU protection here |
196 | */ | 196 | */ |
197 | user = __task_cred(t)->user; | 197 | user = get_uid(__task_cred(t)->user); |
198 | atomic_inc(&user->sigpending); | 198 | atomic_inc(&user->sigpending); |
199 | if (override_rlimit || | 199 | if (override_rlimit || |
200 | atomic_read(&user->sigpending) <= | 200 | atomic_read(&user->sigpending) <= |
@@ -202,12 +202,14 @@ static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags, | |||
202 | q = kmem_cache_alloc(sigqueue_cachep, flags); | 202 | q = kmem_cache_alloc(sigqueue_cachep, flags); |
203 | if (unlikely(q == NULL)) { | 203 | if (unlikely(q == NULL)) { |
204 | atomic_dec(&user->sigpending); | 204 | atomic_dec(&user->sigpending); |
205 | free_uid(user); | ||
205 | } else { | 206 | } else { |
206 | INIT_LIST_HEAD(&q->list); | 207 | INIT_LIST_HEAD(&q->list); |
207 | q->flags = 0; | 208 | q->flags = 0; |
208 | q->user = get_uid(user); | 209 | q->user = user; |
209 | } | 210 | } |
210 | return(q); | 211 | |
212 | return q; | ||
211 | } | 213 | } |
212 | 214 | ||
213 | static void __sigqueue_free(struct sigqueue *q) | 215 | static void __sigqueue_free(struct sigqueue *q) |
diff --git a/kernel/sys.c b/kernel/sys.c index ccc9eb736d35..ab735040468a 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -180,7 +180,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval) | |||
180 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); | 180 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); |
181 | break; | 181 | break; |
182 | case PRIO_USER: | 182 | case PRIO_USER: |
183 | user = cred->user; | 183 | user = (struct user_struct *) cred->user; |
184 | if (!who) | 184 | if (!who) |
185 | who = cred->uid; | 185 | who = cred->uid; |
186 | else if ((who != cred->uid) && | 186 | else if ((who != cred->uid) && |
@@ -479,47 +479,48 @@ void ctrl_alt_del(void) | |||
479 | */ | 479 | */ |
480 | asmlinkage long sys_setregid(gid_t rgid, gid_t egid) | 480 | asmlinkage long sys_setregid(gid_t rgid, gid_t egid) |
481 | { | 481 | { |
482 | struct cred *cred = current->cred; | 482 | const struct cred *old; |
483 | int old_rgid = cred->gid; | 483 | struct cred *new; |
484 | int old_egid = cred->egid; | ||
485 | int new_rgid = old_rgid; | ||
486 | int new_egid = old_egid; | ||
487 | int retval; | 484 | int retval; |
488 | 485 | ||
486 | new = prepare_creds(); | ||
487 | if (!new) | ||
488 | return -ENOMEM; | ||
489 | old = current_cred(); | ||
490 | |||
489 | retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); | 491 | retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); |
490 | if (retval) | 492 | if (retval) |
491 | return retval; | 493 | goto error; |
492 | 494 | ||
495 | retval = -EPERM; | ||
493 | if (rgid != (gid_t) -1) { | 496 | if (rgid != (gid_t) -1) { |
494 | if ((old_rgid == rgid) || | 497 | if (old->gid == rgid || |
495 | (cred->egid == rgid) || | 498 | old->egid == rgid || |
496 | capable(CAP_SETGID)) | 499 | capable(CAP_SETGID)) |
497 | new_rgid = rgid; | 500 | new->gid = rgid; |
498 | else | 501 | else |
499 | return -EPERM; | 502 | goto error; |
500 | } | 503 | } |
501 | if (egid != (gid_t) -1) { | 504 | if (egid != (gid_t) -1) { |
502 | if ((old_rgid == egid) || | 505 | if (old->gid == egid || |
503 | (cred->egid == egid) || | 506 | old->egid == egid || |
504 | (cred->sgid == egid) || | 507 | old->sgid == egid || |
505 | capable(CAP_SETGID)) | 508 | capable(CAP_SETGID)) |
506 | new_egid = egid; | 509 | new->egid = egid; |
507 | else | 510 | else |
508 | return -EPERM; | 511 | goto error; |
509 | } | ||
510 | if (new_egid != old_egid) { | ||
511 | set_dumpable(current->mm, suid_dumpable); | ||
512 | smp_wmb(); | ||
513 | } | 512 | } |
513 | |||
514 | if (rgid != (gid_t) -1 || | 514 | if (rgid != (gid_t) -1 || |
515 | (egid != (gid_t) -1 && egid != old_rgid)) | 515 | (egid != (gid_t) -1 && egid != old->gid)) |
516 | cred->sgid = new_egid; | 516 | new->sgid = new->egid; |
517 | cred->fsgid = new_egid; | 517 | new->fsgid = new->egid; |
518 | cred->egid = new_egid; | 518 | |
519 | cred->gid = new_rgid; | 519 | return commit_creds(new); |
520 | key_fsgid_changed(current); | 520 | |
521 | proc_id_connector(current, PROC_EVENT_GID); | 521 | error: |
522 | return 0; | 522 | abort_creds(new); |
523 | return retval; | ||
523 | } | 524 | } |
524 | 525 | ||
525 | /* | 526 | /* |
@@ -529,40 +530,42 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid) | |||
529 | */ | 530 | */ |
530 | asmlinkage long sys_setgid(gid_t gid) | 531 | asmlinkage long sys_setgid(gid_t gid) |
531 | { | 532 | { |
532 | struct cred *cred = current->cred; | 533 | const struct cred *old; |
533 | int old_egid = cred->egid; | 534 | struct cred *new; |
534 | int retval; | 535 | int retval; |
535 | 536 | ||
537 | new = prepare_creds(); | ||
538 | if (!new) | ||
539 | return -ENOMEM; | ||
540 | old = current_cred(); | ||
541 | |||
536 | retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); | 542 | retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); |
537 | if (retval) | 543 | if (retval) |
538 | return retval; | 544 | goto error; |
539 | 545 | ||
540 | if (capable(CAP_SETGID)) { | 546 | retval = -EPERM; |
541 | if (old_egid != gid) { | 547 | if (capable(CAP_SETGID)) |
542 | set_dumpable(current->mm, suid_dumpable); | 548 | new->gid = new->egid = new->sgid = new->fsgid = gid; |
543 | smp_wmb(); | 549 | else if (gid == old->gid || gid == old->sgid) |
544 | } | 550 | new->egid = new->fsgid = gid; |
545 | cred->gid = cred->egid = cred->sgid = cred->fsgid = gid; | ||
546 | } else if ((gid == cred->gid) || (gid == cred->sgid)) { | ||
547 | if (old_egid != gid) { | ||
548 | set_dumpable(current->mm, suid_dumpable); | ||
549 | smp_wmb(); | ||
550 | } | ||
551 | cred->egid = cred->fsgid = gid; | ||
552 | } | ||
553 | else | 551 | else |
554 | return -EPERM; | 552 | goto error; |
555 | 553 | ||
556 | key_fsgid_changed(current); | 554 | return commit_creds(new); |
557 | proc_id_connector(current, PROC_EVENT_GID); | 555 | |
558 | return 0; | 556 | error: |
557 | abort_creds(new); | ||
558 | return retval; | ||
559 | } | 559 | } |
560 | 560 | ||
561 | static int set_user(uid_t new_ruid, int dumpclear) | 561 | /* |
562 | * change the user struct in a credentials set to match the new UID | ||
563 | */ | ||
564 | static int set_user(struct cred *new) | ||
562 | { | 565 | { |
563 | struct user_struct *new_user; | 566 | struct user_struct *new_user; |
564 | 567 | ||
565 | new_user = alloc_uid(current->nsproxy->user_ns, new_ruid); | 568 | new_user = alloc_uid(current->nsproxy->user_ns, new->uid); |
566 | if (!new_user) | 569 | if (!new_user) |
567 | return -EAGAIN; | 570 | return -EAGAIN; |
568 | 571 | ||
@@ -573,13 +576,8 @@ static int set_user(uid_t new_ruid, int dumpclear) | |||
573 | return -EAGAIN; | 576 | return -EAGAIN; |
574 | } | 577 | } |
575 | 578 | ||
576 | switch_uid(new_user); | 579 | free_uid(new->user); |
577 | 580 | new->user = new_user; | |
578 | if (dumpclear) { | ||
579 | set_dumpable(current->mm, suid_dumpable); | ||
580 | smp_wmb(); | ||
581 | } | ||
582 | current->cred->uid = new_ruid; | ||
583 | return 0; | 581 | return 0; |
584 | } | 582 | } |
585 | 583 | ||
@@ -600,55 +598,56 @@ static int set_user(uid_t new_ruid, int dumpclear) | |||
600 | */ | 598 | */ |
601 | asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) | 599 | asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) |
602 | { | 600 | { |
603 | struct cred *cred = current->cred; | 601 | const struct cred *old; |
604 | int old_ruid, old_euid, old_suid, new_ruid, new_euid; | 602 | struct cred *new; |
605 | int retval; | 603 | int retval; |
606 | 604 | ||
605 | new = prepare_creds(); | ||
606 | if (!new) | ||
607 | return -ENOMEM; | ||
608 | old = current_cred(); | ||
609 | |||
607 | retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); | 610 | retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); |
608 | if (retval) | 611 | if (retval) |
609 | return retval; | 612 | goto error; |
610 | |||
611 | new_ruid = old_ruid = cred->uid; | ||
612 | new_euid = old_euid = cred->euid; | ||
613 | old_suid = cred->suid; | ||
614 | 613 | ||
614 | retval = -EPERM; | ||
615 | if (ruid != (uid_t) -1) { | 615 | if (ruid != (uid_t) -1) { |
616 | new_ruid = ruid; | 616 | new->uid = ruid; |
617 | if ((old_ruid != ruid) && | 617 | if (old->uid != ruid && |
618 | (cred->euid != ruid) && | 618 | old->euid != ruid && |
619 | !capable(CAP_SETUID)) | 619 | !capable(CAP_SETUID)) |
620 | return -EPERM; | 620 | goto error; |
621 | } | 621 | } |
622 | 622 | ||
623 | if (euid != (uid_t) -1) { | 623 | if (euid != (uid_t) -1) { |
624 | new_euid = euid; | 624 | new->euid = euid; |
625 | if ((old_ruid != euid) && | 625 | if (old->uid != euid && |
626 | (cred->euid != euid) && | 626 | old->euid != euid && |
627 | (cred->suid != euid) && | 627 | old->suid != euid && |
628 | !capable(CAP_SETUID)) | 628 | !capable(CAP_SETUID)) |
629 | return -EPERM; | 629 | goto error; |
630 | } | 630 | } |
631 | 631 | ||
632 | if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0) | 632 | retval = -EAGAIN; |
633 | return -EAGAIN; | 633 | if (new->uid != old->uid && set_user(new) < 0) |
634 | goto error; | ||
634 | 635 | ||
635 | if (new_euid != old_euid) { | ||
636 | set_dumpable(current->mm, suid_dumpable); | ||
637 | smp_wmb(); | ||
638 | } | ||
639 | cred->fsuid = cred->euid = new_euid; | ||
640 | if (ruid != (uid_t) -1 || | 636 | if (ruid != (uid_t) -1 || |
641 | (euid != (uid_t) -1 && euid != old_ruid)) | 637 | (euid != (uid_t) -1 && euid != old->uid)) |
642 | cred->suid = cred->euid; | 638 | new->suid = new->euid; |
643 | cred->fsuid = cred->euid; | 639 | new->fsuid = new->euid; |
644 | |||
645 | key_fsuid_changed(current); | ||
646 | proc_id_connector(current, PROC_EVENT_UID); | ||
647 | 640 | ||
648 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE); | 641 | retval = security_task_fix_setuid(new, old, LSM_SETID_RE); |
649 | } | 642 | if (retval < 0) |
643 | goto error; | ||
650 | 644 | ||
645 | return commit_creds(new); | ||
651 | 646 | ||
647 | error: | ||
648 | abort_creds(new); | ||
649 | return retval; | ||
650 | } | ||
652 | 651 | ||
653 | /* | 652 | /* |
654 | * setuid() is implemented like SysV with SAVED_IDS | 653 | * setuid() is implemented like SysV with SAVED_IDS |
@@ -663,37 +662,41 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) | |||
663 | */ | 662 | */ |
664 | asmlinkage long sys_setuid(uid_t uid) | 663 | asmlinkage long sys_setuid(uid_t uid) |
665 | { | 664 | { |
666 | struct cred *cred = current->cred; | 665 | const struct cred *old; |
667 | int old_euid = cred->euid; | 666 | struct cred *new; |
668 | int old_ruid, old_suid, new_suid; | ||
669 | int retval; | 667 | int retval; |
670 | 668 | ||
669 | new = prepare_creds(); | ||
670 | if (!new) | ||
671 | return -ENOMEM; | ||
672 | old = current_cred(); | ||
673 | |||
671 | retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); | 674 | retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); |
672 | if (retval) | 675 | if (retval) |
673 | return retval; | 676 | goto error; |
674 | 677 | ||
675 | old_ruid = cred->uid; | 678 | retval = -EPERM; |
676 | old_suid = cred->suid; | ||
677 | new_suid = old_suid; | ||
678 | |||
679 | if (capable(CAP_SETUID)) { | 679 | if (capable(CAP_SETUID)) { |
680 | if (uid != old_ruid && set_user(uid, old_euid != uid) < 0) | 680 | new->suid = new->uid = uid; |
681 | return -EAGAIN; | 681 | if (uid != old->uid && set_user(new) < 0) { |
682 | new_suid = uid; | 682 | retval = -EAGAIN; |
683 | } else if ((uid != cred->uid) && (uid != new_suid)) | 683 | goto error; |
684 | return -EPERM; | 684 | } |
685 | 685 | } else if (uid != old->uid && uid != new->suid) { | |
686 | if (old_euid != uid) { | 686 | goto error; |
687 | set_dumpable(current->mm, suid_dumpable); | ||
688 | smp_wmb(); | ||
689 | } | 687 | } |
690 | cred->fsuid = cred->euid = uid; | ||
691 | cred->suid = new_suid; | ||
692 | 688 | ||
693 | key_fsuid_changed(current); | 689 | new->fsuid = new->euid = uid; |
694 | proc_id_connector(current, PROC_EVENT_UID); | 690 | |
691 | retval = security_task_fix_setuid(new, old, LSM_SETID_ID); | ||
692 | if (retval < 0) | ||
693 | goto error; | ||
694 | |||
695 | return commit_creds(new); | ||
695 | 696 | ||
696 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID); | 697 | error: |
698 | abort_creds(new); | ||
699 | return retval; | ||
697 | } | 700 | } |
698 | 701 | ||
699 | 702 | ||
@@ -703,47 +706,53 @@ asmlinkage long sys_setuid(uid_t uid) | |||
703 | */ | 706 | */ |
704 | asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) | 707 | asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) |
705 | { | 708 | { |
706 | struct cred *cred = current->cred; | 709 | const struct cred *old; |
707 | int old_ruid = cred->uid; | 710 | struct cred *new; |
708 | int old_euid = cred->euid; | ||
709 | int old_suid = cred->suid; | ||
710 | int retval; | 711 | int retval; |
711 | 712 | ||
713 | new = prepare_creds(); | ||
714 | if (!new) | ||
715 | return -ENOMEM; | ||
716 | |||
712 | retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES); | 717 | retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES); |
713 | if (retval) | 718 | if (retval) |
714 | return retval; | 719 | goto error; |
720 | old = current_cred(); | ||
715 | 721 | ||
722 | retval = -EPERM; | ||
716 | if (!capable(CAP_SETUID)) { | 723 | if (!capable(CAP_SETUID)) { |
717 | if ((ruid != (uid_t) -1) && (ruid != cred->uid) && | 724 | if (ruid != (uid_t) -1 && ruid != old->uid && |
718 | (ruid != cred->euid) && (ruid != cred->suid)) | 725 | ruid != old->euid && ruid != old->suid) |
719 | return -EPERM; | 726 | goto error; |
720 | if ((euid != (uid_t) -1) && (euid != cred->uid) && | 727 | if (euid != (uid_t) -1 && euid != old->uid && |
721 | (euid != cred->euid) && (euid != cred->suid)) | 728 | euid != old->euid && euid != old->suid) |
722 | return -EPERM; | 729 | goto error; |
723 | if ((suid != (uid_t) -1) && (suid != cred->uid) && | 730 | if (suid != (uid_t) -1 && suid != old->uid && |
724 | (suid != cred->euid) && (suid != cred->suid)) | 731 | suid != old->euid && suid != old->suid) |
725 | return -EPERM; | 732 | goto error; |
726 | } | 733 | } |
734 | |||
735 | retval = -EAGAIN; | ||
727 | if (ruid != (uid_t) -1) { | 736 | if (ruid != (uid_t) -1) { |
728 | if (ruid != cred->uid && | 737 | new->uid = ruid; |
729 | set_user(ruid, euid != cred->euid) < 0) | 738 | if (ruid != old->uid && set_user(new) < 0) |
730 | return -EAGAIN; | 739 | goto error; |
731 | } | 740 | } |
732 | if (euid != (uid_t) -1) { | 741 | if (euid != (uid_t) -1) |
733 | if (euid != cred->euid) { | 742 | new->euid = euid; |
734 | set_dumpable(current->mm, suid_dumpable); | ||
735 | smp_wmb(); | ||
736 | } | ||
737 | cred->euid = euid; | ||
738 | } | ||
739 | cred->fsuid = cred->euid; | ||
740 | if (suid != (uid_t) -1) | 743 | if (suid != (uid_t) -1) |
741 | cred->suid = suid; | 744 | new->suid = suid; |
745 | new->fsuid = new->euid; | ||
742 | 746 | ||
743 | key_fsuid_changed(current); | 747 | retval = security_task_fix_setuid(new, old, LSM_SETID_RES); |
744 | proc_id_connector(current, PROC_EVENT_UID); | 748 | if (retval < 0) |
749 | goto error; | ||
745 | 750 | ||
746 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES); | 751 | return commit_creds(new); |
752 | |||
753 | error: | ||
754 | abort_creds(new); | ||
755 | return retval; | ||
747 | } | 756 | } |
748 | 757 | ||
749 | asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid) | 758 | asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid) |
@@ -763,40 +772,45 @@ asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __us | |||
763 | */ | 772 | */ |
764 | asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) | 773 | asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) |
765 | { | 774 | { |
766 | struct cred *cred = current->cred; | 775 | const struct cred *old; |
776 | struct cred *new; | ||
767 | int retval; | 777 | int retval; |
768 | 778 | ||
779 | new = prepare_creds(); | ||
780 | if (!new) | ||
781 | return -ENOMEM; | ||
782 | old = current_cred(); | ||
783 | |||
769 | retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES); | 784 | retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES); |
770 | if (retval) | 785 | if (retval) |
771 | return retval; | 786 | goto error; |
772 | 787 | ||
788 | retval = -EPERM; | ||
773 | if (!capable(CAP_SETGID)) { | 789 | if (!capable(CAP_SETGID)) { |
774 | if ((rgid != (gid_t) -1) && (rgid != cred->gid) && | 790 | if (rgid != (gid_t) -1 && rgid != old->gid && |
775 | (rgid != cred->egid) && (rgid != cred->sgid)) | 791 | rgid != old->egid && rgid != old->sgid) |
776 | return -EPERM; | 792 | goto error; |
777 | if ((egid != (gid_t) -1) && (egid != cred->gid) && | 793 | if (egid != (gid_t) -1 && egid != old->gid && |
778 | (egid != cred->egid) && (egid != cred->sgid)) | 794 | egid != old->egid && egid != old->sgid) |
779 | return -EPERM; | 795 | goto error; |
780 | if ((sgid != (gid_t) -1) && (sgid != cred->gid) && | 796 | if (sgid != (gid_t) -1 && sgid != old->gid && |
781 | (sgid != cred->egid) && (sgid != cred->sgid)) | 797 | sgid != old->egid && sgid != old->sgid) |
782 | return -EPERM; | 798 | goto error; |
783 | } | 799 | } |
784 | if (egid != (gid_t) -1) { | 800 | |
785 | if (egid != cred->egid) { | ||
786 | set_dumpable(current->mm, suid_dumpable); | ||
787 | smp_wmb(); | ||
788 | } | ||
789 | cred->egid = egid; | ||
790 | } | ||
791 | cred->fsgid = cred->egid; | ||
792 | if (rgid != (gid_t) -1) | 801 | if (rgid != (gid_t) -1) |
793 | cred->gid = rgid; | 802 | new->gid = rgid; |
803 | if (egid != (gid_t) -1) | ||
804 | new->egid = egid; | ||
794 | if (sgid != (gid_t) -1) | 805 | if (sgid != (gid_t) -1) |
795 | cred->sgid = sgid; | 806 | new->sgid = sgid; |
807 | new->fsgid = new->egid; | ||
796 | 808 | ||
797 | key_fsgid_changed(current); | 809 | return commit_creds(new); |
798 | proc_id_connector(current, PROC_EVENT_GID); | 810 | |
799 | return 0; | 811 | error: |
812 | abort_creds(new); | ||
813 | return retval; | ||
800 | } | 814 | } |
801 | 815 | ||
802 | asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid) | 816 | asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid) |
@@ -820,28 +834,35 @@ asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __us | |||
820 | */ | 834 | */ |
821 | asmlinkage long sys_setfsuid(uid_t uid) | 835 | asmlinkage long sys_setfsuid(uid_t uid) |
822 | { | 836 | { |
823 | struct cred *cred = current->cred; | 837 | const struct cred *old; |
824 | int old_fsuid; | 838 | struct cred *new; |
839 | uid_t old_fsuid; | ||
840 | |||
841 | new = prepare_creds(); | ||
842 | if (!new) | ||
843 | return current_fsuid(); | ||
844 | old = current_cred(); | ||
845 | old_fsuid = old->fsuid; | ||
825 | 846 | ||
826 | old_fsuid = cred->fsuid; | 847 | if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS) < 0) |
827 | if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS)) | 848 | goto error; |
828 | return old_fsuid; | ||
829 | 849 | ||
830 | if (uid == cred->uid || uid == cred->euid || | 850 | if (uid == old->uid || uid == old->euid || |
831 | uid == cred->suid || uid == cred->fsuid || | 851 | uid == old->suid || uid == old->fsuid || |
832 | capable(CAP_SETUID)) { | 852 | capable(CAP_SETUID)) { |
833 | if (uid != old_fsuid) { | 853 | if (uid != old_fsuid) { |
834 | set_dumpable(current->mm, suid_dumpable); | 854 | new->fsuid = uid; |
835 | smp_wmb(); | 855 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) |
856 | goto change_okay; | ||
836 | } | 857 | } |
837 | cred->fsuid = uid; | ||
838 | } | 858 | } |
839 | 859 | ||
840 | key_fsuid_changed(current); | 860 | error: |
841 | proc_id_connector(current, PROC_EVENT_UID); | 861 | abort_creds(new); |
842 | 862 | return old_fsuid; | |
843 | security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS); | ||
844 | 863 | ||
864 | change_okay: | ||
865 | commit_creds(new); | ||
845 | return old_fsuid; | 866 | return old_fsuid; |
846 | } | 867 | } |
847 | 868 | ||
@@ -850,24 +871,34 @@ asmlinkage long sys_setfsuid(uid_t uid) | |||
850 | */ | 871 | */ |
851 | asmlinkage long sys_setfsgid(gid_t gid) | 872 | asmlinkage long sys_setfsgid(gid_t gid) |
852 | { | 873 | { |
853 | struct cred *cred = current->cred; | 874 | const struct cred *old; |
854 | int old_fsgid; | 875 | struct cred *new; |
876 | gid_t old_fsgid; | ||
877 | |||
878 | new = prepare_creds(); | ||
879 | if (!new) | ||
880 | return current_fsgid(); | ||
881 | old = current_cred(); | ||
882 | old_fsgid = old->fsgid; | ||
855 | 883 | ||
856 | old_fsgid = cred->fsgid; | ||
857 | if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS)) | 884 | if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS)) |
858 | return old_fsgid; | 885 | goto error; |
859 | 886 | ||
860 | if (gid == cred->gid || gid == cred->egid || | 887 | if (gid == old->gid || gid == old->egid || |
861 | gid == cred->sgid || gid == cred->fsgid || | 888 | gid == old->sgid || gid == old->fsgid || |
862 | capable(CAP_SETGID)) { | 889 | capable(CAP_SETGID)) { |
863 | if (gid != old_fsgid) { | 890 | if (gid != old_fsgid) { |
864 | set_dumpable(current->mm, suid_dumpable); | 891 | new->fsgid = gid; |
865 | smp_wmb(); | 892 | goto change_okay; |
866 | } | 893 | } |
867 | cred->fsgid = gid; | ||
868 | key_fsgid_changed(current); | ||
869 | proc_id_connector(current, PROC_EVENT_GID); | ||
870 | } | 894 | } |
895 | |||
896 | error: | ||
897 | abort_creds(new); | ||
898 | return old_fsgid; | ||
899 | |||
900 | change_okay: | ||
901 | commit_creds(new); | ||
871 | return old_fsgid; | 902 | return old_fsgid; |
872 | } | 903 | } |
873 | 904 | ||
@@ -1136,7 +1167,7 @@ EXPORT_SYMBOL(groups_free); | |||
1136 | 1167 | ||
1137 | /* export the group_info to a user-space array */ | 1168 | /* export the group_info to a user-space array */ |
1138 | static int groups_to_user(gid_t __user *grouplist, | 1169 | static int groups_to_user(gid_t __user *grouplist, |
1139 | struct group_info *group_info) | 1170 | const struct group_info *group_info) |
1140 | { | 1171 | { |
1141 | int i; | 1172 | int i; |
1142 | unsigned int count = group_info->ngroups; | 1173 | unsigned int count = group_info->ngroups; |
@@ -1227,31 +1258,25 @@ int groups_search(const struct group_info *group_info, gid_t grp) | |||
1227 | } | 1258 | } |
1228 | 1259 | ||
1229 | /** | 1260 | /** |
1230 | * set_groups - Change a group subscription in a security record | 1261 | * set_groups - Change a group subscription in a set of credentials |
1231 | * @sec: The security record to alter | 1262 | * @new: The newly prepared set of credentials to alter |
1232 | * @group_info: The group list to impose | 1263 | * @group_info: The group list to install |
1233 | * | 1264 | * |
1234 | * Validate a group subscription and, if valid, impose it upon a task security | 1265 | * Validate a group subscription and, if valid, insert it into a set |
1235 | * record. | 1266 | * of credentials. |
1236 | */ | 1267 | */ |
1237 | int set_groups(struct cred *cred, struct group_info *group_info) | 1268 | int set_groups(struct cred *new, struct group_info *group_info) |
1238 | { | 1269 | { |
1239 | int retval; | 1270 | int retval; |
1240 | struct group_info *old_info; | ||
1241 | 1271 | ||
1242 | retval = security_task_setgroups(group_info); | 1272 | retval = security_task_setgroups(group_info); |
1243 | if (retval) | 1273 | if (retval) |
1244 | return retval; | 1274 | return retval; |
1245 | 1275 | ||
1276 | put_group_info(new->group_info); | ||
1246 | groups_sort(group_info); | 1277 | groups_sort(group_info); |
1247 | get_group_info(group_info); | 1278 | get_group_info(group_info); |
1248 | 1279 | new->group_info = group_info; | |
1249 | spin_lock(&cred->lock); | ||
1250 | old_info = cred->group_info; | ||
1251 | cred->group_info = group_info; | ||
1252 | spin_unlock(&cred->lock); | ||
1253 | |||
1254 | put_group_info(old_info); | ||
1255 | return 0; | 1280 | return 0; |
1256 | } | 1281 | } |
1257 | 1282 | ||
@@ -1266,7 +1291,20 @@ EXPORT_SYMBOL(set_groups); | |||
1266 | */ | 1291 | */ |
1267 | int set_current_groups(struct group_info *group_info) | 1292 | int set_current_groups(struct group_info *group_info) |
1268 | { | 1293 | { |
1269 | return set_groups(current->cred, group_info); | 1294 | struct cred *new; |
1295 | int ret; | ||
1296 | |||
1297 | new = prepare_creds(); | ||
1298 | if (!new) | ||
1299 | return -ENOMEM; | ||
1300 | |||
1301 | ret = set_groups(new, group_info); | ||
1302 | if (ret < 0) { | ||
1303 | abort_creds(new); | ||
1304 | return ret; | ||
1305 | } | ||
1306 | |||
1307 | return commit_creds(new); | ||
1270 | } | 1308 | } |
1271 | 1309 | ||
1272 | EXPORT_SYMBOL(set_current_groups); | 1310 | EXPORT_SYMBOL(set_current_groups); |
@@ -1666,9 +1704,11 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
1666 | unsigned char comm[sizeof(me->comm)]; | 1704 | unsigned char comm[sizeof(me->comm)]; |
1667 | long error; | 1705 | long error; |
1668 | 1706 | ||
1669 | if (security_task_prctl(option, arg2, arg3, arg4, arg5, &error)) | 1707 | error = security_task_prctl(option, arg2, arg3, arg4, arg5); |
1708 | if (error != -ENOSYS) | ||
1670 | return error; | 1709 | return error; |
1671 | 1710 | ||
1711 | error = 0; | ||
1672 | switch (option) { | 1712 | switch (option) { |
1673 | case PR_SET_PDEATHSIG: | 1713 | case PR_SET_PDEATHSIG: |
1674 | if (!valid_signal(arg2)) { | 1714 | if (!valid_signal(arg2)) { |
diff --git a/kernel/user.c b/kernel/user.c index 104d22ac84d5..d476307dd4b0 100644 --- a/kernel/user.c +++ b/kernel/user.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/user_namespace.h> | 18 | #include <linux/user_namespace.h> |
19 | #include "cred-internals.h" | ||
19 | 20 | ||
20 | struct user_namespace init_user_ns = { | 21 | struct user_namespace init_user_ns = { |
21 | .kref = { | 22 | .kref = { |
@@ -104,16 +105,10 @@ static int sched_create_user(struct user_struct *up) | |||
104 | return rc; | 105 | return rc; |
105 | } | 106 | } |
106 | 107 | ||
107 | static void sched_switch_user(struct task_struct *p) | ||
108 | { | ||
109 | sched_move_task(p); | ||
110 | } | ||
111 | |||
112 | #else /* CONFIG_USER_SCHED */ | 108 | #else /* CONFIG_USER_SCHED */ |
113 | 109 | ||
114 | static void sched_destroy_user(struct user_struct *up) { } | 110 | static void sched_destroy_user(struct user_struct *up) { } |
115 | static int sched_create_user(struct user_struct *up) { return 0; } | 111 | static int sched_create_user(struct user_struct *up) { return 0; } |
116 | static void sched_switch_user(struct task_struct *p) { } | ||
117 | 112 | ||
118 | #endif /* CONFIG_USER_SCHED */ | 113 | #endif /* CONFIG_USER_SCHED */ |
119 | 114 | ||
@@ -448,36 +443,6 @@ out_unlock: | |||
448 | return NULL; | 443 | return NULL; |
449 | } | 444 | } |
450 | 445 | ||
451 | void switch_uid(struct user_struct *new_user) | ||
452 | { | ||
453 | struct user_struct *old_user; | ||
454 | |||
455 | /* What if a process setreuid()'s and this brings the | ||
456 | * new uid over his NPROC rlimit? We can check this now | ||
457 | * cheaply with the new uid cache, so if it matters | ||
458 | * we should be checking for it. -DaveM | ||
459 | */ | ||
460 | old_user = current->cred->user; | ||
461 | atomic_inc(&new_user->processes); | ||
462 | atomic_dec(&old_user->processes); | ||
463 | switch_uid_keyring(new_user); | ||
464 | current->cred->user = new_user; | ||
465 | sched_switch_user(current); | ||
466 | |||
467 | /* | ||
468 | * We need to synchronize with __sigqueue_alloc() | ||
469 | * doing a get_uid(p->user).. If that saw the old | ||
470 | * user value, we need to wait until it has exited | ||
471 | * its critical region before we can free the old | ||
472 | * structure. | ||
473 | */ | ||
474 | smp_mb(); | ||
475 | spin_unlock_wait(¤t->sighand->siglock); | ||
476 | |||
477 | free_uid(old_user); | ||
478 | suid_keys(current); | ||
479 | } | ||
480 | |||
481 | #ifdef CONFIG_USER_NS | 446 | #ifdef CONFIG_USER_NS |
482 | void release_uids(struct user_namespace *ns) | 447 | void release_uids(struct user_namespace *ns) |
483 | { | 448 | { |
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index f82730adea00..0d9c51d67333 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c | |||
@@ -19,6 +19,7 @@ static struct user_namespace *clone_user_ns(struct user_namespace *old_ns) | |||
19 | { | 19 | { |
20 | struct user_namespace *ns; | 20 | struct user_namespace *ns; |
21 | struct user_struct *new_user; | 21 | struct user_struct *new_user; |
22 | struct cred *new; | ||
22 | int n; | 23 | int n; |
23 | 24 | ||
24 | ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL); | 25 | ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL); |
@@ -45,7 +46,16 @@ static struct user_namespace *clone_user_ns(struct user_namespace *old_ns) | |||
45 | return ERR_PTR(-ENOMEM); | 46 | return ERR_PTR(-ENOMEM); |
46 | } | 47 | } |
47 | 48 | ||
48 | switch_uid(new_user); | 49 | /* Install the new user */ |
50 | new = prepare_creds(); | ||
51 | if (!new) { | ||
52 | free_uid(new_user); | ||
53 | free_uid(ns->root_user); | ||
54 | kfree(ns); | ||
55 | } | ||
56 | free_uid(new->user); | ||
57 | new->user = new_user; | ||
58 | commit_creds(new); | ||
49 | return ns; | 59 | return ns; |
50 | } | 60 | } |
51 | 61 | ||
diff --git a/lib/Makefile b/lib/Makefile index 7cb65d85aeb0..80fe8a3ec12a 100644 --- a/lib/Makefile +++ b/lib/Makefile | |||
@@ -11,7 +11,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ | |||
11 | rbtree.o radix-tree.o dump_stack.o \ | 11 | rbtree.o radix-tree.o dump_stack.o \ |
12 | idr.o int_sqrt.o extable.o prio_tree.o \ | 12 | idr.o int_sqrt.o extable.o prio_tree.o \ |
13 | sha1.o irq_regs.o reciprocal_div.o argv_split.o \ | 13 | sha1.o irq_regs.o reciprocal_div.o argv_split.o \ |
14 | proportions.o prio_heap.o ratelimit.o show_mem.o | 14 | proportions.o prio_heap.o ratelimit.o show_mem.o is_single_threaded.o |
15 | 15 | ||
16 | lib-$(CONFIG_MMU) += ioremap.o | 16 | lib-$(CONFIG_MMU) += ioremap.o |
17 | lib-$(CONFIG_SMP) += cpumask.o | 17 | lib-$(CONFIG_SMP) += cpumask.o |
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c index 9a8ff684da79..ad8c7a782da1 100644 --- a/net/rxrpc/ar-key.c +++ b/net/rxrpc/ar-key.c | |||
@@ -287,6 +287,7 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *conn, | |||
287 | time_t expiry, | 287 | time_t expiry, |
288 | u32 kvno) | 288 | u32 kvno) |
289 | { | 289 | { |
290 | const struct cred *cred = current_cred(); | ||
290 | struct key *key; | 291 | struct key *key; |
291 | int ret; | 292 | int ret; |
292 | 293 | ||
@@ -297,7 +298,7 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *conn, | |||
297 | 298 | ||
298 | _enter(""); | 299 | _enter(""); |
299 | 300 | ||
300 | key = key_alloc(&key_type_rxrpc, "x", 0, 0, current, 0, | 301 | key = key_alloc(&key_type_rxrpc, "x", 0, 0, cred, 0, |
301 | KEY_ALLOC_NOT_IN_QUOTA); | 302 | KEY_ALLOC_NOT_IN_QUOTA); |
302 | if (IS_ERR(key)) { | 303 | if (IS_ERR(key)) { |
303 | _leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key)); | 304 | _leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key)); |
@@ -340,10 +341,11 @@ EXPORT_SYMBOL(rxrpc_get_server_data_key); | |||
340 | */ | 341 | */ |
341 | struct key *rxrpc_get_null_key(const char *keyname) | 342 | struct key *rxrpc_get_null_key(const char *keyname) |
342 | { | 343 | { |
344 | const struct cred *cred = current_cred(); | ||
343 | struct key *key; | 345 | struct key *key; |
344 | int ret; | 346 | int ret; |
345 | 347 | ||
346 | key = key_alloc(&key_type_rxrpc, keyname, 0, 0, current, | 348 | key = key_alloc(&key_type_rxrpc, keyname, 0, 0, cred, |
347 | KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA); | 349 | KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA); |
348 | if (IS_ERR(key)) | 350 | if (IS_ERR(key)) |
349 | return key; | 351 | return key; |
diff --git a/security/capability.c b/security/capability.c index fac2f61b69a9..efeb6d9e0e6a 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -340,12 +340,16 @@ static int cap_task_create(unsigned long clone_flags) | |||
340 | return 0; | 340 | return 0; |
341 | } | 341 | } |
342 | 342 | ||
343 | static int cap_cred_alloc_security(struct cred *cred) | 343 | static void cap_cred_free(struct cred *cred) |
344 | { | ||
345 | } | ||
346 | |||
347 | static int cap_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) | ||
344 | { | 348 | { |
345 | return 0; | 349 | return 0; |
346 | } | 350 | } |
347 | 351 | ||
348 | static void cap_cred_free(struct cred *cred) | 352 | static void cap_cred_commit(struct cred *new, const struct cred *old) |
349 | { | 353 | { |
350 | } | 354 | } |
351 | 355 | ||
@@ -750,7 +754,7 @@ static void cap_release_secctx(char *secdata, u32 seclen) | |||
750 | } | 754 | } |
751 | 755 | ||
752 | #ifdef CONFIG_KEYS | 756 | #ifdef CONFIG_KEYS |
753 | static int cap_key_alloc(struct key *key, struct task_struct *ctx, | 757 | static int cap_key_alloc(struct key *key, const struct cred *cred, |
754 | unsigned long flags) | 758 | unsigned long flags) |
755 | { | 759 | { |
756 | return 0; | 760 | return 0; |
@@ -760,7 +764,7 @@ static void cap_key_free(struct key *key) | |||
760 | { | 764 | { |
761 | } | 765 | } |
762 | 766 | ||
763 | static int cap_key_permission(key_ref_t key_ref, struct task_struct *context, | 767 | static int cap_key_permission(key_ref_t key_ref, const struct cred *cred, |
764 | key_perm_t perm) | 768 | key_perm_t perm) |
765 | { | 769 | { |
766 | return 0; | 770 | return 0; |
@@ -814,8 +818,7 @@ void security_fixup_ops(struct security_operations *ops) | |||
814 | set_to_cap_if_null(ops, ptrace_may_access); | 818 | set_to_cap_if_null(ops, ptrace_may_access); |
815 | set_to_cap_if_null(ops, ptrace_traceme); | 819 | set_to_cap_if_null(ops, ptrace_traceme); |
816 | set_to_cap_if_null(ops, capget); | 820 | set_to_cap_if_null(ops, capget); |
817 | set_to_cap_if_null(ops, capset_check); | 821 | set_to_cap_if_null(ops, capset); |
818 | set_to_cap_if_null(ops, capset_set); | ||
819 | set_to_cap_if_null(ops, acct); | 822 | set_to_cap_if_null(ops, acct); |
820 | set_to_cap_if_null(ops, capable); | 823 | set_to_cap_if_null(ops, capable); |
821 | set_to_cap_if_null(ops, quotactl); | 824 | set_to_cap_if_null(ops, quotactl); |
@@ -890,10 +893,11 @@ void security_fixup_ops(struct security_operations *ops) | |||
890 | set_to_cap_if_null(ops, file_receive); | 893 | set_to_cap_if_null(ops, file_receive); |
891 | set_to_cap_if_null(ops, dentry_open); | 894 | set_to_cap_if_null(ops, dentry_open); |
892 | set_to_cap_if_null(ops, task_create); | 895 | set_to_cap_if_null(ops, task_create); |
893 | set_to_cap_if_null(ops, cred_alloc_security); | ||
894 | set_to_cap_if_null(ops, cred_free); | 896 | set_to_cap_if_null(ops, cred_free); |
897 | set_to_cap_if_null(ops, cred_prepare); | ||
898 | set_to_cap_if_null(ops, cred_commit); | ||
895 | set_to_cap_if_null(ops, task_setuid); | 899 | set_to_cap_if_null(ops, task_setuid); |
896 | set_to_cap_if_null(ops, task_post_setuid); | 900 | set_to_cap_if_null(ops, task_fix_setuid); |
897 | set_to_cap_if_null(ops, task_setgid); | 901 | set_to_cap_if_null(ops, task_setgid); |
898 | set_to_cap_if_null(ops, task_setpgid); | 902 | set_to_cap_if_null(ops, task_setpgid); |
899 | set_to_cap_if_null(ops, task_getpgid); | 903 | set_to_cap_if_null(ops, task_getpgid); |
@@ -910,7 +914,6 @@ void security_fixup_ops(struct security_operations *ops) | |||
910 | set_to_cap_if_null(ops, task_wait); | 914 | set_to_cap_if_null(ops, task_wait); |
911 | set_to_cap_if_null(ops, task_kill); | 915 | set_to_cap_if_null(ops, task_kill); |
912 | set_to_cap_if_null(ops, task_prctl); | 916 | set_to_cap_if_null(ops, task_prctl); |
913 | set_to_cap_if_null(ops, task_reparent_to_init); | ||
914 | set_to_cap_if_null(ops, task_to_inode); | 917 | set_to_cap_if_null(ops, task_to_inode); |
915 | set_to_cap_if_null(ops, ipc_permission); | 918 | set_to_cap_if_null(ops, ipc_permission); |
916 | set_to_cap_if_null(ops, ipc_getsecid); | 919 | set_to_cap_if_null(ops, ipc_getsecid); |
diff --git a/security/commoncap.c b/security/commoncap.c index 0384bf95db68..b5419273f92d 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -72,8 +72,8 @@ int cap_ptrace_may_access(struct task_struct *child, unsigned int mode) | |||
72 | int ret = 0; | 72 | int ret = 0; |
73 | 73 | ||
74 | rcu_read_lock(); | 74 | rcu_read_lock(); |
75 | if (!cap_issubset(child->cred->cap_permitted, | 75 | if (!cap_issubset(__task_cred(child)->cap_permitted, |
76 | current->cred->cap_permitted) && | 76 | current_cred()->cap_permitted) && |
77 | !capable(CAP_SYS_PTRACE)) | 77 | !capable(CAP_SYS_PTRACE)) |
78 | ret = -EPERM; | 78 | ret = -EPERM; |
79 | rcu_read_unlock(); | 79 | rcu_read_unlock(); |
@@ -85,8 +85,8 @@ int cap_ptrace_traceme(struct task_struct *parent) | |||
85 | int ret = 0; | 85 | int ret = 0; |
86 | 86 | ||
87 | rcu_read_lock(); | 87 | rcu_read_lock(); |
88 | if (!cap_issubset(current->cred->cap_permitted, | 88 | if (!cap_issubset(current_cred()->cap_permitted, |
89 | parent->cred->cap_permitted) && | 89 | __task_cred(parent)->cap_permitted) && |
90 | !has_capability(parent, CAP_SYS_PTRACE)) | 90 | !has_capability(parent, CAP_SYS_PTRACE)) |
91 | ret = -EPERM; | 91 | ret = -EPERM; |
92 | rcu_read_unlock(); | 92 | rcu_read_unlock(); |
@@ -117,7 +117,7 @@ static inline int cap_inh_is_capped(void) | |||
117 | * to the old permitted set. That is, if the current task | 117 | * to the old permitted set. That is, if the current task |
118 | * does *not* possess the CAP_SETPCAP capability. | 118 | * does *not* possess the CAP_SETPCAP capability. |
119 | */ | 119 | */ |
120 | return (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0); | 120 | return cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0; |
121 | } | 121 | } |
122 | 122 | ||
123 | static inline int cap_limit_ptraced_target(void) { return 1; } | 123 | static inline int cap_limit_ptraced_target(void) { return 1; } |
@@ -132,52 +132,39 @@ static inline int cap_limit_ptraced_target(void) | |||
132 | 132 | ||
133 | #endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ | 133 | #endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ |
134 | 134 | ||
135 | int cap_capset_check(const kernel_cap_t *effective, | 135 | int cap_capset(struct cred *new, |
136 | const kernel_cap_t *inheritable, | 136 | const struct cred *old, |
137 | const kernel_cap_t *permitted) | 137 | const kernel_cap_t *effective, |
138 | const kernel_cap_t *inheritable, | ||
139 | const kernel_cap_t *permitted) | ||
138 | { | 140 | { |
139 | const struct cred *cred = current->cred; | 141 | if (cap_inh_is_capped() && |
140 | 142 | !cap_issubset(*inheritable, | |
141 | if (cap_inh_is_capped() | 143 | cap_combine(old->cap_inheritable, |
142 | && !cap_issubset(*inheritable, | 144 | old->cap_permitted))) |
143 | cap_combine(cred->cap_inheritable, | ||
144 | cred->cap_permitted))) { | ||
145 | /* incapable of using this inheritable set */ | 145 | /* incapable of using this inheritable set */ |
146 | return -EPERM; | 146 | return -EPERM; |
147 | } | 147 | |
148 | if (!cap_issubset(*inheritable, | 148 | if (!cap_issubset(*inheritable, |
149 | cap_combine(cred->cap_inheritable, | 149 | cap_combine(old->cap_inheritable, |
150 | cred->cap_bset))) { | 150 | old->cap_bset))) |
151 | /* no new pI capabilities outside bounding set */ | 151 | /* no new pI capabilities outside bounding set */ |
152 | return -EPERM; | 152 | return -EPERM; |
153 | } | ||
154 | 153 | ||
155 | /* verify restrictions on target's new Permitted set */ | 154 | /* verify restrictions on target's new Permitted set */ |
156 | if (!cap_issubset (*permitted, | 155 | if (!cap_issubset(*permitted, old->cap_permitted)) |
157 | cap_combine (cred->cap_permitted, | ||
158 | cred->cap_permitted))) { | ||
159 | return -EPERM; | 156 | return -EPERM; |
160 | } | ||
161 | 157 | ||
162 | /* verify the _new_Effective_ is a subset of the _new_Permitted_ */ | 158 | /* verify the _new_Effective_ is a subset of the _new_Permitted_ */ |
163 | if (!cap_issubset (*effective, *permitted)) { | 159 | if (!cap_issubset(*effective, *permitted)) |
164 | return -EPERM; | 160 | return -EPERM; |
165 | } | ||
166 | 161 | ||
162 | new->cap_effective = *effective; | ||
163 | new->cap_inheritable = *inheritable; | ||
164 | new->cap_permitted = *permitted; | ||
167 | return 0; | 165 | return 0; |
168 | } | 166 | } |
169 | 167 | ||
170 | void cap_capset_set(const kernel_cap_t *effective, | ||
171 | const kernel_cap_t *inheritable, | ||
172 | const kernel_cap_t *permitted) | ||
173 | { | ||
174 | struct cred *cred = current->cred; | ||
175 | |||
176 | cred->cap_effective = *effective; | ||
177 | cred->cap_inheritable = *inheritable; | ||
178 | cred->cap_permitted = *permitted; | ||
179 | } | ||
180 | |||
181 | static inline void bprm_clear_caps(struct linux_binprm *bprm) | 168 | static inline void bprm_clear_caps(struct linux_binprm *bprm) |
182 | { | 169 | { |
183 | cap_clear(bprm->cap_post_exec_permitted); | 170 | cap_clear(bprm->cap_post_exec_permitted); |
@@ -382,41 +369,46 @@ int cap_bprm_set_security (struct linux_binprm *bprm) | |||
382 | return ret; | 369 | return ret; |
383 | } | 370 | } |
384 | 371 | ||
385 | void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) | 372 | int cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) |
386 | { | 373 | { |
387 | struct cred *cred = current->cred; | 374 | const struct cred *old = current_cred(); |
375 | struct cred *new; | ||
376 | |||
377 | new = prepare_creds(); | ||
378 | if (!new) | ||
379 | return -ENOMEM; | ||
388 | 380 | ||
389 | if (bprm->e_uid != cred->uid || bprm->e_gid != cred->gid || | 381 | if (bprm->e_uid != old->uid || bprm->e_gid != old->gid || |
390 | !cap_issubset(bprm->cap_post_exec_permitted, | 382 | !cap_issubset(bprm->cap_post_exec_permitted, |
391 | cred->cap_permitted)) { | 383 | old->cap_permitted)) { |
392 | set_dumpable(current->mm, suid_dumpable); | 384 | set_dumpable(current->mm, suid_dumpable); |
393 | current->pdeath_signal = 0; | 385 | current->pdeath_signal = 0; |
394 | 386 | ||
395 | if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) { | 387 | if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) { |
396 | if (!capable(CAP_SETUID)) { | 388 | if (!capable(CAP_SETUID)) { |
397 | bprm->e_uid = cred->uid; | 389 | bprm->e_uid = old->uid; |
398 | bprm->e_gid = cred->gid; | 390 | bprm->e_gid = old->gid; |
399 | } | 391 | } |
400 | if (cap_limit_ptraced_target()) { | 392 | if (cap_limit_ptraced_target()) { |
401 | bprm->cap_post_exec_permitted = cap_intersect( | 393 | bprm->cap_post_exec_permitted = cap_intersect( |
402 | bprm->cap_post_exec_permitted, | 394 | bprm->cap_post_exec_permitted, |
403 | cred->cap_permitted); | 395 | new->cap_permitted); |
404 | } | 396 | } |
405 | } | 397 | } |
406 | } | 398 | } |
407 | 399 | ||
408 | cred->suid = cred->euid = cred->fsuid = bprm->e_uid; | 400 | new->suid = new->euid = new->fsuid = bprm->e_uid; |
409 | cred->sgid = cred->egid = cred->fsgid = bprm->e_gid; | 401 | new->sgid = new->egid = new->fsgid = bprm->e_gid; |
410 | 402 | ||
411 | /* For init, we want to retain the capabilities set | 403 | /* For init, we want to retain the capabilities set |
412 | * in the init_task struct. Thus we skip the usual | 404 | * in the init_task struct. Thus we skip the usual |
413 | * capability rules */ | 405 | * capability rules */ |
414 | if (!is_global_init(current)) { | 406 | if (!is_global_init(current)) { |
415 | cred->cap_permitted = bprm->cap_post_exec_permitted; | 407 | new->cap_permitted = bprm->cap_post_exec_permitted; |
416 | if (bprm->cap_effective) | 408 | if (bprm->cap_effective) |
417 | cred->cap_effective = bprm->cap_post_exec_permitted; | 409 | new->cap_effective = bprm->cap_post_exec_permitted; |
418 | else | 410 | else |
419 | cap_clear(cred->cap_effective); | 411 | cap_clear(new->cap_effective); |
420 | } | 412 | } |
421 | 413 | ||
422 | /* | 414 | /* |
@@ -431,15 +423,15 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) | |||
431 | * Number 1 above might fail if you don't have a full bset, but I think | 423 | * Number 1 above might fail if you don't have a full bset, but I think |
432 | * that is interesting information to audit. | 424 | * that is interesting information to audit. |
433 | */ | 425 | */ |
434 | if (!cap_isclear(cred->cap_effective)) { | 426 | if (!cap_isclear(new->cap_effective)) { |
435 | if (!cap_issubset(CAP_FULL_SET, cred->cap_effective) || | 427 | if (!cap_issubset(CAP_FULL_SET, new->cap_effective) || |
436 | (bprm->e_uid != 0) || (cred->uid != 0) || | 428 | bprm->e_uid != 0 || new->uid != 0 || |
437 | issecure(SECURE_NOROOT)) | 429 | issecure(SECURE_NOROOT)) |
438 | audit_log_bprm_fcaps(bprm, &cred->cap_permitted, | 430 | audit_log_bprm_fcaps(bprm, new, old); |
439 | &cred->cap_effective); | ||
440 | } | 431 | } |
441 | 432 | ||
442 | cred->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); | 433 | new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); |
434 | return commit_creds(new); | ||
443 | } | 435 | } |
444 | 436 | ||
445 | int cap_bprm_secureexec (struct linux_binprm *bprm) | 437 | int cap_bprm_secureexec (struct linux_binprm *bprm) |
@@ -514,65 +506,49 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name) | |||
514 | * files.. | 506 | * files.. |
515 | * Thanks to Olaf Kirch and Peter Benie for spotting this. | 507 | * Thanks to Olaf Kirch and Peter Benie for spotting this. |
516 | */ | 508 | */ |
517 | static inline void cap_emulate_setxuid (int old_ruid, int old_euid, | 509 | static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old) |
518 | int old_suid) | ||
519 | { | 510 | { |
520 | struct cred *cred = current->cred; | 511 | if ((old->uid == 0 || old->euid == 0 || old->suid == 0) && |
521 | 512 | (new->uid != 0 && new->euid != 0 && new->suid != 0) && | |
522 | if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) && | ||
523 | (cred->uid != 0 && cred->euid != 0 && cred->suid != 0) && | ||
524 | !issecure(SECURE_KEEP_CAPS)) { | 513 | !issecure(SECURE_KEEP_CAPS)) { |
525 | cap_clear(cred->cap_permitted); | 514 | cap_clear(new->cap_permitted); |
526 | cap_clear(cred->cap_effective); | 515 | cap_clear(new->cap_effective); |
527 | } | ||
528 | if (old_euid == 0 && cred->euid != 0) { | ||
529 | cap_clear(cred->cap_effective); | ||
530 | } | ||
531 | if (old_euid != 0 && cred->euid == 0) { | ||
532 | cred->cap_effective = cred->cap_permitted; | ||
533 | } | 516 | } |
517 | if (old->euid == 0 && new->euid != 0) | ||
518 | cap_clear(new->cap_effective); | ||
519 | if (old->euid != 0 && new->euid == 0) | ||
520 | new->cap_effective = new->cap_permitted; | ||
534 | } | 521 | } |
535 | 522 | ||
536 | int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, | 523 | int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags) |
537 | int flags) | ||
538 | { | 524 | { |
539 | struct cred *cred = current->cred; | ||
540 | |||
541 | switch (flags) { | 525 | switch (flags) { |
542 | case LSM_SETID_RE: | 526 | case LSM_SETID_RE: |
543 | case LSM_SETID_ID: | 527 | case LSM_SETID_ID: |
544 | case LSM_SETID_RES: | 528 | case LSM_SETID_RES: |
545 | /* Copied from kernel/sys.c:setreuid/setuid/setresuid. */ | 529 | /* Copied from kernel/sys.c:setreuid/setuid/setresuid. */ |
546 | if (!issecure (SECURE_NO_SETUID_FIXUP)) { | 530 | if (!issecure(SECURE_NO_SETUID_FIXUP)) |
547 | cap_emulate_setxuid (old_ruid, old_euid, old_suid); | 531 | cap_emulate_setxuid(new, old); |
548 | } | ||
549 | break; | 532 | break; |
550 | case LSM_SETID_FS: | 533 | case LSM_SETID_FS: |
551 | { | 534 | /* Copied from kernel/sys.c:setfsuid. */ |
552 | uid_t old_fsuid = old_ruid; | ||
553 | |||
554 | /* Copied from kernel/sys.c:setfsuid. */ | ||
555 | 535 | ||
556 | /* | 536 | /* |
557 | * FIXME - is fsuser used for all CAP_FS_MASK capabilities? | 537 | * FIXME - is fsuser used for all CAP_FS_MASK capabilities? |
558 | * if not, we might be a bit too harsh here. | 538 | * if not, we might be a bit too harsh here. |
559 | */ | 539 | */ |
560 | 540 | if (!issecure(SECURE_NO_SETUID_FIXUP)) { | |
561 | if (!issecure (SECURE_NO_SETUID_FIXUP)) { | 541 | if (old->fsuid == 0 && new->fsuid != 0) { |
562 | if (old_fsuid == 0 && cred->fsuid != 0) { | 542 | new->cap_effective = |
563 | cred->cap_effective = | 543 | cap_drop_fs_set(new->cap_effective); |
564 | cap_drop_fs_set( | 544 | } |
565 | cred->cap_effective); | 545 | if (old->fsuid != 0 && new->fsuid == 0) { |
566 | } | 546 | new->cap_effective = |
567 | if (old_fsuid != 0 && cred->fsuid == 0) { | 547 | cap_raise_fs_set(new->cap_effective, |
568 | cred->cap_effective = | 548 | new->cap_permitted); |
569 | cap_raise_fs_set( | ||
570 | cred->cap_effective, | ||
571 | cred->cap_permitted); | ||
572 | } | ||
573 | } | 549 | } |
574 | break; | ||
575 | } | 550 | } |
551 | break; | ||
576 | default: | 552 | default: |
577 | return -EINVAL; | 553 | return -EINVAL; |
578 | } | 554 | } |
@@ -628,13 +604,14 @@ int cap_task_setnice (struct task_struct *p, int nice) | |||
628 | * this task could get inconsistent info. There can be no | 604 | * this task could get inconsistent info. There can be no |
629 | * racing writer bc a task can only change its own caps. | 605 | * racing writer bc a task can only change its own caps. |
630 | */ | 606 | */ |
631 | static long cap_prctl_drop(unsigned long cap) | 607 | static long cap_prctl_drop(struct cred *new, unsigned long cap) |
632 | { | 608 | { |
633 | if (!capable(CAP_SETPCAP)) | 609 | if (!capable(CAP_SETPCAP)) |
634 | return -EPERM; | 610 | return -EPERM; |
635 | if (!cap_valid(cap)) | 611 | if (!cap_valid(cap)) |
636 | return -EINVAL; | 612 | return -EINVAL; |
637 | cap_lower(current->cred->cap_bset, cap); | 613 | |
614 | cap_lower(new->cap_bset, cap); | ||
638 | return 0; | 615 | return 0; |
639 | } | 616 | } |
640 | 617 | ||
@@ -655,22 +632,29 @@ int cap_task_setnice (struct task_struct *p, int nice) | |||
655 | #endif | 632 | #endif |
656 | 633 | ||
657 | int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | 634 | int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, |
658 | unsigned long arg4, unsigned long arg5, long *rc_p) | 635 | unsigned long arg4, unsigned long arg5) |
659 | { | 636 | { |
660 | struct cred *cred = current_cred(); | 637 | struct cred *new; |
661 | long error = 0; | 638 | long error = 0; |
662 | 639 | ||
640 | new = prepare_creds(); | ||
641 | if (!new) | ||
642 | return -ENOMEM; | ||
643 | |||
663 | switch (option) { | 644 | switch (option) { |
664 | case PR_CAPBSET_READ: | 645 | case PR_CAPBSET_READ: |
646 | error = -EINVAL; | ||
665 | if (!cap_valid(arg2)) | 647 | if (!cap_valid(arg2)) |
666 | error = -EINVAL; | 648 | goto error; |
667 | else | 649 | error = !!cap_raised(new->cap_bset, arg2); |
668 | error = !!cap_raised(cred->cap_bset, arg2); | 650 | goto no_change; |
669 | break; | 651 | |
670 | #ifdef CONFIG_SECURITY_FILE_CAPABILITIES | 652 | #ifdef CONFIG_SECURITY_FILE_CAPABILITIES |
671 | case PR_CAPBSET_DROP: | 653 | case PR_CAPBSET_DROP: |
672 | error = cap_prctl_drop(arg2); | 654 | error = cap_prctl_drop(new, arg2); |
673 | break; | 655 | if (error < 0) |
656 | goto error; | ||
657 | goto changed; | ||
674 | 658 | ||
675 | /* | 659 | /* |
676 | * The next four prctl's remain to assist with transitioning a | 660 | * The next four prctl's remain to assist with transitioning a |
@@ -692,12 +676,12 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
692 | * capability-based-privilege environment. | 676 | * capability-based-privilege environment. |
693 | */ | 677 | */ |
694 | case PR_SET_SECUREBITS: | 678 | case PR_SET_SECUREBITS: |
695 | if ((((cred->securebits & SECURE_ALL_LOCKS) >> 1) | 679 | error = -EPERM; |
696 | & (cred->securebits ^ arg2)) /*[1]*/ | 680 | if ((((new->securebits & SECURE_ALL_LOCKS) >> 1) |
697 | || ((cred->securebits & SECURE_ALL_LOCKS | 681 | & (new->securebits ^ arg2)) /*[1]*/ |
698 | & ~arg2)) /*[2]*/ | 682 | || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ |
699 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ | 683 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ |
700 | || (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0)) { /*[4]*/ | 684 | || (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0) /*[4]*/ |
701 | /* | 685 | /* |
702 | * [1] no changing of bits that are locked | 686 | * [1] no changing of bits that are locked |
703 | * [2] no unlocking of locks | 687 | * [2] no unlocking of locks |
@@ -705,50 +689,51 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
705 | * [4] doing anything requires privilege (go read about | 689 | * [4] doing anything requires privilege (go read about |
706 | * the "sendmail capabilities bug") | 690 | * the "sendmail capabilities bug") |
707 | */ | 691 | */ |
708 | error = -EPERM; /* cannot change a locked bit */ | 692 | ) |
709 | } else { | 693 | /* cannot change a locked bit */ |
710 | cred->securebits = arg2; | 694 | goto error; |
711 | } | 695 | new->securebits = arg2; |
712 | break; | 696 | goto changed; |
697 | |||
713 | case PR_GET_SECUREBITS: | 698 | case PR_GET_SECUREBITS: |
714 | error = cred->securebits; | 699 | error = new->securebits; |
715 | break; | 700 | goto no_change; |
716 | 701 | ||
717 | #endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ | 702 | #endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ |
718 | 703 | ||
719 | case PR_GET_KEEPCAPS: | 704 | case PR_GET_KEEPCAPS: |
720 | if (issecure(SECURE_KEEP_CAPS)) | 705 | if (issecure(SECURE_KEEP_CAPS)) |
721 | error = 1; | 706 | error = 1; |
722 | break; | 707 | goto no_change; |
708 | |||
723 | case PR_SET_KEEPCAPS: | 709 | case PR_SET_KEEPCAPS: |
710 | error = -EINVAL; | ||
724 | if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */ | 711 | if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */ |
725 | error = -EINVAL; | 712 | goto error; |
726 | else if (issecure(SECURE_KEEP_CAPS_LOCKED)) | 713 | error = -EPERM; |
727 | error = -EPERM; | 714 | if (issecure(SECURE_KEEP_CAPS_LOCKED)) |
728 | else if (arg2) | 715 | goto error; |
729 | cred->securebits |= issecure_mask(SECURE_KEEP_CAPS); | 716 | if (arg2) |
717 | new->securebits |= issecure_mask(SECURE_KEEP_CAPS); | ||
730 | else | 718 | else |
731 | cred->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); | 719 | new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); |
732 | break; | 720 | goto changed; |
733 | 721 | ||
734 | default: | 722 | default: |
735 | /* No functionality available - continue with default */ | 723 | /* No functionality available - continue with default */ |
736 | return 0; | 724 | error = -ENOSYS; |
725 | goto error; | ||
737 | } | 726 | } |
738 | 727 | ||
739 | /* Functionality provided */ | 728 | /* Functionality provided */ |
740 | *rc_p = error; | 729 | changed: |
741 | return 1; | 730 | return commit_creds(new); |
742 | } | 731 | |
743 | 732 | no_change: | |
744 | void cap_task_reparent_to_init (struct task_struct *p) | 733 | error = 0; |
745 | { | 734 | error: |
746 | struct cred *cred = p->cred; | 735 | abort_creds(new); |
747 | 736 | return error; | |
748 | cap_set_init_eff(cred->cap_effective); | ||
749 | cap_clear(cred->cap_inheritable); | ||
750 | cap_set_full(cred->cap_permitted); | ||
751 | p->cred->securebits = SECUREBITS_DEFAULT; | ||
752 | } | 737 | } |
753 | 738 | ||
754 | int cap_syslog (int type) | 739 | int cap_syslog (int type) |
diff --git a/security/keys/internal.h b/security/keys/internal.h index d1586c629788..81932abefe7b 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #ifndef _INTERNAL_H | 12 | #ifndef _INTERNAL_H |
13 | #define _INTERNAL_H | 13 | #define _INTERNAL_H |
14 | 14 | ||
15 | #include <linux/sched.h> | ||
15 | #include <linux/key-type.h> | 16 | #include <linux/key-type.h> |
16 | 17 | ||
17 | static inline __attribute__((format(printf, 1, 2))) | 18 | static inline __attribute__((format(printf, 1, 2))) |
@@ -25,7 +26,7 @@ void no_printk(const char *fmt, ...) | |||
25 | #define kleave(FMT, ...) \ | 26 | #define kleave(FMT, ...) \ |
26 | printk(KERN_DEBUG "<== %s()"FMT"\n", __func__, ##__VA_ARGS__) | 27 | printk(KERN_DEBUG "<== %s()"FMT"\n", __func__, ##__VA_ARGS__) |
27 | #define kdebug(FMT, ...) \ | 28 | #define kdebug(FMT, ...) \ |
28 | printk(KERN_DEBUG "xxx" FMT"yyy\n", ##__VA_ARGS__) | 29 | printk(KERN_DEBUG " "FMT"\n", ##__VA_ARGS__) |
29 | #else | 30 | #else |
30 | #define kenter(FMT, ...) \ | 31 | #define kenter(FMT, ...) \ |
31 | no_printk(KERN_DEBUG "==> %s("FMT")\n", __func__, ##__VA_ARGS__) | 32 | no_printk(KERN_DEBUG "==> %s("FMT")\n", __func__, ##__VA_ARGS__) |
@@ -97,7 +98,7 @@ extern struct key *keyring_search_instkey(struct key *keyring, | |||
97 | typedef int (*key_match_func_t)(const struct key *, const void *); | 98 | typedef int (*key_match_func_t)(const struct key *, const void *); |
98 | 99 | ||
99 | extern key_ref_t keyring_search_aux(key_ref_t keyring_ref, | 100 | extern key_ref_t keyring_search_aux(key_ref_t keyring_ref, |
100 | struct task_struct *tsk, | 101 | const struct cred *cred, |
101 | struct key_type *type, | 102 | struct key_type *type, |
102 | const void *description, | 103 | const void *description, |
103 | key_match_func_t match); | 104 | key_match_func_t match); |
@@ -105,13 +106,13 @@ extern key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
105 | extern key_ref_t search_process_keyrings(struct key_type *type, | 106 | extern key_ref_t search_process_keyrings(struct key_type *type, |
106 | const void *description, | 107 | const void *description, |
107 | key_match_func_t match, | 108 | key_match_func_t match, |
108 | struct task_struct *tsk); | 109 | const struct cred *cred); |
109 | 110 | ||
110 | extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check); | 111 | extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check); |
111 | 112 | ||
112 | extern int install_user_keyrings(void); | 113 | extern int install_user_keyrings(void); |
113 | extern int install_thread_keyring(void); | 114 | extern int install_thread_keyring_to_cred(struct cred *); |
114 | extern int install_process_keyring(void); | 115 | extern int install_process_keyring_to_cred(struct cred *); |
115 | 116 | ||
116 | extern struct key *request_key_and_link(struct key_type *type, | 117 | extern struct key *request_key_and_link(struct key_type *type, |
117 | const char *description, | 118 | const char *description, |
@@ -130,12 +131,12 @@ extern long join_session_keyring(const char *name); | |||
130 | * check to see whether permission is granted to use a key in the desired way | 131 | * check to see whether permission is granted to use a key in the desired way |
131 | */ | 132 | */ |
132 | extern int key_task_permission(const key_ref_t key_ref, | 133 | extern int key_task_permission(const key_ref_t key_ref, |
133 | struct task_struct *context, | 134 | const struct cred *cred, |
134 | key_perm_t perm); | 135 | key_perm_t perm); |
135 | 136 | ||
136 | static inline int key_permission(const key_ref_t key_ref, key_perm_t perm) | 137 | static inline int key_permission(const key_ref_t key_ref, key_perm_t perm) |
137 | { | 138 | { |
138 | return key_task_permission(key_ref, current, perm); | 139 | return key_task_permission(key_ref, current_cred(), perm); |
139 | } | 140 | } |
140 | 141 | ||
141 | /* required permissions */ | 142 | /* required permissions */ |
@@ -153,7 +154,7 @@ static inline int key_permission(const key_ref_t key_ref, key_perm_t perm) | |||
153 | struct request_key_auth { | 154 | struct request_key_auth { |
154 | struct key *target_key; | 155 | struct key *target_key; |
155 | struct key *dest_keyring; | 156 | struct key *dest_keyring; |
156 | struct task_struct *context; | 157 | const struct cred *cred; |
157 | void *callout_info; | 158 | void *callout_info; |
158 | size_t callout_len; | 159 | size_t callout_len; |
159 | pid_t pid; | 160 | pid_t pid; |
diff --git a/security/keys/key.c b/security/keys/key.c index a6ca39ed3b0e..f76c8a546fd3 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -218,7 +218,7 @@ serial_exists: | |||
218 | * instantiate the key or discard it before returning | 218 | * instantiate the key or discard it before returning |
219 | */ | 219 | */ |
220 | struct key *key_alloc(struct key_type *type, const char *desc, | 220 | struct key *key_alloc(struct key_type *type, const char *desc, |
221 | uid_t uid, gid_t gid, struct task_struct *ctx, | 221 | uid_t uid, gid_t gid, const struct cred *cred, |
222 | key_perm_t perm, unsigned long flags) | 222 | key_perm_t perm, unsigned long flags) |
223 | { | 223 | { |
224 | struct key_user *user = NULL; | 224 | struct key_user *user = NULL; |
@@ -294,7 +294,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, | |||
294 | #endif | 294 | #endif |
295 | 295 | ||
296 | /* let the security module know about the key */ | 296 | /* let the security module know about the key */ |
297 | ret = security_key_alloc(key, ctx, flags); | 297 | ret = security_key_alloc(key, cred, flags); |
298 | if (ret < 0) | 298 | if (ret < 0) |
299 | goto security_error; | 299 | goto security_error; |
300 | 300 | ||
@@ -391,7 +391,7 @@ static int __key_instantiate_and_link(struct key *key, | |||
391 | const void *data, | 391 | const void *data, |
392 | size_t datalen, | 392 | size_t datalen, |
393 | struct key *keyring, | 393 | struct key *keyring, |
394 | struct key *instkey) | 394 | struct key *authkey) |
395 | { | 395 | { |
396 | int ret, awaken; | 396 | int ret, awaken; |
397 | 397 | ||
@@ -421,8 +421,8 @@ static int __key_instantiate_and_link(struct key *key, | |||
421 | ret = __key_link(keyring, key); | 421 | ret = __key_link(keyring, key); |
422 | 422 | ||
423 | /* disable the authorisation key */ | 423 | /* disable the authorisation key */ |
424 | if (instkey) | 424 | if (authkey) |
425 | key_revoke(instkey); | 425 | key_revoke(authkey); |
426 | } | 426 | } |
427 | } | 427 | } |
428 | 428 | ||
@@ -444,14 +444,14 @@ int key_instantiate_and_link(struct key *key, | |||
444 | const void *data, | 444 | const void *data, |
445 | size_t datalen, | 445 | size_t datalen, |
446 | struct key *keyring, | 446 | struct key *keyring, |
447 | struct key *instkey) | 447 | struct key *authkey) |
448 | { | 448 | { |
449 | int ret; | 449 | int ret; |
450 | 450 | ||
451 | if (keyring) | 451 | if (keyring) |
452 | down_write(&keyring->sem); | 452 | down_write(&keyring->sem); |
453 | 453 | ||
454 | ret = __key_instantiate_and_link(key, data, datalen, keyring, instkey); | 454 | ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey); |
455 | 455 | ||
456 | if (keyring) | 456 | if (keyring) |
457 | up_write(&keyring->sem); | 457 | up_write(&keyring->sem); |
@@ -469,7 +469,7 @@ EXPORT_SYMBOL(key_instantiate_and_link); | |||
469 | int key_negate_and_link(struct key *key, | 469 | int key_negate_and_link(struct key *key, |
470 | unsigned timeout, | 470 | unsigned timeout, |
471 | struct key *keyring, | 471 | struct key *keyring, |
472 | struct key *instkey) | 472 | struct key *authkey) |
473 | { | 473 | { |
474 | struct timespec now; | 474 | struct timespec now; |
475 | int ret, awaken; | 475 | int ret, awaken; |
@@ -504,8 +504,8 @@ int key_negate_and_link(struct key *key, | |||
504 | ret = __key_link(keyring, key); | 504 | ret = __key_link(keyring, key); |
505 | 505 | ||
506 | /* disable the authorisation key */ | 506 | /* disable the authorisation key */ |
507 | if (instkey) | 507 | if (authkey) |
508 | key_revoke(instkey); | 508 | key_revoke(authkey); |
509 | } | 509 | } |
510 | 510 | ||
511 | mutex_unlock(&key_construction_mutex); | 511 | mutex_unlock(&key_construction_mutex); |
@@ -743,6 +743,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
743 | key_perm_t perm, | 743 | key_perm_t perm, |
744 | unsigned long flags) | 744 | unsigned long flags) |
745 | { | 745 | { |
746 | const struct cred *cred = current_cred(); | ||
746 | struct key_type *ktype; | 747 | struct key_type *ktype; |
747 | struct key *keyring, *key = NULL; | 748 | struct key *keyring, *key = NULL; |
748 | key_ref_t key_ref; | 749 | key_ref_t key_ref; |
@@ -802,8 +803,8 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
802 | } | 803 | } |
803 | 804 | ||
804 | /* allocate a new key */ | 805 | /* allocate a new key */ |
805 | key = key_alloc(ktype, description, current_fsuid(), current_fsgid(), | 806 | key = key_alloc(ktype, description, cred->fsuid, cred->fsgid, cred, |
806 | current, perm, flags); | 807 | perm, flags); |
807 | if (IS_ERR(key)) { | 808 | if (IS_ERR(key)) { |
808 | key_ref = ERR_CAST(key); | 809 | key_ref = ERR_CAST(key); |
809 | goto error_3; | 810 | goto error_3; |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 8833b447adef..7c72baa02f2e 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -866,6 +866,23 @@ static long get_instantiation_keyring(key_serial_t ringid, | |||
866 | return -ENOKEY; | 866 | return -ENOKEY; |
867 | } | 867 | } |
868 | 868 | ||
869 | /* | ||
870 | * change the request_key authorisation key on the current process | ||
871 | */ | ||
872 | static int keyctl_change_reqkey_auth(struct key *key) | ||
873 | { | ||
874 | struct cred *new; | ||
875 | |||
876 | new = prepare_creds(); | ||
877 | if (!new) | ||
878 | return -ENOMEM; | ||
879 | |||
880 | key_put(new->request_key_auth); | ||
881 | new->request_key_auth = key_get(key); | ||
882 | |||
883 | return commit_creds(new); | ||
884 | } | ||
885 | |||
869 | /*****************************************************************************/ | 886 | /*****************************************************************************/ |
870 | /* | 887 | /* |
871 | * instantiate the key with the specified payload, and, if one is given, link | 888 | * instantiate the key with the specified payload, and, if one is given, link |
@@ -876,12 +893,15 @@ long keyctl_instantiate_key(key_serial_t id, | |||
876 | size_t plen, | 893 | size_t plen, |
877 | key_serial_t ringid) | 894 | key_serial_t ringid) |
878 | { | 895 | { |
896 | const struct cred *cred = current_cred(); | ||
879 | struct request_key_auth *rka; | 897 | struct request_key_auth *rka; |
880 | struct key *instkey, *dest_keyring; | 898 | struct key *instkey, *dest_keyring; |
881 | void *payload; | 899 | void *payload; |
882 | long ret; | 900 | long ret; |
883 | bool vm = false; | 901 | bool vm = false; |
884 | 902 | ||
903 | kenter("%d,,%zu,%d", id, plen, ringid); | ||
904 | |||
885 | ret = -EINVAL; | 905 | ret = -EINVAL; |
886 | if (plen > 1024 * 1024 - 1) | 906 | if (plen > 1024 * 1024 - 1) |
887 | goto error; | 907 | goto error; |
@@ -889,7 +909,7 @@ long keyctl_instantiate_key(key_serial_t id, | |||
889 | /* the appropriate instantiation authorisation key must have been | 909 | /* the appropriate instantiation authorisation key must have been |
890 | * assumed before calling this */ | 910 | * assumed before calling this */ |
891 | ret = -EPERM; | 911 | ret = -EPERM; |
892 | instkey = current->cred->request_key_auth; | 912 | instkey = cred->request_key_auth; |
893 | if (!instkey) | 913 | if (!instkey) |
894 | goto error; | 914 | goto error; |
895 | 915 | ||
@@ -931,10 +951,8 @@ long keyctl_instantiate_key(key_serial_t id, | |||
931 | 951 | ||
932 | /* discard the assumed authority if it's just been disabled by | 952 | /* discard the assumed authority if it's just been disabled by |
933 | * instantiation of the key */ | 953 | * instantiation of the key */ |
934 | if (ret == 0) { | 954 | if (ret == 0) |
935 | key_put(current->cred->request_key_auth); | 955 | keyctl_change_reqkey_auth(NULL); |
936 | current->cred->request_key_auth = NULL; | ||
937 | } | ||
938 | 956 | ||
939 | error2: | 957 | error2: |
940 | if (!vm) | 958 | if (!vm) |
@@ -953,14 +971,17 @@ error: | |||
953 | */ | 971 | */ |
954 | long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) | 972 | long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) |
955 | { | 973 | { |
974 | const struct cred *cred = current_cred(); | ||
956 | struct request_key_auth *rka; | 975 | struct request_key_auth *rka; |
957 | struct key *instkey, *dest_keyring; | 976 | struct key *instkey, *dest_keyring; |
958 | long ret; | 977 | long ret; |
959 | 978 | ||
979 | kenter("%d,%u,%d", id, timeout, ringid); | ||
980 | |||
960 | /* the appropriate instantiation authorisation key must have been | 981 | /* the appropriate instantiation authorisation key must have been |
961 | * assumed before calling this */ | 982 | * assumed before calling this */ |
962 | ret = -EPERM; | 983 | ret = -EPERM; |
963 | instkey = current->cred->request_key_auth; | 984 | instkey = cred->request_key_auth; |
964 | if (!instkey) | 985 | if (!instkey) |
965 | goto error; | 986 | goto error; |
966 | 987 | ||
@@ -982,10 +1003,8 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) | |||
982 | 1003 | ||
983 | /* discard the assumed authority if it's just been disabled by | 1004 | /* discard the assumed authority if it's just been disabled by |
984 | * instantiation of the key */ | 1005 | * instantiation of the key */ |
985 | if (ret == 0) { | 1006 | if (ret == 0) |
986 | key_put(current->cred->request_key_auth); | 1007 | keyctl_change_reqkey_auth(NULL); |
987 | current->cred->request_key_auth = NULL; | ||
988 | } | ||
989 | 1008 | ||
990 | error: | 1009 | error: |
991 | return ret; | 1010 | return ret; |
@@ -999,36 +1018,56 @@ error: | |||
999 | */ | 1018 | */ |
1000 | long keyctl_set_reqkey_keyring(int reqkey_defl) | 1019 | long keyctl_set_reqkey_keyring(int reqkey_defl) |
1001 | { | 1020 | { |
1002 | struct cred *cred = current->cred; | 1021 | struct cred *new; |
1003 | int ret; | 1022 | int ret, old_setting; |
1023 | |||
1024 | old_setting = current_cred_xxx(jit_keyring); | ||
1025 | |||
1026 | if (reqkey_defl == KEY_REQKEY_DEFL_NO_CHANGE) | ||
1027 | return old_setting; | ||
1028 | |||
1029 | new = prepare_creds(); | ||
1030 | if (!new) | ||
1031 | return -ENOMEM; | ||
1004 | 1032 | ||
1005 | switch (reqkey_defl) { | 1033 | switch (reqkey_defl) { |
1006 | case KEY_REQKEY_DEFL_THREAD_KEYRING: | 1034 | case KEY_REQKEY_DEFL_THREAD_KEYRING: |
1007 | ret = install_thread_keyring(); | 1035 | ret = install_thread_keyring_to_cred(new); |
1008 | if (ret < 0) | 1036 | if (ret < 0) |
1009 | return ret; | 1037 | goto error; |
1010 | goto set; | 1038 | goto set; |
1011 | 1039 | ||
1012 | case KEY_REQKEY_DEFL_PROCESS_KEYRING: | 1040 | case KEY_REQKEY_DEFL_PROCESS_KEYRING: |
1013 | ret = install_process_keyring(); | 1041 | ret = install_process_keyring_to_cred(new); |
1014 | if (ret < 0) | 1042 | if (ret < 0) { |
1015 | return ret; | 1043 | if (ret != -EEXIST) |
1044 | goto error; | ||
1045 | ret = 0; | ||
1046 | } | ||
1047 | goto set; | ||
1016 | 1048 | ||
1017 | case KEY_REQKEY_DEFL_DEFAULT: | 1049 | case KEY_REQKEY_DEFL_DEFAULT: |
1018 | case KEY_REQKEY_DEFL_SESSION_KEYRING: | 1050 | case KEY_REQKEY_DEFL_SESSION_KEYRING: |
1019 | case KEY_REQKEY_DEFL_USER_KEYRING: | 1051 | case KEY_REQKEY_DEFL_USER_KEYRING: |
1020 | case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: | 1052 | case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: |
1021 | set: | 1053 | case KEY_REQKEY_DEFL_REQUESTOR_KEYRING: |
1022 | cred->jit_keyring = reqkey_defl; | 1054 | goto set; |
1023 | 1055 | ||
1024 | case KEY_REQKEY_DEFL_NO_CHANGE: | 1056 | case KEY_REQKEY_DEFL_NO_CHANGE: |
1025 | return cred->jit_keyring; | ||
1026 | |||
1027 | case KEY_REQKEY_DEFL_GROUP_KEYRING: | 1057 | case KEY_REQKEY_DEFL_GROUP_KEYRING: |
1028 | default: | 1058 | default: |
1029 | return -EINVAL; | 1059 | ret = -EINVAL; |
1060 | goto error; | ||
1030 | } | 1061 | } |
1031 | 1062 | ||
1063 | set: | ||
1064 | new->jit_keyring = reqkey_defl; | ||
1065 | commit_creds(new); | ||
1066 | return old_setting; | ||
1067 | error: | ||
1068 | abort_creds(new); | ||
1069 | return -EINVAL; | ||
1070 | |||
1032 | } /* end keyctl_set_reqkey_keyring() */ | 1071 | } /* end keyctl_set_reqkey_keyring() */ |
1033 | 1072 | ||
1034 | /*****************************************************************************/ | 1073 | /*****************************************************************************/ |
@@ -1087,9 +1126,7 @@ long keyctl_assume_authority(key_serial_t id) | |||
1087 | 1126 | ||
1088 | /* we divest ourselves of authority if given an ID of 0 */ | 1127 | /* we divest ourselves of authority if given an ID of 0 */ |
1089 | if (id == 0) { | 1128 | if (id == 0) { |
1090 | key_put(current->cred->request_key_auth); | 1129 | ret = keyctl_change_reqkey_auth(NULL); |
1091 | current->cred->request_key_auth = NULL; | ||
1092 | ret = 0; | ||
1093 | goto error; | 1130 | goto error; |
1094 | } | 1131 | } |
1095 | 1132 | ||
@@ -1104,10 +1141,12 @@ long keyctl_assume_authority(key_serial_t id) | |||
1104 | goto error; | 1141 | goto error; |
1105 | } | 1142 | } |
1106 | 1143 | ||
1107 | key_put(current->cred->request_key_auth); | 1144 | ret = keyctl_change_reqkey_auth(authkey); |
1108 | current->cred->request_key_auth = authkey; | 1145 | if (ret < 0) |
1109 | ret = authkey->serial; | 1146 | goto error; |
1147 | key_put(authkey); | ||
1110 | 1148 | ||
1149 | ret = authkey->serial; | ||
1111 | error: | 1150 | error: |
1112 | return ret; | 1151 | return ret; |
1113 | 1152 | ||
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index fdf75f901991..ed851574d073 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -245,14 +245,14 @@ static long keyring_read(const struct key *keyring, | |||
245 | * allocate a keyring and link into the destination keyring | 245 | * allocate a keyring and link into the destination keyring |
246 | */ | 246 | */ |
247 | struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, | 247 | struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, |
248 | struct task_struct *ctx, unsigned long flags, | 248 | const struct cred *cred, unsigned long flags, |
249 | struct key *dest) | 249 | struct key *dest) |
250 | { | 250 | { |
251 | struct key *keyring; | 251 | struct key *keyring; |
252 | int ret; | 252 | int ret; |
253 | 253 | ||
254 | keyring = key_alloc(&key_type_keyring, description, | 254 | keyring = key_alloc(&key_type_keyring, description, |
255 | uid, gid, ctx, | 255 | uid, gid, cred, |
256 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, | 256 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, |
257 | flags); | 257 | flags); |
258 | 258 | ||
@@ -281,7 +281,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, | |||
281 | * - we propagate the possession attribute from the keyring ref to the key ref | 281 | * - we propagate the possession attribute from the keyring ref to the key ref |
282 | */ | 282 | */ |
283 | key_ref_t keyring_search_aux(key_ref_t keyring_ref, | 283 | key_ref_t keyring_search_aux(key_ref_t keyring_ref, |
284 | struct task_struct *context, | 284 | const struct cred *cred, |
285 | struct key_type *type, | 285 | struct key_type *type, |
286 | const void *description, | 286 | const void *description, |
287 | key_match_func_t match) | 287 | key_match_func_t match) |
@@ -304,7 +304,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
304 | key_check(keyring); | 304 | key_check(keyring); |
305 | 305 | ||
306 | /* top keyring must have search permission to begin the search */ | 306 | /* top keyring must have search permission to begin the search */ |
307 | err = key_task_permission(keyring_ref, context, KEY_SEARCH); | 307 | err = key_task_permission(keyring_ref, cred, KEY_SEARCH); |
308 | if (err < 0) { | 308 | if (err < 0) { |
309 | key_ref = ERR_PTR(err); | 309 | key_ref = ERR_PTR(err); |
310 | goto error; | 310 | goto error; |
@@ -377,7 +377,7 @@ descend: | |||
377 | 377 | ||
378 | /* key must have search permissions */ | 378 | /* key must have search permissions */ |
379 | if (key_task_permission(make_key_ref(key, possessed), | 379 | if (key_task_permission(make_key_ref(key, possessed), |
380 | context, KEY_SEARCH) < 0) | 380 | cred, KEY_SEARCH) < 0) |
381 | continue; | 381 | continue; |
382 | 382 | ||
383 | /* we set a different error code if we pass a negative key */ | 383 | /* we set a different error code if we pass a negative key */ |
@@ -404,7 +404,7 @@ ascend: | |||
404 | continue; | 404 | continue; |
405 | 405 | ||
406 | if (key_task_permission(make_key_ref(key, possessed), | 406 | if (key_task_permission(make_key_ref(key, possessed), |
407 | context, KEY_SEARCH) < 0) | 407 | cred, KEY_SEARCH) < 0) |
408 | continue; | 408 | continue; |
409 | 409 | ||
410 | /* stack the current position */ | 410 | /* stack the current position */ |
@@ -459,7 +459,7 @@ key_ref_t keyring_search(key_ref_t keyring, | |||
459 | if (!type->match) | 459 | if (!type->match) |
460 | return ERR_PTR(-ENOKEY); | 460 | return ERR_PTR(-ENOKEY); |
461 | 461 | ||
462 | return keyring_search_aux(keyring, current, | 462 | return keyring_search_aux(keyring, current->cred, |
463 | type, description, type->match); | 463 | type, description, type->match); |
464 | 464 | ||
465 | } /* end keyring_search() */ | 465 | } /* end keyring_search() */ |
diff --git a/security/keys/permission.c b/security/keys/permission.c index 13c36164f284..5d9fc7b93f2e 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c | |||
@@ -14,24 +14,27 @@ | |||
14 | #include "internal.h" | 14 | #include "internal.h" |
15 | 15 | ||
16 | /*****************************************************************************/ | 16 | /*****************************************************************************/ |
17 | /* | 17 | /** |
18 | * check to see whether permission is granted to use a key in the desired way, | 18 | * key_task_permission - Check a key can be used |
19 | * but permit the security modules to override | 19 | * @key_ref: The key to check |
20 | * @cred: The credentials to use | ||
21 | * @perm: The permissions to check for | ||
22 | * | ||
23 | * Check to see whether permission is granted to use a key in the desired way, | ||
24 | * but permit the security modules to override. | ||
25 | * | ||
26 | * The caller must hold either a ref on cred or must hold the RCU readlock or a | ||
27 | * spinlock. | ||
20 | */ | 28 | */ |
21 | int key_task_permission(const key_ref_t key_ref, | 29 | int key_task_permission(const key_ref_t key_ref, const struct cred *cred, |
22 | struct task_struct *context, | ||
23 | key_perm_t perm) | 30 | key_perm_t perm) |
24 | { | 31 | { |
25 | const struct cred *cred; | ||
26 | struct key *key; | 32 | struct key *key; |
27 | key_perm_t kperm; | 33 | key_perm_t kperm; |
28 | int ret; | 34 | int ret; |
29 | 35 | ||
30 | key = key_ref_to_ptr(key_ref); | 36 | key = key_ref_to_ptr(key_ref); |
31 | 37 | ||
32 | rcu_read_lock(); | ||
33 | cred = __task_cred(context); | ||
34 | |||
35 | /* use the second 8-bits of permissions for keys the caller owns */ | 38 | /* use the second 8-bits of permissions for keys the caller owns */ |
36 | if (key->uid == cred->fsuid) { | 39 | if (key->uid == cred->fsuid) { |
37 | kperm = key->perm >> 16; | 40 | kperm = key->perm >> 16; |
@@ -57,7 +60,6 @@ int key_task_permission(const key_ref_t key_ref, | |||
57 | kperm = key->perm; | 60 | kperm = key->perm; |
58 | 61 | ||
59 | use_these_perms: | 62 | use_these_perms: |
60 | rcu_read_lock(); | ||
61 | 63 | ||
62 | /* use the top 8-bits of permissions for keys the caller possesses | 64 | /* use the top 8-bits of permissions for keys the caller possesses |
63 | * - possessor permissions are additive with other permissions | 65 | * - possessor permissions are additive with other permissions |
@@ -71,7 +73,7 @@ use_these_perms: | |||
71 | return -EACCES; | 73 | return -EACCES; |
72 | 74 | ||
73 | /* let LSM be the final arbiter */ | 75 | /* let LSM be the final arbiter */ |
74 | return security_key_permission(key_ref, context, perm); | 76 | return security_key_permission(key_ref, cred, perm); |
75 | 77 | ||
76 | } /* end key_task_permission() */ | 78 | } /* end key_task_permission() */ |
77 | 79 | ||
diff --git a/security/keys/proc.c b/security/keys/proc.c index f619170da760..7f508def50e3 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c | |||
@@ -136,8 +136,12 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
136 | int rc; | 136 | int rc; |
137 | 137 | ||
138 | /* check whether the current task is allowed to view the key (assuming | 138 | /* check whether the current task is allowed to view the key (assuming |
139 | * non-possession) */ | 139 | * non-possession) |
140 | rc = key_task_permission(make_key_ref(key, 0), current, KEY_VIEW); | 140 | * - the caller holds a spinlock, and thus the RCU read lock, making our |
141 | * access to __current_cred() safe | ||
142 | */ | ||
143 | rc = key_task_permission(make_key_ref(key, 0), current_cred(), | ||
144 | KEY_VIEW); | ||
141 | if (rc < 0) | 145 | if (rc < 0) |
142 | return 0; | 146 | return 0; |
143 | 147 | ||
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 70ee93406f30..df329f684a65 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -42,11 +42,15 @@ struct key_user root_key_user = { | |||
42 | */ | 42 | */ |
43 | int install_user_keyrings(void) | 43 | int install_user_keyrings(void) |
44 | { | 44 | { |
45 | struct user_struct *user = current->cred->user; | 45 | struct user_struct *user; |
46 | const struct cred *cred; | ||
46 | struct key *uid_keyring, *session_keyring; | 47 | struct key *uid_keyring, *session_keyring; |
47 | char buf[20]; | 48 | char buf[20]; |
48 | int ret; | 49 | int ret; |
49 | 50 | ||
51 | cred = current_cred(); | ||
52 | user = cred->user; | ||
53 | |||
50 | kenter("%p{%u}", user, user->uid); | 54 | kenter("%p{%u}", user, user->uid); |
51 | 55 | ||
52 | if (user->uid_keyring) { | 56 | if (user->uid_keyring) { |
@@ -67,7 +71,7 @@ int install_user_keyrings(void) | |||
67 | uid_keyring = find_keyring_by_name(buf, true); | 71 | uid_keyring = find_keyring_by_name(buf, true); |
68 | if (IS_ERR(uid_keyring)) { | 72 | if (IS_ERR(uid_keyring)) { |
69 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, | 73 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, |
70 | current, KEY_ALLOC_IN_QUOTA, | 74 | cred, KEY_ALLOC_IN_QUOTA, |
71 | NULL); | 75 | NULL); |
72 | if (IS_ERR(uid_keyring)) { | 76 | if (IS_ERR(uid_keyring)) { |
73 | ret = PTR_ERR(uid_keyring); | 77 | ret = PTR_ERR(uid_keyring); |
@@ -83,8 +87,7 @@ int install_user_keyrings(void) | |||
83 | if (IS_ERR(session_keyring)) { | 87 | if (IS_ERR(session_keyring)) { |
84 | session_keyring = | 88 | session_keyring = |
85 | keyring_alloc(buf, user->uid, (gid_t) -1, | 89 | keyring_alloc(buf, user->uid, (gid_t) -1, |
86 | current, KEY_ALLOC_IN_QUOTA, | 90 | cred, KEY_ALLOC_IN_QUOTA, NULL); |
87 | NULL); | ||
88 | if (IS_ERR(session_keyring)) { | 91 | if (IS_ERR(session_keyring)) { |
89 | ret = PTR_ERR(session_keyring); | 92 | ret = PTR_ERR(session_keyring); |
90 | goto error_release; | 93 | goto error_release; |
@@ -116,142 +119,128 @@ error: | |||
116 | return ret; | 119 | return ret; |
117 | } | 120 | } |
118 | 121 | ||
119 | /*****************************************************************************/ | ||
120 | /* | 122 | /* |
121 | * deal with the UID changing | 123 | * install a fresh thread keyring directly to new credentials |
122 | */ | 124 | */ |
123 | void switch_uid_keyring(struct user_struct *new_user) | 125 | int install_thread_keyring_to_cred(struct cred *new) |
124 | { | 126 | { |
125 | #if 0 /* do nothing for now */ | 127 | struct key *keyring; |
126 | struct key *old; | ||
127 | |||
128 | /* switch to the new user's session keyring if we were running under | ||
129 | * root's default session keyring */ | ||
130 | if (new_user->uid != 0 && | ||
131 | current->session_keyring == &root_session_keyring | ||
132 | ) { | ||
133 | atomic_inc(&new_user->session_keyring->usage); | ||
134 | |||
135 | task_lock(current); | ||
136 | old = current->session_keyring; | ||
137 | current->session_keyring = new_user->session_keyring; | ||
138 | task_unlock(current); | ||
139 | 128 | ||
140 | key_put(old); | 129 | keyring = keyring_alloc("_tid", new->uid, new->gid, new, |
141 | } | 130 | KEY_ALLOC_QUOTA_OVERRUN, NULL); |
142 | #endif | 131 | if (IS_ERR(keyring)) |
132 | return PTR_ERR(keyring); | ||
143 | 133 | ||
144 | } /* end switch_uid_keyring() */ | 134 | new->thread_keyring = keyring; |
135 | return 0; | ||
136 | } | ||
145 | 137 | ||
146 | /*****************************************************************************/ | ||
147 | /* | 138 | /* |
148 | * install a fresh thread keyring, discarding the old one | 139 | * install a fresh thread keyring, discarding the old one |
149 | */ | 140 | */ |
150 | int install_thread_keyring(void) | 141 | static int install_thread_keyring(void) |
151 | { | 142 | { |
152 | struct task_struct *tsk = current; | 143 | struct cred *new; |
153 | struct key *keyring, *old; | ||
154 | char buf[20]; | ||
155 | int ret; | 144 | int ret; |
156 | 145 | ||
157 | sprintf(buf, "_tid.%u", tsk->pid); | 146 | new = prepare_creds(); |
147 | if (!new) | ||
148 | return -ENOMEM; | ||
158 | 149 | ||
159 | keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk, | 150 | BUG_ON(new->thread_keyring); |
160 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | 151 | |
161 | if (IS_ERR(keyring)) { | 152 | ret = install_thread_keyring_to_cred(new); |
162 | ret = PTR_ERR(keyring); | 153 | if (ret < 0) { |
163 | goto error; | 154 | abort_creds(new); |
155 | return ret; | ||
164 | } | 156 | } |
165 | 157 | ||
166 | task_lock(tsk); | 158 | return commit_creds(new); |
167 | old = tsk->cred->thread_keyring; | 159 | } |
168 | tsk->cred->thread_keyring = keyring; | ||
169 | task_unlock(tsk); | ||
170 | 160 | ||
171 | ret = 0; | 161 | /* |
162 | * install a process keyring directly to a credentials struct | ||
163 | * - returns -EEXIST if there was already a process keyring, 0 if one installed, | ||
164 | * and other -ve on any other error | ||
165 | */ | ||
166 | int install_process_keyring_to_cred(struct cred *new) | ||
167 | { | ||
168 | struct key *keyring; | ||
169 | int ret; | ||
172 | 170 | ||
173 | key_put(old); | 171 | if (new->tgcred->process_keyring) |
174 | error: | 172 | return -EEXIST; |
173 | |||
174 | keyring = keyring_alloc("_pid", new->uid, new->gid, | ||
175 | new, KEY_ALLOC_QUOTA_OVERRUN, NULL); | ||
176 | if (IS_ERR(keyring)) | ||
177 | return PTR_ERR(keyring); | ||
178 | |||
179 | spin_lock_irq(&new->tgcred->lock); | ||
180 | if (!new->tgcred->process_keyring) { | ||
181 | new->tgcred->process_keyring = keyring; | ||
182 | keyring = NULL; | ||
183 | ret = 0; | ||
184 | } else { | ||
185 | ret = -EEXIST; | ||
186 | } | ||
187 | spin_unlock_irq(&new->tgcred->lock); | ||
188 | key_put(keyring); | ||
175 | return ret; | 189 | return ret; |
190 | } | ||
176 | 191 | ||
177 | } /* end install_thread_keyring() */ | ||
178 | |||
179 | /*****************************************************************************/ | ||
180 | /* | 192 | /* |
181 | * make sure a process keyring is installed | 193 | * make sure a process keyring is installed |
194 | * - we | ||
182 | */ | 195 | */ |
183 | int install_process_keyring(void) | 196 | static int install_process_keyring(void) |
184 | { | 197 | { |
185 | struct task_struct *tsk = current; | 198 | struct cred *new; |
186 | struct key *keyring; | ||
187 | char buf[20]; | ||
188 | int ret; | 199 | int ret; |
189 | 200 | ||
190 | might_sleep(); | 201 | new = prepare_creds(); |
191 | 202 | if (!new) | |
192 | if (!tsk->cred->tgcred->process_keyring) { | 203 | return -ENOMEM; |
193 | sprintf(buf, "_pid.%u", tsk->tgid); | ||
194 | |||
195 | keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk, | ||
196 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | ||
197 | if (IS_ERR(keyring)) { | ||
198 | ret = PTR_ERR(keyring); | ||
199 | goto error; | ||
200 | } | ||
201 | |||
202 | /* attach keyring */ | ||
203 | spin_lock_irq(&tsk->cred->tgcred->lock); | ||
204 | if (!tsk->cred->tgcred->process_keyring) { | ||
205 | tsk->cred->tgcred->process_keyring = keyring; | ||
206 | keyring = NULL; | ||
207 | } | ||
208 | spin_unlock_irq(&tsk->cred->tgcred->lock); | ||
209 | 204 | ||
210 | key_put(keyring); | 205 | ret = install_process_keyring_to_cred(new); |
206 | if (ret < 0) { | ||
207 | abort_creds(new); | ||
208 | return ret != -EEXIST ?: 0; | ||
211 | } | 209 | } |
212 | 210 | ||
213 | ret = 0; | 211 | return commit_creds(new); |
214 | error: | 212 | } |
215 | return ret; | ||
216 | |||
217 | } /* end install_process_keyring() */ | ||
218 | 213 | ||
219 | /*****************************************************************************/ | ||
220 | /* | 214 | /* |
221 | * install a session keyring, discarding the old one | 215 | * install a session keyring directly to a credentials struct |
222 | * - if a keyring is not supplied, an empty one is invented | ||
223 | */ | 216 | */ |
224 | static int install_session_keyring(struct key *keyring) | 217 | static int install_session_keyring_to_cred(struct cred *cred, |
218 | struct key *keyring) | ||
225 | { | 219 | { |
226 | struct task_struct *tsk = current; | ||
227 | unsigned long flags; | 220 | unsigned long flags; |
228 | struct key *old; | 221 | struct key *old; |
229 | char buf[20]; | ||
230 | 222 | ||
231 | might_sleep(); | 223 | might_sleep(); |
232 | 224 | ||
233 | /* create an empty session keyring */ | 225 | /* create an empty session keyring */ |
234 | if (!keyring) { | 226 | if (!keyring) { |
235 | sprintf(buf, "_ses.%u", tsk->tgid); | ||
236 | |||
237 | flags = KEY_ALLOC_QUOTA_OVERRUN; | 227 | flags = KEY_ALLOC_QUOTA_OVERRUN; |
238 | if (tsk->cred->tgcred->session_keyring) | 228 | if (cred->tgcred->session_keyring) |
239 | flags = KEY_ALLOC_IN_QUOTA; | 229 | flags = KEY_ALLOC_IN_QUOTA; |
240 | 230 | ||
241 | keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, | 231 | keyring = keyring_alloc("_ses", cred->uid, cred->gid, |
242 | tsk, flags, NULL); | 232 | cred, flags, NULL); |
243 | if (IS_ERR(keyring)) | 233 | if (IS_ERR(keyring)) |
244 | return PTR_ERR(keyring); | 234 | return PTR_ERR(keyring); |
245 | } | 235 | } else { |
246 | else { | ||
247 | atomic_inc(&keyring->usage); | 236 | atomic_inc(&keyring->usage); |
248 | } | 237 | } |
249 | 238 | ||
250 | /* install the keyring */ | 239 | /* install the keyring */ |
251 | spin_lock_irq(&tsk->cred->tgcred->lock); | 240 | spin_lock_irq(&cred->tgcred->lock); |
252 | old = tsk->cred->tgcred->session_keyring; | 241 | old = cred->tgcred->session_keyring; |
253 | rcu_assign_pointer(tsk->cred->tgcred->session_keyring, keyring); | 242 | rcu_assign_pointer(cred->tgcred->session_keyring, keyring); |
254 | spin_unlock_irq(&tsk->cred->tgcred->lock); | 243 | spin_unlock_irq(&cred->tgcred->lock); |
255 | 244 | ||
256 | /* we're using RCU on the pointer, but there's no point synchronising | 245 | /* we're using RCU on the pointer, but there's no point synchronising |
257 | * on it if it didn't previously point to anything */ | 246 | * on it if it didn't previously point to anything */ |
@@ -261,38 +250,29 @@ static int install_session_keyring(struct key *keyring) | |||
261 | } | 250 | } |
262 | 251 | ||
263 | return 0; | 252 | return 0; |
253 | } | ||
264 | 254 | ||
265 | } /* end install_session_keyring() */ | ||
266 | |||
267 | /*****************************************************************************/ | ||
268 | /* | 255 | /* |
269 | * copy the keys for fork | 256 | * install a session keyring, discarding the old one |
257 | * - if a keyring is not supplied, an empty one is invented | ||
270 | */ | 258 | */ |
271 | int copy_keys(unsigned long clone_flags, struct task_struct *tsk) | 259 | static int install_session_keyring(struct key *keyring) |
272 | { | 260 | { |
273 | key_check(tsk->cred->thread_keyring); | 261 | struct cred *new; |
274 | key_check(tsk->cred->request_key_auth); | 262 | int ret; |
275 | |||
276 | /* no thread keyring yet */ | ||
277 | tsk->cred->thread_keyring = NULL; | ||
278 | |||
279 | /* copy the request_key() authorisation for this thread */ | ||
280 | key_get(tsk->cred->request_key_auth); | ||
281 | |||
282 | return 0; | ||
283 | 263 | ||
284 | } /* end copy_keys() */ | 264 | new = prepare_creds(); |
265 | if (!new) | ||
266 | return -ENOMEM; | ||
285 | 267 | ||
286 | /*****************************************************************************/ | 268 | ret = install_session_keyring_to_cred(new, NULL); |
287 | /* | 269 | if (ret < 0) { |
288 | * dispose of per-thread keys upon thread exit | 270 | abort_creds(new); |
289 | */ | 271 | return ret; |
290 | void exit_keys(struct task_struct *tsk) | 272 | } |
291 | { | ||
292 | key_put(tsk->cred->thread_keyring); | ||
293 | key_put(tsk->cred->request_key_auth); | ||
294 | 273 | ||
295 | } /* end exit_keys() */ | 274 | return commit_creds(new); |
275 | } | ||
296 | 276 | ||
297 | /*****************************************************************************/ | 277 | /*****************************************************************************/ |
298 | /* | 278 | /* |
@@ -300,38 +280,41 @@ void exit_keys(struct task_struct *tsk) | |||
300 | */ | 280 | */ |
301 | int exec_keys(struct task_struct *tsk) | 281 | int exec_keys(struct task_struct *tsk) |
302 | { | 282 | { |
303 | struct key *old; | 283 | struct thread_group_cred *tgcred = NULL; |
284 | struct cred *new; | ||
304 | 285 | ||
305 | /* newly exec'd tasks don't get a thread keyring */ | 286 | #ifdef CONFIG_KEYS |
306 | task_lock(tsk); | 287 | tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL); |
307 | old = tsk->cred->thread_keyring; | 288 | if (!tgcred) |
308 | tsk->cred->thread_keyring = NULL; | 289 | return -ENOMEM; |
309 | task_unlock(tsk); | 290 | #endif |
310 | 291 | ||
311 | key_put(old); | 292 | new = prepare_creds(); |
293 | if (new < 0) | ||
294 | return -ENOMEM; | ||
312 | 295 | ||
313 | /* discard the process keyring from a newly exec'd task */ | 296 | /* newly exec'd tasks don't get a thread keyring */ |
314 | spin_lock_irq(&tsk->cred->tgcred->lock); | 297 | key_put(new->thread_keyring); |
315 | old = tsk->cred->tgcred->process_keyring; | 298 | new->thread_keyring = NULL; |
316 | tsk->cred->tgcred->process_keyring = NULL; | ||
317 | spin_unlock_irq(&tsk->cred->tgcred->lock); | ||
318 | 299 | ||
319 | key_put(old); | 300 | /* create a new per-thread-group creds for all this set of threads to |
301 | * share */ | ||
302 | memcpy(tgcred, new->tgcred, sizeof(struct thread_group_cred)); | ||
320 | 303 | ||
321 | return 0; | 304 | atomic_set(&tgcred->usage, 1); |
305 | spin_lock_init(&tgcred->lock); | ||
322 | 306 | ||
323 | } /* end exec_keys() */ | 307 | /* inherit the session keyring; new process keyring */ |
308 | key_get(tgcred->session_keyring); | ||
309 | tgcred->process_keyring = NULL; | ||
324 | 310 | ||
325 | /*****************************************************************************/ | 311 | release_tgcred(new); |
326 | /* | 312 | new->tgcred = tgcred; |
327 | * deal with SUID programs | 313 | |
328 | * - we might want to make this invent a new session keyring | 314 | commit_creds(new); |
329 | */ | ||
330 | int suid_keys(struct task_struct *tsk) | ||
331 | { | ||
332 | return 0; | 315 | return 0; |
333 | 316 | ||
334 | } /* end suid_keys() */ | 317 | } /* end exec_keys() */ |
335 | 318 | ||
336 | /*****************************************************************************/ | 319 | /*****************************************************************************/ |
337 | /* | 320 | /* |
@@ -376,16 +359,13 @@ void key_fsgid_changed(struct task_struct *tsk) | |||
376 | key_ref_t search_process_keyrings(struct key_type *type, | 359 | key_ref_t search_process_keyrings(struct key_type *type, |
377 | const void *description, | 360 | const void *description, |
378 | key_match_func_t match, | 361 | key_match_func_t match, |
379 | struct task_struct *context) | 362 | const struct cred *cred) |
380 | { | 363 | { |
381 | struct request_key_auth *rka; | 364 | struct request_key_auth *rka; |
382 | struct cred *cred; | ||
383 | key_ref_t key_ref, ret, err; | 365 | key_ref_t key_ref, ret, err; |
384 | 366 | ||
385 | might_sleep(); | 367 | might_sleep(); |
386 | 368 | ||
387 | cred = get_task_cred(context); | ||
388 | |||
389 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were | 369 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were |
390 | * searchable, but we failed to find a key or we found a negative key; | 370 | * searchable, but we failed to find a key or we found a negative key; |
391 | * otherwise we want to return a sample error (probably -EACCES) if | 371 | * otherwise we want to return a sample error (probably -EACCES) if |
@@ -401,7 +381,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
401 | if (cred->thread_keyring) { | 381 | if (cred->thread_keyring) { |
402 | key_ref = keyring_search_aux( | 382 | key_ref = keyring_search_aux( |
403 | make_key_ref(cred->thread_keyring, 1), | 383 | make_key_ref(cred->thread_keyring, 1), |
404 | context, type, description, match); | 384 | cred, type, description, match); |
405 | if (!IS_ERR(key_ref)) | 385 | if (!IS_ERR(key_ref)) |
406 | goto found; | 386 | goto found; |
407 | 387 | ||
@@ -422,7 +402,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
422 | if (cred->tgcred->process_keyring) { | 402 | if (cred->tgcred->process_keyring) { |
423 | key_ref = keyring_search_aux( | 403 | key_ref = keyring_search_aux( |
424 | make_key_ref(cred->tgcred->process_keyring, 1), | 404 | make_key_ref(cred->tgcred->process_keyring, 1), |
425 | context, type, description, match); | 405 | cred, type, description, match); |
426 | if (!IS_ERR(key_ref)) | 406 | if (!IS_ERR(key_ref)) |
427 | goto found; | 407 | goto found; |
428 | 408 | ||
@@ -446,7 +426,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
446 | make_key_ref(rcu_dereference( | 426 | make_key_ref(rcu_dereference( |
447 | cred->tgcred->session_keyring), | 427 | cred->tgcred->session_keyring), |
448 | 1), | 428 | 1), |
449 | context, type, description, match); | 429 | cred, type, description, match); |
450 | rcu_read_unlock(); | 430 | rcu_read_unlock(); |
451 | 431 | ||
452 | if (!IS_ERR(key_ref)) | 432 | if (!IS_ERR(key_ref)) |
@@ -468,7 +448,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
468 | else if (cred->user->session_keyring) { | 448 | else if (cred->user->session_keyring) { |
469 | key_ref = keyring_search_aux( | 449 | key_ref = keyring_search_aux( |
470 | make_key_ref(cred->user->session_keyring, 1), | 450 | make_key_ref(cred->user->session_keyring, 1), |
471 | context, type, description, match); | 451 | cred, type, description, match); |
472 | if (!IS_ERR(key_ref)) | 452 | if (!IS_ERR(key_ref)) |
473 | goto found; | 453 | goto found; |
474 | 454 | ||
@@ -490,7 +470,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
490 | * - we don't permit access to request_key auth keys via this method | 470 | * - we don't permit access to request_key auth keys via this method |
491 | */ | 471 | */ |
492 | if (cred->request_key_auth && | 472 | if (cred->request_key_auth && |
493 | context == current && | 473 | cred == current_cred() && |
494 | type != &key_type_request_key_auth | 474 | type != &key_type_request_key_auth |
495 | ) { | 475 | ) { |
496 | /* defend against the auth key being revoked */ | 476 | /* defend against the auth key being revoked */ |
@@ -500,7 +480,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
500 | rka = cred->request_key_auth->payload.data; | 480 | rka = cred->request_key_auth->payload.data; |
501 | 481 | ||
502 | key_ref = search_process_keyrings(type, description, | 482 | key_ref = search_process_keyrings(type, description, |
503 | match, rka->context); | 483 | match, rka->cred); |
504 | 484 | ||
505 | up_read(&cred->request_key_auth->sem); | 485 | up_read(&cred->request_key_auth->sem); |
506 | 486 | ||
@@ -527,7 +507,6 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
527 | key_ref = ret ? ret : err; | 507 | key_ref = ret ? ret : err; |
528 | 508 | ||
529 | found: | 509 | found: |
530 | put_cred(cred); | ||
531 | return key_ref; | 510 | return key_ref; |
532 | 511 | ||
533 | } /* end search_process_keyrings() */ | 512 | } /* end search_process_keyrings() */ |
@@ -552,8 +531,7 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial, | |||
552 | key_perm_t perm) | 531 | key_perm_t perm) |
553 | { | 532 | { |
554 | struct request_key_auth *rka; | 533 | struct request_key_auth *rka; |
555 | struct task_struct *t = current; | 534 | const struct cred *cred; |
556 | struct cred *cred; | ||
557 | struct key *key; | 535 | struct key *key; |
558 | key_ref_t key_ref, skey_ref; | 536 | key_ref_t key_ref, skey_ref; |
559 | int ret; | 537 | int ret; |
@@ -608,6 +586,7 @@ try_again: | |||
608 | goto error; | 586 | goto error; |
609 | ret = install_session_keyring( | 587 | ret = install_session_keyring( |
610 | cred->user->session_keyring); | 588 | cred->user->session_keyring); |
589 | |||
611 | if (ret < 0) | 590 | if (ret < 0) |
612 | goto error; | 591 | goto error; |
613 | goto reget_creds; | 592 | goto reget_creds; |
@@ -693,7 +672,7 @@ try_again: | |||
693 | /* check to see if we possess the key */ | 672 | /* check to see if we possess the key */ |
694 | skey_ref = search_process_keyrings(key->type, key, | 673 | skey_ref = search_process_keyrings(key->type, key, |
695 | lookup_user_key_possessed, | 674 | lookup_user_key_possessed, |
696 | current); | 675 | cred); |
697 | 676 | ||
698 | if (!IS_ERR(skey_ref)) { | 677 | if (!IS_ERR(skey_ref)) { |
699 | key_put(key); | 678 | key_put(key); |
@@ -725,7 +704,7 @@ try_again: | |||
725 | goto invalid_key; | 704 | goto invalid_key; |
726 | 705 | ||
727 | /* check the permissions */ | 706 | /* check the permissions */ |
728 | ret = key_task_permission(key_ref, t, perm); | 707 | ret = key_task_permission(key_ref, cred, perm); |
729 | if (ret < 0) | 708 | if (ret < 0) |
730 | goto invalid_key; | 709 | goto invalid_key; |
731 | 710 | ||
@@ -755,21 +734,33 @@ reget_creds: | |||
755 | */ | 734 | */ |
756 | long join_session_keyring(const char *name) | 735 | long join_session_keyring(const char *name) |
757 | { | 736 | { |
758 | struct task_struct *tsk = current; | 737 | const struct cred *old; |
759 | struct cred *cred = current->cred; | 738 | struct cred *new; |
760 | struct key *keyring; | 739 | struct key *keyring; |
761 | long ret; | 740 | long ret, serial; |
741 | |||
742 | /* only permit this if there's a single thread in the thread group - | ||
743 | * this avoids us having to adjust the creds on all threads and risking | ||
744 | * ENOMEM */ | ||
745 | if (!is_single_threaded(current)) | ||
746 | return -EMLINK; | ||
747 | |||
748 | new = prepare_creds(); | ||
749 | if (!new) | ||
750 | return -ENOMEM; | ||
751 | old = current_cred(); | ||
762 | 752 | ||
763 | /* if no name is provided, install an anonymous keyring */ | 753 | /* if no name is provided, install an anonymous keyring */ |
764 | if (!name) { | 754 | if (!name) { |
765 | ret = install_session_keyring(NULL); | 755 | ret = install_session_keyring_to_cred(new, NULL); |
766 | if (ret < 0) | 756 | if (ret < 0) |
767 | goto error; | 757 | goto error; |
768 | 758 | ||
769 | rcu_read_lock(); | 759 | serial = new->tgcred->session_keyring->serial; |
770 | ret = rcu_dereference(cred->tgcred->session_keyring)->serial; | 760 | ret = commit_creds(new); |
771 | rcu_read_unlock(); | 761 | if (ret == 0) |
772 | goto error; | 762 | ret = serial; |
763 | goto okay; | ||
773 | } | 764 | } |
774 | 765 | ||
775 | /* allow the user to join or create a named keyring */ | 766 | /* allow the user to join or create a named keyring */ |
@@ -779,29 +770,33 @@ long join_session_keyring(const char *name) | |||
779 | keyring = find_keyring_by_name(name, false); | 770 | keyring = find_keyring_by_name(name, false); |
780 | if (PTR_ERR(keyring) == -ENOKEY) { | 771 | if (PTR_ERR(keyring) == -ENOKEY) { |
781 | /* not found - try and create a new one */ | 772 | /* not found - try and create a new one */ |
782 | keyring = keyring_alloc(name, cred->uid, cred->gid, tsk, | 773 | keyring = keyring_alloc(name, old->uid, old->gid, old, |
783 | KEY_ALLOC_IN_QUOTA, NULL); | 774 | KEY_ALLOC_IN_QUOTA, NULL); |
784 | if (IS_ERR(keyring)) { | 775 | if (IS_ERR(keyring)) { |
785 | ret = PTR_ERR(keyring); | 776 | ret = PTR_ERR(keyring); |
786 | goto error2; | 777 | goto error2; |
787 | } | 778 | } |
788 | } | 779 | } else if (IS_ERR(keyring)) { |
789 | else if (IS_ERR(keyring)) { | ||
790 | ret = PTR_ERR(keyring); | 780 | ret = PTR_ERR(keyring); |
791 | goto error2; | 781 | goto error2; |
792 | } | 782 | } |
793 | 783 | ||
794 | /* we've got a keyring - now to install it */ | 784 | /* we've got a keyring - now to install it */ |
795 | ret = install_session_keyring(keyring); | 785 | ret = install_session_keyring_to_cred(new, keyring); |
796 | if (ret < 0) | 786 | if (ret < 0) |
797 | goto error2; | 787 | goto error2; |
798 | 788 | ||
789 | commit_creds(new); | ||
790 | mutex_unlock(&key_session_mutex); | ||
791 | |||
799 | ret = keyring->serial; | 792 | ret = keyring->serial; |
800 | key_put(keyring); | 793 | key_put(keyring); |
794 | okay: | ||
795 | return ret; | ||
801 | 796 | ||
802 | error2: | 797 | error2: |
803 | mutex_unlock(&key_session_mutex); | 798 | mutex_unlock(&key_session_mutex); |
804 | error: | 799 | error: |
800 | abort_creds(new); | ||
805 | return ret; | 801 | return ret; |
806 | 802 | } | |
807 | } /* end join_session_keyring() */ | ||
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 3d12558362df..0e04f72ef2d4 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
@@ -83,8 +83,10 @@ static int call_sbin_request_key(struct key_construction *cons, | |||
83 | /* allocate a new session keyring */ | 83 | /* allocate a new session keyring */ |
84 | sprintf(desc, "_req.%u", key->serial); | 84 | sprintf(desc, "_req.%u", key->serial); |
85 | 85 | ||
86 | keyring = keyring_alloc(desc, current_fsuid(), current_fsgid(), current, | 86 | cred = get_current_cred(); |
87 | keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred, | ||
87 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | 88 | KEY_ALLOC_QUOTA_OVERRUN, NULL); |
89 | put_cred(cred); | ||
88 | if (IS_ERR(keyring)) { | 90 | if (IS_ERR(keyring)) { |
89 | ret = PTR_ERR(keyring); | 91 | ret = PTR_ERR(keyring); |
90 | goto error_alloc; | 92 | goto error_alloc; |
@@ -104,8 +106,7 @@ static int call_sbin_request_key(struct key_construction *cons, | |||
104 | 106 | ||
105 | /* we specify the process's default keyrings */ | 107 | /* we specify the process's default keyrings */ |
106 | sprintf(keyring_str[0], "%d", | 108 | sprintf(keyring_str[0], "%d", |
107 | cred->thread_keyring ? | 109 | cred->thread_keyring ? cred->thread_keyring->serial : 0); |
108 | cred->thread_keyring->serial : 0); | ||
109 | 110 | ||
110 | prkey = 0; | 111 | prkey = 0; |
111 | if (cred->tgcred->process_keyring) | 112 | if (cred->tgcred->process_keyring) |
@@ -155,8 +156,8 @@ error_link: | |||
155 | key_put(keyring); | 156 | key_put(keyring); |
156 | 157 | ||
157 | error_alloc: | 158 | error_alloc: |
158 | kleave(" = %d", ret); | ||
159 | complete_request_key(cons, ret); | 159 | complete_request_key(cons, ret); |
160 | kleave(" = %d", ret); | ||
160 | return ret; | 161 | return ret; |
161 | } | 162 | } |
162 | 163 | ||
@@ -295,6 +296,7 @@ static int construct_alloc_key(struct key_type *type, | |||
295 | struct key_user *user, | 296 | struct key_user *user, |
296 | struct key **_key) | 297 | struct key **_key) |
297 | { | 298 | { |
299 | const struct cred *cred = current_cred(); | ||
298 | struct key *key; | 300 | struct key *key; |
299 | key_ref_t key_ref; | 301 | key_ref_t key_ref; |
300 | 302 | ||
@@ -302,9 +304,8 @@ static int construct_alloc_key(struct key_type *type, | |||
302 | 304 | ||
303 | mutex_lock(&user->cons_lock); | 305 | mutex_lock(&user->cons_lock); |
304 | 306 | ||
305 | key = key_alloc(type, description, | 307 | key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, |
306 | current_fsuid(), current_fsgid(), current, KEY_POS_ALL, | 308 | KEY_POS_ALL, flags); |
307 | flags); | ||
308 | if (IS_ERR(key)) | 309 | if (IS_ERR(key)) |
309 | goto alloc_failed; | 310 | goto alloc_failed; |
310 | 311 | ||
@@ -317,8 +318,7 @@ static int construct_alloc_key(struct key_type *type, | |||
317 | * waited for locks */ | 318 | * waited for locks */ |
318 | mutex_lock(&key_construction_mutex); | 319 | mutex_lock(&key_construction_mutex); |
319 | 320 | ||
320 | key_ref = search_process_keyrings(type, description, type->match, | 321 | key_ref = search_process_keyrings(type, description, type->match, cred); |
321 | current); | ||
322 | if (!IS_ERR(key_ref)) | 322 | if (!IS_ERR(key_ref)) |
323 | goto key_already_present; | 323 | goto key_already_present; |
324 | 324 | ||
@@ -363,6 +363,8 @@ static struct key *construct_key_and_link(struct key_type *type, | |||
363 | struct key *key; | 363 | struct key *key; |
364 | int ret; | 364 | int ret; |
365 | 365 | ||
366 | kenter(""); | ||
367 | |||
366 | user = key_user_lookup(current_fsuid()); | 368 | user = key_user_lookup(current_fsuid()); |
367 | if (!user) | 369 | if (!user) |
368 | return ERR_PTR(-ENOMEM); | 370 | return ERR_PTR(-ENOMEM); |
@@ -376,17 +378,21 @@ static struct key *construct_key_and_link(struct key_type *type, | |||
376 | if (ret == 0) { | 378 | if (ret == 0) { |
377 | ret = construct_key(key, callout_info, callout_len, aux, | 379 | ret = construct_key(key, callout_info, callout_len, aux, |
378 | dest_keyring); | 380 | dest_keyring); |
379 | if (ret < 0) | 381 | if (ret < 0) { |
382 | kdebug("cons failed"); | ||
380 | goto construction_failed; | 383 | goto construction_failed; |
384 | } | ||
381 | } | 385 | } |
382 | 386 | ||
383 | key_put(dest_keyring); | 387 | key_put(dest_keyring); |
388 | kleave(" = key %d", key_serial(key)); | ||
384 | return key; | 389 | return key; |
385 | 390 | ||
386 | construction_failed: | 391 | construction_failed: |
387 | key_negate_and_link(key, key_negative_timeout, NULL, NULL); | 392 | key_negate_and_link(key, key_negative_timeout, NULL, NULL); |
388 | key_put(key); | 393 | key_put(key); |
389 | key_put(dest_keyring); | 394 | key_put(dest_keyring); |
395 | kleave(" = %d", ret); | ||
390 | return ERR_PTR(ret); | 396 | return ERR_PTR(ret); |
391 | } | 397 | } |
392 | 398 | ||
@@ -405,6 +411,7 @@ struct key *request_key_and_link(struct key_type *type, | |||
405 | struct key *dest_keyring, | 411 | struct key *dest_keyring, |
406 | unsigned long flags) | 412 | unsigned long flags) |
407 | { | 413 | { |
414 | const struct cred *cred = current_cred(); | ||
408 | struct key *key; | 415 | struct key *key; |
409 | key_ref_t key_ref; | 416 | key_ref_t key_ref; |
410 | 417 | ||
@@ -414,7 +421,7 @@ struct key *request_key_and_link(struct key_type *type, | |||
414 | 421 | ||
415 | /* search all the process keyrings for a key */ | 422 | /* search all the process keyrings for a key */ |
416 | key_ref = search_process_keyrings(type, description, type->match, | 423 | key_ref = search_process_keyrings(type, description, type->match, |
417 | current); | 424 | cred); |
418 | 425 | ||
419 | if (!IS_ERR(key_ref)) { | 426 | if (!IS_ERR(key_ref)) { |
420 | key = key_ref_to_ptr(key_ref); | 427 | key = key_ref_to_ptr(key_ref); |
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 2125579d5d73..86747151ee5b 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c | |||
@@ -105,9 +105,9 @@ static void request_key_auth_revoke(struct key *key) | |||
105 | 105 | ||
106 | kenter("{%d}", key->serial); | 106 | kenter("{%d}", key->serial); |
107 | 107 | ||
108 | if (rka->context) { | 108 | if (rka->cred) { |
109 | put_task_struct(rka->context); | 109 | put_cred(rka->cred); |
110 | rka->context = NULL; | 110 | rka->cred = NULL; |
111 | } | 111 | } |
112 | 112 | ||
113 | } /* end request_key_auth_revoke() */ | 113 | } /* end request_key_auth_revoke() */ |
@@ -122,9 +122,9 @@ static void request_key_auth_destroy(struct key *key) | |||
122 | 122 | ||
123 | kenter("{%d}", key->serial); | 123 | kenter("{%d}", key->serial); |
124 | 124 | ||
125 | if (rka->context) { | 125 | if (rka->cred) { |
126 | put_task_struct(rka->context); | 126 | put_cred(rka->cred); |
127 | rka->context = NULL; | 127 | rka->cred = NULL; |
128 | } | 128 | } |
129 | 129 | ||
130 | key_put(rka->target_key); | 130 | key_put(rka->target_key); |
@@ -143,6 +143,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info, | |||
143 | size_t callout_len, struct key *dest_keyring) | 143 | size_t callout_len, struct key *dest_keyring) |
144 | { | 144 | { |
145 | struct request_key_auth *rka, *irka; | 145 | struct request_key_auth *rka, *irka; |
146 | const struct cred *cred = current->cred; | ||
146 | struct key *authkey = NULL; | 147 | struct key *authkey = NULL; |
147 | char desc[20]; | 148 | char desc[20]; |
148 | int ret; | 149 | int ret; |
@@ -164,28 +165,25 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info, | |||
164 | 165 | ||
165 | /* see if the calling process is already servicing the key request of | 166 | /* see if the calling process is already servicing the key request of |
166 | * another process */ | 167 | * another process */ |
167 | if (current->cred->request_key_auth) { | 168 | if (cred->request_key_auth) { |
168 | /* it is - use that instantiation context here too */ | 169 | /* it is - use that instantiation context here too */ |
169 | down_read(¤t->cred->request_key_auth->sem); | 170 | down_read(&cred->request_key_auth->sem); |
170 | 171 | ||
171 | /* if the auth key has been revoked, then the key we're | 172 | /* if the auth key has been revoked, then the key we're |
172 | * servicing is already instantiated */ | 173 | * servicing is already instantiated */ |
173 | if (test_bit(KEY_FLAG_REVOKED, | 174 | if (test_bit(KEY_FLAG_REVOKED, &cred->request_key_auth->flags)) |
174 | ¤t->cred->request_key_auth->flags)) | ||
175 | goto auth_key_revoked; | 175 | goto auth_key_revoked; |
176 | 176 | ||
177 | irka = current->cred->request_key_auth->payload.data; | 177 | irka = cred->request_key_auth->payload.data; |
178 | rka->context = irka->context; | 178 | rka->cred = get_cred(irka->cred); |
179 | rka->pid = irka->pid; | 179 | rka->pid = irka->pid; |
180 | get_task_struct(rka->context); | ||
181 | 180 | ||
182 | up_read(¤t->cred->request_key_auth->sem); | 181 | up_read(&cred->request_key_auth->sem); |
183 | } | 182 | } |
184 | else { | 183 | else { |
185 | /* it isn't - use this process as the context */ | 184 | /* it isn't - use this process as the context */ |
186 | rka->context = current; | 185 | rka->cred = get_cred(cred); |
187 | rka->pid = current->pid; | 186 | rka->pid = current->pid; |
188 | get_task_struct(rka->context); | ||
189 | } | 187 | } |
190 | 188 | ||
191 | rka->target_key = key_get(target); | 189 | rka->target_key = key_get(target); |
@@ -197,7 +195,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info, | |||
197 | sprintf(desc, "%x", target->serial); | 195 | sprintf(desc, "%x", target->serial); |
198 | 196 | ||
199 | authkey = key_alloc(&key_type_request_key_auth, desc, | 197 | authkey = key_alloc(&key_type_request_key_auth, desc, |
200 | current_fsuid(), current_fsgid(), current, | 198 | cred->fsuid, cred->fsgid, cred, |
201 | KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | | 199 | KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | |
202 | KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA); | 200 | KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA); |
203 | if (IS_ERR(authkey)) { | 201 | if (IS_ERR(authkey)) { |
@@ -205,16 +203,16 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info, | |||
205 | goto error_alloc; | 203 | goto error_alloc; |
206 | } | 204 | } |
207 | 205 | ||
208 | /* construct and attach to the keyring */ | 206 | /* construct the auth key */ |
209 | ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL); | 207 | ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL); |
210 | if (ret < 0) | 208 | if (ret < 0) |
211 | goto error_inst; | 209 | goto error_inst; |
212 | 210 | ||
213 | kleave(" = {%d}", authkey->serial); | 211 | kleave(" = {%d,%d}", authkey->serial, atomic_read(&authkey->usage)); |
214 | return authkey; | 212 | return authkey; |
215 | 213 | ||
216 | auth_key_revoked: | 214 | auth_key_revoked: |
217 | up_read(¤t->cred->request_key_auth->sem); | 215 | up_read(&cred->request_key_auth->sem); |
218 | kfree(rka->callout_info); | 216 | kfree(rka->callout_info); |
219 | kfree(rka); | 217 | kfree(rka); |
220 | kleave("= -EKEYREVOKED"); | 218 | kleave("= -EKEYREVOKED"); |
@@ -257,6 +255,7 @@ static int key_get_instantiation_authkey_match(const struct key *key, | |||
257 | */ | 255 | */ |
258 | struct key *key_get_instantiation_authkey(key_serial_t target_id) | 256 | struct key *key_get_instantiation_authkey(key_serial_t target_id) |
259 | { | 257 | { |
258 | const struct cred *cred = current_cred(); | ||
260 | struct key *authkey; | 259 | struct key *authkey; |
261 | key_ref_t authkey_ref; | 260 | key_ref_t authkey_ref; |
262 | 261 | ||
@@ -264,7 +263,7 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id) | |||
264 | &key_type_request_key_auth, | 263 | &key_type_request_key_auth, |
265 | (void *) (unsigned long) target_id, | 264 | (void *) (unsigned long) target_id, |
266 | key_get_instantiation_authkey_match, | 265 | key_get_instantiation_authkey_match, |
267 | current); | 266 | cred); |
268 | 267 | ||
269 | if (IS_ERR(authkey_ref)) { | 268 | if (IS_ERR(authkey_ref)) { |
270 | authkey = ERR_CAST(authkey_ref); | 269 | authkey = ERR_CAST(authkey_ref); |
diff --git a/security/security.c b/security/security.c index f40a0a04c3c2..a55d739c6864 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -145,18 +145,13 @@ int security_capget(struct task_struct *target, | |||
145 | return security_ops->capget(target, effective, inheritable, permitted); | 145 | return security_ops->capget(target, effective, inheritable, permitted); |
146 | } | 146 | } |
147 | 147 | ||
148 | int security_capset_check(const kernel_cap_t *effective, | 148 | int security_capset(struct cred *new, const struct cred *old, |
149 | const kernel_cap_t *inheritable, | 149 | const kernel_cap_t *effective, |
150 | const kernel_cap_t *permitted) | 150 | const kernel_cap_t *inheritable, |
151 | const kernel_cap_t *permitted) | ||
151 | { | 152 | { |
152 | return security_ops->capset_check(effective, inheritable, permitted); | 153 | return security_ops->capset(new, old, |
153 | } | 154 | effective, inheritable, permitted); |
154 | |||
155 | void security_capset_set(const kernel_cap_t *effective, | ||
156 | const kernel_cap_t *inheritable, | ||
157 | const kernel_cap_t *permitted) | ||
158 | { | ||
159 | security_ops->capset_set(effective, inheritable, permitted); | ||
160 | } | 155 | } |
161 | 156 | ||
162 | int security_capable(struct task_struct *tsk, int cap) | 157 | int security_capable(struct task_struct *tsk, int cap) |
@@ -228,9 +223,9 @@ void security_bprm_free(struct linux_binprm *bprm) | |||
228 | security_ops->bprm_free_security(bprm); | 223 | security_ops->bprm_free_security(bprm); |
229 | } | 224 | } |
230 | 225 | ||
231 | void security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) | 226 | int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) |
232 | { | 227 | { |
233 | security_ops->bprm_apply_creds(bprm, unsafe); | 228 | return security_ops->bprm_apply_creds(bprm, unsafe); |
234 | } | 229 | } |
235 | 230 | ||
236 | void security_bprm_post_apply_creds(struct linux_binprm *bprm) | 231 | void security_bprm_post_apply_creds(struct linux_binprm *bprm) |
@@ -616,14 +611,19 @@ int security_task_create(unsigned long clone_flags) | |||
616 | return security_ops->task_create(clone_flags); | 611 | return security_ops->task_create(clone_flags); |
617 | } | 612 | } |
618 | 613 | ||
619 | int security_cred_alloc(struct cred *cred) | 614 | void security_cred_free(struct cred *cred) |
620 | { | 615 | { |
621 | return security_ops->cred_alloc_security(cred); | 616 | security_ops->cred_free(cred); |
622 | } | 617 | } |
623 | 618 | ||
624 | void security_cred_free(struct cred *cred) | 619 | int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp) |
625 | { | 620 | { |
626 | security_ops->cred_free(cred); | 621 | return security_ops->cred_prepare(new, old, gfp); |
622 | } | ||
623 | |||
624 | void security_commit_creds(struct cred *new, const struct cred *old) | ||
625 | { | ||
626 | return security_ops->cred_commit(new, old); | ||
627 | } | 627 | } |
628 | 628 | ||
629 | int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) | 629 | int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) |
@@ -631,10 +631,10 @@ int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) | |||
631 | return security_ops->task_setuid(id0, id1, id2, flags); | 631 | return security_ops->task_setuid(id0, id1, id2, flags); |
632 | } | 632 | } |
633 | 633 | ||
634 | int security_task_post_setuid(uid_t old_ruid, uid_t old_euid, | 634 | int security_task_fix_setuid(struct cred *new, const struct cred *old, |
635 | uid_t old_suid, int flags) | 635 | int flags) |
636 | { | 636 | { |
637 | return security_ops->task_post_setuid(old_ruid, old_euid, old_suid, flags); | 637 | return security_ops->task_fix_setuid(new, old, flags); |
638 | } | 638 | } |
639 | 639 | ||
640 | int security_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags) | 640 | int security_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags) |
@@ -716,14 +716,9 @@ int security_task_wait(struct task_struct *p) | |||
716 | } | 716 | } |
717 | 717 | ||
718 | int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, | 718 | int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, |
719 | unsigned long arg4, unsigned long arg5, long *rc_p) | 719 | unsigned long arg4, unsigned long arg5) |
720 | { | ||
721 | return security_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p); | ||
722 | } | ||
723 | |||
724 | void security_task_reparent_to_init(struct task_struct *p) | ||
725 | { | 720 | { |
726 | security_ops->task_reparent_to_init(p); | 721 | return security_ops->task_prctl(option, arg2, arg3, arg4, arg5); |
727 | } | 722 | } |
728 | 723 | ||
729 | void security_task_to_inode(struct task_struct *p, struct inode *inode) | 724 | void security_task_to_inode(struct task_struct *p, struct inode *inode) |
@@ -1123,9 +1118,10 @@ EXPORT_SYMBOL(security_skb_classify_flow); | |||
1123 | 1118 | ||
1124 | #ifdef CONFIG_KEYS | 1119 | #ifdef CONFIG_KEYS |
1125 | 1120 | ||
1126 | int security_key_alloc(struct key *key, struct task_struct *tsk, unsigned long flags) | 1121 | int security_key_alloc(struct key *key, const struct cred *cred, |
1122 | unsigned long flags) | ||
1127 | { | 1123 | { |
1128 | return security_ops->key_alloc(key, tsk, flags); | 1124 | return security_ops->key_alloc(key, cred, flags); |
1129 | } | 1125 | } |
1130 | 1126 | ||
1131 | void security_key_free(struct key *key) | 1127 | void security_key_free(struct key *key) |
@@ -1134,9 +1130,9 @@ void security_key_free(struct key *key) | |||
1134 | } | 1130 | } |
1135 | 1131 | ||
1136 | int security_key_permission(key_ref_t key_ref, | 1132 | int security_key_permission(key_ref_t key_ref, |
1137 | struct task_struct *context, key_perm_t perm) | 1133 | const struct cred *cred, key_perm_t perm) |
1138 | { | 1134 | { |
1139 | return security_ops->key_permission(key_ref, context, perm); | 1135 | return security_ops->key_permission(key_ref, cred, perm); |
1140 | } | 1136 | } |
1141 | 1137 | ||
1142 | int security_key_getsecurity(struct key *key, char **_buffer) | 1138 | int security_key_getsecurity(struct key *key, char **_buffer) |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index f20cbd681ba6..c71bba78872f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -156,20 +156,20 @@ static int selinux_secmark_enabled(void) | |||
156 | return (atomic_read(&selinux_secmark_refcount) > 0); | 156 | return (atomic_read(&selinux_secmark_refcount) > 0); |
157 | } | 157 | } |
158 | 158 | ||
159 | /* Allocate and free functions for each kind of security blob. */ | 159 | /* |
160 | 160 | * initialise the security for the init task | |
161 | static int cred_alloc_security(struct cred *cred) | 161 | */ |
162 | static void cred_init_security(void) | ||
162 | { | 163 | { |
164 | struct cred *cred = (struct cred *) current->cred; | ||
163 | struct task_security_struct *tsec; | 165 | struct task_security_struct *tsec; |
164 | 166 | ||
165 | tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL); | 167 | tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL); |
166 | if (!tsec) | 168 | if (!tsec) |
167 | return -ENOMEM; | 169 | panic("SELinux: Failed to initialize initial task.\n"); |
168 | 170 | ||
169 | tsec->osid = tsec->sid = SECINITSID_UNLABELED; | 171 | tsec->osid = tsec->sid = SECINITSID_KERNEL; |
170 | cred->security = tsec; | 172 | cred->security = tsec; |
171 | |||
172 | return 0; | ||
173 | } | 173 | } |
174 | 174 | ||
175 | /* | 175 | /* |
@@ -1379,6 +1379,19 @@ static inline u32 signal_to_av(int sig) | |||
1379 | } | 1379 | } |
1380 | 1380 | ||
1381 | /* | 1381 | /* |
1382 | * Check permission between a pair of credentials | ||
1383 | * fork check, ptrace check, etc. | ||
1384 | */ | ||
1385 | static int cred_has_perm(const struct cred *actor, | ||
1386 | const struct cred *target, | ||
1387 | u32 perms) | ||
1388 | { | ||
1389 | u32 asid = cred_sid(actor), tsid = cred_sid(target); | ||
1390 | |||
1391 | return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL); | ||
1392 | } | ||
1393 | |||
1394 | /* | ||
1382 | * Check permission between a pair of tasks, e.g. signal checks, | 1395 | * Check permission between a pair of tasks, e.g. signal checks, |
1383 | * fork check, ptrace check, etc. | 1396 | * fork check, ptrace check, etc. |
1384 | * tsk1 is the actor and tsk2 is the target | 1397 | * tsk1 is the actor and tsk2 is the target |
@@ -1820,24 +1833,19 @@ static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, | |||
1820 | return secondary_ops->capget(target, effective, inheritable, permitted); | 1833 | return secondary_ops->capget(target, effective, inheritable, permitted); |
1821 | } | 1834 | } |
1822 | 1835 | ||
1823 | static int selinux_capset_check(const kernel_cap_t *effective, | 1836 | static int selinux_capset(struct cred *new, const struct cred *old, |
1824 | const kernel_cap_t *inheritable, | 1837 | const kernel_cap_t *effective, |
1825 | const kernel_cap_t *permitted) | 1838 | const kernel_cap_t *inheritable, |
1839 | const kernel_cap_t *permitted) | ||
1826 | { | 1840 | { |
1827 | int error; | 1841 | int error; |
1828 | 1842 | ||
1829 | error = secondary_ops->capset_check(effective, inheritable, permitted); | 1843 | error = secondary_ops->capset(new, old, |
1844 | effective, inheritable, permitted); | ||
1830 | if (error) | 1845 | if (error) |
1831 | return error; | 1846 | return error; |
1832 | 1847 | ||
1833 | return task_has_perm(current, current, PROCESS__SETCAP); | 1848 | return cred_has_perm(old, new, PROCESS__SETCAP); |
1834 | } | ||
1835 | |||
1836 | static void selinux_capset_set(const kernel_cap_t *effective, | ||
1837 | const kernel_cap_t *inheritable, | ||
1838 | const kernel_cap_t *permitted) | ||
1839 | { | ||
1840 | secondary_ops->capset_set(effective, inheritable, permitted); | ||
1841 | } | 1849 | } |
1842 | 1850 | ||
1843 | static int selinux_capable(struct task_struct *tsk, int cap, int audit) | 1851 | static int selinux_capable(struct task_struct *tsk, int cap, int audit) |
@@ -2244,16 +2252,23 @@ static inline void flush_unauthorized_files(const struct cred *cred, | |||
2244 | spin_unlock(&files->file_lock); | 2252 | spin_unlock(&files->file_lock); |
2245 | } | 2253 | } |
2246 | 2254 | ||
2247 | static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) | 2255 | static int selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) |
2248 | { | 2256 | { |
2249 | struct task_security_struct *tsec; | 2257 | struct task_security_struct *tsec; |
2250 | struct bprm_security_struct *bsec; | 2258 | struct bprm_security_struct *bsec; |
2259 | struct cred *new; | ||
2251 | u32 sid; | 2260 | u32 sid; |
2252 | int rc; | 2261 | int rc; |
2253 | 2262 | ||
2254 | secondary_ops->bprm_apply_creds(bprm, unsafe); | 2263 | rc = secondary_ops->bprm_apply_creds(bprm, unsafe); |
2264 | if (rc < 0) | ||
2265 | return rc; | ||
2255 | 2266 | ||
2256 | tsec = current_security(); | 2267 | new = prepare_creds(); |
2268 | if (!new) | ||
2269 | return -ENOMEM; | ||
2270 | |||
2271 | tsec = new->security; | ||
2257 | 2272 | ||
2258 | bsec = bprm->security; | 2273 | bsec = bprm->security; |
2259 | sid = bsec->sid; | 2274 | sid = bsec->sid; |
@@ -2268,7 +2283,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) | |||
2268 | PROCESS__SHARE, NULL); | 2283 | PROCESS__SHARE, NULL); |
2269 | if (rc) { | 2284 | if (rc) { |
2270 | bsec->unsafe = 1; | 2285 | bsec->unsafe = 1; |
2271 | return; | 2286 | goto out; |
2272 | } | 2287 | } |
2273 | } | 2288 | } |
2274 | 2289 | ||
@@ -2292,12 +2307,16 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) | |||
2292 | PROCESS__PTRACE, NULL); | 2307 | PROCESS__PTRACE, NULL); |
2293 | if (rc) { | 2308 | if (rc) { |
2294 | bsec->unsafe = 1; | 2309 | bsec->unsafe = 1; |
2295 | return; | 2310 | goto out; |
2296 | } | 2311 | } |
2297 | } | 2312 | } |
2298 | } | 2313 | } |
2299 | tsec->sid = sid; | 2314 | tsec->sid = sid; |
2300 | } | 2315 | } |
2316 | |||
2317 | out: | ||
2318 | commit_creds(new); | ||
2319 | return 0; | ||
2301 | } | 2320 | } |
2302 | 2321 | ||
2303 | /* | 2322 | /* |
@@ -3021,6 +3040,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, | |||
3021 | static int file_map_prot_check(struct file *file, unsigned long prot, int shared) | 3040 | static int file_map_prot_check(struct file *file, unsigned long prot, int shared) |
3022 | { | 3041 | { |
3023 | const struct cred *cred = current_cred(); | 3042 | const struct cred *cred = current_cred(); |
3043 | int rc = 0; | ||
3024 | 3044 | ||
3025 | #ifndef CONFIG_PPC32 | 3045 | #ifndef CONFIG_PPC32 |
3026 | if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) { | 3046 | if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) { |
@@ -3029,9 +3049,9 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared | |||
3029 | * private file mapping that will also be writable. | 3049 | * private file mapping that will also be writable. |
3030 | * This has an additional check. | 3050 | * This has an additional check. |
3031 | */ | 3051 | */ |
3032 | int rc = task_has_perm(current, current, PROCESS__EXECMEM); | 3052 | rc = cred_has_perm(cred, cred, PROCESS__EXECMEM); |
3033 | if (rc) | 3053 | if (rc) |
3034 | return rc; | 3054 | goto error; |
3035 | } | 3055 | } |
3036 | #endif | 3056 | #endif |
3037 | 3057 | ||
@@ -3048,7 +3068,9 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared | |||
3048 | 3068 | ||
3049 | return file_has_perm(cred, file, av); | 3069 | return file_has_perm(cred, file, av); |
3050 | } | 3070 | } |
3051 | return 0; | 3071 | |
3072 | error: | ||
3073 | return rc; | ||
3052 | } | 3074 | } |
3053 | 3075 | ||
3054 | static int selinux_file_mmap(struct file *file, unsigned long reqprot, | 3076 | static int selinux_file_mmap(struct file *file, unsigned long reqprot, |
@@ -3090,8 +3112,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, | |||
3090 | rc = 0; | 3112 | rc = 0; |
3091 | if (vma->vm_start >= vma->vm_mm->start_brk && | 3113 | if (vma->vm_start >= vma->vm_mm->start_brk && |
3092 | vma->vm_end <= vma->vm_mm->brk) { | 3114 | vma->vm_end <= vma->vm_mm->brk) { |
3093 | rc = task_has_perm(current, current, | 3115 | rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP); |
3094 | PROCESS__EXECHEAP); | ||
3095 | } else if (!vma->vm_file && | 3116 | } else if (!vma->vm_file && |
3096 | vma->vm_start <= vma->vm_mm->start_stack && | 3117 | vma->vm_start <= vma->vm_mm->start_stack && |
3097 | vma->vm_end >= vma->vm_mm->start_stack) { | 3118 | vma->vm_end >= vma->vm_mm->start_stack) { |
@@ -3104,8 +3125,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, | |||
3104 | * modified content. This typically should only | 3125 | * modified content. This typically should only |
3105 | * occur for text relocations. | 3126 | * occur for text relocations. |
3106 | */ | 3127 | */ |
3107 | rc = file_has_perm(cred, vma->vm_file, | 3128 | rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD); |
3108 | FILE__EXECMOD); | ||
3109 | } | 3129 | } |
3110 | if (rc) | 3130 | if (rc) |
3111 | return rc; | 3131 | return rc; |
@@ -3211,6 +3231,7 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred) | |||
3211 | struct file_security_struct *fsec; | 3231 | struct file_security_struct *fsec; |
3212 | struct inode *inode; | 3232 | struct inode *inode; |
3213 | struct inode_security_struct *isec; | 3233 | struct inode_security_struct *isec; |
3234 | |||
3214 | inode = file->f_path.dentry->d_inode; | 3235 | inode = file->f_path.dentry->d_inode; |
3215 | fsec = file->f_security; | 3236 | fsec = file->f_security; |
3216 | isec = inode->i_security; | 3237 | isec = inode->i_security; |
@@ -3247,38 +3268,41 @@ static int selinux_task_create(unsigned long clone_flags) | |||
3247 | return task_has_perm(current, current, PROCESS__FORK); | 3268 | return task_has_perm(current, current, PROCESS__FORK); |
3248 | } | 3269 | } |
3249 | 3270 | ||
3250 | static int selinux_cred_alloc_security(struct cred *cred) | 3271 | /* |
3272 | * detach and free the LSM part of a set of credentials | ||
3273 | */ | ||
3274 | static void selinux_cred_free(struct cred *cred) | ||
3251 | { | 3275 | { |
3252 | struct task_security_struct *tsec1, *tsec2; | 3276 | struct task_security_struct *tsec = cred->security; |
3253 | int rc; | 3277 | cred->security = NULL; |
3254 | 3278 | kfree(tsec); | |
3255 | tsec1 = current_security(); | 3279 | } |
3256 | 3280 | ||
3257 | rc = cred_alloc_security(cred); | 3281 | /* |
3258 | if (rc) | 3282 | * prepare a new set of credentials for modification |
3259 | return rc; | 3283 | */ |
3260 | tsec2 = cred->security; | 3284 | static int selinux_cred_prepare(struct cred *new, const struct cred *old, |
3285 | gfp_t gfp) | ||
3286 | { | ||
3287 | const struct task_security_struct *old_tsec; | ||
3288 | struct task_security_struct *tsec; | ||
3261 | 3289 | ||
3262 | tsec2->osid = tsec1->osid; | 3290 | old_tsec = old->security; |
3263 | tsec2->sid = tsec1->sid; | ||
3264 | 3291 | ||
3265 | /* Retain the exec, fs, key, and sock SIDs across fork */ | 3292 | tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp); |
3266 | tsec2->exec_sid = tsec1->exec_sid; | 3293 | if (!tsec) |
3267 | tsec2->create_sid = tsec1->create_sid; | 3294 | return -ENOMEM; |
3268 | tsec2->keycreate_sid = tsec1->keycreate_sid; | ||
3269 | tsec2->sockcreate_sid = tsec1->sockcreate_sid; | ||
3270 | 3295 | ||
3296 | new->security = tsec; | ||
3271 | return 0; | 3297 | return 0; |
3272 | } | 3298 | } |
3273 | 3299 | ||
3274 | /* | 3300 | /* |
3275 | * detach and free the LSM part of a set of credentials | 3301 | * commit new credentials |
3276 | */ | 3302 | */ |
3277 | static void selinux_cred_free(struct cred *cred) | 3303 | static void selinux_cred_commit(struct cred *new, const struct cred *old) |
3278 | { | 3304 | { |
3279 | struct task_security_struct *tsec = cred->security; | 3305 | secondary_ops->cred_commit(new, old); |
3280 | cred->security = NULL; | ||
3281 | kfree(tsec); | ||
3282 | } | 3306 | } |
3283 | 3307 | ||
3284 | static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) | 3308 | static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) |
@@ -3292,9 +3316,10 @@ static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) | |||
3292 | return 0; | 3316 | return 0; |
3293 | } | 3317 | } |
3294 | 3318 | ||
3295 | static int selinux_task_post_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) | 3319 | static int selinux_task_fix_setuid(struct cred *new, const struct cred *old, |
3320 | int flags) | ||
3296 | { | 3321 | { |
3297 | return secondary_ops->task_post_setuid(id0, id1, id2, flags); | 3322 | return secondary_ops->task_fix_setuid(new, old, flags); |
3298 | } | 3323 | } |
3299 | 3324 | ||
3300 | static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags) | 3325 | static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags) |
@@ -3368,7 +3393,7 @@ static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim | |||
3368 | /* Control the ability to change the hard limit (whether | 3393 | /* Control the ability to change the hard limit (whether |
3369 | lowering or raising it), so that the hard limit can | 3394 | lowering or raising it), so that the hard limit can |
3370 | later be used as a safe reset point for the soft limit | 3395 | later be used as a safe reset point for the soft limit |
3371 | upon context transitions. See selinux_bprm_apply_creds. */ | 3396 | upon context transitions. See selinux_bprm_committing_creds. */ |
3372 | if (old_rlim->rlim_max != new_rlim->rlim_max) | 3397 | if (old_rlim->rlim_max != new_rlim->rlim_max) |
3373 | return task_has_perm(current, current, PROCESS__SETRLIMIT); | 3398 | return task_has_perm(current, current, PROCESS__SETRLIMIT); |
3374 | 3399 | ||
@@ -3422,13 +3447,12 @@ static int selinux_task_prctl(int option, | |||
3422 | unsigned long arg2, | 3447 | unsigned long arg2, |
3423 | unsigned long arg3, | 3448 | unsigned long arg3, |
3424 | unsigned long arg4, | 3449 | unsigned long arg4, |
3425 | unsigned long arg5, | 3450 | unsigned long arg5) |
3426 | long *rc_p) | ||
3427 | { | 3451 | { |
3428 | /* The current prctl operations do not appear to require | 3452 | /* The current prctl operations do not appear to require |
3429 | any SELinux controls since they merely observe or modify | 3453 | any SELinux controls since they merely observe or modify |
3430 | the state of the current process. */ | 3454 | the state of the current process. */ |
3431 | return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p); | 3455 | return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5); |
3432 | } | 3456 | } |
3433 | 3457 | ||
3434 | static int selinux_task_wait(struct task_struct *p) | 3458 | static int selinux_task_wait(struct task_struct *p) |
@@ -3436,18 +3460,6 @@ static int selinux_task_wait(struct task_struct *p) | |||
3436 | return task_has_perm(p, current, PROCESS__SIGCHLD); | 3460 | return task_has_perm(p, current, PROCESS__SIGCHLD); |
3437 | } | 3461 | } |
3438 | 3462 | ||
3439 | static void selinux_task_reparent_to_init(struct task_struct *p) | ||
3440 | { | ||
3441 | struct task_security_struct *tsec; | ||
3442 | |||
3443 | secondary_ops->task_reparent_to_init(p); | ||
3444 | |||
3445 | tsec = p->cred->security; | ||
3446 | tsec->osid = tsec->sid; | ||
3447 | tsec->sid = SECINITSID_KERNEL; | ||
3448 | return; | ||
3449 | } | ||
3450 | |||
3451 | static void selinux_task_to_inode(struct task_struct *p, | 3463 | static void selinux_task_to_inode(struct task_struct *p, |
3452 | struct inode *inode) | 3464 | struct inode *inode) |
3453 | { | 3465 | { |
@@ -5325,7 +5337,8 @@ static int selinux_setprocattr(struct task_struct *p, | |||
5325 | { | 5337 | { |
5326 | struct task_security_struct *tsec; | 5338 | struct task_security_struct *tsec; |
5327 | struct task_struct *tracer; | 5339 | struct task_struct *tracer; |
5328 | u32 sid = 0; | 5340 | struct cred *new; |
5341 | u32 sid = 0, ptsid; | ||
5329 | int error; | 5342 | int error; |
5330 | char *str = value; | 5343 | char *str = value; |
5331 | 5344 | ||
@@ -5372,86 +5385,75 @@ static int selinux_setprocattr(struct task_struct *p, | |||
5372 | return error; | 5385 | return error; |
5373 | } | 5386 | } |
5374 | 5387 | ||
5388 | new = prepare_creds(); | ||
5389 | if (!new) | ||
5390 | return -ENOMEM; | ||
5391 | |||
5375 | /* Permission checking based on the specified context is | 5392 | /* Permission checking based on the specified context is |
5376 | performed during the actual operation (execve, | 5393 | performed during the actual operation (execve, |
5377 | open/mkdir/...), when we know the full context of the | 5394 | open/mkdir/...), when we know the full context of the |
5378 | operation. See selinux_bprm_set_security for the execve | 5395 | operation. See selinux_bprm_set_creds for the execve |
5379 | checks and may_create for the file creation checks. The | 5396 | checks and may_create for the file creation checks. The |
5380 | operation will then fail if the context is not permitted. */ | 5397 | operation will then fail if the context is not permitted. */ |
5381 | tsec = p->cred->security; | 5398 | tsec = new->security; |
5382 | if (!strcmp(name, "exec")) | 5399 | if (!strcmp(name, "exec")) { |
5383 | tsec->exec_sid = sid; | 5400 | tsec->exec_sid = sid; |
5384 | else if (!strcmp(name, "fscreate")) | 5401 | } else if (!strcmp(name, "fscreate")) { |
5385 | tsec->create_sid = sid; | 5402 | tsec->create_sid = sid; |
5386 | else if (!strcmp(name, "keycreate")) { | 5403 | } else if (!strcmp(name, "keycreate")) { |
5387 | error = may_create_key(sid, p); | 5404 | error = may_create_key(sid, p); |
5388 | if (error) | 5405 | if (error) |
5389 | return error; | 5406 | goto abort_change; |
5390 | tsec->keycreate_sid = sid; | 5407 | tsec->keycreate_sid = sid; |
5391 | } else if (!strcmp(name, "sockcreate")) | 5408 | } else if (!strcmp(name, "sockcreate")) { |
5392 | tsec->sockcreate_sid = sid; | 5409 | tsec->sockcreate_sid = sid; |
5393 | else if (!strcmp(name, "current")) { | 5410 | } else if (!strcmp(name, "current")) { |
5394 | struct av_decision avd; | 5411 | error = -EINVAL; |
5395 | |||
5396 | if (sid == 0) | 5412 | if (sid == 0) |
5397 | return -EINVAL; | 5413 | goto abort_change; |
5398 | /* | 5414 | |
5399 | * SELinux allows to change context in the following case only. | 5415 | /* Only allow single threaded processes to change context */ |
5400 | * - Single threaded processes. | 5416 | error = -EPERM; |
5401 | * - Multi threaded processes intend to change its context into | 5417 | if (!is_single_threaded(p)) { |
5402 | * more restricted domain (defined by TYPEBOUNDS statement). | 5418 | error = security_bounded_transition(tsec->sid, sid); |
5403 | */ | 5419 | if (error) |
5404 | if (atomic_read(&p->mm->mm_users) != 1) { | 5420 | goto abort_change; |
5405 | struct task_struct *g, *t; | ||
5406 | struct mm_struct *mm = p->mm; | ||
5407 | read_lock(&tasklist_lock); | ||
5408 | do_each_thread(g, t) { | ||
5409 | if (t->mm == mm && t != p) { | ||
5410 | read_unlock(&tasklist_lock); | ||
5411 | error = security_bounded_transition(tsec->sid, sid); | ||
5412 | if (!error) | ||
5413 | goto boundary_ok; | ||
5414 | |||
5415 | return error; | ||
5416 | } | ||
5417 | } while_each_thread(g, t); | ||
5418 | read_unlock(&tasklist_lock); | ||
5419 | } | 5421 | } |
5420 | boundary_ok: | ||
5421 | 5422 | ||
5422 | /* Check permissions for the transition. */ | 5423 | /* Check permissions for the transition. */ |
5423 | error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, | 5424 | error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, |
5424 | PROCESS__DYNTRANSITION, NULL); | 5425 | PROCESS__DYNTRANSITION, NULL); |
5425 | if (error) | 5426 | if (error) |
5426 | return error; | 5427 | goto abort_change; |
5427 | 5428 | ||
5428 | /* Check for ptracing, and update the task SID if ok. | 5429 | /* Check for ptracing, and update the task SID if ok. |
5429 | Otherwise, leave SID unchanged and fail. */ | 5430 | Otherwise, leave SID unchanged and fail. */ |
5431 | ptsid = 0; | ||
5430 | task_lock(p); | 5432 | task_lock(p); |
5431 | rcu_read_lock(); | ||
5432 | tracer = tracehook_tracer_task(p); | 5433 | tracer = tracehook_tracer_task(p); |
5433 | if (tracer != NULL) { | 5434 | if (tracer) |
5434 | u32 ptsid = task_sid(tracer); | 5435 | ptsid = task_sid(tracer); |
5435 | rcu_read_unlock(); | 5436 | task_unlock(p); |
5436 | error = avc_has_perm_noaudit(ptsid, sid, | 5437 | |
5437 | SECCLASS_PROCESS, | 5438 | if (tracer) { |
5438 | PROCESS__PTRACE, 0, &avd); | 5439 | error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, |
5439 | if (!error) | 5440 | PROCESS__PTRACE, NULL); |
5440 | tsec->sid = sid; | ||
5441 | task_unlock(p); | ||
5442 | avc_audit(ptsid, sid, SECCLASS_PROCESS, | ||
5443 | PROCESS__PTRACE, &avd, error, NULL); | ||
5444 | if (error) | 5441 | if (error) |
5445 | return error; | 5442 | goto abort_change; |
5446 | } else { | ||
5447 | rcu_read_unlock(); | ||
5448 | tsec->sid = sid; | ||
5449 | task_unlock(p); | ||
5450 | } | 5443 | } |
5451 | } else | ||
5452 | return -EINVAL; | ||
5453 | 5444 | ||
5445 | tsec->sid = sid; | ||
5446 | } else { | ||
5447 | error = -EINVAL; | ||
5448 | goto abort_change; | ||
5449 | } | ||
5450 | |||
5451 | commit_creds(new); | ||
5454 | return size; | 5452 | return size; |
5453 | |||
5454 | abort_change: | ||
5455 | abort_creds(new); | ||
5456 | return error; | ||
5455 | } | 5457 | } |
5456 | 5458 | ||
5457 | static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) | 5459 | static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) |
@@ -5471,23 +5473,21 @@ static void selinux_release_secctx(char *secdata, u32 seclen) | |||
5471 | 5473 | ||
5472 | #ifdef CONFIG_KEYS | 5474 | #ifdef CONFIG_KEYS |
5473 | 5475 | ||
5474 | static int selinux_key_alloc(struct key *k, struct task_struct *tsk, | 5476 | static int selinux_key_alloc(struct key *k, const struct cred *cred, |
5475 | unsigned long flags) | 5477 | unsigned long flags) |
5476 | { | 5478 | { |
5477 | const struct task_security_struct *__tsec; | 5479 | const struct task_security_struct *tsec; |
5478 | struct key_security_struct *ksec; | 5480 | struct key_security_struct *ksec; |
5479 | 5481 | ||
5480 | ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL); | 5482 | ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL); |
5481 | if (!ksec) | 5483 | if (!ksec) |
5482 | return -ENOMEM; | 5484 | return -ENOMEM; |
5483 | 5485 | ||
5484 | rcu_read_lock(); | 5486 | tsec = cred->security; |
5485 | __tsec = __task_cred(tsk)->security; | 5487 | if (tsec->keycreate_sid) |
5486 | if (__tsec->keycreate_sid) | 5488 | ksec->sid = tsec->keycreate_sid; |
5487 | ksec->sid = __tsec->keycreate_sid; | ||
5488 | else | 5489 | else |
5489 | ksec->sid = __tsec->sid; | 5490 | ksec->sid = tsec->sid; |
5490 | rcu_read_unlock(); | ||
5491 | 5491 | ||
5492 | k->security = ksec; | 5492 | k->security = ksec; |
5493 | return 0; | 5493 | return 0; |
@@ -5502,8 +5502,8 @@ static void selinux_key_free(struct key *k) | |||
5502 | } | 5502 | } |
5503 | 5503 | ||
5504 | static int selinux_key_permission(key_ref_t key_ref, | 5504 | static int selinux_key_permission(key_ref_t key_ref, |
5505 | struct task_struct *ctx, | 5505 | const struct cred *cred, |
5506 | key_perm_t perm) | 5506 | key_perm_t perm) |
5507 | { | 5507 | { |
5508 | struct key *key; | 5508 | struct key *key; |
5509 | struct key_security_struct *ksec; | 5509 | struct key_security_struct *ksec; |
@@ -5515,7 +5515,7 @@ static int selinux_key_permission(key_ref_t key_ref, | |||
5515 | if (perm == 0) | 5515 | if (perm == 0) |
5516 | return 0; | 5516 | return 0; |
5517 | 5517 | ||
5518 | sid = task_sid(ctx); | 5518 | sid = cred_sid(cred); |
5519 | 5519 | ||
5520 | key = key_ref_to_ptr(key_ref); | 5520 | key = key_ref_to_ptr(key_ref); |
5521 | ksec = key->security; | 5521 | ksec = key->security; |
@@ -5545,8 +5545,7 @@ static struct security_operations selinux_ops = { | |||
5545 | .ptrace_may_access = selinux_ptrace_may_access, | 5545 | .ptrace_may_access = selinux_ptrace_may_access, |
5546 | .ptrace_traceme = selinux_ptrace_traceme, | 5546 | .ptrace_traceme = selinux_ptrace_traceme, |
5547 | .capget = selinux_capget, | 5547 | .capget = selinux_capget, |
5548 | .capset_check = selinux_capset_check, | 5548 | .capset = selinux_capset, |
5549 | .capset_set = selinux_capset_set, | ||
5550 | .sysctl = selinux_sysctl, | 5549 | .sysctl = selinux_sysctl, |
5551 | .capable = selinux_capable, | 5550 | .capable = selinux_capable, |
5552 | .quotactl = selinux_quotactl, | 5551 | .quotactl = selinux_quotactl, |
@@ -5621,10 +5620,11 @@ static struct security_operations selinux_ops = { | |||
5621 | .dentry_open = selinux_dentry_open, | 5620 | .dentry_open = selinux_dentry_open, |
5622 | 5621 | ||
5623 | .task_create = selinux_task_create, | 5622 | .task_create = selinux_task_create, |
5624 | .cred_alloc_security = selinux_cred_alloc_security, | ||
5625 | .cred_free = selinux_cred_free, | 5623 | .cred_free = selinux_cred_free, |
5624 | .cred_prepare = selinux_cred_prepare, | ||
5625 | .cred_commit = selinux_cred_commit, | ||
5626 | .task_setuid = selinux_task_setuid, | 5626 | .task_setuid = selinux_task_setuid, |
5627 | .task_post_setuid = selinux_task_post_setuid, | 5627 | .task_fix_setuid = selinux_task_fix_setuid, |
5628 | .task_setgid = selinux_task_setgid, | 5628 | .task_setgid = selinux_task_setgid, |
5629 | .task_setpgid = selinux_task_setpgid, | 5629 | .task_setpgid = selinux_task_setpgid, |
5630 | .task_getpgid = selinux_task_getpgid, | 5630 | .task_getpgid = selinux_task_getpgid, |
@@ -5641,7 +5641,6 @@ static struct security_operations selinux_ops = { | |||
5641 | .task_kill = selinux_task_kill, | 5641 | .task_kill = selinux_task_kill, |
5642 | .task_wait = selinux_task_wait, | 5642 | .task_wait = selinux_task_wait, |
5643 | .task_prctl = selinux_task_prctl, | 5643 | .task_prctl = selinux_task_prctl, |
5644 | .task_reparent_to_init = selinux_task_reparent_to_init, | ||
5645 | .task_to_inode = selinux_task_to_inode, | 5644 | .task_to_inode = selinux_task_to_inode, |
5646 | 5645 | ||
5647 | .ipc_permission = selinux_ipc_permission, | 5646 | .ipc_permission = selinux_ipc_permission, |
@@ -5737,8 +5736,6 @@ static struct security_operations selinux_ops = { | |||
5737 | 5736 | ||
5738 | static __init int selinux_init(void) | 5737 | static __init int selinux_init(void) |
5739 | { | 5738 | { |
5740 | struct task_security_struct *tsec; | ||
5741 | |||
5742 | if (!security_module_enable(&selinux_ops)) { | 5739 | if (!security_module_enable(&selinux_ops)) { |
5743 | selinux_enabled = 0; | 5740 | selinux_enabled = 0; |
5744 | return 0; | 5741 | return 0; |
@@ -5752,10 +5749,7 @@ static __init int selinux_init(void) | |||
5752 | printk(KERN_INFO "SELinux: Initializing.\n"); | 5749 | printk(KERN_INFO "SELinux: Initializing.\n"); |
5753 | 5750 | ||
5754 | /* Set the security state for the initial task. */ | 5751 | /* Set the security state for the initial task. */ |
5755 | if (cred_alloc_security(current->cred)) | 5752 | cred_init_security(); |
5756 | panic("SELinux: Failed to initialize initial task.\n"); | ||
5757 | tsec = current->cred->security; | ||
5758 | tsec->osid = tsec->sid = SECINITSID_KERNEL; | ||
5759 | 5753 | ||
5760 | sel_inode_cache = kmem_cache_create("selinux_inode_security", | 5754 | sel_inode_cache = kmem_cache_create("selinux_inode_security", |
5761 | sizeof(struct inode_security_struct), | 5755 | sizeof(struct inode_security_struct), |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 11167fd567b9..e952b397153d 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -104,8 +104,7 @@ static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode) | |||
104 | if (rc != 0) | 104 | if (rc != 0) |
105 | return rc; | 105 | return rc; |
106 | 106 | ||
107 | rc = smk_access(current->cred->security, ctp->cred->security, | 107 | rc = smk_access(current_security(), task_security(ctp), MAY_READWRITE); |
108 | MAY_READWRITE); | ||
109 | if (rc != 0 && capable(CAP_MAC_OVERRIDE)) | 108 | if (rc != 0 && capable(CAP_MAC_OVERRIDE)) |
110 | return 0; | 109 | return 0; |
111 | return rc; | 110 | return rc; |
@@ -127,8 +126,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp) | |||
127 | if (rc != 0) | 126 | if (rc != 0) |
128 | return rc; | 127 | return rc; |
129 | 128 | ||
130 | rc = smk_access(ptp->cred->security, current->cred->security, | 129 | rc = smk_access(task_security(ptp), current_security(), MAY_READWRITE); |
131 | MAY_READWRITE); | ||
132 | if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE)) | 130 | if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE)) |
133 | return 0; | 131 | return 0; |
134 | return rc; | 132 | return rc; |
@@ -977,22 +975,6 @@ static int smack_file_receive(struct file *file) | |||
977 | */ | 975 | */ |
978 | 976 | ||
979 | /** | 977 | /** |
980 | * smack_cred_alloc_security - "allocate" a task cred blob | ||
981 | * @cred: the task creds in need of a blob | ||
982 | * | ||
983 | * Smack isn't using copies of blobs. Everyone | ||
984 | * points to an immutable list. No alloc required. | ||
985 | * No data copy required. | ||
986 | * | ||
987 | * Always returns 0 | ||
988 | */ | ||
989 | static int smack_cred_alloc_security(struct cred *cred) | ||
990 | { | ||
991 | cred->security = current_security(); | ||
992 | return 0; | ||
993 | } | ||
994 | |||
995 | /** | ||
996 | * smack_cred_free - "free" task-level security credentials | 978 | * smack_cred_free - "free" task-level security credentials |
997 | * @cred: the credentials in question | 979 | * @cred: the credentials in question |
998 | * | 980 | * |
@@ -1006,6 +988,30 @@ static void smack_cred_free(struct cred *cred) | |||
1006 | } | 988 | } |
1007 | 989 | ||
1008 | /** | 990 | /** |
991 | * smack_cred_prepare - prepare new set of credentials for modification | ||
992 | * @new: the new credentials | ||
993 | * @old: the original credentials | ||
994 | * @gfp: the atomicity of any memory allocations | ||
995 | * | ||
996 | * Prepare a new set of credentials for modification. | ||
997 | */ | ||
998 | static int smack_cred_prepare(struct cred *new, const struct cred *old, | ||
999 | gfp_t gfp) | ||
1000 | { | ||
1001 | new->security = old->security; | ||
1002 | return 0; | ||
1003 | } | ||
1004 | |||
1005 | /* | ||
1006 | * commit new credentials | ||
1007 | * @new: the new credentials | ||
1008 | * @old: the original credentials | ||
1009 | */ | ||
1010 | static void smack_cred_commit(struct cred *new, const struct cred *old) | ||
1011 | { | ||
1012 | } | ||
1013 | |||
1014 | /** | ||
1009 | * smack_task_setpgid - Smack check on setting pgid | 1015 | * smack_task_setpgid - Smack check on setting pgid |
1010 | * @p: the task object | 1016 | * @p: the task object |
1011 | * @pgid: unused | 1017 | * @pgid: unused |
@@ -2036,6 +2042,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value) | |||
2036 | static int smack_setprocattr(struct task_struct *p, char *name, | 2042 | static int smack_setprocattr(struct task_struct *p, char *name, |
2037 | void *value, size_t size) | 2043 | void *value, size_t size) |
2038 | { | 2044 | { |
2045 | struct cred *new; | ||
2039 | char *newsmack; | 2046 | char *newsmack; |
2040 | 2047 | ||
2041 | /* | 2048 | /* |
@@ -2058,7 +2065,11 @@ static int smack_setprocattr(struct task_struct *p, char *name, | |||
2058 | if (newsmack == NULL) | 2065 | if (newsmack == NULL) |
2059 | return -EINVAL; | 2066 | return -EINVAL; |
2060 | 2067 | ||
2061 | p->cred->security = newsmack; | 2068 | new = prepare_creds(); |
2069 | if (!new) | ||
2070 | return -ENOMEM; | ||
2071 | new->security = newsmack; | ||
2072 | commit_creds(new); | ||
2062 | return size; | 2073 | return size; |
2063 | } | 2074 | } |
2064 | 2075 | ||
@@ -2354,17 +2365,17 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
2354 | /** | 2365 | /** |
2355 | * smack_key_alloc - Set the key security blob | 2366 | * smack_key_alloc - Set the key security blob |
2356 | * @key: object | 2367 | * @key: object |
2357 | * @tsk: the task associated with the key | 2368 | * @cred: the credentials to use |
2358 | * @flags: unused | 2369 | * @flags: unused |
2359 | * | 2370 | * |
2360 | * No allocation required | 2371 | * No allocation required |
2361 | * | 2372 | * |
2362 | * Returns 0 | 2373 | * Returns 0 |
2363 | */ | 2374 | */ |
2364 | static int smack_key_alloc(struct key *key, struct task_struct *tsk, | 2375 | static int smack_key_alloc(struct key *key, const struct cred *cred, |
2365 | unsigned long flags) | 2376 | unsigned long flags) |
2366 | { | 2377 | { |
2367 | key->security = tsk->cred->security; | 2378 | key->security = cred->security; |
2368 | return 0; | 2379 | return 0; |
2369 | } | 2380 | } |
2370 | 2381 | ||
@@ -2382,14 +2393,14 @@ static void smack_key_free(struct key *key) | |||
2382 | /* | 2393 | /* |
2383 | * smack_key_permission - Smack access on a key | 2394 | * smack_key_permission - Smack access on a key |
2384 | * @key_ref: gets to the object | 2395 | * @key_ref: gets to the object |
2385 | * @context: task involved | 2396 | * @cred: the credentials to use |
2386 | * @perm: unused | 2397 | * @perm: unused |
2387 | * | 2398 | * |
2388 | * Return 0 if the task has read and write to the object, | 2399 | * Return 0 if the task has read and write to the object, |
2389 | * an error code otherwise | 2400 | * an error code otherwise |
2390 | */ | 2401 | */ |
2391 | static int smack_key_permission(key_ref_t key_ref, | 2402 | static int smack_key_permission(key_ref_t key_ref, |
2392 | struct task_struct *context, key_perm_t perm) | 2403 | const struct cred *cred, key_perm_t perm) |
2393 | { | 2404 | { |
2394 | struct key *keyp; | 2405 | struct key *keyp; |
2395 | 2406 | ||
@@ -2405,11 +2416,10 @@ static int smack_key_permission(key_ref_t key_ref, | |||
2405 | /* | 2416 | /* |
2406 | * This should not occur | 2417 | * This should not occur |
2407 | */ | 2418 | */ |
2408 | if (context->cred->security == NULL) | 2419 | if (cred->security == NULL) |
2409 | return -EACCES; | 2420 | return -EACCES; |
2410 | 2421 | ||
2411 | return smk_access(context->cred->security, keyp->security, | 2422 | return smk_access(cred->security, keyp->security, MAY_READWRITE); |
2412 | MAY_READWRITE); | ||
2413 | } | 2423 | } |
2414 | #endif /* CONFIG_KEYS */ | 2424 | #endif /* CONFIG_KEYS */ |
2415 | 2425 | ||
@@ -2580,8 +2590,7 @@ struct security_operations smack_ops = { | |||
2580 | .ptrace_may_access = smack_ptrace_may_access, | 2590 | .ptrace_may_access = smack_ptrace_may_access, |
2581 | .ptrace_traceme = smack_ptrace_traceme, | 2591 | .ptrace_traceme = smack_ptrace_traceme, |
2582 | .capget = cap_capget, | 2592 | .capget = cap_capget, |
2583 | .capset_check = cap_capset_check, | 2593 | .capset = cap_capset, |
2584 | .capset_set = cap_capset_set, | ||
2585 | .capable = cap_capable, | 2594 | .capable = cap_capable, |
2586 | .syslog = smack_syslog, | 2595 | .syslog = smack_syslog, |
2587 | .settime = cap_settime, | 2596 | .settime = cap_settime, |
@@ -2630,9 +2639,10 @@ struct security_operations smack_ops = { | |||
2630 | .file_send_sigiotask = smack_file_send_sigiotask, | 2639 | .file_send_sigiotask = smack_file_send_sigiotask, |
2631 | .file_receive = smack_file_receive, | 2640 | .file_receive = smack_file_receive, |
2632 | 2641 | ||
2633 | .cred_alloc_security = smack_cred_alloc_security, | ||
2634 | .cred_free = smack_cred_free, | 2642 | .cred_free = smack_cred_free, |
2635 | .task_post_setuid = cap_task_post_setuid, | 2643 | .cred_prepare = smack_cred_prepare, |
2644 | .cred_commit = smack_cred_commit, | ||
2645 | .task_fix_setuid = cap_task_fix_setuid, | ||
2636 | .task_setpgid = smack_task_setpgid, | 2646 | .task_setpgid = smack_task_setpgid, |
2637 | .task_getpgid = smack_task_getpgid, | 2647 | .task_getpgid = smack_task_getpgid, |
2638 | .task_getsid = smack_task_getsid, | 2648 | .task_getsid = smack_task_getsid, |
@@ -2645,7 +2655,6 @@ struct security_operations smack_ops = { | |||
2645 | .task_movememory = smack_task_movememory, | 2655 | .task_movememory = smack_task_movememory, |
2646 | .task_kill = smack_task_kill, | 2656 | .task_kill = smack_task_kill, |
2647 | .task_wait = smack_task_wait, | 2657 | .task_wait = smack_task_wait, |
2648 | .task_reparent_to_init = cap_task_reparent_to_init, | ||
2649 | .task_to_inode = smack_task_to_inode, | 2658 | .task_to_inode = smack_task_to_inode, |
2650 | .task_prctl = cap_task_prctl, | 2659 | .task_prctl = cap_task_prctl, |
2651 | 2660 | ||
@@ -2721,6 +2730,8 @@ struct security_operations smack_ops = { | |||
2721 | */ | 2730 | */ |
2722 | static __init int smack_init(void) | 2731 | static __init int smack_init(void) |
2723 | { | 2732 | { |
2733 | struct cred *cred; | ||
2734 | |||
2724 | if (!security_module_enable(&smack_ops)) | 2735 | if (!security_module_enable(&smack_ops)) |
2725 | return 0; | 2736 | return 0; |
2726 | 2737 | ||
@@ -2729,7 +2740,8 @@ static __init int smack_init(void) | |||
2729 | /* | 2740 | /* |
2730 | * Set the security state for the initial task. | 2741 | * Set the security state for the initial task. |
2731 | */ | 2742 | */ |
2732 | current->cred->security = &smack_known_floor.smk_known; | 2743 | cred = (struct cred *) current->cred; |
2744 | cred->security = &smack_known_floor.smk_known; | ||
2733 | 2745 | ||
2734 | /* | 2746 | /* |
2735 | * Initialize locks | 2747 | * Initialize locks |