Re: [PATCH bpf-next 2/2] selftests/bpf: Add tests for bpf_get_dentry_xattr
From: Song Liu <hidden>
Date: 2024-08-19 20:25:43
Also in:
bpf, linux-fsdevel, lkml
Hi Christian,
On Aug 19, 2024, at 4:16 AM, Christian Brauner [off-list ref] wrote:
[...]
quoted
Did I get this right? IIUC, there are a few issues with this approach. 1. security_inode_permission takes inode as parameter. However, we need dentry to get the xattr. Shall we change security_inode_permission to take dentry instead? PS: Maybe we should change most/all inode hooks to take dentry instead?security_inode_permission() is called in generic_permission() which in turn is called from inode_permission() which in turn is called from inode->i_op->permission() for various filesystems. So to make security_inode_permission() take a dentry argument one would need to change all inode->i_op->permission() to take a dentry argument for all filesystems. NAK on that. That's ignoring that it's just plain wrong to pass a dentry to **inode**_permission() or security_**inode**_permission(). It's permissions on the inode, not the dentry.
Agreed. [...]
quoted
quoted
Which means this code ends up charging relative lookups twice. Even if one irons that out in the program this encourages really bad patterns. Path lookup is iterative top down. One can't just randomly walk back up and assume that's equivalent.I understand that walk-up is not equivalent to walk down. But it is probably accurate enough for some security policies. For example, LSM LandLock uses similar logic in the file_open hook (file security/landlock/fs.c, function is_access_to_paths_allowed).I'm not well-versed in landlock so I'll let Mickaël comment on this with more details but there's very important restrictions and differences here. Landlock expresses security policies with file hierarchies and security_inode_permission() doesn't and cannot have access to that. Landlock is subject to the same problem that the BPF is here. Namely that the VFS permission checking could have been done on a path walk completely different from the path walk that is checked when walking back up from security_file_open(). But because landlock works with a deny-by-default security policy this is ok and it takes overmounts into account etc.quoted
To summary my thoughts here. I think we need: 1. Change security_inode_permission to take dentry instead of inode.Sorry, no.quoted
2. Still add bpf_dget_parent. We will use it with security_inode_permission so that we can propagate flags from parents to children. We will need a bpf_dput as well. 3. There are pros and cons with different approaches to implement this policy (tags on directory work for all files in it). We probably need the policy writer to decide with one to use. From BPF's POV, dget_parent is "safe", because it won't crash the system. It may encourage some bad patterns, but it appears to be required in some use cases.You cannot just walk a path upwards and check permissions and assume that this is safe unless you have a clear idea what makes it safe in this scenario. Landlock has afaict. But so far you only have a vague sketch of checking permissions walking upwards and retrieving xattrs without any notion of the problems involved.
I am sorry for being vague with the use case here. We are trying to cover a few different use cases, such as sandboxing, allowlisting certain operations to selected binaries, prevent operation errors, etc. For this work, we are looking for the right building blocks to enable these use cases.
If you provide a bpf_get_parent() api for userspace to consume you'll end up providing them with an api that is extremly easy to misuse.
Does this make sense to have higher level API that walks up the path,
so that it takes mounts into account. It can probably be something like:
int bpf_get_parent_path(struct path *p) {
again:
if (p->dentry == p->mnt.mnt_root) {
follow_up(p);
goto again;
}
if (unlikely(IS_ROOT(p->dentry))) {
return PARENT_WALK_DONE;
}
parent_dentry = dget_parent(p->dentry);
dput(p->dentry);
p->dentry = parent_dentry;
return PARENT_WALK_NEXT;
}
This will handle the mount. However, we cannot guarantee deny-by-default
policies like LandLock does, because this is just a building block of
some security policies.
Is this something we can give a try with?
Thanks,
Song