diff options
-rw-r--r-- | include/linux/lsm_audit.h | 5 | ||||
-rw-r--r-- | security/selinux/avc.c | 24 | ||||
-rw-r--r-- | security/selinux/hooks.c | 20 | ||||
-rw-r--r-- | security/selinux/include/classmap.h | 2 |
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 { | |||
90 | u32 requested; | 90 | u32 requested; |
91 | u32 audited; | 91 | u32 audited; |
92 | u32 denied; | 92 | u32 denied; |
93 | /* | ||
94 | * auditdeny is a bit tricky and unintuitive. See the | ||
95 | * comments in avc.c for it's meaning and usage. | ||
96 | */ | ||
97 | u32 auditdeny; | ||
93 | struct av_decision *avd; | 98 | struct av_decision *avd; |
94 | int result; | 99 | int result; |
95 | } selinux_audit_data; | 100 | } 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, | |||
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 | |||
2644 | static int selinux_inode_permission(struct inode *inode, int mask) | 2644 | static 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 | ||
2659 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | 2669 | 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 @@ | |||
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", \ |