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
43
cmdline.c
43
cmdline.c
@ -114,10 +114,24 @@ void cmdlineLogParams(struct nsjconf_t *nsjconf)
|
|||||||
logYesNo(nsjconf->clone_newuts), logYesNo(nsjconf->clone_newcgroup),
|
logYesNo(nsjconf->clone_newuts), logYesNo(nsjconf->clone_newcgroup),
|
||||||
logYesNo(nsjconf->apply_sandbox), logYesNo(nsjconf->keep_caps), nsjconf->tmpfs_size);
|
logYesNo(nsjconf->apply_sandbox), logYesNo(nsjconf->keep_caps), nsjconf->tmpfs_size);
|
||||||
|
|
||||||
struct mounts_t *p;
|
{
|
||||||
TAILQ_FOREACH(p, &nsjconf->mountpts, pointers) {
|
struct mounts_t *p;
|
||||||
LOG_I("Mount point: src:'%s' dst:'%s' type:'%s' flags:0x%tx options:'%s'",
|
TAILQ_FOREACH(p, &nsjconf->mountpts, pointers) {
|
||||||
p->src, p->dst, p->fs_type, p->flags, p->options);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,6 +320,8 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
|||||||
TAILQ_INIT(&nsjconf->pids);
|
TAILQ_INIT(&nsjconf->pids);
|
||||||
TAILQ_INIT(&nsjconf->mountpts);
|
TAILQ_INIT(&nsjconf->mountpts);
|
||||||
TAILQ_INIT(&nsjconf->open_fds);
|
TAILQ_INIT(&nsjconf->open_fds);
|
||||||
|
TAILQ_INIT(&nsjconf->uid_mappings);
|
||||||
|
TAILQ_INIT(&nsjconf->gid_mappings);
|
||||||
|
|
||||||
char *user = NULL;
|
char *user = NULL;
|
||||||
char *group = 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_newipc", no_argument, NULL, 0x0405}, "Don't use CLONE_NEWIPC"},
|
||||||
{{"disable_clone_newuts", no_argument, NULL, 0x0406}, "Don't use CLONE_NEWUTS"},
|
{{"disable_clone_newuts", no_argument, NULL, 0x0406}, "Don't use CLONE_NEWUTS"},
|
||||||
{{"enable_clone_newcgroup", no_argument, NULL, 0x0407}, "Use CLONE_NEWCGROUP"},
|
{{"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_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'"},
|
{{"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"},
|
{{"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;
|
int opt_index = 0;
|
||||||
for (;;) {
|
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);
|
&opt_index);
|
||||||
if (c == -1) {
|
if (c == -1) {
|
||||||
break;
|
break;
|
||||||
@ -539,6 +557,21 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
|||||||
TAILQ_INSERT_TAIL(&nsjconf->envs, p, pointers);
|
TAILQ_INSERT_TAIL(&nsjconf->envs, p, pointers);
|
||||||
}
|
}
|
||||||
break;
|
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':
|
case 'R':
|
||||||
{
|
{
|
||||||
struct mounts_t *p = utilMalloc(sizeof(struct mounts_t));
|
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;
|
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 {
|
struct fds_t {
|
||||||
int fd;
|
int fd;
|
||||||
TAILQ_ENTRY(fds_t) pointers;
|
TAILQ_ENTRY(fds_t) pointers;
|
||||||
@ -139,6 +146,8 @@ struct nsjconf_t {
|
|||||||
TAILQ_HEAD(pidslist, pids_t) pids;
|
TAILQ_HEAD(pidslist, pids_t) pids;
|
||||||
TAILQ_HEAD(mountptslist, mounts_t) mountpts;
|
TAILQ_HEAD(mountptslist, mounts_t) mountpts;
|
||||||
TAILQ_HEAD(fdslistt, fds_t) open_fds;
|
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 */
|
#endif /* NS_COMMON_H */
|
||||||
|
105
user.c
105
user.c
@ -54,8 +54,7 @@ static bool userSetGroups(pid_t pid)
|
|||||||
return true;
|
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 fname[PATH_MAX];
|
||||||
char map[128];
|
char map[128];
|
||||||
|
|
||||||
@ -68,6 +67,13 @@ static bool userUidGidMap(struct nsjconf_t *nsjconf, pid_t pid)
|
|||||||
return false;
|
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(fname, sizeof(fname), "/proc/%d/gid_map", pid);
|
||||||
snprintf(map, sizeof(map), "%lu %lu 1", (unsigned long)nsjconf->inside_gid,
|
snprintf(map, sizeof(map), "%lu %lu 1", (unsigned long)nsjconf->inside_gid,
|
||||||
(unsigned long)nsjconf->outside_gid);
|
(unsigned long)nsjconf->outside_gid);
|
||||||
@ -79,6 +85,101 @@ static bool userUidGidMap(struct nsjconf_t *nsjconf, pid_t pid)
|
|||||||
return true;
|
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)
|
bool userInitNsFromParent(struct nsjconf_t * nsjconf, pid_t pid)
|
||||||
{
|
{
|
||||||
if (nsjconf->clone_newuser == false) {
|
if (nsjconf->clone_newuser == false) {
|
||||||
|
Loading…
Reference in New Issue
Block a user