From 621c01059536ec167da8c9d5571e8bf860b4dadb Mon Sep 17 00:00:00 2001
From: wangfengtu <wangfengtu@huawei.com>
Date: Wed, 13 Feb 2019 05:26:38 -0500
Subject: [PATCH 91/94] runc:  cve-2019-5736: workaround if
 memfd_create and O_TMPFILE not work

[Changelog]: create tmpfile using mkostemp when memfd_create and
O_TMPFILE not work
[Author]: git

Change-Id: I785295b19759487ddaa5e0dcb5c11e4aa9ace838
Signed-off-by: sdu.liu <sdu.liu@huawei.com>
Signed-off-by: wangfengtu <wangfengtu@huawei.com>
---
 libcontainer/nsenter/cloned_binary.c | 117 +++++++++++++++++++++++++----------
 script/runc-euleros.spec             |   2 +-
 2 files changed, 87 insertions(+), 32 deletions(-)

diff --git a/libcontainer/nsenter/cloned_binary.c b/libcontainer/nsenter/cloned_binary.c
index c8a42c2..e59d434 100644
--- a/libcontainer/nsenter/cloned_binary.c
+++ b/libcontainer/nsenter/cloned_binary.c
@@ -71,6 +71,14 @@ int memfd_create(const char *name, unsigned int flags)
 	(F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE)
 #endif
 
+enum clone_type
+{
+	USING_MEMFD = 0,
+	USING_UNAMED_FILE,
+	USING_TMPFILE,
+};
+
+
 static void *must_realloc(void *ptr, size_t size)
 {
 	void *old = ptr;
@@ -80,6 +88,23 @@ static void *must_realloc(void *ptr, size_t size)
 	return ptr;
 }
 
+static int get_clone_type()
+{
+	int memfd = 0;
+#ifdef HAVE_MEMFD_CREATE
+	memfd = memfd_create(RUNC_MEMFD_COMMENT, MFD_CLOEXEC | MFD_ALLOW_SEALING);
+	if (memfd > 0 || memfd == 0) {
+		close(memfd);
+		return USING_MEMFD;
+	}
+#else
+#ifdef O_TMPFILE
+	return USING_UNAMED_FILE;
+#endif
+#endif
+	return USING_TMPFILE;
+}
+
 /*
  * Verify whether we are currently in a self-cloned program (namely, is
  * /proc/self/exe a memfd). F_GET_SEALS will only succeed for memfds (or rather
@@ -87,21 +112,23 @@ static void *must_realloc(void *ptr, size_t size)
  */
 static int is_self_cloned(void)
 {
-	int fd, ret, is_cloned = 0;
+	int fd, ret, type, is_cloned = 0;
 
 	fd = open("/proc/self/exe", O_RDONLY|O_CLOEXEC);
 	if (fd < 0)
 		return -ENOTRECOVERABLE;
+	type = get_clone_type();
+
+	if (type == USING_MEMFD) {
+		ret = fcntl(fd, F_GET_SEALS);
+		is_cloned = (ret == RUNC_MEMFD_SEALS);
+	} else {
+		struct stat statbuf = {0};
+		ret = fstat(fd, &statbuf);
+		if (ret >= 0)
+			is_cloned = (statbuf.st_nlink == 0);
+	}
 
-#ifdef HAVE_MEMFD_CREATE
-	ret = fcntl(fd, F_GET_SEALS);
-	is_cloned = (ret == RUNC_MEMFD_SEALS);
-#else
-	struct stat statbuf = {0};
-	ret = fstat(fd, &statbuf);
-	if (ret >= 0)
-		is_cloned = (statbuf.st_nlink == 0);
-#endif
 	close(fd);
 	return is_cloned;
 }
@@ -198,16 +225,37 @@ error:
 	return -EINVAL;
 }
 
+
 static int clone_binary(void)
 {
 	int binfd, memfd;
 	ssize_t sent = 0;
+	char template[] = "/tmp/runc.XXXXXX";
+	int type = 0;
+	char *tmpfile = NULL;
+
+	type = get_clone_type();
+	switch (type) {
+		case USING_MEMFD:
+			memfd = memfd_create(RUNC_MEMFD_COMMENT, MFD_CLOEXEC | MFD_ALLOW_SEALING);
+			break;
+		case USING_UNAMED_FILE:
+			memfd = open("/tmp", O_TMPFILE | O_EXCL | O_RDWR | O_CLOEXEC, 0711);
+			break;
+		case USING_TMPFILE:
+			memfd = mkostemp(template,O_EXCL | O_RDWR | O_CLOEXEC);
+			if (memfd < 0) {
+				goto error;
+			}
+			tmpfile = template;
+			if (fchmod(memfd, 0711)) {
+				goto error;
+			}
+			break;
+		default:
+			return -ENOTRECOVERABLE;
+	}
 
-#ifdef HAVE_MEMFD_CREATE
-	memfd = memfd_create(RUNC_MEMFD_COMMENT, MFD_CLOEXEC | MFD_ALLOW_SEALING);
-#else
-	memfd = open("/tmp", O_TMPFILE | O_EXCL | O_RDWR | O_CLOEXEC, 0711);
-#endif
 	if (memfd < 0)
 		return -ENOTRECOVERABLE;
 
@@ -220,29 +268,36 @@ static int clone_binary(void)
 	if (sent < 0)
 		goto error;
 
-#ifdef HAVE_MEMFD_CREATE
-	int err = fcntl(memfd, F_ADD_SEALS, RUNC_MEMFD_SEALS);
-	if (err < 0)
-		goto error;
-#else
+	if (type == USING_MEMFD) {
+		int err = fcntl(memfd, F_ADD_SEALS, RUNC_MEMFD_SEALS);
+		if (err < 0)
+			goto error;
+	} else {
 	/* Need to re-open "memfd" as read-only to avoid execve(2) giving -EXTBUSY. */
-	int newfd;
-	char *fdpath = NULL;
+		int newfd;
+		char *fdpath = NULL;
 
-	if (asprintf(&fdpath, "/proc/self/fd/%d", memfd) < 0)
-		goto error;
-	newfd = open(fdpath, O_RDONLY | O_CLOEXEC);
-	free(fdpath);
-	if (newfd < 0)
-		goto error;
+		if (asprintf(&fdpath, "/proc/self/fd/%d", memfd) < 0)
+			goto error;
+		newfd = open(fdpath, O_RDONLY | O_CLOEXEC);
+		free(fdpath);
+		if (newfd < 0)
+			goto error;
+		close(memfd);
 
-	close(memfd);
-	memfd = newfd;
-#endif
+		memfd = newfd;
+	}
+
+	if(tmpfile) {
+		remove(tmpfile);
+	}
 	return memfd;
 
 error:
 	close(memfd);
+	if(tmpfile) {
+		remove(tmpfile);
+	}
 	return -EIO;
 }
 
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index 2448078..b577d1a 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
 
 Name: docker-runc
 Version: 1.0.0.rc3
-Release: 20%{?dist}
+Release: 21%{?dist}
 Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
 
 License: ASL 2.0
-- 
2.7.4.3

