* [PATCH v5 08/34] lsm: replace the name field with a pointer to the lsm_id struct
From: Paul Moore @ 2025-10-17 20:24 UTC (permalink / raw)
To: linux-security-module, linux-integrity, selinux
Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
Mickaël Salaün, Günther Noack, Kees Cook,
Micah Morton, Casey Schaufler, Tetsuo Handa, Nicolas Bouchinet,
Xiu Jianfeng
In-Reply-To: <20251017202456.484010-36-paul@paul-moore.com>
Reduce the duplication between the lsm_id struct and the DEFINE_LSM()
definition by linking the lsm_id struct directly into the individual
LSM's DEFINE_LSM() instance.
Linking the lsm_id into the LSM definition also allows us to simplify
the security_add_hooks() function by removing the code which populates
the lsm_idlist[] array and moving it into the normal LSM startup code
where the LSM list is parsed and the individual LSMs are enabled,
making for a cleaner implementation with less overhead at boot.
Reviewed-by: Kees Cook <kees@kernel.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
---
include/linux/lsm_hooks.h | 2 +-
security/apparmor/lsm.c | 2 +-
security/bpf/hooks.c | 2 +-
security/commoncap.c | 2 +-
security/integrity/evm/evm_main.c | 2 +-
security/integrity/ima/ima_main.c | 2 +-
security/ipe/ipe.c | 2 +-
security/landlock/setup.c | 2 +-
security/loadpin/loadpin.c | 2 +-
security/lockdown/lockdown.c | 2 +-
security/lsm_init.c | 45 +++++++++++++------------------
security/safesetid/lsm.c | 2 +-
security/selinux/hooks.c | 2 +-
security/smack/smack_lsm.c | 2 +-
security/tomoyo/tomoyo.c | 2 +-
security/yama/yama_lsm.c | 2 +-
16 files changed, 33 insertions(+), 42 deletions(-)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 0112926ed923..7343dd60b1d5 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -152,7 +152,7 @@ enum lsm_order {
};
struct lsm_info {
- const char *name; /* Required. */
+ const struct lsm_id *id;
enum lsm_order order; /* Optional: default is LSM_ORDER_MUTABLE */
unsigned long flags; /* Optional: flags describing LSM */
int *enabled; /* Optional: controlled by CONFIG_LSM */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index b3f7a3258a2c..f6798144234b 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -2555,7 +2555,7 @@ static int __init apparmor_init(void)
}
DEFINE_LSM(apparmor) = {
- .name = "apparmor",
+ .id = &apparmor_lsmid,
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.enabled = &apparmor_enabled,
.blobs = &apparmor_blob_sizes,
diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
index db759025abe1..40efde233f3a 100644
--- a/security/bpf/hooks.c
+++ b/security/bpf/hooks.c
@@ -33,7 +33,7 @@ struct lsm_blob_sizes bpf_lsm_blob_sizes __ro_after_init = {
};
DEFINE_LSM(bpf) = {
- .name = "bpf",
+ .id = &bpf_lsmid,
.init = bpf_lsm_init,
.blobs = &bpf_lsm_blob_sizes
};
diff --git a/security/commoncap.c b/security/commoncap.c
index 6bd4adeb4795..b50479bd0286 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -1505,7 +1505,7 @@ static int __init capability_init(void)
}
DEFINE_LSM(capability) = {
- .name = "capability",
+ .id = &capability_lsmid,
.order = LSM_ORDER_FIRST,
.init = capability_init,
};
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 0add782e73ba..db8e324ed4e6 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -1175,7 +1175,7 @@ struct lsm_blob_sizes evm_blob_sizes __ro_after_init = {
};
DEFINE_LSM(evm) = {
- .name = "evm",
+ .id = &evm_lsmid,
.init = init_evm_lsm,
.order = LSM_ORDER_LAST,
.blobs = &evm_blob_sizes,
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index cdd225f65a62..eade8e1e3cb1 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -1279,7 +1279,7 @@ struct lsm_blob_sizes ima_blob_sizes __ro_after_init = {
};
DEFINE_LSM(ima) = {
- .name = "ima",
+ .id = &ima_lsmid,
.init = init_ima_lsm,
.order = LSM_ORDER_LAST,
.blobs = &ima_blob_sizes,
diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
index 4317134cb0da..2426441181dc 100644
--- a/security/ipe/ipe.c
+++ b/security/ipe/ipe.c
@@ -92,7 +92,7 @@ static int __init ipe_init(void)
}
DEFINE_LSM(ipe) = {
- .name = "ipe",
+ .id = &ipe_lsmid,
.init = ipe_init,
.blobs = &ipe_blobs,
};
diff --git a/security/landlock/setup.c b/security/landlock/setup.c
index bd53c7a56ab9..47dac1736f10 100644
--- a/security/landlock/setup.c
+++ b/security/landlock/setup.c
@@ -75,7 +75,7 @@ static int __init landlock_init(void)
}
DEFINE_LSM(LANDLOCK_NAME) = {
- .name = LANDLOCK_NAME,
+ .id = &landlock_lsmid,
.init = landlock_init,
.blobs = &landlock_blob_sizes,
};
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
index 68252452b66c..b9ddf05c5c16 100644
--- a/security/loadpin/loadpin.c
+++ b/security/loadpin/loadpin.c
@@ -271,7 +271,7 @@ static int __init loadpin_init(void)
}
DEFINE_LSM(loadpin) = {
- .name = "loadpin",
+ .id = &loadpin_lsmid,
.init = loadpin_init,
};
diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
index cf83afa1d879..4813f168ff93 100644
--- a/security/lockdown/lockdown.c
+++ b/security/lockdown/lockdown.c
@@ -168,6 +168,6 @@ DEFINE_EARLY_LSM(lockdown) = {
#else
DEFINE_LSM(lockdown) = {
#endif
- .name = "lockdown",
+ .id = &lockdown_lsmid,
.init = lockdown_lsm_init,
};
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 9249d5f37ae9..692d61a2ea10 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -127,9 +127,10 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
/* Enable this LSM, if it is not already set. */
if (!lsm->enabled)
lsm->enabled = &lsm_enabled_true;
- ordered_lsms[last_lsm++] = lsm;
+ ordered_lsms[last_lsm] = lsm;
+ lsm_idlist[last_lsm++] = lsm->id;
- init_debug("%s ordered: %s (%s)\n", from, lsm->name,
+ init_debug("%s ordered: %s (%s)\n", from, lsm->id->name,
is_enabled(lsm) ? "enabled" : "disabled");
}
@@ -157,7 +158,7 @@ static void __init lsm_prepare(struct lsm_info *lsm)
set_enabled(lsm, false);
return;
} else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
- init_debug("exclusive disabled: %s\n", lsm->name);
+ init_debug("exclusive disabled: %s\n", lsm->id->name);
set_enabled(lsm, false);
return;
}
@@ -165,7 +166,7 @@ static void __init lsm_prepare(struct lsm_info *lsm)
/* Mark the LSM as enabled. */
set_enabled(lsm, true);
if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
- init_debug("exclusive chosen: %s\n", lsm->name);
+ init_debug("exclusive chosen: %s\n", lsm->id->name);
exclusive = lsm;
}
@@ -200,9 +201,9 @@ static void __init initialize_lsm(struct lsm_info *lsm)
if (is_enabled(lsm)) {
int ret;
- init_debug("initializing %s\n", lsm->name);
+ init_debug("initializing %s\n", lsm->id->name);
ret = lsm->init();
- WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
+ WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
}
}
@@ -236,10 +237,10 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
*/
lsm_for_each_raw(major) {
if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
- strcmp(major->name, chosen_major_lsm) != 0) {
+ strcmp(major->id->name, chosen_major_lsm) != 0) {
set_enabled(major, false);
init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
- chosen_major_lsm, major->name);
+ chosen_major_lsm, major->id->name);
}
}
}
@@ -251,7 +252,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
bool found = false;
lsm_for_each_raw(lsm) {
- if (strcmp(lsm->name, name) == 0) {
+ if (strcmp(lsm->id->name, name) == 0) {
if (lsm->order == LSM_ORDER_MUTABLE)
append_ordered_lsm(lsm, origin);
found = true;
@@ -268,7 +269,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
lsm_for_each_raw(lsm) {
if (exists_ordered_lsm(lsm))
continue;
- if (strcmp(lsm->name, chosen_major_lsm) == 0)
+ if (strcmp(lsm->id->name, chosen_major_lsm) == 0)
append_ordered_lsm(lsm, "security=");
}
}
@@ -285,7 +286,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
continue;
set_enabled(lsm, false);
init_debug("%s skipped: %s (not in requested order)\n",
- origin, lsm->name);
+ origin, lsm->id->name);
}
kfree(sep);
@@ -317,11 +318,13 @@ static void __init lsm_init_ordered(void)
pr_info("initializing lsm=");
lsm_early_for_each_raw(early) {
if (is_enabled(early))
- pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
+ pr_cont("%s%s",
+ first++ == 0 ? "" : ",", early->id->name);
}
lsm_order_for_each(lsm) {
if (is_enabled(*lsm))
- pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
+ pr_cont("%s%s",
+ first++ == 0 ? "" : ",", (*lsm)->id->name);
}
pr_cont("\n");
@@ -432,18 +435,6 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
{
int i;
- /*
- * A security module may call security_add_hooks() more
- * than once during initialization, and LSM initialization
- * is serialized. Landlock is one such case.
- * Look at the previous entry, if there is one, for duplication.
- */
- if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) {
- if (lsm_active_cnt >= MAX_LSM_COUNT)
- panic("%s Too many LSMs registered.\n", __func__);
- lsm_idlist[lsm_active_cnt++] = lsmid;
- }
-
for (i = 0; i < count; i++) {
hooks[i].lsmid = lsmid;
lsm_static_call_init(&hooks[i]);
@@ -491,10 +482,10 @@ int __init security_init(void)
* available
*/
lsm_early_for_each_raw(lsm) {
- init_debug(" early started: %s (%s)\n", lsm->name,
+ init_debug(" early started: %s (%s)\n", lsm->id->name,
is_enabled(lsm) ? "enabled" : "disabled");
if (lsm->enabled)
- lsm_append(lsm->name, &lsm_names);
+ lsm_append(lsm->id->name, &lsm_names);
}
/* Load LSMs in specified order. */
diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c
index 1ba564f097f5..9a7c68d4e642 100644
--- a/security/safesetid/lsm.c
+++ b/security/safesetid/lsm.c
@@ -287,6 +287,6 @@ static int __init safesetid_security_init(void)
}
DEFINE_LSM(safesetid_security_init) = {
+ .id = &safesetid_lsmid,
.init = safesetid_security_init,
- .name = "safesetid",
};
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index dfc22da42f30..299b656ac007 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7639,7 +7639,7 @@ void selinux_complete_init(void)
/* SELinux requires early initialization in order to label
all processes and objects when they are created. */
DEFINE_LSM(selinux) = {
- .name = "selinux",
+ .id = &selinux_lsmid,
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.enabled = &selinux_enabled_boot,
.blobs = &selinux_blob_sizes,
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index af986587841d..392698e41120 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5280,7 +5280,7 @@ static __init int smack_init(void)
* all processes and objects when they are created.
*/
DEFINE_LSM(smack) = {
- .name = "smack",
+ .id = &smack_lsmid,
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.blobs = &smack_blob_sizes,
.init = smack_init,
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index 48fc59d38ab2..cb003c460dc2 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -612,7 +612,7 @@ static int __init tomoyo_init(void)
}
DEFINE_LSM(tomoyo) = {
- .name = "tomoyo",
+ .id = &tomoyo_lsmid,
.enabled = &tomoyo_enabled,
.flags = LSM_FLAG_LEGACY_MAJOR,
.blobs = &tomoyo_blob_sizes,
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 3d064dd4e03f..38b21ee0c560 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -476,6 +476,6 @@ static int __init yama_init(void)
}
DEFINE_LSM(yama) = {
- .name = "yama",
+ .id = &yama_lsmid,
.init = yama_init,
};
--
2.51.1.dirty
^ permalink raw reply related
* [PATCH v5 07/34] lsm: rename ordered_lsm_init() to lsm_init_ordered()
From: Paul Moore @ 2025-10-17 20:24 UTC (permalink / raw)
To: linux-security-module, linux-integrity, selinux
Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
Mickaël Salaün, Günther Noack, Kees Cook,
Micah Morton, Casey Schaufler, Tetsuo Handa, Nicolas Bouchinet,
Xiu Jianfeng
In-Reply-To: <20251017202456.484010-36-paul@paul-moore.com>
The new name more closely fits the rest of the naming scheme in
security/lsm_init.c. This patch also adds a trivial comment block to
the top of the function.
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
---
security/lsm_init.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 8bb473aca113..9249d5f37ae9 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -291,7 +291,10 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
kfree(sep);
}
-static void __init ordered_lsm_init(void)
+/**
+ * lsm_init_ordered - Initialize the ordered LSMs
+ */
+static void __init lsm_init_ordered(void)
{
unsigned int first = 0;
struct lsm_info **lsm;
@@ -342,9 +345,6 @@ static void __init ordered_lsm_init(void)
init_debug("bpf prog blob size = %d\n", blob_sizes.lbs_bpf_prog);
init_debug("bpf token blob size = %d\n", blob_sizes.lbs_bpf_token);
- /*
- * Create any kmem_caches needed for blobs
- */
if (blob_sizes.lbs_file)
lsm_file_cache = kmem_cache_create("lsm_file_cache",
blob_sizes.lbs_file, 0,
@@ -498,7 +498,7 @@ int __init security_init(void)
}
/* Load LSMs in specified order. */
- ordered_lsm_init();
+ lsm_init_ordered();
return 0;
}
--
2.51.1.dirty
^ permalink raw reply related
* [PATCH v5 06/34] lsm: integrate lsm_early_cred() and lsm_early_task() into caller
From: Paul Moore @ 2025-10-17 20:24 UTC (permalink / raw)
To: linux-security-module, linux-integrity, selinux
Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
Mickaël Salaün, Günther Noack, Kees Cook,
Micah Morton, Casey Schaufler, Tetsuo Handa, Nicolas Bouchinet,
Xiu Jianfeng
In-Reply-To: <20251017202456.484010-36-paul@paul-moore.com>
With only one caller of lsm_early_cred() and lsm_early_task(), insert
the functions' code directly into the caller and ger rid of the two
functions.
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
---
security/lsm_init.c | 35 +++++------------------------------
1 file changed, 5 insertions(+), 30 deletions(-)
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 09afa7ad719e..8bb473aca113 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -291,34 +291,6 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
kfree(sep);
}
-/**
- * lsm_early_cred - during initialization allocate a composite cred blob
- * @cred: the cred that needs a blob
- *
- * Allocate the cred blob for all the modules
- */
-static void __init lsm_early_cred(struct cred *cred)
-{
- int rc = lsm_cred_alloc(cred, GFP_KERNEL);
-
- if (rc)
- panic("%s: Early cred alloc failed.\n", __func__);
-}
-
-/**
- * lsm_early_task - during initialization allocate a composite task blob
- * @task: the task that needs a blob
- *
- * Allocate the task blob for all the modules
- */
-static void __init lsm_early_task(struct task_struct *task)
-{
- int rc = lsm_task_alloc(task);
-
- if (rc)
- panic("%s: Early task alloc failed.\n", __func__);
-}
-
static void __init ordered_lsm_init(void)
{
unsigned int first = 0;
@@ -382,8 +354,11 @@ static void __init ordered_lsm_init(void)
blob_sizes.lbs_inode, 0,
SLAB_PANIC, NULL);
- lsm_early_cred((struct cred *) current->cred);
- lsm_early_task(current);
+ if (lsm_cred_alloc((struct cred __rcu *)current->cred, GFP_KERNEL))
+ panic("%s: early cred alloc failed.\n", __func__);
+ if (lsm_task_alloc(current))
+ panic("%s: early task alloc failed.\n", __func__);
+
lsm_order_for_each(lsm) {
initialize_lsm(*lsm);
}
--
2.51.1.dirty
^ permalink raw reply related
* [PATCH v5 05/34] lsm: integrate report_lsm_order() code into caller
From: Paul Moore @ 2025-10-17 20:24 UTC (permalink / raw)
To: linux-security-module, linux-integrity, selinux
Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
Mickaël Salaün, Günther Noack, Kees Cook,
Micah Morton, Casey Schaufler, Tetsuo Handa, Nicolas Bouchinet,
Xiu Jianfeng
In-Reply-To: <20251017202456.484010-36-paul@paul-moore.com>
With only one caller of report_lsm_order(), insert the function's code
directly into the caller and ger rid of report_lsm_order().
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
---
security/lsm_init.c | 33 ++++++++++++---------------------
1 file changed, 12 insertions(+), 21 deletions(-)
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 18828a65c364..09afa7ad719e 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -291,26 +291,6 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
kfree(sep);
}
-static void __init report_lsm_order(void)
-{
- struct lsm_info **lsm, *early;
- int first = 0;
-
- pr_info("initializing lsm=");
-
- /* Report each enabled LSM name, comma separated. */
- lsm_early_for_each_raw(early) {
- if (is_enabled(early))
- pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
- }
- lsm_order_for_each(lsm) {
- if (is_enabled(*lsm))
- pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
- }
-
- pr_cont("\n");
-}
-
/**
* lsm_early_cred - during initialization allocate a composite cred blob
* @cred: the cred that needs a blob
@@ -341,7 +321,9 @@ static void __init lsm_early_task(struct task_struct *task)
static void __init ordered_lsm_init(void)
{
+ unsigned int first = 0;
struct lsm_info **lsm;
+ struct lsm_info *early;
if (chosen_lsm_order) {
if (chosen_major_lsm) {
@@ -357,7 +339,16 @@ static void __init ordered_lsm_init(void)
lsm_prepare(*lsm);
}
- report_lsm_order();
+ pr_info("initializing lsm=");
+ lsm_early_for_each_raw(early) {
+ if (is_enabled(early))
+ pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
+ }
+ lsm_order_for_each(lsm) {
+ if (is_enabled(*lsm))
+ pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
+ }
+ pr_cont("\n");
init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
init_debug("file blob size = %d\n", blob_sizes.lbs_file);
--
2.51.1.dirty
^ permalink raw reply related
* [PATCH v5 04/34] lsm: introduce looping macros for the initialization code
From: Paul Moore @ 2025-10-17 20:24 UTC (permalink / raw)
To: linux-security-module, linux-integrity, selinux
Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
Mickaël Salaün, Günther Noack, Kees Cook,
Micah Morton, Casey Schaufler, Tetsuo Handa, Nicolas Bouchinet,
Xiu Jianfeng
In-Reply-To: <20251017202456.484010-36-paul@paul-moore.com>
There are three common for loop patterns in the LSM initialization code
to loop through the ordered LSM list and the registered "early" LSMs.
This patch implements these loop patterns as macros to help simplify the
code and reduce the chance for errors.
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
---
security/lsm_init.c | 42 +++++++++++++++++++++++++++---------------
1 file changed, 27 insertions(+), 15 deletions(-)
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 6f40ab1d2f54..18828a65c364 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -32,6 +32,15 @@ static __initdata bool debug;
pr_info(__VA_ARGS__); \
} while (0)
+#define lsm_order_for_each(iter) \
+ for ((iter) = ordered_lsms; *(iter); (iter)++)
+#define lsm_for_each_raw(iter) \
+ for ((iter) = __start_lsm_info; \
+ (iter) < __end_lsm_info; (iter)++)
+#define lsm_early_for_each_raw(iter) \
+ for ((iter) = __start_early_lsm_info; \
+ (iter) < __end_early_lsm_info; (iter)++)
+
static int lsm_append(const char *new, char **result);
/* Save user chosen LSM */
@@ -96,9 +105,10 @@ static bool __init exists_ordered_lsm(struct lsm_info *lsm)
{
struct lsm_info **check;
- for (check = ordered_lsms; *check; check++)
+ lsm_order_for_each(check) {
if (*check == lsm)
return true;
+ }
return false;
}
@@ -209,7 +219,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
char *sep, *name, *next;
/* LSM_ORDER_FIRST is always first. */
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ lsm_for_each_raw(lsm) {
if (lsm->order == LSM_ORDER_FIRST)
append_ordered_lsm(lsm, " first");
}
@@ -224,8 +234,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
* if the selected one was separately disabled: disable
* all non-matching Legacy Major LSMs.
*/
- for (major = __start_lsm_info; major < __end_lsm_info;
- major++) {
+ lsm_for_each_raw(major) {
if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
strcmp(major->name, chosen_major_lsm) != 0) {
set_enabled(major, false);
@@ -241,7 +250,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
while ((name = strsep(&next, ",")) != NULL) {
bool found = false;
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ lsm_for_each_raw(lsm) {
if (strcmp(lsm->name, name) == 0) {
if (lsm->order == LSM_ORDER_MUTABLE)
append_ordered_lsm(lsm, origin);
@@ -256,7 +265,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
/* Process "security=", if given. */
if (chosen_major_lsm) {
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ lsm_for_each_raw(lsm) {
if (exists_ordered_lsm(lsm))
continue;
if (strcmp(lsm->name, chosen_major_lsm) == 0)
@@ -265,13 +274,13 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
}
/* LSM_ORDER_LAST is always last. */
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ lsm_for_each_raw(lsm) {
if (lsm->order == LSM_ORDER_LAST)
append_ordered_lsm(lsm, " last");
}
/* Disable all LSMs not in the ordered list. */
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ lsm_for_each_raw(lsm) {
if (exists_ordered_lsm(lsm))
continue;
set_enabled(lsm, false);
@@ -290,13 +299,14 @@ static void __init report_lsm_order(void)
pr_info("initializing lsm=");
/* Report each enabled LSM name, comma separated. */
- for (early = __start_early_lsm_info;
- early < __end_early_lsm_info; early++)
+ lsm_early_for_each_raw(early) {
if (is_enabled(early))
pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
- for (lsm = ordered_lsms; *lsm; lsm++)
+ }
+ lsm_order_for_each(lsm) {
if (is_enabled(*lsm))
pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
+ }
pr_cont("\n");
}
@@ -343,8 +353,9 @@ static void __init ordered_lsm_init(void)
} else
ordered_lsm_parse(builtin_lsm_order, "builtin");
- for (lsm = ordered_lsms; *lsm; lsm++)
+ lsm_order_for_each(lsm) {
lsm_prepare(*lsm);
+ }
report_lsm_order();
@@ -382,8 +393,9 @@ static void __init ordered_lsm_init(void)
lsm_early_cred((struct cred *) current->cred);
lsm_early_task(current);
- for (lsm = ordered_lsms; *lsm; lsm++)
+ lsm_order_for_each(lsm) {
initialize_lsm(*lsm);
+ }
}
static bool match_last_lsm(const char *list, const char *lsm)
@@ -485,7 +497,7 @@ int __init early_security_init(void)
{
struct lsm_info *lsm;
- for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
+ lsm_early_for_each_raw(lsm) {
if (!lsm->enabled)
lsm->enabled = &lsm_enabled_true;
lsm_prepare(lsm);
@@ -512,7 +524,7 @@ int __init security_init(void)
* Append the names of the early LSM modules now that kmalloc() is
* available
*/
- for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
+ lsm_early_for_each_raw(lsm) {
init_debug(" early started: %s (%s)\n", lsm->name,
is_enabled(lsm) ? "enabled" : "disabled");
if (lsm->enabled)
--
2.51.1.dirty
^ permalink raw reply related
* [PATCH v5 03/34] lsm: consolidate lsm_allowed() and prepare_lsm() into lsm_prepare()
From: Paul Moore @ 2025-10-17 20:24 UTC (permalink / raw)
To: linux-security-module, linux-integrity, selinux
Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
Mickaël Salaün, Günther Noack, Kees Cook,
Micah Morton, Casey Schaufler, Tetsuo Handa, Nicolas Bouchinet,
Xiu Jianfeng
In-Reply-To: <20251017202456.484010-36-paul@paul-moore.com>
Simplify and consolidate the lsm_allowed() and prepare_lsm() functions
into a new function, lsm_prepare().
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
---
security/lsm_init.c | 109 +++++++++++++++++++-------------------------
1 file changed, 46 insertions(+), 63 deletions(-)
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 124213b906af..6f40ab1d2f54 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -123,22 +123,6 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
is_enabled(lsm) ? "enabled" : "disabled");
}
-/* Is an LSM allowed to be initialized? */
-static bool __init lsm_allowed(struct lsm_info *lsm)
-{
- /* Skip if the LSM is disabled. */
- if (!is_enabled(lsm))
- return false;
-
- /* Not allowed if another exclusive LSM already initialized. */
- if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
- init_debug("exclusive disabled: %s\n", lsm->name);
- return false;
- }
-
- return true;
-}
-
static void __init lsm_set_blob_size(int *need, int *lbs)
{
int offset;
@@ -151,54 +135,53 @@ static void __init lsm_set_blob_size(int *need, int *lbs)
*need = offset;
}
-static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
+/**
+ * lsm_prepare - Prepare the LSM framework for a new LSM
+ * @lsm: LSM definition
+ */
+static void __init lsm_prepare(struct lsm_info *lsm)
{
- if (!needed)
+ struct lsm_blob_sizes *blobs;
+
+ if (!is_enabled(lsm)) {
+ set_enabled(lsm, false);
+ return;
+ } else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
+ init_debug("exclusive disabled: %s\n", lsm->name);
+ set_enabled(lsm, false);
return;
-
- lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
- lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
- lsm_set_blob_size(&needed->lbs_ib, &blob_sizes.lbs_ib);
- /*
- * The inode blob gets an rcu_head in addition to
- * what the modules might need.
- */
- if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
- blob_sizes.lbs_inode = sizeof(struct rcu_head);
- lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
- lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
- lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
- lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
- lsm_set_blob_size(&needed->lbs_perf_event, &blob_sizes.lbs_perf_event);
- lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
- lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
- lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
- lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
- lsm_set_blob_size(&needed->lbs_xattr_count,
- &blob_sizes.lbs_xattr_count);
- lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
- lsm_set_blob_size(&needed->lbs_bpf_map, &blob_sizes.lbs_bpf_map);
- lsm_set_blob_size(&needed->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog);
- lsm_set_blob_size(&needed->lbs_bpf_token, &blob_sizes.lbs_bpf_token);
-}
-
-/* Prepare LSM for initialization. */
-static void __init prepare_lsm(struct lsm_info *lsm)
-{
- int enabled = lsm_allowed(lsm);
-
- /* Record enablement (to handle any following exclusive LSMs). */
- set_enabled(lsm, enabled);
-
- /* If enabled, do pre-initialization work. */
- if (enabled) {
- if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
- exclusive = lsm;
- init_debug("exclusive chosen: %s\n", lsm->name);
- }
-
- lsm_set_blob_sizes(lsm->blobs);
}
+
+ /* Mark the LSM as enabled. */
+ set_enabled(lsm, true);
+ if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
+ init_debug("exclusive chosen: %s\n", lsm->name);
+ exclusive = lsm;
+ }
+
+ /* Register the LSM blob sizes. */
+ blobs = lsm->blobs;
+ lsm_set_blob_size(&blobs->lbs_cred, &blob_sizes.lbs_cred);
+ lsm_set_blob_size(&blobs->lbs_file, &blob_sizes.lbs_file);
+ lsm_set_blob_size(&blobs->lbs_ib, &blob_sizes.lbs_ib);
+ /* inode blob gets an rcu_head in addition to LSM blobs. */
+ if (blobs->lbs_inode && blob_sizes.lbs_inode == 0)
+ blob_sizes.lbs_inode = sizeof(struct rcu_head);
+ lsm_set_blob_size(&blobs->lbs_inode, &blob_sizes.lbs_inode);
+ lsm_set_blob_size(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
+ lsm_set_blob_size(&blobs->lbs_key, &blob_sizes.lbs_key);
+ lsm_set_blob_size(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
+ lsm_set_blob_size(&blobs->lbs_perf_event, &blob_sizes.lbs_perf_event);
+ lsm_set_blob_size(&blobs->lbs_sock, &blob_sizes.lbs_sock);
+ lsm_set_blob_size(&blobs->lbs_superblock, &blob_sizes.lbs_superblock);
+ lsm_set_blob_size(&blobs->lbs_task, &blob_sizes.lbs_task);
+ lsm_set_blob_size(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
+ lsm_set_blob_size(&blobs->lbs_xattr_count,
+ &blob_sizes.lbs_xattr_count);
+ lsm_set_blob_size(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
+ lsm_set_blob_size(&blobs->lbs_bpf_map, &blob_sizes.lbs_bpf_map);
+ lsm_set_blob_size(&blobs->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog);
+ lsm_set_blob_size(&blobs->lbs_bpf_token, &blob_sizes.lbs_bpf_token);
}
/* Initialize a given LSM, if it is enabled. */
@@ -361,7 +344,7 @@ static void __init ordered_lsm_init(void)
ordered_lsm_parse(builtin_lsm_order, "builtin");
for (lsm = ordered_lsms; *lsm; lsm++)
- prepare_lsm(*lsm);
+ lsm_prepare(*lsm);
report_lsm_order();
@@ -505,7 +488,7 @@ int __init early_security_init(void)
for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
if (!lsm->enabled)
lsm->enabled = &lsm_enabled_true;
- prepare_lsm(lsm);
+ lsm_prepare(lsm);
initialize_lsm(lsm);
}
--
2.51.1.dirty
^ permalink raw reply related
* [PATCH v5 02/34] lsm: split the init code out into lsm_init.c
From: Paul Moore @ 2025-10-17 20:24 UTC (permalink / raw)
To: linux-security-module, linux-integrity, selinux
Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
Mickaël Salaün, Günther Noack, Kees Cook,
Micah Morton, Casey Schaufler, Tetsuo Handa, Nicolas Bouchinet,
Xiu Jianfeng
In-Reply-To: <20251017202456.484010-36-paul@paul-moore.com>
Continue to pull code out of security/security.c to help improve
readability by pulling all of the LSM framework initialization
code out into a new file.
No code changes.
Reviewed-by: Kees Cook <kees@kernel.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
---
include/linux/lsm_hooks.h | 3 +-
security/Makefile | 2 +-
security/lsm.h | 22 ++
security/lsm_init.c | 543 ++++++++++++++++++++++++++++++++++
security/security.c | 597 +++-----------------------------------
5 files changed, 601 insertions(+), 566 deletions(-)
create mode 100644 security/lsm.h
create mode 100644 security/lsm_init.c
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 79ec5a2bdcca..0112926ed923 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -170,11 +170,10 @@ struct lsm_info {
__used __section(".early_lsm_info.init") \
__aligned(sizeof(unsigned long))
+
/* DO NOT tamper with these variables outside of the LSM framework */
extern char *lsm_names;
extern struct lsm_static_calls_table static_calls_table __ro_after_init;
-extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
-extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
/**
* lsm_get_xattr_slot - Return the next available slot and increment the index
diff --git a/security/Makefile b/security/Makefile
index 14d87847bce8..4601230ba442 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_SECURITY) += lsm_syscalls.o
obj-$(CONFIG_MMU) += min_addr.o
# Object file lists
-obj-$(CONFIG_SECURITY) += security.o lsm_notifier.o
+obj-$(CONFIG_SECURITY) += security.o lsm_notifier.o lsm_init.o
obj-$(CONFIG_SECURITYFS) += inode.o
obj-$(CONFIG_SECURITY_SELINUX) += selinux/
obj-$(CONFIG_SECURITY_SMACK) += smack/
diff --git a/security/lsm.h b/security/lsm.h
new file mode 100644
index 000000000000..0e1731bad4a7
--- /dev/null
+++ b/security/lsm.h
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * LSM functions
+ */
+
+#ifndef _LSM_H_
+#define _LSM_H_
+
+#include <linux/lsm_hooks.h>
+
+/* LSM blob configuration */
+extern struct lsm_blob_sizes blob_sizes;
+
+/* LSM blob caches */
+extern struct kmem_cache *lsm_file_cache;
+extern struct kmem_cache *lsm_inode_cache;
+
+/* LSM blob allocators */
+int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
+int lsm_task_alloc(struct task_struct *task);
+
+#endif /* _LSM_H_ */
diff --git a/security/lsm_init.c b/security/lsm_init.c
new file mode 100644
index 000000000000..124213b906af
--- /dev/null
+++ b/security/lsm_init.c
@@ -0,0 +1,543 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * LSM initialization functions
+ */
+
+#define pr_fmt(fmt) "LSM: " fmt
+
+#include <linux/init.h>
+#include <linux/lsm_hooks.h>
+
+#include "lsm.h"
+
+char *lsm_names;
+
+/* Pointers to LSM sections defined in include/asm-generic/vmlinux.lds.h */
+extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
+extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
+
+/* Boot-time LSM user choice */
+static __initconst const char *const builtin_lsm_order = CONFIG_LSM;
+static __initdata const char *chosen_lsm_order;
+static __initdata const char *chosen_major_lsm;
+
+/* Ordered list of LSMs to initialize. */
+static __initdata struct lsm_info *ordered_lsms[MAX_LSM_COUNT + 1];
+static __initdata struct lsm_info *exclusive;
+
+static __initdata bool debug;
+#define init_debug(...) \
+ do { \
+ if (debug) \
+ pr_info(__VA_ARGS__); \
+ } while (0)
+
+static int lsm_append(const char *new, char **result);
+
+/* Save user chosen LSM */
+static int __init choose_major_lsm(char *str)
+{
+ chosen_major_lsm = str;
+ return 1;
+}
+__setup("security=", choose_major_lsm);
+
+/* Explicitly choose LSM initialization order. */
+static int __init choose_lsm_order(char *str)
+{
+ chosen_lsm_order = str;
+ return 1;
+}
+__setup("lsm=", choose_lsm_order);
+
+/* Enable LSM order debugging. */
+static int __init enable_debug(char *str)
+{
+ debug = true;
+ return 1;
+}
+__setup("lsm.debug", enable_debug);
+
+/* Mark an LSM's enabled flag. */
+static int lsm_enabled_true __initdata = 1;
+static int lsm_enabled_false __initdata = 0;
+static void __init set_enabled(struct lsm_info *lsm, bool enabled)
+{
+ /*
+ * When an LSM hasn't configured an enable variable, we can use
+ * a hard-coded location for storing the default enabled state.
+ */
+ if (!lsm->enabled) {
+ if (enabled)
+ lsm->enabled = &lsm_enabled_true;
+ else
+ lsm->enabled = &lsm_enabled_false;
+ } else if (lsm->enabled == &lsm_enabled_true) {
+ if (!enabled)
+ lsm->enabled = &lsm_enabled_false;
+ } else if (lsm->enabled == &lsm_enabled_false) {
+ if (enabled)
+ lsm->enabled = &lsm_enabled_true;
+ } else {
+ *lsm->enabled = enabled;
+ }
+}
+
+static inline bool is_enabled(struct lsm_info *lsm)
+{
+ if (!lsm->enabled)
+ return false;
+
+ return *lsm->enabled;
+}
+
+/* Is an LSM already listed in the ordered LSMs list? */
+static bool __init exists_ordered_lsm(struct lsm_info *lsm)
+{
+ struct lsm_info **check;
+
+ for (check = ordered_lsms; *check; check++)
+ if (*check == lsm)
+ return true;
+
+ return false;
+}
+
+/* Append an LSM to the list of ordered LSMs to initialize. */
+static int last_lsm __initdata;
+static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
+{
+ /* Ignore duplicate selections. */
+ if (exists_ordered_lsm(lsm))
+ return;
+
+ if (WARN(last_lsm == MAX_LSM_COUNT, "%s: out of LSM static calls!?\n", from))
+ return;
+
+ /* Enable this LSM, if it is not already set. */
+ if (!lsm->enabled)
+ lsm->enabled = &lsm_enabled_true;
+ ordered_lsms[last_lsm++] = lsm;
+
+ init_debug("%s ordered: %s (%s)\n", from, lsm->name,
+ is_enabled(lsm) ? "enabled" : "disabled");
+}
+
+/* Is an LSM allowed to be initialized? */
+static bool __init lsm_allowed(struct lsm_info *lsm)
+{
+ /* Skip if the LSM is disabled. */
+ if (!is_enabled(lsm))
+ return false;
+
+ /* Not allowed if another exclusive LSM already initialized. */
+ if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
+ init_debug("exclusive disabled: %s\n", lsm->name);
+ return false;
+ }
+
+ return true;
+}
+
+static void __init lsm_set_blob_size(int *need, int *lbs)
+{
+ int offset;
+
+ if (*need <= 0)
+ return;
+
+ offset = ALIGN(*lbs, sizeof(void *));
+ *lbs = offset + *need;
+ *need = offset;
+}
+
+static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
+{
+ if (!needed)
+ return;
+
+ lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
+ lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
+ lsm_set_blob_size(&needed->lbs_ib, &blob_sizes.lbs_ib);
+ /*
+ * The inode blob gets an rcu_head in addition to
+ * what the modules might need.
+ */
+ if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
+ blob_sizes.lbs_inode = sizeof(struct rcu_head);
+ lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
+ lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
+ lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
+ lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
+ lsm_set_blob_size(&needed->lbs_perf_event, &blob_sizes.lbs_perf_event);
+ lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
+ lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
+ lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
+ lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
+ lsm_set_blob_size(&needed->lbs_xattr_count,
+ &blob_sizes.lbs_xattr_count);
+ lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
+ lsm_set_blob_size(&needed->lbs_bpf_map, &blob_sizes.lbs_bpf_map);
+ lsm_set_blob_size(&needed->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog);
+ lsm_set_blob_size(&needed->lbs_bpf_token, &blob_sizes.lbs_bpf_token);
+}
+
+/* Prepare LSM for initialization. */
+static void __init prepare_lsm(struct lsm_info *lsm)
+{
+ int enabled = lsm_allowed(lsm);
+
+ /* Record enablement (to handle any following exclusive LSMs). */
+ set_enabled(lsm, enabled);
+
+ /* If enabled, do pre-initialization work. */
+ if (enabled) {
+ if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
+ exclusive = lsm;
+ init_debug("exclusive chosen: %s\n", lsm->name);
+ }
+
+ lsm_set_blob_sizes(lsm->blobs);
+ }
+}
+
+/* Initialize a given LSM, if it is enabled. */
+static void __init initialize_lsm(struct lsm_info *lsm)
+{
+ if (is_enabled(lsm)) {
+ int ret;
+
+ init_debug("initializing %s\n", lsm->name);
+ ret = lsm->init();
+ WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
+ }
+}
+
+/*
+ * Current index to use while initializing the lsm id list.
+ */
+u32 lsm_active_cnt __ro_after_init;
+const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
+
+/* Populate ordered LSMs list from comma-separated LSM name list. */
+static void __init ordered_lsm_parse(const char *order, const char *origin)
+{
+ struct lsm_info *lsm;
+ char *sep, *name, *next;
+
+ /* LSM_ORDER_FIRST is always first. */
+ for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ if (lsm->order == LSM_ORDER_FIRST)
+ append_ordered_lsm(lsm, " first");
+ }
+
+ /* Process "security=", if given. */
+ if (chosen_major_lsm) {
+ struct lsm_info *major;
+
+ /*
+ * To match the original "security=" behavior, this
+ * explicitly does NOT fallback to another Legacy Major
+ * if the selected one was separately disabled: disable
+ * all non-matching Legacy Major LSMs.
+ */
+ for (major = __start_lsm_info; major < __end_lsm_info;
+ major++) {
+ if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
+ strcmp(major->name, chosen_major_lsm) != 0) {
+ set_enabled(major, false);
+ init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
+ chosen_major_lsm, major->name);
+ }
+ }
+ }
+
+ sep = kstrdup(order, GFP_KERNEL);
+ next = sep;
+ /* Walk the list, looking for matching LSMs. */
+ while ((name = strsep(&next, ",")) != NULL) {
+ bool found = false;
+
+ for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ if (strcmp(lsm->name, name) == 0) {
+ if (lsm->order == LSM_ORDER_MUTABLE)
+ append_ordered_lsm(lsm, origin);
+ found = true;
+ }
+ }
+
+ if (!found)
+ init_debug("%s ignored: %s (not built into kernel)\n",
+ origin, name);
+ }
+
+ /* Process "security=", if given. */
+ if (chosen_major_lsm) {
+ for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ if (exists_ordered_lsm(lsm))
+ continue;
+ if (strcmp(lsm->name, chosen_major_lsm) == 0)
+ append_ordered_lsm(lsm, "security=");
+ }
+ }
+
+ /* LSM_ORDER_LAST is always last. */
+ for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ if (lsm->order == LSM_ORDER_LAST)
+ append_ordered_lsm(lsm, " last");
+ }
+
+ /* Disable all LSMs not in the ordered list. */
+ for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ if (exists_ordered_lsm(lsm))
+ continue;
+ set_enabled(lsm, false);
+ init_debug("%s skipped: %s (not in requested order)\n",
+ origin, lsm->name);
+ }
+
+ kfree(sep);
+}
+
+static void __init report_lsm_order(void)
+{
+ struct lsm_info **lsm, *early;
+ int first = 0;
+
+ pr_info("initializing lsm=");
+
+ /* Report each enabled LSM name, comma separated. */
+ for (early = __start_early_lsm_info;
+ early < __end_early_lsm_info; early++)
+ if (is_enabled(early))
+ pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
+ for (lsm = ordered_lsms; *lsm; lsm++)
+ if (is_enabled(*lsm))
+ pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
+
+ pr_cont("\n");
+}
+
+/**
+ * lsm_early_cred - during initialization allocate a composite cred blob
+ * @cred: the cred that needs a blob
+ *
+ * Allocate the cred blob for all the modules
+ */
+static void __init lsm_early_cred(struct cred *cred)
+{
+ int rc = lsm_cred_alloc(cred, GFP_KERNEL);
+
+ if (rc)
+ panic("%s: Early cred alloc failed.\n", __func__);
+}
+
+/**
+ * lsm_early_task - during initialization allocate a composite task blob
+ * @task: the task that needs a blob
+ *
+ * Allocate the task blob for all the modules
+ */
+static void __init lsm_early_task(struct task_struct *task)
+{
+ int rc = lsm_task_alloc(task);
+
+ if (rc)
+ panic("%s: Early task alloc failed.\n", __func__);
+}
+
+static void __init ordered_lsm_init(void)
+{
+ struct lsm_info **lsm;
+
+ if (chosen_lsm_order) {
+ if (chosen_major_lsm) {
+ pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
+ chosen_major_lsm, chosen_lsm_order);
+ chosen_major_lsm = NULL;
+ }
+ ordered_lsm_parse(chosen_lsm_order, "cmdline");
+ } else
+ ordered_lsm_parse(builtin_lsm_order, "builtin");
+
+ for (lsm = ordered_lsms; *lsm; lsm++)
+ prepare_lsm(*lsm);
+
+ report_lsm_order();
+
+ init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
+ init_debug("file blob size = %d\n", blob_sizes.lbs_file);
+ init_debug("ib blob size = %d\n", blob_sizes.lbs_ib);
+ init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
+ init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc);
+#ifdef CONFIG_KEYS
+ init_debug("key blob size = %d\n", blob_sizes.lbs_key);
+#endif /* CONFIG_KEYS */
+ init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
+ init_debug("sock blob size = %d\n", blob_sizes.lbs_sock);
+ init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
+ init_debug("perf event blob size = %d\n", blob_sizes.lbs_perf_event);
+ init_debug("task blob size = %d\n", blob_sizes.lbs_task);
+ init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev);
+ init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count);
+ init_debug("bdev blob size = %d\n", blob_sizes.lbs_bdev);
+ init_debug("bpf map blob size = %d\n", blob_sizes.lbs_bpf_map);
+ init_debug("bpf prog blob size = %d\n", blob_sizes.lbs_bpf_prog);
+ init_debug("bpf token blob size = %d\n", blob_sizes.lbs_bpf_token);
+
+ /*
+ * Create any kmem_caches needed for blobs
+ */
+ if (blob_sizes.lbs_file)
+ lsm_file_cache = kmem_cache_create("lsm_file_cache",
+ blob_sizes.lbs_file, 0,
+ SLAB_PANIC, NULL);
+ if (blob_sizes.lbs_inode)
+ lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
+ blob_sizes.lbs_inode, 0,
+ SLAB_PANIC, NULL);
+
+ lsm_early_cred((struct cred *) current->cred);
+ lsm_early_task(current);
+ for (lsm = ordered_lsms; *lsm; lsm++)
+ initialize_lsm(*lsm);
+}
+
+static bool match_last_lsm(const char *list, const char *lsm)
+{
+ const char *last;
+
+ if (WARN_ON(!list || !lsm))
+ return false;
+ last = strrchr(list, ',');
+ if (last)
+ /* Pass the comma, strcmp() will check for '\0' */
+ last++;
+ else
+ last = list;
+ return !strcmp(last, lsm);
+}
+
+static int lsm_append(const char *new, char **result)
+{
+ char *cp;
+
+ if (*result == NULL) {
+ *result = kstrdup(new, GFP_KERNEL);
+ if (*result == NULL)
+ return -ENOMEM;
+ } else {
+ /* Check if it is the last registered name */
+ if (match_last_lsm(*result, new))
+ return 0;
+ cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
+ if (cp == NULL)
+ return -ENOMEM;
+ kfree(*result);
+ *result = cp;
+ }
+ return 0;
+}
+
+static void __init lsm_static_call_init(struct security_hook_list *hl)
+{
+ struct lsm_static_call *scall = hl->scalls;
+ int i;
+
+ for (i = 0; i < MAX_LSM_COUNT; i++) {
+ /* Update the first static call that is not used yet */
+ if (!scall->hl) {
+ __static_call_update(scall->key, scall->trampoline,
+ hl->hook.lsm_func_addr);
+ scall->hl = hl;
+ static_branch_enable(scall->active);
+ return;
+ }
+ scall++;
+ }
+ panic("%s - Ran out of static slots.\n", __func__);
+}
+
+/**
+ * security_add_hooks - Add a modules hooks to the hook lists.
+ * @hooks: the hooks to add
+ * @count: the number of hooks to add
+ * @lsmid: the identification information for the security module
+ *
+ * Each LSM has to register its hooks with the infrastructure.
+ */
+void __init security_add_hooks(struct security_hook_list *hooks, int count,
+ const struct lsm_id *lsmid)
+{
+ int i;
+
+ /*
+ * A security module may call security_add_hooks() more
+ * than once during initialization, and LSM initialization
+ * is serialized. Landlock is one such case.
+ * Look at the previous entry, if there is one, for duplication.
+ */
+ if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) {
+ if (lsm_active_cnt >= MAX_LSM_COUNT)
+ panic("%s Too many LSMs registered.\n", __func__);
+ lsm_idlist[lsm_active_cnt++] = lsmid;
+ }
+
+ for (i = 0; i < count; i++) {
+ hooks[i].lsmid = lsmid;
+ lsm_static_call_init(&hooks[i]);
+ }
+
+ /*
+ * Don't try to append during early_security_init(), we'll come back
+ * and fix this up afterwards.
+ */
+ if (slab_is_available()) {
+ if (lsm_append(lsmid->name, &lsm_names) < 0)
+ panic("%s - Cannot get early memory.\n", __func__);
+ }
+}
+
+int __init early_security_init(void)
+{
+ struct lsm_info *lsm;
+
+ for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
+ if (!lsm->enabled)
+ lsm->enabled = &lsm_enabled_true;
+ prepare_lsm(lsm);
+ initialize_lsm(lsm);
+ }
+
+ return 0;
+}
+
+/**
+ * security_init - initializes the security framework
+ *
+ * This should be called early in the kernel initialization sequence.
+ */
+int __init security_init(void)
+{
+ struct lsm_info *lsm;
+
+ init_debug("legacy security=%s\n", chosen_major_lsm ? : " *unspecified*");
+ init_debug(" CONFIG_LSM=%s\n", builtin_lsm_order);
+ init_debug("boot arg lsm=%s\n", chosen_lsm_order ? : " *unspecified*");
+
+ /*
+ * Append the names of the early LSM modules now that kmalloc() is
+ * available
+ */
+ for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
+ init_debug(" early started: %s (%s)\n", lsm->name,
+ is_enabled(lsm) ? "enabled" : "disabled");
+ if (lsm->enabled)
+ lsm_append(lsm->name, &lsm_names);
+ }
+
+ /* Load LSMs in specified order. */
+ ordered_lsm_init();
+
+ return 0;
+}
diff --git a/security/security.c b/security/security.c
index 667479c2e82f..dc9734f0d45c 100644
--- a/security/security.c
+++ b/security/security.c
@@ -32,24 +32,7 @@
#include <net/flow.h>
#include <net/sock.h>
-#define SECURITY_HOOK_ACTIVE_KEY(HOOK, IDX) security_hook_active_##HOOK##_##IDX
-
-/*
- * Identifier for the LSM static calls.
- * HOOK is an LSM hook as defined in linux/lsm_hookdefs.h
- * IDX is the index of the static call. 0 <= NUM < MAX_LSM_COUNT
- */
-#define LSM_STATIC_CALL(HOOK, IDX) lsm_static_call_##HOOK##_##IDX
-
-/*
- * Call the macro M for each LSM hook MAX_LSM_COUNT times.
- */
-#define LSM_LOOP_UNROLL(M, ...) \
-do { \
- UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__) \
-} while (0)
-
-#define LSM_DEFINE_UNROLL(M, ...) UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)
+#include "lsm.h"
/*
* These are descriptions of the reasons that can be passed to the
@@ -90,21 +73,29 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
};
-static struct kmem_cache *lsm_file_cache;
-static struct kmem_cache *lsm_inode_cache;
+struct lsm_blob_sizes blob_sizes;
-char *lsm_names;
-static struct lsm_blob_sizes blob_sizes __ro_after_init;
+struct kmem_cache *lsm_file_cache;
+struct kmem_cache *lsm_inode_cache;
-/* Boot-time LSM user choice */
-static __initdata const char *chosen_lsm_order;
-static __initdata const char *chosen_major_lsm;
+#define SECURITY_HOOK_ACTIVE_KEY(HOOK, IDX) security_hook_active_##HOOK##_##IDX
-static __initconst const char *const builtin_lsm_order = CONFIG_LSM;
+/*
+ * Identifier for the LSM static calls.
+ * HOOK is an LSM hook as defined in linux/lsm_hookdefs.h
+ * IDX is the index of the static call. 0 <= NUM < MAX_LSM_COUNT
+ */
+#define LSM_STATIC_CALL(HOOK, IDX) lsm_static_call_##HOOK##_##IDX
-/* Ordered list of LSMs to initialize. */
-static __initdata struct lsm_info *ordered_lsms[MAX_LSM_COUNT + 1];
-static __initdata struct lsm_info *exclusive;
+/*
+ * Call the macro M for each LSM hook MAX_LSM_COUNT times.
+ */
+#define LSM_LOOP_UNROLL(M, ...) \
+do { \
+ UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__) \
+} while (0)
+
+#define LSM_DEFINE_UNROLL(M, ...) UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)
#ifdef CONFIG_HAVE_STATIC_CALL
#define LSM_HOOK_TRAMP(NAME, NUM) \
@@ -155,496 +146,25 @@ struct lsm_static_calls_table
#undef INIT_LSM_STATIC_CALL
};
-static __initdata bool debug;
-#define init_debug(...) \
- do { \
- if (debug) \
- pr_info(__VA_ARGS__); \
- } while (0)
-
-static bool __init is_enabled(struct lsm_info *lsm)
-{
- if (!lsm->enabled)
- return false;
-
- return *lsm->enabled;
-}
-
-/* Mark an LSM's enabled flag. */
-static int lsm_enabled_true __initdata = 1;
-static int lsm_enabled_false __initdata = 0;
-static void __init set_enabled(struct lsm_info *lsm, bool enabled)
-{
- /*
- * When an LSM hasn't configured an enable variable, we can use
- * a hard-coded location for storing the default enabled state.
- */
- if (!lsm->enabled) {
- if (enabled)
- lsm->enabled = &lsm_enabled_true;
- else
- lsm->enabled = &lsm_enabled_false;
- } else if (lsm->enabled == &lsm_enabled_true) {
- if (!enabled)
- lsm->enabled = &lsm_enabled_false;
- } else if (lsm->enabled == &lsm_enabled_false) {
- if (enabled)
- lsm->enabled = &lsm_enabled_true;
- } else {
- *lsm->enabled = enabled;
- }
-}
-
-/* Is an LSM already listed in the ordered LSMs list? */
-static bool __init exists_ordered_lsm(struct lsm_info *lsm)
-{
- struct lsm_info **check;
-
- for (check = ordered_lsms; *check; check++)
- if (*check == lsm)
- return true;
-
- return false;
-}
-
-/* Append an LSM to the list of ordered LSMs to initialize. */
-static int last_lsm __initdata;
-static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
-{
- /* Ignore duplicate selections. */
- if (exists_ordered_lsm(lsm))
- return;
-
- if (WARN(last_lsm == MAX_LSM_COUNT, "%s: out of LSM static calls!?\n", from))
- return;
-
- /* Enable this LSM, if it is not already set. */
- if (!lsm->enabled)
- lsm->enabled = &lsm_enabled_true;
- ordered_lsms[last_lsm++] = lsm;
-
- init_debug("%s ordered: %s (%s)\n", from, lsm->name,
- is_enabled(lsm) ? "enabled" : "disabled");
-}
-
-/* Is an LSM allowed to be initialized? */
-static bool __init lsm_allowed(struct lsm_info *lsm)
-{
- /* Skip if the LSM is disabled. */
- if (!is_enabled(lsm))
- return false;
-
- /* Not allowed if another exclusive LSM already initialized. */
- if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
- init_debug("exclusive disabled: %s\n", lsm->name);
- return false;
- }
-
- return true;
-}
-
-static void __init lsm_set_blob_size(int *need, int *lbs)
-{
- int offset;
-
- if (*need <= 0)
- return;
-
- offset = ALIGN(*lbs, sizeof(void *));
- *lbs = offset + *need;
- *need = offset;
-}
-
-static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
-{
- if (!needed)
- return;
-
- lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
- lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
- lsm_set_blob_size(&needed->lbs_ib, &blob_sizes.lbs_ib);
- /*
- * The inode blob gets an rcu_head in addition to
- * what the modules might need.
- */
- if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
- blob_sizes.lbs_inode = sizeof(struct rcu_head);
- lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
- lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
- lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
- lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
- lsm_set_blob_size(&needed->lbs_perf_event, &blob_sizes.lbs_perf_event);
- lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
- lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
- lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
- lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
- lsm_set_blob_size(&needed->lbs_xattr_count,
- &blob_sizes.lbs_xattr_count);
- lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
- lsm_set_blob_size(&needed->lbs_bpf_map, &blob_sizes.lbs_bpf_map);
- lsm_set_blob_size(&needed->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog);
- lsm_set_blob_size(&needed->lbs_bpf_token, &blob_sizes.lbs_bpf_token);
-}
-
-/* Prepare LSM for initialization. */
-static void __init prepare_lsm(struct lsm_info *lsm)
-{
- int enabled = lsm_allowed(lsm);
-
- /* Record enablement (to handle any following exclusive LSMs). */
- set_enabled(lsm, enabled);
-
- /* If enabled, do pre-initialization work. */
- if (enabled) {
- if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
- exclusive = lsm;
- init_debug("exclusive chosen: %s\n", lsm->name);
- }
-
- lsm_set_blob_sizes(lsm->blobs);
- }
-}
-
-/* Initialize a given LSM, if it is enabled. */
-static void __init initialize_lsm(struct lsm_info *lsm)
-{
- if (is_enabled(lsm)) {
- int ret;
-
- init_debug("initializing %s\n", lsm->name);
- ret = lsm->init();
- WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
- }
-}
-
-/*
- * Current index to use while initializing the lsm id list.
- */
-u32 lsm_active_cnt __ro_after_init;
-const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
-
-/* Populate ordered LSMs list from comma-separated LSM name list. */
-static void __init ordered_lsm_parse(const char *order, const char *origin)
-{
- struct lsm_info *lsm;
- char *sep, *name, *next;
-
- /* LSM_ORDER_FIRST is always first. */
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
- if (lsm->order == LSM_ORDER_FIRST)
- append_ordered_lsm(lsm, " first");
- }
-
- /* Process "security=", if given. */
- if (chosen_major_lsm) {
- struct lsm_info *major;
-
- /*
- * To match the original "security=" behavior, this
- * explicitly does NOT fallback to another Legacy Major
- * if the selected one was separately disabled: disable
- * all non-matching Legacy Major LSMs.
- */
- for (major = __start_lsm_info; major < __end_lsm_info;
- major++) {
- if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
- strcmp(major->name, chosen_major_lsm) != 0) {
- set_enabled(major, false);
- init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
- chosen_major_lsm, major->name);
- }
- }
- }
-
- sep = kstrdup(order, GFP_KERNEL);
- next = sep;
- /* Walk the list, looking for matching LSMs. */
- while ((name = strsep(&next, ",")) != NULL) {
- bool found = false;
-
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
- if (strcmp(lsm->name, name) == 0) {
- if (lsm->order == LSM_ORDER_MUTABLE)
- append_ordered_lsm(lsm, origin);
- found = true;
- }
- }
-
- if (!found)
- init_debug("%s ignored: %s (not built into kernel)\n",
- origin, name);
- }
-
- /* Process "security=", if given. */
- if (chosen_major_lsm) {
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
- if (exists_ordered_lsm(lsm))
- continue;
- if (strcmp(lsm->name, chosen_major_lsm) == 0)
- append_ordered_lsm(lsm, "security=");
- }
- }
-
- /* LSM_ORDER_LAST is always last. */
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
- if (lsm->order == LSM_ORDER_LAST)
- append_ordered_lsm(lsm, " last");
- }
-
- /* Disable all LSMs not in the ordered list. */
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
- if (exists_ordered_lsm(lsm))
- continue;
- set_enabled(lsm, false);
- init_debug("%s skipped: %s (not in requested order)\n",
- origin, lsm->name);
- }
-
- kfree(sep);
-}
-
-static void __init lsm_static_call_init(struct security_hook_list *hl)
-{
- struct lsm_static_call *scall = hl->scalls;
- int i;
-
- for (i = 0; i < MAX_LSM_COUNT; i++) {
- /* Update the first static call that is not used yet */
- if (!scall->hl) {
- __static_call_update(scall->key, scall->trampoline,
- hl->hook.lsm_func_addr);
- scall->hl = hl;
- static_branch_enable(scall->active);
- return;
- }
- scall++;
- }
- panic("%s - Ran out of static slots.\n", __func__);
-}
-
-static void __init lsm_early_cred(struct cred *cred);
-static void __init lsm_early_task(struct task_struct *task);
-
-static int lsm_append(const char *new, char **result);
-
-static void __init report_lsm_order(void)
-{
- struct lsm_info **lsm, *early;
- int first = 0;
-
- pr_info("initializing lsm=");
-
- /* Report each enabled LSM name, comma separated. */
- for (early = __start_early_lsm_info;
- early < __end_early_lsm_info; early++)
- if (is_enabled(early))
- pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
- for (lsm = ordered_lsms; *lsm; lsm++)
- if (is_enabled(*lsm))
- pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
-
- pr_cont("\n");
-}
-
-static void __init ordered_lsm_init(void)
-{
- struct lsm_info **lsm;
-
- if (chosen_lsm_order) {
- if (chosen_major_lsm) {
- pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
- chosen_major_lsm, chosen_lsm_order);
- chosen_major_lsm = NULL;
- }
- ordered_lsm_parse(chosen_lsm_order, "cmdline");
- } else
- ordered_lsm_parse(builtin_lsm_order, "builtin");
-
- for (lsm = ordered_lsms; *lsm; lsm++)
- prepare_lsm(*lsm);
-
- report_lsm_order();
-
- init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
- init_debug("file blob size = %d\n", blob_sizes.lbs_file);
- init_debug("ib blob size = %d\n", blob_sizes.lbs_ib);
- init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
- init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc);
-#ifdef CONFIG_KEYS
- init_debug("key blob size = %d\n", blob_sizes.lbs_key);
-#endif /* CONFIG_KEYS */
- init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
- init_debug("sock blob size = %d\n", blob_sizes.lbs_sock);
- init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
- init_debug("perf event blob size = %d\n", blob_sizes.lbs_perf_event);
- init_debug("task blob size = %d\n", blob_sizes.lbs_task);
- init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev);
- init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count);
- init_debug("bdev blob size = %d\n", blob_sizes.lbs_bdev);
- init_debug("bpf map blob size = %d\n", blob_sizes.lbs_bpf_map);
- init_debug("bpf prog blob size = %d\n", blob_sizes.lbs_bpf_prog);
- init_debug("bpf token blob size = %d\n", blob_sizes.lbs_bpf_token);
-
- /*
- * Create any kmem_caches needed for blobs
- */
- if (blob_sizes.lbs_file)
- lsm_file_cache = kmem_cache_create("lsm_file_cache",
- blob_sizes.lbs_file, 0,
- SLAB_PANIC, NULL);
- if (blob_sizes.lbs_inode)
- lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
- blob_sizes.lbs_inode, 0,
- SLAB_PANIC, NULL);
-
- lsm_early_cred((struct cred *) current->cred);
- lsm_early_task(current);
- for (lsm = ordered_lsms; *lsm; lsm++)
- initialize_lsm(*lsm);
-}
-
-int __init early_security_init(void)
-{
- struct lsm_info *lsm;
-
- for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
- if (!lsm->enabled)
- lsm->enabled = &lsm_enabled_true;
- prepare_lsm(lsm);
- initialize_lsm(lsm);
- }
-
- return 0;
-}
-
/**
- * security_init - initializes the security framework
+ * lsm_file_alloc - allocate a composite file blob
+ * @file: the file that needs a blob
*
- * This should be called early in the kernel initialization sequence.
- */
-int __init security_init(void)
-{
- struct lsm_info *lsm;
-
- init_debug("legacy security=%s\n", chosen_major_lsm ? : " *unspecified*");
- init_debug(" CONFIG_LSM=%s\n", builtin_lsm_order);
- init_debug("boot arg lsm=%s\n", chosen_lsm_order ? : " *unspecified*");
-
- /*
- * Append the names of the early LSM modules now that kmalloc() is
- * available
- */
- for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
- init_debug(" early started: %s (%s)\n", lsm->name,
- is_enabled(lsm) ? "enabled" : "disabled");
- if (lsm->enabled)
- lsm_append(lsm->name, &lsm_names);
- }
-
- /* Load LSMs in specified order. */
- ordered_lsm_init();
-
- return 0;
-}
-
-/* Save user chosen LSM */
-static int __init choose_major_lsm(char *str)
-{
- chosen_major_lsm = str;
- return 1;
-}
-__setup("security=", choose_major_lsm);
-
-/* Explicitly choose LSM initialization order. */
-static int __init choose_lsm_order(char *str)
-{
- chosen_lsm_order = str;
- return 1;
-}
-__setup("lsm=", choose_lsm_order);
-
-/* Enable LSM order debugging. */
-static int __init enable_debug(char *str)
-{
- debug = true;
- return 1;
-}
-__setup("lsm.debug", enable_debug);
-
-static bool match_last_lsm(const char *list, const char *lsm)
-{
- const char *last;
-
- if (WARN_ON(!list || !lsm))
- return false;
- last = strrchr(list, ',');
- if (last)
- /* Pass the comma, strcmp() will check for '\0' */
- last++;
- else
- last = list;
- return !strcmp(last, lsm);
-}
-
-static int lsm_append(const char *new, char **result)
-{
- char *cp;
-
- if (*result == NULL) {
- *result = kstrdup(new, GFP_KERNEL);
- if (*result == NULL)
- return -ENOMEM;
- } else {
- /* Check if it is the last registered name */
- if (match_last_lsm(*result, new))
- return 0;
- cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
- if (cp == NULL)
- return -ENOMEM;
- kfree(*result);
- *result = cp;
- }
- return 0;
-}
-
-/**
- * security_add_hooks - Add a modules hooks to the hook lists.
- * @hooks: the hooks to add
- * @count: the number of hooks to add
- * @lsmid: the identification information for the security module
+ * Allocate the file blob for all the modules
*
- * Each LSM has to register its hooks with the infrastructure.
+ * Returns 0, or -ENOMEM if memory can't be allocated.
*/
-void __init security_add_hooks(struct security_hook_list *hooks, int count,
- const struct lsm_id *lsmid)
+static int lsm_file_alloc(struct file *file)
{
- int i;
-
- /*
- * A security module may call security_add_hooks() more
- * than once during initialization, and LSM initialization
- * is serialized. Landlock is one such case.
- * Look at the previous entry, if there is one, for duplication.
- */
- if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) {
- if (lsm_active_cnt >= MAX_LSM_COUNT)
- panic("%s Too many LSMs registered.\n", __func__);
- lsm_idlist[lsm_active_cnt++] = lsmid;
+ if (!lsm_file_cache) {
+ file->f_security = NULL;
+ return 0;
}
- for (i = 0; i < count; i++) {
- hooks[i].lsmid = lsmid;
- lsm_static_call_init(&hooks[i]);
- }
-
- /*
- * Don't try to append during early_security_init(), we'll come back
- * and fix this up afterwards.
- */
- if (slab_is_available()) {
- if (lsm_append(lsmid->name, &lsm_names) < 0)
- panic("%s - Cannot get early memory.\n", __func__);
- }
+ file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
+ if (file->f_security == NULL)
+ return -ENOMEM;
+ return 0;
}
/**
@@ -679,46 +199,11 @@ static int lsm_blob_alloc(void **dest, size_t size, gfp_t gfp)
*
* Returns 0, or -ENOMEM if memory can't be allocated.
*/
-static int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
+int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
{
return lsm_blob_alloc(&cred->security, blob_sizes.lbs_cred, gfp);
}
-/**
- * lsm_early_cred - during initialization allocate a composite cred blob
- * @cred: the cred that needs a blob
- *
- * Allocate the cred blob for all the modules
- */
-static void __init lsm_early_cred(struct cred *cred)
-{
- int rc = lsm_cred_alloc(cred, GFP_KERNEL);
-
- if (rc)
- panic("%s: Early cred alloc failed.\n", __func__);
-}
-
-/**
- * lsm_file_alloc - allocate a composite file blob
- * @file: the file that needs a blob
- *
- * Allocate the file blob for all the modules
- *
- * Returns 0, or -ENOMEM if memory can't be allocated.
- */
-static int lsm_file_alloc(struct file *file)
-{
- if (!lsm_file_cache) {
- file->f_security = NULL;
- return 0;
- }
-
- file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
- if (file->f_security == NULL)
- return -ENOMEM;
- return 0;
-}
-
/**
* lsm_inode_alloc - allocate a composite inode blob
* @inode: the inode that needs a blob
@@ -749,7 +234,7 @@ static int lsm_inode_alloc(struct inode *inode, gfp_t gfp)
*
* Returns 0, or -ENOMEM if memory can't be allocated.
*/
-static int lsm_task_alloc(struct task_struct *task)
+int lsm_task_alloc(struct task_struct *task)
{
return lsm_blob_alloc(&task->security, blob_sizes.lbs_task, GFP_KERNEL);
}
@@ -851,20 +336,6 @@ static int lsm_bpf_token_alloc(struct bpf_token *token)
}
#endif /* CONFIG_BPF_SYSCALL */
-/**
- * lsm_early_task - during initialization allocate a composite task blob
- * @task: the task that needs a blob
- *
- * Allocate the task blob for all the modules
- */
-static void __init lsm_early_task(struct task_struct *task)
-{
- int rc = lsm_task_alloc(task);
-
- if (rc)
- panic("%s: Early task alloc failed.\n", __func__);
-}
-
/**
* lsm_superblock_alloc - allocate a composite superblock blob
* @sb: the superblock that needs a blob
--
2.51.1.dirty
^ permalink raw reply related
* [PATCH v5 01/34] lsm: split the notifier code out into lsm_notifier.c
From: Paul Moore @ 2025-10-17 20:24 UTC (permalink / raw)
To: linux-security-module, linux-integrity, selinux
Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
Mickaël Salaün, Günther Noack, Kees Cook,
Micah Morton, Casey Schaufler, Tetsuo Handa, Nicolas Bouchinet,
Xiu Jianfeng
In-Reply-To: <20251017202456.484010-36-paul@paul-moore.com>
In an effort to decompose security/security.c somewhat to make it less
twisted and unwieldy, pull out the LSM notifier code into a new file
as it is fairly well self-contained.
No code changes.
Reviewed-by: Kees Cook <kees@kernel.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
---
security/Makefile | 2 +-
security/lsm_notifier.c | 31 +++++++++++++++++++++++++++++++
security/security.c | 23 -----------------------
3 files changed, 32 insertions(+), 24 deletions(-)
create mode 100644 security/lsm_notifier.c
diff --git a/security/Makefile b/security/Makefile
index 22ff4c8bd8ce..14d87847bce8 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_SECURITY) += lsm_syscalls.o
obj-$(CONFIG_MMU) += min_addr.o
# Object file lists
-obj-$(CONFIG_SECURITY) += security.o
+obj-$(CONFIG_SECURITY) += security.o lsm_notifier.o
obj-$(CONFIG_SECURITYFS) += inode.o
obj-$(CONFIG_SECURITY_SELINUX) += selinux/
obj-$(CONFIG_SECURITY_SMACK) += smack/
diff --git a/security/lsm_notifier.c b/security/lsm_notifier.c
new file mode 100644
index 000000000000..c92fad5d57d4
--- /dev/null
+++ b/security/lsm_notifier.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * LSM notifier functions
+ *
+ */
+
+#include <linux/notifier.h>
+#include <linux/security.h>
+
+static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain);
+
+int call_blocking_lsm_notifier(enum lsm_event event, void *data)
+{
+ return blocking_notifier_call_chain(&blocking_lsm_notifier_chain,
+ event, data);
+}
+EXPORT_SYMBOL(call_blocking_lsm_notifier);
+
+int register_blocking_lsm_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&blocking_lsm_notifier_chain,
+ nb);
+}
+EXPORT_SYMBOL(register_blocking_lsm_notifier);
+
+int unregister_blocking_lsm_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&blocking_lsm_notifier_chain,
+ nb);
+}
+EXPORT_SYMBOL(unregister_blocking_lsm_notifier);
diff --git a/security/security.c b/security/security.c
index 4d3c03a4524c..667479c2e82f 100644
--- a/security/security.c
+++ b/security/security.c
@@ -90,8 +90,6 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
};
-static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain);
-
static struct kmem_cache *lsm_file_cache;
static struct kmem_cache *lsm_inode_cache;
@@ -649,27 +647,6 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
}
}
-int call_blocking_lsm_notifier(enum lsm_event event, void *data)
-{
- return blocking_notifier_call_chain(&blocking_lsm_notifier_chain,
- event, data);
-}
-EXPORT_SYMBOL(call_blocking_lsm_notifier);
-
-int register_blocking_lsm_notifier(struct notifier_block *nb)
-{
- return blocking_notifier_chain_register(&blocking_lsm_notifier_chain,
- nb);
-}
-EXPORT_SYMBOL(register_blocking_lsm_notifier);
-
-int unregister_blocking_lsm_notifier(struct notifier_block *nb)
-{
- return blocking_notifier_chain_unregister(&blocking_lsm_notifier_chain,
- nb);
-}
-EXPORT_SYMBOL(unregister_blocking_lsm_notifier);
-
/**
* lsm_blob_alloc - allocate a composite blob
* @dest: the destination for the blob
--
2.51.1.dirty
^ permalink raw reply related
* [PATCH v5 0/34] Rework the LSM initialization
From: Paul Moore @ 2025-10-17 20:24 UTC (permalink / raw)
To: linux-security-module, linux-integrity, selinux
Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
Mickaël Salaün, Günther Noack, Kees Cook,
Micah Morton, Casey Schaufler, Tetsuo Handa, Nicolas Bouchinet,
Xiu Jianfeng
This is the fifth, and likely final, revision of the LSM rework patchset.
The number of changes in this revision are very minor and barring any
surprises I expect to merge this into the lsm/dev branch next week; I'll
send a notice when I do. While there isn't anything in this revision
that people haven't seen previously, if you do have any concerns or
feedback, please let me know. Once again, thank you to all of you that
have taken the time to review these patches.
I've aldo updated the working-lsm_init_rework branch of the main LSM
tree to contain the latest v5 revision of the patchset:
https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm.git/log/?h=working-lsm_init_rework
The v4 patchset:
https://lore.kernel.org/linux-security-module/20250916220355.252592-36-paul@paul-moore.com/
The RFC/v3 patchset:
https://lore.kernel.org/linux-security-module/20250814225159.275901-36-paul@paul-moore.com/
The RFC/v2 patchset:
https://lore.kernel.org/linux-security-module/20250721232142.77224-36-paul@paul-moore.com/
The RFC/v1 patchset is below, the cover letter provides some background
and motivation for this series which still applies:
https://lore.kernel.org/linux-security-module/20250409185019.238841-31-paul@paul-moore.com/
CHANGELOG
v5:
- rebased to lsm/dev branch post v6.18-rc1
- fixed a !CONFIG_SECURITYFS bug (kernel test robot)
- fixed a missing "__rcu" annotation on a cast (kernel test robot)
v4:
- reworked the lsm_read() function (John, Roberto, Tetsuo)
- replaced the IMA/EVM patch with one from Roberto
RFC/v3:
- rebased to lsm/dev branch
- fixed IMA/EVM initcall comment (Roberto)
- fixed CONFIG_IMA and CONFIG_EVM problems (Nicolas, Roberto)
- fixed CONFIG_SECURITY_SMACK_NETFILTER problems (Roberto)
- fixed the IMA/EVM header file include macro protections
- fixed an off-by-one string length issue in lsm_read() (Casey)
RFC/v2:
- rename lsm_prep_single() to lsm_prepare()
- drop the lsm_prop counting patch
- drop the platform_certs changes from the IMA/EVM patch (Mimi)
- split/reorder anough patches in the patchset that I lost track
- added missing function comment blocks in the SELinux patches
- split patch 04/29 into smaller patches (Kees)
- fix an LSM list output problem in an intermediate patch (Kees)
- preserve the "lsm_active_cnt" variable name (Casey)
- cache the lsm_read() string (Kees)
- squashed, split, and reordered the enabled/ordering patches
- reworked the Smack patch (Casey)
- conditionalized the SELinux IB init code (Stephen)
- fixed missing Smack "__init" annotation (Fan)
- fixed a potential unused variable warning in IMA/EVM (John)
- fixed the placeholder commit descriptions (various)
RFC/v1:
- initial version
--
Paul Moore (33):
lsm: split the notifier code out into lsm_notifier.c
lsm: split the init code out into lsm_init.c
lsm: consolidate lsm_allowed() and prepare_lsm() into
lsm_prepare()
lsm: introduce looping macros for the initialization code
lsm: integrate report_lsm_order() code into caller
lsm: integrate lsm_early_cred() and lsm_early_task() into caller
lsm: rename ordered_lsm_init() to lsm_init_ordered()
lsm: replace the name field with a pointer to the lsm_id struct
lsm: rename the lsm order variables for consistency
lsm: rework lsm_active_cnt and lsm_idlist[]
lsm: get rid of the lsm_names list and do some cleanup
lsm: rework the LSM enable/disable setter/getter functions
lsm: rename exists_ordered_lsm() to lsm_order_exists()
lsm: rename/rework append_ordered_lsm() into lsm_order_append()
lsm: rename/rework ordered_lsm_parse() to lsm_order_parse()
lsm: cleanup the LSM blob size code
lsm: cleanup initialize_lsm() and rename to lsm_init_single()
lsm: fold lsm_init_ordered() into security_init()
lsm: add/tweak function header comment blocks in lsm_init.c
lsm: cleanup the debug and console output in lsm_init.c
lsm: output available LSMs when debugging
lsm: group lsm_order_parse() with the other lsm_order_*()
functions
lsm: introduce an initcall mechanism into the LSM framework
loadpin: move initcalls to the LSM framework
ipe: move initcalls to the LSM framework
smack: move initcalls to the LSM framework
tomoyo: move initcalls to the LSM framework
safesetid: move initcalls to the LSM framework
apparmor: move initcalls to the LSM framework
lockdown: move initcalls to the LSM framework
selinux: move initcalls to the LSM framework
lsm: consolidate all of the LSM framework initcalls
lsm: add a LSM_STARTED_ALL notification event
Roberto Sassu (1):
ima,evm: move initcalls to the LSM framework
include/linux/lsm_hooks.h | 73 +-
include/linux/security.h | 3
security/Makefile | 2
security/apparmor/apparmorfs.c | 4
security/apparmor/crypto.c | 3
security/apparmor/include/apparmorfs.h | 2
security/apparmor/include/crypto.h | 1
security/apparmor/lsm.c | 11
security/bpf/hooks.c | 2
security/commoncap.c | 2
security/inode.c | 46 +
security/integrity/evm/evm_main.c | 5
security/integrity/evm/evm_secfs.c | 11
security/integrity/iint.c | 14
security/integrity/ima/ima_fs.c | 11
security/integrity/ima/ima_main.c | 6
security/integrity/integrity.h | 2
security/ipe/fs.c | 4
security/ipe/ipe.c | 3
security/ipe/ipe.h | 2
security/landlock/setup.c | 2
security/loadpin/loadpin.c | 15
security/lockdown/lockdown.c | 5
security/lsm.h | 58 ++
security/lsm_init.c | 563 ++++++++++++++++++++++
security/lsm_notifier.c | 31 +
security/lsm_syscalls.c | 2
security/min_addr.c | 5
security/safesetid/lsm.c | 3
security/safesetid/lsm.h | 2
security/safesetid/securityfs.c | 3
security/security.c | 623 +------------------------
security/selinux/Makefile | 2
security/selinux/hooks.c | 11
security/selinux/ibpkey.c | 5
security/selinux/include/audit.h | 9
security/selinux/include/initcalls.h | 19
security/selinux/initcalls.c | 52 ++
security/selinux/netif.c | 5
security/selinux/netlink.c | 5
security/selinux/netnode.c | 5
security/selinux/netport.c | 5
security/selinux/selinuxfs.c | 5
security/selinux/ss/services.c | 26 -
security/smack/smack.h | 14
security/smack/smack_lsm.c | 11
security/smack/smack_netfilter.c | 4
security/smack/smackfs.c | 4
security/tomoyo/common.h | 2
security/tomoyo/securityfs_if.c | 4
security/tomoyo/tomoyo.c | 3
security/yama/yama_lsm.c | 2
52 files changed, 1000 insertions(+), 712 deletions(-)
^ permalink raw reply
* Re: [PATCH] docs: trusted-encrypted: fix htmldocs build error
From: Randy Dunlap @ 2025-10-17 19:27 UTC (permalink / raw)
To: Gopi Krishna Menon, zohar, James.Bottomley, jarkko, corbet,
Meenakshi Aggarwal, Pankaj Gupta, Herbert Xu
Cc: linux-integrity, keyrings, linux-doc, linux-kernel, skhan,
david.hunter.linux, linux-kernel-mentees, khalid
In-Reply-To: <20251017181135.354411-1-krishnagopi487@gmail.com>
Adding patch signers.
Fixes: 95c46f40aac4 ("docs: trusted-encrypted: trusted-keys as protected keys")
although that might not matter if this patch is only in a -next tree.
On 10/17/25 11:11 AM, Gopi Krishna Menon wrote:
> Running "make htmldocs" generates the following build error and
> warning in trusted-encrypted.rst:
>
> Documentation/security/keys/trusted-encrypted.rst:18: ERROR: Unexpected indentation.
> Documentation/security/keys/trusted-encrypted.rst:19: WARNING: Block quote ends without a blank line; unexpected unindent.
>
> Add a blank line before bullet list and fix the indentation of text to
> fix the build error and resolve the warning.
>
> Signed-off-by: Gopi Krishna Menon <krishnagopi487@gmail.com>
Reviewed-by: Randy Dunlap <rdunlap@infradead.org>
Tested-by: Randy Dunlap <rdunlap@infradead.org>
> ---
>
> Tested by running "make htmldocs" before and after the change,
> ensuring that output renders correctly in browsers.
>
> Documentation/security/keys/trusted-encrypted.rst | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst
> index 2bcaaa7d119b..eae6a36b1c9a 100644
> --- a/Documentation/security/keys/trusted-encrypted.rst
> +++ b/Documentation/security/keys/trusted-encrypted.rst
> @@ -14,10 +14,11 @@ Trusted Keys as Protected key
> =============================
> It is the secure way of keeping the keys in the kernel key-ring as Trusted-Key,
> such that:
> +
> - Key-blob, an encrypted key-data, created to be stored, loaded and seen by
> - userspace.
> + userspace.
> - Key-data, the plain-key text in the system memory, to be used by
> - kernel space only.
> + kernel space only.
>
> Though key-data is not accessible to the user-space in plain-text, but it is in
> plain-text in system memory, when used in kernel space. Even though kernel-space
--
~Randy
^ permalink raw reply
* [PATCH] docs: trusted-encrypted: fix htmldocs build error
From: Gopi Krishna Menon @ 2025-10-17 18:11 UTC (permalink / raw)
To: zohar, James.Bottomley, jarkko, corbet
Cc: Gopi Krishna Menon, linux-integrity, keyrings, linux-doc,
linux-kernel, skhan, david.hunter.linux, linux-kernel-mentees,
khalid
Running "make htmldocs" generates the following build error and
warning in trusted-encrypted.rst:
Documentation/security/keys/trusted-encrypted.rst:18: ERROR: Unexpected indentation.
Documentation/security/keys/trusted-encrypted.rst:19: WARNING: Block quote ends without a blank line; unexpected unindent.
Add a blank line before bullet list and fix the indentation of text to
fix the build error and resolve the warning.
Signed-off-by: Gopi Krishna Menon <krishnagopi487@gmail.com>
---
Tested by running "make htmldocs" before and after the change,
ensuring that output renders correctly in browsers.
Documentation/security/keys/trusted-encrypted.rst | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst
index 2bcaaa7d119b..eae6a36b1c9a 100644
--- a/Documentation/security/keys/trusted-encrypted.rst
+++ b/Documentation/security/keys/trusted-encrypted.rst
@@ -14,10 +14,11 @@ Trusted Keys as Protected key
=============================
It is the secure way of keeping the keys in the kernel key-ring as Trusted-Key,
such that:
+
- Key-blob, an encrypted key-data, created to be stored, loaded and seen by
- userspace.
+ userspace.
- Key-data, the plain-key text in the system memory, to be used by
- kernel space only.
+ kernel space only.
Though key-data is not accessible to the user-space in plain-text, but it is in
plain-text in system memory, when used in kernel space. Even though kernel-space
--
2.43.0
^ permalink raw reply related
* Re: [PATCH] ima: Fall back to default kernel module signature verification
From: Mimi Zohar @ 2025-10-17 17:49 UTC (permalink / raw)
To: Coiby Xu
Cc: linux-integrity, Dmitry Torokhov, Karel Srot, Roberto Sassu,
Dmitry Kasatkin, Eric Snowberg, Paul Moore, James Morris,
Serge E. Hallyn, open list:SECURITY SUBSYSTEM, open list
In-Reply-To: <5bzredottmp2tdm3uebzjfqjr6c7bwssqkrbdqvudruvzr764e@37j6ycjci2sk>
On Fri, 2025-10-17 at 11:19 +0800, Coiby Xu wrote:
> On Thu, Oct 16, 2025 at 10:31:35PM -0400, Mimi Zohar wrote:
> > On Thu, 2025-10-16 at 11:46 +0800, Coiby Xu wrote:
> > > On Tue, Sep 30, 2025 at 04:28:14PM -0400, Mimi Zohar wrote:
> > > > On Tue, 2025-09-30 at 09:57 -0400, Mimi Zohar wrote:
> > > > > On Sun, 2025-09-28 at 11:03 +0800, Coiby Xu wrote:
> > > > > > Currently, for any IMA policy that requires appraisal for kernel modules
> > > > > > e.g. ima_policy=secure_boot, PowerPC architecture specific policy,
> > > > > > booting will fail because IMA will reject a kernel module which will
> > > > > > be decompressed in the kernel space and then have its signature
> > > > > > verified.
> > > > > >
> > > > > > This happens because when in-kernel module decompression
> > > > > > (CONFIG_MODULE_DECOMPRESS) is enabled, kmod will use finit_module
> > > > > > syscall instead of init_module to load a module. And IMA mandates IMA
> > > > > > xattr verification for finit_module unless appraise_type=imasig|modsig
> > > > > > is specified in the rule. However currently initramfs doesn't support
> > > > > > xattr. And IMA rule "func=MODULE_CHECK appraise_type=imasig|modsig"
> > > > > > doesn't work either because IMA will treat to-be-decompressed kernel
> > > > > > module as not having module signature as it can't decompress kernel
> > > > > > module to check if signature exists.
> > > > > >
> > > > > > So fall back to default kernel module signature verification when we have
> > > > > > no way to verify IMA xattr.
> > > > > >
> > > > > > Reported-by: Karel Srot <ksrot@redhat.com>
> > > > > > Signed-off-by: Coiby Xu <coxu@redhat.com>
> > > > > > ---
> > > > > > Another approach will be to make IMA decompress the kernel module to
> > > > > > check the signature. This requires refactoring kernel module code to
> > > > > > make the in-kernel module decompressing feature modular and seemingly
> > > > > > more efforts are needed. A second disadvantage is it feels
> > > > > > counter-intuitive to verify the same kernel module signature twice. And
> > > > > > we still need to make ima_policy=secure_boot allow verifying appended
> > > > > > module signature.
> > > > > >
> > > > > > Anyways, I'm open to suggestions and can try the latter approach if
> > > > > > there are some benefits I'm not aware of or a better approach.
> > > > >
> > > > > Coiby, there are multiple issues being discussed here. Before deciding on an
> > > > > appropriate solution, let's frame the issues(s) properly.
> > >
> > > Hi Mimi,
> > >
> > > Thanks for listing and framing the issues! Sorry, it took me a while to
> > > go through your feedback as I also had a 8-day holiday.
> > >
> > > > >
> > > > > 1. The finit_module syscall eventually calls init_module_from_file() to read the
> > > > > module into memory and then decompress it. The problem is that the kernel
> > > > > module signature verification occurs during the kernel_read_file(), before the
> > > > > kernel module is decompressed. Thus, the appended kernel module signature
> > > > > cannot be verified.
> > >
> > > Since IMA only accesses a kernel module as a fd or struct file*, even if
> > > IMA hook is triggerd after kernel module is decompressed, IMA still
> > > doesn't know the default verification has passed or can't access the
> > > decompressed kernel buffer [2] to do the verification by itself.
> > >
> > > [2] https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/module/main.c?h=v6.17#n3689
> > >
> > > > >
> > > > > 2. CPIO doesn't have xattr support. There were multiple attempts at including
> > > > > xattrs in CPIO, but none were upstreamed [1]. If file signatures stored in
> > > > > security.ima were available in the initramfs, then finit_module() could verify
> > > > > them, as opposed to the appended kernel module signature.
> > >
> > > Thanks you for pointing me to the work [1]. I'll take a more careful
> > > look at [1]. I think CPIO supporting xattr can be a long-term solution
> > > and also close a important security gap.
> > >
> > > > >
> > > > > 3. The issues described above are generic, not limited to Power. When
> > > > > CONFIG_MODULE_SIG is configured, the arch specific IMA policy rules do not
> > > > > include an "appraise func=MODULE_CHECK".
> > >
> > > Yes, the issue is not limited to Power. And thanks for correcting me
> > > that Power arch specific IMA policy rules don't have this problem! Sorry
> > > I misread the code.
> > >
> > > > >
> > > > > 4. Unlike the arch specific IMA policy rules, the built-in secure boot IMA
> > > > > policy, specified on the boot command line as "ima_policy=secure_boot", always
> > > > > enforces the IMA signature stored in security.ima.
> > > > >
> > > > > Partial solutions without kernel changes:
> > > > > - Enable CONFIG_MODULE_SIG (Doesn't solve 4)
> > > > > - Disable kernel module compression.
> > > > >
> > > > > Complete solution:
> > > > > - Pick up and upstream Roberto Sassu's last version of initramfs support [1].
> > > > > - Somehow prevent kernel_read_file() from failing when the kernel_read_file_id
> > > > > enumeration is READING_MODULE and the kernel module is compressed. The change
> > > > > might be limited to ima_post_read_file().
> > > >
> > > > or perhaps not totally.
> > > >
> > > > init_module_from_file() doesn't pass the flags variable to kernel_read_file().
> > > > You might want to consider defining a new kernel_read_file_id enumeration named
> > > > READING_COMPRESSED_MODULE.
> > >
> > > Thanks for suggesting the solutions! I like the solution of CPIO
> > > supporting xattr but it seems it won't land in upstream soon. So I
> > > prefer the last approach. I've implemented one [3] by defining a new
> > > kernel_read_file_id enumeration, would you like me to post the patches
> > > to the mailing list directly?
> > >
> > > [3] https://github.com/coiby/linux/tree/in_kernel_decompression_ima
> >
> > A few thoughts, before you post the patch.
>
> Thank you for sharing your thoughts!
>
> >
> > 1. In the general case, the kernel module could be compressed, but without an
> > appended signature. The new code should only defer appended signature
> > verification, if there isn't an xattr or appended signature.
>
> I'll add these two condition checks, thanks!
>
> >
> > 2. Instead of defining an additional process_measurement() argument to identify
> > compressed kernel modules, to simplify the code it might be possible to define a
> > new "func" named COMPRESSED_MODULE_CHECK.
> >
> > + [READING_COMPRESSED_MODULE] = MODULE_CHECK, -> COMPRESSED_MODULE_CHECK
>
> I also thought about this approach. But IMA rule maps kernel module
> loading to MODULE_CHECK. If we define a new rule and ask users to use
> this new rule, ima_policy=secure_boot still won't work.
I don't have a problem with extending the "secure-boot" policy to support
uncompressed kernel modules appended signatures, based on whether
CONFIG_MODULE_SIG is enabled. The new rule would be in addition to the existing
MODULE_CHECK rule.
>
> >
> > 3. The patch title "ima: Use default kernel module signature verification for
> > compressed ones" is a bit off. It should be something along the lines of "ima:
> > defer compressed kernel module appended signature verification".
>
> >
> > 4. Simplify the patch description.
>
> I'll rephrase the title and try simplifying it. Thanks!
Thank you.
^ permalink raw reply
* Re: [PATCH v3] hwrng: core - Allow runtime disabling of the HW RNG
From: Herbert Xu @ 2025-10-17 8:17 UTC (permalink / raw)
To: Jonathan McDowell
Cc: Olivia Mackall, linux-crypto, linux-kernel, linux-integrity
In-Reply-To: <aNKhkberbgFJph6R@earth.li>
On Tue, Sep 23, 2025 at 02:33:05PM +0100, Jonathan McDowell wrote:
> From: Jonathan McDowell <noodles@meta.com>
>
> The HW RNG core allows for manual selection of which RNG device to use,
> but does not allow for no device to be enabled. It may be desirable to
> do this on systems with only a single suitable hardware RNG, where we
> need exclusive access to other functionality on this device. In
> particular when performing TPM firmware upgrades this lets us ensure the
> kernel does not try to access the device.
>
> Before:
>
> root@debian-qemu-efi:~# grep "" /sys/devices/virtual/misc/hw_random/rng_*
> /sys/devices/virtual/misc/hw_random/rng_available:tpm-rng-0
> /sys/devices/virtual/misc/hw_random/rng_current:tpm-rng-0
> /sys/devices/virtual/misc/hw_random/rng_quality:1024
> /sys/devices/virtual/misc/hw_random/rng_selected:0
>
> After:
>
> root@debian-qemu-efi:~# grep "" /sys/devices/virtual/misc/hw_random/rng_*
> /sys/devices/virtual/misc/hw_random/rng_available:tpm-rng-0 none
> /sys/devices/virtual/misc/hw_random/rng_current:tpm-rng-0
> /sys/devices/virtual/misc/hw_random/rng_quality:1024
> /sys/devices/virtual/misc/hw_random/rng_selected:0
>
> root@debian-qemu-efi:~# echo none > /sys/devices/virtual/misc/hw_random/rng_current
> root@debian-qemu-efi:~# grep "" /sys/devices/virtual/misc/hw_random/rng_*
> /sys/devices/virtual/misc/hw_random/rng_available:tpm-rng-0 none
> /sys/devices/virtual/misc/hw_random/rng_current:none
> grep: /sys/devices/virtual/misc/hw_random/rng_quality: No such device
> /sys/devices/virtual/misc/hw_random/rng_selected:1
>
> (Observe using bpftrace no calls to TPM being made)
>
> root@debian-qemu-efi:~# echo "" > /sys/devices/virtual/misc/hw_random/rng_current
> root@debian-qemu-efi:~# grep "" /sys/devices/virtual/misc/hw_random/rng_*
> /sys/devices/virtual/misc/hw_random/rng_available:tpm-rng-0 none
> /sys/devices/virtual/misc/hw_random/rng_current:tpm-rng-0
> /sys/devices/virtual/misc/hw_random/rng_quality:1024
> /sys/devices/virtual/misc/hw_random/rng_selected:0
>
> (Observe using bpftrace that calls to the TPM resume)
>
> Signed-off-by: Jonathan McDowell <noodles@meta.com>
> ---
> v3: Always set cur_rng_set_by_user if user forces no HW RNG.
> v2: If the user manually forces the HWRNG to none do not override this
> when a new driver is loaded. Pointed out by Herbert Xu.
> drivers/char/hw_random/core.c | 9 ++++++---
> 1 file changed, 6 insertions(+), 3 deletions(-)
Patch applied. Thanks.
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH] ima: Fall back to default kernel module signature verification
From: Coiby Xu @ 2025-10-17 3:19 UTC (permalink / raw)
To: Mimi Zohar
Cc: linux-integrity, Dmitry Torokhov, Karel Srot, Roberto Sassu,
Dmitry Kasatkin, Eric Snowberg, Paul Moore, James Morris,
Serge E. Hallyn, open list:SECURITY SUBSYSTEM, open list
In-Reply-To: <9d279fd3d7b3cbb2778183ec777d6b9da8a64b82.camel@linux.ibm.com>
On Thu, Oct 16, 2025 at 10:31:35PM -0400, Mimi Zohar wrote:
>On Thu, 2025-10-16 at 11:46 +0800, Coiby Xu wrote:
>> On Tue, Sep 30, 2025 at 04:28:14PM -0400, Mimi Zohar wrote:
>> > On Tue, 2025-09-30 at 09:57 -0400, Mimi Zohar wrote:
>> > > On Sun, 2025-09-28 at 11:03 +0800, Coiby Xu wrote:
>> > > > Currently, for any IMA policy that requires appraisal for kernel modules
>> > > > e.g. ima_policy=secure_boot, PowerPC architecture specific policy,
>> > > > booting will fail because IMA will reject a kernel module which will
>> > > > be decompressed in the kernel space and then have its signature
>> > > > verified.
>> > > >
>> > > > This happens because when in-kernel module decompression
>> > > > (CONFIG_MODULE_DECOMPRESS) is enabled, kmod will use finit_module
>> > > > syscall instead of init_module to load a module. And IMA mandates IMA
>> > > > xattr verification for finit_module unless appraise_type=imasig|modsig
>> > > > is specified in the rule. However currently initramfs doesn't support
>> > > > xattr. And IMA rule "func=MODULE_CHECK appraise_type=imasig|modsig"
>> > > > doesn't work either because IMA will treat to-be-decompressed kernel
>> > > > module as not having module signature as it can't decompress kernel
>> > > > module to check if signature exists.
>> > > >
>> > > > So fall back to default kernel module signature verification when we have
>> > > > no way to verify IMA xattr.
>> > > >
>> > > > Reported-by: Karel Srot <ksrot@redhat.com>
>> > > > Signed-off-by: Coiby Xu <coxu@redhat.com>
>> > > > ---
>> > > > Another approach will be to make IMA decompress the kernel module to
>> > > > check the signature. This requires refactoring kernel module code to
>> > > > make the in-kernel module decompressing feature modular and seemingly
>> > > > more efforts are needed. A second disadvantage is it feels
>> > > > counter-intuitive to verify the same kernel module signature twice. And
>> > > > we still need to make ima_policy=secure_boot allow verifying appended
>> > > > module signature.
>> > > >
>> > > > Anyways, I'm open to suggestions and can try the latter approach if
>> > > > there are some benefits I'm not aware of or a better approach.
>> > >
>> > > Coiby, there are multiple issues being discussed here. Before deciding on an
>> > > appropriate solution, let's frame the issues(s) properly.
>>
>> Hi Mimi,
>>
>> Thanks for listing and framing the issues! Sorry, it took me a while to
>> go through your feedback as I also had a 8-day holiday.
>>
>> > >
>> > > 1. The finit_module syscall eventually calls init_module_from_file() to read the
>> > > module into memory and then decompress it. The problem is that the kernel
>> > > module signature verification occurs during the kernel_read_file(), before the
>> > > kernel module is decompressed. Thus, the appended kernel module signature
>> > > cannot be verified.
>>
>> Since IMA only accesses a kernel module as a fd or struct file*, even if
>> IMA hook is triggerd after kernel module is decompressed, IMA still
>> doesn't know the default verification has passed or can't access the
>> decompressed kernel buffer [2] to do the verification by itself.
>>
>> [2] https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/module/main.c?h=v6.17#n3689
>>
>> > >
>> > > 2. CPIO doesn't have xattr support. There were multiple attempts at including
>> > > xattrs in CPIO, but none were upstreamed [1]. If file signatures stored in
>> > > security.ima were available in the initramfs, then finit_module() could verify
>> > > them, as opposed to the appended kernel module signature.
>>
>> Thanks you for pointing me to the work [1]. I'll take a more careful
>> look at [1]. I think CPIO supporting xattr can be a long-term solution
>> and also close a important security gap.
>>
>> > >
>> > > 3. The issues described above are generic, not limited to Power. When
>> > > CONFIG_MODULE_SIG is configured, the arch specific IMA policy rules do not
>> > > include an "appraise func=MODULE_CHECK".
>>
>> Yes, the issue is not limited to Power. And thanks for correcting me
>> that Power arch specific IMA policy rules don't have this problem! Sorry
>> I misread the code.
>>
>> > >
>> > > 4. Unlike the arch specific IMA policy rules, the built-in secure boot IMA
>> > > policy, specified on the boot command line as "ima_policy=secure_boot", always
>> > > enforces the IMA signature stored in security.ima.
>> > >
>> > > Partial solutions without kernel changes:
>> > > - Enable CONFIG_MODULE_SIG (Doesn't solve 4)
>> > > - Disable kernel module compression.
>> > >
>> > > Complete solution:
>> > > - Pick up and upstream Roberto Sassu's last version of initramfs support [1].
>> > > - Somehow prevent kernel_read_file() from failing when the kernel_read_file_id
>> > > enumeration is READING_MODULE and the kernel module is compressed. The change
>> > > might be limited to ima_post_read_file().
>> >
>> > or perhaps not totally.
>> >
>> > init_module_from_file() doesn't pass the flags variable to kernel_read_file().
>> > You might want to consider defining a new kernel_read_file_id enumeration named
>> > READING_COMPRESSED_MODULE.
>>
>> Thanks for suggesting the solutions! I like the solution of CPIO
>> supporting xattr but it seems it won't land in upstream soon. So I
>> prefer the last approach. I've implemented one [3] by defining a new
>> kernel_read_file_id enumeration, would you like me to post the patches
>> to the mailing list directly?
>>
>> [3] https://github.com/coiby/linux/tree/in_kernel_decompression_ima
>
>A few thoughts, before you post the patch.
Thank you for sharing your thoughts!
>
>1. In the general case, the kernel module could be compressed, but without an
>appended signature. The new code should only defer appended signature
>verification, if there isn't an xattr or appended signature.
I'll add these two condition checks, thanks!
>
>2. Instead of defining an additional process_measurement() argument to identify
>compressed kernel modules, to simplify the code it might be possible to define a
>new "func" named COMPRESSED_MODULE_CHECK.
>
> + [READING_COMPRESSED_MODULE] = MODULE_CHECK, -> COMPRESSED_MODULE_CHECK
I also thought about this approach. But IMA rule maps kernel module
loading to MODULE_CHECK. If we define a new rule and ask users to use
this new rule, ima_policy=secure_boot still won't work.
>
>3. The patch title "ima: Use default kernel module signature verification for
>compressed ones" is a bit off. It should be something along the lines of "ima:
>defer compressed kernel module appended signature verification".
>
>4. Simplify the patch description.
I'll rephrase the title and try simplifying it. Thanks!
>
>> >
>Mimi
>
--
Best regards,
Coiby
^ permalink raw reply
* Re: [PATCH] ima: Fall back to default kernel module signature verification
From: Mimi Zohar @ 2025-10-17 2:31 UTC (permalink / raw)
To: Coiby Xu
Cc: linux-integrity, Dmitry Torokhov, Karel Srot, Roberto Sassu,
Dmitry Kasatkin, Eric Snowberg, Paul Moore, James Morris,
Serge E. Hallyn, open list:SECURITY SUBSYSTEM, open list
In-Reply-To: <xq7bgyg63xlbogcik2we26yr5uf62f6kj3qn7ooljmqaoccrix@kkmuhza5cfdr>
On Thu, 2025-10-16 at 11:46 +0800, Coiby Xu wrote:
> On Tue, Sep 30, 2025 at 04:28:14PM -0400, Mimi Zohar wrote:
> > On Tue, 2025-09-30 at 09:57 -0400, Mimi Zohar wrote:
> > > On Sun, 2025-09-28 at 11:03 +0800, Coiby Xu wrote:
> > > > Currently, for any IMA policy that requires appraisal for kernel modules
> > > > e.g. ima_policy=secure_boot, PowerPC architecture specific policy,
> > > > booting will fail because IMA will reject a kernel module which will
> > > > be decompressed in the kernel space and then have its signature
> > > > verified.
> > > >
> > > > This happens because when in-kernel module decompression
> > > > (CONFIG_MODULE_DECOMPRESS) is enabled, kmod will use finit_module
> > > > syscall instead of init_module to load a module. And IMA mandates IMA
> > > > xattr verification for finit_module unless appraise_type=imasig|modsig
> > > > is specified in the rule. However currently initramfs doesn't support
> > > > xattr. And IMA rule "func=MODULE_CHECK appraise_type=imasig|modsig"
> > > > doesn't work either because IMA will treat to-be-decompressed kernel
> > > > module as not having module signature as it can't decompress kernel
> > > > module to check if signature exists.
> > > >
> > > > So fall back to default kernel module signature verification when we have
> > > > no way to verify IMA xattr.
> > > >
> > > > Reported-by: Karel Srot <ksrot@redhat.com>
> > > > Signed-off-by: Coiby Xu <coxu@redhat.com>
> > > > ---
> > > > Another approach will be to make IMA decompress the kernel module to
> > > > check the signature. This requires refactoring kernel module code to
> > > > make the in-kernel module decompressing feature modular and seemingly
> > > > more efforts are needed. A second disadvantage is it feels
> > > > counter-intuitive to verify the same kernel module signature twice. And
> > > > we still need to make ima_policy=secure_boot allow verifying appended
> > > > module signature.
> > > >
> > > > Anyways, I'm open to suggestions and can try the latter approach if
> > > > there are some benefits I'm not aware of or a better approach.
> > >
> > > Coiby, there are multiple issues being discussed here. Before deciding on an
> > > appropriate solution, let's frame the issues(s) properly.
>
> Hi Mimi,
>
> Thanks for listing and framing the issues! Sorry, it took me a while to
> go through your feedback as I also had a 8-day holiday.
>
> > >
> > > 1. The finit_module syscall eventually calls init_module_from_file() to read the
> > > module into memory and then decompress it. The problem is that the kernel
> > > module signature verification occurs during the kernel_read_file(), before the
> > > kernel module is decompressed. Thus, the appended kernel module signature
> > > cannot be verified.
>
> Since IMA only accesses a kernel module as a fd or struct file*, even if
> IMA hook is triggerd after kernel module is decompressed, IMA still
> doesn't know the default verification has passed or can't access the
> decompressed kernel buffer [2] to do the verification by itself.
>
> [2] https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/module/main.c?h=v6.17#n3689
>
> > >
> > > 2. CPIO doesn't have xattr support. There were multiple attempts at including
> > > xattrs in CPIO, but none were upstreamed [1]. If file signatures stored in
> > > security.ima were available in the initramfs, then finit_module() could verify
> > > them, as opposed to the appended kernel module signature.
>
> Thanks you for pointing me to the work [1]. I'll take a more careful
> look at [1]. I think CPIO supporting xattr can be a long-term solution
> and also close a important security gap.
>
> > >
> > > 3. The issues described above are generic, not limited to Power. When
> > > CONFIG_MODULE_SIG is configured, the arch specific IMA policy rules do not
> > > include an "appraise func=MODULE_CHECK".
>
> Yes, the issue is not limited to Power. And thanks for correcting me
> that Power arch specific IMA policy rules don't have this problem! Sorry
> I misread the code.
>
> > >
> > > 4. Unlike the arch specific IMA policy rules, the built-in secure boot IMA
> > > policy, specified on the boot command line as "ima_policy=secure_boot", always
> > > enforces the IMA signature stored in security.ima.
> > >
> > > Partial solutions without kernel changes:
> > > - Enable CONFIG_MODULE_SIG (Doesn't solve 4)
> > > - Disable kernel module compression.
> > >
> > > Complete solution:
> > > - Pick up and upstream Roberto Sassu's last version of initramfs support [1].
> > > - Somehow prevent kernel_read_file() from failing when the kernel_read_file_id
> > > enumeration is READING_MODULE and the kernel module is compressed. The change
> > > might be limited to ima_post_read_file().
> >
> > or perhaps not totally.
> >
> > init_module_from_file() doesn't pass the flags variable to kernel_read_file().
> > You might want to consider defining a new kernel_read_file_id enumeration named
> > READING_COMPRESSED_MODULE.
>
> Thanks for suggesting the solutions! I like the solution of CPIO
> supporting xattr but it seems it won't land in upstream soon. So I
> prefer the last approach. I've implemented one [3] by defining a new
> kernel_read_file_id enumeration, would you like me to post the patches
> to the mailing list directly?
>
> [3] https://github.com/coiby/linux/tree/in_kernel_decompression_ima
A few thoughts, before you post the patch.
1. In the general case, the kernel module could be compressed, but without an
appended signature. The new code should only defer appended signature
verification, if there isn't an xattr or appended signature.
2. Instead of defining an additional process_measurement() argument to identify
compressed kernel modules, to simplify the code it might be possible to define a
new "func" named COMPRESSED_MODULE_CHECK.
+ [READING_COMPRESSED_MODULE] = MODULE_CHECK, -> COMPRESSED_MODULE_CHECK
3. The patch title "ima: Use default kernel module signature verification for
compressed ones" is a bit off. It should be something along the lines of "ima:
defer compressed kernel module appended signature verification".
4. Simplify the patch description.
> >
Mimi
^ permalink raw reply
* Re: [PATCH 0/2] ima: add dont_audit and fs_subtype to policy language
From: Mimi Zohar @ 2025-10-16 15:52 UTC (permalink / raw)
To: Jann Horn
Cc: Roberto Sassu, Dmitry Kasatkin, Eric Snowberg, Frank Dinoff,
linux-kernel, linux-integrity
In-Reply-To: <CAG48ez1jqa2y=aTJ=C+s9v0_xhWra7gezdY+BO=Red-XVGNQJQ@mail.gmail.com>
On Tue, 2025-09-30 at 16:26 +0200, Jann Horn wrote:
> On Tue, Sep 30, 2025 at 12:23 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> > On Fri, 2025-09-26 at 01:45 +0200, Jann Horn wrote:
> > > This series adds a "dont_audit" action that cancels out following
> > > "audit" actions (as we already have for other action types), and also
> > > adds an "fs_subtype" that can be used to distinguish between FUSE
> > > filesystems.
> > >
> > > With these two patches applied, as a toy example, you can use the
> > > following policy:
> > > ```
> > > dont_audit fsname=fuse fs_subtype=sshfs
> > > audit func=BPRM_CHECK fsname=fuse
> > > ```
> > >
> > > I have tested that with this policy, executing a binary from a
> > > "fuse-zip" FUSE filesystem results in an audit log entry:
> > > ```
> > > type=INTEGRITY_RULE msg=audit([...]): file="/home/user/ima/zipmount/usr/bin/echo" hash="sha256:1d82e8[...]
> > > ```
> > > while executing a binary from an "sshfs" FUSE filesystem does not
> > > generate any audit log entries.
> > >
> > > Signed-off-by: Jann Horn <jannh@google.com>
> >
> >
> > Thanks, Jann. The patches look fine. Assuming the "toy" test program creates
> > and mounts the fuse filesystems, not just loads the IMA policy rules, could you
> > share it?
>
> Thanks for the quick review! To clarify, by "toy example" I meant that
> while I was using real FUSE filesystems, the policy I was using is not
> very sensible.
>
> I used real FUSE filesystems for this since I figured that would be
> the easiest way to test, https://github.com/libfuse/sshfs and
> https://bitbucket.org/agalanin/fuse-zip. These are packaged in distros
> like Debian (as "sshfs" and "fuse-zip"). I mounted sshfs with these
> commands (mounting the home directory over ssh at ~/mnt/ssh):
>
> user@vm:~$ cp /usr/bin/echo ~/ima/
> user@vm:~$ sshfs localhost: ~/mnt/ssh
>
> and mounted fuse-zip with:
>
> user@vm:~/ima$ zip -rD echo.zip /usr/bin/echo
> adding: usr/bin/echo (deflated 62%)
> user@vm:~/ima$ mkdir zipmount
> user@vm:~/ima$ fuse-zip echo.zip zipmount/
>
> I then ran the executables ~/ima/zipmount/usr/bin/echo and ~/mnt/ssh/ima/echo.
Thank you for the instructions. Due to the holidays, there was a delay. The
patches are now queued in next-integrity for 6.19.
Mimi
^ permalink raw reply
* Re: [PATCH 0/2] ima: add dont_audit and fs_subtype to policy language
From: Jann Horn @ 2025-10-16 15:53 UTC (permalink / raw)
To: Mimi Zohar
Cc: Roberto Sassu, Dmitry Kasatkin, Eric Snowberg, Frank Dinoff,
linux-kernel, linux-integrity
In-Reply-To: <73d071ece8b1773740d494868f552abdd99decc6.camel@linux.ibm.com>
On Thu, Oct 16, 2025 at 5:52 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> On Tue, 2025-09-30 at 16:26 +0200, Jann Horn wrote:
> > On Tue, Sep 30, 2025 at 12:23 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> > > On Fri, 2025-09-26 at 01:45 +0200, Jann Horn wrote:
> > > > This series adds a "dont_audit" action that cancels out following
> > > > "audit" actions (as we already have for other action types), and also
> > > > adds an "fs_subtype" that can be used to distinguish between FUSE
> > > > filesystems.
> > > >
> > > > With these two patches applied, as a toy example, you can use the
> > > > following policy:
> > > > ```
> > > > dont_audit fsname=fuse fs_subtype=sshfs
> > > > audit func=BPRM_CHECK fsname=fuse
> > > > ```
> > > >
> > > > I have tested that with this policy, executing a binary from a
> > > > "fuse-zip" FUSE filesystem results in an audit log entry:
> > > > ```
> > > > type=INTEGRITY_RULE msg=audit([...]): file="/home/user/ima/zipmount/usr/bin/echo" hash="sha256:1d82e8[...]
> > > > ```
> > > > while executing a binary from an "sshfs" FUSE filesystem does not
> > > > generate any audit log entries.
> > > >
> > > > Signed-off-by: Jann Horn <jannh@google.com>
> > >
> > >
> > > Thanks, Jann. The patches look fine. Assuming the "toy" test program creates
> > > and mounts the fuse filesystems, not just loads the IMA policy rules, could you
> > > share it?
> >
> > Thanks for the quick review! To clarify, by "toy example" I meant that
> > while I was using real FUSE filesystems, the policy I was using is not
> > very sensible.
> >
> > I used real FUSE filesystems for this since I figured that would be
> > the easiest way to test, https://github.com/libfuse/sshfs and
> > https://bitbucket.org/agalanin/fuse-zip. These are packaged in distros
> > like Debian (as "sshfs" and "fuse-zip"). I mounted sshfs with these
> > commands (mounting the home directory over ssh at ~/mnt/ssh):
> >
> > user@vm:~$ cp /usr/bin/echo ~/ima/
> > user@vm:~$ sshfs localhost: ~/mnt/ssh
> >
> > and mounted fuse-zip with:
> >
> > user@vm:~/ima$ zip -rD echo.zip /usr/bin/echo
> > adding: usr/bin/echo (deflated 62%)
> > user@vm:~/ima$ mkdir zipmount
> > user@vm:~/ima$ fuse-zip echo.zip zipmount/
> >
> > I then ran the executables ~/ima/zipmount/usr/bin/echo and ~/mnt/ssh/ima/echo.
>
> Thank you for the instructions. Due to the holidays, there was a delay. The
> patches are now queued in next-integrity for 6.19.
Thanks a lot!
^ permalink raw reply
* Re: [PATCH] ima: Fall back to default kernel module signature verification
From: Coiby Xu @ 2025-10-16 3:51 UTC (permalink / raw)
To: kernel test robot
Cc: linux-integrity, oe-kbuild-all, Dmitry Torokhov, Karel Srot,
Mimi Zohar, Roberto Sassu, Dmitry Kasatkin, Eric Snowberg,
Paul Moore, James Morris, Serge E. Hallyn, linux-security-module,
linux-kernel
In-Reply-To: <202510030029.VRKgik99-lkp@intel.com>
On Fri, Oct 03, 2025 at 01:17:30AM +0800, kernel test robot wrote:
>Hi Coiby,
Hi,
>
>kernel test robot noticed the following build errors:
>
>[auto build test ERROR on cec1e6e5d1ab33403b809f79cd20d6aff124ccfe]
>
>url: https://github.com/intel-lab-lkp/linux/commits/Coiby-Xu/ima-Fall-back-to-default-kernel-module-signature-verification/20250928-110501
>base: cec1e6e5d1ab33403b809f79cd20d6aff124ccfe
>patch link: https://lore.kernel.org/r/20250928030358.3873311-1-coxu%40redhat.com
>patch subject: [PATCH] ima: Fall back to default kernel module signature verification
>config: i386-randconfig-012-20251002 (https://download.01.org/0day-ci/archive/20251003/202510030029.VRKgik99-lkp@intel.com/config)
>compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
>reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251003/202510030029.VRKgik99-lkp@intel.com/reproduce)
>
>If you fix the issue in a separate patch/commit (i.e. not just a new version of
>the same patch/commit), kindly add following tags
>| Reported-by: kernel test robot <lkp@intel.com>
>| Closes: https://lore.kernel.org/oe-kbuild-all/202510030029.VRKgik99-lkp@intel.com/
>
>All errors (new ones prefixed by >>):
>
> ld: security/integrity/ima/ima_appraise.o: in function `ima_appraise_measurement':
>>> security/integrity/ima/ima_appraise.c:587:(.text+0xbbb): undefined reference to `set_module_sig_enforced'
Thanks for reporting the error! This happens when
set_module_sig_enforced is called without CONFIG_MODULE_SIG not enabled.
I'll address this issue by declaring set_module_sig_enforced only when
CONFIG_MODULE_SIG is enabled.
>
>
>vim +587 security/integrity/ima/ima_appraise.c
>
> 483
> 484 /*
> 485 * ima_appraise_measurement - appraise file measurement
> 486 *
> 487 * Call evm_verifyxattr() to verify the integrity of 'security.ima'.
> 488 * Assuming success, compare the xattr hash with the collected measurement.
> 489 *
> 490 * Return 0 on success, error code otherwise
> 491 */
> 492 int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
> 493 struct file *file, const unsigned char *filename,
> 494 struct evm_ima_xattr_data *xattr_value,
> 495 int xattr_len, const struct modsig *modsig)
> 496 {
> 497 static const char op[] = "appraise_data";
> 498 int audit_msgno = AUDIT_INTEGRITY_DATA;
> 499 const char *cause = "unknown";
> 500 struct dentry *dentry = file_dentry(file);
> 501 struct inode *inode = d_backing_inode(dentry);
> 502 enum integrity_status status = INTEGRITY_UNKNOWN;
> 503 int rc = xattr_len;
> 504 bool try_modsig = iint->flags & IMA_MODSIG_ALLOWED && modsig;
> 505 bool enforce_module_sig = iint->flags & IMA_DIGSIG_REQUIRED && func == MODULE_CHECK;
> 506
> 507 /* If not appraising a modsig or using default module verification, we need an xattr. */
> 508 if (!(inode->i_opflags & IOP_XATTR) && !try_modsig && !enforce_module_sig)
> 509 return INTEGRITY_UNKNOWN;
> 510
> 511 /*
> 512 * Unlike any of the other LSM hooks where the kernel enforces file
> 513 * integrity, enforcing file integrity for the bprm_creds_for_exec()
> 514 * LSM hook with the AT_EXECVE_CHECK flag is left up to the discretion
> 515 * of the script interpreter(userspace). Differentiate kernel and
> 516 * userspace enforced integrity audit messages.
> 517 */
> 518 if (is_bprm_creds_for_exec(func, file))
> 519 audit_msgno = AUDIT_INTEGRITY_USERSPACE;
> 520
> 521 /* If reading the xattr failed and there's no modsig or module verification, error out. */
> 522 if (rc <= 0 && !try_modsig && !enforce_module_sig) {
> 523 if (rc && rc != -ENODATA)
> 524 goto out;
> 525
> 526 if (iint->flags & IMA_DIGSIG_REQUIRED) {
> 527 if (iint->flags & IMA_VERITY_REQUIRED)
> 528 cause = "verity-signature-required";
> 529 else
> 530 cause = "IMA-signature-required";
> 531 } else {
> 532 cause = "missing-hash";
> 533 }
> 534
> 535 status = INTEGRITY_NOLABEL;
> 536 if (file->f_mode & FMODE_CREATED)
> 537 iint->flags |= IMA_NEW_FILE;
> 538 if ((iint->flags & IMA_NEW_FILE) &&
> 539 (!(iint->flags & IMA_DIGSIG_REQUIRED) ||
> 540 (inode->i_size == 0)))
> 541 status = INTEGRITY_PASS;
> 542 goto out;
> 543 }
> 544
> 545 status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value,
> 546 rc < 0 ? 0 : rc);
> 547 switch (status) {
> 548 case INTEGRITY_PASS:
> 549 case INTEGRITY_PASS_IMMUTABLE:
> 550 case INTEGRITY_UNKNOWN:
> 551 break;
> 552 case INTEGRITY_NOXATTRS: /* No EVM protected xattrs. */
> 553 /* Fine to not have xattrs when using a modsig or default module verification. */
> 554 if (try_modsig || enforce_module_sig)
> 555 break;
> 556 fallthrough;
> 557 case INTEGRITY_NOLABEL: /* No security.evm xattr. */
> 558 cause = "missing-HMAC";
> 559 goto out;
> 560 case INTEGRITY_FAIL_IMMUTABLE:
> 561 set_bit(IMA_DIGSIG, &iint->atomic_flags);
> 562 cause = "invalid-fail-immutable";
> 563 goto out;
> 564 case INTEGRITY_FAIL: /* Invalid HMAC/signature. */
> 565 cause = "invalid-HMAC";
> 566 goto out;
> 567 default:
> 568 WARN_ONCE(true, "Unexpected integrity status %d\n", status);
> 569 }
> 570
> 571 if (xattr_value)
> 572 rc = xattr_verify(func, iint, xattr_value, xattr_len, &status,
> 573 &cause);
> 574
> 575 /*
> 576 * If we have a modsig and either no imasig or the imasig's key isn't
> 577 * known, then try verifying the modsig.
> 578 */
> 579 if (try_modsig &&
> 580 (!xattr_value || xattr_value->type == IMA_XATTR_DIGEST_NG ||
> 581 rc == -ENOKEY))
> 582 rc = modsig_verify(func, modsig, &status, &cause);
> 583
> 584 /* Fall back to default kernel module signature verification */
> 585 if (rc && enforce_module_sig) {
> 586 rc = 0;
> > 587 set_module_sig_enforced();
> 588 /* CONFIG_MODULE_SIG may be disabled */
> 589 if (is_module_sig_enforced()) {
> 590 rc = 0;
> 591 status = INTEGRITY_PASS;
> 592 pr_debug("Fall back to default kernel module verification for %s\n", filename);
> 593 }
> 594 }
> 595
> 596 out:
> 597 /*
> 598 * File signatures on some filesystems can not be properly verified.
> 599 * When such filesystems are mounted by an untrusted mounter or on a
> 600 * system not willing to accept such a risk, fail the file signature
> 601 * verification.
> 602 */
> 603 if ((inode->i_sb->s_iflags & SB_I_IMA_UNVERIFIABLE_SIGNATURE) &&
> 604 ((inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER) ||
> 605 (iint->flags & IMA_FAIL_UNVERIFIABLE_SIGS))) {
> 606 status = INTEGRITY_FAIL;
> 607 cause = "unverifiable-signature";
> 608 integrity_audit_msg(audit_msgno, inode, filename,
> 609 op, cause, rc, 0);
> 610 } else if (status != INTEGRITY_PASS) {
> 611 /* Fix mode, but don't replace file signatures. */
> 612 if ((ima_appraise & IMA_APPRAISE_FIX) && !try_modsig &&
> 613 (!xattr_value ||
> 614 xattr_value->type != EVM_IMA_XATTR_DIGSIG)) {
> 615 if (!ima_fix_xattr(dentry, iint))
> 616 status = INTEGRITY_PASS;
> 617 }
> 618
> 619 /*
> 620 * Permit new files with file/EVM portable signatures, but
> 621 * without data.
> 622 */
> 623 if (inode->i_size == 0 && iint->flags & IMA_NEW_FILE &&
> 624 test_bit(IMA_DIGSIG, &iint->atomic_flags)) {
> 625 status = INTEGRITY_PASS;
> 626 }
> 627
> 628 integrity_audit_msg(audit_msgno, inode, filename,
> 629 op, cause, rc, 0);
> 630 } else {
> 631 ima_cache_flags(iint, func);
> 632 }
> 633
> 634 ima_set_cache_status(iint, func, status);
> 635 return status;
> 636 }
> 637
>
>--
>0-DAY CI Kernel Test Service
>https://github.com/intel/lkp-tests/wiki
>
--
Best regards,
Coiby
^ permalink raw reply
* Re: [PATCH] ima: Fall back to default kernel module signature verification
From: Coiby Xu @ 2025-10-16 3:46 UTC (permalink / raw)
To: Mimi Zohar
Cc: linux-integrity, Dmitry Torokhov, Karel Srot, Roberto Sassu,
Dmitry Kasatkin, Eric Snowberg, Paul Moore, James Morris,
Serge E. Hallyn, open list:SECURITY SUBSYSTEM, open list
In-Reply-To: <bcd1f7b48311aff55711cdff4a6cdbb72aae1d04.camel@linux.ibm.com>
On Tue, Sep 30, 2025 at 04:28:14PM -0400, Mimi Zohar wrote:
>On Tue, 2025-09-30 at 09:57 -0400, Mimi Zohar wrote:
>> On Sun, 2025-09-28 at 11:03 +0800, Coiby Xu wrote:
>> > Currently, for any IMA policy that requires appraisal for kernel modules
>> > e.g. ima_policy=secure_boot, PowerPC architecture specific policy,
>> > booting will fail because IMA will reject a kernel module which will
>> > be decompressed in the kernel space and then have its signature
>> > verified.
>> >
>> > This happens because when in-kernel module decompression
>> > (CONFIG_MODULE_DECOMPRESS) is enabled, kmod will use finit_module
>> > syscall instead of init_module to load a module. And IMA mandates IMA
>> > xattr verification for finit_module unless appraise_type=imasig|modsig
>> > is specified in the rule. However currently initramfs doesn't support
>> > xattr. And IMA rule "func=MODULE_CHECK appraise_type=imasig|modsig"
>> > doesn't work either because IMA will treat to-be-decompressed kernel
>> > module as not having module signature as it can't decompress kernel
>> > module to check if signature exists.
>> >
>> > So fall back to default kernel module signature verification when we have
>> > no way to verify IMA xattr.
>> >
>> > Reported-by: Karel Srot <ksrot@redhat.com>
>> > Signed-off-by: Coiby Xu <coxu@redhat.com>
>> > ---
>> > Another approach will be to make IMA decompress the kernel module to
>> > check the signature. This requires refactoring kernel module code to
>> > make the in-kernel module decompressing feature modular and seemingly
>> > more efforts are needed. A second disadvantage is it feels
>> > counter-intuitive to verify the same kernel module signature twice. And
>> > we still need to make ima_policy=secure_boot allow verifying appended
>> > module signature.
>> >
>> > Anyways, I'm open to suggestions and can try the latter approach if
>> > there are some benefits I'm not aware of or a better approach.
>>
>> Coiby, there are multiple issues being discussed here. Before deciding on an
>> appropriate solution, let's frame the issues(s) properly.
Hi Mimi,
Thanks for listing and framing the issues! Sorry, it took me a while to
go through your feedback as I also had a 8-day holiday.
>>
>> 1. The finit_module syscall eventually calls init_module_from_file() to read the
>> module into memory and then decompress it. The problem is that the kernel
>> module signature verification occurs during the kernel_read_file(), before the
>> kernel module is decompressed. Thus, the appended kernel module signature
>> cannot be verified.
Since IMA only accesses a kernel module as a fd or struct file*, even if
IMA hook is triggerd after kernel module is decompressed, IMA still
doesn't know the default verification has passed or can't access the
decompressed kernel buffer [2] to do the verification by itself.
[2] https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/module/main.c?h=v6.17#n3689
>>
>> 2. CPIO doesn't have xattr support. There were multiple attempts at including
>> xattrs in CPIO, but none were upstreamed [1]. If file signatures stored in
>> security.ima were available in the initramfs, then finit_module() could verify
>> them, as opposed to the appended kernel module signature.
Thanks you for pointing me to the work [1]. I'll take a more careful
look at [1]. I think CPIO supporting xattr can be a long-term solution
and also close a important security gap.
>>
>> 3. The issues described above are generic, not limited to Power. When
>> CONFIG_MODULE_SIG is configured, the arch specific IMA policy rules do not
>> include an "appraise func=MODULE_CHECK".
Yes, the issue is not limited to Power. And thanks for correcting me
that Power arch specific IMA policy rules don't have this problem! Sorry
I misread the code.
>>
>> 4. Unlike the arch specific IMA policy rules, the built-in secure boot IMA
>> policy, specified on the boot command line as "ima_policy=secure_boot", always
>> enforces the IMA signature stored in security.ima.
>>
>> Partial solutions without kernel changes:
>> - Enable CONFIG_MODULE_SIG (Doesn't solve 4)
>> - Disable kernel module compression.
>>
>> Complete solution:
>> - Pick up and upstream Roberto Sassu's last version of initramfs support [1].
>> - Somehow prevent kernel_read_file() from failing when the kernel_read_file_id
>> enumeration is READING_MODULE and the kernel module is compressed. The change
>> might be limited to ima_post_read_file().
>
>or perhaps not totally.
>
>init_module_from_file() doesn't pass the flags variable to kernel_read_file().
>You might want to consider defining a new kernel_read_file_id enumeration named
>READING_COMPRESSED_MODULE.
Thanks for suggesting the solutions! I like the solution of CPIO
supporting xattr but it seems it won't land in upstream soon. So I
prefer the last approach. I've implemented one [3] by defining a new
kernel_read_file_id enumeration, would you like me to post the patches
to the mailing list directly?
[3] https://github.com/coiby/linux/tree/in_kernel_decompression_ima
>
>Mimi
>
>>
>> [1] [PATCH v4 0/3] initramfs: add support for xattrs in the initial ram disk
>> https://lore.kernel.org/linux-fsdevel/20190523121803.21638-1-roberto.sassu@huawei.com/
>>
>>
>
>
--
Best regards,
Coiby
^ permalink raw reply
* [PATCH] KEYS: encrypted: Simplify determining 'format_len'
From: Thorsten Blum @ 2025-10-15 23:21 UTC (permalink / raw)
To: Mimi Zohar, David Howells, Jarkko Sakkinen, Paul Moore,
James Morris, Serge E. Hallyn
Cc: Thorsten Blum, linux-integrity, keyrings, linux-security-module,
linux-kernel
Don't unnecessarily negate 'format' and simplify the calculation of
'format_len' in encrypted_key_alloc() and __ekey_init().
Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
---
security/keys/encrypted-keys/encrypted.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index aef438d18da8..d70f71d37f5f 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -581,7 +581,7 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
if (ret < 0 || dlen < MIN_DATA_SIZE || dlen > MAX_DATA_SIZE)
return ERR_PTR(-EINVAL);
- format_len = (!format) ? strlen(key_format_default) : strlen(format);
+ format_len = strlen(format ?: key_format_default);
decrypted_datalen = dlen;
payload_datalen = decrypted_datalen;
@@ -704,7 +704,7 @@ static void __ekey_init(struct encrypted_key_payload *epayload,
{
unsigned int format_len;
- format_len = (!format) ? strlen(key_format_default) : strlen(format);
+ format_len = strlen(format ?: key_format_default);
epayload->format = epayload->payload_data + epayload->payload_datalen;
epayload->master_desc = epayload->format + format_len + 1;
epayload->datalen = epayload->master_desc + strlen(master_desc) + 1;
--
2.51.0
^ permalink raw reply related
* Re: [PATCH] tpm_crb: Add idle support for the Arm FF-A start method
From: Stuart Yoder @ 2025-10-15 22:22 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: linux-integrity, peterhuewe, jgg, sudeep.holla, Prachotan.Bathi,
linux-kernel
In-Reply-To: <aKzoaWeJOh5W0M6J@kernel.org>
On 8/25/25 5:49 PM, Jarkko Sakkinen wrote:
> On Mon, Aug 25, 2025 at 05:19:34PM -0500, Stuart Yoder wrote:
>>
>>
>> On 8/25/25 4:58 PM, Jarkko Sakkinen wrote:
>>> On Mon, Aug 25, 2025 at 03:59:43PM -0500, Stuart Yoder wrote:
>>>> According to the CRB over FF-A specification [1], a TPM that implements
>>>> the ABI must comply with the TCG PTP specification. This requires support
>>>> for the Idle and Ready states.
>>>>
>>>> This patch implements CRB control area requests for goIdle and
>>>> cmdReady on FF-A based TPMs.
>>>>
>>>> The FF-A message used to notify the TPM of CRB updates includes a
>>>> locality parameter, which provides a hint to the TPM about which
>>>> locality modified the CRB. This patch adds a locality parameter
>>>> to __crb_go_idle() and __crb_cmd_ready() to support this.
>>>>
>>>> [1] https://developer.arm.com/documentation/den0138/latest/
>>>>
>>>> Signed-off-by: Stuart Yoder <stuart.yoder@arm.com>
>>>
>>> Perhaps a dummy question but is this "QEMU testable"? I know how
>>> to bind swtpm to QEMU and make it appear as CRB device on x86-64.
>>>
>>> I don't see much testing happening with these ARM CRB patches,
>>> and if that works in the first palce I could probably add
>>> a new board target to my BR2_EXTERNAL [1].
>>>
>>> I can of course do "negative testing' i.e. that these don't
>>> break x86 ;-)
>>
>> Unfortunately this is not currently testable on QEMU. We are using
>> the Arm FVP [1], which is also a machine emulator, with the firmware
>> stack and an fTPM running in TrustZone. The firmware, fTPM, etc are
>> not all publicly available yet, but everything is based on open
>> source projects and the intent is that all the components needed do
>> test this on FVP will be available at some point.
>>
>> There is nothing fundamental that would prevent this from running
>> on QEMU, but just a fair amount of integration and possibly firmware
>> work.
>
> OK, it's cool and the patch looks totally fine and I can
> "hallucinate it" so:
>
> Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
Hi Jarkko,
It looks like this patch did not make it into 6.18. I wanted to make
sure it didn't get lost. Will it be queued up for 6.19?
Thanks,
Stuart
^ permalink raw reply
* Re: [PATCH v3] keys: Replace deprecated strncpy in ecryptfs_fill_auth_tok
From: Jarkko Sakkinen @ 2025-10-15 11:06 UTC (permalink / raw)
To: Paul Menzel, David Howells
Cc: Thorsten Blum, Mimi Zohar, David Howells, Paul Moore,
James Morris, Serge E. Hallyn, linux-hardening, Kees Cook,
linux-integrity, keyrings, linux-security-module, linux-kernel
In-Reply-To: <b9246396-c9d9-4452-a16c-f2c8166a32ee@molgen.mpg.de>
On Mon, Oct 13, 2025 at 06:11:38PM +0200, Paul Menzel wrote:
> Dear Thorsten,
>
>
> Thank you for the patch.
>
> Am 13.10.25 um 17:26 schrieb Thorsten Blum:
> > strncpy() is deprecated for NUL-terminated destination buffers; use
> > strscpy_pad() instead to retain the NUL-padding behavior of strncpy().
> >
> > The destination buffer is initialized using kzalloc() with a 'signature'
> > size of ECRYPTFS_PASSWORD_SIG_SIZE + 1. strncpy() then copies up to
> > ECRYPTFS_PASSWORD_SIG_SIZE bytes from 'key_desc', NUL-padding any
> > remaining bytes if needed, but expects the last byte to be zero.
> >
> > strscpy_pad() also copies the source string to 'signature', and NUL-pads
> > the destination buffer if needed, but ensures it's always NUL-terminated
> > without relying on it being zero-initialized.
> >
> > strscpy_pad() automatically determines the size of the fixed-length
> > destination buffer via sizeof() when the optional size argument is
> > omitted, making an explicit size unnecessary.
> >
> > In encrypted_init(), the source string 'key_desc' is validated by
> > valid_ecryptfs_desc() before calling ecryptfs_fill_auth_tok(), and is
> > therefore NUL-terminated and satisfies the __must_be_cstr() requirement
> > of strscpy_pad().
> >
> > Link: https://github.com/KSPP/linux/issues/90
> > Reviewed-by: Kees Cook <kees@kernel.org>
> > Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
> > Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
> > ---
> > Changes in v3:
> > - Improve commit message
> > - Link to v2: https://lore.kernel.org/lkml/20251010161340.458707-2-thorsten.blum@linux.dev/
> >
> > Changes in v2:
> > - Improve commit message as suggested by Jarkko and Kees
> > - Link to v1: https://lore.kernel.org/lkml/20251009180316.394708-3-thorsten.blum@linux.dev/
> > ---
> > security/keys/encrypted-keys/ecryptfs_format.c | 3 +--
> > 1 file changed, 1 insertion(+), 2 deletions(-)
> >
> > diff --git a/security/keys/encrypted-keys/ecryptfs_format.c b/security/keys/encrypted-keys/ecryptfs_format.c
> > index 8fdd76105ce3..2fc6f3a66135 100644
> > --- a/security/keys/encrypted-keys/ecryptfs_format.c
> > +++ b/security/keys/encrypted-keys/ecryptfs_format.c
> > @@ -54,8 +54,7 @@ int ecryptfs_fill_auth_tok(struct ecryptfs_auth_tok *auth_tok,
> > auth_tok->version = (((uint16_t)(major << 8) & 0xFF00)
> > | ((uint16_t)minor & 0x00FF));
> > auth_tok->token_type = ECRYPTFS_PASSWORD;
> > - strncpy((char *)auth_tok->token.password.signature, key_desc,
> > - ECRYPTFS_PASSWORD_SIG_SIZE);
> > + strscpy_pad(auth_tok->token.password.signature, key_desc);
> > auth_tok->token.password.session_key_encryption_key_bytes =
> > ECRYPTFS_MAX_KEY_BYTES;
> > /*
>
> Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Thanks for the review Paul.
David: and also this is in my tree now.
>
>
> Kind regards,
>
> Paul
BR, Jarkko
^ permalink raw reply
* Re: [PATCH] keys: Remove redundant less-than-zero checks
From: Jarkko Sakkinen @ 2025-10-15 11:02 UTC (permalink / raw)
To: Thorsten Blum, David Howells
Cc: David Howells, Paul Moore, James Morris, Serge E. Hallyn,
Mimi Zohar, James Bottomley, keyrings, linux-security-module,
linux-kernel, linux-integrity
In-Reply-To: <20251011144824.1257-2-thorsten.blum@linux.dev>
On Sat, Oct 11, 2025 at 04:48:24PM +0200, Thorsten Blum wrote:
> The local variables 'size_t datalen' are unsigned and cannot be less
> than zero. Remove the redundant conditions.
>
> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
David, I've applied this.
BR, Jarkko
^ permalink raw reply
* tpm2sh 0.11
From: Jarkko Sakkinen @ 2025-10-14 16:42 UTC (permalink / raw)
To: tpm2, linux-integrity
Hi
Kernel testing focused and somewhat opionated TPM2 tool tpm2sh has
now first usable release:
https://crates.io/crates/tpm2sh/0.11.0
❯ tpm2sh help
Usage: tpm2sh [-d <device>] [--log-format <log-format>] [-P] <command> [<args>]
TPM 2.0 shell
Options:
-d, --device device path
--log-format log format: 'plain' or 'pretty'
-P, --plain print tables without headers and with space-separated
columns
--help, help display usage information
Commands:
algorithm Lists available algorithms supported by the chip.
certificate Exports an endorsement key certificate.
convert Converts external key files to TPMKey files.
create Creates secondary keys.
create-primary Creates a new primary key in a specified hierarchy.
delete Deletes TPM objects, and cached keys and sessions.
key Lists cached keys.
load Loads a key under a parent and caches its context.
memory Lists objects inside TPM memory.
pcr-event Extends a PCR with an event.
policy Builds an authorization policy.
return-code Prints a TPM return code in human-readable format.
reset-lock Resets the dictionary attack lockout counter.
save Stores a cached key to non-volatile memory.
seal Creates a sealed data object.
session Lists cached authorization sessions.
start-session Starts a new authorization session.
unseal Retrieves data from a sealed data object.
It can convert and load PKCS#1, SEC1 and PKCS#8 keys into TPMKey files,
which makes it practical with kernel interfaces.
BR, Jarkko
^ permalink raw reply
* Re: [PATCH 0/2] ima: add dont_audit and fs_subtype to policy language
From: Jann Horn @ 2025-10-14 15:55 UTC (permalink / raw)
To: Mimi Zohar
Cc: Roberto Sassu, Dmitry Kasatkin, Eric Snowberg, Frank Dinoff,
linux-kernel, linux-integrity
In-Reply-To: <ef7c07585e41c8afbb2b97df98fd47c9374b15cb.camel@linux.ibm.com>
Hi!
On Tue, Sep 30, 2025 at 12:23 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> On Fri, 2025-09-26 at 01:45 +0200, Jann Horn wrote:
> > This series adds a "dont_audit" action that cancels out following
> > "audit" actions (as we already have for other action types), and also
> > adds an "fs_subtype" that can be used to distinguish between FUSE
> > filesystems.
> >
> > With these two patches applied, as a toy example, you can use the
> > following policy:
> > ```
> > dont_audit fsname=fuse fs_subtype=sshfs
> > audit func=BPRM_CHECK fsname=fuse
> > ```
> >
> > I have tested that with this policy, executing a binary from a
> > "fuse-zip" FUSE filesystem results in an audit log entry:
> > ```
> > type=INTEGRITY_RULE msg=audit([...]): file="/home/user/ima/zipmount/usr/bin/echo" hash="sha256:1d82e8[...]
> > ```
> > while executing a binary from an "sshfs" FUSE filesystem does not
> > generate any audit log entries.
> >
> > Signed-off-by: Jann Horn <jannh@google.com>
>
>
> Thanks, Jann. The patches look fine.
What's the next step here - are the patches going to land in the
next-integrity branch, so that they will go into 6.19?
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox