mirror of https://github.com/torvalds/linux.git
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:
commit
c8e00cdc74
|
|
@ -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)
|
||||
|
|
|
|||
146
fs/coredump.c
146
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/<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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
ret = trace_add_event_call(&user->call);
|
||||
else
|
||||
ret = trace_remove_event_call(&user->call);
|
||||
return trace_add_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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue