mirror of
https://github.com/troglobit/finit.git
synced 2026-11-06 15:51:03 +00:00
Trap segfaults caused by service callbacks in separate process context
This patch traps segfaults caused by 3rd party service callbacks in a separate process context. Effectively preventing a single programming mistake from taking down the entire system. Previously it was up to the callback coder to write error free code so that PID 1 did not crash. Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
1 parent
d6efe85a57
commit
b4b63d3722
2 files changed
+46
-3
No files matched your search
@@ -49,7 +49,7 @@
|
|||||||
|
|
||||||
static int stopped = 0;
|
static int stopped = 0;
|
||||||
static uev_t sigint_watcher, sigpwr_watcher;
|
static uev_t sigint_watcher, sigpwr_watcher;
|
||||||
static uev_t sigchld_watcher;
|
static uev_t sigchld_watcher, sigsegv_watcher;
|
||||||
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
|
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
|
||||||
|
|
||||||
|
|
||||||
@@ -103,6 +103,15 @@ static void sigchld_cb(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *UNUSED(ar
|
|||||||
svc_monitor(waitpid(-1, NULL, WNOHANG));
|
svc_monitor(waitpid(-1, NULL, WNOHANG));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SIGSEGV: mostly if service callbacks segfault
|
||||||
|
*/
|
||||||
|
static void sigsegv_cb(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||||
|
{
|
||||||
|
_e("PID %d caused a segfault!\n", getpid());
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SIGSTOP/SIGTSTP: Paused by user or netflash
|
* SIGSTOP/SIGTSTP: Paused by user or netflash
|
||||||
*/
|
*/
|
||||||
@@ -204,6 +213,9 @@ void sig_setup(uev_ctx_t *ctx)
|
|||||||
/* After initial bootstrap of Finit we call the service monitor to reap children */
|
/* After initial bootstrap of Finit we call the service monitor to reap children */
|
||||||
uev_signal_init(ctx, &sigchld_watcher, sigchld_cb, NULL, SIGCHLD);
|
uev_signal_init(ctx, &sigchld_watcher, sigchld_cb, NULL, SIGCHLD);
|
||||||
|
|
||||||
|
/* Trap SIGSEGV in case service callbacks crash */
|
||||||
|
uev_signal_init(ctx, &sigsegv_watcher, sigsegv_cb, NULL, SIGSEGV);
|
||||||
|
|
||||||
/* Stopping init is a bit tricky. */
|
/* Stopping init is a bit tricky. */
|
||||||
uev_signal_init(ctx, &sigstop_watcher, sigstop_cb, NULL, SIGSTOP);
|
uev_signal_init(ctx, &sigstop_watcher, sigstop_cb, NULL, SIGSTOP);
|
||||||
uev_signal_init(ctx, &sigtstp_watcher, sigstop_cb, NULL, SIGTSTP);
|
uev_signal_init(ctx, &sigtstp_watcher, sigstop_cb, NULL, SIGTSTP);
|
||||||
|
|||||||
@@ -395,8 +395,39 @@ svc_cmd_t svc_enabled(svc_t *svc, int event, void *arg)
|
|||||||
return SVC_STOP;
|
return SVC_STOP;
|
||||||
|
|
||||||
/* Is there a service plugin registered? */
|
/* Is there a service plugin registered? */
|
||||||
if (svc->cb)
|
if (svc->cb) {
|
||||||
return svc->cb(svc, event, arg);
|
int status;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
/* Let callback run in separate process so it doesn't crash PID 1 */
|
||||||
|
pid = fork();
|
||||||
|
if (-1 == pid) {
|
||||||
|
_pe("Failed in %s callback", svc->cmd);
|
||||||
|
return SVC_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pid) {
|
||||||
|
status = svc->cb(svc, event, arg);
|
||||||
|
exit(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waitpid(pid, &status, 0) == -1) {
|
||||||
|
_pe("Failed reading status from %s callback", svc->cmd);
|
||||||
|
return SVC_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callback normally exits here. */
|
||||||
|
if (WIFEXITED(status))
|
||||||
|
return WEXITSTATUS(status);
|
||||||
|
|
||||||
|
/* Check for SEGFAULT or other error ... */
|
||||||
|
if (WCOREDUMP(status))
|
||||||
|
_e("Callback to %s crashed!\n", svc->cmd);
|
||||||
|
else
|
||||||
|
_e("Callback to %s did not exit normally!\n", svc->cmd);
|
||||||
|
|
||||||
|
return SVC_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
/* No service plugin, default to start, since listed in finit.conf */
|
/* No service plugin, default to start, since listed in finit.conf */
|
||||||
return SVC_START;
|
return SVC_START;
|
||||||
|
|||||||
Reference in new issue
Block a user