Improve bindmount interface.
Now supports readonly bindmounts and differentiating between source and target path.
This commit is contained in:
parent
459a220133
commit
821eb78054
27
cmdline.c
27
cmdline.c
@ -95,8 +95,11 @@ void cmdlineLogParams(struct nsjconf_t *nsjconf)
|
||||
logYesNo(nsjconf->clone_newuts), logYesNo(nsjconf->apply_sandbox), logYesNo(nsjconf->keep_caps));
|
||||
|
||||
struct constchar_t *p;
|
||||
LIST_FOREACH(p, &nsjconf->bindmountpts, pointers) {
|
||||
LOG_I("Additional bind mount point: '%s'", p->value);
|
||||
LIST_FOREACH(p, &nsjconf->robindmountpts, pointers) {
|
||||
LOG_I("Additional (ro) bind mount point: '%s'", p->value);
|
||||
}
|
||||
LIST_FOREACH(p, &nsjconf->rwbindmountpts, pointers) {
|
||||
LOG_I("Additional (rw) bind mount point: '%s'", p->value);
|
||||
}
|
||||
LIST_FOREACH(p, &nsjconf->tmpfsmountpts, pointers) {
|
||||
LOG_I("Additional tmpfs mount point: '%s'", p->value);
|
||||
@ -181,7 +184,8 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
||||
/* *INDENT-OFF* */
|
||||
|
||||
LIST_INIT(&nsjconf->pids);
|
||||
LIST_INIT(&nsjconf->bindmountpts);
|
||||
LIST_INIT(&nsjconf->robindmountpts);
|
||||
LIST_INIT(&nsjconf->rwbindmountpts);
|
||||
LIST_INIT(&nsjconf->tmpfsmountpts);
|
||||
|
||||
const char *user = "nobody";
|
||||
@ -228,8 +232,9 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
||||
{{"disable_sandbox", no_argument, NULL, 0x0501}, "Don't enable the seccomp-bpf sandboxing (default: false)"},
|
||||
{{"rw", no_argument, NULL, 0x0503}, "Mount / as RW (default: RO)"},
|
||||
{{"silent", no_argument, NULL, 0x0504}, "Redirect child's fd:0/1/2 to /dev/null (default: false)"},
|
||||
{{"bindmount", required_argument, NULL, 'B'}, "List of mountpoints to be mounted --bind inside the container. Can be specified multiple times (default: none)"},
|
||||
{{"tmpfsmount", required_argument, NULL, 'T'}, "List of mountpoints to be mounted as RW/tmpfs inside the container. Can be specified multiple times (default: none)"},
|
||||
{{"bindmount_ro", required_argument, NULL, 0x0505}, "List of mountpoints to be mounted --bind (ro) inside the container. Can be specified multiple times. Supports 'source' syntax, or 'source:dest'. (default: none)"},
|
||||
{{"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'. (default: none)"},
|
||||
{{"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. (default: none)"},
|
||||
{{"iface", required_argument, NULL, 'I'}, "Interface which will be cloned (MACVTAP) and put inside the subprocess' namespace"},
|
||||
{{0, 0, 0, 0}, NULL},
|
||||
};
|
||||
@ -350,6 +355,16 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
||||
case 0x0504:
|
||||
nsjconf->is_silent = true;
|
||||
break;
|
||||
case 0x0505:
|
||||
{
|
||||
struct constchar_t *p = malloc(sizeof(struct constchar_t));
|
||||
if (p == NULL) {
|
||||
PLOG_F("malloc(%zu)", sizeof(struct constchar_t));
|
||||
}
|
||||
p->value = optarg;
|
||||
LIST_INSERT_HEAD(&nsjconf->robindmountpts, p, pointers);
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
{
|
||||
struct constchar_t *p = malloc(sizeof(struct constchar_t));
|
||||
@ -357,7 +372,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
||||
PLOG_F("malloc(%zu)", sizeof(struct constchar_t));
|
||||
}
|
||||
p->value = optarg;
|
||||
LIST_INSERT_HEAD(&nsjconf->bindmountpts, p, pointers);
|
||||
LIST_INSERT_HEAD(&nsjconf->rwbindmountpts, p, pointers);
|
||||
}
|
||||
break;
|
||||
case 'T':
|
||||
|
3
common.h
3
common.h
@ -84,7 +84,8 @@ struct nsjconf_t {
|
||||
gid_t initial_gid;
|
||||
unsigned int max_conns_per_ip;
|
||||
LIST_HEAD(pidslist, pids_t) pids;
|
||||
LIST_HEAD(bindmountptslist, constchar_t) bindmountpts;
|
||||
LIST_HEAD(rwbindmountptslist, constchar_t) rwbindmountpts;
|
||||
LIST_HEAD(robindmountptslist, constchar_t) robindmountpts;
|
||||
LIST_HEAD(tmpfsmountptslist, constchar_t) tmpfsmountpts;
|
||||
};
|
||||
|
||||
|
94
contain.c
94
contain.c
@ -174,6 +174,67 @@ bool containPrepareEnv(struct nsjconf_t * nsjconf)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* findSpecDestination mutates spec (source:dest) to have a null byte instead
|
||||
* of ':' in between source and dest, then returns a pointer to the dest
|
||||
* string. */
|
||||
static char *findSpecDestination(char *spec) {
|
||||
char *dest = spec;
|
||||
while (*dest != ':' && *dest != '\0') {
|
||||
dest++;
|
||||
}
|
||||
|
||||
switch (*dest) {
|
||||
case ':':
|
||||
*dest = '\0';
|
||||
return dest + 1;
|
||||
case '\0':
|
||||
return spec;
|
||||
default:
|
||||
// not reached
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
|
||||
static bool bindMount(const char *newrootdir, const char *spec) {
|
||||
char mount_pt[PATH_MAX];
|
||||
bool success = false;
|
||||
char *source = strdup(spec);
|
||||
char *dest = findSpecDestination(source);
|
||||
|
||||
snprintf(mount_pt, sizeof(mount_pt), "%s/%s", newrootdir, dest);
|
||||
if (mkdir(mount_pt, 0700) == -1 && errno != EEXIST) {
|
||||
PLOG_E("mkdir('%s')", mount_pt);
|
||||
goto cleanup;
|
||||
}
|
||||
LOG_D("Mounting (bind) '%s' on '%s'", source, mount_pt);
|
||||
if (mount(source, mount_pt, NULL, MS_BIND | MS_REC, NULL) == -1) {
|
||||
PLOG_E("mount('%s', '%s', MS_BIND|MS_REC)", source, mount_pt);
|
||||
goto cleanup;
|
||||
}
|
||||
success = true;
|
||||
|
||||
cleanup:
|
||||
free(source);
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool remountBindMount(const char *spec, unsigned long flags) {
|
||||
bool success = false;
|
||||
char *source = strdup(spec);
|
||||
char *dest = findSpecDestination(source);
|
||||
|
||||
LOG_D("Remounting (bind|%lu) '%s' on '%s'", flags, dest, dest);
|
||||
if (mount(dest, dest, NULL, MS_BIND | MS_NOSUID | MS_NODEV | MS_REMOUNT | MS_PRIVATE | flags, NULL) != 0) {
|
||||
PLOG_E("mount('%s', '%s', MS_BIND|MS_NOSUID|MS_NODEV|MS_REMOUNT|MS_PRIVATE|%lu)", dest, dest, flags);
|
||||
goto cleanup;
|
||||
}
|
||||
success = true;
|
||||
|
||||
cleanup:
|
||||
free(source);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool containMountFS(struct nsjconf_t * nsjconf)
|
||||
{
|
||||
const char *destdir = "/tmp";
|
||||
@ -184,7 +245,7 @@ bool containMountFS(struct nsjconf_t * nsjconf)
|
||||
char newrootdir[PATH_MAX];
|
||||
snprintf(newrootdir, sizeof(newrootdir), "%s/%s", destdir, "new_root");
|
||||
if (mkdir(newrootdir, 0755) == -1) {
|
||||
PLOG_E("mkdir(/tmp/new_root");
|
||||
PLOG_E("mkdir(/tmp/new_root)");
|
||||
return false;
|
||||
}
|
||||
if (mount(nsjconf->chroot, newrootdir, NULL, MS_BIND | MS_REC, NULL) == -1) {
|
||||
@ -193,16 +254,13 @@ bool containMountFS(struct nsjconf_t * nsjconf)
|
||||
}
|
||||
|
||||
struct constchar_t *p;
|
||||
char mount_pt[PATH_MAX];
|
||||
LIST_FOREACH(p, &nsjconf->bindmountpts, pointers) {
|
||||
snprintf(mount_pt, sizeof(mount_pt), "%s/%s", newrootdir, p->value);
|
||||
if (mkdir(mount_pt, 0700) == -1 && errno != EEXIST) {
|
||||
PLOG_E("mkdir('%s')", mount_pt);
|
||||
LIST_FOREACH(p, &nsjconf->robindmountpts, pointers) {
|
||||
if (!bindMount(newrootdir, p->value)) {
|
||||
return false;
|
||||
}
|
||||
LOG_D("Mounting (bind) '%s' on '%s'", p->value, mount_pt);
|
||||
if (mount(p->value, mount_pt, NULL, MS_BIND | MS_REC, NULL) == -1) {
|
||||
PLOG_E("mount('%s', '%s', MS_BIND|MS_REC", p->value, mount_pt);
|
||||
}
|
||||
LIST_FOREACH(p, &nsjconf->rwbindmountpts, pointers) {
|
||||
if (!bindMount(newrootdir, p->value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -236,10 +294,14 @@ bool containMountFS(struct nsjconf_t * nsjconf)
|
||||
PLOG_E("chdir('/')");
|
||||
return false;
|
||||
}
|
||||
/* It only makes sense with "--chroot /", so don't worry about erorrs */
|
||||
/* It only makes sense with "--chroot /", so don't worry about errors */
|
||||
umount2(destdir, MNT_DETACH);
|
||||
|
||||
LIST_FOREACH(p, &nsjconf->tmpfsmountpts, pointers) {
|
||||
if (strchr(p->value, ':') != NULL) {
|
||||
PLOG_E("invalid tmpfs mount spec. source:dest format unsupported.");
|
||||
return false;
|
||||
}
|
||||
if (mkdir(p->value, 0700) == -1 && errno != EEXIST) {
|
||||
PLOG_E("mkdir('%s'); You probably need to create it in your --chroot ('%s') directory",
|
||||
p->value, nsjconf->chroot);
|
||||
@ -261,6 +323,18 @@ bool containMountFS(struct nsjconf_t * nsjconf)
|
||||
}
|
||||
}
|
||||
|
||||
LIST_FOREACH(p, &nsjconf->robindmountpts, pointers) {
|
||||
if (!remountBindMount(p->value, MS_RDONLY)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
LIST_FOREACH(p, &nsjconf->rwbindmountpts, pointers) {
|
||||
if (!remountBindMount(p->value, 0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user