* [PATCH v6] backing_file: store user_path_file
@ 2026-03-18 13:12 Amir Goldstein
2026-03-18 23:46 ` Paul Moore
0 siblings, 1 reply; 4+ messages in thread
From: Amir Goldstein @ 2026-03-18 13:12 UTC (permalink / raw)
To: Christian Brauner
Cc: Miklos Szeredi, Paul Moore, Gao Xiang, linux-security-module,
selinux, linux-erofs, linux-fsdevel, linux-unionfs
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 file_ref_init() helper was changed to accept the FILE_REF_ constant
instead of the fake +1 integer count.
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
Christian,
My v5 patch was sent by Paul along with his LSM/selinux pataches [1].
Here are the changes you requested.
I removed the ACKs and Tested-by because of the changes.
Thanks,
Amir.
Changes since v5:
- Restore file_ref_init() helper without refcnt -1 offset
- Future proofing errors from backing_file_open_user_path()
[1] https://lore.kernel.org/r/20260316213606.374109-6-paul@paul-moore.com/
fs/backing-file.c | 26 ++++++++++--------
fs/erofs/ishare.c | 13 +++++++--
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 | 4 +--
9 files changed, 103 insertions(+), 34 deletions(-)
diff --git a/fs/backing-file.c b/fs/backing-file.c
index 45da8600d5644..271ff27521063 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,20 +31,21 @@
* 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);
- error = vfs_open(real_path, f);
+ error = backing_file_open_user_path(f, user_path);
+ if (!error)
+ error = vfs_open(real_path, f);
if (error) {
fput(f);
f = ERR_PTR(error);
@@ -52,7 +55,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,13 +64,13 @@ 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);
- error = vfs_tmpfile(real_idmap, real_parentpath, f, mode);
+ error = backing_file_open_user_path(f, user_path);
+ if (!error)
+ error = vfs_tmpfile(real_idmap, real_parentpath, f, mode);
if (error) {
fput(f);
f = ERR_PTR(error);
diff --git a/fs/erofs/ishare.c b/fs/erofs/ishare.c
index 829d50d5c717d..f3a5fb0bffaf0 100644
--- a/fs/erofs/ishare.c
+++ b/fs/erofs/ishare.c
@@ -103,18 +103,25 @@ static int erofs_ishare_file_open(struct inode *inode, struct file *file)
{
struct inode *sharedinode = EROFS_I(inode)->sharedinode;
struct file *realfile;
+ int err;
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);
+
+ err = backing_file_open_user_path(realfile, &file->f_path);
+ if (err) {
+ fput(realfile);
+ return err;
+ }
+
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);
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 aaa5faaace1e9..e8b4eb2bbff85 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_set_user_path);
+EXPORT_SYMBOL_GPL(backing_file_user_path_file);
-static inline void file_free(struct file *f)
+int backing_file_open_user_path(struct file *f, const struct path *path)
+{
+ /* open an O_PATH file to reference the user path - should not fail */
+ return 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);
+}
+
+static inline void file_free(struct file *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);
+ file_ref_init(&f->f_ref, FILE_REF_ONEREF);
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 */
+ file_ref_init(&ff->user_path_file.f_ref, FILE_REF_DEAD);
+ if (unlikely(error)) {
+ destroy_file(&ff->file);
+ kmem_cache_free(bfilp_cachep, ff);
+ return ERR_PTR(error);
+ }
+
ff->file.f_mode |= FMODE_BACKING | FMODE_NOACCOUNT;
return &ff->file;
}
diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
index 72de97c03d0ee..60018c6359342 100644
--- a/fs/fuse/passthrough.c
+++ b/fs/fuse/passthrough.c
@@ -10,6 +10,7 @@
#include <linux/file.h>
#include <linux/backing-file.h>
#include <linux/splice.h>
+#include <linux/uio.h>
static void fuse_file_accessed(struct file *file)
{
@@ -167,7 +168,7 @@ struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id)
goto out;
/* Allocate backing file per fuse file to store fuse path */
- backing_file = backing_file_open(&file->f_path, file->f_flags,
+ backing_file = backing_file_open(&file->f_path, file->f_cred, file->f_flags,
&fb->file->f_path, fb->cred);
err = PTR_ERR(backing_file);
if (IS_ERR(backing_file)) {
diff --git a/fs/internal.h b/fs/internal.h
index cbc384a1aa096..7c44a58627ba3 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -106,8 +106,9 @@ extern void chroot_fs_refs(const struct path *, const struct path *);
*/
struct file *alloc_empty_file(int flags, const struct cred *cred);
struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred);
-struct file *alloc_empty_backing_file(int flags, const struct cred *cred);
-void backing_file_set_user_path(struct file *f, const struct path *path);
+struct file *alloc_empty_backing_file(int flags, const struct cred *cred,
+ const struct cred *user_cred);
+int backing_file_open_user_path(struct file *f, const struct path *path);
static inline void file_put_write_access(struct file *file)
{
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 8c0a3d876fef1..5fd32ccc134d2 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -1389,7 +1389,8 @@ static int ovl_create_tmpfile(struct file *file, struct dentry *dentry,
return PTR_ERR(cred);
ovl_path_upper(dentry->d_parent, &realparentpath);
- realfile = backing_tmpfile_open(&file->f_path, flags, &realparentpath,
+ realfile = backing_tmpfile_open(&file->f_path, file->f_cred,
+ flags, &realparentpath,
mode, current_cred());
err = PTR_ERR_OR_ZERO(realfile);
pr_debug("tmpfile/open(%pd2, 0%o) = %i\n", realparentpath.dentry, mode, err);
diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
index 97bed2286030d..767c128407fcc 100644
--- a/fs/overlayfs/file.c
+++ b/fs/overlayfs/file.c
@@ -49,6 +49,7 @@ static struct file *ovl_open_realfile(const struct file *file,
flags &= ~O_NOATIME;
realfile = backing_file_open(file_user_path(file),
+ file_user_cred(file),
flags, realpath, current_cred());
}
}
diff --git a/include/linux/backing-file.h b/include/linux/backing-file.h
index 1476a6ed1bfd7..8afba93f3ce07 100644
--- a/include/linux/backing-file.h
+++ b/include/linux/backing-file.h
@@ -9,19 +9,42 @@
#define _LINUX_BACKING_FILE_H
#include <linux/file.h>
-#include <linux/uio.h>
#include <linux/fs.h>
+/*
+ * When mmapping a file on a stackable filesystem (e.g., overlayfs), the file
+ * stored in ->vm_file is a backing file whose f_inode is on the underlying
+ * filesystem.
+ *
+ * LSM can use file_user_path_file() to store context related to the user path
+ * that was opened and mmaped.
+ */
+const struct file *backing_file_user_path_file(const struct file *f);
+
+static inline const struct file *file_user_path_file(const struct file *f)
+{
+ if (f && unlikely(f->f_mode & FMODE_BACKING))
+ return backing_file_user_path_file(f);
+ return f;
+}
+
+static inline const struct cred *file_user_cred(const struct file *f)
+{
+ return file_user_path_file(f)->f_cred;
+}
+
struct backing_file_ctx {
const struct cred *cred;
void (*accessed)(struct file *file);
void (*end_write)(struct kiocb *iocb, ssize_t);
};
-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 *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);
ssize_t backing_file_read_iter(struct file *file, struct iov_iter *iter,
diff --git a/include/linux/file_ref.h b/include/linux/file_ref.h
index 31551e4cb8f34..c7512ce70f9c4 100644
--- a/include/linux/file_ref.h
+++ b/include/linux/file_ref.h
@@ -54,11 +54,11 @@ typedef struct {
/**
* file_ref_init - Initialize a file reference count
* @ref: Pointer to the reference count
- * @cnt: The initial reference count typically '1'
+ * @cnt: The initial reference count typically FILE_REF_ONEREF
*/
static inline void file_ref_init(file_ref_t *ref, unsigned long cnt)
{
- atomic_long_set(&ref->refcnt, cnt - 1);
+ atomic_long_set(&ref->refcnt, cnt);
}
bool __file_ref_put(file_ref_t *ref, unsigned long cnt);
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH v6] backing_file: store user_path_file
2026-03-18 13:12 [PATCH v6] backing_file: store user_path_file Amir Goldstein
@ 2026-03-18 23:46 ` Paul Moore
2026-03-19 14:53 ` Amir Goldstein
0 siblings, 1 reply; 4+ messages in thread
From: Paul Moore @ 2026-03-18 23:46 UTC (permalink / raw)
To: Amir Goldstein
Cc: Christian Brauner, Miklos Szeredi, Gao Xiang,
linux-security-module, selinux, linux-erofs, linux-fsdevel,
linux-unionfs
On Wed, Mar 18, 2026 at 9:13 AM Amir Goldstein <amir73il@gmail.com> wrote:
>
> 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 file_ref_init() helper was changed to accept the FILE_REF_ constant
> instead of the fake +1 integer count.
>
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> ---
>
> Christian,
>
> My v5 patch was sent by Paul along with his LSM/selinux pataches [1].
> Here are the changes you requested.
>
> I removed the ACKs and Tested-by because of the changes.
>
> Thanks,
> Amir.
>
> Changes since v5:
> - Restore file_ref_init() helper without refcnt -1 offset
> - Future proofing errors from backing_file_open_user_path()
>
> [1] https://lore.kernel.org/r/20260316213606.374109-6-paul@paul-moore.com/
>
> fs/backing-file.c | 26 ++++++++++--------
> fs/erofs/ishare.c | 13 +++++++--
> 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 | 4 +--
> 9 files changed, 103 insertions(+), 34 deletions(-)
Still works for me. I'm going to update lsm/stable-7.0 with this
patch so we can get some more linux-next testing.
Tested-by: Paul Moore <paul@paul-moore.com>
--
paul-moore.com
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v6] backing_file: store user_path_file
2026-03-18 23:46 ` Paul Moore
@ 2026-03-19 14:53 ` Amir Goldstein
2026-03-19 15:56 ` Paul Moore
0 siblings, 1 reply; 4+ messages in thread
From: Amir Goldstein @ 2026-03-19 14:53 UTC (permalink / raw)
To: Paul Moore
Cc: Christian Brauner, Miklos Szeredi, Gao Xiang,
linux-security-module, selinux, linux-erofs, linux-fsdevel,
linux-unionfs
On Thu, Mar 19, 2026 at 12:47 AM Paul Moore <paul@paul-moore.com> wrote:
>
> On Wed, Mar 18, 2026 at 9:13 AM Amir Goldstein <amir73il@gmail.com> wrote:
> >
> > 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 file_ref_init() helper was changed to accept the FILE_REF_ constant
> > instead of the fake +1 integer count.
> >
> > Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> > ---
> >
> > Christian,
> >
> > My v5 patch was sent by Paul along with his LSM/selinux pataches [1].
> > Here are the changes you requested.
> >
> > I removed the ACKs and Tested-by because of the changes.
> >
> > Thanks,
> > Amir.
> >
> > Changes since v5:
> > - Restore file_ref_init() helper without refcnt -1 offset
> > - Future proofing errors from backing_file_open_user_path()
> >
> > [1] https://lore.kernel.org/r/20260316213606.374109-6-paul@paul-moore.com/
> >
> > fs/backing-file.c | 26 ++++++++++--------
> > fs/erofs/ishare.c | 13 +++++++--
> > 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 | 4 +--
> > 9 files changed, 103 insertions(+), 34 deletions(-)
>
> Still works for me. I'm going to update lsm/stable-7.0 with this
> patch so we can get some more linux-next testing.
>
> Tested-by: Paul Moore <paul@paul-moore.com>
>
Paul,
As you saw, syzbot found a nasty bug in this patch and it is too hard
to fix it without introducing more hazards.
Therefore, per Christian's request I am withdrawing this patch.
Please see compile tested alternative solution for selinux without
intrusive vfs change at:
https://github.com/amir73il/linux/commits/user_path_file/
Thanks,
Amir.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v6] backing_file: store user_path_file
2026-03-19 14:53 ` Amir Goldstein
@ 2026-03-19 15:56 ` Paul Moore
0 siblings, 0 replies; 4+ messages in thread
From: Paul Moore @ 2026-03-19 15:56 UTC (permalink / raw)
To: Amir Goldstein
Cc: Christian Brauner, Miklos Szeredi, Gao Xiang,
linux-security-module, selinux, linux-erofs, linux-fsdevel,
linux-unionfs
On Thu, Mar 19, 2026 at 10:54 AM Amir Goldstein <amir73il@gmail.com> wrote:
> On Thu, Mar 19, 2026 at 12:47 AM Paul Moore <paul@paul-moore.com> wrote:
> > On Wed, Mar 18, 2026 at 9:13 AM Amir Goldstein <amir73il@gmail.com> wrote:
> > >
> > > 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 file_ref_init() helper was changed to accept the FILE_REF_ constant
> > > instead of the fake +1 integer count.
> > >
> > > Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> > > ---
> > >
> > > Christian,
> > >
> > > My v5 patch was sent by Paul along with his LSM/selinux pataches [1].
> > > Here are the changes you requested.
> > >
> > > I removed the ACKs and Tested-by because of the changes.
> > >
> > > Thanks,
> > > Amir.
> > >
> > > Changes since v5:
> > > - Restore file_ref_init() helper without refcnt -1 offset
> > > - Future proofing errors from backing_file_open_user_path()
> > >
> > > [1] https://lore.kernel.org/r/20260316213606.374109-6-paul@paul-moore.com/
> > >
> > > fs/backing-file.c | 26 ++++++++++--------
> > > fs/erofs/ishare.c | 13 +++++++--
> > > 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 | 4 +--
> > > 9 files changed, 103 insertions(+), 34 deletions(-)
> >
> > Still works for me. I'm going to update lsm/stable-7.0 with this
> > patch so we can get some more linux-next testing.
> >
> > Tested-by: Paul Moore <paul@paul-moore.com>
> >
>
> Paul,
>
> As you saw, syzbot found a nasty bug in this patch and it is too hard
> to fix it without introducing more hazards.
>
> Therefore, per Christian's request I am withdrawing this patch.
>
> Please see compile tested alternative solution for selinux without
> intrusive vfs change at:
> https://github.com/amir73il/linux/commits/user_path_file/
Let's let this thread die in favor of the other. I'll already
commented there, but the quick summary is that pushing the ugliness
into an individual LSM, or the LSM framework itself, is not a
solution.
--
paul-moore.com
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-03-19 15:56 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-18 13:12 [PATCH v6] backing_file: store user_path_file Amir Goldstein
2026-03-18 23:46 ` Paul Moore
2026-03-19 14:53 ` Amir Goldstein
2026-03-19 15:56 ` Paul Moore
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox