Skip to content
This repository has been archived by the owner on Jun 11, 2020. It is now read-only.

[18.06 backport] remove hot-fix, and apply latest upstream patch for CVE-2019-5736 #8

Closed
98 changes: 64 additions & 34 deletions libcontainer/nsenter/cloned_binary.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
/*
* Copyright (C) 2019 Aleksa Sarai <cyphar@cyphar.com>
* Copyright (C) 2019 SUSE LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
Expand All @@ -15,37 +32,22 @@
#include <sys/sendfile.h>
#include <sys/syscall.h>

#include <linux/magic.h>

/* flags for memfd_create(2) (unsigned int), taken from linux/memfd.h */
#define MFD_CLOEXEC 0x0001U
#define MFD_ALLOW_SEALING 0x0002U

/* Use our own wrapper for memfd_create. */
#if !defined(__NR_memfd_create)
# ifdef __i386__
# define __NR_memfd_create 356
# elif __x86_64__
# define __NR_memfd_create 319
# elif __powerpc64__
# define __NR_memfd_create 360
# elif __aarch64__
# define __NR_memfd_create 279
# elif __arm__
# define __NR_memfd_create 385
# endif
#endif /* !__NR_memfd_create */

#if !defined(SYS_memfd_create) && defined(__NR_memfd_create)
# define SYS_memfd_create __NR_memfd_create
#endif
#ifndef SYS_memfd_create
# error "memfd_create(2) syscall not supported by this glibc version"
#endif
#ifdef SYS_memfd_create
# define HAVE_MEMFD_CREATE
/* memfd_create(2) flags -- copied from <linux/memfd.h>. */
# ifndef MFD_CLOEXEC
# define MFD_CLOEXEC 0x0001U
# define MFD_ALLOW_SEALING 0x0002U
# endif
int memfd_create(const char *name, unsigned int flags)
{
return syscall(SYS_memfd_create, name, flags);
}
#endif

/* This comes directly from <linux/fcntl.h>. */
#ifndef F_LINUX_SPECIFIC_BASE
Expand All @@ -62,10 +64,12 @@ int memfd_create(const char *name, unsigned int flags)
# define F_SEAL_WRITE 0x0008 /* prevent writes */
#endif


#define OUR_MEMFD_COMMENT "runc_cloned:/proc/self/exe"
#define OUR_MEMFD_SEALS \
#define RUNC_SENDFILE_MAX 0x7FFFF000 /* sendfile(2) is limited to 2GB. */
#ifdef HAVE_MEMFD_CREATE
# define RUNC_MEMFD_COMMENT "runc_cloned:/proc/self/exe"
# define RUNC_MEMFD_SEALS \
(F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE)
#endif

static void *must_realloc(void *ptr, size_t size)
{
Expand All @@ -83,15 +87,23 @@ static void *must_realloc(void *ptr, size_t size)
*/
static int is_self_cloned(void)
{
int fd, seals;
int fd, ret, is_cloned = 0;

fd = open("/proc/self/exe", O_RDONLY|O_CLOEXEC);
if (fd < 0)
return -ENOTRECOVERABLE;

seals = fcntl(fd, F_GET_SEALS);
#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 seals == OUR_MEMFD_SEALS;
return is_cloned;
}

/*
Expand Down Expand Up @@ -186,29 +198,47 @@ static int fetchve(char ***argv, char ***envp)
return -EINVAL;
}

#define SENDFILE_MAX 0x7FFFF000 /* sendfile(2) is limited to 2GB. */
static int clone_binary(void)
{
int binfd, memfd, err;
int binfd, memfd;
ssize_t sent = 0;

memfd = memfd_create(OUR_MEMFD_COMMENT, MFD_CLOEXEC | MFD_ALLOW_SEALING);
#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;

binfd = open("/proc/self/exe", O_RDONLY | O_CLOEXEC);
if (binfd < 0)
goto error;

sent = sendfile(memfd, binfd, NULL, SENDFILE_MAX);
sent = sendfile(memfd, binfd, NULL, RUNC_SENDFILE_MAX);
close(binfd);
if (sent < 0)
goto error;

err = fcntl(memfd, F_ADD_SEALS, OUR_MEMFD_SEALS);
#ifdef HAVE_MEMFD_CREATE
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;

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);
memfd = newfd;
#endif
return memfd;

error:
Expand Down
2 changes: 1 addition & 1 deletion libcontainer/nsenter/nsexec.c
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ void join_namespaces(char *nslist)
}

/* Defined in cloned_binary.c. */
int ensure_cloned_binary(void);
extern int ensure_cloned_binary(void);

void nsexec(void)
{
Expand Down