aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/lsm_audit.h5
-rw-r--r--security/selinux/avc.c24
-rw-r--r--security/selinux/hooks.c20
-rw-r--r--security/selinux/include/classmap.h2
4 files changed, 43 insertions, 8 deletions
diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h
index 6907251d5200..788f0ab937aa 100644
--- a/include/linux/lsm_audit.h
+++ b/include/linux/lsm_audit.h
@@ -90,6 +90,11 @@ struct common_audit_data {
u32 requested;
u32 audited;
u32 denied;
+ /*
+ * auditdeny is a bit tricky and unintuitive. See the
+ * comments in avc.c for it's meaning and usage.
+ */
+ u32 auditdeny;
struct av_decision *avd;
int result;
} selinux_audit_data;
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 3662b0f15ec5..9da6420e2056 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -488,9 +488,29 @@ void avc_audit(u32 ssid, u32 tsid,
struct common_audit_data stack_data;
u32 denied, audited;
denied = requested & ~avd->allowed;
- if (denied)
+ if (denied) {
audited = denied & avd->auditdeny;
- else if (result)
+ /*
+ * a->selinux_audit_data.auditdeny is TRICKY! Setting a bit in
+ * this field means that ANY denials should NOT be audited if
+ * the policy contains an explicit dontaudit rule for that
+ * permission. Take notice that this is unrelated to the
+ * actual permissions that were denied. As an example lets
+ * assume:
+ *
+ * denied == READ
+ * avd.auditdeny & ACCESS == 0 (not set means explicit rule)
+ * selinux_audit_data.auditdeny & ACCESS == 1
+ *
+ * We will NOT audit the denial even though the denied
+ * permission was READ and the auditdeny checks were for
+ * ACCESS
+ */
+ if (a &&
+ a->selinux_audit_data.auditdeny &&
+ !(a->selinux_audit_data.auditdeny & avd->auditdeny))
+ audited = 0;
+ } else if (result)
audited = denied = requested;
else
audited = requested & avd->auditallow;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 0c98846f188d..650947a72a2b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2644,16 +2644,26 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na
static int selinux_inode_permission(struct inode *inode, int mask)
{
const struct cred *cred = current_cred();
+ struct common_audit_data ad;
+ u32 perms;
+ bool from_access;
+ from_access = mask & MAY_ACCESS;
mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
- if (!mask) {
- /* No permission to check. Existence test. */
+ /* No permission to check. Existence test. */
+ if (!mask)
return 0;
- }
- return inode_has_perm(cred, inode,
- file_mask_to_av(inode->i_mode, mask), NULL);
+ COMMON_AUDIT_DATA_INIT(&ad, FS);
+ ad.u.fs.inode = inode;
+
+ if (from_access)
+ ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
+
+ perms = file_mask_to_av(inode->i_mode, mask);
+
+ return inode_has_perm(cred, inode, perms, &ad);
}
static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 8b32e959bb2e..d64603e10dbe 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -2,7 +2,7 @@
"getattr", "setattr", "lock", "relabelfrom", "relabelto", "append"
#define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \
- "rename", "execute", "swapon", "quotaon", "mounton"
+ "rename", "execute", "swapon", "quotaon", "mounton", "audit_access"
#define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \
"listen", "accept", "getopt", "setopt", "shutdown", "recvfrom", \