[PATCH v5 7/8] vfs: Replace security_sb_mount/security_move_mount with granular hooks
Christian Brauner
brauner at kernel.org
Wed Jun 17 13:53:48 UTC 2026
On Thu, May 28, 2026 at 11:26:06AM -0700, Song Liu wrote:
> Replace the monolithic security_sb_mount() call in path_mount() and
> security_move_mount() in vfs_move_mount() with the new granular mount
> hooks:
>
> - do_loopback(): call security_mount_bind()
> - do_new_mount(): call security_mount_new()
> - do_remount(): call security_mount_remount()
> - do_reconfigure_mnt(): call security_mount_reconfigure()
> - do_move_mount_old(): call security_mount_move()
> - do_change_type(): call security_mount_change_type()
> - vfs_move_mount(): replace security_move_mount() with
> security_mount_move()
>
> The new hooks are called at the individual operation level with
> appropriate context (resolved paths, fs_context), rather than at
> the top of path_mount() with raw string arguments.
>
> Code generated with the assistance of Claude, reviewed by human.
>
> Reviewed-by: Stephen Smalley <stephen.smalley.work at gmail.com>
> Tested-by: Stephen Smalley <stephen.smalley.work at gmail.com> # for selinux only
> Signed-off-by: Song Liu <song at kernel.org>
> ---
> fs/namespace.c | 41 ++++++++++++++++++++++++++++++-----------
> 1 file changed, 30 insertions(+), 11 deletions(-)
>
> diff --git a/fs/namespace.c b/fs/namespace.c
> index fe919abd2f01..43f22c5e2bf4 100644
> --- a/fs/namespace.c
> +++ b/fs/namespace.c
> @@ -2888,6 +2888,10 @@ static int do_change_type(const struct path *path, int ms_flags)
> if (!type)
> return -EINVAL;
>
> + err = security_mount_change_type(path, ms_flags);
> + if (err)
> + return err;
> +
> guard(namespace_excl)();
>
> err = may_change_propagation(mnt);
> @@ -3006,6 +3010,10 @@ static int do_loopback(const struct path *path, const char *old_name,
> if (err)
> return err;
>
> + err = security_mount_bind(&old_path, path, recurse);
> + if (err)
> + return err;
This again is racy as it is called outside of the namespace semaphore:
err = security_mount_bind(&old_path, path, recurse);
if (err)
return err;
if (mnt_ns_loop(old_path.dentry))
return -EINVAL;
LOCK_MOUNT(mp, path);
if (IS_ERR(mp.parent))
return PTR_ERR(mp.parent);
After LOCK_MOUNT @path might point to a completely different mount then
the one you performed your security checks on.
> +
> if (mnt_ns_loop(old_path.dentry))
> return -EINVAL;
>
> @@ -3328,7 +3336,8 @@ static void mnt_warn_timestamp_expiry(const struct path *mountpoint,
> * superblock it refers to. This is triggered by specifying MS_REMOUNT|MS_BIND
> * to mount(2).
> */
> -static int do_reconfigure_mnt(const struct path *path, unsigned int mnt_flags)
> +static int do_reconfigure_mnt(const struct path *path, unsigned int mnt_flags,
> + unsigned long flags)
> {
> struct super_block *sb = path->mnt->mnt_sb;
> struct mount *mnt = real_mount(path->mnt);
> @@ -3343,6 +3352,10 @@ static int do_reconfigure_mnt(const struct path *path, unsigned int mnt_flags)
> if (!can_change_locked_flags(mnt, mnt_flags))
> return -EPERM;
>
> + ret = security_mount_reconfigure(path, mnt_flags, flags);
> + if (ret)
> + return ret;
> +
> /*
> * We're only checking whether the superblock is read-only not
> * changing it, so only take down_read(&sb->s_umount).
> @@ -3366,7 +3379,7 @@ static int do_reconfigure_mnt(const struct path *path, unsigned int mnt_flags)
> * on it - tough luck.
> */
> static int do_remount(const struct path *path, int sb_flags,
> - int mnt_flags, void *data)
> + int mnt_flags, void *data, unsigned long flags)
> {
> int err;
> struct super_block *sb = path->mnt->mnt_sb;
> @@ -3393,6 +3406,9 @@ static int do_remount(const struct path *path, int sb_flags,
> fc->oldapi = true;
>
> err = parse_monolithic_mount_data(fc, data);
> + if (!err)
> + err = security_mount_remount(fc, path, mnt_flags, flags,
> + data);
> if (!err) {
> down_write(&sb->s_umount);
> err = -EPERM;
> @@ -3708,6 +3724,10 @@ static int do_move_mount_old(const struct path *path, const char *old_name)
> if (err)
> return err;
>
> + err = security_mount_move(&old_path, path);
> + if (err)
> + return err;
Placement of this hook suffers from the same issue as the bind mount
hook. Here it's worse because the security layer isn't even informed
about MOVE_MOUNT_BENEATH which completely alters the mount relationship.
More information about the Linux-security-module-archive
mailing list