--- linux-2.6.6-mm2-cap/include/linux/capability.h.orig 2004-05-09 19:32:26.000000000 -0700 +++ linux-2.6.6-mm2-cap/include/linux/capability.h 2004-05-17 23:24:08.143860096 -0700 @@ -309,7 +309,9 @@ #define CAP_EMPTY_SET to_cap_t(0) #define CAP_FULL_SET to_cap_t(~0) #define CAP_INIT_EFF_SET to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP)) -#define CAP_INIT_INH_SET to_cap_t(0) +#define CAP_INIT_INH_SET to_cap_t(~0) +/* ~0 is legacy inheritable mode and can never be capset by user */ +#define cap_orig_inh(_cap) (cap_t((_cap)) == ~0) #define CAP_TO_MASK(x) (1 << (x)) #define cap_raise(c, flag) (cap_t(c) |= CAP_TO_MASK(flag)) --- linux-2.6.6-mm2-cap/security/commoncap.c.orig 2004-05-13 22:06:24.000000000 -0700 +++ linux-2.6.6-mm2-cap/security/commoncap.c 2004-05-17 23:22:48.883909440 -0700 @@ -46,9 +46,12 @@ int cap_capget (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { + kernel_cap_t target_inheritable = target->cap_inheritable; + if (cap_orig_inh(target_inheritable)) + target_inheritable = 0; /* Derived from kernel/capability.c:sys_capget. */ *effective = cap_t (target->cap_effective); - *inheritable = cap_t (target->cap_inheritable); + *inheritable = cap_t (target_inheritable); *permitted = cap_t (target->cap_permitted); return 0; } @@ -56,10 +59,13 @@ int cap_capset_check (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { + kernel_cap_t target_inheritable = target->cap_inheritable; + if (cap_orig_inh(target_inheritable)) + target_inheritable = 0; /* Derived from kernel/capability.c:sys_capset. */ /* verify restrictions on target's new Inheritable set */ if (!cap_issubset (*inheritable, - cap_combine (target->cap_inheritable, + cap_combine (target_inheritable, current->cap_permitted))) { return -EPERM; } @@ -96,6 +102,12 @@ cap_clear (bprm->cap_permitted); cap_clear (bprm->cap_effective); + if (!cap_orig_inh(current->cap_inheritable)) { + bprm->cap_permitted = cap_intersect(current->cap_permitted, + current->cap_inheritable); + bprm->cap_effective = cap_intersect(current->cap_effective, + current->cap_inheritable); + } /* To support inheritance of root-permissions and suid-root * executables under compatibility mode, we raise all three * capability sets for the file. @@ -105,12 +117,23 @@ */ if (!issecure (SECURE_NOROOT)) { + int mode = bprm->file->f_dentry->d_inode->i_mode; if (bprm->e_uid == 0 || current->uid == 0) { - cap_set_full (bprm->cap_inheritable); - cap_set_full (bprm->cap_permitted); + if (cap_orig_inh(current->cap_inheritable)) { + cap_set_full(bprm->cap_inheritable); + cap_set_full(bprm->cap_permitted); + } + if (mode & S_ISUID) { + cap_set_full(bprm->cap_inheritable); + if (bprm->e_uid == 0) + cap_set_full(bprm->cap_permitted); + else + cap_clear(bprm->cap_effective); + } } if (bprm->e_uid == 0) - cap_set_full (bprm->cap_effective); + if (cap_orig_inh(current->cap_inheritable) || mode & S_ISUID) + cap_set_full(bprm->cap_effective); } return 0; } @@ -118,11 +141,13 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) { /* Derived from fs/exec.c:compute_creds. */ - kernel_cap_t new_permitted, working; + kernel_cap_t new_permitted, working, cap_inheritable; + cap_inheritable = current->cap_inheritable; + if (cap_orig_inh(cap_inheritable)) + cap_inheritable = 0; new_permitted = cap_intersect (bprm->cap_permitted, cap_bset); - working = cap_intersect (bprm->cap_inheritable, - current->cap_inheritable); + working = cap_intersect (bprm->cap_inheritable, cap_inheritable); new_permitted = cap_combine (new_permitted, working); if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || @@ -148,9 +173,13 @@ * in the init_task struct. Thus we skip the usual * capability rules */ if (current->pid != 1) { + int mode = bprm->file->f_dentry->d_inode->i_mode; current->cap_permitted = new_permitted; current->cap_effective = cap_intersect (new_permitted, bprm->cap_effective); + /* reset on setuid root */ + if (!bprm->e_uid && mode & S_ISUID) + current->cap_inheritable = CAP_INIT_INH_SET; } /* AUD: Audit candidate if current->cap_effective is set */