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)
|
static struct file *open_file_as_root(const char *filename, int flags, umode_t mode)
|
||||||
{
|
{
|
||||||
struct file *fp;
|
struct path root __free(path_put) = {};
|
||||||
struct path root;
|
|
||||||
struct cred *cred;
|
|
||||||
const struct cred *old_cred;
|
|
||||||
|
|
||||||
task_lock(&init_task);
|
task_lock(&init_task);
|
||||||
get_fs_root(init_task.fs, &root);
|
get_fs_root(init_task.fs, &root);
|
||||||
task_unlock(&init_task);
|
task_unlock(&init_task);
|
||||||
|
|
||||||
cred = prepare_creds();
|
CLASS(prepare_creds, cred)();
|
||||||
if (!cred)
|
if (!cred)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
cred->fsuid = GLOBAL_ROOT_UID;
|
cred->fsuid = GLOBAL_ROOT_UID;
|
||||||
old_cred = override_creds(cred);
|
|
||||||
|
|
||||||
fp = file_open_root(&root, filename, flags, mode);
|
scoped_with_creds(cred)
|
||||||
path_put(&root);
|
return file_open_root(&root, filename, flags, mode);
|
||||||
|
|
||||||
put_cred(revert_creds(old_cred));
|
|
||||||
|
|
||||||
return fp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sev_read_init_ex_file(void)
|
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,
|
static bool coredump_write(struct core_name *cn,
|
||||||
struct coredump_params *cprm,
|
struct coredump_params *cprm,
|
||||||
struct linux_binfmt *binfmt)
|
const struct linux_binfmt *binfmt)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (dump_interrupted())
|
if (dump_interrupted())
|
||||||
|
|
@ -1086,15 +1086,80 @@ static inline bool coredump_skip(const struct coredump_params *cprm,
|
||||||
return false;
|
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)
|
void vfs_coredump(const kernel_siginfo_t *siginfo)
|
||||||
{
|
{
|
||||||
struct cred *cred __free(put_cred) = NULL;
|
|
||||||
size_t *argv __free(kfree) = NULL;
|
size_t *argv __free(kfree) = NULL;
|
||||||
struct core_state core_state;
|
struct core_state core_state;
|
||||||
struct core_name cn;
|
struct core_name cn;
|
||||||
struct mm_struct *mm = current->mm;
|
const 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;
|
int argc = 0;
|
||||||
struct coredump_params cprm = {
|
struct coredump_params cprm = {
|
||||||
.siginfo = siginfo,
|
.siginfo = siginfo,
|
||||||
|
|
@ -1116,7 +1181,7 @@ void vfs_coredump(const kernel_siginfo_t *siginfo)
|
||||||
if (coredump_skip(&cprm, binfmt))
|
if (coredump_skip(&cprm, binfmt))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cred = prepare_creds();
|
CLASS(prepare_creds, cred)();
|
||||||
if (!cred)
|
if (!cred)
|
||||||
return;
|
return;
|
||||||
/*
|
/*
|
||||||
|
|
@ -1131,74 +1196,9 @@ void vfs_coredump(const kernel_siginfo_t *siginfo)
|
||||||
if (coredump_wait(siginfo->si_signo, &core_state) < 0)
|
if (coredump_wait(siginfo->si_signo, &core_state) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
old_cred = override_creds(cred);
|
scoped_with_creds(cred)
|
||||||
|
do_coredump(&cn, &cprm, &argv, &argc, binfmt);
|
||||||
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:
|
|
||||||
coredump_cleanup(&cn, &cprm);
|
coredump_cleanup(&cn, &cprm);
|
||||||
revert_creds(old_cred);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -280,6 +280,11 @@ static inline void put_cred(const struct cred *cred)
|
||||||
put_cred_many(cred, 1);
|
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))
|
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_USER 1 /* Dump as user of process */
|
||||||
#define SUID_DUMP_ROOT 2 /* Dump as root */
|
#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
|
* 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)
|
static int user_event_set_call_visible(struct user_event *user, bool visible)
|
||||||
{
|
{
|
||||||
int ret;
|
CLASS(prepare_creds, cred)();
|
||||||
const struct cred *old_cred;
|
|
||||||
struct cred *cred;
|
|
||||||
|
|
||||||
cred = prepare_creds();
|
|
||||||
|
|
||||||
if (!cred)
|
if (!cred)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
@ -1469,17 +1464,12 @@ static int user_event_set_call_visible(struct user_event *user, bool visible)
|
||||||
*/
|
*/
|
||||||
cred->fsuid = GLOBAL_ROOT_UID;
|
cred->fsuid = GLOBAL_ROOT_UID;
|
||||||
|
|
||||||
old_cred = override_creds(cred);
|
scoped_with_creds(cred) {
|
||||||
|
|
||||||
if (visible)
|
if (visible)
|
||||||
ret = trace_add_event_call(&user->call);
|
return trace_add_event_call(&user->call);
|
||||||
else
|
|
||||||
ret = trace_remove_event_call(&user->call);
|
|
||||||
|
|
||||||
revert_creds(old_cred);
|
return trace_remove_event_call(&user->call);
|
||||||
put_cred(cred);
|
}
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int destroy_user_event(struct user_event *user)
|
static int destroy_user_event(struct user_event *user)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue