Merge patch series "credential guards: credential preparation"

Christian Brauner <brauner@kernel.org> says:

This converts most users combining

* prepare_creds()
* modify new creds
* override_creds()
* revert_creds()
* put_cred()

to rely on credentials guards.

* patches from https://patch.msgid.link/20251103-work-creds-guards-prepare_creds-v1-0-b447b82f2c9b@kernel.org:
  trace: use override credential guard
  trace: use prepare credential guard
  coredump: use override credential guard
  coredump: use prepare credential guard
  coredump: split out do_coredump() from vfs_coredump()
  coredump: mark struct mm_struct as const
  coredump: pass struct linux_binfmt as const
  coredump: move revert_cred() before coredump_cleanup()
  sev-dev: use override credential guards
  sev-dev: use prepare credential guard
  sev-dev: use guard for path
  cred: add prepare credential guard

Link: https://patch.msgid.link/20251103-work-creds-guards-prepare_creds-v1-0-b447b82f2c9b@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Christian Brauner 2025-11-03 22:44:50 +01:00
commit c8e00cdc74
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2
5 changed files with 90 additions and 102 deletions

View File

@ -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)

View File

@ -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/<pid>.
*/
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/<pid>.
*/
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;
}

View File

@ -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))
/**

View File

@ -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

View File

@ -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)