LOG_I
("Jail parameters: hostname:'%s', chroot:'%s', process:'%s', bind:[%s]:%d, "
- "max_conns_per_ip:%u, uid:(ns:%u, global:%u), gid:(ns:%u, global:%u), time_limit:%ld, personality:%#lx, daemonize:%s, "
+ "max_conns_per_ip:%u, time_limit:%ld, personality:%#lx, daemonize:%s, "
"clone_newnet:%s, clone_newuser:%s, clone_newns:%s, clone_newpid:%s, "
"clone_newipc:%s, clonew_newuts:%s, clone_newcgroup:%s, keep_caps:%s, "
"tmpfs_size:%zu, disable_no_new_privs:%s, pivot_root_only:%s",
nsjconf->hostname, nsjconf->chroot, nsjconf->argv[0], nsjconf->bindhost, nsjconf->port,
- nsjconf->max_conns_per_ip, nsjconf->inside_uid, nsjconf->outside_uid,
- nsjconf->inside_gid, nsjconf->outside_gid, nsjconf->tlimit, nsjconf->personality,
+ nsjconf->max_conns_per_ip, nsjconf->tlimit, nsjconf->personality,
logYesNo(nsjconf->daemonize), logYesNo(nsjconf->clone_newnet),
logYesNo(nsjconf->clone_newuser), logYesNo(nsjconf->clone_newns),
logYesNo(nsjconf->clone_newpid), logYesNo(nsjconf->clone_newipc),
p->src, p->dst, p->fs_type, p->flags, p->options);
}
}
+ {
+ struct idmap_t *p;
+ TAILQ_FOREACH(p, &nsjconf->uids, pointers) {
+ LOG_I("Uid map: inside_uid:%d outside_uid:%d", p->inside_id, p->outside_id);
+ }
+ TAILQ_FOREACH(p, &nsjconf->gids, pointers) {
+ LOG_I("Gid map: inside_gid:%d outside_gid:%d", p->inside_id, p->outside_id);
+ }
+ }
+
{
struct mapping_t *p;
TAILQ_FOREACH(p, &nsjconf->uid_mappings, pointers) {
- LOG_I("Uid mapping: inside_uid:'%s' outside_uid:'%s' count:'%s'",
+ LOG_I("Newuid mapping: inside_uid:'%s' outside_uid:'%s' count:'%s'",
p->inside_id, p->outside_id, p->count);
}
TAILQ_FOREACH(p, &nsjconf->gid_mappings, pointers) {
- LOG_I("Gid mapping: inside_uid:'%s' outside_uid:'%s' count:'%s'",
+ LOG_I("Newgid mapping: inside_uid:'%s' outside_uid:'%s' count:'%s'",
p->inside_id, p->outside_id, p->count);
}
}
}
char *second = cmdlineSplitStrByColon(str);
+ pid_t inside_uid;
+ pid_t outside_uid;
struct passwd *pw = getpwnam(str);
if (pw != NULL) {
- nsjconf->inside_uid = pw->pw_uid;
+ inside_uid = pw->pw_uid;
} else if (cmdlineIsANumber(str)) {
- nsjconf->inside_uid = (uid_t) strtoull(str, NULL, 0);
+ inside_uid = (uid_t) strtoull(str, NULL, 0);
} else {
LOG_E("No such user '%s'", str);
return false;
}
if (str == second) {
- return true;
- }
-
- pw = getpwnam(second);
- if (pw != NULL) {
- nsjconf->outside_uid = pw->pw_uid;
- } else if (cmdlineIsANumber(second)) {
- nsjconf->outside_uid = (uid_t) strtoull(second, NULL, 0);
+ outside_uid = inside_uid;
} else {
- LOG_E("No such user '%s'", second);
- return false;
+ pw = getpwnam(second);
+ if (pw != NULL) {
+ outside_uid = pw->pw_uid;
+ } else if (cmdlineIsANumber(second)) {
+ outside_uid = (uid_t) strtoull(second, NULL, 0);
+ } else {
+ LOG_E("No such user '%s'", second);
+ return false;
+ }
}
+
+ struct idmap_t *p = utilMalloc(sizeof(struct idmap_t));
+ p->inside_id = inside_uid;
+ p->outside_id = outside_uid;
+ TAILQ_INSERT_TAIL(&nsjconf->uids, p, pointers);
+
return true;
}
}
char *second = cmdlineSplitStrByColon(str);
+ gid_t inside_gid;
+ gid_t outside_gid;
struct group *gr = getgrnam(str);
if (gr != NULL) {
- nsjconf->inside_gid = gr->gr_gid;
+ inside_gid = gr->gr_gid;
} else if (cmdlineIsANumber(str)) {
- nsjconf->inside_gid = (gid_t) strtoull(str, NULL, 0);
+ inside_gid = (gid_t) strtoull(str, NULL, 0);
} else {
LOG_E("No such group '%s'", str);
return false;
}
if (str == second) {
- return true;
- }
-
- gr = getgrnam(second);
- if (gr != NULL) {
- nsjconf->outside_gid = gr->gr_gid;
- } else if (cmdlineIsANumber(second)) {
- nsjconf->outside_gid = (gid_t) strtoull(second, NULL, 0);
+ outside_gid = inside_gid;
} else {
- LOG_E("No such group '%s'", second);
- return false;
+
+ gr = getgrnam(second);
+ if (gr != NULL) {
+ outside_gid = gr->gr_gid;
+ } else if (cmdlineIsANumber(second)) {
+ outside_gid = (gid_t) strtoull(second, NULL, 0);
+ } else {
+ LOG_E("No such group '%s'", second);
+ return false;
+ }
}
+
+ struct idmap_t *p = utilMalloc(sizeof(struct idmap_t));
+ p->inside_id = inside_gid;
+ p->outside_id = outside_gid;
+ TAILQ_INSERT_TAIL(&nsjconf->gids, p, pointers);
+
return true;
}
.is_root_rw = false,
.is_silent = false,
.skip_setsid = false,
- .inside_uid = getuid(),
- .inside_gid = getgid(),
- .outside_uid = getuid(),
- .outside_gid = getgid(),
.max_conns_per_ip = 0,
.tmpfs_size = 4 * (1024 * 1024),
.mount_proc = true,
};
/* *INDENT-OFF* */
+ TAILQ_INIT(&nsjconf->uids);
+ TAILQ_INIT(&nsjconf->gids);
TAILQ_INIT(&nsjconf->envs);
TAILQ_INIT(&nsjconf->pids);
TAILQ_INIT(&nsjconf->mountpts);
TAILQ_INIT(&nsjconf->uid_mappings);
TAILQ_INIT(&nsjconf->gid_mappings);
- char *user = NULL;
- char *group = NULL;
const char *logfile = NULL;
static char cmdlineTmpfsSz[PATH_MAX] = "size=4194304";
"\tr: Immediately launch a single process on the console, keep doing it forever [MODE_STANDALONE_RERUN]"},
{{"chroot", required_argument, NULL, 'c'}, "Directory containing / of the jail (default: none)"},
{{"rw", no_argument, NULL, 0x601}, "Mount / as RW (default: RO)"},
- {{"user", required_argument, NULL, 'u'}, "Username/uid of processess inside the jail (default: your current uid). You can also use inside_ns_uid:outside_ns_uid convention here"},
- {{"group", required_argument, NULL, 'g'}, "Groupname/gid of processess inside the jail (default: your current gid). You can also use inside_ns_gid:global_ns_gid convention here"},
+ {{"user", required_argument, NULL, 'u'}, "Username/uid of processess inside the jail (default: your current uid). You can also use inside_ns_uid:outside_ns_uid convention here. Can be specified multiple times"},
+ {{"group", required_argument, NULL, 'g'}, "Groupname/gid of processess inside the jail (default: your current gid). You can also use inside_ns_gid:global_ns_gid convention here. Can be specified multiple times"},
{{"hostname", required_argument, NULL, 'H'}, "UTS name (hostname) of the jail (default: 'NSJAIL')"},
{{"cwd", required_argument, NULL, 'D'}, "Directory in the namespace the process will run (default: '/')"},
{{"port", required_argument, NULL, 'p'}, "TCP port to bind to (enables MODE_LISTEN_TCP) (default: 0)"},
nsjconf->max_conns_per_ip = strtoul(optarg, NULL, 0);
break;
case 'u':
- user = optarg;
+ if (cmdlineParseUid(nsjconf, optarg) == false) {
+ LOG_F("cmdlineParseUid('%s')", optarg);
+ }
break;
case 'g':
- group = optarg;
+ if (cmdlineParseGid(nsjconf, optarg) == false) {
+ LOG_F("cmdlineParseGid('%s')", optarg);
+ }
break;
case 'l':
logfile = optarg;
TAILQ_INSERT_HEAD(&nsjconf->mountpts, p, pointers);
}
+ if (TAILQ_EMPTY(&nsjconf->uids)) {
+ struct idmap_t *p = utilMalloc(sizeof(struct idmap_t));
+ p->inside_id = getuid();
+ p->outside_id = getuid();
+ TAILQ_INSERT_HEAD(&nsjconf->uids, p, pointers);
+ }
+ if (TAILQ_EMPTY(&nsjconf->gids)) {
+ struct idmap_t *p = utilMalloc(sizeof(struct idmap_t));
+ p->inside_id = getgid();
+ p->outside_id = getgid();
+ TAILQ_INSERT_HEAD(&nsjconf->gids, p, pointers);
+ }
#if !defined(USE_KAFEL)
if (nsjconf->kafel_file != NULL || nsjconf->kafel_string != NULL) {
LOG_F("Kafel policy specified but the kafel/ is not compiled in");
return false;
}
- if (cmdlineParseUid(nsjconf, user) == false) {
- return false;
- }
- if (cmdlineParseGid(nsjconf, group) == false) {
- return false;
- }
-
nsjconf->argv = &argv[optind];
if (nsjconf->argv[0] == NULL) {
LOG_E("No command provided");
static bool userUidMapSelf(struct nsjconf_t *nsjconf, pid_t pid)
{
char fname[PATH_MAX];
- char map[128];
-
snprintf(fname, sizeof(fname), "/proc/%d/uid_map", pid);
- snprintf(map, sizeof(map), "%lu %lu 1", (unsigned long)nsjconf->inside_uid,
- (unsigned long)nsjconf->outside_uid);
+
+ char map[4096] = {[0] = '\0' };
+
+ struct idmap_t *p;
+ TAILQ_FOREACH(p, &nsjconf->uids, pointers) {
+ utilSSnPrintf(map, sizeof(map), "%lu %lu 1\n", (unsigned long)p->inside_id,
+ (unsigned long)p->outside_id);
+ }
+
LOG_D("Writing '%s' to '%s'", map, fname);
if (utilWriteBufToFile(fname, map, strlen(map), O_WRONLY) == false) {
LOG_E("utilWriteBufToFile('%s', '%s') failed", fname, map);
static bool userGidMapSelf(struct nsjconf_t *nsjconf, pid_t pid)
{
char fname[PATH_MAX];
- char map[128];
-
snprintf(fname, sizeof(fname), "/proc/%d/gid_map", pid);
- snprintf(map, sizeof(map), "%lu %lu 1", (unsigned long)nsjconf->inside_gid,
- (unsigned long)nsjconf->outside_gid);
+
+ char map[4096] = {[0] = '\0' };
+
+ struct idmap_t *p;
+ TAILQ_FOREACH(p, &nsjconf->gids, pointers) {
+ utilSSnPrintf(map, sizeof(map), "%lu %lu 1\n", (unsigned long)p->inside_id,
+ (unsigned long)p->outside_id);
+ }
+
LOG_D("Writing '%s' to '%s'", map, fname);
if (utilWriteBufToFile(fname, map, strlen(map), O_WRONLY) == false) {
LOG_E("utilWriteBufToFile('%s', '%s') failed", fname, map);
return false;
}
+
return true;
}
/* Use /usr/bin/newgidmap for writing the gid map */
-static bool userGidMapExternal(struct nsjconf_t *nsjconf, pid_t pid)
+static bool userGidMapExternal(struct nsjconf_t *nsjconf, pid_t pid UNUSED)
{
- char pid_str[16];
- char ins_gid_str[16];
- char out_gid_str[16];
-
- snprintf(pid_str, sizeof(pid_str), "%lu", (unsigned long)pid);
- snprintf(ins_gid_str, sizeof(ins_gid_str), "%lu", (unsigned long)nsjconf->inside_gid);
- snprintf(out_gid_str, sizeof(out_gid_str), "%lu", (unsigned long)nsjconf->outside_gid);
-
- const char *argv[1024] = { "/usr/bin/newgidmap", pid_str, ins_gid_str, out_gid_str, "1" };
- size_t argv_idx = 5;
+ const char *argv[1024] = { "/usr/bin/newgidmap" };
+ size_t argv_idx = 1;
struct mapping_t *p;
TAILQ_FOREACH(p, &nsjconf->gid_mappings, pointers) {
- if ((argv_idx + 4) >= ARRAYSIZE(argv)) {
+ if (argv_idx >= ARRAYSIZE(argv)) {
LOG_W("Number of arguments to '/usr/bin/newgidmap' too big");
return false;
}
}
/* Use /usr/bin/newuidmap for writing the uid map */
-static bool userUidMapExternal(struct nsjconf_t *nsjconf, pid_t pid)
+static bool userUidMapExternal(struct nsjconf_t *nsjconf, pid_t pid UNUSED)
{
- char pid_str[16];
- char ins_uid_str[16];
- char out_uid_str[16];
-
- snprintf(pid_str, sizeof(pid_str), "%lu", (unsigned long)pid);
- snprintf(ins_uid_str, sizeof(ins_uid_str), "%lu", (unsigned long)nsjconf->inside_uid);
- snprintf(out_uid_str, sizeof(out_uid_str), "%lu", (unsigned long)nsjconf->outside_uid);
-
- const char *argv[1024] = { "/usr/bin/newuidmap", pid_str, ins_uid_str, out_uid_str, "1" };
- size_t argv_idx = 5;
+ const char *argv[1024] = { "/usr/bin/newuidmap" };
+ size_t argv_idx = 1;
struct mapping_t *p;
TAILQ_FOREACH(p, &nsjconf->uid_mappings, pointers) {
- if ((argv_idx + 4) >= ARRAYSIZE(argv)) {
+ if (argv_idx >= ARRAYSIZE(argv)) {
LOG_W("Number of arguments to '/usr/bin/newuidmap' too big");
return false;
}
if (setgroups(0, group_list) == -1) {
PLOG_D("setgroups(NULL) failed");
}
- LOG_D("setresgid(%d, %d, %d)", nsjconf->inside_gid, nsjconf->inside_gid,
- nsjconf->inside_gid);
- if (syscall(__NR_setresgid, nsjconf->inside_gid, nsjconf->inside_gid, nsjconf->inside_gid)
+ LOG_D("setresgid(%d, %d, %d)", TAILQ_FIRST(&nsjconf->gids)->inside_id,
+ TAILQ_FIRST(&nsjconf->gids)->inside_id, TAILQ_FIRST(&nsjconf->gids)->inside_id);
+ if (syscall
+ (__NR_setresgid, TAILQ_FIRST(&nsjconf->gids)->inside_id,
+ TAILQ_FIRST(&nsjconf->gids)->inside_id, TAILQ_FIRST(&nsjconf->gids)->inside_id)
== -1) {
- PLOG_E("setresgid(%u)", nsjconf->inside_gid);
+ PLOG_E("setresgid(%u)", TAILQ_FIRST(&nsjconf->gids)->inside_id);
return false;
}
- LOG_D("setresuid(%d, %d, %d)", nsjconf->inside_uid, nsjconf->inside_uid,
- nsjconf->inside_uid);
- if (syscall(__NR_setresuid, nsjconf->inside_uid, nsjconf->inside_uid, nsjconf->inside_uid)
+ LOG_D("setresuid(%d, %d, %d)", TAILQ_FIRST(&nsjconf->uids)->inside_id,
+ TAILQ_FIRST(&nsjconf->uids)->inside_id, TAILQ_FIRST(&nsjconf->uids)->inside_id);
+ if (syscall
+ (__NR_setresuid, TAILQ_FIRST(&nsjconf->uids)->inside_id,
+ TAILQ_FIRST(&nsjconf->uids)->inside_id, TAILQ_FIRST(&nsjconf->uids)->inside_id)
== -1) {
- PLOG_E("setresuid(%u)", nsjconf->inside_uid);
+ PLOG_E("setresuid(%u)", TAILQ_FIRST(&nsjconf->uids)->inside_id);
return false;
}