From 621c01059536ec167da8c9d5571e8bf860b4dadb Mon Sep 17 00:00:00 2001 From: wangfengtu 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 Signed-off-by: wangfengtu --- 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