int pw_uid;
int pw_gid;
int gr_gid;
+ int root_map_uid;
gid_t *additional_gids;
size_t num_additional_gids;
mode_t umask;
free_library_search();
mount_free();
+ cgroups_free();
/* we need to keep argv, envp and seccomp filter in child */
if (parent) { /* parent-only */
free_oci_envp(opts.jail_argv);
free_oci_envp(opts.envp);
- } else { /* child-only */
- if (opts.ocibundle)
- cgroups_free();
}
free_rlimits();
snprintf(dev_console_path, sizeof(dev_console_path), "%s/dev/console", jail_root);
close(creat(dev_console_path, 0620));
- if (mount(console_fname, dev_console_path, NULL, MS_BIND, NULL))
+ if (mount(console_fname, dev_console_path, "bind", MS_BIND, NULL))
goto no_console;
/* use PTY slave for stdio */
}
/* oldroot can't be MS_SHARED else pivot_root() fails */
- if (mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL)) {
+ if (mount("none", "/", "none", MS_REC|MS_PRIVATE, NULL)) {
ERROR("private mount failed %m\n");
return -1;
}
if (opts.extroot) {
- if (mount(opts.extroot, jail_root, NULL, MS_BIND, NULL)) {
+ if (mount(opts.extroot, jail_root, "bind", MS_BIND, NULL)) {
ERROR("extroot mount failed %m\n");
return -1;
}
free_and_exit(-1);
}
if (opts.ronly)
- mount(NULL, "/", NULL, MS_REMOUNT | MS_BIND | MS_RDONLY, 0);
+ mount(NULL, "/", "bind", MS_REMOUNT | MS_BIND | MS_RDONLY, 0);
umask(old_umask);
post_jail_fs();
fprintf(stderr, " -E\t\tfail if jail cannot be setup\n");
fprintf(stderr, " -y\t\tprovide jail console\n");
fprintf(stderr, " -J <dir>\tcreate container from OCI bundle\n");
- fprintf(stderr, " -j\t\tstart container immediately\n");
+ fprintf(stderr, " -i\t\tstart container immediately\n");
fprintf(stderr, " -P <pidfile>\tcreate <pidfile>\n");
fprintf(stderr, "\nWarning: by default root inside the jail is the same\n\
and he has the same powers as root outside the jail,\n\
char buf[1];
exit_from_child = true;
+ prctl(PR_SET_SECUREBITS, 0);
+
uloop_init();
signals_init();
if (opts.namespace & CLONE_NEWCGROUP)
unshare(CLONE_NEWCGROUP);
+ setns_open(CLONE_NEWCGROUP);
+
if ((opts.namespace & CLONE_NEWUSER) || (opts.setns.user != -1)) {
if (setregid(0, 0) < 0) {
ERROR("setgid\n");
if (opts.set_umask)
umask(opts.umask);
- /* restore securebits back to normal */
+ /* restore securebits back to normal (and lock them if not in userns) */
if (opts.capset.apply) {
- if (prctl(PR_SET_SECUREBITS, 0)) {
+ if (prctl(PR_SET_SECUREBITS, (opts.namespace & CLONE_NEWUSER)?0:
+ SECBIT_KEEP_CAPS_LOCKED|SECBIT_NO_SETUID_FIXUP_LOCKED|SECBIT_NOROOT_LOCKED)) {
ERROR("prctl(PR_SET_SECUREBITS) failed: %m\n");
free_and_exit(EXIT_FAILURE);
}
}
return 0;
-};
+}
+static void get_jail_root_user(bool is_gidmap, uint32_t container_id, uint32_t host_id, uint32_t size)
+{
+ if (container_id == 0 && size >= 1)
+ if (!is_gidmap)
+ opts.root_map_uid = host_id;
+}
enum {
OCI_LINUX_UIDGIDMAP_CONTAINERID,
blobmsg_for_each_attr(cur, msg, rem) {
blobmsg_parse(oci_linux_uidgidmap_policy, __OCI_LINUX_UIDGIDMAP_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
+ get_jail_root_user(is_gidmap, blobmsg_get_u32(tb[OCI_LINUX_UIDGIDMAP_CONTAINERID]),
+ blobmsg_get_u32(tb[OCI_LINUX_UIDGIDMAP_HOSTID]),
+ blobmsg_get_u32(tb[OCI_LINUX_UIDGIDMAP_SIZE]));
+
/* write mapping line into pre-allocated string */
len = snprintf(&map[pos], totallen + 1, "%d %d %d\n",
blobmsg_get_u32(tb[OCI_LINUX_UIDGIDMAP_CONTAINERID]),
opts.setns.time = -1;
#endif
+ /*
+ * uid in parent user namespace representing root user in new
+ * user namespace, defaults to nobody unless specified in uidMappings
+ */
+ opts.root_map_uid = 65534;
+
if (opts.capabilities && parseOCIcapabilities_from_file(&opts.capset, opts.capabilities)) {
ERROR("failed to read capabilities from file %s\n", opts.capabilities);
ret=-1;
#endif
if (!(opts.namespace & CLONE_NEWNET)) {
- add_mount_bind("/etc/resolv.conf", 1, -1);
+ add_mount_bind("/etc/resolv.conf", 1, 0);
} else if (opts.setns.net == -1) {
char hostdir[PATH_MAX];
snprintf(hostdir, PATH_MAX, "/tmp/resolv.conf-%s.d", opts.name);
mkdir_p(hostdir, 0755);
- add_mount(hostdir, "/dev/resolv.conf.d", NULL, MS_BIND | MS_NOEXEC | MS_NOATIME | MS_NOSUID | MS_NODEV | MS_RDONLY, 0, NULL, -1);
+ add_mount(hostdir, "/dev/resolv.conf.d", NULL, MS_BIND | MS_NOEXEC | MS_NOATIME | MS_NOSUID | MS_NODEV | MS_RDONLY, 0, NULL, 0);
}
/* default mounts */
}
if (opts.sysfs || opts.ocibundle)
- add_mount("sysfs", "/sys", "sysfs", MS_NOATIME | MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RDONLY, 0, NULL, -1);
+ add_mount("sysfs", "/sys", "sysfs", MS_RELATIME | MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RDONLY, 0, NULL, -1);
if (opts.ocibundle)
add_mount("shm", "/dev/shm", "tmpfs", MS_NOSUID | MS_NOEXEC | MS_NODEV, 0, "mode=1777", -1);
if (opts.setns.time != -1) {
timens_fd = ns_open_pid("time", getpid());
setns_open(CLONE_NEWTIME);
+ } else {
+ timens_fd = -1;
}
#endif
+ if (opts.namespace & CLONE_NEWUSER) {
+ if (prctl(PR_SET_SECUREBITS, SECBIT_NO_SETUID_FIXUP)) {
+ ERROR("prctl(PR_SET_SECUREBITS) failed: %m\n");
+ free_and_exit(EXIT_FAILURE);
+ }
+ seteuid(opts.root_map_uid);
+ }
+
jail_process.pid = clone(exec_jail, child_stack + STACK_SIZE, SIGCHLD | (opts.namespace & (~CLONE_NEWCGROUP)), NULL);
} else {
jail_process.pid = fork();
uloop_process_add(&jail_process);
jail_running = 1;
seteuid(0);
+ prctl(PR_SET_SECUREBITS, 0);
+
if (pidns_fd != -1) {
setns(pidns_fd, CLONE_NEWPID);
close(pidns_fd);