]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
execute: ensure parent is notified about child exec and close all unneeded fds 3885/head
authorChristian Brauner <christian.brauner@ubuntu.com>
Tue, 29 Jun 2021 08:32:31 +0000 (10:32 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Tue, 29 Jun 2021 09:20:55 +0000 (11:20 +0200)
lxc_container_init() creates the container payload process as it's child
so lxc_container_init() itself never really exits and thus the parent
isn't notified about the child exec'ing since the sync file descriptor
is never closed. Make sure it's closed to notify the parent about the
child's exec.

In addition we're currently leaking all file descriptors associated with
the handler into the stub init. Make sure that all file descriptors
other than stderr are closed.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/conf.h
src/lxc/initutils.c

index 625e80955b5576db9fc9f400de2ed00a5aaec4ab..cdefc2ad5c4d9903ecc91e00c3e15c97f55fad0b 100644 (file)
 #include "list.h"
 #include "lxcseccomp.h"
 #include "memory_utils.h"
+#include "namespace.h"
 #include "ringbuf.h"
 #include "start.h"
+#include "state.h"
 #include "storage/storage.h"
 #include "string_utils.h"
 #include "syscall_wrappers.h"
index 21a7c1a05a9fa0fcd8814ce6d89eecf5620e35e4..f5e41804dd858d24918e4ddd0e55576c3ce6faac 100644 (file)
@@ -429,6 +429,46 @@ static void interrupt_handler(int sig)
                was_interrupted = sig;
 }
 
+static int close_inherited(void)
+{
+       int fddir;
+       DIR *dir;
+       struct dirent *direntp;
+
+restart:
+       dir = opendir("/proc/self/fd");
+       if (!dir)
+               return -errno;
+
+       fddir = dirfd(dir);
+
+       while ((direntp = readdir(dir))) {
+               int fd, ret;
+
+               if (strcmp(direntp->d_name, ".") == 0)
+                       continue;
+
+               if (strcmp(direntp->d_name, "..") == 0)
+                       continue;
+
+               ret = lxc_safe_int(direntp->d_name, &fd);
+               if (ret < 0)
+                       continue;
+
+               if (fd == STDERR_FILENO || fd == fddir)
+                       break;
+
+               if (close(fd))
+                       return -errno;
+
+               closedir(dir);
+               goto restart;
+       }
+
+       closedir(dir);
+       return 0;
+}
+
 __noreturn int lxc_container_init(int argc, char *const *argv, bool quiet)
 {
        int i, logfd, ret;
@@ -565,9 +605,22 @@ __noreturn int lxc_container_init(int argc, char *const *argv, bool quiet)
                exit(EXIT_FAILURE);
        }
 
-       /* No need of other inherited fds but stderr. */
-       close(STDIN_FILENO);
-       close(STDOUT_FILENO);
+       ret = close_range(STDERR_FILENO + 1, UINT_MAX, CLOSE_RANGE_UNSHARE);
+       if (ret) {
+               /*
+                * Fallback to close_inherited() when the syscall is not
+                * available or when CLOSE_RANGE_UNSHARE isn't supported.
+                * On a regular kernel CLOSE_RANGE_UNSHARE should always be
+                * available but openSUSE Leap 15.3 seems to have a partial
+                * backport without CLOSE_RANGE_UNSHARE support.
+                */
+               if (errno == ENOSYS || errno == EINVAL)
+                       ret = close_inherited();
+       }
+       if (ret) {
+               fprintf(stderr, "Aborting attach to prevent leaking file descriptors into container\n");
+               exit(EXIT_FAILURE);
+       }
 
        for (;;) {
                int status;