[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