summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/capability.h3
-rw-r--r--include/linux/security.h16
-rw-r--r--security/commoncap.c8
-rw-r--r--security/security.c7
-rw-r--r--security/selinux/hooks.c20
5 files changed, 39 insertions, 15 deletions
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 0f1950181102..b313ba1dd5d1 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 c13f1cec9abb..5fe28a671cd3 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 d45393380997..dc06c0086b55 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 c0acfa7177e5..346f21e0ec2c 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 7fd4de46b2a9..88a3ee33068a 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,