From: Song Liu <song@kernel.org>
To: linux-security-module@vger.kernel.org,
linux-fsdevel@vger.kernel.org, selinux@vger.kernel.org,
apparmor@lists.ubuntu.com
Cc: paul@paul-moore.com, jmorris@namei.org, serge@hallyn.com,
viro@zeniv.linux.org.uk, brauner@kernel.org, jack@suse.cz,
john.johansen@canonical.com, stephen.smalley.work@gmail.com,
omosnace@redhat.com, mic@digikod.net, gnoack@google.com,
takedakn@nttdata.co.jp, penguin-kernel@I-love.SAKURA.ne.jp,
herton@canonical.com, kernel-team@meta.com,
Song Liu <song@kernel.org>
Subject: [PATCH v5 1/8] lsm: Add granular mount hooks
Date: Thu, 28 May 2026 11:26:00 -0700 [thread overview]
Message-ID: <20260528182607.3150386-2-song@kernel.org> (raw)
In-Reply-To: <20260528182607.3150386-1-song@kernel.org>
Add the new granular mount hook declarations and implementations
to the LSM framework:
mount_bind - bind mount (pre-resolved source path)
mount_new - new filesystem mount (with fs_context)
mount_remount - filesystem remount (with fs_context)
mount_reconfigure - mount flag reconfiguration (MS_REMOUNT|MS_BIND)
mount_move - move mount (pre-resolved paths)
mount_change_type - propagation type changes
These hooks are added alongside the existing security_sb_mount() and
security_move_mount() hooks, which remain in place until all LSMs
are converted.
Code generated with the assistance of Claude, reviewed by human.
Reviewed-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Tested-by: Stephen Smalley <stephen.smalley.work@gmail.com> # for selinux only
Signed-off-by: Song Liu <song@kernel.org>
---
include/linux/lsm_hook_defs.h | 12 ++++
include/linux/security.h | 50 +++++++++++++++++
kernel/bpf/bpf_lsm.c | 7 +++
security/security.c | 101 ++++++++++++++++++++++++++++++++++
4 files changed, 170 insertions(+)
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 2b8dfb35caed..98f0fe382665 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -81,6 +81,18 @@ LSM_HOOK(int, 0, sb_clone_mnt_opts, const struct super_block *oldsb,
unsigned long *set_kern_flags)
LSM_HOOK(int, 0, move_mount, const struct path *from_path,
const struct path *to_path)
+LSM_HOOK(int, 0, mount_bind, const struct path *from, const struct path *to,
+ bool recurse)
+LSM_HOOK(int, 0, mount_new, struct fs_context *fc, const struct path *mp,
+ int mnt_flags, unsigned long flags, void *data)
+LSM_HOOK(int, 0, mount_remount, struct fs_context *fc,
+ const struct path *mp, int mnt_flags, unsigned long flags,
+ void *data)
+LSM_HOOK(int, 0, mount_reconfigure, const struct path *mp,
+ unsigned int mnt_flags, unsigned long flags)
+LSM_HOOK(int, 0, mount_move, const struct path *from_path,
+ const struct path *to_path)
+LSM_HOOK(int, 0, mount_change_type, const struct path *mp, int ms_flags)
LSM_HOOK(int, -EOPNOTSUPP, dentry_init_security, struct dentry *dentry,
int mode, const struct qstr *name, const char **xattr_name,
struct lsm_context *cp)
diff --git a/include/linux/security.h b/include/linux/security.h
index 41d7367cf403..b1b3da51a88d 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -386,6 +386,17 @@ int security_sb_clone_mnt_opts(const struct super_block *oldsb,
unsigned long kern_flags,
unsigned long *set_kern_flags);
int security_move_mount(const struct path *from_path, const struct path *to_path);
+int security_mount_bind(const struct path *from, const struct path *to,
+ bool recurse);
+int security_mount_new(struct fs_context *fc, const struct path *mp,
+ int mnt_flags, unsigned long flags, void *data);
+int security_mount_remount(struct fs_context *fc, const struct path *mp,
+ int mnt_flags, unsigned long flags, void *data);
+int security_mount_reconfigure(const struct path *mp, unsigned int mnt_flags,
+ unsigned long flags);
+int security_mount_move(const struct path *from_path,
+ const struct path *to_path);
+int security_mount_change_type(const struct path *mp, int ms_flags);
int security_dentry_init_security(struct dentry *dentry, int mode,
const struct qstr *name,
const char **xattr_name,
@@ -854,6 +865,45 @@ static inline int security_move_mount(const struct path *from_path,
return 0;
}
+static inline int security_mount_bind(const struct path *from,
+ const struct path *to, bool recurse)
+{
+ return 0;
+}
+
+static inline int security_mount_new(struct fs_context *fc,
+ const struct path *mp, int mnt_flags,
+ unsigned long flags, void *data)
+{
+ return 0;
+}
+
+static inline int security_mount_remount(struct fs_context *fc,
+ const struct path *mp, int mnt_flags,
+ unsigned long flags, void *data)
+{
+ return 0;
+}
+
+static inline int security_mount_reconfigure(const struct path *mp,
+ unsigned int mnt_flags,
+ unsigned long flags)
+{
+ return 0;
+}
+
+static inline int security_mount_move(const struct path *from_path,
+ const struct path *to_path)
+{
+ return 0;
+}
+
+static inline int security_mount_change_type(const struct path *mp,
+ int ms_flags)
+{
+ return 0;
+}
+
static inline int security_path_notify(const struct path *path, u64 mask,
unsigned int obj_type)
{
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index c5c925f00202..aa228372cfb4 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -382,6 +382,13 @@ BTF_ID(func, bpf_lsm_task_setscheduler)
BTF_ID(func, bpf_lsm_userns_create)
BTF_ID(func, bpf_lsm_bdev_alloc_security)
BTF_ID(func, bpf_lsm_bdev_setintegrity)
+BTF_ID(func, bpf_lsm_move_mount)
+BTF_ID(func, bpf_lsm_mount_bind)
+BTF_ID(func, bpf_lsm_mount_new)
+BTF_ID(func, bpf_lsm_mount_remount)
+BTF_ID(func, bpf_lsm_mount_reconfigure)
+BTF_ID(func, bpf_lsm_mount_move)
+BTF_ID(func, bpf_lsm_mount_change_type)
BTF_SET_END(sleepable_lsm_hooks)
BTF_SET_START(untrusted_lsm_hooks)
diff --git a/security/security.c b/security/security.c
index 4e999f023651..b7ec0ec7af26 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1182,6 +1182,107 @@ int security_move_mount(const struct path *from_path,
return call_int_hook(move_mount, from_path, to_path);
}
+/**
+ * security_mount_bind() - Check permissions for a bind mount
+ * @from: source path
+ * @to: destination mount point
+ * @recurse: whether this is a recursive bind mount
+ *
+ * Check permission before a bind mount is performed. Called with the
+ * source path already resolved, eliminating TOCTOU issues with
+ * string-based dev_name in security_sb_mount().
+ *
+ * Return: Returns 0 if permission is granted.
+ */
+int security_mount_bind(const struct path *from, const struct path *to,
+ bool recurse)
+{
+ return call_int_hook(mount_bind, from, to, recurse);
+}
+
+/**
+ * security_mount_new() - Check permissions for a new mount
+ * @fc: filesystem context with parsed options
+ * @mp: mount point path
+ * @mnt_flags: mount flags (MNT_*)
+ * @flags: original mount flags (MS_*, used by AppArmor/Tomoyo)
+ * @data: filesystem specific data (used by AppArmor)
+ *
+ * Check permission before a new filesystem is mounted. Called after
+ * mount options are parsed, providing access to the fs_context.
+ *
+ * Return: Returns 0 if permission is granted.
+ */
+int security_mount_new(struct fs_context *fc, const struct path *mp,
+ int mnt_flags, unsigned long flags, void *data)
+{
+ return call_int_hook(mount_new, fc, mp, mnt_flags, flags, data);
+}
+
+/**
+ * security_mount_remount() - Check permissions for a remount
+ * @fc: filesystem context with parsed options
+ * @mp: mount point path
+ * @mnt_flags: mount flags (MNT_*)
+ * @flags: original mount flags (MS_*, used by AppArmor/Tomoyo)
+ * @data: filesystem specific data (used by AppArmor)
+ *
+ * Check permission before a filesystem is remounted. Called after
+ * mount options are parsed, providing access to the fs_context.
+ *
+ * Return: Returns 0 if permission is granted.
+ */
+int security_mount_remount(struct fs_context *fc, const struct path *mp,
+ int mnt_flags, unsigned long flags, void *data)
+{
+ return call_int_hook(mount_remount, fc, mp, mnt_flags, flags, data);
+}
+
+/**
+ * security_mount_reconfigure() - Check permissions for mount reconfiguration
+ * @mp: mount point path
+ * @mnt_flags: new mount flags (MNT_*)
+ * @flags: original mount flags (MS_*, used by AppArmor/Tomoyo)
+ *
+ * Check permission before mount flags are reconfigured (MS_REMOUNT|MS_BIND).
+ *
+ * Return: Returns 0 if permission is granted.
+ */
+int security_mount_reconfigure(const struct path *mp, unsigned int mnt_flags,
+ unsigned long flags)
+{
+ return call_int_hook(mount_reconfigure, mp, mnt_flags, flags);
+}
+
+/**
+ * security_mount_move() - Check permissions for moving a mount
+ * @from_path: source mount path
+ * @to_path: destination mount point path
+ *
+ * Check permission before a mount is moved.
+ *
+ * Return: Returns 0 if permission is granted.
+ */
+int security_mount_move(const struct path *from_path,
+ const struct path *to_path)
+{
+ return call_int_hook(mount_move, from_path, to_path);
+}
+
+/**
+ * security_mount_change_type() - Check permissions for propagation changes
+ * @mp: mount point path
+ * @ms_flags: propagation flags (MS_SHARED, MS_PRIVATE, etc.)
+ *
+ * Check permission before mount propagation type is changed.
+ *
+ * Return: Returns 0 if permission is granted.
+ */
+int security_mount_change_type(const struct path *mp, int ms_flags)
+{
+ return call_int_hook(mount_change_type, mp, ms_flags);
+}
+
/**
* security_path_notify() - Check if setting a watch is allowed
* @path: file path
--
2.53.0-Meta
next prev parent reply other threads:[~2026-05-28 18:26 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-28 18:25 [PATCH v5 0/8] lsm: Replace security_sb_mount with granular mount hooks Song Liu
2026-05-28 18:26 ` Song Liu [this message]
2026-05-28 18:26 ` [PATCH v5 2/8] apparmor: Remove redundant MS_MGC_MSK stripping in apparmor_sb_mount Song Liu
2026-05-28 18:26 ` [PATCH v5 3/8] apparmor: Convert from sb_mount to granular mount hooks Song Liu
2026-05-28 18:26 ` [PATCH v5 4/8] selinux: " Song Liu
2026-05-28 18:26 ` [PATCH v5 5/8] landlock: " Song Liu
2026-05-28 18:26 ` [PATCH v5 6/8] tomoyo: " Song Liu
2026-05-28 18:26 ` [PATCH v5 7/8] vfs: Replace security_sb_mount/security_move_mount with granular hooks Song Liu
2026-05-28 18:26 ` [PATCH v5 8/8] lsm: Remove security_sb_mount and security_move_mount Song Liu
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=20260528182607.3150386-2-song@kernel.org \
--to=song@kernel.org \
--cc=apparmor@lists.ubuntu.com \
--cc=brauner@kernel.org \
--cc=gnoack@google.com \
--cc=herton@canonical.com \
--cc=jack@suse.cz \
--cc=jmorris@namei.org \
--cc=john.johansen@canonical.com \
--cc=kernel-team@meta.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=mic@digikod.net \
--cc=omosnace@redhat.com \
--cc=paul@paul-moore.com \
--cc=penguin-kernel@I-love.SAKURA.ne.jp \
--cc=selinux@vger.kernel.org \
--cc=serge@hallyn.com \
--cc=stephen.smalley.work@gmail.com \
--cc=takedakn@nttdata.co.jp \
--cc=viro@zeniv.linux.org.uk \
/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