|
@@ -513,10 +513,10 @@ void do_coredump(const siginfo_t *siginfo)
|
|
|
const struct cred *old_cred;
|
|
|
struct cred *cred;
|
|
|
int retval = 0;
|
|
|
- int flag = 0;
|
|
|
int ispipe;
|
|
|
struct files_struct *displaced;
|
|
|
- bool need_nonrelative = false;
|
|
|
+ /* require nonrelative corefile path and be extra careful */
|
|
|
+ bool need_suid_safe = false;
|
|
|
bool core_dumped = false;
|
|
|
static atomic_t core_dump_count = ATOMIC_INIT(0);
|
|
|
struct coredump_params cprm = {
|
|
@@ -550,9 +550,8 @@ void do_coredump(const siginfo_t *siginfo)
|
|
|
*/
|
|
|
if (__get_dumpable(cprm.mm_flags) == SUID_DUMP_ROOT) {
|
|
|
/* Setuid core dump mode */
|
|
|
- flag = O_EXCL; /* Stop rewrite attacks */
|
|
|
cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */
|
|
|
- need_nonrelative = true;
|
|
|
+ need_suid_safe = true;
|
|
|
}
|
|
|
|
|
|
retval = coredump_wait(siginfo->si_signo, &core_state);
|
|
@@ -633,7 +632,7 @@ void do_coredump(const siginfo_t *siginfo)
|
|
|
if (cprm.limit < binfmt->min_coredump)
|
|
|
goto fail_unlock;
|
|
|
|
|
|
- if (need_nonrelative && cn.corename[0] != '/') {
|
|
|
+ if (need_suid_safe && cn.corename[0] != '/') {
|
|
|
printk(KERN_WARNING "Pid %d(%s) can only dump core "\
|
|
|
"to fully qualified path!\n",
|
|
|
task_tgid_vnr(current), current->comm);
|
|
@@ -641,8 +640,35 @@ void do_coredump(const siginfo_t *siginfo)
|
|
|
goto fail_unlock;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * Unlink the file if it exists unless this is a SUID
|
|
|
+ * binary - in that case, we're running around with root
|
|
|
+ * privs and don't want to unlink another user's coredump.
|
|
|
+ */
|
|
|
+ if (!need_suid_safe) {
|
|
|
+ mm_segment_t old_fs;
|
|
|
+
|
|
|
+ old_fs = get_fs();
|
|
|
+ set_fs(KERNEL_DS);
|
|
|
+ /*
|
|
|
+ * If it doesn't exist, that's fine. If there's some
|
|
|
+ * other problem, we'll catch it at the filp_open().
|
|
|
+ */
|
|
|
+ (void) sys_unlink((const char __user *)cn.corename);
|
|
|
+ set_fs(old_fs);
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * There is a race between unlinking and creating the
|
|
|
+ * file, but if that causes an EEXIST here, that's
|
|
|
+ * fine - another process raced with us while creating
|
|
|
+ * the corefile, and the other process won. To userspace,
|
|
|
+ * what matters is that at least one of the two processes
|
|
|
+ * writes its coredump successfully, not which one.
|
|
|
+ */
|
|
|
cprm.file = filp_open(cn.corename,
|
|
|
- O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag,
|
|
|
+ O_CREAT | 2 | O_NOFOLLOW |
|
|
|
+ O_LARGEFILE | O_EXCL,
|
|
|
0600);
|
|
|
if (IS_ERR(cprm.file))
|
|
|
goto fail_unlock;
|