Support more complex uid and gid mappings
Introduces the new options uid_mapping and gid_mapping that specify arbitrary custom mappings. If these options are used, nsjail will use newuidmap/newgidmap to write the map files.
This commit is contained in:
parent
ee7de33531
commit
1c950391a1
35
cmdline.c
35
cmdline.c
@ -114,12 +114,26 @@ void cmdlineLogParams(struct nsjconf_t *nsjconf)
|
||||
logYesNo(nsjconf->clone_newuts), logYesNo(nsjconf->clone_newcgroup),
|
||||
logYesNo(nsjconf->apply_sandbox), logYesNo(nsjconf->keep_caps), nsjconf->tmpfs_size);
|
||||
|
||||
{
|
||||
struct mounts_t *p;
|
||||
TAILQ_FOREACH(p, &nsjconf->mountpts, pointers) {
|
||||
LOG_I("Mount point: src:'%s' dst:'%s' type:'%s' flags:0x%tx options:'%s'",
|
||||
p->src, p->dst, p->fs_type, p->flags, p->options);
|
||||
}
|
||||
}
|
||||
{
|
||||
struct mapping_t *p;
|
||||
TAILQ_FOREACH(p, &nsjconf->uid_mappings, pointers) {
|
||||
LOG_I("Uid 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'",
|
||||
p->inside_id, p->outside_id, p->count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cmdlineUsage(const char *pname, struct custom_option *opts)
|
||||
{
|
||||
@ -306,6 +320,8 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
||||
TAILQ_INIT(&nsjconf->pids);
|
||||
TAILQ_INIT(&nsjconf->mountpts);
|
||||
TAILQ_INIT(&nsjconf->open_fds);
|
||||
TAILQ_INIT(&nsjconf->uid_mappings);
|
||||
TAILQ_INIT(&nsjconf->gid_mappings);
|
||||
|
||||
char *user = NULL;
|
||||
char *group = NULL;
|
||||
@ -370,6 +386,8 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
||||
{{"disable_clone_newipc", no_argument, NULL, 0x0405}, "Don't use CLONE_NEWIPC"},
|
||||
{{"disable_clone_newuts", no_argument, NULL, 0x0406}, "Don't use CLONE_NEWUTS"},
|
||||
{{"enable_clone_newcgroup", no_argument, NULL, 0x0407}, "Use CLONE_NEWCGROUP"},
|
||||
{{"uid_mapping", required_argument, NULL, 'U'}, "Add a custom uid mapping of the form inside_uid:outside_uid:count. Setting this requires newuidmap to be present"},
|
||||
{{"gid_mapping", required_argument, NULL, 'G'}, "Add a custom gid mapping of the form inside_gid:outside_gid:count. Setting this requires newuidmap to be present"},
|
||||
{{"bindmount_ro", required_argument, NULL, 'R'}, "List of mountpoints to be mounted --bind (ro) inside the container. Can be specified multiple times. Supports 'source' syntax, or 'source:dest'"},
|
||||
{{"bindmount", required_argument, NULL, 'B'}, "List of mountpoints to be mounted --bind (rw) inside the container. Can be specified multiple times. Supports 'source' syntax, or 'source:dest'"},
|
||||
{{"tmpfsmount", required_argument, NULL, 'T'}, "List of mountpoints to be mounted as RW/tmpfs inside the container. Can be specified multiple times. Supports 'dest' syntax"},
|
||||
@ -394,7 +412,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
||||
|
||||
int opt_index = 0;
|
||||
for (;;) {
|
||||
int c = getopt_long(argc, argv, "H:D:c:p:i:u:g:l:t:M:Ndveh?E:R:B:T:I:", opts,
|
||||
int c = getopt_long(argc, argv, "H:D:c:p:i:u:g:l:t:M:Ndveh?E:R:B:T:I:U:G:", opts,
|
||||
&opt_index);
|
||||
if (c == -1) {
|
||||
break;
|
||||
@ -539,6 +557,21 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
||||
TAILQ_INSERT_TAIL(&nsjconf->envs, p, pointers);
|
||||
}
|
||||
break;
|
||||
case 'U':
|
||||
case 'G':
|
||||
{
|
||||
struct mapping_t *p = utilMalloc(sizeof(struct mapping_t));
|
||||
p->inside_id = optarg;
|
||||
char *outside_id = cmdlineSplitStrByColon(optarg);
|
||||
p->outside_id = outside_id;
|
||||
p->count = cmdlineSplitStrByColon(outside_id);
|
||||
if (c == 'U') {
|
||||
TAILQ_INSERT_TAIL(&nsjconf->uid_mappings, p, pointers);
|
||||
} else {
|
||||
TAILQ_INSERT_TAIL(&nsjconf->gid_mappings, p, pointers);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'R':
|
||||
{
|
||||
struct mounts_t *p = utilMalloc(sizeof(struct mounts_t));
|
||||
|
9
common.h
9
common.h
@ -71,6 +71,13 @@ struct mounts_t {
|
||||
TAILQ_ENTRY(mounts_t) pointers;
|
||||
};
|
||||
|
||||
struct mapping_t {
|
||||
const char *inside_id;
|
||||
const char *outside_id;
|
||||
const char *count;
|
||||
TAILQ_ENTRY(mapping_t) pointers;
|
||||
};
|
||||
|
||||
struct fds_t {
|
||||
int fd;
|
||||
TAILQ_ENTRY(fds_t) pointers;
|
||||
@ -139,6 +146,8 @@ struct nsjconf_t {
|
||||
TAILQ_HEAD(pidslist, pids_t) pids;
|
||||
TAILQ_HEAD(mountptslist, mounts_t) mountpts;
|
||||
TAILQ_HEAD(fdslistt, fds_t) open_fds;
|
||||
TAILQ_HEAD(uidmaplistt, mapping_t) uid_mappings;
|
||||
TAILQ_HEAD(gidmaplistt, mapping_t) gid_mappings;
|
||||
};
|
||||
|
||||
#endif /* NS_COMMON_H */
|
||||
|
105
user.c
105
user.c
@ -54,8 +54,7 @@ static bool userSetGroups(pid_t pid)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool userUidGidMap(struct nsjconf_t *nsjconf, pid_t pid)
|
||||
{
|
||||
static bool userUidMapSelf(struct nsjconf_t *nsjconf, pid_t pid) {
|
||||
char fname[PATH_MAX];
|
||||
char map[128];
|
||||
|
||||
@ -68,6 +67,13 @@ static bool userUidGidMap(struct nsjconf_t *nsjconf, pid_t pid)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
@ -79,6 +85,101 @@ static bool userUidGidMap(struct nsjconf_t *nsjconf, pid_t pid)
|
||||
return true;
|
||||
}
|
||||
|
||||
// use /usr/bin/newgidmap for writing the uid and gid map
|
||||
static bool userGidMapExternal(struct nsjconf_t *nsjconf, pid_t pid) {
|
||||
char cmd_buf[1024];
|
||||
char *cmd_ptr = cmd_buf;
|
||||
size_t len = sizeof(cmd_buf);
|
||||
int write_size;
|
||||
|
||||
write_size = snprintf(cmd_ptr, len, "/usr/bin/newgidmap %lu %lu %lu 1",
|
||||
(unsigned long)pid,
|
||||
(unsigned long)nsjconf->inside_gid,
|
||||
(unsigned long)nsjconf->outside_gid);
|
||||
if (write_size <= 0 || (size_t) write_size > len) {
|
||||
LOG_E("snprintf writing the new{u,g}idmap command failed");
|
||||
return false;
|
||||
}
|
||||
cmd_ptr += write_size;
|
||||
len -= write_size;
|
||||
|
||||
struct mapping_t *p;
|
||||
TAILQ_FOREACH(p, &nsjconf->gid_mappings, pointers) {
|
||||
write_size = snprintf(cmd_ptr, len, " %s %s %s",
|
||||
p->inside_id, p->outside_id, p->count);
|
||||
if (write_size <= 0 || (size_t) write_size > len) {
|
||||
LOG_E("snprintf writing the new{u,g}idmap command failed");
|
||||
return false;
|
||||
}
|
||||
cmd_ptr += write_size;
|
||||
len -= write_size;
|
||||
}
|
||||
|
||||
if (system(cmd_buf) != 0) {
|
||||
LOG_E("system('%s') failed", cmd_buf);
|
||||
while(1) ;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// use /usr/bin/newuidmap for writing the uid and gid map
|
||||
static bool userUidMapExternal(struct nsjconf_t *nsjconf, pid_t pid) {
|
||||
char cmd_buf[1024];
|
||||
char *cmd_ptr = cmd_buf;
|
||||
size_t len = sizeof(cmd_buf);
|
||||
int write_size;
|
||||
|
||||
write_size = snprintf(cmd_ptr, len, "/usr/bin/newuidmap %lu %lu %lu 1",
|
||||
(unsigned long)pid,
|
||||
(unsigned long)nsjconf->inside_uid,
|
||||
(unsigned long)nsjconf->outside_uid);
|
||||
if (write_size <= 0 || (size_t) write_size > len) {
|
||||
LOG_E("snprintf writing the new{u,g}idmap command failed");
|
||||
return false;
|
||||
}
|
||||
cmd_ptr += write_size;
|
||||
len -= write_size;
|
||||
|
||||
struct mapping_t *p;
|
||||
TAILQ_FOREACH(p, &nsjconf->uid_mappings, pointers) {
|
||||
write_size = snprintf(cmd_ptr, len, " %s %s %s",
|
||||
p->inside_id, p->outside_id, p->count);
|
||||
if (write_size <= 0 || (size_t) write_size > len) {
|
||||
LOG_E("snprintf writing the new{u,g}idmap command failed");
|
||||
return false;
|
||||
}
|
||||
cmd_ptr += write_size;
|
||||
len -= write_size;
|
||||
}
|
||||
|
||||
if (system(cmd_buf) != 0) {
|
||||
LOG_E("system('%s') failed", cmd_buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool userUidGidMap(struct nsjconf_t *nsjconf, pid_t pid)
|
||||
{
|
||||
if (TAILQ_EMPTY(&nsjconf->gid_mappings)) {
|
||||
if (!userGidMapSelf(nsjconf, pid)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!userGidMapExternal(nsjconf, pid)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (TAILQ_EMPTY(&nsjconf->uid_mappings)) {
|
||||
return userUidMapSelf(nsjconf, pid);
|
||||
} else {
|
||||
return userUidMapExternal(nsjconf, pid);
|
||||
}
|
||||
}
|
||||
|
||||
bool userInitNsFromParent(struct nsjconf_t * nsjconf, pid_t pid)
|
||||
{
|
||||
if (nsjconf->clone_newuser == false) {
|
||||
|
Loading…
Reference in New Issue
Block a user