guix-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[shepherd] 01/02: Add SIGSEGV/SIGABRT "crash" handler.


From: Ludovic Courtès
Subject: [shepherd] 01/02: Add SIGSEGV/SIGABRT "crash" handler.
Date: Mon, 9 Dec 2019 17:17:10 -0500 (EST)

civodul pushed a commit to branch master
in repository shepherd.

commit dfb7c7ecdb2d12061073e6939ec6e765ae59c00c
Author: Ludovic Courtès <address@hidden>
Date:   Mon Dec 9 23:09:23 2019 +0100

    Add SIGSEGV/SIGABRT "crash" handler.
    
    This allows shepherd to dump core when it's running as PID 1 on
    GNU/Linux.
    
    * etc/crash-handler.c: New file.
    * configure.ac: Define 'BUILD_CRASH_HANDLER' Automake conditional.
    * Makefile.am (EXTRA_DIST): Add 'etc/crash-handler.c'.
    (all-local, install-crash-handler, etc/crash-handler.so) 
[BUILD_CRASH_HANDLER]:
    New targets.
    (CLEANFILES) [BUILD_CRASH_HANDLER]: Add 'etc/crash-handler.so'.
    (install-exec-hook): Depend on 'install-crash-handler'.
    (uninstall-hook): Delete $(pkglibdir)/crash-handler.so.
    (instantiate): Substitute "%pkglibdir%".
    * modules/shepherd/config.scm.in (%pkglibdir): New variable.
    * modules/shepherd.scm (main): Attempt to load "crash-handler.so".
---
 Makefile.am                    | 38 +++++++++++++++--
 configure.ac                   |  8 ++++
 etc/crash-handler.c            | 93 ++++++++++++++++++++++++++++++++++++++++++
 modules/shepherd.scm           |  7 +++-
 modules/shepherd/config.scm.in |  2 +
 5 files changed, 144 insertions(+), 4 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index b6d4831..9a1f019 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -68,6 +68,36 @@ CLEANFILES =                                         \
   $(nodist_scriptsgo_DATA)                             \
   $(bin_SCRIPTS) $(sbin_SCRIPTS)
 
+
+# Crash handler.
+
+EXTRA_DIST = etc/crash-handler.c
+
+if BUILD_CRASH_HANDLER
+
+# Build the crash handler "manually" rather than with Libtool.
+
+all-local: etc/crash-handler.so
+install-crash-handler:
+       $(MKDIR_P) $(DESTDIR)$(pkglibdir)
+       $(INSTALL) -m 755 etc/crash-handler.so \
+                  $(DESTDIR)$(pkglibdir)/crash-handler.so
+
+etc/crash-handler.so: etc/crash-handler.c
+       $(AM_V_GEN)$(MKDIR_P) etc;                      \
+       $(CC) -O2 -g -Wall -shared -fPIC -o "$@" "$^"
+
+CLEANFILES += etc/crash-handler.so
+
+else !BUILD_CRASH_HANDLER
+
+install-crash-handler:
+
+endif !BUILD_CRASH_HANDLER
+
+.PHONY: install-crash-handler
+
+
 # Documentation.
 info_TEXINFOS = doc/shepherd.texi
 doc_shepherd_TEXINFOS = doc/fdl-1.3.texi
@@ -93,7 +123,7 @@ dist_man1_MANS = doc/shepherd.1 doc/herd.1
 dist_man8_MANS = doc/halt.8 doc/reboot.8
 
 # Things not automatically included in the distribution.
-EXTRA_DIST =                                   \
+EXTRA_DIST +=                                  \
   build-aux/config.rpath                       \
   ChangeLog-2003                               \
   QUESTIONS                                    \
@@ -111,7 +141,7 @@ install-data-local:
 
 # Relocate the script---i.e., have them refer to the installed module
 # directory.
-install-exec-hook: install-executable-symlinks
+install-exec-hook: install-executable-symlinks install-crash-handler
        for script in                                                   \
           $(bin_SCRIPTS:%=$(DESTDIR)$(bindir)/%)                       \
           $(sbin_SCRIPTS:%=$(DESTDIR)$(sbindir)/%) ;                   \
@@ -126,9 +156,10 @@ install-exec-hook: install-executable-symlinks
 install-executable-symlinks:
        cd $(DESTDIR)$(sbindir); ln -s halt shutdown
 
-# Remove the 'shutdown' symlink.
+# Remove the 'shutdown' symlink and 'crash-handler.so'.
 uninstall-hook:
        cd $(DESTDIR)$(sbindir); rm -f shutdown
+       cd $(DESTDIR)$(pkglibdir); rm -f crash-handler.so
 
 # 'sed' expression to instantiate templates.
 instantiate =                                          \
@@ -136,6 +167,7 @@ instantiate =                                               
\
   -e 's,%modsrcdir%,${abs_top_srcdir}/modules,g'       \
   -e 's,%modbuilddir%,${abs_top_builddir}/modules,g'   \
   -e 's,%localstatedir%,${localstatedir},g'            \
+  -e 's,%pkglibdir%,${pkglibdir},g'                    \
   -e 's,%sysconfdir%,${sysconfdir},g'                  \
   -e 's,%localedir%,${localedir},g'                    \
   -e 's,%VERSION%,@VERSION@,g'                         \
diff --git a/configure.ac b/configure.ac
index 58c4978..1fc6c2f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -87,6 +87,14 @@ AC_COMPUTE_INT([PR_SET_CHILD_SUBREAPER], 
[PR_SET_CHILD_SUBREAPER], [#include <sy
 AC_SUBST([PR_SET_CHILD_SUBREAPER])
 AC_MSG_RESULT([done])
 
+AC_MSG_CHECKING([whether to build crash handler])
+case "$host_os" in
+  linux-gnu*)  build_crash_handler=yes;;
+  *)           build_crash_handler=no;;
+esac
+AC_MSG_RESULT([$build_crash_handler])
+AM_CONDITIONAL([BUILD_CRASH_HANDLER], [test "x$build_crash_handler" = "xyes"])
+
 dnl Manual pages.
 AM_MISSING_PROG([HELP2MAN], [help2man])
 
diff --git a/etc/crash-handler.c b/etc/crash-handler.c
new file mode 100644
index 0000000..2921002
--- /dev/null
+++ b/etc/crash-handler.c
@@ -0,0 +1,93 @@
+/* crash-handler.c -- PID 1 helper to dump core upon a crash on GNU/Linux.
+   Copyright © 2019 Ludovic Courtès <address@hidden>
+
+   This file is part of the GNU Shepherd.
+
+   The GNU Shepherd is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or (at
+   your option) any later version.
+
+   The GNU Shepherd is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Shepherd.  If not, see <http://www.gnu.org/licenses/>.  
*/
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sched.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/syscall.h>   /* For SYS_xxx definitions */
+#include <signal.h>
+
+/* Arrange to dump core.  */
+static void
+handle_crash (int sig)
+{
+  static const char msg[] = "Shepherd crashed!\n";
+  write (2, msg, sizeof msg);
+
+#ifdef __sparc__
+  /* See 'raw_clone' in systemd.  */
+# error "SPARC uses a different 'clone' syscall convention"
+#endif
+
+  /* Start a child process that will be able to dump core.  */
+  pid_t pid = syscall (SYS_clone, SIGCHLD, NULL);
+  if (pid < 0)
+    abort ();
+
+  if (pid == 0)
+    {
+      /* Restore the default signal handler to get a core dump.  */
+      signal (sig, SIG_DFL);
+
+      const struct rlimit infinity = { RLIM_INFINITY, RLIM_INFINITY };
+      setrlimit (RLIMIT_CORE, &infinity);
+      chdir ("/");
+
+      int pid = syscall (SYS_getpid);
+      kill (pid, sig);
+
+      /* As it turns out, 'kill' simply returns without doing anything, which
+        is consistent with the "Notes" section of kill(2).  Thus, force a
+        crash.  */
+      * (int *) 0 = 42;
+
+      _exit (254);
+    }
+  else
+    {
+      /* Wait for the child process and terminate.  */
+      signal (sig, SIG_IGN);
+
+      int status;
+      waitpid (pid, &status, 0);
+
+      sync ();
+
+      _exit (255);
+    }
+
+  _exit (253);
+}
+
+static void initialize_crash_handler (void)
+  __attribute__ ((constructor));
+
+static void
+initialize_crash_handler (void)
+{
+  /* Register raw signal handlers.  This cannot be done in Scheme because the
+     handler can only call async-signal-safe functions.  */
+  signal (SIGSEGV, handle_crash);
+  signal (SIGABRT, handle_crash);
+}
diff --git a/modules/shepherd.scm b/modules/shepherd.scm
index 769085a..3812f8a 100644
--- a/modules/shepherd.scm
+++ b/modules/shepherd.scm
@@ -211,7 +211,12 @@ socket file at FILE-NAME upon exit of PROC.  Return the 
values of PROC."
               ;; 'reboot_pid_ns' in kernel/pid_namespace.c.)  We get EPERM in
               ;; a user namespace that lacks CAP_SYS_BOOT.
               (unless (member err (list EINVAL EPERM))
-                (apply throw args))))))
+                (apply throw args)))))
+
+        ;; Load the SIGSEGV/SIGABRT handler.  This is what allows PID 1 to
+        ;; dump core on "/", should something go wrong.
+        (false-if-exception
+         (dynamic-link (string-append %pkglibdir "/crash-handler"))))
 
       ;; Stop everything when we get SIGINT.
       (sigaction SIGINT
diff --git a/modules/shepherd/config.scm.in b/modules/shepherd/config.scm.in
index 547b885..def5442 100644
--- a/modules/shepherd/config.scm.in
+++ b/modules/shepherd/config.scm.in
@@ -6,6 +6,7 @@
             %localstatedir
             %sysconfdir
             %localedir
+            %pkglibdir
             copyright
             bug-address
             package-name
@@ -16,6 +17,7 @@
 (define %localstatedir "%localstatedir%")
 (define %sysconfdir "%sysconfdir%")
 (define %localedir "%localedir%")
+(define %pkglibdir "%pkglibdir%")
 
 (define copyright "Copyright (C) 2002, 2003 Wolfgang J�hrling")
 (define bug-address "%PACKAGE_BUGREPORT%")



reply via email to

[Prev in Thread] Current Thread [Next in Thread]