diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-07 23:35:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-07 23:35:29 -0400 |
commit | 828f4257d1d33aed0f9ef82982dcb8ace8b7fe86 (patch) | |
tree | ce9e1fc4eaae2c66e8a5bba25579c32c229352b4 | |
parent | 44ccba3f7b230af1bd7ebe173cbf5803df1df486 (diff) | |
parent | fe8993b3a05cbba6318a54e0f85901aaea6fc244 (diff) |
Merge tag 'secureexec-v4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux
Pull secureexec update from Kees Cook:
"This series has the ultimate goal of providing a sane stack rlimit
when running set*id processes.
To do this, the bprm_secureexec LSM hook is collapsed into the
bprm_set_creds hook so the secureexec-ness of an exec can be
determined early enough to make decisions about rlimits and the
resulting memory layouts. Other logic acting on the secureexec-ness of
an exec is similarly consolidated. Capabilities needed some special
handling, but the refactoring removed other special handling, so that
was a wash"
* tag 'secureexec-v4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
exec: Consolidate pdeath_signal clearing
exec: Use sane stack rlimit under secureexec
exec: Consolidate dumpability logic
smack: Remove redundant pdeath_signal clearing
exec: Use secureexec for clearing pdeath_signal
exec: Use secureexec for setting dumpability
LSM: drop bprm_secureexec hook
commoncap: Move cap_elevated calculation into bprm_set_creds
commoncap: Refactor to remove bprm_secureexec hook
smack: Refactor to remove bprm_secureexec hook
selinux: Refactor to remove bprm_secureexec hook
apparmor: Refactor to remove bprm_secureexec hook
binfmt: Introduce secureexec flag
exec: Correct comments about "point of no return"
exec: Rename bprm->cred_prepared to called_set_creds
-rw-r--r-- | fs/binfmt_elf.c | 2 | ||||
-rw-r--r-- | fs/binfmt_elf_fdpic.c | 2 | ||||
-rw-r--r-- | fs/binfmt_flat.c | 2 | ||||
-rw-r--r-- | fs/exec.c | 56 | ||||
-rw-r--r-- | include/linux/binfmts.h | 24 | ||||
-rw-r--r-- | include/linux/lsm_hooks.h | 14 | ||||
-rw-r--r-- | include/linux/security.h | 7 | ||||
-rw-r--r-- | security/apparmor/domain.c | 21 | ||||
-rw-r--r-- | security/apparmor/include/domain.h | 1 | ||||
-rw-r--r-- | security/apparmor/include/file.h | 3 | ||||
-rw-r--r-- | security/apparmor/lsm.c | 1 | ||||
-rw-r--r-- | security/commoncap.c | 50 | ||||
-rw-r--r-- | security/security.c | 5 | ||||
-rw-r--r-- | security/selinux/hooks.c | 26 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 34 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.c | 2 |
16 files changed, 91 insertions, 159 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 6466153f2bf0..ec45d24875b1 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -252,7 +252,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | |||
252 | NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid)); | 252 | NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid)); |
253 | NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid)); | 253 | NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid)); |
254 | NEW_AUX_ENT(AT_EGID, from_kgid_munged(cred->user_ns, cred->egid)); | 254 | NEW_AUX_ENT(AT_EGID, from_kgid_munged(cred->user_ns, cred->egid)); |
255 | NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm)); | 255 | NEW_AUX_ENT(AT_SECURE, bprm->secureexec); |
256 | NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes); | 256 | NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes); |
257 | #ifdef ELF_HWCAP2 | 257 | #ifdef ELF_HWCAP2 |
258 | NEW_AUX_ENT(AT_HWCAP2, ELF_HWCAP2); | 258 | NEW_AUX_ENT(AT_HWCAP2, ELF_HWCAP2); |
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index cf93a4fad012..5aa9199dfb13 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c | |||
@@ -650,7 +650,7 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm, | |||
650 | NEW_AUX_ENT(AT_EUID, (elf_addr_t) from_kuid_munged(cred->user_ns, cred->euid)); | 650 | NEW_AUX_ENT(AT_EUID, (elf_addr_t) from_kuid_munged(cred->user_ns, cred->euid)); |
651 | NEW_AUX_ENT(AT_GID, (elf_addr_t) from_kgid_munged(cred->user_ns, cred->gid)); | 651 | NEW_AUX_ENT(AT_GID, (elf_addr_t) from_kgid_munged(cred->user_ns, cred->gid)); |
652 | NEW_AUX_ENT(AT_EGID, (elf_addr_t) from_kgid_munged(cred->user_ns, cred->egid)); | 652 | NEW_AUX_ENT(AT_EGID, (elf_addr_t) from_kgid_munged(cred->user_ns, cred->egid)); |
653 | NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm)); | 653 | NEW_AUX_ENT(AT_SECURE, bprm->secureexec); |
654 | NEW_AUX_ENT(AT_EXECFN, bprm->exec); | 654 | NEW_AUX_ENT(AT_EXECFN, bprm->exec); |
655 | 655 | ||
656 | #ifdef ARCH_DLINFO | 656 | #ifdef ARCH_DLINFO |
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index a1e6860b6f46..604a176df0c2 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c | |||
@@ -890,7 +890,7 @@ static int load_flat_shared_library(int id, struct lib_info *libs) | |||
890 | * as we're past the point of no return and are dealing with shared | 890 | * as we're past the point of no return and are dealing with shared |
891 | * libraries. | 891 | * libraries. |
892 | */ | 892 | */ |
893 | bprm.cred_prepared = 1; | 893 | bprm.called_set_creds = 1; |
894 | 894 | ||
895 | res = prepare_binprm(&bprm); | 895 | res = prepare_binprm(&bprm); |
896 | 896 | ||
@@ -1259,6 +1259,12 @@ void __set_task_comm(struct task_struct *tsk, const char *buf, bool exec) | |||
1259 | perf_event_comm(tsk, exec); | 1259 | perf_event_comm(tsk, exec); |
1260 | } | 1260 | } |
1261 | 1261 | ||
1262 | /* | ||
1263 | * Calling this is the point of no return. None of the failures will be | ||
1264 | * seen by userspace since either the process is already taking a fatal | ||
1265 | * signal (via de_thread() or coredump), or will have SEGV raised | ||
1266 | * (after exec_mmap()) by search_binary_handlers (see below). | ||
1267 | */ | ||
1262 | int flush_old_exec(struct linux_binprm * bprm) | 1268 | int flush_old_exec(struct linux_binprm * bprm) |
1263 | { | 1269 | { |
1264 | int retval; | 1270 | int retval; |
@@ -1286,7 +1292,13 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
1286 | if (retval) | 1292 | if (retval) |
1287 | goto out; | 1293 | goto out; |
1288 | 1294 | ||
1289 | bprm->mm = NULL; /* We're using it now */ | 1295 | /* |
1296 | * After clearing bprm->mm (to mark that current is using the | ||
1297 | * prepared mm now), we have nothing left of the original | ||
1298 | * process. If anything from here on returns an error, the check | ||
1299 | * in search_binary_handler() will SEGV current. | ||
1300 | */ | ||
1301 | bprm->mm = NULL; | ||
1290 | 1302 | ||
1291 | set_fs(USER_DS); | 1303 | set_fs(USER_DS); |
1292 | current->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD | | 1304 | current->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD | |
@@ -1331,15 +1343,38 @@ EXPORT_SYMBOL(would_dump); | |||
1331 | 1343 | ||
1332 | void setup_new_exec(struct linux_binprm * bprm) | 1344 | void setup_new_exec(struct linux_binprm * bprm) |
1333 | { | 1345 | { |
1346 | /* | ||
1347 | * Once here, prepare_binrpm() will not be called any more, so | ||
1348 | * the final state of setuid/setgid/fscaps can be merged into the | ||
1349 | * secureexec flag. | ||
1350 | */ | ||
1351 | bprm->secureexec |= bprm->cap_elevated; | ||
1352 | |||
1353 | if (bprm->secureexec) { | ||
1354 | /* Make sure parent cannot signal privileged process. */ | ||
1355 | current->pdeath_signal = 0; | ||
1356 | |||
1357 | /* | ||
1358 | * For secureexec, reset the stack limit to sane default to | ||
1359 | * avoid bad behavior from the prior rlimits. This has to | ||
1360 | * happen before arch_pick_mmap_layout(), which examines | ||
1361 | * RLIMIT_STACK, but after the point of no return to avoid | ||
1362 | * needing to clean up the change on failure. | ||
1363 | */ | ||
1364 | if (current->signal->rlim[RLIMIT_STACK].rlim_cur > _STK_LIM) | ||
1365 | current->signal->rlim[RLIMIT_STACK].rlim_cur = _STK_LIM; | ||
1366 | } | ||
1367 | |||
1334 | arch_pick_mmap_layout(current->mm); | 1368 | arch_pick_mmap_layout(current->mm); |
1335 | 1369 | ||
1336 | /* This is the point of no return */ | ||
1337 | current->sas_ss_sp = current->sas_ss_size = 0; | 1370 | current->sas_ss_sp = current->sas_ss_size = 0; |
1338 | 1371 | ||
1339 | if (uid_eq(current_euid(), current_uid()) && gid_eq(current_egid(), current_gid())) | 1372 | /* Figure out dumpability. */ |
1340 | set_dumpable(current->mm, SUID_DUMP_USER); | 1373 | if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP || |
1341 | else | 1374 | bprm->secureexec) |
1342 | set_dumpable(current->mm, suid_dumpable); | 1375 | set_dumpable(current->mm, suid_dumpable); |
1376 | else | ||
1377 | set_dumpable(current->mm, SUID_DUMP_USER); | ||
1343 | 1378 | ||
1344 | arch_setup_new_exec(); | 1379 | arch_setup_new_exec(); |
1345 | perf_event_exec(); | 1380 | perf_event_exec(); |
@@ -1351,15 +1386,6 @@ void setup_new_exec(struct linux_binprm * bprm) | |||
1351 | */ | 1386 | */ |
1352 | current->mm->task_size = TASK_SIZE; | 1387 | current->mm->task_size = TASK_SIZE; |
1353 | 1388 | ||
1354 | /* install the new credentials */ | ||
1355 | if (!uid_eq(bprm->cred->uid, current_euid()) || | ||
1356 | !gid_eq(bprm->cred->gid, current_egid())) { | ||
1357 | current->pdeath_signal = 0; | ||
1358 | } else { | ||
1359 | if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) | ||
1360 | set_dumpable(current->mm, suid_dumpable); | ||
1361 | } | ||
1362 | |||
1363 | /* An exec changes our domain. We are no longer part of the thread | 1389 | /* An exec changes our domain. We are no longer part of the thread |
1364 | group */ | 1390 | group */ |
1365 | current->self_exec_id++; | 1391 | current->self_exec_id++; |
@@ -1548,7 +1574,7 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
1548 | retval = security_bprm_set_creds(bprm); | 1574 | retval = security_bprm_set_creds(bprm); |
1549 | if (retval) | 1575 | if (retval) |
1550 | return retval; | 1576 | return retval; |
1551 | bprm->cred_prepared = 1; | 1577 | bprm->called_set_creds = 1; |
1552 | 1578 | ||
1553 | memset(bprm->buf, 0, BINPRM_BUF_SIZE); | 1579 | memset(bprm->buf, 0, BINPRM_BUF_SIZE); |
1554 | return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE); | 1580 | return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE); |
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 3ae9013eeaaa..fb44d6180ca0 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h | |||
@@ -25,11 +25,25 @@ struct linux_binprm { | |||
25 | struct mm_struct *mm; | 25 | struct mm_struct *mm; |
26 | unsigned long p; /* current top of mem */ | 26 | unsigned long p; /* current top of mem */ |
27 | unsigned int | 27 | unsigned int |
28 | cred_prepared:1,/* true if creds already prepared (multiple | 28 | /* |
29 | * preps happen for interpreters) */ | 29 | * True after the bprm_set_creds hook has been called once |
30 | cap_effective:1;/* true if has elevated effective capabilities, | 30 | * (multiple calls can be made via prepare_binprm() for |
31 | * false if not; except for init which inherits | 31 | * binfmt_script/misc). |
32 | * its parent's caps anyway */ | 32 | */ |
33 | called_set_creds:1, | ||
34 | /* | ||
35 | * True if most recent call to the commoncaps bprm_set_creds | ||
36 | * hook (due to multiple prepare_binprm() calls from the | ||
37 | * binfmt_script/misc handlers) resulted in elevated | ||
38 | * privileges. | ||
39 | */ | ||
40 | cap_elevated:1, | ||
41 | /* | ||
42 | * Set by bprm_set_creds hook to indicate a privilege-gaining | ||
43 | * exec has happened. Used to sanitize execution environment | ||
44 | * and to set AT_SECURE auxv for glibc. | ||
45 | */ | ||
46 | secureexec:1; | ||
33 | #ifdef __alpha__ | 47 | #ifdef __alpha__ |
34 | unsigned int taso:1; | 48 | unsigned int taso:1; |
35 | #endif | 49 | #endif |
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 3a90febadbe2..d1c7bef25691 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h | |||
@@ -43,7 +43,11 @@ | |||
43 | * interpreters. The hook can tell whether it has already been called by | 43 | * interpreters. The hook can tell whether it has already been called by |
44 | * checking to see if @bprm->security is non-NULL. If so, then the hook | 44 | * checking to see if @bprm->security is non-NULL. If so, then the hook |
45 | * may decide either to retain the security information saved earlier or | 45 | * may decide either to retain the security information saved earlier or |
46 | * to replace it. | 46 | * to replace it. The hook must set @bprm->secureexec to 1 if a "secure |
47 | * exec" has happened as a result of this hook call. The flag is used to | ||
48 | * indicate the need for a sanitized execution environment, and is also | ||
49 | * passed in the ELF auxiliary table on the initial stack to indicate | ||
50 | * whether libc should enable secure mode. | ||
47 | * @bprm contains the linux_binprm structure. | 51 | * @bprm contains the linux_binprm structure. |
48 | * Return 0 if the hook is successful and permission is granted. | 52 | * Return 0 if the hook is successful and permission is granted. |
49 | * @bprm_check_security: | 53 | * @bprm_check_security: |
@@ -71,12 +75,6 @@ | |||
71 | * linux_binprm structure. This hook is a good place to perform state | 75 | * linux_binprm structure. This hook is a good place to perform state |
72 | * changes on the process such as clearing out non-inheritable signal | 76 | * changes on the process such as clearing out non-inheritable signal |
73 | * state. This is called immediately after commit_creds(). | 77 | * state. This is called immediately after commit_creds(). |
74 | * @bprm_secureexec: | ||
75 | * Return a boolean value (0 or 1) indicating whether a "secure exec" | ||
76 | * is required. The flag is passed in the auxiliary table | ||
77 | * on the initial stack to the ELF interpreter to indicate whether libc | ||
78 | * should enable secure mode. | ||
79 | * @bprm contains the linux_binprm structure. | ||
80 | * | 78 | * |
81 | * Security hooks for filesystem operations. | 79 | * Security hooks for filesystem operations. |
82 | * | 80 | * |
@@ -1388,7 +1386,6 @@ union security_list_options { | |||
1388 | 1386 | ||
1389 | int (*bprm_set_creds)(struct linux_binprm *bprm); | 1387 | int (*bprm_set_creds)(struct linux_binprm *bprm); |
1390 | int (*bprm_check_security)(struct linux_binprm *bprm); | 1388 | int (*bprm_check_security)(struct linux_binprm *bprm); |
1391 | int (*bprm_secureexec)(struct linux_binprm *bprm); | ||
1392 | void (*bprm_committing_creds)(struct linux_binprm *bprm); | 1389 | void (*bprm_committing_creds)(struct linux_binprm *bprm); |
1393 | void (*bprm_committed_creds)(struct linux_binprm *bprm); | 1390 | void (*bprm_committed_creds)(struct linux_binprm *bprm); |
1394 | 1391 | ||
@@ -1710,7 +1707,6 @@ struct security_hook_heads { | |||
1710 | struct list_head vm_enough_memory; | 1707 | struct list_head vm_enough_memory; |
1711 | struct list_head bprm_set_creds; | 1708 | struct list_head bprm_set_creds; |
1712 | struct list_head bprm_check_security; | 1709 | struct list_head bprm_check_security; |
1713 | struct list_head bprm_secureexec; | ||
1714 | struct list_head bprm_committing_creds; | 1710 | struct list_head bprm_committing_creds; |
1715 | struct list_head bprm_committed_creds; | 1711 | struct list_head bprm_committed_creds; |
1716 | struct list_head sb_alloc_security; | 1712 | struct list_head sb_alloc_security; |
diff --git a/include/linux/security.h b/include/linux/security.h index b6ea1dc9cc9d..974bb9b0996c 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -85,7 +85,6 @@ extern int cap_capset(struct cred *new, const struct cred *old, | |||
85 | const kernel_cap_t *inheritable, | 85 | const kernel_cap_t *inheritable, |
86 | const kernel_cap_t *permitted); | 86 | const kernel_cap_t *permitted); |
87 | extern int cap_bprm_set_creds(struct linux_binprm *bprm); | 87 | extern int cap_bprm_set_creds(struct linux_binprm *bprm); |
88 | extern int cap_bprm_secureexec(struct linux_binprm *bprm); | ||
89 | extern int cap_inode_setxattr(struct dentry *dentry, const char *name, | 88 | extern int cap_inode_setxattr(struct dentry *dentry, const char *name, |
90 | const void *value, size_t size, int flags); | 89 | const void *value, size_t size, int flags); |
91 | extern int cap_inode_removexattr(struct dentry *dentry, const char *name); | 90 | extern int cap_inode_removexattr(struct dentry *dentry, const char *name); |
@@ -232,7 +231,6 @@ int security_bprm_set_creds(struct linux_binprm *bprm); | |||
232 | int security_bprm_check(struct linux_binprm *bprm); | 231 | int security_bprm_check(struct linux_binprm *bprm); |
233 | void security_bprm_committing_creds(struct linux_binprm *bprm); | 232 | void security_bprm_committing_creds(struct linux_binprm *bprm); |
234 | void security_bprm_committed_creds(struct linux_binprm *bprm); | 233 | void security_bprm_committed_creds(struct linux_binprm *bprm); |
235 | int security_bprm_secureexec(struct linux_binprm *bprm); | ||
236 | int security_sb_alloc(struct super_block *sb); | 234 | int security_sb_alloc(struct super_block *sb); |
237 | void security_sb_free(struct super_block *sb); | 235 | void security_sb_free(struct super_block *sb); |
238 | int security_sb_copy_data(char *orig, char *copy); | 236 | int security_sb_copy_data(char *orig, char *copy); |
@@ -541,11 +539,6 @@ static inline void security_bprm_committed_creds(struct linux_binprm *bprm) | |||
541 | { | 539 | { |
542 | } | 540 | } |
543 | 541 | ||
544 | static inline int security_bprm_secureexec(struct linux_binprm *bprm) | ||
545 | { | ||
546 | return cap_bprm_secureexec(bprm); | ||
547 | } | ||
548 | |||
549 | static inline int security_sb_alloc(struct super_block *sb) | 542 | static inline int security_sb_alloc(struct super_block *sb) |
550 | { | 543 | { |
551 | return 0; | 544 | return 0; |
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index d0594446ae3f..17a601c67b62 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c | |||
@@ -758,7 +758,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) | |||
758 | file_inode(bprm->file)->i_mode | 758 | file_inode(bprm->file)->i_mode |
759 | }; | 759 | }; |
760 | 760 | ||
761 | if (bprm->cred_prepared) | 761 | if (bprm->called_set_creds) |
762 | return 0; | 762 | return 0; |
763 | 763 | ||
764 | ctx = cred_ctx(bprm->cred); | 764 | ctx = cred_ctx(bprm->cred); |
@@ -807,7 +807,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) | |||
807 | aa_label_printk(new, GFP_ATOMIC); | 807 | aa_label_printk(new, GFP_ATOMIC); |
808 | dbg_printk("\n"); | 808 | dbg_printk("\n"); |
809 | } | 809 | } |
810 | bprm->unsafe |= AA_SECURE_X_NEEDED; | 810 | bprm->secureexec = 1; |
811 | } | 811 | } |
812 | 812 | ||
813 | if (label->proxy != new->proxy) { | 813 | if (label->proxy != new->proxy) { |
@@ -843,23 +843,6 @@ audit: | |||
843 | goto done; | 843 | goto done; |
844 | } | 844 | } |
845 | 845 | ||
846 | /** | ||
847 | * apparmor_bprm_secureexec - determine if secureexec is needed | ||
848 | * @bprm: binprm for exec (NOT NULL) | ||
849 | * | ||
850 | * Returns: %1 if secureexec is needed else %0 | ||
851 | */ | ||
852 | int apparmor_bprm_secureexec(struct linux_binprm *bprm) | ||
853 | { | ||
854 | /* the decision to use secure exec is computed in set_creds | ||
855 | * and stored in bprm->unsafe. | ||
856 | */ | ||
857 | if (bprm->unsafe & AA_SECURE_X_NEEDED) | ||
858 | return 1; | ||
859 | |||
860 | return 0; | ||
861 | } | ||
862 | |||
863 | /* | 846 | /* |
864 | * Functions for self directed profile change | 847 | * Functions for self directed profile change |
865 | */ | 848 | */ |
diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h index bab5810b6e9a..24c5976d6143 100644 --- a/security/apparmor/include/domain.h +++ b/security/apparmor/include/domain.h | |||
@@ -30,7 +30,6 @@ struct aa_domain { | |||
30 | #define AA_CHANGE_STACK 8 | 30 | #define AA_CHANGE_STACK 8 |
31 | 31 | ||
32 | int apparmor_bprm_set_creds(struct linux_binprm *bprm); | 32 | int apparmor_bprm_set_creds(struct linux_binprm *bprm); |
33 | int apparmor_bprm_secureexec(struct linux_binprm *bprm); | ||
34 | 33 | ||
35 | void aa_free_domain_entries(struct aa_domain *domain); | 34 | void aa_free_domain_entries(struct aa_domain *domain); |
36 | int aa_change_hat(const char *hats[], int count, u64 token, int flags); | 35 | int aa_change_hat(const char *hats[], int count, u64 token, int flags); |
diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index 001e40073ff9..4c2c8ac8842f 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h | |||
@@ -101,9 +101,6 @@ static inline struct aa_label *aa_get_file_label(struct aa_file_ctx *ctx) | |||
101 | #define AA_X_INHERIT 0x4000 | 101 | #define AA_X_INHERIT 0x4000 |
102 | #define AA_X_UNCONFINED 0x8000 | 102 | #define AA_X_UNCONFINED 0x8000 |
103 | 103 | ||
104 | /* AA_SECURE_X_NEEDED - is passed in the bprm->unsafe field */ | ||
105 | #define AA_SECURE_X_NEEDED 0x8000 | ||
106 | |||
107 | /* need to make conditional which ones are being set */ | 104 | /* need to make conditional which ones are being set */ |
108 | struct path_cond { | 105 | struct path_cond { |
109 | kuid_t uid; | 106 | kuid_t uid; |
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 867bcd154c7e..7a82c0f61452 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c | |||
@@ -694,7 +694,6 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { | |||
694 | LSM_HOOK_INIT(bprm_set_creds, apparmor_bprm_set_creds), | 694 | LSM_HOOK_INIT(bprm_set_creds, apparmor_bprm_set_creds), |
695 | LSM_HOOK_INIT(bprm_committing_creds, apparmor_bprm_committing_creds), | 695 | LSM_HOOK_INIT(bprm_committing_creds, apparmor_bprm_committing_creds), |
696 | LSM_HOOK_INIT(bprm_committed_creds, apparmor_bprm_committed_creds), | 696 | LSM_HOOK_INIT(bprm_committed_creds, apparmor_bprm_committed_creds), |
697 | LSM_HOOK_INIT(bprm_secureexec, apparmor_bprm_secureexec), | ||
698 | 697 | ||
699 | LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit), | 698 | LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit), |
700 | }; | 699 | }; |
diff --git a/security/commoncap.c b/security/commoncap.c index 7abebd782d5e..d8e26fb9781d 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -285,15 +285,6 @@ int cap_capset(struct cred *new, | |||
285 | return 0; | 285 | return 0; |
286 | } | 286 | } |
287 | 287 | ||
288 | /* | ||
289 | * Clear proposed capability sets for execve(). | ||
290 | */ | ||
291 | static inline void bprm_clear_caps(struct linux_binprm *bprm) | ||
292 | { | ||
293 | cap_clear(bprm->cred->cap_permitted); | ||
294 | bprm->cap_effective = false; | ||
295 | } | ||
296 | |||
297 | /** | 288 | /** |
298 | * cap_inode_need_killpriv - Determine if inode change affects privileges | 289 | * cap_inode_need_killpriv - Determine if inode change affects privileges |
299 | * @dentry: The inode/dentry in being changed with change marked ATTR_KILL_PRIV | 290 | * @dentry: The inode/dentry in being changed with change marked ATTR_KILL_PRIV |
@@ -443,7 +434,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c | |||
443 | int rc = 0; | 434 | int rc = 0; |
444 | struct cpu_vfs_cap_data vcaps; | 435 | struct cpu_vfs_cap_data vcaps; |
445 | 436 | ||
446 | bprm_clear_caps(bprm); | 437 | cap_clear(bprm->cred->cap_permitted); |
447 | 438 | ||
448 | if (!file_caps_enabled) | 439 | if (!file_caps_enabled) |
449 | return 0; | 440 | return 0; |
@@ -476,7 +467,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c | |||
476 | 467 | ||
477 | out: | 468 | out: |
478 | if (rc) | 469 | if (rc) |
479 | bprm_clear_caps(bprm); | 470 | cap_clear(bprm->cred->cap_permitted); |
480 | 471 | ||
481 | return rc; | 472 | return rc; |
482 | } | 473 | } |
@@ -585,8 +576,6 @@ skip: | |||
585 | if (WARN_ON(!cap_ambient_invariant_ok(new))) | 576 | if (WARN_ON(!cap_ambient_invariant_ok(new))) |
586 | return -EPERM; | 577 | return -EPERM; |
587 | 578 | ||
588 | bprm->cap_effective = effective; | ||
589 | |||
590 | /* | 579 | /* |
591 | * Audit candidate if current->cap_effective is set | 580 | * Audit candidate if current->cap_effective is set |
592 | * | 581 | * |
@@ -614,33 +603,17 @@ skip: | |||
614 | if (WARN_ON(!cap_ambient_invariant_ok(new))) | 603 | if (WARN_ON(!cap_ambient_invariant_ok(new))) |
615 | return -EPERM; | 604 | return -EPERM; |
616 | 605 | ||
617 | return 0; | 606 | /* Check for privilege-elevated exec. */ |
618 | } | 607 | bprm->cap_elevated = 0; |
619 | 608 | if (is_setid) { | |
620 | /** | 609 | bprm->cap_elevated = 1; |
621 | * cap_bprm_secureexec - Determine whether a secure execution is required | 610 | } else if (!uid_eq(new->uid, root_uid)) { |
622 | * @bprm: The execution parameters | 611 | if (effective || |
623 | * | 612 | !cap_issubset(new->cap_permitted, new->cap_ambient)) |
624 | * Determine whether a secure execution is required, return 1 if it is, and 0 | 613 | bprm->cap_elevated = 1; |
625 | * if it is not. | ||
626 | * | ||
627 | * The credentials have been committed by this point, and so are no longer | ||
628 | * available through @bprm->cred. | ||
629 | */ | ||
630 | int cap_bprm_secureexec(struct linux_binprm *bprm) | ||
631 | { | ||
632 | const struct cred *cred = current_cred(); | ||
633 | kuid_t root_uid = make_kuid(cred->user_ns, 0); | ||
634 | |||
635 | if (!uid_eq(cred->uid, root_uid)) { | ||
636 | if (bprm->cap_effective) | ||
637 | return 1; | ||
638 | if (!cap_issubset(cred->cap_permitted, cred->cap_ambient)) | ||
639 | return 1; | ||
640 | } | 614 | } |
641 | 615 | ||
642 | return (!uid_eq(cred->euid, cred->uid) || | 616 | return 0; |
643 | !gid_eq(cred->egid, cred->gid)); | ||
644 | } | 617 | } |
645 | 618 | ||
646 | /** | 619 | /** |
@@ -1079,7 +1052,6 @@ struct security_hook_list capability_hooks[] __lsm_ro_after_init = { | |||
1079 | LSM_HOOK_INIT(capget, cap_capget), | 1052 | LSM_HOOK_INIT(capget, cap_capget), |
1080 | LSM_HOOK_INIT(capset, cap_capset), | 1053 | LSM_HOOK_INIT(capset, cap_capset), |
1081 | LSM_HOOK_INIT(bprm_set_creds, cap_bprm_set_creds), | 1054 | LSM_HOOK_INIT(bprm_set_creds, cap_bprm_set_creds), |
1082 | LSM_HOOK_INIT(bprm_secureexec, cap_bprm_secureexec), | ||
1083 | LSM_HOOK_INIT(inode_need_killpriv, cap_inode_need_killpriv), | 1055 | LSM_HOOK_INIT(inode_need_killpriv, cap_inode_need_killpriv), |
1084 | LSM_HOOK_INIT(inode_killpriv, cap_inode_killpriv), | 1056 | LSM_HOOK_INIT(inode_killpriv, cap_inode_killpriv), |
1085 | LSM_HOOK_INIT(mmap_addr, cap_mmap_addr), | 1057 | LSM_HOOK_INIT(mmap_addr, cap_mmap_addr), |
diff --git a/security/security.c b/security/security.c index 30132378d103..afc34f46c6c5 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -351,11 +351,6 @@ void security_bprm_committed_creds(struct linux_binprm *bprm) | |||
351 | call_void_hook(bprm_committed_creds, bprm); | 351 | call_void_hook(bprm_committed_creds, bprm); |
352 | } | 352 | } |
353 | 353 | ||
354 | int security_bprm_secureexec(struct linux_binprm *bprm) | ||
355 | { | ||
356 | return call_int_hook(bprm_secureexec, 0, bprm); | ||
357 | } | ||
358 | |||
359 | int security_sb_alloc(struct super_block *sb) | 354 | int security_sb_alloc(struct super_block *sb) |
360 | { | 355 | { |
361 | return call_int_hook(sb_alloc_security, 0, sb); | 356 | return call_int_hook(sb_alloc_security, 0, sb); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 2f2e1338cd3d..ad3b0f53ede0 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -2356,7 +2356,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
2356 | 2356 | ||
2357 | /* SELinux context only depends on initial program or script and not | 2357 | /* SELinux context only depends on initial program or script and not |
2358 | * the script interpreter */ | 2358 | * the script interpreter */ |
2359 | if (bprm->cred_prepared) | 2359 | if (bprm->called_set_creds) |
2360 | return 0; | 2360 | return 0; |
2361 | 2361 | ||
2362 | old_tsec = current_security(); | 2362 | old_tsec = current_security(); |
@@ -2442,30 +2442,17 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
2442 | 2442 | ||
2443 | /* Clear any possibly unsafe personality bits on exec: */ | 2443 | /* Clear any possibly unsafe personality bits on exec: */ |
2444 | bprm->per_clear |= PER_CLEAR_ON_SETID; | 2444 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
2445 | } | ||
2446 | |||
2447 | return 0; | ||
2448 | } | ||
2449 | |||
2450 | static int selinux_bprm_secureexec(struct linux_binprm *bprm) | ||
2451 | { | ||
2452 | const struct task_security_struct *tsec = current_security(); | ||
2453 | u32 sid, osid; | ||
2454 | int atsecure = 0; | ||
2455 | |||
2456 | sid = tsec->sid; | ||
2457 | osid = tsec->osid; | ||
2458 | 2445 | ||
2459 | if (osid != sid) { | ||
2460 | /* Enable secure mode for SIDs transitions unless | 2446 | /* Enable secure mode for SIDs transitions unless |
2461 | the noatsecure permission is granted between | 2447 | the noatsecure permission is granted between |
2462 | the two SIDs, i.e. ahp returns 0. */ | 2448 | the two SIDs, i.e. ahp returns 0. */ |
2463 | atsecure = avc_has_perm(osid, sid, | 2449 | rc = avc_has_perm(old_tsec->sid, new_tsec->sid, |
2464 | SECCLASS_PROCESS, | 2450 | SECCLASS_PROCESS, PROCESS__NOATSECURE, |
2465 | PROCESS__NOATSECURE, NULL); | 2451 | NULL); |
2452 | bprm->secureexec |= !!rc; | ||
2466 | } | 2453 | } |
2467 | 2454 | ||
2468 | return !!atsecure; | 2455 | return 0; |
2469 | } | 2456 | } |
2470 | 2457 | ||
2471 | static int match_file(const void *p, struct file *file, unsigned fd) | 2458 | static int match_file(const void *p, struct file *file, unsigned fd) |
@@ -6266,7 +6253,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { | |||
6266 | LSM_HOOK_INIT(bprm_set_creds, selinux_bprm_set_creds), | 6253 | LSM_HOOK_INIT(bprm_set_creds, selinux_bprm_set_creds), |
6267 | LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds), | 6254 | LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds), |
6268 | LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds), | 6255 | LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds), |
6269 | LSM_HOOK_INIT(bprm_secureexec, selinux_bprm_secureexec), | ||
6270 | 6256 | ||
6271 | LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security), | 6257 | LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security), |
6272 | LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security), | 6258 | LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security), |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 463af86812c7..319add31b4a4 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -917,7 +917,7 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) | |||
917 | struct superblock_smack *sbsp; | 917 | struct superblock_smack *sbsp; |
918 | int rc; | 918 | int rc; |
919 | 919 | ||
920 | if (bprm->cred_prepared) | 920 | if (bprm->called_set_creds) |
921 | return 0; | 921 | return 0; |
922 | 922 | ||
923 | isp = inode->i_security; | 923 | isp = inode->i_security; |
@@ -950,35 +950,9 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) | |||
950 | bsp->smk_task = isp->smk_task; | 950 | bsp->smk_task = isp->smk_task; |
951 | bprm->per_clear |= PER_CLEAR_ON_SETID; | 951 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
952 | 952 | ||
953 | return 0; | 953 | /* Decide if this is a secure exec. */ |
954 | } | ||
955 | |||
956 | /** | ||
957 | * smack_bprm_committing_creds - Prepare to install the new credentials | ||
958 | * from bprm. | ||
959 | * | ||
960 | * @bprm: binprm for exec | ||
961 | */ | ||
962 | static void smack_bprm_committing_creds(struct linux_binprm *bprm) | ||
963 | { | ||
964 | struct task_smack *bsp = bprm->cred->security; | ||
965 | |||
966 | if (bsp->smk_task != bsp->smk_forked) | 954 | if (bsp->smk_task != bsp->smk_forked) |
967 | current->pdeath_signal = 0; | 955 | bprm->secureexec = 1; |
968 | } | ||
969 | |||
970 | /** | ||
971 | * smack_bprm_secureexec - Return the decision to use secureexec. | ||
972 | * @bprm: binprm for exec | ||
973 | * | ||
974 | * Returns 0 on success. | ||
975 | */ | ||
976 | static int smack_bprm_secureexec(struct linux_binprm *bprm) | ||
977 | { | ||
978 | struct task_smack *tsp = current_security(); | ||
979 | |||
980 | if (tsp->smk_task != tsp->smk_forked) | ||
981 | return 1; | ||
982 | 956 | ||
983 | return 0; | 957 | return 0; |
984 | } | 958 | } |
@@ -4645,8 +4619,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { | |||
4645 | LSM_HOOK_INIT(sb_parse_opts_str, smack_parse_opts_str), | 4619 | LSM_HOOK_INIT(sb_parse_opts_str, smack_parse_opts_str), |
4646 | 4620 | ||
4647 | LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds), | 4621 | LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds), |
4648 | LSM_HOOK_INIT(bprm_committing_creds, smack_bprm_committing_creds), | ||
4649 | LSM_HOOK_INIT(bprm_secureexec, smack_bprm_secureexec), | ||
4650 | 4622 | ||
4651 | LSM_HOOK_INIT(inode_alloc_security, smack_inode_alloc_security), | 4623 | LSM_HOOK_INIT(inode_alloc_security, smack_inode_alloc_security), |
4652 | LSM_HOOK_INIT(inode_free_security, smack_inode_free_security), | 4624 | LSM_HOOK_INIT(inode_free_security, smack_inode_free_security), |
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 130b4fa4f65f..d25b705360e0 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
@@ -76,7 +76,7 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | |||
76 | * Do only if this function is called for the first time of an execve | 76 | * Do only if this function is called for the first time of an execve |
77 | * operation. | 77 | * operation. |
78 | */ | 78 | */ |
79 | if (bprm->cred_prepared) | 79 | if (bprm->called_set_creds) |
80 | return 0; | 80 | return 0; |
81 | #ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER | 81 | #ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER |
82 | /* | 82 | /* |