| From 7fcac0b7d688ae02e2cd970cd51e52b40f80f297 Mon Sep 17 00:00:00 2001 |
| From: Stephen Smalley <sds@tycho.nsa.gov> |
| Date: Fri, 22 Nov 2019 12:22:44 -0500 |
| Subject: [PATCH] selinux: revert "stop passing MAY_NOT_BLOCK to the AVC upon |
| follow_link" |
| |
| 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: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/security/selinux/avc.c b/security/selinux/avc.c |
| index ecd3829996aa..74c43ebe34bb 100644 |
| --- a/security/selinux/avc.c |
| +++ b/security/selinux/avc.c |
| @@ -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; |
| diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c |
| index c106167423a1..17dcfb1e2fc5 100644 |
| --- a/security/selinux/hooks.c |
| +++ b/security/selinux/hooks.c |
| @@ -3006,8 +3006,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, |
| diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h |
| index 7be0e1e90e8b..74ea50977c20 100644 |
| --- a/security/selinux/include/avc.h |
| +++ b/security/selinux/include/avc.h |
| @@ -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, |
| -- |
| 2.7.4 |
| |