diff options
| author | Jann Horn <jannh@google.com> | 2026-08-06 22:15:54 +0200 |
|---|---|---|
| committer | Paul Moore <paul@paul-moore.com> | 2026-08-31 16:14:09 -0400 |
| commit | b030ffaedc1d638f232f6992406cdcdcc82d5602 (patch) | |
| tree | 2802f24962af082633e86f5e86db43d7334e7d9c /kernel | |
| parent | cee9395acd8043be0644b25c34bfa86623f2b935 (diff) | |
| download | linux-next-b030ffaedc1d638f232f6992406cdcdcc82d5602.tar.gz linux-next-b030ffaedc1d638f232f6992406cdcdcc82d5602.zip | |
cred: clarify that task_struct::cred is only for the current task
The `cred` field in task_struct is currently marked as __rcu, but that's
not true: It can point to credentials from access_override_creds(), which
do not get freed with RCU delay.
What actually protects task_struct::cred is that accessing it is only
permitted for the current task (except for setting up a child during fork()
or tearing down a dead process).
(There is currently code in Smack that violates this rule, but that's a bug
and causes UAF, I have sent a separate fix for that.)
Clarify this, remove the __rcu marker, and remove RCU helpers from all
accesses to this field.
Signed-off-by: Jann Horn <jannh@google.com>
Reviewed-by: Serge Hallyn <serge@hallyn.com>
[PM: style tweak in security_init(), applied fixup from JH]
Signed-off-by: Paul Moore <paul@paul-moore.com>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/auditsc.c | 5 | ||||
| -rw-r--r-- | kernel/cred.c | 2 |
2 files changed, 4 insertions, 3 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 2b9ce0b52511..1b9cf25291e0 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -459,7 +459,7 @@ static int audit_field_compare(struct task_struct *tsk, * * If task_creation is true, this is an explicit indication that we are * filtering a task rule at task creation time. This and tsk == current are - * the only situations where tsk->cred may be accessed without an rcu read lock. + * the only situations where tsk->cred may be accessed. */ static int audit_filter_rules(struct task_struct *tsk, struct audit_krule *rule, @@ -476,7 +476,8 @@ static int audit_filter_rules(struct task_struct *tsk, if (ctx && rule->prio <= ctx->prio) return 0; - cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation); + WARN_ON(tsk != current && !task_creation); + cred = tsk->cred; for (i = 0; i < rule->field_count; i++) { struct audit_field *f = &rule->fields[i]; diff --git a/kernel/cred.c b/kernel/cred.c index 3df4e15bd67f..0bd6a58bc12d 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -414,7 +414,7 @@ int commit_creds(struct cred *new) inc_rlimit_ucounts(new->ucounts, UCOUNT_RLIMIT_NPROC, 1); rcu_assign_pointer(task->real_cred, new); - rcu_assign_pointer(task->cred, new); + task->cred = new; if (new->user != old->user || new->user_ns != old->user_ns) dec_rlimit_ucounts(old->ucounts, UCOUNT_RLIMIT_NPROC, 1); if (new->user_ns != old->user_ns) |
