execute: ensure parent is notified about child exec and close all unneeded fds

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: 's avatarChristian Brauner <christian.brauner@ubuntu.com>
parent a1150aa1
...@@ -22,8 +22,10 @@ ...@@ -22,8 +22,10 @@
#include "list.h" #include "list.h"
#include "lxcseccomp.h" #include "lxcseccomp.h"
#include "memory_utils.h" #include "memory_utils.h"
#include "namespace.h"
#include "ringbuf.h" #include "ringbuf.h"
#include "start.h" #include "start.h"
#include "state.h"
#include "storage/storage.h" #include "storage/storage.h"
#include "string_utils.h" #include "string_utils.h"
#include "syscall_wrappers.h" #include "syscall_wrappers.h"
......
...@@ -429,6 +429,46 @@ static void interrupt_handler(int sig) ...@@ -429,6 +429,46 @@ static void interrupt_handler(int sig)
was_interrupted = 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) __noreturn int lxc_container_init(int argc, char *const *argv, bool quiet)
{ {
int i, logfd, ret; int i, logfd, ret;
...@@ -565,9 +605,22 @@ __noreturn int lxc_container_init(int argc, char *const *argv, bool quiet) ...@@ -565,9 +605,22 @@ __noreturn int lxc_container_init(int argc, char *const *argv, bool quiet)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* No need of other inherited fds but stderr. */ ret = close_range(STDERR_FILENO + 1, UINT_MAX, CLOSE_RANGE_UNSHARE);
close(STDIN_FILENO); if (ret) {
close(STDOUT_FILENO); /*
* 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 (;;) { for (;;) {
int status; int status;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment