aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-11-13 18:39:24 -0500
committerJames Morris <jmorris@namei.org>2008-11-13 18:39:24 -0500
commita6f76f23d297f70e2a6b3ec607f7aeeea9e37e8d (patch)
tree8f95617996d0974507f176163459212a7def8b9a
parentd84f4f992cbd76e8f39c488cf0c5d123843923b1 (diff)
CRED: Make execve() take advantage of copy-on-write credentials
Make execve() take advantage of copy-on-write credentials, allowing it to set up the credentials in advance, and then commit the whole lot after the point of no return. This patch and the preceding patches have been tested with the LTP SELinux testsuite. This patch makes several logical sets of alteration: (1) execve(). The credential bits from struct linux_binprm are, for the most part, replaced with a single credentials pointer (bprm->cred). This means that all the creds can be calculated in advance and then applied at the point of no return with no possibility of failure. I would like to replace bprm->cap_effective with: cap_isclear(bprm->cap_effective) but this seems impossible due to special behaviour for processes of pid 1 (they always retain their parent's capability masks where normally they'd be changed - see cap_bprm_set_creds()). The following sequence of events now happens: (a) At the start of do_execve, the current task's cred_exec_mutex is locked to prevent PTRACE_ATTACH from obsoleting the calculation of creds that we make. (a) prepare_exec_creds() is then called to make a copy of the current task's credentials and prepare it. This copy is then assigned to bprm->cred. This renders security_bprm_alloc() and security_bprm_free() unnecessary, and so they've been removed. (b) The determination of unsafe execution is now performed immediately after (a) rather than later on in the code. The result is stored in bprm->unsafe for future reference. (c) prepare_binprm() is called, possibly multiple times. (i) This applies the result of set[ug]id binaries to the new creds attached to bprm->cred. Personality bit clearance is recorded, but now deferred on the basis that the exec procedure may yet fail. (ii) This then calls the new security_bprm_set_creds(). This should calculate the new LSM and capability credentials into *bprm->cred. This folds together security_bprm_set() and parts of security_bprm_apply_creds() (these two have been removed). Anything that might fail must be done at this point. (iii) bprm->cred_prepared is set to 1. bprm->cred_prepared is 0 on the first pass of the security calculations, and 1 on all subsequent passes. This allows SELinux in (ii) to base its calculations only on the initial script and not on the interpreter. (d) flush_old_exec() is called to commit the task to execution. This performs the following steps with regard to credentials: (i) Clear pdeath_signal and set dumpable on certain circumstances that may not be covered by commit_creds(). (ii) Clear any bits in current->personality that were deferred from (c.i). (e) install_exec_creds() [compute_creds() as was] is called to install the new credentials. This performs the following steps with regard to credentials: (i) Calls security_bprm_committing_creds() to apply any security requirements, such as flushing unauthorised files in SELinux, that must be done before the credentials are changed. This is made up of bits of security_bprm_apply_creds() and security_bprm_post_apply_creds(), both of which have been removed. This function is not allowed to fail; anything that might fail must have been done in (c.ii). (ii) Calls commit_creds() to apply the new credentials in a single assignment (more or less). Possibly pdeath_signal and dumpable should be part of struct creds. (iii) Unlocks the task's cred_replace_mutex, thus allowing PTRACE_ATTACH to take place. (iv) Clears The bprm->cred pointer as the credentials it was holding are now immutable. (v) Calls security_bprm_committed_creds() to apply any security alterations that must be done after the creds have been changed. SELinux uses this to flush signals and signal handlers. (f) If an error occurs before (d.i), bprm_free() will call abort_creds() to destroy the proposed new credentials and will then unlock cred_replace_mutex. No changes to the credentials will have been made. (2) LSM interface. A number of functions have been changed, added or removed: (*) security_bprm_alloc(), ->bprm_alloc_security() (*) security_bprm_free(), ->bprm_free_security() Removed in favour of preparing new credentials and modifying those. (*) security_bprm_apply_creds(), ->bprm_apply_creds() (*) security_bprm_post_apply_creds(), ->bprm_post_apply_creds() Removed; split between security_bprm_set_creds(), security_bprm_committing_creds() and security_bprm_committed_creds(). (*) security_bprm_set(), ->bprm_set_security() Removed; folded into security_bprm_set_creds(). (*) security_bprm_set_creds(), ->bprm_set_creds() New. The new credentials in bprm->creds should be checked and set up as appropriate. bprm->cred_prepared is 0 on the first call, 1 on the second and subsequent calls. (*) security_bprm_committing_creds(), ->bprm_committing_creds() (*) security_bprm_committed_creds(), ->bprm_committed_creds() New. Apply the security effects of the new credentials. This includes closing unauthorised files in SELinux. This function may not fail. When the former is called, the creds haven't yet been applied to the process; when the latter is called, they have. The former may access bprm->cred, the latter may not. (3) SELinux. SELinux has a number of changes, in addition to those to support the LSM interface changes mentioned above: (a) The bprm_security_struct struct has been removed in favour of using the credentials-under-construction approach. (c) flush_unauthorized_files() now takes a cred pointer and passes it on to inode_has_perm(), file_has_perm() and dentry_open(). Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: James Morris <jmorris@namei.org> Acked-by: Serge Hallyn <serue@us.ibm.com> Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r--arch/x86/ia32/ia32_aout.c2
-rw-r--r--fs/binfmt_aout.c2
-rw-r--r--fs/binfmt_elf.c2
-rw-r--r--fs/binfmt_elf_fdpic.c2
-rw-r--r--fs/binfmt_flat.c2
-rw-r--r--fs/binfmt_som.c2
-rw-r--r--fs/compat.c42
-rw-r--r--fs/exec.c149
-rw-r--r--fs/internal.h6
-rw-r--r--include/linux/audit.h16
-rw-r--r--include/linux/binfmts.h16
-rw-r--r--include/linux/cred.h3
-rw-r--r--include/linux/key.h2
-rw-r--r--include/linux/security.h103
-rw-r--r--kernel/cred.c46
-rw-r--r--security/capability.c19
-rw-r--r--security/commoncap.c152
-rw-r--r--security/keys/process_keys.c42
-rw-r--r--security/root_plug.c13
-rw-r--r--security/security.c26
-rw-r--r--security/selinux/hooks.c283
-rw-r--r--security/selinux/include/objsec.h11
-rw-r--r--security/smack/smack_lsm.c3
23 files changed, 429 insertions, 515 deletions
diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c
index 127ec3f07214..2a4d073d2cf1 100644
--- a/arch/x86/ia32/ia32_aout.c
+++ b/arch/x86/ia32/ia32_aout.c
@@ -327,7 +327,7 @@ static int load_aout_binary(struct linux_binprm *bprm, struct pt_regs *regs)
327 current->mm->cached_hole_size = 0; 327 current->mm->cached_hole_size = 0;
328 328
329 current->mm->mmap = NULL; 329 current->mm->mmap = NULL;
330 compute_creds(bprm); 330 install_exec_creds(bprm);
331 current->flags &= ~PF_FORKNOEXEC; 331 current->flags &= ~PF_FORKNOEXEC;
332 332
333 if (N_MAGIC(ex) == OMAGIC) { 333 if (N_MAGIC(ex) == OMAGIC) {
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 204cfd1d7676..f1f3f4192a60 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -320,7 +320,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
320 current->mm->free_area_cache = current->mm->mmap_base; 320 current->mm->free_area_cache = current->mm->mmap_base;
321 current->mm->cached_hole_size = 0; 321 current->mm->cached_hole_size = 0;
322 322
323 compute_creds(bprm); 323 install_exec_creds(bprm);
324 current->flags &= ~PF_FORKNOEXEC; 324 current->flags &= ~PF_FORKNOEXEC;
325#ifdef __sparc__ 325#ifdef __sparc__
326 if (N_MAGIC(ex) == NMAGIC) { 326 if (N_MAGIC(ex) == NMAGIC) {
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 9142ff5dc8e6..f458c1217c5e 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -956,7 +956,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
956 } 956 }
957#endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ 957#endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
958 958
959 compute_creds(bprm); 959 install_exec_creds(bprm);
960 current->flags &= ~PF_FORKNOEXEC; 960 current->flags &= ~PF_FORKNOEXEC;
961 retval = create_elf_tables(bprm, &loc->elf_ex, 961 retval = create_elf_tables(bprm, &loc->elf_ex,
962 load_addr, interp_load_addr); 962 load_addr, interp_load_addr);
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 45dabd59936f..aa5b43205e37 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -404,7 +404,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm,
404 current->mm->start_stack = current->mm->start_brk + stack_size; 404 current->mm->start_stack = current->mm->start_brk + stack_size;
405#endif 405#endif
406 406
407 compute_creds(bprm); 407 install_exec_creds(bprm);
408 current->flags &= ~PF_FORKNOEXEC; 408 current->flags &= ~PF_FORKNOEXEC;
409 if (create_elf_fdpic_tables(bprm, current->mm, 409 if (create_elf_fdpic_tables(bprm, current->mm,
410 &exec_params, &interp_params) < 0) 410 &exec_params, &interp_params) < 0)
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index ccb781a6a804..7bbd5c6b3725 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -880,7 +880,7 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs)
880 (libinfo.lib_list[j].loaded)? 880 (libinfo.lib_list[j].loaded)?
881 libinfo.lib_list[j].start_data:UNLOADED_LIB; 881 libinfo.lib_list[j].start_data:UNLOADED_LIB;
882 882
883 compute_creds(bprm); 883 install_exec_creds(bprm);
884 current->flags &= ~PF_FORKNOEXEC; 884 current->flags &= ~PF_FORKNOEXEC;
885 885
886 set_binfmt(&flat_format); 886 set_binfmt(&flat_format);
diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c
index 74e587a52796..08644a61616e 100644
--- a/fs/binfmt_som.c
+++ b/fs/binfmt_som.c
@@ -255,7 +255,7 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
255 kfree(hpuxhdr); 255 kfree(hpuxhdr);
256 256
257 set_binfmt(&som_format); 257 set_binfmt(&som_format);
258 compute_creds(bprm); 258 install_exec_creds(bprm);
259 setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT); 259 setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
260 260
261 create_som_tables(bprm); 261 create_som_tables(bprm);
diff --git a/fs/compat.c b/fs/compat.c
index e5f49f538502..d1ece79b6411 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1393,10 +1393,20 @@ int compat_do_execve(char * filename,
1393 if (!bprm) 1393 if (!bprm)
1394 goto out_ret; 1394 goto out_ret;
1395 1395
1396 retval = mutex_lock_interruptible(&current->cred_exec_mutex);
1397 if (retval < 0)
1398 goto out_free;
1399
1400 retval = -ENOMEM;
1401 bprm->cred = prepare_exec_creds();
1402 if (!bprm->cred)
1403 goto out_unlock;
1404 check_unsafe_exec(bprm);
1405
1396 file = open_exec(filename); 1406 file = open_exec(filename);
1397 retval = PTR_ERR(file); 1407 retval = PTR_ERR(file);
1398 if (IS_ERR(file)) 1408 if (IS_ERR(file))
1399 goto out_kfree; 1409 goto out_unlock;
1400 1410
1401 sched_exec(); 1411 sched_exec();
1402 1412
@@ -1410,14 +1420,10 @@ int compat_do_execve(char * filename,
1410 1420
1411 bprm->argc = compat_count(argv, MAX_ARG_STRINGS); 1421 bprm->argc = compat_count(argv, MAX_ARG_STRINGS);
1412 if ((retval = bprm->argc) < 0) 1422 if ((retval = bprm->argc) < 0)
1413 goto out_mm; 1423 goto out;
1414 1424
1415 bprm->envc = compat_count(envp, MAX_ARG_STRINGS); 1425 bprm->envc = compat_count(envp, MAX_ARG_STRINGS);
1416 if ((retval = bprm->envc) < 0) 1426 if ((retval = bprm->envc) < 0)
1417 goto out_mm;
1418
1419 retval = security_bprm_alloc(bprm);
1420 if (retval)
1421 goto out; 1427 goto out;
1422 1428
1423 retval = prepare_binprm(bprm); 1429 retval = prepare_binprm(bprm);
@@ -1438,19 +1444,16 @@ int compat_do_execve(char * filename,
1438 goto out; 1444 goto out;
1439 1445
1440 retval = search_binary_handler(bprm, regs); 1446 retval = search_binary_handler(bprm, regs);
1441 if (retval >= 0) { 1447 if (retval < 0)
1442 /* execve success */ 1448 goto out;
1443 security_bprm_free(bprm);
1444 acct_update_integrals(current);
1445 free_bprm(bprm);
1446 return retval;
1447 }
1448 1449
1449out: 1450 /* execve succeeded */
1450 if (bprm->security) 1451 mutex_unlock(&current->cred_exec_mutex);
1451 security_bprm_free(bprm); 1452 acct_update_integrals(current);
1453 free_bprm(bprm);
1454 return retval;
1452 1455
1453out_mm: 1456out:
1454 if (bprm->mm) 1457 if (bprm->mm)
1455 mmput(bprm->mm); 1458 mmput(bprm->mm);
1456 1459
@@ -1460,7 +1463,10 @@ out_file:
1460 fput(bprm->file); 1463 fput(bprm->file);
1461 } 1464 }
1462 1465
1463out_kfree: 1466out_unlock:
1467 mutex_unlock(&current->cred_exec_mutex);
1468
1469out_free:
1464 free_bprm(bprm); 1470 free_bprm(bprm);
1465 1471
1466out_ret: 1472out_ret:
diff --git a/fs/exec.c b/fs/exec.c
index 9bd3559ddece..32f13e299417 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -55,6 +55,7 @@
55#include <asm/uaccess.h> 55#include <asm/uaccess.h>
56#include <asm/mmu_context.h> 56#include <asm/mmu_context.h>
57#include <asm/tlb.h> 57#include <asm/tlb.h>
58#include "internal.h"
58 59
59#ifdef __alpha__ 60#ifdef __alpha__
60/* for /sbin/loader handling in search_binary_handler() */ 61/* for /sbin/loader handling in search_binary_handler() */
@@ -1007,15 +1008,17 @@ int flush_old_exec(struct linux_binprm * bprm)
1007 */ 1008 */
1008 current->mm->task_size = TASK_SIZE; 1009 current->mm->task_size = TASK_SIZE;
1009 1010
1010 if (bprm->e_uid != current_euid() || 1011 /* install the new credentials */
1011 bprm->e_gid != current_egid()) { 1012 if (bprm->cred->uid != current_euid() ||
1012 set_dumpable(current->mm, suid_dumpable); 1013 bprm->cred->gid != current_egid()) {
1013 current->pdeath_signal = 0; 1014 current->pdeath_signal = 0;
1014 } else if (file_permission(bprm->file, MAY_READ) || 1015 } else if (file_permission(bprm->file, MAY_READ) ||
1015 (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { 1016 bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) {
1016 set_dumpable(current->mm, suid_dumpable); 1017 set_dumpable(current->mm, suid_dumpable);
1017 } 1018 }
1018 1019
1020 current->personality &= ~bprm->per_clear;
1021
1019 /* An exec changes our domain. We are no longer part of the thread 1022 /* An exec changes our domain. We are no longer part of the thread
1020 group */ 1023 group */
1021 1024
@@ -1032,13 +1035,50 @@ out:
1032 1035
1033EXPORT_SYMBOL(flush_old_exec); 1036EXPORT_SYMBOL(flush_old_exec);
1034 1037
1038/*
1039 * install the new credentials for this executable
1040 */
1041void install_exec_creds(struct linux_binprm *bprm)
1042{
1043 security_bprm_committing_creds(bprm);
1044
1045 commit_creds(bprm->cred);
1046 bprm->cred = NULL;
1047
1048 /* cred_exec_mutex must be held at least to this point to prevent
1049 * ptrace_attach() from altering our determination of the task's
1050 * credentials; any time after this it may be unlocked */
1051
1052 security_bprm_committed_creds(bprm);
1053}
1054EXPORT_SYMBOL(install_exec_creds);
1055
1056/*
1057 * determine how safe it is to execute the proposed program
1058 * - the caller must hold current->cred_exec_mutex to protect against
1059 * PTRACE_ATTACH
1060 */
1061void check_unsafe_exec(struct linux_binprm *bprm)
1062{
1063 struct task_struct *p = current;
1064
1065 bprm->unsafe = tracehook_unsafe_exec(p);
1066
1067 if (atomic_read(&p->fs->count) > 1 ||
1068 atomic_read(&p->files->count) > 1 ||
1069 atomic_read(&p->sighand->count) > 1)
1070 bprm->unsafe |= LSM_UNSAFE_SHARE;
1071}
1072
1035/* 1073/*
1036 * Fill the binprm structure from the inode. 1074 * Fill the binprm structure from the inode.
1037 * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes 1075 * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
1076 *
1077 * This may be called multiple times for binary chains (scripts for example).
1038 */ 1078 */
1039int prepare_binprm(struct linux_binprm *bprm) 1079int prepare_binprm(struct linux_binprm *bprm)
1040{ 1080{
1041 int mode; 1081 umode_t mode;
1042 struct inode * inode = bprm->file->f_path.dentry->d_inode; 1082 struct inode * inode = bprm->file->f_path.dentry->d_inode;
1043 int retval; 1083 int retval;
1044 1084
@@ -1046,14 +1086,15 @@ int prepare_binprm(struct linux_binprm *bprm)
1046 if (bprm->file->f_op == NULL) 1086 if (bprm->file->f_op == NULL)
1047 return -EACCES; 1087 return -EACCES;
1048 1088
1049 bprm->e_uid = current_euid(); 1089 /* clear any previous set[ug]id data from a previous binary */
1050 bprm->e_gid = current_egid(); 1090 bprm->cred->euid = current_euid();
1091 bprm->cred->egid = current_egid();
1051 1092
1052 if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { 1093 if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
1053 /* Set-uid? */ 1094 /* Set-uid? */
1054 if (mode & S_ISUID) { 1095 if (mode & S_ISUID) {
1055 current->personality &= ~PER_CLEAR_ON_SETID; 1096 bprm->per_clear |= PER_CLEAR_ON_SETID;
1056 bprm->e_uid = inode->i_uid; 1097 bprm->cred->euid = inode->i_uid;
1057 } 1098 }
1058 1099
1059 /* Set-gid? */ 1100 /* Set-gid? */
@@ -1063,50 +1104,23 @@ int prepare_binprm(struct linux_binprm *bprm)
1063 * executable. 1104 * executable.
1064 */ 1105 */
1065 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 1106 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
1066 current->personality &= ~PER_CLEAR_ON_SETID; 1107 bprm->per_clear |= PER_CLEAR_ON_SETID;
1067 bprm->e_gid = inode->i_gid; 1108 bprm->cred->egid = inode->i_gid;
1068 } 1109 }
1069 } 1110 }
1070 1111
1071 /* fill in binprm security blob */ 1112 /* fill in binprm security blob */
1072 retval = security_bprm_set(bprm); 1113 retval = security_bprm_set_creds(bprm);
1073 if (retval) 1114 if (retval)
1074 return retval; 1115 return retval;
1116 bprm->cred_prepared = 1;
1075 1117
1076 memset(bprm->buf,0,BINPRM_BUF_SIZE); 1118 memset(bprm->buf, 0, BINPRM_BUF_SIZE);
1077 return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE); 1119 return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE);
1078} 1120}
1079 1121
1080EXPORT_SYMBOL(prepare_binprm); 1122EXPORT_SYMBOL(prepare_binprm);
1081 1123
1082static int unsafe_exec(struct task_struct *p)
1083{
1084 int unsafe = tracehook_unsafe_exec(p);
1085
1086 if (atomic_read(&p->fs->count) > 1 ||
1087 atomic_read(&p->files->count) > 1 ||
1088 atomic_read(&p->sighand->count) > 1)
1089 unsafe |= LSM_UNSAFE_SHARE;
1090
1091 return unsafe;
1092}
1093
1094void compute_creds(struct linux_binprm *bprm)
1095{
1096 int unsafe;
1097
1098 if (bprm->e_uid != current_uid())
1099 current->pdeath_signal = 0;
1100 exec_keys(current);
1101
1102 task_lock(current);
1103 unsafe = unsafe_exec(current);
1104 security_bprm_apply_creds(bprm, unsafe);
1105 task_unlock(current);
1106 security_bprm_post_apply_creds(bprm);
1107}
1108EXPORT_SYMBOL(compute_creds);
1109
1110/* 1124/*
1111 * Arguments are '\0' separated strings found at the location bprm->p 1125 * Arguments are '\0' separated strings found at the location bprm->p
1112 * points to; chop off the first by relocating brpm->p to right after 1126 * points to; chop off the first by relocating brpm->p to right after
@@ -1259,6 +1273,8 @@ EXPORT_SYMBOL(search_binary_handler);
1259void free_bprm(struct linux_binprm *bprm) 1273void free_bprm(struct linux_binprm *bprm)
1260{ 1274{
1261 free_arg_pages(bprm); 1275 free_arg_pages(bprm);
1276 if (bprm->cred)
1277 abort_creds(bprm->cred);
1262 kfree(bprm); 1278 kfree(bprm);
1263} 1279}
1264 1280
@@ -1284,10 +1300,20 @@ int do_execve(char * filename,
1284 if (!bprm) 1300 if (!bprm)
1285 goto out_files; 1301 goto out_files;
1286 1302
1303 retval = mutex_lock_interruptible(&current->cred_exec_mutex);
1304 if (retval < 0)
1305 goto out_free;
1306
1307 retval = -ENOMEM;
1308 bprm->cred = prepare_exec_creds();
1309 if (!bprm->cred)
1310 goto out_unlock;
1311 check_unsafe_exec(bprm);
1312
1287 file = open_exec(filename); 1313 file = open_exec(filename);
1288 retval = PTR_ERR(file); 1314 retval = PTR_ERR(file);
1289 if (IS_ERR(file)) 1315 if (IS_ERR(file))
1290 goto out_kfree; 1316 goto out_unlock;
1291 1317
1292 sched_exec(); 1318 sched_exec();
1293 1319
@@ -1301,14 +1327,10 @@ int do_execve(char * filename,
1301 1327
1302 bprm->argc = count(argv, MAX_ARG_STRINGS); 1328 bprm->argc = count(argv, MAX_ARG_STRINGS);
1303 if ((retval = bprm->argc) < 0) 1329 if ((retval = bprm->argc) < 0)
1304 goto out_mm; 1330 goto out;
1305 1331
1306 bprm->envc = count(envp, MAX_ARG_STRINGS); 1332 bprm->envc = count(envp, MAX_ARG_STRINGS);
1307 if ((retval = bprm->envc) < 0) 1333 if ((retval = bprm->envc) < 0)
1308 goto out_mm;
1309
1310 retval = security_bprm_alloc(bprm);
1311 if (retval)
1312 goto out; 1334 goto out;
1313 1335
1314 retval = prepare_binprm(bprm); 1336 retval = prepare_binprm(bprm);
@@ -1330,21 +1352,18 @@ int do_execve(char * filename,
1330 1352
1331 current->flags &= ~PF_KTHREAD; 1353 current->flags &= ~PF_KTHREAD;
1332 retval = search_binary_handler(bprm,regs); 1354 retval = search_binary_handler(bprm,regs);
1333 if (retval >= 0) { 1355 if (retval < 0)
1334 /* execve success */ 1356 goto out;
1335 security_bprm_free(bprm);
1336 acct_update_integrals(current);
1337 free_bprm(bprm);
1338 if (displaced)
1339 put_files_struct(displaced);
1340 return retval;
1341 }
1342 1357
1343out: 1358 /* execve succeeded */
1344 if (bprm->security) 1359 mutex_unlock(&current->cred_exec_mutex);
1345 security_bprm_free(bprm); 1360 acct_update_integrals(current);
1361 free_bprm(bprm);
1362 if (displaced)
1363 put_files_struct(displaced);
1364 return retval;
1346 1365
1347out_mm: 1366out:
1348 if (bprm->mm) 1367 if (bprm->mm)
1349 mmput (bprm->mm); 1368 mmput (bprm->mm);
1350 1369
@@ -1353,7 +1372,11 @@ out_file:
1353 allow_write_access(bprm->file); 1372 allow_write_access(bprm->file);
1354 fput(bprm->file); 1373 fput(bprm->file);
1355 } 1374 }
1356out_kfree: 1375
1376out_unlock:
1377 mutex_unlock(&current->cred_exec_mutex);
1378
1379out_free:
1357 free_bprm(bprm); 1380 free_bprm(bprm);
1358 1381
1359out_files: 1382out_files:
diff --git a/fs/internal.h b/fs/internal.h
index 80aa9a023372..53af885f1732 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -10,6 +10,7 @@
10 */ 10 */
11 11
12struct super_block; 12struct super_block;
13struct linux_binprm;
13 14
14/* 15/*
15 * block_dev.c 16 * block_dev.c
@@ -40,6 +41,11 @@ static inline int sb_is_blkdev_sb(struct super_block *sb)
40extern void __init chrdev_init(void); 41extern void __init chrdev_init(void);
41 42
42/* 43/*
44 * exec.c
45 */
46extern void check_unsafe_exec(struct linux_binprm *);
47
48/*
43 * namespace.c 49 * namespace.c
44 */ 50 */
45extern int copy_mount_options(const void __user *, unsigned long *); 51extern int copy_mount_options(const void __user *, unsigned long *);
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 0b2fcb698a63..e8ce2c4c7ac7 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -508,22 +508,6 @@ static inline int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
508 return 0; 508 return 0;
509} 509}
510 510
511/*
512 * ieieeeeee, an audit function without a return code!
513 *
514 * This function might fail! I decided that it didn't matter. We are too late
515 * to fail the syscall and the information isn't REQUIRED for any purpose. It's
516 * just nice to have. We should be able to look at past audit logs to figure
517 * out this process's current cap set along with the fcaps from the PATH record
518 * and use that to come up with the final set. Yeah, its ugly, but all the info
519 * is still in the audit log. So I'm not going to bother mentioning we failed
520 * if we couldn't allocate memory.
521 *
522 * If someone changes their mind they could create the aux record earlier and
523 * then search here and use that earlier allocation. But I don't wanna.
524 *
525 * -Eric
526 */
527static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm, 511static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm,
528 const struct cred *new, 512 const struct cred *new,
529 const struct cred *old) 513 const struct cred *old)
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index 7394b5b349ff..6cbfbe297180 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -35,16 +35,20 @@ struct linux_binprm{
35 struct mm_struct *mm; 35 struct mm_struct *mm;
36 unsigned long p; /* current top of mem */ 36 unsigned long p; /* current top of mem */
37 unsigned int sh_bang:1, 37 unsigned int sh_bang:1,
38 misc_bang:1; 38 misc_bang:1,
39 cred_prepared:1,/* true if creds already prepared (multiple
40 * preps happen for interpreters) */
41 cap_effective:1;/* true if has elevated effective capabilities,
42 * false if not; except for init which inherits
43 * its parent's caps anyway */
39#ifdef __alpha__ 44#ifdef __alpha__
40 unsigned int taso:1; 45 unsigned int taso:1;
41#endif 46#endif
42 unsigned int recursion_depth; 47 unsigned int recursion_depth;
43 struct file * file; 48 struct file * file;
44 int e_uid, e_gid; 49 struct cred *cred; /* new credentials */
45 kernel_cap_t cap_post_exec_permitted; 50 int unsafe; /* how unsafe this exec is (mask of LSM_UNSAFE_*) */
46 bool cap_effective; 51 unsigned int per_clear; /* bits to clear in current->personality */
47 void *security;
48 int argc, envc; 52 int argc, envc;
49 char * filename; /* Name of binary as seen by procps */ 53 char * filename; /* Name of binary as seen by procps */
50 char * interp; /* Name of the binary really executed. Most 54 char * interp; /* Name of the binary really executed. Most
@@ -101,7 +105,7 @@ extern int setup_arg_pages(struct linux_binprm * bprm,
101 int executable_stack); 105 int executable_stack);
102extern int bprm_mm_init(struct linux_binprm *bprm); 106extern int bprm_mm_init(struct linux_binprm *bprm);
103extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm); 107extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm);
104extern void compute_creds(struct linux_binprm *binprm); 108extern void install_exec_creds(struct linux_binprm *bprm);
105extern int do_coredump(long signr, int exit_code, struct pt_regs * regs); 109extern int do_coredump(long signr, int exit_code, struct pt_regs * regs);
106extern int set_binfmt(struct linux_binfmt *new); 110extern int set_binfmt(struct linux_binfmt *new);
107extern void free_bprm(struct linux_binprm *); 111extern void free_bprm(struct linux_binprm *);
diff --git a/include/linux/cred.h b/include/linux/cred.h
index eaf6fa695a04..8edb4d1d5427 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -84,8 +84,6 @@ 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
88extern void release_tgcred(struct cred *cred);
89#endif 87#endif
90 88
91/* 89/*
@@ -144,6 +142,7 @@ struct cred {
144extern void __put_cred(struct cred *); 142extern void __put_cred(struct cred *);
145extern int copy_creds(struct task_struct *, unsigned long); 143extern int copy_creds(struct task_struct *, unsigned long);
146extern struct cred *prepare_creds(void); 144extern struct cred *prepare_creds(void);
145extern struct cred *prepare_exec_creds(void);
147extern struct cred *prepare_usermodehelper_creds(void); 146extern struct cred *prepare_usermodehelper_creds(void);
148extern int commit_creds(struct cred *); 147extern int commit_creds(struct cred *);
149extern void abort_creds(struct cred *); 148extern void abort_creds(struct cred *);
diff --git a/include/linux/key.h b/include/linux/key.h
index 69ecf0934b02..21d32a142c00 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -278,7 +278,6 @@ extern ctl_table key_sysctls[];
278 * the userspace interface 278 * the userspace interface
279 */ 279 */
280extern int install_thread_keyring_to_cred(struct cred *cred); 280extern int install_thread_keyring_to_cred(struct cred *cred);
281extern int exec_keys(struct task_struct *tsk);
282extern void key_fsuid_changed(struct task_struct *tsk); 281extern void key_fsuid_changed(struct task_struct *tsk);
283extern void key_fsgid_changed(struct task_struct *tsk); 282extern void key_fsgid_changed(struct task_struct *tsk);
284extern void key_init(void); 283extern void key_init(void);
@@ -294,7 +293,6 @@ extern void key_init(void);
294#define make_key_ref(k, p) NULL 293#define make_key_ref(k, p) NULL
295#define key_ref_to_ptr(k) NULL 294#define key_ref_to_ptr(k) NULL
296#define is_key_possessed(k) 0 295#define is_key_possessed(k) 0
297#define exec_keys(t) do { } while(0)
298#define key_fsuid_changed(t) do { } while(0) 296#define key_fsuid_changed(t) do { } while(0)
299#define key_fsgid_changed(t) do { } while(0) 297#define key_fsgid_changed(t) do { } while(0)
300#define key_init() do { } while(0) 298#define key_init() do { } while(0)
diff --git a/include/linux/security.h b/include/linux/security.h
index 68be11251447..56a0eed65673 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -57,8 +57,7 @@ extern int cap_capset(struct cred *new, const struct cred *old,
57 const kernel_cap_t *effective, 57 const kernel_cap_t *effective,
58 const kernel_cap_t *inheritable, 58 const kernel_cap_t *inheritable,
59 const kernel_cap_t *permitted); 59 const kernel_cap_t *permitted);
60extern int cap_bprm_set_security(struct linux_binprm *bprm); 60extern int cap_bprm_set_creds(struct linux_binprm *bprm);
61extern int cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
62extern int cap_bprm_secureexec(struct linux_binprm *bprm); 61extern int cap_bprm_secureexec(struct linux_binprm *bprm);
63extern int cap_inode_setxattr(struct dentry *dentry, const char *name, 62extern int cap_inode_setxattr(struct dentry *dentry, const char *name,
64 const void *value, size_t size, int flags); 63 const void *value, size_t size, int flags);
@@ -110,7 +109,7 @@ extern unsigned long mmap_min_addr;
110struct sched_param; 109struct sched_param;
111struct request_sock; 110struct request_sock;
112 111
113/* bprm_apply_creds unsafe reasons */ 112/* bprm->unsafe reasons */
114#define LSM_UNSAFE_SHARE 1 113#define LSM_UNSAFE_SHARE 1
115#define LSM_UNSAFE_PTRACE 2 114#define LSM_UNSAFE_PTRACE 2
116#define LSM_UNSAFE_PTRACE_CAP 4 115#define LSM_UNSAFE_PTRACE_CAP 4
@@ -154,36 +153,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
154 * 153 *
155 * Security hooks for program execution operations. 154 * Security hooks for program execution operations.
156 * 155 *
157 * @bprm_alloc_security: 156 * @bprm_set_creds:
158 * Allocate and attach a security structure to the @bprm->security field.
159 * The security field is initialized to NULL when the bprm structure is
160 * allocated.
161 * @bprm contains the linux_binprm structure to be modified.
162 * Return 0 if operation was successful.
163 * @bprm_free_security:
164 * @bprm contains the linux_binprm structure to be modified.
165 * Deallocate and clear the @bprm->security field.
166 * @bprm_apply_creds:
167 * Compute and set the security attributes of a process being transformed
168 * by an execve operation based on the old attributes (current->security)
169 * and the information saved in @bprm->security by the set_security hook.
170 * Since this function may return an error, in which case the process will
171 * be killed. However, it can leave the security attributes of the
172 * process unchanged if an access failure occurs at this point.
173 * bprm_apply_creds is called under task_lock. @unsafe indicates various
174 * reasons why it may be unsafe to change security state.
175 * @bprm contains the linux_binprm structure.
176 * @bprm_post_apply_creds:
177 * Runs after bprm_apply_creds with the task_lock dropped, so that
178 * functions which cannot be called safely under the task_lock can
179 * be used. This hook is a good place to perform state changes on
180 * the process such as closing open file descriptors to which access
181 * is no longer granted if the attributes were changed.
182 * Note that a security module might need to save state between
183 * bprm_apply_creds and bprm_post_apply_creds to store the decision
184 * on whether the process may proceed.
185 * @bprm contains the linux_binprm structure.
186 * @bprm_set_security:
187 * Save security information in the bprm->security field, typically based 157 * Save security information in the bprm->security field, typically based
188 * on information about the bprm->file, for later use by the apply_creds 158 * on information about the bprm->file, for later use by the apply_creds
189 * hook. This hook may also optionally check permissions (e.g. for 159 * hook. This hook may also optionally check permissions (e.g. for
@@ -196,15 +166,30 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
196 * @bprm contains the linux_binprm structure. 166 * @bprm contains the linux_binprm structure.
197 * Return 0 if the hook is successful and permission is granted. 167 * Return 0 if the hook is successful and permission is granted.
198 * @bprm_check_security: 168 * @bprm_check_security:
199 * This hook mediates the point when a search for a binary handler will 169 * This hook mediates the point when a search for a binary handler will
200 * begin. It allows a check the @bprm->security value which is set in 170 * begin. It allows a check the @bprm->security value which is set in the
201 * the preceding set_security call. The primary difference from 171 * preceding set_creds call. The primary difference from set_creds is
202 * set_security is that the argv list and envp list are reliably 172 * that the argv list and envp list are reliably available in @bprm. This
203 * available in @bprm. This hook may be called multiple times 173 * hook may be called multiple times during a single execve; and in each
204 * during a single execve; and in each pass set_security is called 174 * pass set_creds is called first.
205 * first.
206 * @bprm contains the linux_binprm structure. 175 * @bprm contains the linux_binprm structure.
207 * Return 0 if the hook is successful and permission is granted. 176 * Return 0 if the hook is successful and permission is granted.
177 * @bprm_committing_creds:
178 * Prepare to install the new security attributes of a process being
179 * transformed by an execve operation, based on the old credentials
180 * pointed to by @current->cred and the information set in @bprm->cred by
181 * the bprm_set_creds hook. @bprm points to the linux_binprm structure.
182 * This hook is a good place to perform state changes on the process such
183 * as closing open file descriptors to which access will no longer be
184 * granted when the attributes are changed. This is called immediately
185 * before commit_creds().
186 * @bprm_committed_creds:
187 * Tidy up after the installation of the new security attributes of a
188 * process being transformed by an execve operation. The new credentials
189 * have, by this point, been set to @current->cred. @bprm points to the
190 * linux_binprm structure. This hook is a good place to perform state
191 * changes on the process such as clearing out non-inheritable signal
192 * state. This is called immediately after commit_creds().
208 * @bprm_secureexec: 193 * @bprm_secureexec:
209 * Return a boolean value (0 or 1) indicating whether a "secure exec" 194 * Return a boolean value (0 or 1) indicating whether a "secure exec"
210 * is required. The flag is passed in the auxiliary table 195 * is required. The flag is passed in the auxiliary table
@@ -1301,13 +1286,11 @@ struct security_operations {
1301 int (*settime) (struct timespec *ts, struct timezone *tz); 1286 int (*settime) (struct timespec *ts, struct timezone *tz);
1302 int (*vm_enough_memory) (struct mm_struct *mm, long pages); 1287 int (*vm_enough_memory) (struct mm_struct *mm, long pages);
1303 1288
1304 int (*bprm_alloc_security) (struct linux_binprm *bprm); 1289 int (*bprm_set_creds) (struct linux_binprm *bprm);
1305 void (*bprm_free_security) (struct linux_binprm *bprm);
1306 int (*bprm_apply_creds) (struct linux_binprm *bprm, int unsafe);
1307 void (*bprm_post_apply_creds) (struct linux_binprm *bprm);
1308 int (*bprm_set_security) (struct linux_binprm *bprm);
1309 int (*bprm_check_security) (struct linux_binprm *bprm); 1290 int (*bprm_check_security) (struct linux_binprm *bprm);
1310 int (*bprm_secureexec) (struct linux_binprm *bprm); 1291 int (*bprm_secureexec) (struct linux_binprm *bprm);
1292 void (*bprm_committing_creds) (struct linux_binprm *bprm);
1293 void (*bprm_committed_creds) (struct linux_binprm *bprm);
1311 1294
1312 int (*sb_alloc_security) (struct super_block *sb); 1295 int (*sb_alloc_security) (struct super_block *sb);
1313 void (*sb_free_security) (struct super_block *sb); 1296 void (*sb_free_security) (struct super_block *sb);
@@ -1569,12 +1552,10 @@ int security_settime(struct timespec *ts, struct timezone *tz);
1569int security_vm_enough_memory(long pages); 1552int security_vm_enough_memory(long pages);
1570int security_vm_enough_memory_mm(struct mm_struct *mm, long pages); 1553int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
1571int security_vm_enough_memory_kern(long pages); 1554int security_vm_enough_memory_kern(long pages);
1572int security_bprm_alloc(struct linux_binprm *bprm); 1555int security_bprm_set_creds(struct linux_binprm *bprm);
1573void security_bprm_free(struct linux_binprm *bprm);
1574int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
1575void security_bprm_post_apply_creds(struct linux_binprm *bprm);
1576int security_bprm_set(struct linux_binprm *bprm);
1577int security_bprm_check(struct linux_binprm *bprm); 1556int security_bprm_check(struct linux_binprm *bprm);
1557void security_bprm_committing_creds(struct linux_binprm *bprm);
1558void security_bprm_committed_creds(struct linux_binprm *bprm);
1578int security_bprm_secureexec(struct linux_binprm *bprm); 1559int security_bprm_secureexec(struct linux_binprm *bprm);
1579int security_sb_alloc(struct super_block *sb); 1560int security_sb_alloc(struct super_block *sb);
1580void security_sb_free(struct super_block *sb); 1561void security_sb_free(struct super_block *sb);
@@ -1812,32 +1793,22 @@ static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
1812 return cap_vm_enough_memory(mm, pages); 1793 return cap_vm_enough_memory(mm, pages);
1813} 1794}
1814 1795
1815static inline int security_bprm_alloc(struct linux_binprm *bprm) 1796static inline int security_bprm_set_creds(struct linux_binprm *bprm)
1816{
1817 return 0;
1818}
1819
1820static inline void security_bprm_free(struct linux_binprm *bprm)
1821{ }
1822
1823static inline int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
1824{ 1797{
1825 return cap_bprm_apply_creds(bprm, unsafe); 1798 return cap_bprm_set_creds(bprm);
1826} 1799}
1827 1800
1828static inline void security_bprm_post_apply_creds(struct linux_binprm *bprm) 1801static inline int security_bprm_check(struct linux_binprm *bprm)
1829{ 1802{
1830 return; 1803 return 0;
1831} 1804}
1832 1805
1833static inline int security_bprm_set(struct linux_binprm *bprm) 1806static inline void security_bprm_committing_creds(struct linux_binprm *bprm)
1834{ 1807{
1835 return cap_bprm_set_security(bprm);
1836} 1808}
1837 1809
1838static inline int security_bprm_check(struct linux_binprm *bprm) 1810static inline void security_bprm_committed_creds(struct linux_binprm *bprm)
1839{ 1811{
1840 return 0;
1841} 1812}
1842 1813
1843static inline int security_bprm_secureexec(struct linux_binprm *bprm) 1814static inline int security_bprm_secureexec(struct linux_binprm *bprm)
diff --git a/kernel/cred.c b/kernel/cred.c
index cb6b5eda978d..e6fcdd67b2ec 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -68,7 +68,7 @@ static void release_tgcred_rcu(struct rcu_head *rcu)
68/* 68/*
69 * Release a set of thread group credentials. 69 * Release a set of thread group credentials.
70 */ 70 */
71void release_tgcred(struct cred *cred) 71static void release_tgcred(struct cred *cred)
72{ 72{
73#ifdef CONFIG_KEYS 73#ifdef CONFIG_KEYS
74 struct thread_group_cred *tgcred = cred->tgcred; 74 struct thread_group_cred *tgcred = cred->tgcred;
@@ -164,6 +164,50 @@ error:
164EXPORT_SYMBOL(prepare_creds); 164EXPORT_SYMBOL(prepare_creds);
165 165
166/* 166/*
167 * Prepare credentials for current to perform an execve()
168 * - The caller must hold current->cred_exec_mutex
169 */
170struct cred *prepare_exec_creds(void)
171{
172 struct thread_group_cred *tgcred = NULL;
173 struct cred *new;
174
175#ifdef CONFIG_KEYS
176 tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
177 if (!tgcred)
178 return NULL;
179#endif
180
181 new = prepare_creds();
182 if (!new) {
183 kfree(tgcred);
184 return new;
185 }
186
187#ifdef CONFIG_KEYS
188 /* newly exec'd tasks don't get a thread keyring */
189 key_put(new->thread_keyring);
190 new->thread_keyring = NULL;
191
192 /* create a new per-thread-group creds for all this set of threads to
193 * share */
194 memcpy(tgcred, new->tgcred, sizeof(struct thread_group_cred));
195
196 atomic_set(&tgcred->usage, 1);
197 spin_lock_init(&tgcred->lock);
198
199 /* inherit the session keyring; new process keyring */
200 key_get(tgcred->session_keyring);
201 tgcred->process_keyring = NULL;
202
203 release_tgcred(new);
204 new->tgcred = tgcred;
205#endif
206
207 return new;
208}
209
210/*
167 * prepare new credentials for the usermode helper dispatcher 211 * prepare new credentials for the usermode helper dispatcher
168 */ 212 */
169struct cred *prepare_usermodehelper_creds(void) 213struct cred *prepare_usermodehelper_creds(void)
diff --git a/security/capability.c b/security/capability.c
index efeb6d9e0e6a..185804f99ad1 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -32,24 +32,19 @@ static int cap_quota_on(struct dentry *dentry)
32 return 0; 32 return 0;
33} 33}
34 34
35static int cap_bprm_alloc_security(struct linux_binprm *bprm) 35static int cap_bprm_check_security (struct linux_binprm *bprm)
36{ 36{
37 return 0; 37 return 0;
38} 38}
39 39
40static void cap_bprm_free_security(struct linux_binprm *bprm) 40static void cap_bprm_committing_creds(struct linux_binprm *bprm)
41{ 41{
42} 42}
43 43
44static void cap_bprm_post_apply_creds(struct linux_binprm *bprm) 44static void cap_bprm_committed_creds(struct linux_binprm *bprm)
45{ 45{
46} 46}
47 47
48static int cap_bprm_check_security(struct linux_binprm *bprm)
49{
50 return 0;
51}
52
53static int cap_sb_alloc_security(struct super_block *sb) 48static int cap_sb_alloc_security(struct super_block *sb)
54{ 49{
55 return 0; 50 return 0;
@@ -827,11 +822,9 @@ void security_fixup_ops(struct security_operations *ops)
827 set_to_cap_if_null(ops, syslog); 822 set_to_cap_if_null(ops, syslog);
828 set_to_cap_if_null(ops, settime); 823 set_to_cap_if_null(ops, settime);
829 set_to_cap_if_null(ops, vm_enough_memory); 824 set_to_cap_if_null(ops, vm_enough_memory);
830 set_to_cap_if_null(ops, bprm_alloc_security); 825 set_to_cap_if_null(ops, bprm_set_creds);
831 set_to_cap_if_null(ops, bprm_free_security); 826 set_to_cap_if_null(ops, bprm_committing_creds);
832 set_to_cap_if_null(ops, bprm_apply_creds); 827 set_to_cap_if_null(ops, bprm_committed_creds);
833 set_to_cap_if_null(ops, bprm_post_apply_creds);
834 set_to_cap_if_null(ops, bprm_set_security);
835 set_to_cap_if_null(ops, bprm_check_security); 828 set_to_cap_if_null(ops, bprm_check_security);
836 set_to_cap_if_null(ops, bprm_secureexec); 829 set_to_cap_if_null(ops, bprm_secureexec);
837 set_to_cap_if_null(ops, sb_alloc_security); 830 set_to_cap_if_null(ops, sb_alloc_security);
diff --git a/security/commoncap.c b/security/commoncap.c
index b5419273f92d..51dfa11e8e56 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -167,7 +167,7 @@ int cap_capset(struct cred *new,
167 167
168static inline void bprm_clear_caps(struct linux_binprm *bprm) 168static inline void bprm_clear_caps(struct linux_binprm *bprm)
169{ 169{
170 cap_clear(bprm->cap_post_exec_permitted); 170 cap_clear(bprm->cred->cap_permitted);
171 bprm->cap_effective = false; 171 bprm->cap_effective = false;
172} 172}
173 173
@@ -198,15 +198,15 @@ int cap_inode_killpriv(struct dentry *dentry)
198} 198}
199 199
200static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps, 200static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
201 struct linux_binprm *bprm) 201 struct linux_binprm *bprm,
202 bool *effective)
202{ 203{
204 struct cred *new = bprm->cred;
203 unsigned i; 205 unsigned i;
204 int ret = 0; 206 int ret = 0;
205 207
206 if (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE) 208 if (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
207 bprm->cap_effective = true; 209 *effective = true;
208 else
209 bprm->cap_effective = false;
210 210
211 CAP_FOR_EACH_U32(i) { 211 CAP_FOR_EACH_U32(i) {
212 __u32 permitted = caps->permitted.cap[i]; 212 __u32 permitted = caps->permitted.cap[i];
@@ -215,16 +215,13 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
215 /* 215 /*
216 * pP' = (X & fP) | (pI & fI) 216 * pP' = (X & fP) | (pI & fI)
217 */ 217 */
218 bprm->cap_post_exec_permitted.cap[i] = 218 new->cap_permitted.cap[i] =
219 (current->cred->cap_bset.cap[i] & permitted) | 219 (new->cap_bset.cap[i] & permitted) |
220 (current->cred->cap_inheritable.cap[i] & inheritable); 220 (new->cap_inheritable.cap[i] & inheritable);
221 221
222 if (permitted & ~bprm->cap_post_exec_permitted.cap[i]) { 222 if (permitted & ~new->cap_permitted.cap[i])
223 /* 223 /* insufficient to execute correctly */
224 * insufficient to execute correctly
225 */
226 ret = -EPERM; 224 ret = -EPERM;
227 }
228 } 225 }
229 226
230 /* 227 /*
@@ -232,7 +229,7 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
232 * do not have enough capabilities, we return an error if they are 229 * do not have enough capabilities, we return an error if they are
233 * missing some "forced" (aka file-permitted) capabilities. 230 * missing some "forced" (aka file-permitted) capabilities.
234 */ 231 */
235 return bprm->cap_effective ? ret : 0; 232 return *effective ? ret : 0;
236} 233}
237 234
238int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps) 235int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps)
@@ -250,10 +247,9 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
250 247
251 size = inode->i_op->getxattr((struct dentry *)dentry, XATTR_NAME_CAPS, &caps, 248 size = inode->i_op->getxattr((struct dentry *)dentry, XATTR_NAME_CAPS, &caps,
252 XATTR_CAPS_SZ); 249 XATTR_CAPS_SZ);
253 if (size == -ENODATA || size == -EOPNOTSUPP) { 250 if (size == -ENODATA || size == -EOPNOTSUPP)
254 /* no data, that's ok */ 251 /* no data, that's ok */
255 return -ENODATA; 252 return -ENODATA;
256 }
257 if (size < 0) 253 if (size < 0)
258 return size; 254 return size;
259 255
@@ -262,7 +258,7 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
262 258
263 cpu_caps->magic_etc = magic_etc = le32_to_cpu(caps.magic_etc); 259 cpu_caps->magic_etc = magic_etc = le32_to_cpu(caps.magic_etc);
264 260
265 switch ((magic_etc & VFS_CAP_REVISION_MASK)) { 261 switch (magic_etc & VFS_CAP_REVISION_MASK) {
266 case VFS_CAP_REVISION_1: 262 case VFS_CAP_REVISION_1:
267 if (size != XATTR_CAPS_SZ_1) 263 if (size != XATTR_CAPS_SZ_1)
268 return -EINVAL; 264 return -EINVAL;
@@ -283,11 +279,12 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
283 cpu_caps->permitted.cap[i] = le32_to_cpu(caps.data[i].permitted); 279 cpu_caps->permitted.cap[i] = le32_to_cpu(caps.data[i].permitted);
284 cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable); 280 cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable);
285 } 281 }
282
286 return 0; 283 return 0;
287} 284}
288 285
289/* Locate any VFS capabilities: */ 286/* Locate any VFS capabilities: */
290static int get_file_caps(struct linux_binprm *bprm) 287static int get_file_caps(struct linux_binprm *bprm, bool *effective)
291{ 288{
292 struct dentry *dentry; 289 struct dentry *dentry;
293 int rc = 0; 290 int rc = 0;
@@ -313,7 +310,10 @@ static int get_file_caps(struct linux_binprm *bprm)
313 goto out; 310 goto out;
314 } 311 }
315 312
316 rc = bprm_caps_from_vfs_caps(&vcaps, bprm); 313 rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective);
314 if (rc == -EINVAL)
315 printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
316 __func__, rc, bprm->filename);
317 317
318out: 318out:
319 dput(dentry); 319 dput(dentry);
@@ -334,18 +334,27 @@ int cap_inode_killpriv(struct dentry *dentry)
334 return 0; 334 return 0;
335} 335}
336 336
337static inline int get_file_caps(struct linux_binprm *bprm) 337static inline int get_file_caps(struct linux_binprm *bprm, bool *effective)
338{ 338{
339 bprm_clear_caps(bprm); 339 bprm_clear_caps(bprm);
340 return 0; 340 return 0;
341} 341}
342#endif 342#endif
343 343
344int cap_bprm_set_security (struct linux_binprm *bprm) 344/*
345 * set up the new credentials for an exec'd task
346 */
347int cap_bprm_set_creds(struct linux_binprm *bprm)
345{ 348{
349 const struct cred *old = current_cred();
350 struct cred *new = bprm->cred;
351 bool effective;
346 int ret; 352 int ret;
347 353
348 ret = get_file_caps(bprm); 354 effective = false;
355 ret = get_file_caps(bprm, &effective);
356 if (ret < 0)
357 return ret;
349 358
350 if (!issecure(SECURE_NOROOT)) { 359 if (!issecure(SECURE_NOROOT)) {
351 /* 360 /*
@@ -353,63 +362,47 @@ int cap_bprm_set_security (struct linux_binprm *bprm)
353 * executables under compatibility mode, we override the 362 * executables under compatibility mode, we override the
354 * capability sets for the file. 363 * capability sets for the file.
355 * 364 *
356 * If only the real uid is 0, we do not set the effective 365 * If only the real uid is 0, we do not set the effective bit.
357 * bit.
358 */ 366 */
359 if (bprm->e_uid == 0 || current_uid() == 0) { 367 if (new->euid == 0 || new->uid == 0) {
360 /* pP' = (cap_bset & ~0) | (pI & ~0) */ 368 /* pP' = (cap_bset & ~0) | (pI & ~0) */
361 bprm->cap_post_exec_permitted = cap_combine( 369 new->cap_permitted = cap_combine(old->cap_bset,
362 current->cred->cap_bset, 370 old->cap_inheritable);
363 current->cred->cap_inheritable);
364 bprm->cap_effective = (bprm->e_uid == 0);
365 ret = 0;
366 } 371 }
372 if (new->euid == 0)
373 effective = true;
367 } 374 }
368 375
369 return ret; 376 /* Don't let someone trace a set[ug]id/setpcap binary with the revised
370} 377 * credentials unless they have the appropriate permit
371 378 */
372int cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) 379 if ((new->euid != old->uid ||
373{ 380 new->egid != old->gid ||
374 const struct cred *old = current_cred(); 381 !cap_issubset(new->cap_permitted, old->cap_permitted)) &&
375 struct cred *new; 382 bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
376 383 /* downgrade; they get no more than they had, and maybe less */
377 new = prepare_creds(); 384 if (!capable(CAP_SETUID)) {
378 if (!new) 385 new->euid = new->uid;
379 return -ENOMEM; 386 new->egid = new->gid;
380
381 if (bprm->e_uid != old->uid || bprm->e_gid != old->gid ||
382 !cap_issubset(bprm->cap_post_exec_permitted,
383 old->cap_permitted)) {
384 set_dumpable(current->mm, suid_dumpable);
385 current->pdeath_signal = 0;
386
387 if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
388 if (!capable(CAP_SETUID)) {
389 bprm->e_uid = old->uid;
390 bprm->e_gid = old->gid;
391 }
392 if (cap_limit_ptraced_target()) {
393 bprm->cap_post_exec_permitted = cap_intersect(
394 bprm->cap_post_exec_permitted,
395 new->cap_permitted);
396 }
397 } 387 }
388 if (cap_limit_ptraced_target())
389 new->cap_permitted = cap_intersect(new->cap_permitted,
390 old->cap_permitted);
398 } 391 }
399 392
400 new->suid = new->euid = new->fsuid = bprm->e_uid; 393 new->suid = new->fsuid = new->euid;
401 new->sgid = new->egid = new->fsgid = bprm->e_gid; 394 new->sgid = new->fsgid = new->egid;
402 395
403 /* For init, we want to retain the capabilities set 396 /* For init, we want to retain the capabilities set in the initial
404 * in the init_task struct. Thus we skip the usual 397 * task. Thus we skip the usual capability rules
405 * capability rules */ 398 */
406 if (!is_global_init(current)) { 399 if (!is_global_init(current)) {
407 new->cap_permitted = bprm->cap_post_exec_permitted; 400 if (effective)
408 if (bprm->cap_effective) 401 new->cap_effective = new->cap_permitted;
409 new->cap_effective = bprm->cap_post_exec_permitted;
410 else 402 else
411 cap_clear(new->cap_effective); 403 cap_clear(new->cap_effective);
412 } 404 }
405 bprm->cap_effective = effective;
413 406
414 /* 407 /*
415 * Audit candidate if current->cap_effective is set 408 * Audit candidate if current->cap_effective is set
@@ -425,23 +418,31 @@ int cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
425 */ 418 */
426 if (!cap_isclear(new->cap_effective)) { 419 if (!cap_isclear(new->cap_effective)) {
427 if (!cap_issubset(CAP_FULL_SET, new->cap_effective) || 420 if (!cap_issubset(CAP_FULL_SET, new->cap_effective) ||
428 bprm->e_uid != 0 || new->uid != 0 || 421 new->euid != 0 || new->uid != 0 ||
429 issecure(SECURE_NOROOT)) 422 issecure(SECURE_NOROOT)) {
430 audit_log_bprm_fcaps(bprm, new, old); 423 ret = audit_log_bprm_fcaps(bprm, new, old);
424 if (ret < 0)
425 return ret;
426 }
431 } 427 }
432 428
433 new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); 429 new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
434 return commit_creds(new); 430 return 0;
435} 431}
436 432
437int cap_bprm_secureexec (struct linux_binprm *bprm) 433/*
434 * determine whether a secure execution is required
435 * - the creds have been committed at this point, and are no longer available
436 * through bprm
437 */
438int cap_bprm_secureexec(struct linux_binprm *bprm)
438{ 439{
439 const struct cred *cred = current_cred(); 440 const struct cred *cred = current_cred();
440 441
441 if (cred->uid != 0) { 442 if (cred->uid != 0) {
442 if (bprm->cap_effective) 443 if (bprm->cap_effective)
443 return 1; 444 return 1;
444 if (!cap_isclear(bprm->cap_post_exec_permitted)) 445 if (!cap_isclear(cred->cap_permitted))
445 return 1; 446 return 1;
446 } 447 }
447 448
@@ -477,7 +478,7 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name)
477} 478}
478 479
479/* moved from kernel/sys.c. */ 480/* moved from kernel/sys.c. */
480/* 481/*
481 * cap_emulate_setxuid() fixes the effective / permitted capabilities of 482 * cap_emulate_setxuid() fixes the effective / permitted capabilities of
482 * a process after a call to setuid, setreuid, or setresuid. 483 * a process after a call to setuid, setreuid, or setresuid.
483 * 484 *
@@ -491,10 +492,10 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name)
491 * 3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective 492 * 3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective
492 * capabilities are set to the permitted capabilities. 493 * capabilities are set to the permitted capabilities.
493 * 494 *
494 * fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should 495 * fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should
495 * never happen. 496 * never happen.
496 * 497 *
497 * -astor 498 * -astor
498 * 499 *
499 * cevans - New behaviour, Oct '99 500 * cevans - New behaviour, Oct '99
500 * A process may, via prctl(), elect to keep its capabilities when it 501 * A process may, via prctl(), elect to keep its capabilities when it
@@ -751,4 +752,3 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
751 cap_sys_admin = 1; 752 cap_sys_admin = 1;
752 return __vm_enough_memory(mm, pages, cap_sys_admin); 753 return __vm_enough_memory(mm, pages, cap_sys_admin);
753} 754}
754
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index df329f684a65..2f5d89e92b85 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -276,48 +276,6 @@ static int install_session_keyring(struct key *keyring)
276 276
277/*****************************************************************************/ 277/*****************************************************************************/
278/* 278/*
279 * deal with execve()
280 */
281int exec_keys(struct task_struct *tsk)
282{
283 struct thread_group_cred *tgcred = NULL;
284 struct cred *new;
285
286#ifdef CONFIG_KEYS
287 tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
288 if (!tgcred)
289 return -ENOMEM;
290#endif
291
292 new = prepare_creds();
293 if (new < 0)
294 return -ENOMEM;
295
296 /* newly exec'd tasks don't get a thread keyring */
297 key_put(new->thread_keyring);
298 new->thread_keyring = NULL;
299
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));
303
304 atomic_set(&tgcred->usage, 1);
305 spin_lock_init(&tgcred->lock);
306
307 /* inherit the session keyring; new process keyring */
308 key_get(tgcred->session_keyring);
309 tgcred->process_keyring = NULL;
310
311 release_tgcred(new);
312 new->tgcred = tgcred;
313
314 commit_creds(new);
315 return 0;
316
317} /* end exec_keys() */
318
319/*****************************************************************************/
320/*
321 * the filesystem user ID changed 279 * the filesystem user ID changed
322 */ 280 */
323void key_fsuid_changed(struct task_struct *tsk) 281void key_fsuid_changed(struct task_struct *tsk)
diff --git a/security/root_plug.c b/security/root_plug.c
index c3f68b5b372d..40fb4f15e27b 100644
--- a/security/root_plug.c
+++ b/security/root_plug.c
@@ -55,9 +55,9 @@ static int rootplug_bprm_check_security (struct linux_binprm *bprm)
55 struct usb_device *dev; 55 struct usb_device *dev;
56 56
57 root_dbg("file %s, e_uid = %d, e_gid = %d\n", 57 root_dbg("file %s, e_uid = %d, e_gid = %d\n",
58 bprm->filename, bprm->e_uid, bprm->e_gid); 58 bprm->filename, bprm->cred->euid, bprm->cred->egid);
59 59
60 if (bprm->e_gid == 0) { 60 if (bprm->cred->egid == 0) {
61 dev = usb_find_device(vendor_id, product_id); 61 dev = usb_find_device(vendor_id, product_id);
62 if (!dev) { 62 if (!dev) {
63 root_dbg("e_gid = 0, and device not found, " 63 root_dbg("e_gid = 0, and device not found, "
@@ -75,15 +75,12 @@ static struct security_operations rootplug_security_ops = {
75 .ptrace_may_access = cap_ptrace_may_access, 75 .ptrace_may_access = cap_ptrace_may_access,
76 .ptrace_traceme = cap_ptrace_traceme, 76 .ptrace_traceme = cap_ptrace_traceme,
77 .capget = cap_capget, 77 .capget = cap_capget,
78 .capset_check = cap_capset_check, 78 .capset = cap_capset,
79 .capset_set = cap_capset_set,
80 .capable = cap_capable, 79 .capable = cap_capable,
81 80
82 .bprm_apply_creds = cap_bprm_apply_creds, 81 .bprm_set_creds = cap_bprm_set_creds,
83 .bprm_set_security = cap_bprm_set_security,
84 82
85 .task_post_setuid = cap_task_post_setuid, 83 .task_fix_setuid = cap_task_fix_setuid,
86 .task_reparent_to_init = cap_task_reparent_to_init,
87 .task_prctl = cap_task_prctl, 84 .task_prctl = cap_task_prctl,
88 85
89 .bprm_check_security = rootplug_bprm_check_security, 86 .bprm_check_security = rootplug_bprm_check_security,
diff --git a/security/security.c b/security/security.c
index a55d739c6864..dc5babb2d6d8 100644
--- a/security/security.c
+++ b/security/security.c
@@ -213,34 +213,24 @@ int security_vm_enough_memory_kern(long pages)
213 return security_ops->vm_enough_memory(current->mm, pages); 213 return security_ops->vm_enough_memory(current->mm, pages);
214} 214}
215 215
216int security_bprm_alloc(struct linux_binprm *bprm) 216int security_bprm_set_creds(struct linux_binprm *bprm)
217{ 217{
218 return security_ops->bprm_alloc_security(bprm); 218 return security_ops->bprm_set_creds(bprm);
219} 219}
220 220
221void security_bprm_free(struct linux_binprm *bprm) 221int security_bprm_check(struct linux_binprm *bprm)
222{
223 security_ops->bprm_free_security(bprm);
224}
225
226int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
227{
228 return security_ops->bprm_apply_creds(bprm, unsafe);
229}
230
231void security_bprm_post_apply_creds(struct linux_binprm *bprm)
232{ 222{
233 security_ops->bprm_post_apply_creds(bprm); 223 return security_ops->bprm_check_security(bprm);
234} 224}
235 225
236int security_bprm_set(struct linux_binprm *bprm) 226void security_bprm_committing_creds(struct linux_binprm *bprm)
237{ 227{
238 return security_ops->bprm_set_security(bprm); 228 return security_ops->bprm_committing_creds(bprm);
239} 229}
240 230
241int security_bprm_check(struct linux_binprm *bprm) 231void security_bprm_committed_creds(struct linux_binprm *bprm)
242{ 232{
243 return security_ops->bprm_check_security(bprm); 233 return security_ops->bprm_committed_creds(bprm);
244} 234}
245 235
246int security_bprm_secureexec(struct linux_binprm *bprm) 236int security_bprm_secureexec(struct linux_binprm *bprm)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index c71bba78872f..21a592184633 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2029,59 +2029,45 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
2029 2029
2030/* binprm security operations */ 2030/* binprm security operations */
2031 2031
2032static int selinux_bprm_alloc_security(struct linux_binprm *bprm) 2032static int selinux_bprm_set_creds(struct linux_binprm *bprm)
2033{ 2033{
2034 struct bprm_security_struct *bsec; 2034 const struct task_security_struct *old_tsec;
2035 2035 struct task_security_struct *new_tsec;
2036 bsec = kzalloc(sizeof(struct bprm_security_struct), GFP_KERNEL);
2037 if (!bsec)
2038 return -ENOMEM;
2039
2040 bsec->sid = SECINITSID_UNLABELED;
2041 bsec->set = 0;
2042
2043 bprm->security = bsec;
2044 return 0;
2045}
2046
2047static int selinux_bprm_set_security(struct linux_binprm *bprm)
2048{
2049 struct task_security_struct *tsec;
2050 struct inode *inode = bprm->file->f_path.dentry->d_inode;
2051 struct inode_security_struct *isec; 2036 struct inode_security_struct *isec;
2052 struct bprm_security_struct *bsec;
2053 u32 newsid;
2054 struct avc_audit_data ad; 2037 struct avc_audit_data ad;
2038 struct inode *inode = bprm->file->f_path.dentry->d_inode;
2055 int rc; 2039 int rc;
2056 2040
2057 rc = secondary_ops->bprm_set_security(bprm); 2041 rc = secondary_ops->bprm_set_creds(bprm);
2058 if (rc) 2042 if (rc)
2059 return rc; 2043 return rc;
2060 2044
2061 bsec = bprm->security; 2045 /* SELinux context only depends on initial program or script and not
2062 2046 * the script interpreter */
2063 if (bsec->set) 2047 if (bprm->cred_prepared)
2064 return 0; 2048 return 0;
2065 2049
2066 tsec = current_security(); 2050 old_tsec = current_security();
2051 new_tsec = bprm->cred->security;
2067 isec = inode->i_security; 2052 isec = inode->i_security;
2068 2053
2069 /* Default to the current task SID. */ 2054 /* Default to the current task SID. */
2070 bsec->sid = tsec->sid; 2055 new_tsec->sid = old_tsec->sid;
2056 new_tsec->osid = old_tsec->sid;
2071 2057
2072 /* Reset fs, key, and sock SIDs on execve. */ 2058 /* Reset fs, key, and sock SIDs on execve. */
2073 tsec->create_sid = 0; 2059 new_tsec->create_sid = 0;
2074 tsec->keycreate_sid = 0; 2060 new_tsec->keycreate_sid = 0;
2075 tsec->sockcreate_sid = 0; 2061 new_tsec->sockcreate_sid = 0;
2076 2062
2077 if (tsec->exec_sid) { 2063 if (old_tsec->exec_sid) {
2078 newsid = tsec->exec_sid; 2064 new_tsec->sid = old_tsec->exec_sid;
2079 /* Reset exec SID on execve. */ 2065 /* Reset exec SID on execve. */
2080 tsec->exec_sid = 0; 2066 new_tsec->exec_sid = 0;
2081 } else { 2067 } else {
2082 /* Check for a default transition on this program. */ 2068 /* Check for a default transition on this program. */
2083 rc = security_transition_sid(tsec->sid, isec->sid, 2069 rc = security_transition_sid(old_tsec->sid, isec->sid,
2084 SECCLASS_PROCESS, &newsid); 2070 SECCLASS_PROCESS, &new_tsec->sid);
2085 if (rc) 2071 if (rc)
2086 return rc; 2072 return rc;
2087 } 2073 }
@@ -2090,33 +2076,63 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
2090 ad.u.fs.path = bprm->file->f_path; 2076 ad.u.fs.path = bprm->file->f_path;
2091 2077
2092 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) 2078 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
2093 newsid = tsec->sid; 2079 new_tsec->sid = old_tsec->sid;
2094 2080
2095 if (tsec->sid == newsid) { 2081 if (new_tsec->sid == old_tsec->sid) {
2096 rc = avc_has_perm(tsec->sid, isec->sid, 2082 rc = avc_has_perm(old_tsec->sid, isec->sid,
2097 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); 2083 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2098 if (rc) 2084 if (rc)
2099 return rc; 2085 return rc;
2100 } else { 2086 } else {
2101 /* Check permissions for the transition. */ 2087 /* Check permissions for the transition. */
2102 rc = avc_has_perm(tsec->sid, newsid, 2088 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2103 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad); 2089 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2104 if (rc) 2090 if (rc)
2105 return rc; 2091 return rc;
2106 2092
2107 rc = avc_has_perm(newsid, isec->sid, 2093 rc = avc_has_perm(new_tsec->sid, isec->sid,
2108 SECCLASS_FILE, FILE__ENTRYPOINT, &ad); 2094 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2109 if (rc) 2095 if (rc)
2110 return rc; 2096 return rc;
2111 2097
2112 /* Clear any possibly unsafe personality bits on exec: */ 2098 /* Check for shared state */
2113 current->personality &= ~PER_CLEAR_ON_SETID; 2099 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
2100 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2101 SECCLASS_PROCESS, PROCESS__SHARE,
2102 NULL);
2103 if (rc)
2104 return -EPERM;
2105 }
2106
2107 /* Make sure that anyone attempting to ptrace over a task that
2108 * changes its SID has the appropriate permit */
2109 if (bprm->unsafe &
2110 (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
2111 struct task_struct *tracer;
2112 struct task_security_struct *sec;
2113 u32 ptsid = 0;
2114
2115 rcu_read_lock();
2116 tracer = tracehook_tracer_task(current);
2117 if (likely(tracer != NULL)) {
2118 sec = __task_cred(tracer)->security;
2119 ptsid = sec->sid;
2120 }
2121 rcu_read_unlock();
2122
2123 if (ptsid != 0) {
2124 rc = avc_has_perm(ptsid, new_tsec->sid,
2125 SECCLASS_PROCESS,
2126 PROCESS__PTRACE, NULL);
2127 if (rc)
2128 return -EPERM;
2129 }
2130 }
2114 2131
2115 /* Set the security field to the new SID. */ 2132 /* Clear any possibly unsafe personality bits on exec: */
2116 bsec->sid = newsid; 2133 bprm->per_clear |= PER_CLEAR_ON_SETID;
2117 } 2134 }
2118 2135
2119 bsec->set = 1;
2120 return 0; 2136 return 0;
2121} 2137}
2122 2138
@@ -2125,7 +2141,6 @@ static int selinux_bprm_check_security(struct linux_binprm *bprm)
2125 return secondary_ops->bprm_check_security(bprm); 2141 return secondary_ops->bprm_check_security(bprm);
2126} 2142}
2127 2143
2128
2129static int selinux_bprm_secureexec(struct linux_binprm *bprm) 2144static int selinux_bprm_secureexec(struct linux_binprm *bprm)
2130{ 2145{
2131 const struct cred *cred = current_cred(); 2146 const struct cred *cred = current_cred();
@@ -2141,19 +2156,13 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm)
2141 the noatsecure permission is granted between 2156 the noatsecure permission is granted between
2142 the two SIDs, i.e. ahp returns 0. */ 2157 the two SIDs, i.e. ahp returns 0. */
2143 atsecure = avc_has_perm(osid, sid, 2158 atsecure = avc_has_perm(osid, sid,
2144 SECCLASS_PROCESS, 2159 SECCLASS_PROCESS,
2145 PROCESS__NOATSECURE, NULL); 2160 PROCESS__NOATSECURE, NULL);
2146 } 2161 }
2147 2162
2148 return (atsecure || secondary_ops->bprm_secureexec(bprm)); 2163 return (atsecure || secondary_ops->bprm_secureexec(bprm));
2149} 2164}
2150 2165
2151static void selinux_bprm_free_security(struct linux_binprm *bprm)
2152{
2153 kfree(bprm->security);
2154 bprm->security = NULL;
2155}
2156
2157extern struct vfsmount *selinuxfs_mount; 2166extern struct vfsmount *selinuxfs_mount;
2158extern struct dentry *selinux_null; 2167extern struct dentry *selinux_null;
2159 2168
@@ -2252,108 +2261,78 @@ static inline void flush_unauthorized_files(const struct cred *cred,
2252 spin_unlock(&files->file_lock); 2261 spin_unlock(&files->file_lock);
2253} 2262}
2254 2263
2255static int selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) 2264/*
2265 * Prepare a process for imminent new credential changes due to exec
2266 */
2267static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
2256{ 2268{
2257 struct task_security_struct *tsec; 2269 struct task_security_struct *new_tsec;
2258 struct bprm_security_struct *bsec; 2270 struct rlimit *rlim, *initrlim;
2259 struct cred *new; 2271 int rc, i;
2260 u32 sid;
2261 int rc;
2262
2263 rc = secondary_ops->bprm_apply_creds(bprm, unsafe);
2264 if (rc < 0)
2265 return rc;
2266
2267 new = prepare_creds();
2268 if (!new)
2269 return -ENOMEM;
2270 2272
2271 tsec = new->security; 2273 secondary_ops->bprm_committing_creds(bprm);
2272 2274
2273 bsec = bprm->security; 2275 new_tsec = bprm->cred->security;
2274 sid = bsec->sid; 2276 if (new_tsec->sid == new_tsec->osid)
2275 2277 return;
2276 tsec->osid = tsec->sid;
2277 bsec->unsafe = 0;
2278 if (tsec->sid != sid) {
2279 /* Check for shared state. If not ok, leave SID
2280 unchanged and kill. */
2281 if (unsafe & LSM_UNSAFE_SHARE) {
2282 rc = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
2283 PROCESS__SHARE, NULL);
2284 if (rc) {
2285 bsec->unsafe = 1;
2286 goto out;
2287 }
2288 }
2289 2278
2290 /* Check for ptracing, and update the task SID if ok. 2279 /* Close files for which the new task SID is not authorized. */
2291 Otherwise, leave SID unchanged and kill. */ 2280 flush_unauthorized_files(bprm->cred, current->files);
2292 if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
2293 struct task_struct *tracer;
2294 struct task_security_struct *sec;
2295 u32 ptsid = 0;
2296 2281
2297 rcu_read_lock(); 2282 /* Always clear parent death signal on SID transitions. */
2298 tracer = tracehook_tracer_task(current); 2283 current->pdeath_signal = 0;
2299 if (likely(tracer != NULL)) {
2300 sec = __task_cred(tracer)->security;
2301 ptsid = sec->sid;
2302 }
2303 rcu_read_unlock();
2304 2284
2305 if (ptsid != 0) { 2285 /* Check whether the new SID can inherit resource limits from the old
2306 rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, 2286 * SID. If not, reset all soft limits to the lower of the current
2307 PROCESS__PTRACE, NULL); 2287 * task's hard limit and the init task's soft limit.
2308 if (rc) { 2288 *
2309 bsec->unsafe = 1; 2289 * Note that the setting of hard limits (even to lower them) can be
2310 goto out; 2290 * controlled by the setrlimit check. The inclusion of the init task's
2311 } 2291 * soft limit into the computation is to avoid resetting soft limits
2312 } 2292 * higher than the default soft limit for cases where the default is
2293 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
2294 */
2295 rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
2296 PROCESS__RLIMITINH, NULL);
2297 if (rc) {
2298 for (i = 0; i < RLIM_NLIMITS; i++) {
2299 rlim = current->signal->rlim + i;
2300 initrlim = init_task.signal->rlim + i;
2301 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2313 } 2302 }
2314 tsec->sid = sid; 2303 update_rlimit_cpu(rlim->rlim_cur);
2315 } 2304 }
2316
2317out:
2318 commit_creds(new);
2319 return 0;
2320} 2305}
2321 2306
2322/* 2307/*
2323 * called after apply_creds without the task lock held 2308 * Clean up the process immediately after the installation of new credentials
2309 * due to exec
2324 */ 2310 */
2325static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm) 2311static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
2326{ 2312{
2327 const struct cred *cred = current_cred(); 2313 const struct task_security_struct *tsec = current_security();
2328 struct task_security_struct *tsec;
2329 struct rlimit *rlim, *initrlim;
2330 struct itimerval itimer; 2314 struct itimerval itimer;
2331 struct bprm_security_struct *bsec;
2332 struct sighand_struct *psig; 2315 struct sighand_struct *psig;
2316 u32 osid, sid;
2333 int rc, i; 2317 int rc, i;
2334 unsigned long flags; 2318 unsigned long flags;
2335 2319
2336 tsec = current_security(); 2320 secondary_ops->bprm_committed_creds(bprm);
2337 bsec = bprm->security;
2338 2321
2339 if (bsec->unsafe) { 2322 osid = tsec->osid;
2340 force_sig_specific(SIGKILL, current); 2323 sid = tsec->sid;
2341 return; 2324
2342 } 2325 if (sid == osid)
2343 if (tsec->osid == tsec->sid)
2344 return; 2326 return;
2345 2327
2346 /* Close files for which the new task SID is not authorized. */ 2328 /* Check whether the new SID can inherit signal state from the old SID.
2347 flush_unauthorized_files(cred, current->files); 2329 * If not, clear itimers to avoid subsequent signal generation and
2348 2330 * flush and unblock signals.
2349 /* Check whether the new SID can inherit signal state 2331 *
2350 from the old SID. If not, clear itimers to avoid 2332 * This must occur _after_ the task SID has been updated so that any
2351 subsequent signal generation and flush and unblock 2333 * kill done after the flush will be checked against the new SID.
2352 signals. This must occur _after_ the task SID has 2334 */
2353 been updated so that any kill done after the flush 2335 rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
2354 will be checked against the new SID. */
2355 rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
2356 PROCESS__SIGINH, NULL);
2357 if (rc) { 2336 if (rc) {
2358 memset(&itimer, 0, sizeof itimer); 2337 memset(&itimer, 0, sizeof itimer);
2359 for (i = 0; i < 3; i++) 2338 for (i = 0; i < 3; i++)
@@ -2366,32 +2345,8 @@ static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
2366 spin_unlock_irq(&current->sighand->siglock); 2345 spin_unlock_irq(&current->sighand->siglock);
2367 } 2346 }
2368 2347
2369 /* Always clear parent death signal on SID transitions. */ 2348 /* Wake up the parent if it is waiting so that it can recheck
2370 current->pdeath_signal = 0; 2349 * wait permission to the new task SID. */
2371
2372 /* Check whether the new SID can inherit resource limits
2373 from the old SID. If not, reset all soft limits to
2374 the lower of the current task's hard limit and the init
2375 task's soft limit. Note that the setting of hard limits
2376 (even to lower them) can be controlled by the setrlimit
2377 check. The inclusion of the init task's soft limit into
2378 the computation is to avoid resetting soft limits higher
2379 than the default soft limit for cases where the default
2380 is lower than the hard limit, e.g. RLIMIT_CORE or
2381 RLIMIT_STACK.*/
2382 rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
2383 PROCESS__RLIMITINH, NULL);
2384 if (rc) {
2385 for (i = 0; i < RLIM_NLIMITS; i++) {
2386 rlim = current->signal->rlim + i;
2387 initrlim = init_task.signal->rlim+i;
2388 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2389 }
2390 update_rlimit_cpu(rlim->rlim_cur);
2391 }
2392
2393 /* Wake up the parent if it is waiting so that it can
2394 recheck wait permission to the new task SID. */
2395 read_lock_irq(&tasklist_lock); 2350 read_lock_irq(&tasklist_lock);
2396 psig = current->parent->sighand; 2351 psig = current->parent->sighand;
2397 spin_lock_irqsave(&psig->siglock, flags); 2352 spin_lock_irqsave(&psig->siglock, flags);
@@ -5556,12 +5511,10 @@ static struct security_operations selinux_ops = {
5556 .netlink_send = selinux_netlink_send, 5511 .netlink_send = selinux_netlink_send,
5557 .netlink_recv = selinux_netlink_recv, 5512 .netlink_recv = selinux_netlink_recv,
5558 5513
5559 .bprm_alloc_security = selinux_bprm_alloc_security, 5514 .bprm_set_creds = selinux_bprm_set_creds,
5560 .bprm_free_security = selinux_bprm_free_security,
5561 .bprm_apply_creds = selinux_bprm_apply_creds,
5562 .bprm_post_apply_creds = selinux_bprm_post_apply_creds,
5563 .bprm_set_security = selinux_bprm_set_security,
5564 .bprm_check_security = selinux_bprm_check_security, 5515 .bprm_check_security = selinux_bprm_check_security,
5516 .bprm_committing_creds = selinux_bprm_committing_creds,
5517 .bprm_committed_creds = selinux_bprm_committed_creds,
5565 .bprm_secureexec = selinux_bprm_secureexec, 5518 .bprm_secureexec = selinux_bprm_secureexec,
5566 5519
5567 .sb_alloc_security = selinux_sb_alloc_security, 5520 .sb_alloc_security = selinux_sb_alloc_security,
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index f8be8d7fa26d..3cc45168f674 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -77,17 +77,6 @@ struct ipc_security_struct {
77 u32 sid; /* SID of IPC resource */ 77 u32 sid; /* SID of IPC resource */
78}; 78};
79 79
80struct bprm_security_struct {
81 u32 sid; /* SID for transformed process */
82 unsigned char set;
83
84 /*
85 * unsafe is used to share failure information from bprm_apply_creds()
86 * to bprm_post_apply_creds().
87 */
88 char unsafe;
89};
90
91struct netif_security_struct { 80struct netif_security_struct {
92 int ifindex; /* device index */ 81 int ifindex; /* device index */
93 u32 sid; /* SID for this interface */ 82 u32 sid; /* SID for this interface */
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index e952b397153d..de396742abf4 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2596,8 +2596,7 @@ struct security_operations smack_ops = {
2596 .settime = cap_settime, 2596 .settime = cap_settime,
2597 .vm_enough_memory = cap_vm_enough_memory, 2597 .vm_enough_memory = cap_vm_enough_memory,
2598 2598
2599 .bprm_apply_creds = cap_bprm_apply_creds, 2599 .bprm_set_creds = cap_bprm_set_creds,
2600 .bprm_set_security = cap_bprm_set_security,
2601 .bprm_secureexec = cap_bprm_secureexec, 2600 .bprm_secureexec = cap_bprm_secureexec,
2602 2601
2603 .sb_alloc_security = smack_sb_alloc_security, 2602 .sb_alloc_security = smack_sb_alloc_security,