[lxc-devel] [lxc/master] rexec: handle legacy kernels

brauner on Github lxc-bot at linuxcontainers.org
Mon Feb 18 18:50:19 UTC 2019


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/20190218/45d1bfbd/attachment.bin>
-------------- next part --------------
From 80109327f23c7358c1bed86c148f1df68e43f8df Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 18 Feb 2019 13:32:26 +0100
Subject: [PATCH] rexec: handle legacy kernels

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/file_utils.c   | 45 +++++++++++++++++++++----
 src/lxc/file_utils.h   |  1 +
 src/lxc/memory_utils.h | 16 ++++++---
 src/lxc/rexec.c        | 75 +++++++++++++++++++++++++++++++++++-------
 4 files changed, 115 insertions(+), 22 deletions(-)

diff --git a/src/lxc/file_utils.c b/src/lxc/file_utils.c
index 930fd738a..e5c548cc8 100644
--- a/src/lxc/file_utils.c
+++ b/src/lxc/file_utils.c
@@ -32,6 +32,7 @@
 #include "file_utils.h"
 #include "macro.h"
 #include "string_utils.h"
+#include "utils.h"
 
 int lxc_write_to_file(const char *filename, const void *buf, size_t count,
 		      bool add_newline, mode_t mode)
@@ -218,7 +219,8 @@ int lxc_count_file_lines(const char *fn)
 
 int lxc_make_tmpfile(char *template, bool rm)
 {
-	int fd, ret;
+	__do_close_prot_errno int fd = -EBADF;
+	int ret;
 	mode_t msk;
 
 	msk = umask(0022);
@@ -227,16 +229,17 @@ int lxc_make_tmpfile(char *template, bool rm)
 	if (fd < 0)
 		return -1;
 
+	if (lxc_set_cloexec(fd))
+		return -1;
+
 	if (!rm)
-		return fd;
+		return steal_fd(fd);
 
 	ret = unlink(template);
-	if (ret < 0) {
-		close(fd);
+	if (ret < 0)
 		return -1;
-	}
 
-	return fd;
+	return steal_fd(fd);
 }
 
 bool is_fs_type(const struct statfs *fs, fs_type_magic magic_val)
@@ -366,3 +369,33 @@ char *file_to_buf(char *path, size_t *length)
 
 	return NULL;
 }
+
+int fd_to_fd(int from, int to)
+{
+	for (;;) {
+		uint8_t buf[PATH_MAX];
+		uint8_t *p = buf;
+		ssize_t bytes_to_write;
+		ssize_t bytes_read;
+
+		bytes_read = lxc_read_nointr(from, buf, sizeof buf);
+		if (bytes_read < 0)
+			return -1;
+		if (bytes_read == 0)
+			break;
+
+		bytes_to_write = (size_t)bytes_read;
+		do {
+			ssize_t bytes_written;
+
+			bytes_written = lxc_write_nointr(to, p, bytes_to_write);
+			if (bytes_written < 0)
+				return -1;
+
+			bytes_to_write -= bytes_written;
+			p += bytes_written;
+		} while (bytes_to_write > 0);
+	}
+
+	return 0;
+}
diff --git a/src/lxc/file_utils.h b/src/lxc/file_utils.h
index fc2b7d8c1..cc8f69e18 100644
--- a/src/lxc/file_utils.h
+++ b/src/lxc/file_utils.h
@@ -57,5 +57,6 @@ extern FILE *fopen_cloexec(const char *path, const char *mode);
 extern ssize_t lxc_sendfile_nointr(int out_fd, int in_fd, off_t *offset,
 				   size_t count);
 extern char *file_to_buf(char *path, size_t *length);
+extern int fd_to_fd(int from, int to);
 
 #endif /* __LXC_FILE_UTILS_H */
diff --git a/src/lxc/memory_utils.h b/src/lxc/memory_utils.h
index fdcfb5530..c1dafb441 100644
--- a/src/lxc/memory_utils.h
+++ b/src/lxc/memory_utils.h
@@ -28,6 +28,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include "macro.h"
+
 static inline void __auto_free__(void *p)
 {
 	free(*(void **)p);
@@ -45,13 +47,17 @@ static inline void __auto_closedir__(DIR **d)
 		closedir(*d);
 }
 
+#define close_prot_errno_disarm(fd) \
+	if (fd >= 0) {              \
+		int _e_ = errno;    \
+		close(fd);          \
+		errno = _e_;        \
+		fd = -EBADF;        \
+	}
+
 static inline void __auto_close__(int *fd)
 {
-	if (*fd >= 0) {
-		int e = errno;
-		close(*fd);
-		errno = e;
-	}
+	close_prot_errno_disarm(*fd);
 }
 
 #define __do_close_prot_errno __attribute__((__cleanup__(__auto_close__)))
diff --git a/src/lxc/rexec.c b/src/lxc/rexec.c
index 0589b4a78..2258baae0 100644
--- a/src/lxc/rexec.c
+++ b/src/lxc/rexec.c
@@ -84,42 +84,95 @@ static int parse_argv(char ***argv)
 static int is_memfd(void)
 {
 	__do_close_prot_errno int fd = -EBADF;
-	int saved_errno, seals;
+	int seals;
 
 	fd = open("/proc/self/exe", O_RDONLY | O_CLOEXEC);
 	if (fd < 0)
 		return -ENOTRECOVERABLE;
 
 	seals = fcntl(fd, F_GET_SEALS);
-	if (seals < 0)
+	if (seals < 0) {
+		struct stat s = {0};
+
+		if (fstat(fd, &s) == 0)
+			return (s.st_nlink == 0);
+
 		return -EINVAL;
+	}
 
 	return seals == LXC_MEMFD_REXEC_SEALS;
 }
 
 static void lxc_rexec_as_memfd(char **argv, char **envp, const char *memfd_name)
 {
-	__do_close_prot_errno int fd = -EBADF, memfd = -EBADF;
-	int saved_errno;
-	ssize_t bytes_sent;
+	__do_close_prot_errno int fd = -EBADF, memfd = -EBADF, tmpfd = -EBADF;
+	int ret;
 
 	memfd = memfd_create(memfd_name, MFD_ALLOW_SEALING | MFD_CLOEXEC);
-	if (memfd < 0)
-		return;
+	if (memfd < 0) {
+		char template[PATH_MAX];
+
+		ret = snprintf(template, sizeof(template),
+			       P_tmpdir "/.%s_XXXXXX", memfd_name);
+		if (ret < 0 || (size_t)ret >= sizeof(template))
+			return;
+
+		tmpfd = lxc_make_tmpfile(template, true);
+		if (tmpfd < 0)
+			return;
+
+		ret = fchmod(tmpfd, 0700);
+		if (ret)
+			return;
+	}
 
 	fd = open("/proc/self/exe", O_RDONLY | O_CLOEXEC);
 	if (fd < 0)
 		return;
 
 	/* sendfile() handles up to 2GB. */
-	bytes_sent = lxc_sendfile_nointr(memfd, fd, NULL, LXC_SENDFILE_MAX);
-	if (bytes_sent < 0)
+	if (memfd >= 0) {
+		ssize_t bytes_sent = 0;
+		struct stat st = {0};
+
+		ret = fstat(fd, &st);
+		if (ret)
+			return;
+
+		while (bytes_sent < st.st_size) {
+			ssize_t sent;
+			sent = lxc_sendfile_nointr(memfd, fd, NULL,
+						   st.st_size - bytes_sent);
+			if (sent < 0)
+				return;
+			bytes_sent += sent;
+		}
+	} else if (fd_to_fd(fd, tmpfd)) {
 		return;
+	}
 
-	if (fcntl(memfd, F_ADD_SEALS, LXC_MEMFD_REXEC_SEALS))
+	close_prot_errno_disarm(fd);
+
+	if (memfd >= 0 && fcntl(memfd, F_ADD_SEALS, LXC_MEMFD_REXEC_SEALS))
 		return;
 
-	fexecve(memfd, argv, envp);
+	if (memfd >= 0) {
+		fexecve(memfd, argv, envp);
+	} else {
+		__do_close_prot_errno int execfd = -EBADF;
+		char procfd[LXC_PROC_PID_FD_LEN];
+
+		ret = snprintf(procfd, sizeof(procfd), "/proc/self/fd/%d", tmpfd);
+		if (ret < 0 || (size_t)ret >= sizeof(procfd))
+			return;
+
+		execfd = open(procfd, O_PATH | O_CLOEXEC);
+		close_prot_errno_disarm(tmpfd);
+		if (execfd < 0)
+			return;
+
+		fexecve(execfd, argv, envp);
+	}
 }
 
 /*


More information about the lxc-devel mailing list