mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
ovl: inherit FMODE_NONOTIFY when opening directory realfiles
When fanotify hands a listener an fd for a permission event on an
overlay directory, ovl_dir_open_realfile() opens the real directory via
dentry_open(), not backing_file_open(), so the lower open could still
raise FS_OPEN_PERM and deadlock a listener that also marks the backing
filesystem.
Export dentry_open_nonotify() and call it from ovl_path_open_realfile()
when the overlay user file must not generate events. Ordinary
ovl_path_open() callers are unchanged.
Reported-by: Christian Brauner (Amutable) <brauner@kernel.org>
Closes: https://lore.kernel.org/all/20261030-welpen-anbinden-nullen-b2432cee1d10@brauner/
Fixes: 130fdbc3d1 ("ovl: pass correct flags for opening real directory")
Cc: stable@vger.kernel.org
Tested-by: Edvard Conrad <edvard@tuta.io>
Link: https://lore.kernel.org/ltp/P5Iny41--F-9@tuta.io/
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
This commit is contained in:
parent
e803c82dcd
commit
323899b4ed
|
|
@ -1172,6 +1172,7 @@ struct file *dentry_open_nonotify(const struct path *path, int flags,
|
|||
}
|
||||
return f;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dentry_open_nonotify);
|
||||
|
||||
/**
|
||||
* kernel_file_open - open a file for kernel internal use
|
||||
|
|
|
|||
|
|
@ -531,7 +531,14 @@ void ovl_dir_modified(struct dentry *dentry, bool impurity);
|
|||
u64 ovl_inode_version_get(struct inode *inode);
|
||||
bool ovl_is_whiteout(struct dentry *dentry);
|
||||
bool ovl_path_is_whiteout(struct ovl_fs *ofs, const struct path *path);
|
||||
struct file *ovl_path_open(const struct path *path, int flags);
|
||||
struct file *ovl_path_open_realfile(const struct file *user_file,
|
||||
const struct path *path, int flags);
|
||||
|
||||
static inline struct file *ovl_path_open(const struct path *path, int flags)
|
||||
{
|
||||
return ovl_path_open_realfile(NULL, path, flags);
|
||||
}
|
||||
|
||||
int ovl_copy_up_start(struct dentry *dentry, int flags);
|
||||
void ovl_copy_up_end(struct dentry *dentry);
|
||||
bool ovl_already_copied_up(struct dentry *dentry, int flags);
|
||||
|
|
|
|||
|
|
@ -994,7 +994,8 @@ static struct file *ovl_dir_open_realfile(const struct file *file,
|
|||
const struct path *realpath)
|
||||
{
|
||||
with_ovl_creds(file_inode(file)->i_sb)
|
||||
return ovl_path_open(realpath, O_RDONLY | (file->f_flags & O_LARGEFILE));
|
||||
return ovl_path_open_realfile(file, realpath,
|
||||
O_RDONLY | (file->f_flags & O_LARGEFILE));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -654,7 +654,8 @@ bool ovl_path_is_whiteout(struct ovl_fs *ofs, const struct path *path)
|
|||
ovl_path_check_xwhiteout_xattr(ofs, path);
|
||||
}
|
||||
|
||||
struct file *ovl_path_open(const struct path *path, int flags)
|
||||
struct file *ovl_path_open_realfile(const struct file *user_file,
|
||||
const struct path *path, int flags)
|
||||
{
|
||||
struct inode *inode = d_inode(path->dentry);
|
||||
const struct mnt_idmap *real_idmap = mnt_idmap(path->mnt);
|
||||
|
|
@ -682,6 +683,14 @@ struct file *ovl_path_open(const struct path *path, int flags)
|
|||
if (inode_owner_or_capable(real_idmap, inode))
|
||||
flags |= O_NOATIME;
|
||||
|
||||
/*
|
||||
* Directory opens use dentry_open() here, not backing_file_open().
|
||||
* Inherit FMODE_NONOTIFY from a fanotify permission fd so a listener
|
||||
* that also watches the real filesystem does not deadlock.
|
||||
*/
|
||||
if (user_file && FMODE_FSNOTIFY_NONE(user_file->f_mode))
|
||||
return dentry_open_nonotify(path, flags, current_cred());
|
||||
|
||||
return dentry_open(path, flags, current_cred());
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user