]>
Commit | Line | Data |
---|---|---|
efa860ba GKH |
1 | From 3a28cff3bd4bf43f02be0c4e7933aebf3dc8197e Mon Sep 17 00:00:00 2001 |
2 | From: Stephen Smalley <sds@tycho.nsa.gov> | |
3 | Date: Wed, 12 Dec 2018 10:10:55 -0500 | |
4 | Subject: selinux: avoid silent denials in permissive mode under RCU walk | |
5 | ||
6 | From: Stephen Smalley <sds@tycho.nsa.gov> | |
7 | ||
8 | commit 3a28cff3bd4bf43f02be0c4e7933aebf3dc8197e upstream. | |
9 | ||
10 | commit 0dc1ba24f7fff6 ("SELINUX: Make selinux cache VFS RCU walks safe") | |
11 | results in no audit messages at all if in permissive mode because the | |
12 | cache is updated during the rcu walk and thus no denial occurs on | |
13 | the subsequent ref walk. Fix this by not updating the cache when | |
14 | performing a non-blocking permission check. This only affects search | |
15 | and symlink read checks during rcu walk. | |
16 | ||
17 | Fixes: 0dc1ba24f7fff6 ("SELINUX: Make selinux cache VFS RCU walks safe") | |
18 | Reported-by: BMK <bmktuwien@gmail.com> | |
19 | Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> | |
20 | Signed-off-by: Paul Moore <paul@paul-moore.com> | |
21 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
22 | ||
23 | --- | |
24 | security/selinux/avc.c | 23 +++++++++++++++++++++-- | |
25 | security/selinux/hooks.c | 4 +++- | |
26 | security/selinux/include/avc.h | 1 + | |
27 | 3 files changed, 25 insertions(+), 3 deletions(-) | |
28 | ||
29 | --- a/security/selinux/avc.c | |
30 | +++ b/security/selinux/avc.c | |
31 | @@ -838,6 +838,7 @@ out: | |
32 | * @ssid,@tsid,@tclass : identifier of an AVC entry | |
33 | * @seqno : sequence number when decision was made | |
34 | * @xpd: extended_perms_decision to be added to the node | |
35 | + * @flags: the AVC_* flags, e.g. AVC_NONBLOCKING, AVC_EXTENDED_PERMS, or 0. | |
36 | * | |
37 | * if a valid AVC entry doesn't exist,this function returns -ENOENT. | |
38 | * if kmalloc() called internal returns NULL, this function returns -ENOMEM. | |
39 | @@ -856,6 +857,23 @@ static int avc_update_node(struct selinu | |
40 | struct hlist_head *head; | |
41 | spinlock_t *lock; | |
42 | ||
43 | + /* | |
44 | + * If we are in a non-blocking code path, e.g. VFS RCU walk, | |
45 | + * then we must not add permissions to a cache entry | |
46 | + * because we cannot safely audit the denial. Otherwise, | |
47 | + * during the subsequent blocking retry (e.g. VFS ref walk), we | |
48 | + * will find the permissions already granted in the cache entry | |
49 | + * and won't audit anything at all, leading to silent denials in | |
50 | + * permissive mode that only appear when in enforcing mode. | |
51 | + * | |
52 | + * See the corresponding handling in slow_avc_audit(), and the | |
53 | + * logic in selinux_inode_follow_link and selinux_inode_permission | |
54 | + * for the VFS MAY_NOT_BLOCK flag, which is transliterated into | |
55 | + * AVC_NONBLOCKING for avc_has_perm_noaudit(). | |
56 | + */ | |
57 | + if (flags & AVC_NONBLOCKING) | |
58 | + return 0; | |
59 | + | |
60 | node = avc_alloc_node(avc); | |
61 | if (!node) { | |
62 | rc = -ENOMEM; | |
63 | @@ -1115,7 +1133,7 @@ decision: | |
64 | * @tsid: target security identifier | |
65 | * @tclass: target security class | |
66 | * @requested: requested permissions, interpreted based on @tclass | |
67 | - * @flags: AVC_STRICT or 0 | |
68 | + * @flags: AVC_STRICT, AVC_NONBLOCKING, or 0 | |
69 | * @avd: access vector decisions | |
70 | * | |
71 | * Check the AVC to determine whether the @requested permissions are granted | |
72 | @@ -1199,7 +1217,8 @@ int avc_has_perm_flags(struct selinux_st | |
73 | struct av_decision avd; | |
74 | int rc, rc2; | |
75 | ||
76 | - rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 0, | |
77 | + rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, | |
78 | + (flags & MAY_NOT_BLOCK) ? AVC_NONBLOCKING : 0, | |
79 | &avd); | |
80 | ||
81 | rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc, | |
82 | --- a/security/selinux/hooks.c | |
83 | +++ b/security/selinux/hooks.c | |
84 | @@ -3199,7 +3199,9 @@ static int selinux_inode_permission(stru | |
85 | return PTR_ERR(isec); | |
86 | ||
87 | rc = avc_has_perm_noaudit(&selinux_state, | |
88 | - sid, isec->sid, isec->sclass, perms, 0, &avd); | |
89 | + sid, isec->sid, isec->sclass, perms, | |
90 | + (flags & MAY_NOT_BLOCK) ? AVC_NONBLOCKING : 0, | |
91 | + &avd); | |
92 | audited = avc_audit_required(perms, &avd, rc, | |
93 | from_access ? FILE__AUDIT_ACCESS : 0, | |
94 | &denied); | |
95 | --- a/security/selinux/include/avc.h | |
96 | +++ b/security/selinux/include/avc.h | |
97 | @@ -142,6 +142,7 @@ static inline int avc_audit(struct selin | |
98 | ||
99 | #define AVC_STRICT 1 /* Ignore permissive mode. */ | |
100 | #define AVC_EXTENDED_PERMS 2 /* update extended permissions */ | |
101 | +#define AVC_NONBLOCKING 4 /* non blocking */ | |
102 | int avc_has_perm_noaudit(struct selinux_state *state, | |
103 | u32 ssid, u32 tsid, | |
104 | u16 tclass, u32 requested, |