/* * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ staticvoiddo_signal(struct pt_regs *regs) { structksignalksig;
if (get_signal(&ksig)) { /* Whee! Actually deliver the signal. */ handle_signal(&ksig, regs); return; }
/* Did we come from a system call? */ if (syscall_get_nr(current, regs) >= 0) { /* Restart the system call - no handlers present */ switch (syscall_get_error(current, regs)) { case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: regs->ax = regs->orig_ax; regs->ip -= 2; break;
if (ka->sa.sa_handler == SIG_IGN) /* Do nothing. */ continue; if (ka->sa.sa_handler != SIG_DFL) { /* Run the handler. */ *return_ka = *ka;
if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL;
break; /* will return non-zero "signr" value */ } ... /* * Anything else is fatal, maybe with a core dump. */ current->flags |= PF_SIGNALED;
if (sig_kernel_coredump(signr)) { if (print_fatal_signals) print_fatal_signal(info->si_signo); proc_coredump_connector(current); /* * If it was able to dump core, this kills all * other threads in the group and synchronizes with * their demise. If we lost the race with another * thread getting here, it set group_exit_code * first and our do_group_exit call below will use * that value and ignore the one we pass it. */ do_coredump(info); }
/* * Death signals, no core dump. */ do_group_exit(info->si_signo); /* NOTREACHED */ }
structcoredump_paramscprm = { .siginfo = siginfo, .regs = signal_pt_regs(), .limit = rlimit(RLIMIT_CORE), /* * We must use the same mm->flags while dumping core to avoid * inconsistency of bit flags, since this flag is not protected * by any locks. */ .mm_flags = mm->flags, };
之后会检测当前进程的加载器是否有core_dump指针:
1 2 3
binfmt = mm->binfmt; if (!binfmt || !binfmt->core_dump) goto fail;
/* format_corename will inspect the pattern parameter, and output a * name into corename, which must have space for at least * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator. */ staticintformat_corename(struct core_name *cn, struct coredump_params *cprm) { conststructcred *cred = current_cred(); constchar *pat_ptr = core_pattern; int ispipe = (*pat_ptr == '|'); ... out: return ispipe; }
if (cprm.limit == 1) { /* See umh_pipe_setup() which sets RLIMIT_CORE = 1. * * Normally core limits are irrelevant to pipes, since * we're not writing to the file system, but we use * cprm.limit of 1 here as a speacial value, this is a * consistent way to catch recursive crashes. * We can still crash if the core_pattern binary sets * RLIM_CORE = !1, but it runs as root, and can do * lots of stupid things. * * Note that we use task_tgid_vnr here to grab the pid * of the process group leader. That way we get the * right pid if a thread in a multi-threaded * core_pattern process dies. */ printk(KERN_WARNING "Process %d(%s) has RLIMIT_CORE set to 1\n", task_tgid_vnr(current), current->comm); printk(KERN_WARNING "Aborting core\n"); goto fail_unlock; } cprm.limit = RLIM_INFINITY;
queue_work(system_unbound_wq, &sub_info->work); if (wait == UMH_NO_WAIT) /* task has freed sub_info */ goto unlock;
if (wait & UMH_KILLABLE) { retval = wait_for_completion_killable(&done); if (!retval) goto wait_done;
/* umh_complete() will see NULL and free sub_info */ if (xchg(&sub_info->complete, NULL)) goto unlock; /* fallthrough, umh_complete() was already called */ }
/* This is run by khelper thread */ staticvoid __call_usermodehelper(struct work_struct *work) { structsubprocess_info *sub_info = container_of(work, struct subprocess_info, work); int wait = sub_info->wait & ~UMH_KILLABLE; pid_t pid;
/* CLONE_VFORK: wait until the usermode helper has execve'd * successfully We need the data structures to stay around * until that is done. */ if (wait == UMH_WAIT_PROC) pid = kernel_thread(wait_for_helper, sub_info, CLONE_FS | CLONE_FILES | SIGCHLD); else { pid = kernel_thread(call_helper, sub_info, CLONE_VFORK | SIGCHLD); /* Worker thread stopped blocking khelper thread. */ kmod_thread_locker = NULL; }
switch (wait) { case UMH_NO_WAIT: call_usermodehelper_freeinfo(sub_info); break;
case UMH_WAIT_PROC: if (pid > 0) break; /* FALLTHROUGH */ case UMH_WAIT_EXEC: if (pid < 0) sub_info->retval = pid; umh_complete(sub_info); } }
call_helper最终会调用到____call_usermodehelper:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
if (sub_info->init) { retval = sub_info->init(sub_info, new); if (retval) { abort_creds(new); goto fail; } }
/* * umh_pipe_setup * helper function to customize the process used * to collect the core in userspace. Specifically * it sets up a pipe and installs it as fd 0 (stdin) * for the process. Returns 0 on success, or * PTR_ERR on failure. * Note that it also sets the core limit to 1. This * is a special value that we use to trap recursive * core dumps */ staticintumh_pipe_setup(struct subprocess_info *info, struct cred *new) { structfile *files[2]; structcoredump_params *cp = (struct coredump_params *)info->data; int err = create_pipe_files(files, 0); if (err) return err;
cp->file = files[1];
err = replace_fd(0, files[0], 0); fput(files[0]); /* and disallow core files too */ current->signal->rlim[RLIMIT_CORE] = (struct rlimit){1, 1};
/* get us an unshared descriptor table; almost always a no-op */ retval = unshare_files(&displaced); if (retval) goto close_fail; if (displaced) put_files_struct(displaced); if (!dump_interrupted()) { file_start_write(cprm.file); core_dumped = binfmt->core_dump(&cprm); file_end_write(cprm.file); } if (ispipe && core_pipe_limit) wait_for_dump_helpers(cprm.file); close_fail: if (cprm.file) filp_close(cprm.file, NULL);
[root@default ~]# gdb bad pipecore.5688 GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-119.el7 Copyright (C) 2013 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty"for details. This GDB was configured as "x86_64-redhat-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from /root/bad...done. [New LWP 5688] Core was generated by `./bad'. Program terminated with signal 11, Segmentation fault. #0 0x0000000000400504 in main (argc=1, argv=0x7fff56990d58) at bad.c:5 5 char c = *p; Missing separate debuginfos, use: debuginfo-install glibc-2.17-307.el7.1.x86_64 (gdb)