diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 0d13d47c164b..b28a6f50daaa 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -259,27 +259,20 @@ static int sev_cmd_buffer_len(int cmd) static struct file *open_file_as_root(const char *filename, int flags, umode_t mode) { - struct file *fp; - struct path root; - struct cred *cred; - const struct cred *old_cred; + struct path root __free(path_put) = {}; 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); - path_put(&root); - - put_cred(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) diff --git a/fs/coredump.c b/fs/coredump.c index 5c1c381ee380..fe4099e0530b 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()) @@ -1086,15 +1086,80 @@ 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; size_t *argv __free(kfree) = NULL; struct core_state core_state; struct core_name cn; - struct mm_struct *mm = current->mm; - struct linux_binfmt *binfmt = mm->binfmt; - const struct cred *old_cred; + const struct mm_struct *mm = current->mm; + const struct linux_binfmt *binfmt = mm->binfmt; int argc = 0; struct coredump_params cprm = { .siginfo = siginfo, @@ -1116,7 +1181,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; /* @@ -1131,74 +1196,9 @@ void vfs_coredump(const kernel_siginfo_t *siginfo) if (coredump_wait(siginfo->si_signo, &core_state) < 0) return; - old_cred = override_creds(cred); - - if (!coredump_parse(&cn, &cprm, &argv, &argc)) { - coredump_report_failure("format_corename failed, aborting core"); - goto close_fail; - } - - 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: + scoped_with_creds(cred) + do_coredump(&cn, &cprm, &argv, &argc, binfmt); coredump_cleanup(&cn, &cprm); - revert_creds(old_cred); return; } 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)) /** 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 diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c index c428dafe7496..b15854c75d4f 100644 --- a/kernel/trace/trace_events_user.c +++ b/kernel/trace/trace_events_user.c @@ -1449,12 +1449,7 @@ 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; - struct cred *cred; - - cred = prepare_creds(); - + CLASS(prepare_creds, cred)(); if (!cred) return -ENOMEM; @@ -1469,17 +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); - put_cred(cred); - - return ret; + return trace_remove_event_call(&user->call); + } } static int destroy_user_event(struct user_event *user)