On 11/22/19 11:11 AM, Al Viro wrote:
On Thu, Nov 21, 2019 at 09:52:45AM -0500, Stephen Smalley wrote:
commit bda0be7ad994 ("security: make inode_follow_link RCU-walk aware")
passed down the rcu flag to the SELinux AVC, but failed to adjust the
test in slow_avc_audit() to also return -ECHILD on LSM_AUDIT_DATA_DENTRY.
Previously, we only returned -ECHILD if generating an audit record with
LSM_AUDIT_DATA_INODE since this was only relevant from inode_permission.
Return -ECHILD on either LSM_AUDIT_DATA_INODE or LSM_AUDIT_DATA_DENTRY.
LSM_AUDIT_DATA_INODE only requires this handling due to the fact
that dump_common_audit_data() calls d_find_alias() and collects the
dname from the result if any.
Other cases that might require similar treatment in the future are
LSM_AUDIT_DATA_PATH and LSM_AUDIT_DATA_FILE if any hook that takes
a path or file is called under RCU-walk.
Fixes: bda0be7ad994 ("security: make inode_follow_link RCU-walk aware")
Signed-off-by: Stephen Smalley <sds@xxxxxxxxxxxxx>
---
security/selinux/avc.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 74c43ebe34bb..f1fa1072230c 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -779,7 +779,8 @@ noinline int slow_avc_audit(struct selinux_state *state,
* during retry. However this is logically just as if the operation
* happened a little later.
*/
- if ((a->type == LSM_AUDIT_DATA_INODE) &&
+ if ((a->type == LSM_AUDIT_DATA_INODE ||
+ a->type == LSM_AUDIT_DATA_DENTRY) &&
(flags & MAY_NOT_BLOCK))
IDGI, to be honest. Why do we bother with slow path if MAY_NOT_BLOCK has
been given? If we'd run into "there's something to report" case, we
are not on the fastpath anymore. IOW, why not have
audited = avc_audit_required(requested, avd, result, 0, &denied);
if (likely(!audited))
return 0;
if (flags & MAY_NOT_BLOCK)
return -ECHILD;
return slow_avc_audit(state, ssid, tsid, tclass,
requested, audited, denied, result,
a, flags);
in avc_audit() and be done with that?
That works for me; we would also need to do the same in
selinux_inode_permission(). We can then stop passing flags down to
slow_avc_audit() entirely.
It's not just whether we *can* collect whatever audit might want; do
we want to try and make an audit-spewing syscall marginally faster?
And "marginally" is all you'll get there, really...
We could do
error = security_inode_follow_link(dentry, inode,
nd->flags & LOOKUP_RCU);
if (unlikely(error)) {
if (error == -ECHILD && !unlazy_walk(nd))
error = security_inode_follow_link(dentry, inode, 0);
if (error)
return ERR_PTR(error);
}
in fs/namei.c:get_link() to slightly reduce the costs; that might or
might not be useful - I'd like to see profiling results first. But
trying to push the actual "spew to audit" into RCU case? What for?