Skip to content

Commit

Permalink
Merge commit from fork
Browse files Browse the repository at this point in the history
Create virtual copy of host ldconfig binary before calling fexecve()
  • Loading branch information
elezar authored Dec 4, 2024
2 parents 63d366e + f6a92a5 commit 16f37fc
Showing 1 changed file with 111 additions and 4 deletions.
115 changes: 111 additions & 4 deletions src/nvc_ldcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@
#include <linux/types.h>

#include <sys/capability.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <sched.h>
#ifdef WITH_SECCOMP
Expand All @@ -36,6 +40,10 @@ static int adjust_capabilities(struct error *, uid_t, bool);
static int adjust_privileges(struct error *, uid_t, gid_t, bool);
static int limit_resources(struct error *);
static int limit_syscalls(struct error *);
static ssize_t sendfile_nointr(int, int, off_t *, size_t);
static int open_as_memfd(struct error *, const char *);
int memfd_create(const char *, unsigned int);


static inline bool
secure_mode(void)
Expand Down Expand Up @@ -242,7 +250,7 @@ limit_resources(struct error *err)
limit = (struct rlimit){64, 64};
if (setrlimit(RLIMIT_NOFILE, &limit) < 0)
goto fail;
limit = (struct rlimit){1024*1024, 1024*1024};
limit = (struct rlimit){2*1024*1024, 2*1024*1024};
if (setrlimit(RLIMIT_FSIZE, &limit) < 0)
goto fail;
return (0);
Expand Down Expand Up @@ -279,14 +287,17 @@ limit_syscalls(struct error *err)
SCMP_SYS(getegid),
SCMP_SYS(geteuid),
SCMP_SYS(getgid),
SCMP_SYS(getpgrp),
SCMP_SYS(getpgrp),
SCMP_SYS(getpid),
SCMP_SYS(gettid),
SCMP_SYS(gettimeofday),
SCMP_SYS(getuid),
SCMP_SYS(_llseek),
SCMP_SYS(lseek),
SCMP_SYS(lstat),
#ifdef SYS_memfd_create
SCMP_SYS(memfd_create),
#endif
SCMP_SYS(mkdir),
SCMP_SYS(mmap),
SCMP_SYS(mprotect),
Expand All @@ -303,6 +314,7 @@ limit_syscalls(struct error *err)
SCMP_SYS(rt_sigaction),
SCMP_SYS(rt_sigprocmask),
SCMP_SYS(rt_sigreturn),
SCMP_SYS(sendfile),
SCMP_SYS(stat),
SCMP_SYS(symlink),
SCMP_SYS(tgkill),
Expand Down Expand Up @@ -352,6 +364,98 @@ limit_syscalls(struct error *err)
}
#endif /* WITH_SECCOMP */

/* memfd_create(2) flags -- copied from <linux/memfd.h>. */
#ifndef MFD_CLOEXEC
# define MFD_CLOEXEC 0x0001U
# define MFD_ALLOW_SEALING 0x0002U
#endif
#ifndef MFD_EXEC
# define MFD_EXEC 0x0010U
#endif

/* This comes directly from <linux/fcntl.h>. */
#ifndef F_LINUX_SPECIFIC_BASE
# define F_LINUX_SPECIFIC_BASE 1024
#endif
#ifndef F_ADD_SEALS
# define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
#endif
#ifndef F_SEAL_SEAL
# define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
# define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
# define F_SEAL_GROW 0x0004 /* prevent file from growing */
# define F_SEAL_WRITE 0x0008 /* prevent writes */
#endif

int memfd_create(const char *name, unsigned int flags)
{
#ifdef SYS_memfd_create
return syscall(SYS_memfd_create, name, flags);
#else
errno = ENOSYS;
return -1;
#endif
}

static ssize_t
sendfile_nointr(int out_fd, int in_fd, off_t *offset, size_t count)
{
ssize_t ret;

do {
ret = sendfile(out_fd, in_fd, offset, count);
} while (ret < 0 && errno == EINTR);

return ret;
}

static int
open_as_memfd(struct error *err, const char *path)
{
int fd, memfd, ret;
ssize_t bytes_sent = 0;
struct stat st = {0};
off_t offset = 0;

if ((fd = xopen(err, path, O_RDONLY)) < 0)
return (-1);

log_info("creating a virtual copy of the ldconfig binary");
memfd = memfd_create(path, MFD_ALLOW_SEALING | MFD_CLOEXEC);
if (memfd == -1) {
error_set(err, "error creating memfd for path: %s", path);
return (-1);
}

ret = fstat(fd, &st);
if (ret == -1) {
error_set(err, "error running fstat for path: %s", path);
goto fail;
}

while (bytes_sent < st.st_size) {
ssize_t sent;
sent = sendfile_nointr(memfd, fd, &offset, st.st_size - bytes_sent);
if (sent == -1) {
error_set(err, "failed to copy ldconfig binary to virtual copy");
goto fail;
}
bytes_sent += sent;
}

if (fcntl(memfd, F_ADD_SEALS, F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE) == -1) {
error_set(err, "failed to seal virtual copy of the ldconfig binary");
goto fail;
}

close(fd);
return memfd;
fail:
close(fd);
close(memfd);
return (-1);
}

int
nvc_ldcache_update(struct nvc_context *ctx, const struct nvc_container *cnt)
{
Expand All @@ -374,8 +478,11 @@ nvc_ldcache_update(struct nvc_context *ctx, const struct nvc_container *cnt)
* Force proc to be remounted since we're creating a PID namespace and fexecve depends on it.
*/
++argv[0];
if ((fd = xopen(&ctx->err, argv[0], O_RDONLY|O_CLOEXEC)) < 0)
return (-1);
if ((fd = open_as_memfd(&ctx->err, argv[0])) < 0) {
log_warn("failed to create virtual copy of the ldconfig binary");
if ((fd = xopen(&ctx->err, argv[0], O_RDONLY|O_CLOEXEC)) < 0)
return (-1);
}
host_ldconfig = true;
log_infof("executing %s from host at %s", argv[0], cnt->cfg.rootfs);
} else {
Expand Down

0 comments on commit 16f37fc

Please sign in to comment.