diff --git a/include/linux/capability.h b/include/linux/capability.h index 0f1950181102a10c4c72de50922c190b9d5dc404..b313ba1dd5d1042b5d9f5783ac1b7c22f05e242c 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -521,6 +521,8 @@ extern const kernel_cap_t __cap_init_eff_set; kernel_cap_t cap_set_effective(const kernel_cap_t pE_new); +extern int security_capable(struct task_struct *t, int cap); +extern int security_capable_noaudit(struct task_struct *t, int cap); /** * has_capability - Determine if a task has a superior capability available * @t: The task in question @@ -532,6 +534,7 @@ kernel_cap_t cap_set_effective(const kernel_cap_t pE_new); * Note that this does not set PF_SUPERPRIV on the task. */ #define has_capability(t, cap) (security_capable((t), (cap)) == 0) +#define has_capability_noaudit(t, cap) (security_capable_noaudit((t), (cap)) == 0) extern int capable(int cap); diff --git a/include/linux/security.h b/include/linux/security.h index c13f1cec9abb154e24296216d91d225d245166b2..5fe28a671cd3a7f6af81795c75af20cc14c8637b 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -37,6 +37,10 @@ /* Maximum number of letters for an LSM name string */ #define SECURITY_NAME_MAX 10 +/* If capable should audit the security request */ +#define SECURITY_CAP_NOAUDIT 0 +#define SECURITY_CAP_AUDIT 1 + struct ctl_table; struct audit_krule; @@ -44,7 +48,7 @@ struct audit_krule; * These functions are in security/capability.c and are used * as the default capabilities functions */ -extern int cap_capable(struct task_struct *tsk, int cap); +extern int cap_capable(struct task_struct *tsk, int cap, int audit); extern int cap_settime(struct timespec *ts, struct timezone *tz); extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode); extern int cap_ptrace_traceme(struct task_struct *parent); @@ -1307,7 +1311,7 @@ struct security_operations { kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); - int (*capable) (struct task_struct *tsk, int cap); + int (*capable) (struct task_struct *tsk, int cap, int audit); int (*acct) (struct file *file); int (*sysctl) (struct ctl_table *table, int op); int (*quotactl) (int cmds, int type, int id, struct super_block *sb); @@ -1577,6 +1581,7 @@ void security_capset_set(struct task_struct *target, kernel_cap_t *inheritable, kernel_cap_t *permitted); int security_capable(struct task_struct *tsk, int cap); +int security_capable_noaudit(struct task_struct *tsk, int cap); int security_acct(struct file *file); int security_sysctl(struct ctl_table *table, int op); int security_quotactl(int cmds, int type, int id, struct super_block *sb); @@ -1782,7 +1787,12 @@ static inline void security_capset_set(struct task_struct *target, static inline int security_capable(struct task_struct *tsk, int cap) { - return cap_capable(tsk, cap); + return cap_capable(tsk, cap, SECURITY_CAP_AUDIT); +} + +static inline int security_capable_noaudit(struct task_struct *tsk, int cap) +{ + return cap_capable(tsk, cap, SECURITY_CAP_NOAUDIT); } static inline int security_acct(struct file *file) diff --git a/security/commoncap.c b/security/commoncap.c index d45393380997b4dfa5be7535be080bc4a4719787..dc06c0086b558c1d561057b4bcb7913954b97f42 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -49,7 +49,7 @@ EXPORT_SYMBOL(cap_netlink_recv); * returns 0 when a task has a capability, but the kernel's capable() * returns 1 for this case. */ -int cap_capable (struct task_struct *tsk, int cap) +int cap_capable(struct task_struct *tsk, int cap, int audit) { /* Derived from include/linux/sched.h:capable. */ if (cap_raised(tsk->cap_effective, cap)) @@ -112,7 +112,7 @@ static inline int cap_inh_is_capped(void) * to the old permitted set. That is, if the current task * does *not* possess the CAP_SETPCAP capability. */ - return (cap_capable(current, CAP_SETPCAP) != 0); + return (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0); } static inline int cap_limit_ptraced_target(void) { return 1; } @@ -677,7 +677,7 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, || ((current->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ - || (cap_capable(current, CAP_SETPCAP) != 0)) { /*[4]*/ + || (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0)) { /*[4]*/ /* * [1] no changing of bits that are locked * [2] no unlocking of locks @@ -742,7 +742,7 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages) { int cap_sys_admin = 0; - if (cap_capable(current, CAP_SYS_ADMIN) == 0) + if (cap_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT) == 0) cap_sys_admin = 1; return __vm_enough_memory(mm, pages, cap_sys_admin); } diff --git a/security/security.c b/security/security.c index c0acfa7177e5d1a01d19375f94bfa1ff819637a3..346f21e0ec2cbd7ad5239bfc8f203383252990d3 100644 --- a/security/security.c +++ b/security/security.c @@ -163,7 +163,12 @@ void security_capset_set(struct task_struct *target, int security_capable(struct task_struct *tsk, int cap) { - return security_ops->capable(tsk, cap); + return security_ops->capable(tsk, cap, SECURITY_CAP_AUDIT); +} + +int security_capable_noaudit(struct task_struct *tsk, int cap) +{ + return security_ops->capable(tsk, cap, SECURITY_CAP_NOAUDIT); } int security_acct(struct file *file) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7fd4de46b2a91be21cf90d7a5b947ea8b6b56886..88a3ee33068a8a6e34912288f4f2ac13fd75a303 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1365,12 +1365,14 @@ static int task_has_perm(struct task_struct *tsk1, /* Check whether a task is allowed to use a capability. */ static int task_has_capability(struct task_struct *tsk, - int cap) + int cap, int audit) { struct task_security_struct *tsec; struct avc_audit_data ad; + struct av_decision avd; u16 sclass; u32 av = CAP_TO_MASK(cap); + int rc; tsec = tsk->security; @@ -1390,7 +1392,11 @@ static int task_has_capability(struct task_struct *tsk, "SELinux: out of range capability %d\n", cap); BUG(); } - return avc_has_perm(tsec->sid, tsec->sid, sclass, av, &ad); + + rc = avc_has_perm_noaudit(tsec->sid, tsec->sid, sclass, av, 0, &avd); + if (audit == SECURITY_CAP_AUDIT) + avc_audit(tsec->sid, tsec->sid, sclass, av, &avd, rc, &ad); + return rc; } /* Check whether a task is allowed to use a system operation. */ @@ -1802,15 +1808,15 @@ static void selinux_capset_set(struct task_struct *target, kernel_cap_t *effecti secondary_ops->capset_set(target, effective, inheritable, permitted); } -static int selinux_capable(struct task_struct *tsk, int cap) +static int selinux_capable(struct task_struct *tsk, int cap, int audit) { int rc; - rc = secondary_ops->capable(tsk, cap); + rc = secondary_ops->capable(tsk, cap, audit); if (rc) return rc; - return task_has_capability(tsk, cap); + return task_has_capability(tsk, cap, audit); } static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid) @@ -1975,7 +1981,7 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) int rc, cap_sys_admin = 0; struct task_security_struct *tsec = current->security; - rc = secondary_ops->capable(current, CAP_SYS_ADMIN); + rc = secondary_ops->capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT); if (rc == 0) rc = avc_has_perm_noaudit(tsec->sid, tsec->sid, SECCLASS_CAPABILITY, @@ -2829,7 +2835,7 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name * and lack of permission just means that we fall back to the * in-core context value, not a denial. */ - error = secondary_ops->capable(current, CAP_MAC_ADMIN); + error = secondary_ops->capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT); if (!error) error = avc_has_perm_noaudit(tsec->sid, tsec->sid, SECCLASS_CAPABILITY2,