]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Add variant of close_all_fds() that does not allocate and use it in freeze() 20288/head
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 23 Jul 2021 09:36:44 +0000 (11:36 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 23 Jul 2021 09:39:45 +0000 (11:39 +0200)
Even though it's just a fallback path, let's not be sloppy and allocate in
the crash handler.

> The deadlock happens because systemd crash in malloc() then in signal
> handler, it calls malloc() (close_all_fds()-> opendir()-> __alloc_dir())
> again. malloc() is not a signal-safe function, maybe we should re-think
> the logic here.

Fixes #20266.

src/basic/fd-util.c
src/basic/fd-util.h
src/shared/exec-util.c

index 99b517d8c2f0090e433caac6a7db9408ce59a39e..6b6457dbc22a6baffb77b27c71ccef5b37e3cfe0 100644 (file)
@@ -208,7 +208,7 @@ static int get_max_fd(void) {
         return (int) (m - 1);
 }
 
-int close_all_fds(int except[], size_t n_except) {
+int close_all_fds_full(int except[], size_t n_except, bool allow_alloc) {
         static bool have_close_range = true; /* Assume we live in the future */
         _cleanup_closedir_ DIR *d = NULL;
         int r = 0;
@@ -274,7 +274,7 @@ int close_all_fds(int except[], size_t n_except) {
 
         /* Fallback for when close_range() is not supported */
  opendir_fallback:
-        d = opendir("/proc/self/fd");
+        d = allow_alloc ? opendir("/proc/self/fd") : NULL;
         if (d) {
                 struct dirent *de;
 
@@ -302,8 +302,8 @@ int close_all_fds(int except[], size_t n_except) {
                 return r;
         }
 
-        /* Fallback for when /proc isn't available (for example in chroots) by brute-forcing through the file
-         * descriptor table. */
+        /* Fallback for when /proc isn't available (for example in chroots) or when we cannot allocate by
+         * brute-forcing through the file descriptor table. */
 
         int max_fd = get_max_fd();
         if (max_fd < 0)
index d3c2944d869a69a26d94f1167aa423b86093734c..61b6684cb3c156a8d9040bf6acce590d406d1c44 100644 (file)
@@ -56,7 +56,10 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(DIR*, closedir, NULL);
 int fd_nonblock(int fd, bool nonblock);
 int fd_cloexec(int fd, bool cloexec);
 
-int close_all_fds(int except[], size_t n_except);
+int close_all_fds_full(int except[], size_t n_except, bool allow_alloc);
+static inline int close_all_fds(int except[], size_t n_except) {
+        return close_all_fds_full(except, n_except, true);
+}
 
 int same_fd(int a, int b);
 
index 42f6c4d75ad3936c9293df2fd2714aa721e15b82..cffa3fe96e7644ce63f6a1cec37958f64c523c62 100644 (file)
@@ -452,7 +452,7 @@ _noreturn_ void freeze(void) {
         log_close();
 
         /* Make sure nobody waits for us on a socket anymore */
-        (void) close_all_fds(NULL, 0);
+        (void) close_all_fds_full(NULL, 0, false);
 
         sync();