1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <sys/reboot.h>
4 
5 #include "crash-handler.h"
6 #include "exit-status.h"
7 #include "macro.h"
8 #include "main.h"
9 #include "missing_syscall.h"
10 #include "process-util.h"
11 #include "raw-clone.h"
12 #include "rlimit-util.h"
13 #include "signal-util.h"
14 #include "terminal-util.h"
15 #include "virt.h"
16 
freeze_or_exit_or_reboot(void)17 _noreturn_ void freeze_or_exit_or_reboot(void) {
18 
19         /* If we are running in a container, let's prefer exiting, after all we can propagate an exit code to
20          * the container manager, and thus inform it that something went wrong. */
21         if (detect_container() > 0) {
22                 log_emergency("Exiting PID 1...");
23                 _exit(EXIT_EXCEPTION);
24         }
25 
26         if (arg_crash_reboot) {
27                 log_notice("Rebooting in 10s...");
28                 (void) sleep(10);
29 
30                 log_notice("Rebooting now...");
31                 (void) reboot(RB_AUTOBOOT);
32                 log_emergency_errno(errno, "Failed to reboot: %m");
33         }
34 
35         log_emergency("Freezing execution.");
36         sync();
37         freeze();
38 }
39 
crash(int sig,siginfo_t * siginfo,void * context)40 _noreturn_ static void crash(int sig, siginfo_t *siginfo, void *context) {
41         struct sigaction sa;
42         pid_t pid;
43 
44         /* NB: �� �� �� This is a signal handler, most likely executed in a situation where we have corrupted
45          * memory. Thus: please avoid any libc memory allocation here, or any functions that internally use
46          * memory allocation, as we cannot rely on memory allocation still working at this point! (Note that
47          * memory allocation is not async-signal-safe anyway — see signal-safety(7) for details —, and thus
48          * is not permissible in signal handlers.) */
49 
50         if (getpid_cached() != 1)
51                 /* Pass this on immediately, if this is not PID 1 */
52                 (void) raise(sig);
53         else if (!arg_dump_core)
54                 log_emergency("Caught <%s>, not dumping core.", signal_to_string(sig));
55         else {
56                 sa = (struct sigaction) {
57                         .sa_handler = nop_signal_handler,
58                         .sa_flags = SA_NOCLDSTOP|SA_RESTART,
59                 };
60 
61                 /* We want to wait for the core process, hence let's enable SIGCHLD */
62                 (void) sigaction(SIGCHLD, &sa, NULL);
63 
64                 pid = raw_clone(SIGCHLD);
65                 if (pid < 0)
66                         log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig));
67                 else if (pid == 0) {
68                         /* Enable default signal handler for core dump */
69 
70                         sa = (struct sigaction) {
71                                 .sa_handler = SIG_DFL,
72                         };
73                         (void) sigaction(sig, &sa, NULL);
74 
75                         /* Don't limit the coredump size */
76                         (void) setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY));
77 
78                         /* Just to be sure... */
79                         (void) chdir("/");
80 
81                         /* Raise the signal again */
82                         pid = raw_getpid();
83                         (void) kill(pid, sig); /* raise() would kill the parent */
84 
85                         assert_not_reached();
86                         _exit(EXIT_EXCEPTION);
87                 } else {
88                         siginfo_t status;
89                         int r;
90 
91                         if (siginfo) {
92                                 if (siginfo->si_pid == 0)
93                                         log_emergency("Caught <%s> from unknown sender process.", signal_to_string(sig));
94                                 else if (siginfo->si_pid == 1)
95                                         log_emergency("Caught <%s> from our own process.", signal_to_string(sig));
96                                 else
97                                         log_emergency("Caught <%s> from PID "PID_FMT".", signal_to_string(sig), siginfo->si_pid);
98                         }
99 
100                         /* Order things nicely. */
101                         r = wait_for_terminate(pid, &status);
102                         if (r < 0)
103                                 log_emergency_errno(r, "Caught <%s>, waitpid() failed: %m", signal_to_string(sig));
104                         else if (status.si_code != CLD_DUMPED) {
105                                 const char *s = status.si_code == CLD_EXITED
106                                         ? exit_status_to_string(status.si_status, EXIT_STATUS_LIBC)
107                                         : signal_to_string(status.si_status);
108 
109                                 log_emergency("Caught <%s>, core dump failed (child "PID_FMT", code=%s, status=%i/%s).",
110                                               signal_to_string(sig),
111                                               pid,
112                                               sigchld_code_to_string(status.si_code),
113                                               status.si_status, strna(s));
114                         } else
115                                 log_emergency("Caught <%s>, dumped core as pid "PID_FMT".",
116                                               signal_to_string(sig), pid);
117                 }
118         }
119 
120         if (arg_crash_chvt >= 0)
121                 (void) chvt(arg_crash_chvt);
122 
123         sa = (struct sigaction) {
124                 .sa_handler = SIG_IGN,
125                 .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART,
126         };
127 
128         /* Let the kernel reap children for us */
129         (void) sigaction(SIGCHLD, &sa, NULL);
130 
131         if (arg_crash_shell) {
132                 log_notice("Executing crash shell in 10s...");
133                 (void) sleep(10);
134 
135                 pid = raw_clone(SIGCHLD);
136                 if (pid < 0)
137                         log_emergency_errno(errno, "Failed to fork off crash shell: %m");
138                 else if (pid == 0) {
139                         (void) setsid();
140                         (void) make_console_stdio();
141                         (void) rlimit_nofile_safe();
142                         (void) execle("/bin/sh", "/bin/sh", NULL, environ);
143 
144                         log_emergency_errno(errno, "execle() failed: %m");
145                         _exit(EXIT_EXCEPTION);
146                 } else {
147                         log_info("Spawned crash shell as PID "PID_FMT".", pid);
148                         (void) wait_for_terminate(pid, NULL);
149                 }
150         }
151 
152         freeze_or_exit_or_reboot();
153 }
154 
install_crash_handler(void)155 void install_crash_handler(void) {
156         static const struct sigaction sa = {
157                 .sa_sigaction = crash,
158                 .sa_flags = SA_NODEFER | SA_SIGINFO, /* So that we can raise the signal again from the signal handler */
159         };
160         int r;
161 
162         /* We ignore the return value here, since, we don't mind if we cannot set up a crash handler */
163         r = sigaction_many(&sa, SIGNALS_CRASH_HANDLER);
164         if (r < 0)
165                 log_debug_errno(r, "I had trouble setting up the crash handler, ignoring: %m");
166 }
167