From c8ad3098e1272444b6c75910d6196a36f5c8bc17 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 3 Nov 2025 15:57:27 +0100 Subject: [PATCH 01/12] cred: add prepare credential guard A lot of code uses the following pattern: * prepare new credentials * modify them for their use-case * drop them Support that easier with the new guard infrastructure. Link: https://patch.msgid.link/20251103-work-creds-guards-prepare_creds-v1-1-b447b82f2c9b@kernel.org Signed-off-by: Christian Brauner --- include/linux/cred.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/cred.h b/include/linux/cred.h index 6ea2d81a740b..343a140a6ba2 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -280,6 +280,11 @@ static inline void put_cred(const struct cred *cred) put_cred_many(cred, 1); } +DEFINE_CLASS(prepare_creds, + struct cred *, + if (_T) put_cred(_T), + prepare_creds(), void) + DEFINE_FREE(put_cred, struct cred *, if (!IS_ERR_OR_NULL(_T)) put_cred(_T)) /** From 4c5941ca1104d58a94e59100ebde97a162e72de4 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 3 Nov 2025 15:57:28 +0100 Subject: [PATCH 02/12] sev-dev: use guard for path Just use a guard and also move the path_put() out of the credential change's scope. There's no need to do this with the overridden credentials. Link: https://patch.msgid.link/20251103-work-creds-guards-prepare_creds-v1-2-b447b82f2c9b@kernel.org Signed-off-by: Christian Brauner --- drivers/crypto/ccp/sev-dev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 0d13d47c164b..c5e22af04abb 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -259,8 +259,8 @@ static int sev_cmd_buffer_len(int cmd) static struct file *open_file_as_root(const char *filename, int flags, umode_t mode) { + struct path root __free(path_put) = {}; struct file *fp; - struct path root; struct cred *cred; const struct cred *old_cred; @@ -275,7 +275,6 @@ static struct file *open_file_as_root(const char *filename, int flags, umode_t m old_cred = override_creds(cred); fp = file_open_root(&root, filename, flags, mode); - path_put(&root); put_cred(revert_creds(old_cred)); From 89c545e29ecd6252968611b3ee2599034b911dd8 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 3 Nov 2025 15:57:29 +0100 Subject: [PATCH 03/12] sev-dev: use prepare credential guard Use the prepare credential guard for allocating a new set of credentials. Link: https://patch.msgid.link/20251103-work-creds-guards-prepare_creds-v1-3-b447b82f2c9b@kernel.org Signed-off-by: Christian Brauner --- drivers/crypto/ccp/sev-dev.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index c5e22af04abb..be3e5454c285 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -261,22 +261,22 @@ static struct file *open_file_as_root(const char *filename, int flags, umode_t m { struct path root __free(path_put) = {}; struct file *fp; - struct cred *cred; const struct cred *old_cred; task_lock(&init_task); get_fs_root(init_task.fs, &root); task_unlock(&init_task); - cred = prepare_creds(); + CLASS(prepare_creds, cred)(); if (!cred) return ERR_PTR(-ENOMEM); + cred->fsuid = GLOBAL_ROOT_UID; old_cred = override_creds(cred); fp = file_open_root(&root, filename, flags, mode); - put_cred(revert_creds(old_cred)); + revert_creds(old_cred); return fp; } From b7b4f7554bcc6b9ee0ec0404999bf080adad1f3c Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 3 Nov 2025 15:57:30 +0100 Subject: [PATCH 04/12] sev-dev: use override credential guards Use override credential guards for scoped credential override with automatic restoration on scope exit. Link: https://patch.msgid.link/20251103-work-creds-guards-prepare_creds-v1-4-b447b82f2c9b@kernel.org Signed-off-by: Christian Brauner --- drivers/crypto/ccp/sev-dev.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index be3e5454c285..b28a6f50daaa 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -260,8 +260,6 @@ static int sev_cmd_buffer_len(int cmd) static struct file *open_file_as_root(const char *filename, int flags, umode_t mode) { struct path root __free(path_put) = {}; - struct file *fp; - const struct cred *old_cred; task_lock(&init_task); get_fs_root(init_task.fs, &root); @@ -272,13 +270,9 @@ static struct file *open_file_as_root(const char *filename, int flags, umode_t m return ERR_PTR(-ENOMEM); cred->fsuid = GLOBAL_ROOT_UID; - old_cred = override_creds(cred); - fp = file_open_root(&root, filename, flags, mode); - - revert_creds(old_cred); - - return fp; + scoped_with_creds(cred) + return file_open_root(&root, filename, flags, mode); } static int sev_read_init_ex_file(void) From eb937201bad03bf2f25ac630979e521fbb5e2a07 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 3 Nov 2025 15:57:31 +0100 Subject: [PATCH 05/12] coredump: move revert_cred() before coredump_cleanup() There's no need to pin the credentials across the coredump_cleanup() call. Nothing in there depends on elevated credentials. Link: https://patch.msgid.link/20251103-work-creds-guards-prepare_creds-v1-5-b447b82f2c9b@kernel.org Signed-off-by: Christian Brauner --- fs/coredump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/coredump.c b/fs/coredump.c index 5c1c381ee380..4fce2a2f279c 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -1197,8 +1197,8 @@ void vfs_coredump(const kernel_siginfo_t *siginfo) } close_fail: - coredump_cleanup(&cn, &cprm); revert_creds(old_cred); + coredump_cleanup(&cn, &cprm); return; } From 1ec760fb42404dd7257d1c73dd68295a0d1a974f Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 3 Nov 2025 15:57:32 +0100 Subject: [PATCH 06/12] coredump: pass struct linux_binfmt as const We don't actually modify it. Link: https://patch.msgid.link/20251103-work-creds-guards-prepare_creds-v1-6-b447b82f2c9b@kernel.org Signed-off-by: Christian Brauner --- fs/coredump.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/coredump.c b/fs/coredump.c index 4fce2a2f279c..590360ba0a28 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -1036,7 +1036,7 @@ static bool coredump_pipe(struct core_name *cn, struct coredump_params *cprm, static bool coredump_write(struct core_name *cn, struct coredump_params *cprm, - struct linux_binfmt *binfmt) + const struct linux_binfmt *binfmt) { if (dump_interrupted()) @@ -1093,7 +1093,7 @@ void vfs_coredump(const kernel_siginfo_t *siginfo) struct core_state core_state; struct core_name cn; struct mm_struct *mm = current->mm; - struct linux_binfmt *binfmt = mm->binfmt; + const struct linux_binfmt *binfmt = mm->binfmt; const struct cred *old_cred; int argc = 0; struct coredump_params cprm = { From 313a335057f0894e6e59290d4e7fb8b35ec250e6 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 3 Nov 2025 15:57:33 +0100 Subject: [PATCH 07/12] coredump: mark struct mm_struct as const We don't actually modify it. Link: https://patch.msgid.link/20251103-work-creds-guards-prepare_creds-v1-7-b447b82f2c9b@kernel.org Signed-off-by: Christian Brauner --- fs/coredump.c | 2 +- include/linux/sched/coredump.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/coredump.c b/fs/coredump.c index 590360ba0a28..8253b28bc728 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -1092,7 +1092,7 @@ void vfs_coredump(const kernel_siginfo_t *siginfo) size_t *argv __free(kfree) = NULL; struct core_state core_state; struct core_name cn; - struct mm_struct *mm = current->mm; + const struct mm_struct *mm = current->mm; const struct linux_binfmt *binfmt = mm->binfmt; const struct cred *old_cred; int argc = 0; diff --git a/include/linux/sched/coredump.h b/include/linux/sched/coredump.h index b7fafe999073..624fda17a785 100644 --- a/include/linux/sched/coredump.h +++ b/include/linux/sched/coredump.h @@ -8,7 +8,7 @@ #define SUID_DUMP_USER 1 /* Dump as user of process */ #define SUID_DUMP_ROOT 2 /* Dump as root */ -static inline unsigned long __mm_flags_get_dumpable(struct mm_struct *mm) +static inline unsigned long __mm_flags_get_dumpable(const struct mm_struct *mm) { /* * By convention, dumpable bits are contained in first 32 bits of the From af9803d4b8ca3f59ec66bb6b1557e40a18bc5599 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 3 Nov 2025 15:57:34 +0100 Subject: [PATCH 08/12] coredump: split out do_coredump() from vfs_coredump() Make the function easier to follow and prepare for some of the following changes. Link: https://patch.msgid.link/20251103-work-creds-guards-prepare_creds-v1-8-b447b82f2c9b@kernel.org Signed-off-by: Christian Brauner --- fs/coredump.c | 131 ++++++++++++++++++++++++++------------------------ 1 file changed, 68 insertions(+), 63 deletions(-) diff --git a/fs/coredump.c b/fs/coredump.c index 8253b28bc728..79c681f1d647 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -1086,6 +1086,73 @@ static inline bool coredump_skip(const struct coredump_params *cprm, return false; } +static void do_coredump(struct core_name *cn, struct coredump_params *cprm, + size_t **argv, int *argc, const struct linux_binfmt *binfmt) +{ + if (!coredump_parse(cn, cprm, argv, argc)) { + coredump_report_failure("format_corename failed, aborting core"); + return; + } + + switch (cn->core_type) { + case COREDUMP_FILE: + if (!coredump_file(cn, cprm, binfmt)) + return; + break; + case COREDUMP_PIPE: + if (!coredump_pipe(cn, cprm, *argv, *argc)) + return; + break; + case COREDUMP_SOCK_REQ: + fallthrough; + case COREDUMP_SOCK: + if (!coredump_socket(cn, cprm)) + return; + break; + default: + WARN_ON_ONCE(true); + return; + } + + /* Don't even generate the coredump. */ + if (cn->mask & COREDUMP_REJECT) + return; + + /* get us an unshared descriptor table; almost always a no-op */ + /* The cell spufs coredump code reads the file descriptor tables */ + if (unshare_files()) + return; + + if ((cn->mask & COREDUMP_KERNEL) && !coredump_write(cn, cprm, binfmt)) + return; + + coredump_sock_shutdown(cprm->file); + + /* Let the parent know that a coredump was generated. */ + if (cn->mask & COREDUMP_USERSPACE) + cn->core_dumped = true; + + /* + * When core_pipe_limit is set we wait for the coredump server + * or usermodehelper to finish before exiting so it can e.g., + * inspect /proc/. + */ + if (cn->mask & COREDUMP_WAIT) { + switch (cn->core_type) { + case COREDUMP_PIPE: + wait_for_dump_helpers(cprm->file); + break; + case COREDUMP_SOCK_REQ: + fallthrough; + case COREDUMP_SOCK: + coredump_sock_wait(cprm->file); + break; + default: + break; + } + } +} + void vfs_coredump(const kernel_siginfo_t *siginfo) { struct cred *cred __free(put_cred) = NULL; @@ -1133,70 +1200,8 @@ void vfs_coredump(const kernel_siginfo_t *siginfo) old_cred = override_creds(cred); - if (!coredump_parse(&cn, &cprm, &argv, &argc)) { - coredump_report_failure("format_corename failed, aborting core"); - goto close_fail; - } + do_coredump(&cn, &cprm, &argv, &argc, binfmt); - switch (cn.core_type) { - case COREDUMP_FILE: - if (!coredump_file(&cn, &cprm, binfmt)) - goto close_fail; - break; - case COREDUMP_PIPE: - if (!coredump_pipe(&cn, &cprm, argv, argc)) - goto close_fail; - break; - case COREDUMP_SOCK_REQ: - fallthrough; - case COREDUMP_SOCK: - if (!coredump_socket(&cn, &cprm)) - goto close_fail; - break; - default: - WARN_ON_ONCE(true); - goto close_fail; - } - - /* Don't even generate the coredump. */ - if (cn.mask & COREDUMP_REJECT) - goto close_fail; - - /* get us an unshared descriptor table; almost always a no-op */ - /* The cell spufs coredump code reads the file descriptor tables */ - if (unshare_files()) - goto close_fail; - - if ((cn.mask & COREDUMP_KERNEL) && !coredump_write(&cn, &cprm, binfmt)) - goto close_fail; - - coredump_sock_shutdown(cprm.file); - - /* Let the parent know that a coredump was generated. */ - if (cn.mask & COREDUMP_USERSPACE) - cn.core_dumped = true; - - /* - * When core_pipe_limit is set we wait for the coredump server - * or usermodehelper to finish before exiting so it can e.g., - * inspect /proc/. - */ - if (cn.mask & COREDUMP_WAIT) { - switch (cn.core_type) { - case COREDUMP_PIPE: - wait_for_dump_helpers(cprm.file); - break; - case COREDUMP_SOCK_REQ: - fallthrough; - case COREDUMP_SOCK: - coredump_sock_wait(cprm.file); - break; - default: - break; - } - } - -close_fail: revert_creds(old_cred); coredump_cleanup(&cn, &cprm); return; From 8ed3473c5a8b356c8af950a29d5620be337c3cab Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 3 Nov 2025 15:57:35 +0100 Subject: [PATCH 09/12] coredump: use prepare credential guard Use the prepare credential guard for allocating a new set of credentials. Link: https://patch.msgid.link/20251103-work-creds-guards-prepare_creds-v1-9-b447b82f2c9b@kernel.org Signed-off-by: Christian Brauner --- fs/coredump.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/coredump.c b/fs/coredump.c index 79c681f1d647..5424a6c4e360 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -1155,7 +1155,6 @@ static void do_coredump(struct core_name *cn, struct coredump_params *cprm, void vfs_coredump(const kernel_siginfo_t *siginfo) { - struct cred *cred __free(put_cred) = NULL; size_t *argv __free(kfree) = NULL; struct core_state core_state; struct core_name cn; @@ -1183,7 +1182,7 @@ void vfs_coredump(const kernel_siginfo_t *siginfo) if (coredump_skip(&cprm, binfmt)) return; - cred = prepare_creds(); + CLASS(prepare_creds, cred)(); if (!cred) return; /* From 545985dd3701988c95cba9a8f895631de2039b21 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 3 Nov 2025 15:57:36 +0100 Subject: [PATCH 10/12] coredump: use override credential guard Use override credential guards for scoped credential override with automatic restoration on scope exit. Link: https://patch.msgid.link/20251103-work-creds-guards-prepare_creds-v1-10-b447b82f2c9b@kernel.org Signed-off-by: Christian Brauner --- fs/coredump.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/fs/coredump.c b/fs/coredump.c index 5424a6c4e360..fe4099e0530b 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -1160,7 +1160,6 @@ void vfs_coredump(const kernel_siginfo_t *siginfo) struct core_name cn; const struct mm_struct *mm = current->mm; const struct linux_binfmt *binfmt = mm->binfmt; - const struct cred *old_cred; int argc = 0; struct coredump_params cprm = { .siginfo = siginfo, @@ -1197,11 +1196,8 @@ void vfs_coredump(const kernel_siginfo_t *siginfo) if (coredump_wait(siginfo->si_signo, &core_state) < 0) return; - old_cred = override_creds(cred); - - do_coredump(&cn, &cprm, &argv, &argc, binfmt); - - revert_creds(old_cred); + scoped_with_creds(cred) + do_coredump(&cn, &cprm, &argv, &argc, binfmt); coredump_cleanup(&cn, &cprm); return; } From 2ed6a34de9851dcd4db8441a33882b168261be88 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 3 Nov 2025 15:57:37 +0100 Subject: [PATCH 11/12] trace: use prepare credential guard Use the prepare credential guard for allocating a new set of credentials. Link: https://patch.msgid.link/20251103-work-creds-guards-prepare_creds-v1-11-b447b82f2c9b@kernel.org Acked-by: Steven Rostedt (Google) Signed-off-by: Christian Brauner --- kernel/trace/trace_events_user.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c index c428dafe7496..28c62149eec5 100644 --- a/kernel/trace/trace_events_user.c +++ b/kernel/trace/trace_events_user.c @@ -1451,10 +1451,8 @@ static int user_event_set_call_visible(struct user_event *user, bool visible) { int ret; const struct cred *old_cred; - struct cred *cred; - - cred = prepare_creds(); + CLASS(prepare_creds, cred)(); if (!cred) return -ENOMEM; @@ -1477,7 +1475,6 @@ static int user_event_set_call_visible(struct user_event *user, bool visible) ret = trace_remove_event_call(&user->call); revert_creds(old_cred); - put_cred(cred); return ret; } From 06765b6efc463ce4d3c0c80a3cc2c888dc902dfa Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 3 Nov 2025 15:57:38 +0100 Subject: [PATCH 12/12] trace: use override credential guard Use override credential guards for scoped credential override with automatic restoration on scope exit. Link: https://patch.msgid.link/20251103-work-creds-guards-prepare_creds-v1-12-b447b82f2c9b@kernel.org Acked-by: Steven Rostedt (Google) Signed-off-by: Christian Brauner --- kernel/trace/trace_events_user.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c index 28c62149eec5..b15854c75d4f 100644 --- a/kernel/trace/trace_events_user.c +++ b/kernel/trace/trace_events_user.c @@ -1449,9 +1449,6 @@ static struct trace_event_functions user_event_funcs = { static int user_event_set_call_visible(struct user_event *user, bool visible) { - int ret; - const struct cred *old_cred; - CLASS(prepare_creds, cred)(); if (!cred) return -ENOMEM; @@ -1467,16 +1464,12 @@ static int user_event_set_call_visible(struct user_event *user, bool visible) */ cred->fsuid = GLOBAL_ROOT_UID; - old_cred = override_creds(cred); + scoped_with_creds(cred) { + if (visible) + return trace_add_event_call(&user->call); - if (visible) - ret = trace_add_event_call(&user->call); - else - ret = trace_remove_event_call(&user->call); - - revert_creds(old_cred); - - return ret; + return trace_remove_event_call(&user->call); + } } static int destroy_user_event(struct user_event *user)