aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Smalley <sds@tycho.nsa.gov>2018-12-12 10:10:55 -0500
committerPaul Moore <paul@paul-moore.com>2019-01-10 20:32:53 -0500
commit3a28cff3bd4bf43f02be0c4e7933aebf3dc8197e (patch)
tree64f75c4103e27e02a5edf203bf5f8a1a420ab1e8
parentbfeffd155283772bbe78c6a05dec7c0128ee500c (diff)
selinux: avoid silent denials in permissive mode under RCU walk
commit 0dc1ba24f7fff6 ("SELINUX: Make selinux cache VFS RCU walks safe") results in no audit messages at all if in permissive mode because the cache is updated during the rcu walk and thus no denial occurs on the subsequent ref walk. Fix this by not updating the cache when performing a non-blocking permission check. This only affects search and symlink read checks during rcu walk. Fixes: 0dc1ba24f7fff6 ("SELINUX: Make selinux cache VFS RCU walks safe") Reported-by: BMK <bmktuwien@gmail.com> Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Signed-off-by: Paul Moore <paul@paul-moore.com>
-rw-r--r--security/selinux/avc.c23
-rw-r--r--security/selinux/hooks.c4
-rw-r--r--security/selinux/include/avc.h1
3 files changed, 25 insertions, 3 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 635e5c1e3e48..5de18a6d5c3f 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -838,6 +838,7 @@ out:
838 * @ssid,@tsid,@tclass : identifier of an AVC entry 838 * @ssid,@tsid,@tclass : identifier of an AVC entry
839 * @seqno : sequence number when decision was made 839 * @seqno : sequence number when decision was made
840 * @xpd: extended_perms_decision to be added to the node 840 * @xpd: extended_perms_decision to be added to the node
841 * @flags: the AVC_* flags, e.g. AVC_NONBLOCKING, AVC_EXTENDED_PERMS, or 0.
841 * 842 *
842 * if a valid AVC entry doesn't exist,this function returns -ENOENT. 843 * if a valid AVC entry doesn't exist,this function returns -ENOENT.
843 * if kmalloc() called internal returns NULL, this function returns -ENOMEM. 844 * if kmalloc() called internal returns NULL, this function returns -ENOMEM.
@@ -856,6 +857,23 @@ static int avc_update_node(struct selinux_avc *avc,
856 struct hlist_head *head; 857 struct hlist_head *head;
857 spinlock_t *lock; 858 spinlock_t *lock;
858 859
860 /*
861 * If we are in a non-blocking code path, e.g. VFS RCU walk,
862 * then we must not add permissions to a cache entry
863 * because we cannot safely audit the denial. Otherwise,
864 * during the subsequent blocking retry (e.g. VFS ref walk), we
865 * will find the permissions already granted in the cache entry
866 * and won't audit anything at all, leading to silent denials in
867 * permissive mode that only appear when in enforcing mode.
868 *
869 * See the corresponding handling in slow_avc_audit(), and the
870 * logic in selinux_inode_follow_link and selinux_inode_permission
871 * for the VFS MAY_NOT_BLOCK flag, which is transliterated into
872 * AVC_NONBLOCKING for avc_has_perm_noaudit().
873 */
874 if (flags & AVC_NONBLOCKING)
875 return 0;
876
859 node = avc_alloc_node(avc); 877 node = avc_alloc_node(avc);
860 if (!node) { 878 if (!node) {
861 rc = -ENOMEM; 879 rc = -ENOMEM;
@@ -1115,7 +1133,7 @@ decision:
1115 * @tsid: target security identifier 1133 * @tsid: target security identifier
1116 * @tclass: target security class 1134 * @tclass: target security class
1117 * @requested: requested permissions, interpreted based on @tclass 1135 * @requested: requested permissions, interpreted based on @tclass
1118 * @flags: AVC_STRICT or 0 1136 * @flags: AVC_STRICT, AVC_NONBLOCKING, or 0
1119 * @avd: access vector decisions 1137 * @avd: access vector decisions
1120 * 1138 *
1121 * Check the AVC to determine whether the @requested permissions are granted 1139 * Check the AVC to determine whether the @requested permissions are granted
@@ -1199,7 +1217,8 @@ int avc_has_perm_flags(struct selinux_state *state,
1199 struct av_decision avd; 1217 struct av_decision avd;
1200 int rc, rc2; 1218 int rc, rc2;
1201 1219
1202 rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 0, 1220 rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested,
1221 (flags & MAY_NOT_BLOCK) ? AVC_NONBLOCKING : 0,
1203 &avd); 1222 &avd);
1204 1223
1205 rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc, 1224 rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc,
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f0e36c3492ba..7f6068489a02 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2982,7 +2982,9 @@ static int selinux_inode_permission(struct inode *inode, int mask)
2982 return PTR_ERR(isec); 2982 return PTR_ERR(isec);
2983 2983
2984 rc = avc_has_perm_noaudit(&selinux_state, 2984 rc = avc_has_perm_noaudit(&selinux_state,
2985 sid, isec->sid, isec->sclass, perms, 0, &avd); 2985 sid, isec->sid, isec->sclass, perms,
2986 (flags & MAY_NOT_BLOCK) ? AVC_NONBLOCKING : 0,
2987 &avd);
2986 audited = avc_audit_required(perms, &avd, rc, 2988 audited = avc_audit_required(perms, &avd, rc,
2987 from_access ? FILE__AUDIT_ACCESS : 0, 2989 from_access ? FILE__AUDIT_ACCESS : 0,
2988 &denied); 2990 &denied);
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index ef899bcfd2cb..74ea50977c20 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -142,6 +142,7 @@ static inline int avc_audit(struct selinux_state *state,
142 142
143#define AVC_STRICT 1 /* Ignore permissive mode. */ 143#define AVC_STRICT 1 /* Ignore permissive mode. */
144#define AVC_EXTENDED_PERMS 2 /* update extended permissions */ 144#define AVC_EXTENDED_PERMS 2 /* update extended permissions */
145#define AVC_NONBLOCKING 4 /* non blocking */
145int avc_has_perm_noaudit(struct selinux_state *state, 146int avc_has_perm_noaudit(struct selinux_state *state,
146 u32 ssid, u32 tsid, 147 u32 ssid, u32 tsid,
147 u16 tclass, u32 requested, 148 u16 tclass, u32 requested,