[lxc-devel] [lxd/master] forkexec: close all inherited fds
brauner on Github
lxc-bot at linuxcontainers.org
Fri Apr 10 09:14:26 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200410/425a629e/attachment.bin>
-------------- next part --------------
From 51d0971bf2c8aab88992eab0ccc098137496df86 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 10 Apr 2020 11:06:35 +0200
Subject: [PATCH] forkexec: close all inherited fds
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
lxd/main_forkexec.go | 85 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 84 insertions(+), 1 deletion(-)
diff --git a/lxd/main_forkexec.go b/lxd/main_forkexec.go
index ea2451e8df..3d69fa80ad 100644
--- a/lxd/main_forkexec.go
+++ b/lxd/main_forkexec.go
@@ -122,6 +122,86 @@ static int fd_cloexec(int fd, bool cloexec)
return 0;
}
+static int safe_int(const char *numstr, int *converted)
+{
+ char *err = NULL;
+ signed long int sli;
+
+ errno = 0;
+ sli = strtol(numstr, &err, 0);
+ if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
+ return -ERANGE;
+
+ if (errno != 0 && sli == 0)
+ return -EINVAL;
+
+ if (err == numstr || *err != '\0')
+ return -EINVAL;
+
+ if (sli > INT_MAX || sli < INT_MIN)
+ return -ERANGE;
+
+ *converted = (int)sli;
+ return 0;
+}
+
+static inline bool match_stdfds(int fd)
+{
+ return (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO);
+}
+
+static int close_inherited(int *fds_to_ignore, size_t len_fds)
+{
+ 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;
+ size_t i;
+
+ if (strcmp(direntp->d_name, ".") == 0)
+ continue;
+
+ if (strcmp(direntp->d_name, "..") == 0)
+ continue;
+
+ ret = safe_int(direntp->d_name, &fd);
+ if (ret < 0)
+ continue;
+
+ for (i = 0; i < len_fds; i++)
+ if (fds_to_ignore[i] == fd)
+ break;
+
+ if (fd == fddir || (i < len_fds && fd == fds_to_ignore[i]))
+ continue;
+
+ if (match_stdfds(fd))
+ continue;
+
+ close(fd);
+ closedir(dir);
+ goto restart;
+ }
+
+ closedir(dir);
+ return 0;
+}
+
+#define EXEC_STDIN_FD 3
+#define EXEC_STDOUT_FD 4
+#define EXEC_STDERR_FD 5
+#define EXEC_PIPE_FD 6
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
// We use a separate function because cleanup macros are called during stack
// unwinding if I'm not mistaken and if the compiler knows it exits it won't
// call them. That's not a problem since we're exiting but I just like to be on
@@ -129,7 +209,7 @@ static int fd_cloexec(int fd, bool cloexec)
// tell the compiler to not inline us.
__attribute__ ((noinline)) static int __forkexec(void)
{
- __do_close int status_pipe = 6;
+ __do_close int status_pipe = EXEC_PIPE_FD;
__do_free_string_list char **argvp = NULL, **envvp = NULL;
call_cleaner(lxc_container_put) struct lxc_container *c = NULL;
const char *config_path = NULL, *lxcpath = NULL, *name = NULL;
@@ -138,6 +218,7 @@ __attribute__ ((noinline)) static int __forkexec(void)
lxc_attach_command_t command = {
.program = NULL,
};
+ int fds_to_ignore[] = {EXEC_STDIN_FD, EXEC_STDOUT_FD, EXEC_STDERR_FD, EXEC_PIPE_FD};
int ret;
pid_t pid;
uid_t uid;
@@ -191,6 +272,8 @@ __attribute__ ((noinline)) static int __forkexec(void)
if (!argvp || !*argvp)
return log_error(EXIT_FAILURE, "No command specified");
+ close_inherited(fds_to_ignore, ARRAY_SIZE(fds_to_ignore));
+
ret = fd_cloexec(status_pipe, true);
if (ret)
return EXIT_FAILURE;
More information about the lxc-devel
mailing list