Re: [PATCH v3 1/2] lsm: add backing_file LSM hooks
Paul Moore <[email protected]>
| Newsgroups | org.kernel.vger.linux-unionfs,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-security-module,org.kernel.vger.selinux,org.ozlabs.lists.linux-erofs |
|---|---|
| Message-ID | <CAHC9VhQQZ69LAGZE2DSyM_qidTJ8oGfqSSvysrO6r9BAXW9mkQ@mail.gmail.com> |
On Sat, Mar 28, 2026 at 4:29 AM Amir Goldstein <[email protected]> wrote: > On Fri, Mar 27, 2026 at 11:05 PM Paul Moore <[email protected]> wrote: > > > > Stacked filesystems such as overlayfs do not currently provide the > > necessary mechanisms for LSMs to properly enforce access controls on the > > mmap() and mprotect() operations. In order to resolve this gap, a LSM > > security blob is being added to the backing_file struct and the following > > new LSM hooks are being created: > > > > security_backing_file_alloc() > > security_backing_file_free() > > security_mmap_backing_file() > > > > The first two hooks are to manage the lifecycle of the LSM security blob > > in the backing_file struct, while the third provides a new mmap() access > > control point for the underlying backing file. It is also expected that > > LSMs will likely want to update their security_file_mprotect() callback > > to address issues with their mprotect() controls, but that does not > > require a change to the security_file_mprotect() LSM hook. > > > > There are a two other small changes to support these new LSM hooks. We > > pass the user file associated with a backing file down to > > alloc_empty_backing_file() so it can be included in the > > security_backing_file_alloc() hook, and we constify the file struct field > > in the LSM common_audit_data struct to better support LSMs that need to > > pass a const file struct pointer into the common LSM audit code. > > > > Thanks to Arnd Bergmann for identifying the missing EXPORT_SYMBOL_GPL() > > and supplying a fixup. > > > > Cc: [email protected] > > Acked-by: Christian Brauner <[email protected]> > > Signed-off-by: Paul Moore <[email protected]> > > --- > > I 100% agree with Christian. > This is much better than my O_PATH file hack I'm not surprised that both you and Christian prefer this solution, it moves all the pain of resolving this issue to the individual LSMs. Just look at how the SELinux code has changed, even trying to pretty it up as best as possible, it's objectively much uglier now, not to mention more complicated. From my perspective the root cause of this issue lies in the overlayfs/backing-file design, specifically how overlayfs hides multiple files under a single file so that it can plug into the existing VFS/userspace paradigm of a single file. While the design and abstraction are no doubt very clever things, and for the most part they "just work", there are definitely some corner cases that require special handling, e.g. LSM access controls around mprotect(). In my opinion, the burden of hiding any ugliness associated with this special handling lies with the subsystem implementing the abstraction, which is why I was pushing for a solution where the VFS and/or backing-file layer would provide the user file (or a stand-in) for the LSMs to use. Unfortunately, that was not something the overlayfs and VFS communities were willing to tolerate, so those of us in the LSM space were left with a terrible choice: accept that the overlayfs/VFS folks don't care and hack around the shortcomings of overlayfs, or leave a public vulnerability for an unknown period of time while the overlayfs/VFS folks argue over a solution, with the a non-trivial chance that the LSMs would need to hack around the problem anyway. That's my view of were things were at, and why I begrudgingly took this approach. I'm sure you have your own perspecitve, and I'm not going to be surprised if you view this primarily as a LSM problem; it's a common viewpoint amongst Linux kernel maintainers not responsible for a LSM. > It is also what Miklos had initially suggested. Perhaps I've lost the mail, but going back to when this issue was first discovered, I don't see anything from Miklos relating to this in either my inbox or the mailing lists. > > diff --git a/fs/file_table.c b/fs/file_table.c > > index aaa5faaace1e..0bdc26cae138 100644 > > --- a/fs/file_table.c > > +++ b/fs/file_table.c > > @@ -50,6 +50,7 @@ struct backing_file { > > struct path user_path; > > freeptr_t bf_freeptr; > > }; > > Shouldn't we wrap this with > #ifdef CONFIG_SECURITY Sure, I'll change that. > > + void *security; > > please initialize it in init_file() We lack a clean way to access the backing_file struct in init_file(). I placed the security_backing_file_alloc() initializer in alloc_empty_backing_file() as it was the first place where we could both allocate the necessary LSM blob and initialize it with the data from the user file at the same time. If you want to intialize backing_file->security in init_file(), init_file() we will need to add a FMODE_BACKING check in init_file and split the security_backing_file_alloc() hook into two: one in init_file() to do the allocation and basic init, one in alloc_empty_backing_file() to capture the necessary user file data. Do you still prefer to move the backing_file->security initializtion into init_file()? > > +void *backing_file_security(const struct file *f) > > +{ > > + return backing_file(f)->security; > > I think LSM code should be completely responsible for this ptr > assignment/free so you should export > > void **backing_file_security_ptr(const struct file *f) > { > return &backing_file(f)->security; > } Doing so would require us to also move the backing_file struct definition into include/linux/backing-file.h (or similar), which I tried very hard to avoid as I suspected you would not approve of that. I figured if you had wanted to expose the struct definition you would have defined it in backing-file.h as opposed to file_table.c. Would you like me to move the backing_file struct definition into include/linux/backing-file.h? > > @@ -73,8 +79,11 @@ static inline void file_free(struct file *f) > > percpu_counter_dec(&nr_files); > > put_cred(f->f_cred); > > if (unlikely(f->f_mode & FMODE_BACKING)) { > > - path_put(backing_file_user_path(f)); > > - kmem_cache_free(bfilp_cachep, backing_file(f)); > > + struct backing_file *ff = backing_file(f); > > + > > + security_backing_file_free(&ff->security); > > Why do you need to add this in vfs code? > > Can't you do the same in security_file_free(f)? > if (unlikely(f->f_mode & FMODE_BACKING)) > security_backing_file_free(backing_file_security_ptr(f)); See my comments above regarding the visibility of the backing_file struct. > > + path_put(&ff->user_path); > > + kmem_cache_free(bfilp_cachep, ff); > > } else { > > kmem_cache_free(filp_cachep, f); > > } > > @@ -290,7 +299,8 @@ struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred) > > * This is only for kernel internal use, and the allocate file must not be > > * installed into file tables or such. > > */ > > -struct file *alloc_empty_backing_file(int flags, const struct cred *cred) > > +struct file *alloc_empty_backing_file(int flags, const struct cred *cred, > > + const struct file *user_file) > > { > > struct backing_file *ff; > > int error; > > @@ -306,6 +316,11 @@ struct file *alloc_empty_backing_file(int flags, const struct cred *cred) > > } > > > > ff->file.f_mode |= FMODE_BACKING | FMODE_NOACCOUNT; > > + error = security_backing_file_alloc(&ff->security, user_file);> + if (unlikely(error)) { > > + fput(&ff->file); > > + return ERR_PTR(error); > > + } > > return &ff->file; > > } > > EXPORT_SYMBOL_GPL(alloc_empty_backing_file); > > Maybe, and I am not sure, > alloc_empty_backing_file() should call ONLY > error = security_backing_file_alloc(&ff->file, user_file); > > Instead of security_file_alloc() AND security_backing_file_alloc() > and security_backing_file_alloc() can make use of > backing_file_security_ptr() accessor internally? This is another case of the code being structured so that we don't need to expose the backing_file struct definition to the LSMs. If you would prefer to expose the backing_file struct in include/linux I can probably make a few additional simplifications to the code. -- paul-moore.com