aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2010-07-23 11:44:03 -0400
committerJames Morris <jmorris@namei.org>2010-08-02 01:35:07 -0400
commitb782e0a68d17894d9a618ffea55b33639faa6bb4 (patch)
tree307bc615153075a6e92be5d839a58ff48d6525f3 /security/selinux
parentd09ca73979460b96d5d4684d588b188be9a1f57d (diff)
SELinux: special dontaudit for access checks
Currently there are a number of applications (nautilus being the main one) which calls access() on files in order to determine how they should be displayed. It is normal and expected that nautilus will want to see if files are executable or if they are really read/write-able. access() should return the real permission. SELinux policy checks are done in access() and can result in lots of AVC denials as policy denies RWX on files which DAC allows. Currently SELinux must dontaudit actual attempts to read/write/execute a file in order to silence these messages (and not flood the logs.) But dontaudit rules like that can hide real attacks. This patch addes a new common file permission audit_access. This permission is special in that it is meaningless and should never show up in an allow rule. Instead the only place this permission has meaning is in a dontaudit rule like so: dontaudit nautilus_t sbin_t:file audit_access With such a rule if nautilus just checks access() we will still get denied and thus userspace will still get the correct answer but we will not log the denial. If nautilus attempted to actually perform one of the forbidden actions (rather than just querying access(2) about it) we would still log a denial. This type of dontaudit rule should be used sparingly, as it could be a method for an attacker to probe the system permissions without detection. Signed-off-by: Eric Paris <eparis@redhat.com> Acked-by: Stephen D. Smalley <sds@tycho.nsa.gov> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/selinux')
-rw-r--r--security/selinux/avc.c24
-rw-r--r--security/selinux/hooks.c20
-rw-r--r--security/selinux/include/classmap.h2
3 files changed, 38 insertions, 8 deletions
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,
488 struct common_audit_data stack_data; 488 struct common_audit_data stack_data;
489 u32 denied, audited; 489 u32 denied, audited;
490 denied = requested & ~avd->allowed; 490 denied = requested & ~avd->allowed;
491 if (denied) 491 if (denied) {
492 audited = denied & avd->auditdeny; 492 audited = denied & avd->auditdeny;
493 else if (result) 493 /*
494 * a->selinux_audit_data.auditdeny is TRICKY! Setting a bit in
495 * this field means that ANY denials should NOT be audited if
496 * the policy contains an explicit dontaudit rule for that
497 * permission. Take notice that this is unrelated to the
498 * actual permissions that were denied. As an example lets
499 * assume:
500 *
501 * denied == READ
502 * avd.auditdeny & ACCESS == 0 (not set means explicit rule)
503 * selinux_audit_data.auditdeny & ACCESS == 1
504 *
505 * We will NOT audit the denial even though the denied
506 * permission was READ and the auditdeny checks were for
507 * ACCESS
508 */
509 if (a &&
510 a->selinux_audit_data.auditdeny &&
511 !(a->selinux_audit_data.auditdeny & avd->auditdeny))
512 audited = 0;
513 } else if (result)
494 audited = denied = requested; 514 audited = denied = requested;
495 else 515 else
496 audited = requested & avd->auditallow; 516 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
2644static int selinux_inode_permission(struct inode *inode, int mask) 2644static int selinux_inode_permission(struct inode *inode, int mask)
2645{ 2645{
2646 const struct cred *cred = current_cred(); 2646 const struct cred *cred = current_cred();
2647 struct common_audit_data ad;
2648 u32 perms;
2649 bool from_access;
2647 2650
2651 from_access = mask & MAY_ACCESS;
2648 mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND); 2652 mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
2649 2653
2650 if (!mask) { 2654 /* No permission to check. Existence test. */
2651 /* No permission to check. Existence test. */ 2655 if (!mask)
2652 return 0; 2656 return 0;
2653 }
2654 2657
2655 return inode_has_perm(cred, inode, 2658 COMMON_AUDIT_DATA_INIT(&ad, FS);
2656 file_mask_to_av(inode->i_mode, mask), NULL); 2659 ad.u.fs.inode = inode;
2660
2661 if (from_access)
2662 ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
2663
2664 perms = file_mask_to_av(inode->i_mode, mask);
2665
2666 return inode_has_perm(cred, inode, perms, &ad);
2657} 2667}
2658 2668
2659static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) 2669static 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 @@
2 "getattr", "setattr", "lock", "relabelfrom", "relabelto", "append" 2 "getattr", "setattr", "lock", "relabelfrom", "relabelto", "append"
3 3
4#define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \ 4#define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \
5 "rename", "execute", "swapon", "quotaon", "mounton" 5 "rename", "execute", "swapon", "quotaon", "mounton", "audit_access"
6 6
7#define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \ 7#define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \
8 "listen", "accept", "getopt", "setopt", "shutdown", "recvfrom", \ 8 "listen", "accept", "getopt", "setopt", "shutdown", "recvfrom", \