* [PATCH RESEND 1/1] yama: clean-up ptrace relations upon activating YAMA_SCOPE_NO_ATTACH
From: Ethan Ferguson @ 2026-05-26 15:35 UTC (permalink / raw)
To: kees, paul, jmorris, serge
Cc: linux-security-module, linux-kernel, Ethan Ferguson
In-Reply-To: <20260526153542.105483-1-ethan.ferguson@zetier.com>
Clean up ptracer_relations upon YAMA_SCOPE_NO_ATTACH, and prevent
further modification by processes.
Signed-off-by: Ethan Ferguson <ethan.ferguson@zetier.com>
---
security/yama/yama_lsm.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index cef3776cf3b2..3b7c5384e6bc 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -26,6 +26,7 @@
#define YAMA_SCOPE_NO_ATTACH 3
static int ptrace_scope = YAMA_SCOPE_RELATIONAL;
+static int max_scope = YAMA_SCOPE_NO_ATTACH;
/* describe a ptrace relationship for potential exception */
struct ptrace_relation {
@@ -119,7 +120,7 @@ static void yama_relation_cleanup(struct work_struct *work)
spin_lock(&ptracer_relations_lock);
rcu_read_lock();
list_for_each_entry_rcu(relation, &ptracer_relations, node) {
- if (relation->invalid) {
+ if (relation->invalid || ptrace_scope == max_scope) {
list_del_rcu(&relation->node);
kfree_rcu(relation, rcu);
}
@@ -204,7 +205,8 @@ static void yama_ptracer_del(struct task_struct *tracer,
*/
static void yama_task_free(struct task_struct *task)
{
- yama_ptracer_del(task, task);
+ if (ptrace_scope <= max_scope)
+ yama_ptracer_del(task, task);
}
/**
@@ -224,6 +226,9 @@ static int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3,
int rc = -ENOSYS;
struct task_struct *myself;
+ if (ptrace_scope == max_scope)
+ return -EPERM;
+
switch (option) {
case PR_SET_PTRACER:
/* Since a thread can call prctl(), find the group leader
@@ -432,6 +437,7 @@ static struct security_hook_list yama_hooks[] __ro_after_init = {
static int yama_dointvec_minmax(const struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
+ int ret;
struct ctl_table table_copy;
if (write && !capable(CAP_SYS_PTRACE))
@@ -442,10 +448,17 @@ static int yama_dointvec_minmax(const struct ctl_table *table, int write,
if (*(int *)table_copy.data == *(int *)table_copy.extra2)
table_copy.extra1 = table_copy.extra2;
- return proc_dointvec_minmax(&table_copy, write, buffer, lenp, ppos);
-}
+ ret = proc_dointvec_minmax(&table_copy, write, buffer, lenp, ppos);
+ if (ret < 0)
+ return ret;
-static int max_scope = YAMA_SCOPE_NO_ATTACH;
+ /* If max_scope was just activated in this call */
+ if (*(int *)table_copy.data == *(int *)table_copy.extra2 &&
+ table_copy.extra1 != table_copy.extra2)
+ schedule_work(&yama_relation_work);
+
+ return 0;
+}
static const struct ctl_table yama_sysctl_table[] = {
{
--
2.43.0
^ permalink raw reply related
* [PATCH RESEND 0/1] yama: clean-up ptrace relations upon activating YAMA_SCOPE_NO_ATTACH
From: Ethan Ferguson @ 2026-05-26 15:35 UTC (permalink / raw)
To: kees, paul, jmorris, serge
Cc: linux-security-module, linux-kernel, Ethan Ferguson
Once yama's ptrace_scope gets set to it's max value (currently
YAMA_SCOPE_NO_ATTACH), all ptrace actions will forever be denied.
However, processes may still add ptrace relations, and the memory
to store these relations is still allocated, even though it is never
used again.
This patch cleans up all memory related to ptracer_relations upon
YAMA_SCOPE_NO_ATTACH, and additionally disallows further modification
of ptracer_relations from processes.
Ethan Ferguson (1):
yama: clean-up ptrace relations upon activating YAMA_SCOPE_NO_ATTACH
security/yama/yama_lsm.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
base-commit: cf2f06f7152d
--
2.43.0
^ permalink raw reply
* Re: [PATCH] tomoyo: Fix NULL pointer dereference in tomoyo_init_request_info() when domain is NULL
From: Tetsuo Handa @ 2026-05-26 14:37 UTC (permalink / raw)
To: Jiakai Xu
Cc: jmorris, linux-kernel, linux-security-module, paul, serge,
takedakn
In-Reply-To: <20260526135859.3211799-1-xujiakai24@mails.ucas.ac.cn>
On 2026/05/26 22:58, Jiakai Xu wrote:
>> Thank you for a patch, but I don't think we need this change.
>
> Thanks for your review! I understand your perspective, but I believe
> the crash is a real NULL pointer dereference, and I'd like to explain
> why the defensive check is warranted.
>
>> TOMOYO's initial domain is &tomoyo_kernel_domain, and each thread belongs to
>> a non-NULL domain. Therefore, tomoyo_domain() is not supposed to return NULL.
>
> While tomoyo_domain() is not supposed to return NULL under normal
> operation, there are code paths that leave s->domain_info == NULL:
>
> a) Pre-init window (security/tomoyo/tomoyo.c, lines 598-612):
> The task security blob is zero-allocated via kzalloc(), and
> security_add_hooks() at line 603 is called BEFORE
> s->domain_info = &tomoyo_kernel_domain at line 606. If any LSM
> hook fires during that window, tomoyo_domain() returns NULL.
This code is executed during early boot stage. Other LSM hooks are not
supposed to fire.
>
> b) tomoyo_task_free() (tomoyo.c, lines 533-545) explicitly sets
> s->domain_info = NULL after decrementing the refcount.
This code is executed when a "struct task_struct" is about to be released.
Nobody can find this "struct task_struct". Also, this "struct task_struct"
cannot be the current thread.
>
> c) tomoyo_find_next_domain() (domain.c, lines 876-883) writes
> s->domain_info = NULL when the domain transition fails.
I couldn't catch, but old_domain is initialized as
struct tomoyo_domain_info *old_domain = tomoyo_domain();
which cannot be NULL.
domain is guaranteed to be non-NULL because old_domain cannot be NULL.
if (!domain)
domain = old_domain;
Therefore, s->domain_info is guaranteed to be non-NULL because domain cannot be NULL.
s->domain_info = domain;
If domain were NULL, the kernel should have already crashed at line 884.
>
> I think adding a NULL check makes the code more robust. What do you
> think?
Then, this will be NULL pointer dereference.
But fixing the location that is setting NULL is the correct approach.
^ permalink raw reply
* [PATCH v3] security: Expand task_setscheduler LSM hook to include CPU affinity mask
From: Aaron Tomlin @ 2026-05-26 14:28 UTC (permalink / raw)
To: tsbogend, paul, jmorris, serge, mingo, peterz, juri.lelli,
vincent.guittot, stephen.smalley.work, casey, longman, tj, hannes,
mkoutny
Cc: chenridong, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, omosnace, kees, atomlin, neelx, sean, chjohnst,
steve, mproche, nick.lange, cgroups, linux-mips, linux-fsdevel,
linux-security-module, selinux, linux-kernel
At present, the task_setscheduler LSM hook provides security modules
with the opportunity to mediate changes to a task's scheduling policy.
However, when invoked via sched_setaffinity(), the hook lacks
visibility into the actual CPU affinity mask being requested.
Consequently, BPF-based security modules are entirely blind to the
target CPUs and cannot make granular access control decisions based on
spatial isolation.
In modern multi-tenant and real-time environments, CPU isolation is a
critical boundary. The inability to audit or restrict specific CPU
pinning requests limits the effectiveness of eBPF-driven security
policies, particularly when attempting to shield isolated or
cryptographic cores from unprivileged or compromised tasks.
This patch expands the security_task_setscheduler() hook signature to
include a pointer to the requested cpumask. Because this is a shared
hook used for multiple scheduling attribute changes, call sites that do
not modify CPU affinity are updated to safely pass NULL.
To protect against unverified dereferences, the parameter is annotated
with __nullable in the LSM hook definition, ensuring the BPF verifier
mandates explicit NULL checks for attached eBPF programs.
This change updates all in-tree security modules (SELinux and Smack) to
accommodate the new parameter mechanically, whilst providing BPF LSMs
with the necessary context to enforce strict affinity policies.
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
This patch is strictly dependent on the prior acceptance of "mips:
sched: Fix CPUMASK_OFFSTACK memory corruption in MT fpaff" (Message-ID:
20260526141651.773306-1-atomlin@atomlin.com), as expanding the LSM hook
signature requires passing the mask pointer from
mipsmt_sys_sched_setaffinity().
Changes since v2 [1]:
- Dropped patch 1. This is to be addressed by the cgroup cpuset
maintainer (Waiman Long)
- Dropped patch 3. Will be submitted as a separate patch (Paul Moore)
Changes since v1 [2]:
- Reordered the allocation and user-copy of new_mask in the MIPS
architecture's mipsmt_sys_sched_setaffinity() to occur before the
LSM hook is invoked. This ensures the security modules evaluate a fully
populated mask rather than uninitialised memory, while cleanly handling
error unwinding
- Updated cpuset_can_fork() to pass the destination cpuset's effective CPU
mask instead of NULL
[1]: https://lore.kernel.org/lkml/20260509213803.968464-1-atomlin@atomlin.com/
[2]: https://lore.kernel.org/lkml/20260509164847.939294-1-atomlin@atomlin.com/
---
arch/mips/kernel/mips-mt-fpaff.c | 2 +-
fs/proc/base.c | 2 +-
include/linux/lsm_hook_defs.h | 3 ++-
include/linux/security.h | 11 +++++++----
kernel/cgroup/cpuset.c | 4 ++--
kernel/sched/syscalls.c | 4 ++--
security/commoncap.c | 7 +++++--
security/security.c | 11 ++++++-----
security/selinux/hooks.c | 3 ++-
security/smack/smack_lsm.c | 11 +++++++++--
10 files changed, 37 insertions(+), 21 deletions(-)
diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c
index 4fead87d2f43..c68d1676350e 100644
--- a/arch/mips/kernel/mips-mt-fpaff.c
+++ b/arch/mips/kernel/mips-mt-fpaff.c
@@ -110,7 +110,7 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
goto out_unlock;
}
- retval = security_task_setscheduler(p);
+ retval = security_task_setscheduler(p, new_mask);
if (retval)
goto out_unlock;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index d9acfa89c894..ac4096958a00 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2619,7 +2619,7 @@ static ssize_t timerslack_ns_write(struct file *file, const char __user *buf,
}
rcu_read_unlock();
- err = security_task_setscheduler(p);
+ err = security_task_setscheduler(p, NULL);
if (err) {
count = err;
goto out;
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 2b8dfb35caed..6ec7bc04a1b7 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -255,7 +255,8 @@ LSM_HOOK(int, 0, task_prlimit, const struct cred *cred,
const struct cred *tcred, unsigned int flags)
LSM_HOOK(int, 0, task_setrlimit, struct task_struct *p, unsigned int resource,
struct rlimit *new_rlim)
-LSM_HOOK(int, 0, task_setscheduler, struct task_struct *p)
+LSM_HOOK(int, 0, task_setscheduler, struct task_struct *p,
+ const struct cpumask *in_mask__nullable)
LSM_HOOK(int, 0, task_getscheduler, struct task_struct *p)
LSM_HOOK(int, 0, task_movememory, struct task_struct *p)
LSM_HOOK(int, 0, task_kill, struct task_struct *p, struct kernel_siginfo *info,
diff --git a/include/linux/security.h b/include/linux/security.h
index 41d7367cf403..8b74153daa43 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -196,7 +196,8 @@ extern int cap_mmap_addr(unsigned long addr);
extern int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags);
extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5);
-extern int cap_task_setscheduler(struct task_struct *p);
+extern int cap_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask);
extern int cap_task_setioprio(struct task_struct *p, int ioprio);
extern int cap_task_setnice(struct task_struct *p, int nice);
extern int cap_vm_enough_memory(struct mm_struct *mm, long pages);
@@ -531,7 +532,8 @@ int security_task_prlimit(const struct cred *cred, const struct cred *tcred,
unsigned int flags);
int security_task_setrlimit(struct task_struct *p, unsigned int resource,
struct rlimit *new_rlim);
-int security_task_setscheduler(struct task_struct *p);
+int security_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask);
int security_task_getscheduler(struct task_struct *p);
int security_task_movememory(struct task_struct *p);
int security_task_kill(struct task_struct *p, struct kernel_siginfo *info,
@@ -1392,9 +1394,10 @@ static inline int security_task_setrlimit(struct task_struct *p,
return 0;
}
-static inline int security_task_setscheduler(struct task_struct *p)
+static inline int security_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask)
{
- return cap_task_setscheduler(p);
+ return cap_task_setscheduler(p, in_mask);
}
static inline int security_task_getscheduler(struct task_struct *p)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 5c33ab20cc20..7b3dfccb77d8 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -3033,7 +3033,7 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
goto out_unlock;
if (setsched_check) {
- ret = security_task_setscheduler(task);
+ ret = security_task_setscheduler(task, cs->effective_cpus);
if (ret)
goto out_unlock;
}
@@ -3591,7 +3591,7 @@ static int cpuset_can_fork(struct task_struct *task, struct css_set *cset)
if (ret)
goto out_unlock;
- ret = security_task_setscheduler(task);
+ ret = security_task_setscheduler(task, cs->effective_cpus);
if (ret)
goto out_unlock;
diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c
index b215b0ead9a6..68bc7e466fb1 100644
--- a/kernel/sched/syscalls.c
+++ b/kernel/sched/syscalls.c
@@ -540,7 +540,7 @@ int __sched_setscheduler(struct task_struct *p,
if (attr->sched_flags & SCHED_FLAG_SUGOV)
return -EINVAL;
- retval = security_task_setscheduler(p);
+ retval = security_task_setscheduler(p, NULL);
if (retval)
return retval;
}
@@ -1213,7 +1213,7 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
return -EPERM;
}
- retval = security_task_setscheduler(p);
+ retval = security_task_setscheduler(p, in_mask);
if (retval)
return retval;
diff --git a/security/commoncap.c b/security/commoncap.c
index 3399535808fe..d86f1c2b9210 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -1222,13 +1222,16 @@ static int cap_safe_nice(struct task_struct *p)
/**
* cap_task_setscheduler - Determine if scheduler policy change is permitted
* @p: The task to affect
+ * @in_mask: Requested CPU affinity mask (ignored)
*
* Determine if the requested scheduler policy change is permitted for the
- * specified task.
+ * specified task. The capabilities security module does not evaluate the
+ * @in_mask parameter, relying solely on cap_safe_nice().
*
* Return: 0 if permission is granted, -ve if denied.
*/
-int cap_task_setscheduler(struct task_struct *p)
+int cap_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask __always_unused)
{
return cap_safe_nice(p);
}
diff --git a/security/security.c b/security/security.c
index 4e999f023651..53804ee40df5 100644
--- a/security/security.c
+++ b/security/security.c
@@ -3240,17 +3240,18 @@ int security_task_setrlimit(struct task_struct *p, unsigned int resource,
}
/**
- * security_task_setscheduler() - Check if setting sched policy/param is allowed
+ * security_task_setscheduler() - Check if setting sched policy/param/affinity is allowed
* @p: target task
+ * @in_mask: requested CPU affinity mask, or NULL if not changing affinity
*
- * Check permission before setting scheduling policy and/or parameters of
- * process @p.
+ * Check permission before setting the scheduling policy, parameters, and/or
+ * CPU affinity of process @p.
*
* Return: Returns 0 if permission is granted.
*/
-int security_task_setscheduler(struct task_struct *p)
+int security_task_setscheduler(struct task_struct *p, const struct cpumask *in_mask)
{
- return call_int_hook(task_setscheduler, p);
+ return call_int_hook(task_setscheduler, p, in_mask);
}
/**
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 0f704380a8c8..5f0914db23f6 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4557,7 +4557,8 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
return 0;
}
-static int selinux_task_setscheduler(struct task_struct *p)
+static int selinux_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask __always_unused)
{
return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 3f9ae05039a2..a77143beff44 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2343,10 +2343,17 @@ static int smack_task_getioprio(struct task_struct *p)
/**
* smack_task_setscheduler - Smack check on setting scheduler
* @p: the task object
+ * @in_mask: Requested CPU affinity mask (ignored)
*
- * Return 0 if read access is permitted
+ * Evaluate whether the current task has write access to the target task @p
+ * to change its scheduling policy. The Smack security module relies
+ * strictly on label-based access control and does not evaluate CPU
+ * affinity masks.
+ *
+ * Return: 0 if write access is permitted
*/
-static int smack_task_setscheduler(struct task_struct *p)
+static int smack_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask __always_unused)
{
return smk_curacc_on_task(p, MAY_WRITE, __func__);
}
base-commit: 5200f5f493f79f14bbdc349e402a40dfb32f23c8
prerequisite-patch-id: f9200d420002c9fd0663d0ec00c83db866889c19
--
2.51.0
^ permalink raw reply related
* Re: [PATCH v5 00/13] ima: Introduce staging mechanism
From: Mimi Zohar @ 2026-05-26 14:10 UTC (permalink / raw)
To: Lakshmi Ramasubramanian, steven chen, Roberto Sassu, corbet,
skhan, dmitry.kasatkin, eric.snowberg, paul, jmorris, serge
Cc: linux-doc, linux-kernel, linux-integrity, linux-security-module,
gregorylumen, Roberto Sassu
In-Reply-To: <aaed52cf-26e1-4c40-812d-3788024ce5b5@linux.microsoft.com>
On Mon, 2026-05-11 at 10:29 -0700, Lakshmi Ramasubramanian wrote:
> Roberto, Mimi:
>
> I want to add on to the point Steven has brought up.
>
> With "Stage and Delete N" approach, we have the following sequence of
> tasks for trimming the IMA log:
>
> 1. User mode locks the IMA measurement list through the "write interface".
> a. While this prevents any other user mode process from updating the
> IMA log, kernel can still add new IMA events to the measurement log
> 2. User mode reads the TPM Quote and the IMA measurement events and
> sends it to the remote attestation service
> 3. Once the remote service has successfully processed the IMA events,
> the user mode determines the number of IMA events "N" to be removed from
> the measurement list maintained in the kernel
> 4. User mode provides the value "N" to the kernel
> 5. Kernel now determines the point at which to snap the IMA measurement
> list using "N" - without holding a lock
> 6. Then, the kernel lock is held and the list is snapped at the point
> determined in the previous step thus keeping the kernel lock time to the
> minimum.
> 7. Now, user mode removes the "write" lock on the IMA measurement list
>
> With the above, we believe "Stage and Delete N" alone is sufficient to
> trim IMA log.
Prior versions of removing measurement records (aka "trimming") were rejected
for being overly complicated, locking, requiring a new record type, and code
quality. Patch 11 ("stage and delete N") is much better, but the level of
precision in removing only those measurements records needed for the TPM quote
seems necessary only if the records are not being saved.
The reason for the two methods might be the same — removing measurement records
from the IMA measurement list — but the motivation for the two methods does not
appear to be the same. The motivation for Patch 9 ("stage and delete") is
clearly to free kernel memory by exporting and saving the measurement records.
Remember, the only reason for upstreaming a feature to remove measurement
records from the IMA measurement list is to address the kernel memory issue —
clearly not to drop measurement records and break attestation.
Upstreaming patch 11 (stage and delete N) would be a concession for your
environment, but is definitely not the recommended solution.
Mimi
^ permalink raw reply
* Re: [PATCH v5 12/13] ima: Return error on deleting measurements already copied during kexec
From: Mimi Zohar @ 2026-05-26 14:02 UTC (permalink / raw)
To: Roberto Sassu, corbet, skhan, dmitry.kasatkin, eric.snowberg,
paul, jmorris, serge
Cc: linux-doc, linux-kernel, linux-integrity, linux-security-module,
gregorylumen, chenste, nramas, Roberto Sassu
In-Reply-To: <20260429160319.4162918-13-roberto.sassu@huaweicloud.com>
On Wed, 2026-04-29 at 18:03 +0200, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Refuse to delete staged or active list measurements, if a kexec racing with
> the deletion already copied those measurements in the kexec buffer. In this
> way, user space becomes aware that those measurements are going to appear
> in the secondary kernel, and thus they don't have to be saved twice.
There are two reboot notifiers: one to prevent additional measurements extending
the TPM, while the other copies the measurements for kexec. This patch prevents
deleting the staged measurements after the latter notifier.
Instead of introducing a specific method for detecting whether the measurement
list has been copied, rely on one of the two existing reboot notifiers. The
simplest method would test "ima_measurements_suspended", which would prevent
deleting the staged measurements a bit earlier.
Mimi
^ permalink raw reply
* Re: [PATCH] tomoyo: Fix NULL pointer dereference in tomoyo_init_request_info() when domain is NULL
From: Jiakai Xu @ 2026-05-26 13:58 UTC (permalink / raw)
To: penguin-kernel
Cc: jmorris, linux-kernel, linux-security-module, paul, serge,
takedakn, xujiakai24
In-Reply-To: <814a7f61-67b2-49e9-b5bf-fd049b458079@I-love.SAKURA.ne.jp>
> Thank you for a patch, but I don't think we need this change.
Thanks for your review! I understand your perspective, but I believe
the crash is a real NULL pointer dereference, and I'd like to explain
why the defensive check is warranted.
> TOMOYO's initial domain is &tomoyo_kernel_domain, and each thread belongs to
> a non-NULL domain. Therefore, tomoyo_domain() is not supposed to return NULL.
While tomoyo_domain() is not supposed to return NULL under normal
operation, there are code paths that leave s->domain_info == NULL:
a) Pre-init window (security/tomoyo/tomoyo.c, lines 598-612):
The task security blob is zero-allocated via kzalloc(), and
security_add_hooks() at line 603 is called BEFORE
s->domain_info = &tomoyo_kernel_domain at line 606. If any LSM
hook fires during that window, tomoyo_domain() returns NULL.
b) tomoyo_task_free() (tomoyo.c, lines 533-545) explicitly sets
s->domain_info = NULL after decrementing the refcount.
c) tomoyo_find_next_domain() (domain.c, lines 876-883) writes
s->domain_info = NULL when the domain transition fails.
> > Found by fuzzing. Here is the report:
> >
> > Unable to handle kernel paging request at virtual address dfffffff00000003
>
> Is this a NULL pointer dereference?
> It seems to me that this is just a random memory corruption.
This address is the KASAN shadow byte for memory access at offset 0x18
(24), not a random corrupted value. On RISC-V with sv57 page table,
KASAN_SHADOW_BASE is `0xdfffffff00000000`, and the shadow address is
computed as:
shadow_addr = (access_addr >> 3) + KASAN_SHADOW_BASE
= (24 >> 3) + 0xdfffffff00000000
= 0xdfffffff00000003
In `struct tomoyo_domain_info` (security/tomoyo/common.h, lines
680-693), the layout is:
offset 0: struct list_head list; // 16 bytes
offset 16: struct list_head acl_info_list; // 16 bytes (next at 16, prev at 24)
offset 32: domainname; // 8 bytes
...
Offset 24 from NULL is `domain->acl_info_list.prev`, which is
dereferenced by the `list_for_each_entry_rcu()` loop in
`tomoyo_check_acl()` at security/tomoyo/domain.c:171 when `domain` is
NULL. This is KASAN catching a NULL pointer dereference in action, not
random memory corruption.
I think adding a NULL check makes the code more robust. What do you
think?
Best regards,
Jiakai
^ permalink raw reply
* Re: [PATCH v5 10/14] module: Prepare for additional module authentication mechanisms
From: Petr Pavlu @ 2026-05-26 13:14 UTC (permalink / raw)
To: Thomas Weißschuh
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Nathan Chancellor,
Nicolas Schier, Arnd Bergmann, Luis Chamberlain, Sami Tolvanen,
Daniel Gomez, Paul Moore, James Morris, Serge E. Hallyn,
Jonathan Corbet, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Naveen N Rao, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin, Eric Snowberg, Nicolas Schier, Daniel Gomez,
Aaron Tomlin, Christophe Leroy (CS GROUP), Nicolas Bouchinet,
Xiu Jianfeng, Martin KaFai Lau, Song Liu, Yonghong Song,
Jiri Olsa, bpf, Fabian Grünbichler, Arnout Engelen,
Mattia Rizzolo, kpcyrd, Christian Heusel, Câju Mihai-Drosi,
Eric Biggers, Sebastian Andrzej Siewior, linux-kbuild,
linux-kernel, linux-arch, linux-modules, linux-security-module,
linux-doc, linuxppc-dev, linux-integrity, debian-kernel
In-Reply-To: <20260505-module-hashes-v5-10-e174a5a49fce@weissschuh.net>
On 5/5/26 11:05 AM, Thomas Weißschuh wrote:
> Reorganize the code to make it easier to add the new hash-based module
> authentication.
>
> Also drop the now unnecessary stub for module_sig_check().
>
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
Reviewed-by: Petr Pavlu <petr.pavlu@suse.com>
-- Petr
^ permalink raw reply
* Re: [PATCH v5 09/14] module: Move signature type check out of mod_check_sig()
From: Petr Pavlu @ 2026-05-26 13:03 UTC (permalink / raw)
To: Thomas Weißschuh
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Nathan Chancellor,
Nicolas Schier, Arnd Bergmann, Luis Chamberlain, Sami Tolvanen,
Daniel Gomez, Paul Moore, James Morris, Serge E. Hallyn,
Jonathan Corbet, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Naveen N Rao, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin, Eric Snowberg, Nicolas Schier, Daniel Gomez,
Aaron Tomlin, Christophe Leroy (CS GROUP), Nicolas Bouchinet,
Xiu Jianfeng, Martin KaFai Lau, Song Liu, Yonghong Song,
Jiri Olsa, bpf, Fabian Grünbichler, Arnout Engelen,
Mattia Rizzolo, kpcyrd, Christian Heusel, Câju Mihai-Drosi,
Eric Biggers, Sebastian Andrzej Siewior, linux-kbuild,
linux-kernel, linux-arch, linux-modules, linux-security-module,
linux-doc, linuxppc-dev, linux-integrity, debian-kernel
In-Reply-To: <20260505-module-hashes-v5-9-e174a5a49fce@weissschuh.net>
On 5/5/26 11:05 AM, Thomas Weißschuh wrote:
> Additional signature types are about to be added.
> As each caller of mod_check_sig() can have different support for these,
> move the type validation into the callers.
>
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
Reviewed-by: Petr Pavlu <petr.pavlu@suse.com>
-- Petr
^ permalink raw reply
* Re: [PATCH v5 07/14] module: Make module authentication usable without MODULE_SIG
From: kpcyrd @ 2026-05-26 12:27 UTC (permalink / raw)
To: Thomas Weißschuh, Petr Pavlu
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Nathan Chancellor,
Nicolas Schier, Arnd Bergmann, Luis Chamberlain, Sami Tolvanen,
Daniel Gomez, Paul Moore, James Morris, Serge E. Hallyn,
Jonathan Corbet, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Naveen N Rao, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin, Eric Snowberg, Nicolas Schier, Daniel Gomez,
Aaron Tomlin, Christophe Leroy (CS GROUP), Nicolas Bouchinet,
Xiu Jianfeng, Martin KaFai Lau, Song Liu, Yonghong Song,
Jiri Olsa, bpf, Fabian Grünbichler, Arnout Engelen,
Mattia Rizzolo, Christian Heusel, Câju Mihai-Drosi,
Eric Biggers, Sebastian Andrzej Siewior, linux-kbuild,
linux-kernel, linux-arch, linux-modules, linux-security-module,
linux-doc, linuxppc-dev, linux-integrity, debian-kernel,
Holger Levsen
In-Reply-To: <4ee3c775-1fbf-45e1-8b77-5f9034f45125@t-8ch.de>
On 5/26/26 1:38 PM, Thomas Weißschuh wrote:
> On 2026-05-26 12:53:22+0200, Petr Pavlu wrote:
>> Should MODULE_SIG_FORCE be renamed to MODULE_AUTH_FORCE, along with
>> renaming the sig_enforce functionality in kernel/module/auth.c to
>> auth_enforce?
>
> Given that it is a user-visible symbol we'll need to be a bit careful
> not to break existing configurations.
> I'll try to use the new "transitional" kconfig attribute.
A slightly softer worded alternative (yet semantically equivalent) name could be
MODULE_AUTH_REQUIRE. No strong opinion though, I think MODULE_AUTH_* does make
sense.
I initially shared the concern about renaming well established config options,
but the transitional feature does seem to be a good fit for this.
Sincerely,
kpcyrd
^ permalink raw reply
* Re: [PATCH v5 08/14] module: Move authentication logic into dedicated new file
From: Petr Pavlu @ 2026-05-26 11:58 UTC (permalink / raw)
To: Thomas Weißschuh
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Nathan Chancellor,
Nicolas Schier, Arnd Bergmann, Luis Chamberlain, Sami Tolvanen,
Daniel Gomez, Paul Moore, James Morris, Serge E. Hallyn,
Jonathan Corbet, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Naveen N Rao, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin, Eric Snowberg, Nicolas Schier, Daniel Gomez,
Aaron Tomlin, Christophe Leroy (CS GROUP), Nicolas Bouchinet,
Xiu Jianfeng, Martin KaFai Lau, Song Liu, Yonghong Song,
Jiri Olsa, bpf, Fabian Grünbichler, Arnout Engelen,
Mattia Rizzolo, kpcyrd, Christian Heusel, Câju Mihai-Drosi,
Eric Biggers, Sebastian Andrzej Siewior, linux-kbuild,
linux-kernel, linux-arch, linux-modules, linux-security-module,
linux-doc, linuxppc-dev, linux-integrity, debian-kernel
In-Reply-To: <20260505-module-hashes-v5-8-e174a5a49fce@weissschuh.net>
On 5/5/26 11:05 AM, Thomas Weißschuh wrote:
> The module authentication functionality will also be used by the
> hash-based module authentication. To make it usable even if
> CONFIG_MODULE_SIG is disabled, move it to a new file.
>
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> ---
> [...]
> diff --git a/kernel/module/auth.c b/kernel/module/auth.c
> index 956ac63d9d33..831a13eb0c9b 100644
> --- a/kernel/module/auth.c
> +++ b/kernel/module/auth.c
> @@ -5,10 +5,16 @@
> * Written by David Howells (dhowells@redhat.com)
> */
>
> +#include <linux/errno.h>
> #include <linux/export.h>
> #include <linux/module.h>
> +#include <linux/module_signature.h>
> #include <linux/moduleparam.h>
> +#include <linux/security.h>
> +#include <linux/string.h>
> #include <linux/types.h>
> +#include <uapi/linux/module.h>
> +#include "internal.h"
>
> #undef MODULE_PARAM_PREFIX
> #define MODULE_PARAM_PREFIX "module."
> @@ -30,3 +36,82 @@ void set_module_sig_enforced(void)
> {
> sig_enforce = true;
> }
> +
> +static int mod_verify_sig(const void *mod, struct load_info *info)
> +{
> + struct module_signature ms;
> + size_t sig_len, modlen = info->len;
> + int ret;
> +
> + if (modlen <= sizeof(ms))
> + return -EBADMSG;
> +
> + memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
> +
> + ret = mod_check_sig(&ms, modlen, "module");
> + if (ret)
> + return ret;
> +
> + sig_len = be32_to_cpu(ms.sig_len);
> + modlen -= sig_len + sizeof(ms);
> + info->len = modlen;
> +
> + return module_sig_check(mod, modlen, mod + modlen, sig_len);
> +}
> +
> +int module_auth_check(struct load_info *info, int flags)
> +{
> + int err = -ENODATA;
> + const unsigned long markerlen = sizeof(MODULE_SIGNATURE_MARKER) - 1;
> + const char *reason;
> + const void *mod = info->hdr;
> + bool mangled_module = flags & (MODULE_INIT_IGNORE_MODVERSIONS |
> + MODULE_INIT_IGNORE_VERMAGIC);
> + /*
> + * Do not allow mangled modules as a module with version information
> + * removed is no longer the module that was signed.
> + */
> + if (!mangled_module &&
> + info->len > markerlen &&
> + memcmp(mod + info->len - markerlen, MODULE_SIGNATURE_MARKER, markerlen) == 0) {
> + /* We truncate the module to discard the signature */
> + info->len -= markerlen;
> + err = mod_verify_sig(mod, info);
> + if (!err) {
> + info->auth_ok = true;
> + return 0;
> + }
> + }
> +
> + /*
> + * We don't permit modules to be loaded into the trusted kernels
> + * without a valid signature on them, but if we're not enforcing,
> + * certain errors are non-fatal.
> + */
> + switch (err) {
> + case -ENODATA:
> + reason = "unsigned module";
> + break;
> + case -ENOPKG:
> + reason = "module with unsupported crypto";
> + break;
> + case -ENOKEY:
> + reason = "module with unavailable key";
> + break;
> +
> + default:
> + /*
> + * All other errors are fatal, including lack of memory,
> + * unparseable signatures, and signature check failures --
> + * even if signatures aren't required.
> + */
> + return err;
> + }
> +
> + if (is_module_sig_enforced()) {
> + pr_notice("Loading of %s is rejected\n", reason);
> + return -EKEYREJECTED;
> + }
> +
> + return security_locked_down(LOCKDOWN_MODULE_SIGNATURE);
> +}
The resulting call chain of the module authentication/signature
functions is as follows:
ima_read_modsig() -----------------------------,
v
module_auth_check() -> mod_verify_sig() -> mod_check_sig()
|
|-> module_sig_check()
'-> module_hash_check()
I think this logic is quite hard to follow because mod_verify_sig(),
mod_check_sig() and module_sig_check() have very similar names.
The naming of module_auth_check(), module_sig_check() and
module_hash_check() looks good to me, but I would prefer to rename
mod_check_sig() and mod_verify_sig(). Perhaps mod_check_sig() could be
renamed to mod_check_sig_header(), and mod_verify_sig() to
mod_dispatch_auth_check()?
Otherwise, the patch looks ok to me. Feel free to add:
Reviewed-by: Petr Pavlu <petr.pavlu@suse.com>
--
Thanks,
Petr
^ permalink raw reply
* Re: [PATCH v5 07/14] module: Make module authentication usable without MODULE_SIG
From: Thomas Weißschuh @ 2026-05-26 11:38 UTC (permalink / raw)
To: Petr Pavlu
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Nathan Chancellor,
Nicolas Schier, Arnd Bergmann, Luis Chamberlain, Sami Tolvanen,
Daniel Gomez, Paul Moore, James Morris, Serge E. Hallyn,
Jonathan Corbet, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Naveen N Rao, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin, Eric Snowberg, Nicolas Schier, Daniel Gomez,
Aaron Tomlin, Christophe Leroy (CS GROUP), Nicolas Bouchinet,
Xiu Jianfeng, Martin KaFai Lau, Song Liu, Yonghong Song,
Jiri Olsa, bpf, Fabian Grünbichler, Arnout Engelen,
Mattia Rizzolo, kpcyrd, Christian Heusel, Câju Mihai-Drosi,
Eric Biggers, Sebastian Andrzej Siewior, linux-kbuild,
linux-kernel, linux-arch, linux-modules, linux-security-module,
linux-doc, linuxppc-dev, linux-integrity, debian-kernel
In-Reply-To: <0a0736a4-2cdd-49f2-9062-e2f18d769fc0@suse.com>
On 2026-05-26 12:53:22+0200, Petr Pavlu wrote:
> On 5/5/26 11:05 AM, Thomas Weißschuh wrote:
> > The module authentication functionality will also be used by the
> > hash-based module authentication. Split it out from CONFIG_MODULE_SIG
> > so it is usable by both.
> >
> > Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> > [...]
> > diff --git a/kernel/module/Kconfig b/kernel/module/Kconfig
> > index f535181e0d98..84297da666ff 100644
> > --- a/kernel/module/Kconfig
> > +++ b/kernel/module/Kconfig
> > @@ -271,9 +271,12 @@ config MODULE_SIG
> > debuginfo strip done by some packagers (such as rpmbuild) and
> > inclusion into an initramfs that wants the module size reduced.
> >
> > +config MODULE_AUTH
> > + def_bool MODULE_SIG
> > +
> > config MODULE_SIG_FORCE
> > bool "Require modules to be validly signed"
> > - depends on MODULE_SIG
> > + depends on MODULE_AUTH
> > help
> > Reject unsigned modules or signed modules for which we don't have a
> > key. Without this, such modules will simply taint the kernel.
>
> Should MODULE_SIG_FORCE be renamed to MODULE_AUTH_FORCE, along with
> renaming the sig_enforce functionality in kernel/module/auth.c to
> auth_enforce?
Given that it is a user-visible symbol we'll need to be a bit careful
not to break existing configurations.
I'll try to use the new "transitional" kconfig attribute.
Thomas
^ permalink raw reply
* Re: [PATCH v5 06/14] module: Switch load_info::len to size_t
From: Thomas Weißschuh @ 2026-05-26 11:35 UTC (permalink / raw)
To: Petr Pavlu
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Nathan Chancellor,
Nicolas Schier, Arnd Bergmann, Luis Chamberlain, Sami Tolvanen,
Daniel Gomez, Paul Moore, James Morris, Serge E. Hallyn,
Jonathan Corbet, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Naveen N Rao, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin, Eric Snowberg, Nicolas Schier, Daniel Gomez,
Aaron Tomlin, Christophe Leroy (CS GROUP), Nicolas Bouchinet,
Xiu Jianfeng, Martin KaFai Lau, Song Liu, Yonghong Song,
Jiri Olsa, bpf, Fabian Grünbichler, Arnout Engelen,
Mattia Rizzolo, kpcyrd, Christian Heusel, Câju Mihai-Drosi,
Eric Biggers, Sebastian Andrzej Siewior, linux-kbuild,
linux-kernel, linux-arch, linux-modules, linux-security-module,
linux-doc, linuxppc-dev, linux-integrity, debian-kernel
In-Reply-To: <8de0e6ad-987a-4729-bbd0-8399968dbb48@suse.com>
On 2026-05-26 11:47:09+0200, Petr Pavlu wrote:
> On 5/5/26 11:05 AM, Thomas Weißschuh wrote:
> > Switching the types will make some later changes cleaner.
>
> Since the updated version drops the patch "module: Deduplicate signature
> extraction", I believe this change is no longer necessary.
Ack.
(...)
Thomas
^ permalink raw reply
* Re: [PATCH v5 11/13] ima: Support staging and deleting N measurements entries
From: Mimi Zohar @ 2026-05-26 11:08 UTC (permalink / raw)
To: Roberto Sassu, corbet, skhan, dmitry.kasatkin, eric.snowberg,
paul, jmorris, serge
Cc: linux-doc, linux-kernel, linux-integrity, linux-security-module,
gregorylumen, chenste, nramas, Roberto Sassu
In-Reply-To: <20260429160319.4162918-12-roberto.sassu@huaweicloud.com>
On Wed, 2026-04-29 at 18:03 +0200, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Add support for sending a value N between 1 and ULONG_MAX to the IMA
> original measurement interface. This value represents the number of
> measurements that should be deleted from the current measurements list. In
> this case, measurements are staged in an internal non-user visible list,
> and immediately deleted.
>
> This staging method allows the remote attestation agents to easily separate
> the measurements that were verified (staged and deleted) from those that
> weren't due to the race between taking a TPM quote and reading the
> measurements list.
The reason for removing records from the IMA measurement list is to free kernel
memory. However, the level of precision in removing only those measurements
needed for the quote seems necessary only if the measurement records are not
being saved. Upstreaming a feature to remove measurement records from the IMA
measurement list is to address the kernel memory issue — clearly not to drop
measurement records and break attestation.
>
> In order to minimize the locking time of ima_extend_list_mutex, deleting
> N entries is realized by doing a lockless walk in the current measurements
> list to determine the N-th entry to cut, to cut the current measurements
> list under the lock, and by deleting the excess entries after releasing the
> lock.
>
> Flushing the hash table is not supported for N entries, since it would
> require removing the N entries one by one from the hash table under the
> ima_extend_list_mutex lock, which would increase the locking time.
>
> The ima_extend_list_mutex lock is necessary in ima_dump_measurement_list()
> because ima_queue_delete_partial() uses __list_cut_position() to modify
> ima_measurements, for which no RCU-safe variant exists. For the staging
> with prompt flavor alone, list_replace_rcu() could have been used instead,
> but since both flavors share the same kexec serialization path, the mutex
> is required regardless.
Thank you for the clear explanation for the changes and limitations required to
support this feature.
The changes needed for supporting "stage and delete N" measurement records
should be limited to this patch. Patch 9/13 should have used
list_replace_rcu(), without the mutex_lock.
>
> Link: https://github.com/linux-integrity/linux/issues/1
> Suggested-by: Steven Chen <chenste@linux.microsoft.com>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Otherwise,
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
^ permalink raw reply
* Re: [PATCH v5 07/14] module: Make module authentication usable without MODULE_SIG
From: Petr Pavlu @ 2026-05-26 10:53 UTC (permalink / raw)
To: Thomas Weißschuh
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Nathan Chancellor,
Nicolas Schier, Arnd Bergmann, Luis Chamberlain, Sami Tolvanen,
Daniel Gomez, Paul Moore, James Morris, Serge E. Hallyn,
Jonathan Corbet, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Naveen N Rao, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin, Eric Snowberg, Nicolas Schier, Daniel Gomez,
Aaron Tomlin, Christophe Leroy (CS GROUP), Nicolas Bouchinet,
Xiu Jianfeng, Martin KaFai Lau, Song Liu, Yonghong Song,
Jiri Olsa, bpf, Fabian Grünbichler, Arnout Engelen,
Mattia Rizzolo, kpcyrd, Christian Heusel, Câju Mihai-Drosi,
Eric Biggers, Sebastian Andrzej Siewior, linux-kbuild,
linux-kernel, linux-arch, linux-modules, linux-security-module,
linux-doc, linuxppc-dev, linux-integrity, debian-kernel
In-Reply-To: <20260505-module-hashes-v5-7-e174a5a49fce@weissschuh.net>
On 5/5/26 11:05 AM, Thomas Weißschuh wrote:
> The module authentication functionality will also be used by the
> hash-based module authentication. Split it out from CONFIG_MODULE_SIG
> so it is usable by both.
>
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> [...]
> diff --git a/kernel/module/Kconfig b/kernel/module/Kconfig
> index f535181e0d98..84297da666ff 100644
> --- a/kernel/module/Kconfig
> +++ b/kernel/module/Kconfig
> @@ -271,9 +271,12 @@ config MODULE_SIG
> debuginfo strip done by some packagers (such as rpmbuild) and
> inclusion into an initramfs that wants the module size reduced.
>
> +config MODULE_AUTH
> + def_bool MODULE_SIG
> +
> config MODULE_SIG_FORCE
> bool "Require modules to be validly signed"
> - depends on MODULE_SIG
> + depends on MODULE_AUTH
> help
> Reject unsigned modules or signed modules for which we don't have a
> key. Without this, such modules will simply taint the kernel.
Should MODULE_SIG_FORCE be renamed to MODULE_AUTH_FORCE, along with
renaming the sig_enforce functionality in kernel/module/auth.c to
auth_enforce?
--
Thanks,
Petr
^ permalink raw reply
* Re: [PATCH] firmware: arm_ffa: Treat missing FF-A feature on a platform as a probe miss
From: Yeoreum Yun @ 2026-05-26 10:51 UTC (permalink / raw)
To: Sudeep Holla
Cc: linux-security-module, linux-kernel, linux-integrity,
linux-arm-kernel, kvmarm, Nathan Chancellor
In-Reply-To: <20260526103649.5684-1-sudeep.holla@kernel.org>
LGTM.
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
On Tue, May 26, 2026 at 11:36:49AM +0100, Sudeep Holla wrote:
> When FF-A initialisation is driven from a platform device probe, systems
> that do not implement FF-A can return -EOPNOTSUPP from the early transport
> or version discovery paths. Driver core treats that as a matched probe
> failure and prints:
>
> | arm-ffa arm-ffa: probe with driver arm-ffa failed with error -95
>
> That is noisy for a firmware interface that can be absent on otherwise
> valid systems. Driver core already treats -ENODEV and -ENXIO as quiet
> rejected matches, so translate only the early unsupported discovery cases
> to -ENODEV. Keep later setup failures unchanged so real FF-A
> initialisation problems are still reported as probe failures.
>
> Reported-by: Nathan Chancellor <nathan@kernel.org>
> Closes: https://lore.kernel.org/all/20260523001148.GA1319283@ax162
> Signed-off-by: Sudeep Holla <sudeep.holla@kernel.org>
> ---
> drivers/firmware/arm_ffa/driver.c | 7 +++++--
> 1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
> index 54984e1b9741..0f468362c288 100644
> --- a/drivers/firmware/arm_ffa/driver.c
> +++ b/drivers/firmware/arm_ffa/driver.c
> @@ -2109,7 +2109,7 @@ static int ffa_probe(struct platform_device *pdev)
>
> ret = ffa_transport_init(&invoke_ffa_fn);
> if (ret)
> - return ret;
> + return ret == -EOPNOTSUPP ? -ENODEV : ret;
>
> drv_info = kzalloc_obj(*drv_info);
> if (!drv_info)
> @@ -2117,8 +2117,11 @@ static int ffa_probe(struct platform_device *pdev)
> platform_set_drvdata(pdev, drv_info);
>
> ret = ffa_version_check(&drv_info->version);
> - if (ret)
> + if (ret) {
> + if (ret == -EOPNOTSUPP)
> + ret = -ENODEV;
> goto free_drv_info;
> + }
>
> if (ffa_id_get(&drv_info->vm_id)) {
> pr_err("failed to obtain VM id for self\n");
> --
> 2.43.0
>
--
Sincerely,
Yeoreum Yun
^ permalink raw reply
* Re: [PATCH v2 10/17] landlock: Set audit_net.sk for socket access checks
From: Mickaël Salaün @ 2026-05-26 10:42 UTC (permalink / raw)
To: Christian Brauner, Günther Noack, Steven Rostedt
Cc: Jann Horn, Jeff Xu, Justin Suess, Kees Cook, Masami Hiramatsu,
Mathieu Desnoyers, Matthieu Buffet, Mikhail Ivanov, Tingmao Wang,
kernel-team, linux-fsdevel, linux-security-module,
linux-trace-kernel, stable
In-Reply-To: <20260406143717.1815792-11-mic@digikod.net>
I merged this fix in the -next branch.
On Mon, Apr 06, 2026 at 04:37:08PM +0200, Mickaël Salaün wrote:
> Set audit_net.sk in current_check_access_socket() to provide the socket
> object to audit_log_lsm_data(). This makes Landlock consistent with
> AppArmor, which always sets .sk for socket operations, and with
> SELinux's generic socket permission checks.
>
> The socket's local and foreign address information (laddr, lport, faddr,
> fport) is logged by the shared lsm_audit.c infrastructure when the
> socket has bound or connected state. Fields with zero values are
> suppressed by print_ipv4_addr()/print_ipv6_addr(), so the audit output
> is unchanged for the common case of bind denials on unbound sockets.
> For connect denials after a prior bind, the bound local address (laddr,
> lport) appears before the existing sockaddr fields (daddr, dest).
>
> No existing fields are removed or reordered, and the new field names
> (laddr, lport, faddr, fport) are standard audit fields already emitted
> by other LSMs through the same lsm_audit.c code path.
>
> Add net_bind and net_connect audit tests. The net_bind test verifies
> basic net denial auditing. The net_connect test binds to an allowed
> port, then connects to a denied port, and verifies that the audit record
> includes laddr/lport from the socket state.
>
> Fixes: 9f74411a40ce ("landlock: Log TCP bind and connect denials")
> Cc: stable@vger.kernel.org
> Cc: Günther Noack <gnoack@google.com>
> Signed-off-by: Mickaël Salaün <mic@digikod.net>
> ---
>
> Changes since v1:
> - New patch.
> ---
> security/landlock/net.c | 1 +
> tools/testing/selftests/landlock/audit_test.c | 187 ++++++++++++++++++
> 2 files changed, 188 insertions(+)
>
> diff --git a/security/landlock/net.c b/security/landlock/net.c
> index a2aefc7967a1..d8bc9e0d012a 100644
> --- a/security/landlock/net.c
> +++ b/security/landlock/net.c
> @@ -225,6 +225,7 @@ static int current_check_access_socket(struct socket *const sock,
> return 0;
>
> audit_net.family = address->sa_family;
> + audit_net.sk = sock->sk;
> landlock_log_denial(subject,
> &(struct landlock_request){
> .type = LANDLOCK_REQUEST_NET_ACCESS,
> diff --git a/tools/testing/selftests/landlock/audit_test.c b/tools/testing/selftests/landlock/audit_test.c
> index da0bfd06391e..65dfb272c825 100644
> --- a/tools/testing/selftests/landlock/audit_test.c
> +++ b/tools/testing/selftests/landlock/audit_test.c
> @@ -6,14 +6,17 @@
> */
>
> #define _GNU_SOURCE
> +#include <arpa/inet.h>
> #include <errno.h>
> #include <fcntl.h>
> #include <limits.h>
> #include <linux/landlock.h>
> +#include <netinet/in.h>
> #include <pthread.h>
> #include <stdlib.h>
> #include <sys/mount.h>
> #include <sys/prctl.h>
> +#include <sys/socket.h>
> #include <sys/types.h>
> #include <sys/wait.h>
> #include <unistd.h>
> @@ -160,6 +163,190 @@ TEST_F(audit, layers)
> EXPECT_EQ(0, close(ruleset_fd));
> }
>
> +static int matches_log_net_bind(struct __test_metadata *const _metadata,
> + int audit_fd, __u16 port, __u64 *domain_id)
> +{
> + /*
> + * The socket is unbound at bind() time, so laddr/lport/faddr/fport from
> + * the socket object are zero and not printed. Only the sockaddr fields
> + * (src) appear.
> + */
> + static const char log_template[] = REGEX_LANDLOCK_PREFIX
> + " blockers=net\\.bind_tcp src=%u$";
> + char log_match[sizeof(log_template) + 10];
> +
> + snprintf(log_match, sizeof(log_match), log_template, port);
> + return audit_match_record(audit_fd, AUDIT_LANDLOCK_ACCESS, log_match,
> + domain_id);
> +}
> +
> +/*
> + * Verifies that network denial audit records include enriched socket
> + * information (laddr/lport/faddr/fport) from the socket object.
> + */
> +TEST_F(audit, net_bind)
> +{
> + const struct landlock_ruleset_attr ruleset_attr = {
> + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP,
> + };
> + struct landlock_net_port_attr net_port = {
> + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
> + .port = 1024,
> + };
> + int status, ruleset_fd;
> + pid_t child;
> + __u64 denial_dom = 1;
> +
> + ruleset_fd =
> + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
> + ASSERT_LE(0, ruleset_fd);
> +
> + /* Allow port 1024 only. */
> + ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
> + &net_port, 0));
> +
> + EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
> +
> + child = fork();
> + ASSERT_LE(0, child);
> + if (child == 0) {
> + struct sockaddr_in addr = {
> + .sin_family = AF_INET,
> + .sin_port = htons(1025),
> + .sin_addr.s_addr = htonl(INADDR_ANY),
> + };
> + int sock_fd;
> +
> + EXPECT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
> + close(ruleset_fd);
> +
> + /* Bind to port 1025 (not allowed). */
> + sock_fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
> + ASSERT_LE(0, sock_fd);
> + EXPECT_EQ(-1, bind(sock_fd, (struct sockaddr *)&addr,
> + sizeof(addr)));
> + EXPECT_EQ(EACCES, errno);
> + close(sock_fd);
> +
> + /* Verify audit record with enriched socket info. */
> + EXPECT_EQ(0, matches_log_net_bind(_metadata, self->audit_fd,
> + 1025, &denial_dom));
> + EXPECT_NE(denial_dom, 1);
> + EXPECT_NE(denial_dom, 0);
> +
> + _exit(_metadata->exit_code);
> + return;
> + }
> +
> + ASSERT_EQ(child, waitpid(child, &status, 0));
> + if (WIFSIGNALED(status) || !WIFEXITED(status) ||
> + WEXITSTATUS(status) != EXIT_SUCCESS)
> + _metadata->exit_code = KSFT_FAIL;
> +
> + EXPECT_EQ(0, close(ruleset_fd));
> +}
> +
> +static int matches_log_net_connect(struct __test_metadata *const _metadata,
> + int audit_fd, __u16 denied_port,
> + __u16 bound_port, __u64 *domain_id)
> +{
> + /*
> + * After bind(), the socket has local address state. The audit record
> + * should include laddr/lport from the socket (via audit_net.sk) and
> + * daddr/dest from the connect sockaddr.
> + */
> + static const char log_template[] = REGEX_LANDLOCK_PREFIX
> + " blockers=net\\.connect_tcp"
> + " laddr=127\\.0\\.0\\.1 lport=%u"
> + " daddr=127\\.0\\.0\\.1 dest=%u$";
> + char log_match[sizeof(log_template) + 20];
> +
> + snprintf(log_match, sizeof(log_match), log_template, bound_port,
> + denied_port);
> + return audit_match_record(audit_fd, AUDIT_LANDLOCK_ACCESS, log_match,
> + domain_id);
> +}
> +
> +/*
> + * Verifies that network denial audit records for connect include enriched
> + * socket information (laddr/lport) from the socket object after a prior bind.
> + * This complements net_bind which tests the unbound case.
> + */
> +TEST_F(audit, net_connect)
> +{
> + const struct landlock_ruleset_attr ruleset_attr = {
> + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
> + LANDLOCK_ACCESS_NET_CONNECT_TCP,
> + };
> + struct landlock_net_port_attr net_port;
> + int status, ruleset_fd;
> + pid_t child;
> + __u64 denial_dom = 1;
> +
> + ruleset_fd =
> + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
> + ASSERT_LE(0, ruleset_fd);
> +
> + /* Allow bind to port 1024 and connect to port 1024. */
> + net_port.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
> + LANDLOCK_ACCESS_NET_CONNECT_TCP;
> + net_port.port = 1024;
> + ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
> + &net_port, 0));
> +
> + EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
> +
> + child = fork();
> + ASSERT_LE(0, child);
> + if (child == 0) {
> + struct sockaddr_in bind_addr = {
> + .sin_family = AF_INET,
> + .sin_port = htons(1024),
> + .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
> + };
> + struct sockaddr_in conn_addr = {
> + .sin_family = AF_INET,
> + .sin_port = htons(1025),
> + .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
> + };
> + int sock_fd, optval = 1;
> +
> + EXPECT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
> + close(ruleset_fd);
> +
> + sock_fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
> + ASSERT_LE(0, sock_fd);
> + ASSERT_EQ(0, setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
> + &optval, sizeof(optval)));
> +
> + /* Bind to allowed port 1024 (succeeds). */
> + ASSERT_EQ(0, bind(sock_fd, (struct sockaddr *)&bind_addr,
> + sizeof(bind_addr)));
> +
> + /* Connect to denied port 1025 (fails). */
> + EXPECT_EQ(-1, connect(sock_fd, (struct sockaddr *)&conn_addr,
> + sizeof(conn_addr)));
> + EXPECT_EQ(EACCES, errno);
> + close(sock_fd);
> +
> + /* Verify audit record with laddr/lport from bound socket. */
> + EXPECT_EQ(0, matches_log_net_connect(_metadata, self->audit_fd,
> + 1025, 1024, &denial_dom));
> + EXPECT_NE(denial_dom, 1);
> + EXPECT_NE(denial_dom, 0);
> +
> + _exit(_metadata->exit_code);
> + return;
> + }
> +
> + ASSERT_EQ(child, waitpid(child, &status, 0));
> + if (WIFSIGNALED(status) || !WIFEXITED(status) ||
> + WEXITSTATUS(status) != EXIT_SUCCESS)
> + _metadata->exit_code = KSFT_FAIL;
> +
> + EXPECT_EQ(0, close(ruleset_fd));
> +}
> +
> struct thread_data {
> pid_t parent_pid;
> int ruleset_fd, pipe_child, pipe_parent;
> --
> 2.53.0
>
>
^ permalink raw reply
* [PATCH] firmware: arm_ffa: Treat missing FF-A feature on a platform as a probe miss
From: Sudeep Holla @ 2026-05-26 10:36 UTC (permalink / raw)
To: linux-security-module, linux-kernel, linux-integrity,
linux-arm-kernel, kvmarm
Cc: Sudeep Holla, Yeoreum Yun, Nathan Chancellor
When FF-A initialisation is driven from a platform device probe, systems
that do not implement FF-A can return -EOPNOTSUPP from the early transport
or version discovery paths. Driver core treats that as a matched probe
failure and prints:
| arm-ffa arm-ffa: probe with driver arm-ffa failed with error -95
That is noisy for a firmware interface that can be absent on otherwise
valid systems. Driver core already treats -ENODEV and -ENXIO as quiet
rejected matches, so translate only the early unsupported discovery cases
to -ENODEV. Keep later setup failures unchanged so real FF-A
initialisation problems are still reported as probe failures.
Reported-by: Nathan Chancellor <nathan@kernel.org>
Closes: https://lore.kernel.org/all/20260523001148.GA1319283@ax162
Signed-off-by: Sudeep Holla <sudeep.holla@kernel.org>
---
drivers/firmware/arm_ffa/driver.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index 54984e1b9741..0f468362c288 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -2109,7 +2109,7 @@ static int ffa_probe(struct platform_device *pdev)
ret = ffa_transport_init(&invoke_ffa_fn);
if (ret)
- return ret;
+ return ret == -EOPNOTSUPP ? -ENODEV : ret;
drv_info = kzalloc_obj(*drv_info);
if (!drv_info)
@@ -2117,8 +2117,11 @@ static int ffa_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, drv_info);
ret = ffa_version_check(&drv_info->version);
- if (ret)
+ if (ret) {
+ if (ret == -EOPNOTSUPP)
+ ret = -ENODEV;
goto free_drv_info;
+ }
if (ffa_id_get(&drv_info->vm_id)) {
pr_err("failed to obtain VM id for self\n");
--
2.43.0
^ permalink raw reply related
* Re: [net-next] netlabel: validate unlabeled mask attribute length
From: Paolo Abeni @ 2026-05-26 10:35 UTC (permalink / raw)
To: Chenguang Zhao, Paul Moore, David S. Miller, Eric Dumazet,
Jakub Kicinski, Simon Horman
Cc: netdev, linux-security-module
In-Reply-To: <20260522054521.1169755-1-zhaochenguang@kylinos.cn>
On 5/22/26 7:45 AM, Chenguang Zhao wrote:
> netlbl_unlabel_addrinfo_get() checked the address length
> but allowed shorter mask attributes to pass through to
> fixed-size address reads.
>
> Signed-off-by: Chenguang Zhao <zhaochenguang@kylinos.cn>
> ---
> netlbl_unlabel_addrinfo_get() only rejected a mask
> length mismatch when the address attribute length
> was also invalid. A crafted Generic Netlink request
> could therefore provide a valid IPv4/IPv6 address
> attribute with a shorter mask attribute.
>
> NLA_BINARY policy lengths are maximum lengths,
> not exact lengths, so the short mask can pass
> policy validation. The mask is later read as
> a full struct in_addr or struct in6_addr.
> Require both address and mask attributes to
> have the exact expected size.
The above should be part of the commit message. Also this looks like a
fix that should target the 'net' tree and include a 'Fixes:' tag.
Thanks,
Paolo
^ permalink raw reply
* Re: [PATCH v5 06/14] module: Switch load_info::len to size_t
From: Petr Pavlu @ 2026-05-26 9:47 UTC (permalink / raw)
To: Thomas Weißschuh
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Nathan Chancellor,
Nicolas Schier, Arnd Bergmann, Luis Chamberlain, Sami Tolvanen,
Daniel Gomez, Paul Moore, James Morris, Serge E. Hallyn,
Jonathan Corbet, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Naveen N Rao, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin, Eric Snowberg, Nicolas Schier, Daniel Gomez,
Aaron Tomlin, Christophe Leroy (CS GROUP), Nicolas Bouchinet,
Xiu Jianfeng, Martin KaFai Lau, Song Liu, Yonghong Song,
Jiri Olsa, bpf, Fabian Grünbichler, Arnout Engelen,
Mattia Rizzolo, kpcyrd, Christian Heusel, Câju Mihai-Drosi,
Eric Biggers, Sebastian Andrzej Siewior, linux-kbuild,
linux-kernel, linux-arch, linux-modules, linux-security-module,
linux-doc, linuxppc-dev, linux-integrity, debian-kernel
In-Reply-To: <20260505-module-hashes-v5-6-e174a5a49fce@weissschuh.net>
On 5/5/26 11:05 AM, Thomas Weißschuh wrote:
> Switching the types will make some later changes cleaner.
Since the updated version drops the patch "module: Deduplicate signature
extraction", I believe this change is no longer necessary.
> size_t is also the semantically correct type for this field.
>
> As both 'size_t' and 'unsigned long' are always the same size, this
> should be risk-free.
The module 'len' would now start in init_module() as 'unsigned long',
then change in copy_module_from_user() to size_t, and then back to
'unsigned long' when calling copy_chunked_from_user(). The current code
is more consistent and mostly uses 'unsigned long', matching the syscall
interface.
--
Thanks,
Petr
^ permalink raw reply
* Re: [PATCH 2/4] firmware: arm_ffa: Register core as a platform driver
From: Sudeep Holla @ 2026-05-26 9:41 UTC (permalink / raw)
To: Nathan Chancellor
Cc: linux-security-module, linux-kernel, linux-integrity,
linux-arm-kernel, kvmarm, Yeoreum Yun
In-Reply-To: <20260523001148.GA1319283@ax162>
On Fri, May 22, 2026 at 05:11:48PM -0700, Nathan Chancellor wrote:
> Hi Sudeep,
>
> On Fri, May 08, 2026 at 06:54:16PM +0100, Sudeep Holla wrote:
> > Move the FF-A core bring-up and teardown paths into platform driver
> > probe and remove callbacks, and register a synthetic arm-ffa platform
> > device to bind the driver.
> >
> > This makes the FF-A core lifetime follow the driver model while keeping
> > the device creation internal to the FF-A core. Use normal platform driver
> > registration so the probe path has standard driver-core semantics.
> >
> > The synthetic platform device is a temporary bridge until ACPI and
> > devicetree describe the FF-A core device or object. Once those firmware
> > description paths are defined, the internal platform device creation can
> > be dropped and the driver can bind to the firmware-described device
> > directly.
> >
> > Since the transport selection now happens from the platform probe path,
> > drop the __init annotation from ffa_transport_init().
> >
> > Signed-off-by: Sudeep Holla <sudeep.holla@kernel.org>
>
> I am seeing
>
> arm-ffa arm-ffa: probe with driver arm-ffa failed with error -95
>
> on my two arm64 test machines after this change landed in -next as
> commit e659fc8e537c ("firmware: arm_ffa: Register core as a platform
> driver"), is this expected? If so, perhaps it should be silenced?
>
Yes it should be silenced, I will see how it can be done. Thanks for the
report.
--
Regards,
Sudeep
^ permalink raw reply
* Re: [PATCH] tpm-buf: memory-safe allocations
From: Jarkko Sakkinen @ 2026-05-26 7:53 UTC (permalink / raw)
To: James Bottomley
Cc: linux-integrity, Jarkko Sakkinen, Arun Menon, Daniel P. Smith,
Alec Brown, Ross Philipson, Stefan Berger, Peter Huewe,
Jason Gunthorpe, Mimi Zohar, David Howells, Paul Moore,
James Morris, Serge E. Hallyn, linux-kernel, keyrings,
linux-security-module
In-Reply-To: <33b4a34ceea0934e238c08e0256b975511ef99c8.camel@HansenPartnership.com>
On Mon, May 25, 2026 at 01:50:51PM -0400, James Bottomley wrote:
> On Fri, 2026-05-22 at 04:35 +0300, Jarkko Sakkinen wrote:
> > Decouple kzalloc from buffer creation, so that a managed allocation
> > can be
> > used:
> >
> > struct tpm_buf *buf __free(kfree) buf = kzalloc(TPM_BUFSIZE,
> > GFP_KERNEL);
> > if (!buf)
> > return -ENOMEM;
> >
> > tpm_buf_init(buf, TPM_BUFSIZE);
> >
> > Alternatively, stack allocations are also possible:
> >
> > u8 buf_data[512];
> > struct tpm_buf *buf = (struct tpm_buf *)buf_data;
> > tpm_buf_init(buf, sizeof(buf_data));
>
> This isn't really a good idea from a security point of view. Remember
> the buffer has to be big enough for both the sent and the received
> data. Today we simply set TPM_BUFSIZE to the maximum amount a TPM
> requires and all the send and receives just work. If we let callers
> set this size, we're asking for them to get it wrong (or at least
> forget about the receive part) and for us to get a DMA overrun from the
> TPM ... which might be potentially exploitable depending on how it
> occurs (think of an unseal of user chosen data overrunning).
It's one patch so you're free to remark the call sites where this
happens. This is not a majorn concern at all.
>
> I get the desire to support some of the newer chunked commands, but
> since none of them is yet present in the kernel, why not introduce an
> API that works only for them to avoid the risk of a security cockup in
> existing code?
Multiplying amount of maintenance work with a redundant implemntation
is not something I support.
>
> Regards,
>
> James
BR, Jarkko
^ permalink raw reply
* Re: [PATCH 00/11] Convert moduleparams to seq_buf
From: Petr Pavlu @ 2026-05-26 6:53 UTC (permalink / raw)
To: Kees Cook
Cc: Luis Chamberlain, Pengpeng Hou, Richard Weinberger, Anton Ivanov,
Johannes Berg, Rafael J. Wysocki, Len Brown, Corey Minyard,
Gabriel Somlo, Michael S. Tsirkin, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, David Airlie, Simona Vetter,
Bart Van Assche, Jason Gunthorpe, Leon Romanovsky,
Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Bjorn Helgaas, Hannes Reinecke, James E.J. Bottomley,
Martin K. Petersen, Daniel Lezcano, Zhang Rui, Lukasz Luba,
Greg Kroah-Hartman, Jiri Slaby, Alan Stern, Jason Wang, Xuan Zhuo,
Eugenio Pérez, Jason Baron, Jim Cromie, Tiwei Bie,
Benjamin Berg, Ilpo Järvinen, David E. Box,
Maciej W. Rozycki, Srinivas Pandruvada, Peter Zijlstra,
Heiko Carstens, Vasily Gorbik, Sean Christopherson, Paolo Bonzini,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Vinod Koul, Frank Li, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Alexander Potapenko, Marco Elver, Dmitry Vyukov,
Andrew Morton, John Johansen, Paul Moore, James Morris,
Serge E. Hallyn, Andy Shevchenko, Georgia Garcia, kvm, dmaengine,
linux-modules, kasan-dev, linux-mm, apparmor,
linux-security-module, linux-um, linux-acpi, openipmi-developer,
qemu-devel, intel-gfx, dri-devel, linux-rdma, linux-media,
linux-pci, linux-scsi, linux-pm, linuxppc-dev, linux-serial,
linux-usb, usb-storage, virtualization, linux-kernel, linux-arch,
netdev, linux-fsdevel, linux-hardening
In-Reply-To: <20260521133315.work.845-kees@kernel.org>
On 5/21/26 3:33 PM, Kees Cook wrote:
> Hi,
>
> I tried to trim the CC list here, but it's still pretty huge...
>
> We've had a long-standing issue with "write to a string pointer" callbacks
> that don't bounds check the destination (and for which the bounds is
> also not part of the callback prototype, even if it is "known" to be
> PAGE_SIZE, which sysfs_emit() depends on). Both moduleparams and sysfs
> use this pattern. As a first step, and to test the migration method,
> migrate moduleparams first.
>
> There are 2 "mechanical" treewide patches that are handled by Coccinelle:
> - treewide: Convert struct kernel_param_ops initializers to DEFINE_KERNEL_PARAM_OPS
> - treewide: Convert custom kernel_param_ops .get callbacks to seq_buf via cocci
>
> The last treewide patch is manual, and may need to be broken up into
> per-subsystem patches, though I'd prefer to avoid this, as it would
> extend the migration from 1 relase to at least 2 releases. (1 to
> release the migration infrastructure, then 1 release to collect all the
> subsystem changes, and possibly 1 more release to remove the migration
> infrastructure.)
>
> Thoughts, questions?
This looks reasonable to me. I added a few minor comments on the patches
but they already look solid.
--
Thanks,
Petr
^ permalink raw reply
* Re: [bug report] keys: request_key_auth payload use-after-free in keyctl_instantiate_key_common()
From: Shaomin Chen @ 2026-05-26 2:50 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: keyrings, linux-security-module, linux-kernel, David Howells,
Paul Moore, James Morris, Serge E. Hallyn
In-Reply-To: <20260519144403.436694-1-eeesssooo020@gmail.com>
Thanks, I sent a candidate patch here:
https://lore.kernel.org/r/20260526024838.3368409-1-eeesssooo020@gmail.com
Shaomin
^ permalink raw reply
* [PATCH] keys: Pin request_key_auth payload in instantiate paths
From: Shaomin Chen @ 2026-05-26 2:48 UTC (permalink / raw)
To: keyrings, linux-security-module, linux-kernel
Cc: David Howells, Jarkko Sakkinen, Paul Moore, James Morris,
Serge E. Hallyn
keyctl_instantiate_key_common() reads request_key_auth from the assumed
auth key before copying an instantiation payload from userspace. The copy
can fault and sleep. If the request completes and revokes the auth key in
that window, the auth payload can be detached and freed before the
instantiate path uses it again.
A request-key helper reproducer can trigger this race. One helper child
blocks in KEYCTL_INSTANTIATE_IOV while the original helper instantiates the
requested key and returns. KASAN then reports a use-after-free from the
stale request_key_auth payload in keyctl_instantiate_key_common().
Give request_key_auth payloads a refcount. Take a payload reference while
authkey->sem stabilizes the payload and revocation state. Hold that
reference across the instantiate and reject paths. Drop the auth key
owning reference from revoke and destroy.
Reported-by: Shaomin Chen <eeesssooo020@gmail.com>
Closes: https://lore.kernel.org/r/20260519144403.436694-1-eeesssooo020@gmail.com
Signed-off-by: Shaomin Chen <eeesssooo020@gmail.com>
---
include/keys/request_key_auth-type.h | 2 ++
security/keys/internal.h | 2 ++
security/keys/keyctl.c | 24 +++++++++++++++-----
security/keys/request_key_auth.c | 33 ++++++++++++++++++++++++++--
4 files changed, 53 insertions(+), 8 deletions(-)
diff --git a/include/keys/request_key_auth-type.h b/include/keys/request_key_auth-type.h
index 36b89a933310..01e42ee5f409 100644
--- a/include/keys/request_key_auth-type.h
+++ b/include/keys/request_key_auth-type.h
@@ -9,12 +9,14 @@
#define _KEYS_REQUEST_KEY_AUTH_TYPE_H
#include <linux/key.h>
+#include <linux/refcount.h>
/*
* Authorisation record for request_key().
*/
struct request_key_auth {
struct rcu_head rcu;
+ refcount_t usage;
struct key *target_key;
struct key *dest_keyring;
const struct cred *cred;
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 2cffa6dc8255..b7b622bc36a1 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -208,6 +208,8 @@ extern struct key *request_key_auth_new(struct key *target,
const void *callout_info,
size_t callout_len,
struct key *dest_keyring);
+struct request_key_auth *request_key_auth_get(struct key *authkey);
+void request_key_auth_put(struct request_key_auth *rka);
extern struct key *key_get_instantiation_authkey(key_serial_t target_id);
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index ef855d69c97a..d14ace88e529 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1197,9 +1197,13 @@ static long keyctl_instantiate_key_common(key_serial_t id,
if (!instkey)
goto error;
- rka = instkey->payload.data[0];
- if (rka->target_key->serial != id)
+ rka = request_key_auth_get(instkey);
+ if (!rka) {
+ ret = -EKEYREVOKED;
goto error;
+ }
+ if (rka->target_key->serial != id)
+ goto error_put_rka;
/* pull the payload in if one was supplied */
payload = NULL;
@@ -1208,7 +1212,7 @@ static long keyctl_instantiate_key_common(key_serial_t id,
ret = -ENOMEM;
payload = kvmalloc(plen, GFP_KERNEL);
if (!payload)
- goto error;
+ goto error_put_rka;
ret = -EFAULT;
if (!copy_from_iter_full(payload, plen, from))
@@ -1234,6 +1238,8 @@ static long keyctl_instantiate_key_common(key_serial_t id,
error2:
kvfree_sensitive(payload, plen);
+error_put_rka:
+ request_key_auth_put(rka);
error:
return ret;
}
@@ -1358,15 +1364,19 @@ long keyctl_reject_key(key_serial_t id, unsigned timeout, unsigned error,
if (!instkey)
goto error;
- rka = instkey->payload.data[0];
- if (rka->target_key->serial != id)
+ rka = request_key_auth_get(instkey);
+ if (!rka) {
+ ret = -EKEYREVOKED;
goto error;
+ }
+ if (rka->target_key->serial != id)
+ goto error_put_rka;
/* find the destination keyring if present (which must also be
* writable) */
ret = get_instantiation_keyring(ringid, rka, &dest_keyring);
if (ret < 0)
- goto error;
+ goto error_put_rka;
/* instantiate the key and link it into a keyring */
ret = key_reject_and_link(rka->target_key, timeout, error,
@@ -1379,6 +1389,8 @@ long keyctl_reject_key(key_serial_t id, unsigned timeout, unsigned error,
if (ret == 0)
keyctl_change_reqkey_auth(NULL);
+error_put_rka:
+ request_key_auth_put(rka);
error:
return ret;
}
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index a7d7538c1f70..282e09d8fa46 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -23,6 +23,7 @@ static void request_key_auth_describe(const struct key *, struct seq_file *);
static void request_key_auth_revoke(struct key *);
static void request_key_auth_destroy(struct key *);
static long request_key_auth_read(const struct key *, char *, size_t);
+static void request_key_auth_rcu_disposal(struct rcu_head *);
/*
* The request-key authorisation key type definition.
@@ -115,6 +116,31 @@ static void free_request_key_auth(struct request_key_auth *rka)
kfree(rka);
}
+/*
+ * Take a reference to the request-key authorisation payload so callers can
+ * drop authkey->sem before doing operations that may sleep.
+ */
+struct request_key_auth *request_key_auth_get(struct key *authkey)
+{
+ struct request_key_auth *rka;
+
+ down_read(&authkey->sem);
+ rka = dereference_key_locked(authkey);
+ if (rka && !test_bit(KEY_FLAG_REVOKED, &authkey->flags))
+ refcount_inc(&rka->usage);
+ else
+ rka = NULL;
+ up_read(&authkey->sem);
+
+ return rka;
+}
+
+void request_key_auth_put(struct request_key_auth *rka)
+{
+ if (rka && refcount_dec_and_test(&rka->usage))
+ call_rcu(&rka->rcu, request_key_auth_rcu_disposal);
+}
+
/*
* Dispose of the request_key_auth record under RCU conditions
*/
@@ -136,8 +162,10 @@ static void request_key_auth_revoke(struct key *key)
struct request_key_auth *rka = dereference_key_locked(key);
kenter("{%d}", key->serial);
+ if (!rka)
+ return;
rcu_assign_keypointer(key, NULL);
- call_rcu(&rka->rcu, request_key_auth_rcu_disposal);
+ request_key_auth_put(rka);
}
/*
@@ -150,7 +178,7 @@ static void request_key_auth_destroy(struct key *key)
kenter("{%d}", key->serial);
if (rka) {
rcu_assign_keypointer(key, NULL);
- call_rcu(&rka->rcu, request_key_auth_rcu_disposal);
+ request_key_auth_put(rka);
}
}
@@ -174,6 +202,7 @@ struct key *request_key_auth_new(struct key *target, const char *op,
rka = kzalloc_obj(*rka);
if (!rka)
goto error;
+ refcount_set(&rka->usage, 1);
rka->callout_info = kmemdup(callout_info, callout_len, GFP_KERNEL);
if (!rka->callout_info)
goto error_free_rka;
--
2.47.3
^ permalink raw reply related
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