>From e11ef55c696d65f1dc3c5f151f9f62fe3b3b62cf Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 26 Dec 2021 12:41:15 +0100 Subject: coredump: disable core dumps when transitionning via a suidexec This adds an MMF_NOT_DUMPABLE flag to mm->flags that is set when transitionning via a suidexec program, and is only reset when the target program changes the RLIMIT_CORE values or changes its dumpable state using prctl(PR_SET_DUMPABLE). This allows programs like su/sudo to start a program without this program risking to dump a core, but it also lets such programs explicitly disable this protection by simply changing their core limits. --- fs/coredump.c | 2 ++ fs/exec.c | 4 +++- include/linux/sched/coredump.h | 4 +++- kernel/sys.c | 12 ++++++++++++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/fs/coredump.c b/fs/coredump.c index 3224dee44d30..5f0bfe2c00a6 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -609,6 +609,8 @@ void do_coredump(const kernel_siginfo_t *siginfo) goto fail; if (!__get_dumpable(cprm.mm_flags)) goto fail; + if (cprm.mm_flags & MMF_NOT_DUMPABLE_MASK) + goto fail; cred = prepare_creds(); if (!cred) diff --git a/fs/exec.c b/fs/exec.c index ac7b51b51f38..42f74b6f0ca0 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1348,8 +1348,10 @@ int begin_new_exec(struct linux_binprm * bprm) */ if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP || !(uid_eq(current_euid(), current_uid()) && - gid_eq(current_egid(), current_gid()))) + gid_eq(current_egid(), current_gid()))) { + set_bit(MMF_NOT_DUMPABLE, ¤t->mm->flags); set_dumpable(current->mm, suid_dumpable); + } else set_dumpable(current->mm, SUID_DUMP_USER); diff --git a/include/linux/sched/coredump.h b/include/linux/sched/coredump.h index 4d9e3a656875..e307f70c5b95 100644 --- a/include/linux/sched/coredump.h +++ b/include/linux/sched/coredump.h @@ -81,9 +81,11 @@ static inline int get_dumpable(struct mm_struct *mm) * lifecycle of this mm, just for simplicity. */ #define MMF_HAS_PINNED 28 /* FOLL_PIN has run, never cleared */ +#define MMF_NOT_DUMPABLE 29 /* dump disabled by suidexec */ #define MMF_DISABLE_THP_MASK (1 << MMF_DISABLE_THP) +#define MMF_NOT_DUMPABLE_MASK (1 << MMF_NOT_DUMPABLE) #define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK |\ - MMF_DISABLE_THP_MASK) + MMF_DISABLE_THP_MASK | MMF_NOT_DUMPABLE_MASK) #endif /* _LINUX_SCHED_COREDUMP_H */ diff --git a/kernel/sys.c b/kernel/sys.c index 8fdac0d90504..c5bb0247bde4 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1610,6 +1610,17 @@ int do_prlimit(struct task_struct *tsk, unsigned int resource, new_rlim->rlim_cur != RLIM_INFINITY && IS_ENABLED(CONFIG_POSIX_TIMERS)) update_rlimit_cpu(tsk, new_rlim->rlim_cur); + + /* + * If an application wants to change its own core dump settings, it + * wants to decide on its dumpability so we reset MMF_NOT_DUMPABLE. + * We only do that for applications that were previously dumpable, + * so that suid programs such as su/sudo setting the target process' + * limits do no disable the protection by accident. + */ + if (!retval && new_rlim && resource == RLIMIT_CORE && tsk == current && + get_dumpable(tsk->mm)) + clear_bit(MMF_NOT_DUMPABLE, &tsk->mm->flags); out: read_unlock(&tasklist_lock); return retval; @@ -2293,6 +2304,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, break; } set_dumpable(me->mm, arg2); + clear_bit(MMF_NOT_DUMPABLE, &me->mm->flags); break; case PR_SET_UNALIGN: -- 2.17.5