From: Casey Schaufler <casey@schaufler-ca.com>
To: casey@schaufler-ca.com, paul@paul-moore.com, eparis@redhat.com,
linux-security-module@vger.kernel.org, audit@vger.kernel.org
Cc: jmorris@namei.org, serge@hallyn.com, keescook@chromium.org,
john.johansen@canonical.com, penguin-kernel@i-love.sakura.ne.jp,
stephen.smalley.work@gmail.com, linux-kernel@vger.kernel.org,
selinux@vger.kernel.org
Subject: [RFC PATCH 11/15] LSM: Infrastructure management of the mnt_opts security blob
Date: Sat, 21 Jun 2025 10:18:46 -0700 [thread overview]
Message-ID: <20250621171851.5869-12-casey@schaufler-ca.com> (raw)
In-Reply-To: <20250621171851.5869-1-casey@schaufler-ca.com>
Move management of the mnt_opts->security blob out of the
individual security modules and into the security
infrastructure. Blobs are still allocated within the modules
as they are only required when mount options are present.
The modules tell the infrastructure how much space is required,
and the space is allocated if needed. Modules can no longer
count on the presence of a blob implying that mount options
specific to that module are present, so flags are added
to the module specific blobs to indicate that this module
has options.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
security/security.c | 14 ++++-----
security/selinux/hooks.c | 58 +++++++++++++++++++++++-------------
security/smack/smack_lsm.c | 61 ++++++++++++++++++++++++++------------
3 files changed, 85 insertions(+), 48 deletions(-)
diff --git a/security/security.c b/security/security.c
index 98a80078b2df..dd167a872248 100644
--- a/security/security.c
+++ b/security/security.c
@@ -840,17 +840,14 @@ int security_fs_context_parse_param(struct fs_context *fc,
struct fs_parameter *param)
{
struct lsm_static_call *scall;
- int trc;
- int rc = -ENOPARAM;
+ int rc;
lsm_for_each_hook(scall, fs_context_parse_param) {
- trc = scall->hl->hook.fs_context_parse_param(fc, param);
- if (trc == 0)
- rc = 0;
- else if (trc != -ENOPARAM)
- return trc;
+ rc = scall->hl->hook.fs_context_parse_param(fc, param);
+ if (rc != -ENOPARAM)
+ return rc;
}
- return rc;
+ return -ENOPARAM;
}
/**
@@ -924,6 +921,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);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 8e0671920e3a..636a38449253 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -379,15 +379,28 @@ static void inode_free_security(struct inode *inode)
}
struct selinux_mnt_opts {
+ bool initialized;
u32 fscontext_sid;
u32 context_sid;
u32 rootcontext_sid;
u32 defcontext_sid;
};
+static inline struct selinux_mnt_opts *selinux_mnt_opts(void *mnt_opts)
+{
+ if (mnt_opts)
+ return mnt_opts + selinux_blob_sizes.lbs_mnt_opts;
+ return NULL;
+}
+
static void selinux_free_mnt_opts(void *mnt_opts)
{
- kfree(mnt_opts);
+ struct selinux_mnt_opts *opts;
+
+ if (mnt_opts) {
+ opts = selinux_mnt_opts(mnt_opts);
+ opts->initialized = false;
+ }
}
enum {
@@ -642,7 +655,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;
@@ -658,7 +671,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
mutex_lock(&sbsec->lock);
if (!selinux_initialized()) {
- if (!opts) {
+ if (!opts || !opts->initialized) {
/* Defer initialization until selinux_complete_init,
after the initial policy is loaded and the security
server is ready to handle calls. */
@@ -696,7 +709,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* also check if someone is trying to mount the same sb more
* than once with different security options.
*/
- if (opts) {
+ if (opts && opts->initialized) {
if (opts->fscontext_sid) {
fscontext_sid = opts->fscontext_sid;
if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
@@ -1005,7 +1018,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;
u32 *dst_sid;
int rc;
@@ -1020,12 +1033,12 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
return -EINVAL;
}
- if (!opts) {
- opts = kzalloc(sizeof(*opts), GFP_KERNEL);
- if (!opts)
+ if (!*mnt_opts) {
+ *mnt_opts = lsm_mnt_opts_alloc(GFP_KERNEL);
+ if (!*mnt_opts)
return -ENOMEM;
- *mnt_opts = opts;
}
+ opts = selinux_mnt_opts(*mnt_opts);
switch (token) {
case Opt_context:
@@ -1052,6 +1065,7 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
WARN_ON(1);
return -EINVAL;
}
+ opts->initialized = true;
rc = security_context_str_to_sid(s, dst_sid, GFP_KERNEL);
if (rc)
pr_warn("SELinux: security_context_str_to_sid (%s) failed with errno=%d\n",
@@ -2651,10 +2665,7 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
return 0;
free_opt:
- if (*mnt_opts) {
- selinux_free_mnt_opts(*mnt_opts);
- *mnt_opts = NULL;
- }
+ selinux_free_mnt_opts(*mnt_opts);
return rc;
}
@@ -2705,13 +2716,13 @@ 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))
return 0;
- if (!opts)
+ if (!opts || !opts->initialized)
return 0;
if (opts->fscontext_sid) {
@@ -2809,9 +2820,13 @@ static int selinux_fs_context_submount(struct fs_context *fc,
if (!(sbsec->flags & (FSCONTEXT_MNT|CONTEXT_MNT|DEFCONTEXT_MNT)))
return 0;
- opts = lsm_mnt_opts_alloc(GFP_KERNEL);
- if (!opts)
- return -ENOMEM;
+ if (!fc->security) {
+ fc->security = lsm_mnt_opts_alloc(GFP_KERNEL);
+ if (!fc->security)
+ return -ENOMEM;
+ }
+ opts = selinux_mnt_opts(fc->security);
+ opts->initialized = true;
if (sbsec->flags & FSCONTEXT_MNT)
opts->fscontext_sid = sbsec->sid;
@@ -2819,14 +2834,14 @@ 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;
if (!src)
return 0;
@@ -2835,7 +2850,8 @@ static int selinux_fs_context_dup(struct fs_context *fc,
if (!fc->security)
return -ENOMEM;
- memcpy(fc->security, src, sizeof(*src));
+ dst = selinux_mnt_opts(fc->security);
+ memcpy(dst, src, sizeof(*src));
return 0;
}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 0cc24b57bb52..ced66130fb7d 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -544,6 +544,7 @@ static int smack_sb_alloc_security(struct super_block *sb)
}
struct smack_mnt_opts {
+ bool initialized;
const char *fsdefault;
const char *fsfloor;
const char *fshat;
@@ -551,24 +552,37 @@ struct smack_mnt_opts {
const char *fstransmute;
};
+static inline struct smack_mnt_opts *smack_mnt_opts(void *mnt_opts)
+{
+ if (mnt_opts)
+ return mnt_opts + smack_blob_sizes.lbs_mnt_opts;
+ return NULL;
+}
+
static void smack_free_mnt_opts(void *mnt_opts)
{
- kfree(mnt_opts);
+ struct smack_mnt_opts *opts;
+
+ if (mnt_opts) {
+ opts = smack_mnt_opts(mnt_opts);
+ opts->initialized = false;
+ }
}
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;
struct smack_known *skp;
- if (!opts) {
- opts = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL);
- if (!opts)
+ if (!s)
+ return -EINVAL;
+
+ if (!*mnt_opts) {
+ *mnt_opts = lsm_mnt_opts_alloc(GFP_KERNEL);
+ if (!*mnt_opts)
return -ENOMEM;
- *mnt_opts = opts;
}
- if (!s)
- return -ENOMEM;
+ opts = smack_mnt_opts(*mnt_opts);
skp = smk_import_entry(s, 0);
if (IS_ERR(skp))
@@ -601,6 +615,7 @@ static int smack_add_opt(int token, const char *s, void **mnt_opts)
opts->fstransmute = skp->smk_known;
break;
}
+ opts->initialized = true;
return 0;
out_opt_err:
@@ -622,10 +637,12 @@ static int smack_fs_context_submount(struct fs_context *fc,
struct smack_mnt_opts *ctx;
struct inode_smack *isp;
- ctx = lsm_mnt_opts_alloc(GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
- fc->security = ctx;
+ if (!fc->security) {
+ fc->security = lsm_mnt_opts_alloc(GFP_KERNEL);
+ if (!fc->security)
+ return -ENOMEM;
+ }
+ ctx = smack_mnt_opts(fc->security);
sbsp = smack_superblock(reference);
isp = smack_inode(reference->s_root->d_inode);
@@ -655,6 +672,7 @@ static int smack_fs_context_submount(struct fs_context *fc,
return -ENOMEM;
}
}
+ ctx->initialized = true;
return 0;
}
@@ -668,16 +686,21 @@ 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 *src;
+ struct smack_mnt_opts *dst;
+ src = smack_mnt_opts(src_fc->security);
if (!src)
return 0;
- fc->security = lsm_mnt_opts_alloc(GFP_KERNEL);
- if (!fc->security)
- return -ENOMEM;
+ if (!fc->security) {
+ fc->security = lsm_mnt_opts_alloc(GFP_KERNEL);
+ if (!fc->security)
+ return -ENOMEM;
+ }
- dst = fc->security;
+ dst = smack_mnt_opts(fc->security);
+ dst->initialized = src->initialized;
dst->fsdefault = src->fsdefault;
dst->fsfloor = src->fsfloor;
dst->fshat = src->fshat;
@@ -787,7 +810,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)
@@ -820,7 +843,7 @@ static int smack_set_mnt_opts(struct super_block *sb,
sp->smk_flags |= SMK_SB_INITIALIZED;
- if (opts) {
+ if (opts && opts->initialized) {
if (opts->fsdefault) {
skp = smk_import_entry(opts->fsdefault, 0);
if (IS_ERR(skp))
--
2.47.0
next prev parent reply other threads:[~2025-06-21 17:22 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20250621171851.5869-1-casey.ref@schaufler-ca.com>
2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
2025-06-21 17:18 ` [RFC PATCH 01/15] Audit: Create audit_stamp structure Casey Schaufler
2025-10-14 23:12 ` [PATCH RFC 1/15] " Paul Moore
2025-06-21 17:18 ` [RFC PATCH 02/15] LSM: security_lsmblob_to_secctx module selection Casey Schaufler
2025-10-14 23:12 ` [PATCH RFC 2/15] " Paul Moore
2025-06-21 17:18 ` [RFC PATCH 03/15] Audit: Add record for multiple task security contexts Casey Schaufler
2025-10-14 23:12 ` [PATCH RFC 3/15] " Paul Moore
2025-06-21 17:18 ` [RFC PATCH 04/15] Audit: Add record for multiple object contexts Casey Schaufler
2025-10-14 23:12 ` [PATCH RFC 4/15] " Paul Moore
2025-06-21 17:18 ` [RFC PATCH 05/15] LSM: Single calls in secid hooks Casey Schaufler
2025-10-14 23:12 ` [PATCH RFC 5/15] " Paul Moore
2025-11-04 16:00 ` Casey Schaufler
2025-06-21 17:18 ` [RFC PATCH 06/15] LSM: Exclusive secmark usage Casey Schaufler
2025-10-14 23:12 ` [PATCH RFC 6/15] " Paul Moore
2025-06-21 17:18 ` [RFC PATCH 07/15] Audit: Call only the first of the audit rule hooks Casey Schaufler
2025-10-14 23:12 ` [PATCH RFC 7/15] " Paul Moore
2025-06-21 17:18 ` [RFC PATCH 08/15] AppArmor: Remove the exclusive flag Casey Schaufler
2025-06-21 17:18 ` [RFC PATCH 09/15] LSM: Add mount opts blob size tracking Casey Schaufler
2025-10-14 23:12 ` [PATCH RFC 9/15] " Paul Moore
2025-06-21 17:18 ` [RFC PATCH 10/15] LSM: allocate mnt_opts blobs instead of module specific data Casey Schaufler
2025-10-14 23:12 ` [PATCH RFC " Paul Moore
2025-06-21 17:18 ` Casey Schaufler [this message]
2025-10-14 23:12 ` [PATCH RFC 11/15] LSM: Infrastructure management of the mnt_opts security blob Paul Moore
2025-06-21 17:18 ` [RFC PATCH 12/15] LSM: Allow reservation of netlabel Casey Schaufler
2025-10-14 23:12 ` [PATCH RFC " Paul Moore
2025-06-21 17:18 ` [RFC PATCH 13/15] LSM: restrict security_cred_getsecid() to a single LSM Casey Schaufler
2025-10-14 23:13 ` [PATCH RFC " Paul Moore
2025-06-21 17:18 ` [RFC PATCH 14/15] Smack: Remove LSM_FLAG_EXCLUSIVE Casey Schaufler
2025-06-21 17:18 ` [RFC PATCH 15/15] LSM: Remove exclusive LSM flag Casey Schaufler
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=20250621171851.5869-12-casey@schaufler-ca.com \
--to=casey@schaufler-ca.com \
--cc=audit@vger.kernel.org \
--cc=eparis@redhat.com \
--cc=jmorris@namei.org \
--cc=john.johansen@canonical.com \
--cc=keescook@chromium.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--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 \
/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