selinux: revert "stop passing MAY_NOT_BLOCK to the AVC upon follow_link"
authorStephen Smalley <sds@tycho.nsa.gov>
Fri, 22 Nov 2019 17:22:44 +0000 (12:22 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 14 Feb 2020 21:34:19 +0000 (16:34 -0500)
commit 1a37079c236d55fb31ebbf4b59945dab8ec8764c upstream.

This reverts commit e46e01eebbbc ("selinux: stop passing MAY_NOT_BLOCK
to the AVC upon follow_link"). The correct fix is to instead fall
back to ref-walk if audit is required irrespective of the specific
audit data type.  This is done in the next commit.

Fixes: e46e01eebbbc ("selinux: stop passing MAY_NOT_BLOCK to the AVC upon follow_link")
Reported-by: Will Deacon <will@kernel.org>
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/include/avc.h

index ecd3829..74c43eb 100644 (file)
@@ -862,8 +862,9 @@ static int avc_update_node(struct selinux_avc *avc,
         * permissive mode that only appear when in enforcing mode.
         *
         * See the corresponding handling in slow_avc_audit(), and the
-        * logic in selinux_inode_permission for the MAY_NOT_BLOCK flag,
-        * which is transliterated into AVC_NONBLOCKING.
+        * logic in selinux_inode_follow_link and selinux_inode_permission
+        * for the VFS MAY_NOT_BLOCK flag, which is transliterated into
+        * AVC_NONBLOCKING for avc_has_perm_noaudit().
         */
        if (flags & AVC_NONBLOCKING)
                return 0;
@@ -1205,6 +1206,25 @@ int avc_has_perm(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass,
        return rc;
 }
 
+int avc_has_perm_flags(struct selinux_state *state,
+                      u32 ssid, u32 tsid, u16 tclass, u32 requested,
+                      struct common_audit_data *auditdata,
+                      int flags)
+{
+       struct av_decision avd;
+       int rc, rc2;
+
+       rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested,
+                                 (flags & MAY_NOT_BLOCK) ? AVC_NONBLOCKING : 0,
+                                 &avd);
+
+       rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc,
+                       auditdata, flags);
+       if (rc2)
+               return rc2;
+       return rc;
+}
+
 u32 avc_policy_seqno(struct selinux_state *state)
 {
        return state->avc->avc_cache.latest_notif;
index 9625b99..9943539 100644 (file)
@@ -3008,8 +3008,9 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
        if (IS_ERR(isec))
                return PTR_ERR(isec);
 
-       return avc_has_perm(&selinux_state,
-                           sid, isec->sid, isec->sclass, FILE__READ, &ad);
+       return avc_has_perm_flags(&selinux_state,
+                                 sid, isec->sid, isec->sclass, FILE__READ, &ad,
+                                 rcu ? MAY_NOT_BLOCK : 0);
 }
 
 static noinline int audit_inode_permission(struct inode *inode,
index 7be0e1e..74ea509 100644 (file)
@@ -153,6 +153,11 @@ int avc_has_perm(struct selinux_state *state,
                 u32 ssid, u32 tsid,
                 u16 tclass, u32 requested,
                 struct common_audit_data *auditdata);
+int avc_has_perm_flags(struct selinux_state *state,
+                      u32 ssid, u32 tsid,
+                      u16 tclass, u32 requested,
+                      struct common_audit_data *auditdata,
+                      int flags);
 
 int avc_has_extended_perms(struct selinux_state *state,
                           u32 ssid, u32 tsid, u16 tclass, u32 requested,