nspawn: close extra fds before execing init
authorAlban Crequy <alban@endocode.com>
Mon, 18 May 2015 14:45:30 +0000 (16:45 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 18 May 2015 20:24:15 +0000 (22:24 +0200)
When systemd-nspawn gets exec*()ed, it inherits the followings file
descriptors:
- 0, 1, 2: stdin, stdout, stderr
- SD_LISTEN_FDS_START, ... SD_LISTEN_FDS_START+LISTEN_FDS: file
  descriptors passed by the system manager (useful for socket
  activation). They are passed to the child process (process leader).
- extra lock fd: rkt passes a locked directory as an extra fd, so the
  directory remains locked as long as the container is alive.

systemd-nspawn used to close all open fds except 0, 1, 2 and the
SD_LISTEN_FDS_START..SD_LISTEN_FDS_START+LISTEN_FDS. This patch delays
the close just before the exec so the nspawn process (parent) keeps the
extra fds open.

This patch supersedes the previous attempt ("cloexec extraneous fds"):
http://lists.freedesktop.org/archives/systemd-devel/2015-May/031608.html

src/nspawn/nspawn.c

index 4095c77..a38f47d 100644 (file)
@@ -3990,7 +3990,6 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        log_close();
         n_fd_passed = sd_listen_fds(false);
         if (n_fd_passed > 0) {
                 r = fdset_new_listen_fds(&fds, false);
@@ -3999,8 +3998,6 @@ int main(int argc, char *argv[]) {
                         goto finish;
                 }
         }
-        fdset_close_others(fds);
-        log_open();
 
         if (arg_directory) {
                 assert(!arg_image);
@@ -4510,6 +4507,17 @@ int main(int argc, char *argv[]) {
                          * setup, too... */
                         (void) barrier_place_and_sync(&barrier); /* #5 */
 
+                        /* Now, explicitly close the log, so that we
+                         * then can close all remaining fds. Closing
+                         * the log explicitly first has the benefit
+                         * that the logging subsystem knows about it,
+                         * and is thus ready to be reopened should we
+                         * need it again. Note that the other fds
+                         * closed here are at least the locking and
+                         * barrier fds. */
+                        log_close();
+                        (void) fdset_close_others(fds);
+
                         if (arg_boot) {
                                 char **a;
                                 size_t l;
@@ -4536,6 +4544,7 @@ int main(int argc, char *argv[]) {
                                 execle("/bin/sh", "-sh", NULL, env_use);
                         }
 
+                        (void) log_open();
                         log_error_errno(errno, "execv() failed: %m");
                         _exit(EXIT_FAILURE);
                 }