Index: linux-2.6.10-rc3-bk2/fs/exec.c =================================================================== --- linux-2.6.10-rc3-bk2.orig/fs/exec.c 2004-12-07 19:35:47.000000000 -0600 +++ linux-2.6.10-rc3-bk2/fs/exec.c 2004-12-09 13:00:57.000000000 -0600 @@ -953,6 +953,7 @@ unsafe = unsafe_exec(current); security_bprm_apply_creds(bprm, unsafe); task_unlock(current); + security_bprm_final_setup(bprm); } EXPORT_SYMBOL(compute_creds); Index: linux-2.6.10-rc3-bk2/include/linux/security.h =================================================================== --- linux-2.6.10-rc3-bk2.orig/include/linux/security.h 2004-12-08 18:45:30.000000000 -0600 +++ linux-2.6.10-rc3-bk2/include/linux/security.h 2004-12-09 13:04:02.000000000 -0600 @@ -115,6 +115,10 @@ * bprm_apply_creds is called under task_lock. @unsafe indicates various * reasons why it may be unsafe to change security state. * @bprm contains the linux_binprm structure. + * @bprm_final_setup: + * Runs after bprm_apply_creds with the task_lock dropped, to perform + * slower but necessary checks and setup on execution a new binary. + * @bprm contains the linux_binprm structure. * @bprm_set_security: * Save security information in the bprm->security field, typically based * on information about the bprm->file, for later use by the apply_creds @@ -1041,6 +1045,7 @@ int (*bprm_alloc_security) (struct linux_binprm * bprm); void (*bprm_free_security) (struct linux_binprm * bprm); void (*bprm_apply_creds) (struct linux_binprm * bprm, int unsafe); + void (*bprm_final_setup) (struct linux_binprm * bprm); int (*bprm_set_security) (struct linux_binprm * bprm); int (*bprm_check_security) (struct linux_binprm * bprm); int (*bprm_secureexec) (struct linux_binprm * bprm); @@ -1313,6 +1318,10 @@ { security_ops->bprm_apply_creds (bprm, unsafe); } +static inline void security_bprm_final_setup (struct linux_binprm *bprm) +{ + security_ops->bprm_final_setup (bprm); +} static inline int security_bprm_set (struct linux_binprm *bprm) { return security_ops->bprm_set_security (bprm); @@ -1990,6 +1999,11 @@ cap_bprm_apply_creds (bprm, unsafe); } +static inline void security_bprm_final_setup (struct linux_binprm *bprm) +{ + return; +} + static inline int security_bprm_set (struct linux_binprm *bprm) { return cap_bprm_set_security (bprm); Index: linux-2.6.10-rc3-bk2/security/dummy.c =================================================================== --- linux-2.6.10-rc3-bk2.orig/security/dummy.c 2004-12-08 18:09:39.000000000 -0600 +++ linux-2.6.10-rc3-bk2/security/dummy.c 2004-12-09 13:02:21.000000000 -0600 @@ -193,6 +193,11 @@ current->sgid = current->egid = current->fsgid = bprm->e_gid; } +static void dummy_bprm_final_setup (struct linux_binprm *bprm) +{ + return; +} + static int dummy_bprm_set_security (struct linux_binprm *bprm) { return 0; @@ -908,6 +913,7 @@ set_to_dummy_if_null(ops, bprm_alloc_security); set_to_dummy_if_null(ops, bprm_free_security); set_to_dummy_if_null(ops, bprm_apply_creds); + set_to_dummy_if_null(ops, bprm_final_setup); set_to_dummy_if_null(ops, bprm_set_security); set_to_dummy_if_null(ops, bprm_check_security); set_to_dummy_if_null(ops, bprm_secureexec); Index: linux-2.6.10-rc3-bk2/security/selinux/hooks.c =================================================================== --- linux-2.6.10-rc3-bk2.orig/security/selinux/hooks.c 2004-12-08 18:45:29.000000000 -0600 +++ linux-2.6.10-rc3-bk2/security/selinux/hooks.c 2004-12-09 19:26:58.000000000 -0600 @@ -1807,11 +1807,9 @@ { struct task_security_struct *tsec; struct bprm_security_struct *bsec; - u32 sid; struct av_decision avd; - struct itimerval itimer; - struct rlimit *rlim, *initrlim; - int rc, i; + u32 sid; + int rc; secondary_ops->bprm_apply_creds(bprm, unsafe); @@ -1821,6 +1819,7 @@ sid = bsec->sid; tsec->osid = tsec->sid; + tsec->unsafe = 0; if (tsec->sid != sid) { /* Check for shared state. If not ok, leave SID unchanged and kill. */ @@ -1829,11 +1828,11 @@ SECCLASS_PROCESS, PROCESS__SHARE, NULL, &avd); if (rc) { - task_unlock(current); avc_audit(tsec->sid, sid, SECCLASS_PROCESS, PROCESS__SHARE, &avd, rc, NULL); + tsec->unsafe = 1; force_sig_specific(SIGKILL, current); - goto lock_out; + return; } } @@ -1843,73 +1842,86 @@ rc = avc_has_perm_noaudit(tsec->ptrace_sid, sid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL, &avd); - if (!rc) - tsec->sid = sid; - task_unlock(current); avc_audit(tsec->ptrace_sid, sid, SECCLASS_PROCESS, PROCESS__PTRACE, &avd, rc, NULL); if (rc) { force_sig_specific(SIGKILL, current); - goto lock_out; - } - } else { + tsec->unsafe = 1; + } else + tsec->sid = sid; + } else tsec->sid = sid; - task_unlock(current); - } + } +} - /* Close files for which the new task SID is not authorized. */ - flush_unauthorized_files(current->files); +/* + * called after apply_creds without the task lock held + */ +static void selinux_bprm_final_setup(struct linux_binprm *bprm) +{ + struct task_security_struct *tsec; + struct bprm_security_struct *bsec; + struct rlimit *rlim, *initrlim; + struct itimerval itimer; + int rc, i; + u32 sid; - /* Check whether the new SID can inherit signal state - from the old SID. If not, clear itimers to avoid - subsequent signal generation and flush and unblock - signals. This must occur _after_ the task SID has - been updated so that any kill done after the flush - will be checked against the new SID. */ - rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS, - PROCESS__SIGINH, NULL, NULL); - if (rc) { - memset(&itimer, 0, sizeof itimer); - for (i = 0; i < 3; i++) - do_setitimer(i, &itimer, NULL); - flush_signals(current); - spin_lock_irq(¤t->sighand->siglock); - flush_signal_handlers(current, 1); - sigemptyset(¤t->blocked); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + tsec = current->security; + bsec = bprm->security; + sid = bsec->sid; - /* Check whether the new SID can inherit resource limits - from the old SID. If not, reset all soft limits to - the lower of the current task's hard limit and the init - task's soft limit. Note that the setting of hard limits - (even to lower them) can be controlled by the setrlimit - check. The inclusion of the init task's soft limit into - the computation is to avoid resetting soft limits higher - than the default soft limit for cases where the default - is lower than the hard limit, e.g. RLIMIT_CORE or - RLIMIT_STACK.*/ - rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS, - PROCESS__RLIMITINH, NULL, NULL); - if (rc) { - for (i = 0; i < RLIM_NLIMITS; i++) { - rlim = current->signal->rlim + i; - initrlim = init_task.signal->rlim+i; - rlim->rlim_cur = min(rlim->rlim_max,initrlim->rlim_cur); - } - } + if (tsec->unsafe) + return; - /* Wake up the parent if it is waiting so that it can - recheck wait permission to the new task SID. */ - wake_up_interruptible(¤t->parent->wait_chldexit); + /* Close files for which the new task SID is not authorized. */ + flush_unauthorized_files(current->files); -lock_out: - task_lock(current); - return; + /* Check whether the new SID can inherit signal state + from the old SID. If not, clear itimers to avoid + subsequent signal generation and flush and unblock + signals. This must occur _after_ the task SID has + been updated so that any kill done after the flush + will be checked against the new SID. */ + rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS, + PROCESS__SIGINH, NULL, NULL); + if (rc) { + memset(&itimer, 0, sizeof itimer); + for (i = 0; i < 3; i++) + do_setitimer(i, &itimer, NULL); + flush_signals(current); + spin_lock_irq(¤t->sighand->siglock); + flush_signal_handlers(current, 1); + sigemptyset(¤t->blocked); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } + + /* Check whether the new SID can inherit resource limits + from the old SID. If not, reset all soft limits to + the lower of the current task's hard limit and the init + task's soft limit. Note that the setting of hard limits + (even to lower them) can be controlled by the setrlimit + check. The inclusion of the init task's soft limit into + the computation is to avoid resetting soft limits higher + than the default soft limit for cases where the default + is lower than the hard limit, e.g. RLIMIT_CORE or + RLIMIT_STACK.*/ + rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS, + PROCESS__RLIMITINH, NULL, NULL); + if (rc) { + for (i = 0; i < RLIM_NLIMITS; i++) { + rlim = current->signal->rlim + i; + initrlim = init_task.signal->rlim+i; + rlim->rlim_cur = min(rlim->rlim_max,initrlim->rlim_cur); + } } + + /* Wake up the parent if it is waiting so that it can + recheck wait permission to the new task SID. */ + wake_up_interruptible(¤t->parent->wait_chldexit); } + /* superblock security operations */ static int selinux_sb_alloc_security(struct super_block *sb) @@ -4180,6 +4192,7 @@ .bprm_alloc_security = selinux_bprm_alloc_security, .bprm_free_security = selinux_bprm_free_security, .bprm_apply_creds = selinux_bprm_apply_creds, + .bprm_final_setup = selinux_bprm_final_setup, .bprm_set_security = selinux_bprm_set_security, .bprm_check_security = selinux_bprm_check_security, .bprm_secureexec = selinux_bprm_secureexec, Index: linux-2.6.10-rc3-bk2/security/selinux/include/objsec.h =================================================================== --- linux-2.6.10-rc3-bk2.orig/security/selinux/include/objsec.h 2004-12-07 19:35:54.000000000 -0600 +++ linux-2.6.10-rc3-bk2/security/selinux/include/objsec.h 2004-12-09 17:19:48.000000000 -0600 @@ -35,6 +35,12 @@ u32 create_sid; /* fscreate SID */ struct avc_entry_ref avcr; /* reference to process permissions */ u32 ptrace_sid; /* SID of ptrace parent */ + + /* + * used to share failure information from bprm_apply_creds() + * to bprm_final_setup(). + */ + char unsafe; }; struct inode_security_struct {