From: Christian Brauner <brauner@kernel.org>
To: Paul Moore <paul@paul-moore.com>, Amir Goldstein <amir73il@gmail.com>
Cc: linux-security-module@vger.kernel.org, selinux@vger.kernel.org,
linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org,
linux-erofs@lists.ozlabs.org, Gao Xiang <xiang@kernel.org>
Subject: Re: [PATCH 1/3] backing_file: store user_path_file
Date: Wed, 18 Mar 2026 11:56:57 +0100 [thread overview]
Message-ID: <20260318-einsam-sellerie-2d547dd338ee@brauner> (raw)
In-Reply-To: <20260316213606.374109-6-paul@paul-moore.com>
On Mon, Mar 16, 2026 at 05:35:56PM -0400, Paul Moore wrote:
> From: Amir Goldstein <amir73il@gmail.com>
>
> Instead of storing the user_path, store an O_PATH file for the
> user_path with the original user file creds and a security context.
>
> The user_path_file is only exported as a const pointer and its refcnt
> is initialized to FILE_REF_DEAD, because it is not a refcounted object.
>
> The only caller of file_ref_init() is now open coded, so the helper
> is removed.
>
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> Tested-by: Paul Moore <paul@paul-moore.com> (SELinux)
> Acked-by: Gao Xiang <hsiangkao@linux.alibaba.com> (EROFS)
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
> fs/backing-file.c | 20 ++++++++------
> fs/erofs/ishare.c | 6 ++--
> fs/file_table.c | 53 ++++++++++++++++++++++++++++--------
> fs/fuse/passthrough.c | 3 +-
> fs/internal.h | 5 ++--
> fs/overlayfs/dir.c | 3 +-
> fs/overlayfs/file.c | 1 +
> include/linux/backing-file.h | 29 ++++++++++++++++++--
> include/linux/file_ref.h | 10 -------
> 9 files changed, 90 insertions(+), 40 deletions(-)
>
> diff --git a/fs/backing-file.c b/fs/backing-file.c
> index 45da8600d564..acabeea7efff 100644
> --- a/fs/backing-file.c
> +++ b/fs/backing-file.c
> @@ -11,6 +11,7 @@
> #include <linux/fs.h>
> #include <linux/backing-file.h>
> #include <linux/splice.h>
> +#include <linux/uio.h>
> #include <linux/mm.h>
>
> #include "internal.h"
> @@ -18,9 +19,10 @@
> /**
> * backing_file_open - open a backing file for kernel internal use
> * @user_path: path that the user reuqested to open
> + * @user_cred: credentials that the user used for open
> * @flags: open flags
> * @real_path: path of the backing file
> - * @cred: credentials for open
> + * @cred: credentials for open of the backing file
> *
> * Open a backing file for a stackable filesystem (e.g., overlayfs).
> * @user_path may be on the stackable filesystem and @real_path on the
> @@ -29,19 +31,19 @@
> * returned file into a container structure that also stores the stacked
> * file's path, which can be retrieved using backing_file_user_path().
> */
> -struct file *backing_file_open(const struct path *user_path, int flags,
> +struct file *backing_file_open(const struct path *user_path,
> + const struct cred *user_cred, int flags,
> const struct path *real_path,
> const struct cred *cred)
> {
> struct file *f;
> int error;
>
> - f = alloc_empty_backing_file(flags, cred);
> + f = alloc_empty_backing_file(flags, cred, user_cred);
> if (IS_ERR(f))
> return f;
>
> - path_get(user_path);
> - backing_file_set_user_path(f, user_path);
> + backing_file_open_user_path(f, user_path);
> error = vfs_open(real_path, f);
> if (error) {
> fput(f);
> @@ -52,7 +54,8 @@ struct file *backing_file_open(const struct path *user_path, int flags,
> }
> EXPORT_SYMBOL_GPL(backing_file_open);
>
> -struct file *backing_tmpfile_open(const struct path *user_path, int flags,
> +struct file *backing_tmpfile_open(const struct path *user_path,
> + const struct cred *user_cred, int flags,
> const struct path *real_parentpath,
> umode_t mode, const struct cred *cred)
> {
> @@ -60,12 +63,11 @@ struct file *backing_tmpfile_open(const struct path *user_path, int flags,
> struct file *f;
> int error;
>
> - f = alloc_empty_backing_file(flags, cred);
> + f = alloc_empty_backing_file(flags, cred, user_cred);
> if (IS_ERR(f))
> return f;
>
> - path_get(user_path);
> - backing_file_set_user_path(f, user_path);
> + backing_file_open_user_path(f, user_path);
> error = vfs_tmpfile(real_idmap, real_parentpath, f, mode);
> if (error) {
> fput(f);
> diff --git a/fs/erofs/ishare.c b/fs/erofs/ishare.c
> index 829d50d5c717..17a4941d4518 100644
> --- a/fs/erofs/ishare.c
> +++ b/fs/erofs/ishare.c
> @@ -106,15 +106,15 @@ static int erofs_ishare_file_open(struct inode *inode, struct file *file)
>
> if (file->f_flags & O_DIRECT)
> return -EINVAL;
> - realfile = alloc_empty_backing_file(O_RDONLY|O_NOATIME, current_cred());
> + realfile = alloc_empty_backing_file(O_RDONLY|O_NOATIME, current_cred(),
> + file->f_cred);
> if (IS_ERR(realfile))
> return PTR_ERR(realfile);
> ihold(sharedinode);
> realfile->f_op = &erofs_file_fops;
> realfile->f_inode = sharedinode;
> realfile->f_mapping = sharedinode->i_mapping;
> - path_get(&file->f_path);
> - backing_file_set_user_path(realfile, &file->f_path);
> + backing_file_open_user_path(realfile, &file->f_path);
>
> file_ra_state_init(&realfile->f_ra, file->f_mapping);
> realfile->private_data = EROFS_I(inode);
> diff --git a/fs/file_table.c b/fs/file_table.c
> index aaa5faaace1e..b7dc94656c44 100644
> --- a/fs/file_table.c
> +++ b/fs/file_table.c
> @@ -27,6 +27,7 @@
> #include <linux/task_work.h>
> #include <linux/swap.h>
> #include <linux/kmemleak.h>
> +#include <linux/backing-file.h>
>
> #include <linux/atomic.h>
>
> @@ -43,11 +44,11 @@ static struct kmem_cache *bfilp_cachep __ro_after_init;
>
> static struct percpu_counter nr_files __cacheline_aligned_in_smp;
>
> -/* Container for backing file with optional user path */
> +/* Container for backing file with optional user path file */
> struct backing_file {
> struct file file;
> union {
> - struct path user_path;
> + struct file user_path_file;
> freeptr_t bf_freeptr;
> };
> };
> @@ -56,24 +57,44 @@ struct backing_file {
>
> const struct path *backing_file_user_path(const struct file *f)
> {
> - return &backing_file(f)->user_path;
> + return &backing_file(f)->user_path_file.f_path;
> }
> EXPORT_SYMBOL_GPL(backing_file_user_path);
>
> -void backing_file_set_user_path(struct file *f, const struct path *path)
> +const struct file *backing_file_user_path_file(const struct file *f)
> {
> - backing_file(f)->user_path = *path;
> + return &backing_file(f)->user_path_file;
> +}
> +EXPORT_SYMBOL_GPL(backing_file_user_path_file);
> +
> +void backing_file_open_user_path(struct file *f, const struct path *path)
I think this is a bad idea. This should return an error but still
WARN_ON(). Just make callers handle that error just like we do
everywhere else.
> +{
> + /* open an O_PATH file to reference the user path - cannot fail */
> + WARN_ON(vfs_open(path, &backing_file(f)->user_path_file));
> +}
> +EXPORT_SYMBOL_GPL(backing_file_open_user_path);
> +
> +static void destroy_file(struct file *f)
> +{
> + security_file_free(f);
> + put_cred(f->f_cred);
Note that calling destroy_file() in this way bypasses
security_file_release(). Presumably this doesn't matter because no LSM
does a security_alloc_file() for this but it adds a nother wrinkly into
the cleanup path.
> }
> -EXPORT_SYMBOL_GPL(backing_file_set_user_path);
>
> static inline void file_free(struct file *f)
> {
> - security_file_free(f);
> + destroy_file(f);
> if (likely(!(f->f_mode & FMODE_NOACCOUNT)))
> percpu_counter_dec(&nr_files);
> - put_cred(f->f_cred);
> if (unlikely(f->f_mode & FMODE_BACKING)) {
> - path_put(backing_file_user_path(f));
> + struct file *user_path_file = &backing_file(f)->user_path_file;
> +
> + /*
> + * no refcount on the user_path_file - they die together,
> + * so __fput() is not called for user_path_file. path_put()
> + * is the only relevant cleanup from __fput().
> + */
> + destroy_file(user_path_file);
> + path_put(&user_path_file->__f_path);
> kmem_cache_free(bfilp_cachep, backing_file(f));
> } else {
> kmem_cache_free(filp_cachep, f);
> @@ -201,7 +222,7 @@ static int init_file(struct file *f, int flags, const struct cred *cred)
> * fget-rcu pattern users need to be able to handle spurious
> * refcount bumps we should reinitialize the reused file first.
> */
> - file_ref_init(&f->f_ref, 1);
> + atomic_long_set(&f->f_ref.refcnt, FILE_REF_ONEREF);
No, please don't open-code this. The point is to stop any open-access to
f_ref. And also below you introduce another atomic_long_set() open-coded
call as well. Simply adapt file_ref_init() to not do the -1 subtraction
and use the constants directly.
> return 0;
> }
>
> @@ -290,7 +311,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 cred *user_cred)
> {
> struct backing_file *ff;
> int error;
> @@ -305,6 +327,15 @@ struct file *alloc_empty_backing_file(int flags, const struct cred *cred)
> return ERR_PTR(error);
> }
>
> + error = init_file(&ff->user_path_file, O_PATH, user_cred);
> + /* user_path_file is not refcounterd - it dies with the backing file */
> + atomic_long_set(&ff->user_path_file.f_ref.refcnt, FILE_REF_DEAD);
Please massage this and send that patch. I'll stuff it into a stable vfs
branch that both Paul and I can merge. Paul can then send his PR.
next prev parent reply other threads:[~2026-03-18 10:57 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-16 21:35 [PATCH 0/3] Fix incorrect overlayfs mmap() and mprotect() LSM access controls Paul Moore
2026-03-16 21:35 ` [PATCH 1/3] backing_file: store user_path_file Paul Moore
2026-03-18 10:56 ` Christian Brauner [this message]
2026-03-18 12:06 ` Amir Goldstein
2026-03-18 20:00 ` Paul Moore
2026-03-16 21:35 ` [PATCH 2/3] lsm: add the security_mmap_backing_file() hook Paul Moore
2026-03-17 22:42 ` Paul Moore
2026-03-16 21:35 ` [PATCH 3/3] selinux: fix overlayfs mmap() and mprotect() access checks Paul Moore
2026-03-16 21:59 ` [PATCH 0/3] Fix incorrect overlayfs mmap() and mprotect() LSM access controls Paul Moore
2026-03-17 7:25 ` Amir Goldstein
2026-03-17 18:16 ` Paul Moore
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260318-einsam-sellerie-2d547dd338ee@brauner \
--to=brauner@kernel.org \
--cc=amir73il@gmail.com \
--cc=linux-erofs@lists.ozlabs.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=linux-unionfs@vger.kernel.org \
--cc=paul@paul-moore.com \
--cc=selinux@vger.kernel.org \
--cc=xiang@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox