Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Stephen Smalley and committed by
Paul Moore
3a28cff3 bfeffd15

+25 -3
+21 -2
security/selinux/avc.c
··· 838 838 * @ssid,@tsid,@tclass : identifier of an AVC entry 839 839 * @seqno : sequence number when decision was made 840 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 843 * if a valid AVC entry doesn't exist,this function returns -ENOENT. 843 844 * if kmalloc() called internal returns NULL, this function returns -ENOMEM. ··· 856 855 struct avc_node *pos, *node, *orig = NULL; 857 856 struct hlist_head *head; 858 857 spinlock_t *lock; 858 + 859 + /* 860 + * If we are in a non-blocking code path, e.g. VFS RCU walk, 861 + * then we must not add permissions to a cache entry 862 + * because we cannot safely audit the denial. Otherwise, 863 + * during the subsequent blocking retry (e.g. VFS ref walk), we 864 + * will find the permissions already granted in the cache entry 865 + * and won't audit anything at all, leading to silent denials in 866 + * permissive mode that only appear when in enforcing mode. 867 + * 868 + * See the corresponding handling in slow_avc_audit(), and the 869 + * logic in selinux_inode_follow_link and selinux_inode_permission 870 + * for the VFS MAY_NOT_BLOCK flag, which is transliterated into 871 + * AVC_NONBLOCKING for avc_has_perm_noaudit(). 872 + */ 873 + if (flags & AVC_NONBLOCKING) 874 + return 0; 859 875 860 876 node = avc_alloc_node(avc); 861 877 if (!node) { ··· 1133 1115 * @tsid: target security identifier 1134 1116 * @tclass: target security class 1135 1117 * @requested: requested permissions, interpreted based on @tclass 1136 - * @flags: AVC_STRICT or 0 1118 + * @flags: AVC_STRICT, AVC_NONBLOCKING, or 0 1137 1119 * @avd: access vector decisions 1138 1120 * 1139 1121 * Check the AVC to determine whether the @requested permissions are granted ··· 1217 1199 struct av_decision avd; 1218 1200 int rc, rc2; 1219 1201 1220 - rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 0, 1202 + rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 1203 + (flags & MAY_NOT_BLOCK) ? AVC_NONBLOCKING : 0, 1221 1204 &avd); 1222 1205 1223 1206 rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc,
+3 -1
security/selinux/hooks.c
··· 2982 2982 return PTR_ERR(isec); 2983 2983 2984 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 2988 audited = avc_audit_required(perms, &avd, rc, 2987 2989 from_access ? FILE__AUDIT_ACCESS : 0, 2988 2990 &denied);
+1
security/selinux/include/avc.h
··· 142 142 143 143 #define AVC_STRICT 1 /* Ignore permissive mode. */ 144 144 #define AVC_EXTENDED_PERMS 2 /* update extended permissions */ 145 + #define AVC_NONBLOCKING 4 /* non blocking */ 145 146 int avc_has_perm_noaudit(struct selinux_state *state, 146 147 u32 ssid, u32 tsid, 147 148 u16 tclass, u32 requested,