[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250925171208.5997-3-casey@schaufler-ca.com>
Date: Thu, 25 Sep 2025 10:12:08 -0700
From: Casey Schaufler <casey@...aufler-ca.com>
To: casey@...aufler-ca.com,
paul@...l-moore.com,
eparis@...hat.com,
linux-security-module@...r.kernel.org
Cc: jmorris@...ei.org,
serge@...lyn.com,
keescook@...omium.org,
john.johansen@...onical.com,
penguin-kernel@...ove.sakura.ne.jp,
stephen.smalley.work@...il.com,
linux-kernel@...r.kernel.org,
selinux@...r.kernel.org
Subject: [PATCH v2 2/2] LSM: Infrastructure management of the mnt_opts security blob
Move management of the mnt_opts->security blob out of the individual
security modules and into the security infrastructure. The modules
tell the infrastructure how much space is required, and the space is
allocated as required in the interfaces that use the blob.
Signed-off-by: Casey Schaufler <casey@...aufler-ca.com>
---
security/security.c | 42 +++++++++++++++++
security/selinux/hooks.c | 75 ++++++++++---------------------
security/selinux/include/objsec.h | 8 ++++
security/smack/smack.h | 8 ++++
security/smack/smack_lsm.c | 44 +++++-------------
5 files changed, 92 insertions(+), 85 deletions(-)
diff --git a/security/security.c b/security/security.c
index 8390410aec91..b16c0843dafa 100644
--- a/security/security.c
+++ b/security/security.c
@@ -29,6 +29,7 @@
#include <linux/overflow.h>
#include <linux/perf_event.h>
#include <linux/fs.h>
+#include <linux/fs_context.h>
#include <net/flow.h>
#include <net/sock.h>
@@ -1337,6 +1338,19 @@ void security_bprm_committed_creds(const struct linux_binprm *bprm)
call_void_hook(bprm_committed_creds, bprm);
}
+/**
+ * lsm_mnt_opts_alloc - allocate a mnt_opts blob
+ * @opts: pointer to options
+ *
+ * Allocate a mount options blob.
+ *
+ * Returns 0, or -ENOMEM if memory isn't available.
+ */
+static int lsm_mnt_opts_alloc(void **opts)
+{
+ return lsm_blob_alloc(opts, blob_sizes.lbs_mnt_opts, GFP_KERNEL);
+}
+
/**
* security_fs_context_submount() - Initialise fc->security
* @fc: new filesystem context
@@ -1348,6 +1362,13 @@ void security_bprm_committed_creds(const struct linux_binprm *bprm)
*/
int security_fs_context_submount(struct fs_context *fc, struct super_block *reference)
{
+ int rc;
+
+ if (!fc->security) {
+ rc = lsm_mnt_opts_alloc(&fc->security);
+ if (rc)
+ return rc;
+ }
return call_int_hook(fs_context_submount, fc, reference);
}
@@ -1364,6 +1385,13 @@ int security_fs_context_submount(struct fs_context *fc, struct super_block *refe
*/
int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
{
+ int rc;
+
+ if (!fc->security) {
+ rc = lsm_mnt_opts_alloc(&fc->security);
+ if (rc)
+ return rc;
+ }
return call_int_hook(fs_context_dup, fc, src_fc);
}
@@ -1386,6 +1414,12 @@ int security_fs_context_parse_param(struct fs_context *fc,
int trc;
int rc = -ENOPARAM;
+ if (!fc->security) {
+ trc = lsm_mnt_opts_alloc(&fc->security);
+ if (trc)
+ return trc;
+ }
+
lsm_for_each_hook(scall, fs_context_parse_param) {
trc = scall->hl->hook.fs_context_parse_param(fc, param);
if (trc == 0)
@@ -1455,6 +1489,7 @@ void security_free_mnt_opts(void **mnt_opts)
if (!*mnt_opts)
return;
call_void_hook(sb_free_mnt_opts, *mnt_opts);
+ kfree(*mnt_opts);
*mnt_opts = NULL;
}
EXPORT_SYMBOL(security_free_mnt_opts);
@@ -1470,6 +1505,13 @@ EXPORT_SYMBOL(security_free_mnt_opts);
*/
int security_sb_eat_lsm_opts(char *options, void **mnt_opts)
{
+ int rc;
+
+ if (!*mnt_opts) {
+ rc = lsm_mnt_opts_alloc(mnt_opts);
+ if (rc)
+ return rc;
+ }
return call_int_hook(sb_eat_lsm_opts, options, mnt_opts);
}
EXPORT_SYMBOL(security_sb_eat_lsm_opts);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 4bba9d119713..1ccf880e4894 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -383,11 +383,6 @@ struct selinux_mnt_opts {
u32 defcontext_sid;
};
-static void selinux_free_mnt_opts(void *mnt_opts)
-{
- kfree(mnt_opts);
-}
-
enum {
Opt_error = -1,
Opt_context = 0,
@@ -640,7 +635,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
const struct cred *cred = current_cred();
struct superblock_security_struct *sbsec = selinux_superblock(sb);
struct dentry *root = sb->s_root;
- struct selinux_mnt_opts *opts = mnt_opts;
+ struct selinux_mnt_opts *opts = selinux_mnt_opts(mnt_opts);
struct inode_security_struct *root_isec;
u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
u32 defcontext_sid = 0;
@@ -656,19 +651,13 @@ static int selinux_set_mnt_opts(struct super_block *sb,
mutex_lock(&sbsec->lock);
if (!selinux_initialized()) {
- if (!opts) {
- /* Defer initialization until selinux_complete_init,
- after the initial policy is loaded and the security
- server is ready to handle calls. */
- if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
- sbsec->flags |= SE_SBNATIVE;
- *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
- }
- goto out;
+ /* Defer initialization until selinux_complete_init,
+ after the initial policy is loaded and the security
+ server is ready to handle calls. */
+ if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
+ sbsec->flags |= SE_SBNATIVE;
+ *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
}
- rc = -EINVAL;
- pr_warn("SELinux: Unable to set superblock options "
- "before the security server is initialized\n");
goto out;
}
@@ -1003,7 +992,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
*/
static int selinux_add_opt(int token, const char *s, void **mnt_opts)
{
- struct selinux_mnt_opts *opts = *mnt_opts;
+ struct selinux_mnt_opts *opts = selinux_mnt_opts(*mnt_opts);
u32 *dst_sid;
int rc;
@@ -1012,19 +1001,14 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
return 0;
if (!s)
return -EINVAL;
+ if (!opts)
+ return 0;
if (!selinux_initialized()) {
pr_warn("SELinux: Unable to set superblock options before the security server is initialized\n");
return -EINVAL;
}
- if (!opts) {
- opts = kzalloc(sizeof(*opts), GFP_KERNEL);
- if (!opts)
- return -ENOMEM;
- *mnt_opts = opts;
- }
-
switch (token) {
case Opt_context:
if (opts->context_sid || opts->defcontext_sid)
@@ -2620,17 +2604,14 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
*q++ = c;
}
arg = kmemdup_nul(arg, q - arg, GFP_KERNEL);
- if (!arg) {
- rc = -ENOMEM;
- goto free_opt;
- }
+ if (!arg)
+ return -ENOMEM;
}
rc = selinux_add_opt(token, arg, mnt_opts);
kfree(arg);
arg = NULL;
- if (unlikely(rc)) {
- goto free_opt;
- }
+ if (unlikely(rc))
+ return rc;
} else {
if (!first) { // copy with preceding comma
from--;
@@ -2647,18 +2628,11 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
}
*to = '\0';
return 0;
-
-free_opt:
- if (*mnt_opts) {
- selinux_free_mnt_opts(*mnt_opts);
- *mnt_opts = NULL;
- }
- return rc;
}
static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)
{
- struct selinux_mnt_opts *opts = mnt_opts;
+ struct selinux_mnt_opts *opts = selinux_mnt_opts(mnt_opts);
struct superblock_security_struct *sbsec = selinux_superblock(sb);
/*
@@ -2703,7 +2677,7 @@ static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)
static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
{
- struct selinux_mnt_opts *opts = mnt_opts;
+ struct selinux_mnt_opts *opts = selinux_mnt_opts(mnt_opts);
struct superblock_security_struct *sbsec = selinux_superblock(sb);
if (!(sbsec->flags & SE_SBINITIALIZED))
@@ -2800,14 +2774,10 @@ static int selinux_fs_context_submount(struct fs_context *fc,
const struct superblock_security_struct *sbsec = selinux_superblock(reference);
struct selinux_mnt_opts *opts;
- /*
- * Ensure that fc->security remains NULL when no options are set
- * as expected by selinux_set_mnt_opts().
- */
if (!(sbsec->flags & (FSCONTEXT_MNT|CONTEXT_MNT|DEFCONTEXT_MNT)))
return 0;
- opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ opts = selinux_mnt_opts(fc->security);
if (!opts)
return -ENOMEM;
@@ -2817,20 +2787,22 @@ static int selinux_fs_context_submount(struct fs_context *fc,
opts->context_sid = sbsec->mntpoint_sid;
if (sbsec->flags & DEFCONTEXT_MNT)
opts->defcontext_sid = sbsec->def_sid;
- fc->security = opts;
return 0;
}
static int selinux_fs_context_dup(struct fs_context *fc,
struct fs_context *src_fc)
{
- const struct selinux_mnt_opts *src = src_fc->security;
+ const struct selinux_mnt_opts *src = selinux_mnt_opts(src_fc->security);
+ struct selinux_mnt_opts *dst = selinux_mnt_opts(fc->security);
if (!src)
return 0;
+ if (!dst)
+ return 0;
- fc->security = kmemdup(src, sizeof(*src), GFP_KERNEL);
- return fc->security ? 0 : -ENOMEM;
+ *dst = *src;
+ return 0;
}
static const struct fs_parameter_spec selinux_fs_parameters[] = {
@@ -7337,7 +7309,6 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
- LSM_HOOK_INIT(sb_free_mnt_opts, selinux_free_mnt_opts),
LSM_HOOK_INIT(sb_mnt_opts_compat, selinux_sb_mnt_opts_compat),
LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 1d7ac59015a1..cefc6c550f74 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -245,4 +245,12 @@ selinux_perf_event(void *perf_event)
return perf_event + selinux_blob_sizes.lbs_perf_event;
}
+static inline struct selinux_mnt_opts *selinux_mnt_opts(void *opts)
+{
+ if (!opts)
+ return NULL;
+
+ return opts + selinux_blob_sizes.lbs_mnt_opts;
+}
+
#endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/smack/smack.h b/security/smack/smack.h
index bf6a6ed3946c..828c913dd62d 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -367,6 +367,14 @@ static inline struct socket_smack *smack_sock(const struct sock *sock)
return sock->sk_security + smack_blob_sizes.lbs_sock;
}
+static inline struct smack_mnt_opts *smack_mnt_opts(void *opts)
+{
+ if (!opts)
+ return NULL;
+
+ return opts + smack_blob_sizes.lbs_mnt_opts;
+}
+
#ifdef CONFIG_KEYS
static inline struct smack_known **smack_key(const struct key *key)
{
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 1f236014e7d8..c83bb85ee1b5 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -551,22 +551,13 @@ struct smack_mnt_opts {
const char *fstransmute;
};
-static void smack_free_mnt_opts(void *mnt_opts)
-{
- kfree(mnt_opts);
-}
-
static int smack_add_opt(int token, const char *s, void **mnt_opts)
{
- struct smack_mnt_opts *opts = *mnt_opts;
+ struct smack_mnt_opts *opts = smack_mnt_opts(*mnt_opts);
struct smack_known *skp;
- if (!opts) {
- opts = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL);
- if (!opts)
- return -ENOMEM;
- *mnt_opts = opts;
- }
+ if (!opts)
+ return -ENOMEM;
if (!s)
return -ENOMEM;
@@ -622,10 +613,9 @@ static int smack_fs_context_submount(struct fs_context *fc,
struct smack_mnt_opts *ctx;
struct inode_smack *isp;
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = smack_mnt_opts(fc->security);
if (!ctx)
return -ENOMEM;
- fc->security = ctx;
sbsp = smack_superblock(reference);
isp = smack_inode(reference->s_root->d_inode);
@@ -668,22 +658,15 @@ static int smack_fs_context_submount(struct fs_context *fc,
static int smack_fs_context_dup(struct fs_context *fc,
struct fs_context *src_fc)
{
- struct smack_mnt_opts *dst, *src = src_fc->security;
+ struct smack_mnt_opts *dst = smack_mnt_opts(fc->security);
+ struct smack_mnt_opts *src = smack_mnt_opts(src_fc->security);
if (!src)
return 0;
+ if (!dst)
+ return 0;
- fc->security = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL);
- if (!fc->security)
- return -ENOMEM;
-
- dst = fc->security;
- dst->fsdefault = src->fsdefault;
- dst->fsfloor = src->fsfloor;
- dst->fshat = src->fshat;
- dst->fsroot = src->fsroot;
- dst->fstransmute = src->fstransmute;
-
+ *dst = *src;
return 0;
}
@@ -741,12 +724,8 @@ static int smack_sb_eat_lsm_opts(char *options, void **mnt_opts)
arg = kmemdup_nul(arg, from + len - arg, GFP_KERNEL);
rc = smack_add_opt(token, arg, mnt_opts);
kfree(arg);
- if (unlikely(rc)) {
- if (*mnt_opts)
- smack_free_mnt_opts(*mnt_opts);
- *mnt_opts = NULL;
+ if (unlikely(rc))
return rc;
- }
} else {
if (!first) { // copy with preceding comma
from--;
@@ -787,7 +766,7 @@ static int smack_set_mnt_opts(struct super_block *sb,
struct superblock_smack *sp = smack_superblock(sb);
struct inode_smack *isp;
struct smack_known *skp;
- struct smack_mnt_opts *opts = mnt_opts;
+ struct smack_mnt_opts *opts = smack_mnt_opts(mnt_opts);
bool transmute = false;
if (sp->smk_flags & SMK_SB_INITIALIZED)
@@ -5048,7 +5027,6 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
LSM_HOOK_INIT(fs_context_parse_param, smack_fs_context_parse_param),
LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security),
- LSM_HOOK_INIT(sb_free_mnt_opts, smack_free_mnt_opts),
LSM_HOOK_INIT(sb_eat_lsm_opts, smack_sb_eat_lsm_opts),
LSM_HOOK_INIT(sb_statfs, smack_sb_statfs),
LSM_HOOK_INIT(sb_set_mnt_opts, smack_set_mnt_opts),
--
2.51.0
Powered by blists - more mailing lists