minijail: Add support for entering an existing VFS namespace.
Also, fix the Makefile while in there.
BUG=chromium:376987
TEST=security_Minijail0
CQ-DEPEND=CL:209242
Change-Id: I18877211549500cbb720805a2480b1cb3244c1e9
Reviewed-on: https://chromium-review.googlesource.com/209240
Reviewed-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
Tested-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
Commit-Queue: Jorge Lucangeli Obes <jorgelo@chromium.org>
diff --git a/Makefile b/Makefile
index 204e64b..d931df0 100644
--- a/Makefile
+++ b/Makefile
@@ -81,5 +81,5 @@
@rm -f libminijail.so
@rm -f libminijail_unittest
@rm -f libsyscalls.gen.o libsyscalls.gen.c
- @rm -f syscall_filter.o signal.o bpf.o util.o
+ @rm -f syscall_filter.o signal.o bpf.o util.o elfparse.o
@rm -f syscall_filter_unittest syscall_filter_unittest.o
diff --git a/libminijail.c b/libminijail.c
index 4e56b3e..9fafc51 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -10,6 +10,7 @@
#include <asm/unistd.h>
#include <ctype.h>
#include <errno.h>
+#include <fcntl.h>
#include <grp.h>
#include <inttypes.h>
#include <limits.h>
@@ -27,6 +28,8 @@
#include <sys/mount.h>
#include <sys/param.h>
#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -75,6 +78,7 @@
int gid:1;
int caps:1;
int vfs:1;
+ int enter_vfs:1;
int pids:1;
int net:1;
int seccomp:1;
@@ -93,6 +97,7 @@
char *user;
uint64_t caps;
pid_t initpid;
+ int mountns_fd;
int filter_len;
int binding_count;
char *chrootdir;
@@ -109,6 +114,7 @@
void minijail_preenter(struct minijail *j)
{
j->flags.vfs = 0;
+ j->flags.enter_vfs = 0;
j->flags.readonly = 0;
j->flags.pids = 0;
}
@@ -120,6 +126,7 @@
void minijail_preexec(struct minijail *j)
{
int vfs = j->flags.vfs;
+ int enter_vfs = j->flags.enter_vfs;
int readonly = j->flags.readonly;
if (j->user)
free(j->user);
@@ -127,6 +134,7 @@
memset(&j->flags, 0, sizeof(j->flags));
/* Now restore anything we meant to keep. */
j->flags.vfs = vfs;
+ j->flags.enter_vfs = enter_vfs;
j->flags.readonly = readonly;
/* Note, |pids| will already have been used before this call. */
}
@@ -249,6 +257,16 @@
j->flags.vfs = 1;
}
+void API minijail_namespace_enter_vfs(struct minijail *j, const char *ns_path)
+{
+ int ns_fd = open(ns_path, O_RDONLY);
+ if (ns_fd < 0) {
+ pdie("failed to open namespace '%s'", ns_path);
+ }
+ j->mountns_fd = ns_fd;
+ j->flags.enter_vfs = 1;
+}
+
void API minijail_namespace_pids(struct minijail *j)
{
j->flags.vfs = 1;
@@ -745,7 +763,7 @@
{
if (j->flags.pids)
die("tried to enter a pid-namespaced jail;"
- "try minijail_run()?");
+ " try minijail_run()?");
if (j->flags.usergroups && !j->user)
die("usergroup inheritance without username");
@@ -755,6 +773,9 @@
* so we don't even try. If any of our operations fail, we abort() the
* entire process.
*/
+ if (j->flags.enter_vfs && setns(j->mountns_fd, CLONE_NEWNS))
+ pdie("setns(CLONE_NEWNS)");
+
if (j->flags.vfs && unshare(CLONE_NEWNS))
pdie("unshare(vfs)");
diff --git a/libminijail.h b/libminijail.h
index 865a4f1..6738a32 100644
--- a/libminijail.h
+++ b/libminijail.h
@@ -49,6 +49,7 @@
void minijail_log_seccomp_filter_failures(struct minijail *j);
void minijail_use_caps(struct minijail *j, uint64_t capmask);
void minijail_namespace_vfs(struct minijail *j);
+void minijail_namespace_enter_vfs(struct minijail *j, const char *ns_path);
void minijail_namespace_net(struct minijail *j);
/* Implies namespace_vfs and remount_readonly.
* WARNING: this is NOT THREAD SAFE. See the block comment in </libminijail.c>.
diff --git a/minijail0.c b/minijail0.c
index e5ca3d1..4d103b7 100644
--- a/minijail0.c
+++ b/minijail0.c
@@ -83,7 +83,7 @@
"instances allowed\n"
" -c <caps>: restrict caps to <caps>\n"
" -C <dir>: chroot to <dir>\n"
- " -e: enter a network namespace\n"
+ " -e: enter new network namespace\n"
" -G: inherit secondary groups from uid\n"
" -g <group>: change gid to <group>\n"
" -h: help (this message)\n"
@@ -98,14 +98,15 @@
printf("\n"
" -n: set no_new_privs\n"
- " -p: use pid namespace (implies -vr)\n"
- " -r: remount /proc readonly (implies -v)\n"
+ " -p: enter new pid namespace (implies -vr)\n"
+ " -r: remount /proc read-only (implies -v)\n"
" -s: use seccomp\n"
" -S <file>: set seccomp filter using <file>\n"
" E.g., -S /usr/share/filters/<prog>.$(uname -m)\n"
" -t: mount tmpfs at /tmp inside chroot\n"
" -u <user>: change uid to <user>\n"
- " -v: use vfs namespace\n");
+ " -v: enter new mount namespace\n"
+ " -V <file>: enter specified mount namespace\n");
}
static void seccomp_filter_usage(const char *progn)
@@ -127,7 +128,7 @@
int mount_tmp = 0;
if (argc > 1 && argv[1][0] != '-')
return 1;
- while ((opt = getopt(argc, argv, "u:g:sS:c:C:b:vrGhHinpLet")) != -1) {
+ while ((opt = getopt(argc, argv, "u:g:sS:c:C:b:V:vrGhHinpLet")) != -1) {
switch (opt) {
case 'u':
set_user(j, optarg);
@@ -155,8 +156,10 @@
use_caps(j, optarg);
break;
case 'C':
- if (0 != minijail_enter_chroot(j, optarg))
+ if (0 != minijail_enter_chroot(j, optarg)) {
+ fprintf(stderr, "Could not set chroot.\n");
exit(1);
+ }
chroot = 1;
break;
case 't':
@@ -166,6 +169,9 @@
case 'v':
minijail_namespace_vfs(j);
break;
+ case 'V':
+ minijail_namespace_enter_vfs(j, optarg);
+ break;
case 'r':
minijail_remount_readonly(j);
break;