diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/capability.c | 1 | ||||
-rw-r--r-- | security/commoncap.c | 103 | ||||
-rw-r--r-- | security/dummy.c | 2 | ||||
-rw-r--r-- | security/security.c | 4 | ||||
-rw-r--r-- | security/selinux/hooks.c | 5 |
5 files changed, 101 insertions, 14 deletions
diff --git a/security/capability.c b/security/capability.c index 2c6e06d18fa..38ac54e3aed 100644 --- a/security/capability.c +++ b/security/capability.c @@ -44,6 +44,7 @@ static struct security_operations capability_ops = { .task_setioprio = cap_task_setioprio, .task_setnice = cap_task_setnice, .task_post_setuid = cap_task_post_setuid, + .task_prctl = cap_task_prctl, .task_reparent_to_init = cap_task_reparent_to_init, .syslog = cap_syslog, diff --git a/security/commoncap.c b/security/commoncap.c index 852905789ca..e8c3f5e4670 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -24,11 +24,8 @@ #include <linux/hugetlb.h> #include <linux/mount.h> #include <linux/sched.h> - -/* Global security state */ - -unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ -EXPORT_SYMBOL(securebits); +#include <linux/prctl.h> +#include <linux/securebits.h> int cap_netlink_send(struct sock *sk, struct sk_buff *skb) { @@ -368,7 +365,7 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) /* AUD: Audit candidate if current->cap_effective is set */ - current->keep_capabilities = 0; + current->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); } int cap_bprm_secureexec (struct linux_binprm *bprm) @@ -448,7 +445,7 @@ static inline void cap_emulate_setxuid (int old_ruid, int old_euid, { if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) && (current->uid != 0 && current->euid != 0 && current->suid != 0) && - !current->keep_capabilities) { + !issecure(SECURE_KEEP_CAPS)) { cap_clear (current->cap_permitted); cap_clear (current->cap_effective); } @@ -547,7 +544,7 @@ int cap_task_setnice (struct task_struct *p, int nice) * this task could get inconsistent info. There can be no * racing writer bc a task can only change its own caps. */ -long cap_prctl_drop(unsigned long cap) +static long cap_prctl_drop(unsigned long cap) { if (!capable(CAP_SETPCAP)) return -EPERM; @@ -556,6 +553,7 @@ long cap_prctl_drop(unsigned long cap) cap_lower(current->cap_bset, cap); return 0; } + #else int cap_task_setscheduler (struct task_struct *p, int policy, struct sched_param *lp) @@ -572,12 +570,99 @@ int cap_task_setnice (struct task_struct *p, int nice) } #endif +int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5, long *rc_p) +{ + long error = 0; + + switch (option) { + case PR_CAPBSET_READ: + if (!cap_valid(arg2)) + error = -EINVAL; + else + error = !!cap_raised(current->cap_bset, arg2); + break; +#ifdef CONFIG_SECURITY_FILE_CAPABILITIES + case PR_CAPBSET_DROP: + error = cap_prctl_drop(arg2); + break; + + /* + * The next four prctl's remain to assist with transitioning a + * system from legacy UID=0 based privilege (when filesystem + * capabilities are not in use) to a system using filesystem + * capabilities only - as the POSIX.1e draft intended. + * + * Note: + * + * PR_SET_SECUREBITS = + * issecure_mask(SECURE_KEEP_CAPS_LOCKED) + * | issecure_mask(SECURE_NOROOT) + * | issecure_mask(SECURE_NOROOT_LOCKED) + * | issecure_mask(SECURE_NO_SETUID_FIXUP) + * | issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED) + * + * will ensure that the current process and all of its + * children will be locked into a pure + * capability-based-privilege environment. + */ + case PR_SET_SECUREBITS: + if ((((current->securebits & SECURE_ALL_LOCKS) >> 1) + & (current->securebits ^ arg2)) /*[1]*/ + || ((current->securebits & SECURE_ALL_LOCKS + & ~arg2)) /*[2]*/ + || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ + || (cap_capable(current, CAP_SETPCAP) != 0)) { /*[4]*/ + /* + * [1] no changing of bits that are locked + * [2] no unlocking of locks + * [3] no setting of unsupported bits + * [4] doing anything requires privilege (go read about + * the "sendmail capabilities bug") + */ + error = -EPERM; /* cannot change a locked bit */ + } else { + current->securebits = arg2; + } + break; + case PR_GET_SECUREBITS: + error = current->securebits; + break; + +#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ + + case PR_GET_KEEPCAPS: + if (issecure(SECURE_KEEP_CAPS)) + error = 1; + break; + case PR_SET_KEEPCAPS: + if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */ + error = -EINVAL; + else if (issecure(SECURE_KEEP_CAPS_LOCKED)) + error = -EPERM; + else if (arg2) + current->securebits |= issecure_mask(SECURE_KEEP_CAPS); + else + current->securebits &= + ~issecure_mask(SECURE_KEEP_CAPS); + break; + + default: + /* No functionality available - continue with default */ + return 0; + } + + /* Functionality provided */ + *rc_p = error; + return 1; +} + void cap_task_reparent_to_init (struct task_struct *p) { cap_set_init_eff(p->cap_effective); cap_clear(p->cap_inheritable); cap_set_full(p->cap_permitted); - p->keep_capabilities = 0; + p->securebits = SECUREBITS_DEFAULT; return; } diff --git a/security/dummy.c b/security/dummy.c index b0232bbf427..58d4dd1af5c 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -604,7 +604,7 @@ static int dummy_task_kill (struct task_struct *p, struct siginfo *info, } static int dummy_task_prctl (int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5) + unsigned long arg4, unsigned long arg5, long *rc_p) { return 0; } diff --git a/security/security.c b/security/security.c index 8a285c7b996..d5cb5898d96 100644 --- a/security/security.c +++ b/security/security.c @@ -733,9 +733,9 @@ int security_task_wait(struct task_struct *p) } int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5) + unsigned long arg4, unsigned long arg5, long *rc_p) { - return security_ops->task_prctl(option, arg2, arg3, arg4, arg5); + return security_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p); } void security_task_reparent_to_init(struct task_struct *p) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 308e2cf17d7..04acb5af831 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3303,12 +3303,13 @@ static int selinux_task_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, - unsigned long arg5) + unsigned long arg5, + long *rc_p) { /* The current prctl operations do not appear to require any SELinux controls since they merely observe or modify the state of the current process. */ - return 0; + return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p); } static int selinux_task_wait(struct task_struct *p) |