#define LO_FLAGS_AUTOCLEAR 4
#endif
+/* needed for cgroup automount checks, regardless of whether we
+ * have included linux/capability.h or not */
+#ifndef CAP_SYS_ADMIN
+#define CAP_SYS_ADMIN 21
+#endif
+
/* Define pivot_root() if missing from the C library */
#ifndef HAVE_PIVOT_ROOT
static int pivot_root(const char * new_root, const char * put_old)
int value;
};
+/* Declare this here, since we don't want to reshuffle the whole file. */
+static int in_caplist(int cap, struct lxc_list *caps);
+
static int instanciate_veth(struct lxc_handler *, struct lxc_netdev *);
static int instanciate_macvlan(struct lxc_handler *, struct lxc_netdev *);
static int instanciate_vlan(struct lxc_handler *, struct lxc_netdev *);
}
if (flags & LXC_AUTO_CGROUP_MASK) {
- if (!cgroup_mount(conf->rootfs.mount, handler,
- flags & LXC_AUTO_CGROUP_MASK)) {
+ int cg_flags;
+
+ cg_flags = flags & LXC_AUTO_CGROUP_MASK;
+ /* If the type of cgroup mount was not specified, it depends on the
+ * container's capabilities as to what makes sense: if we have
+ * CAP_SYS_ADMIN, the read-only part can be remounted read-write
+ * anyway, so we may as well default to read-write; then the admin
+ * will not be given a false sense of security. (And if they really
+ * want mixed r/o r/w, then they can explicitly specify :mixed.)
+ * OTOH, if the container lacks CAP_SYS_ADMIN, do only default to
+ * :mixed, because then the container can't remount it read-write. */
+ if (cg_flags == LXC_AUTO_CGROUP_NOSPEC || cg_flags == LXC_AUTO_CGROUP_FULL_NOSPEC) {
+ int has_sys_admin = 0;
+ if (!lxc_list_empty(&conf->keepcaps)) {
+ has_sys_admin = in_caplist(CAP_SYS_ADMIN, &conf->keepcaps);
+ } else {
+ has_sys_admin = !in_caplist(CAP_SYS_ADMIN, &conf->caps);
+ }
+ if (cg_flags == LXC_AUTO_CGROUP_NOSPEC) {
+ cg_flags = has_sys_admin ? LXC_AUTO_CGROUP_RW : LXC_AUTO_CGROUP_MIXED;
+ } else {
+ cg_flags = has_sys_admin ? LXC_AUTO_CGROUP_FULL_RW : LXC_AUTO_CGROUP_FULL_MIXED;
+ }
+ }
+
+ if (!cgroup_mount(conf->rootfs.mount, handler, cg_flags)) {
SYSERROR("error mounting /sys/fs/cgroup");
return -1;
}
return capid;
}
+int in_caplist(int cap, struct lxc_list *caps)
+{
+ struct lxc_list *iterator;
+ int capid;
+
+ lxc_list_for_each(iterator, caps) {
+ capid = parse_cap(iterator->elem);
+ if (capid == cap)
+ return 1;
+ }
+
+ return 0;
+}
+
static int setup_caps(struct lxc_list *caps)
{
struct lxc_list *iterator;
{
char *autos, *autoptr, *sptr, *token;
static struct { const char *token; int mask; int flag; } allowed_auto_mounts[] = {
- { "proc", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
- { "proc:mixed", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
- { "proc:rw", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW },
- { "sys", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RO },
- { "sys:ro", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RO },
- { "sys:rw", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RW },
- { "cgroup", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_MIXED },
- { "cgroup:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_MIXED },
- { "cgroup:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RO },
- { "cgroup:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RW },
- { "cgroup-full", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_MIXED },
- { "cgroup-full:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_MIXED },
- { "cgroup-full:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RO },
- { "cgroup-full:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RW },
+ { "proc", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
+ { "proc:mixed", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
+ { "proc:rw", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW },
+ { "sys", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RO },
+ { "sys:ro", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RO },
+ { "sys:rw", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RW },
+ { "cgroup", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_NOSPEC },
+ { "cgroup:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_MIXED },
+ { "cgroup:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RO },
+ { "cgroup:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RW },
+ { "cgroup-full", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_NOSPEC },
+ { "cgroup-full:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_MIXED },
+ { "cgroup-full:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RO },
+ { "cgroup-full:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RW },
/* NB: For adding anything that ist just a single on/off, but has
* no options: keep mask and flag identical and just define the
* enum value as an unused bit so far
static int lxc_get_auto_mounts(struct lxc_conf *c, char *retv, int inlen)
{
int len, fulllen = 0;
+ const char *sep = "";
if (!retv)
inlen = 0;
return 0;
switch (c->auto_mounts & LXC_AUTO_PROC_MASK) {
- case LXC_AUTO_PROC_MIXED: strprint(retv, inlen, "proc:mixed\n"); break;
- case LXC_AUTO_PROC_RW: strprint(retv, inlen, "proc:rw"); break;
+ case LXC_AUTO_PROC_MIXED: strprint(retv, inlen, "%sproc:mixed", sep); sep = " "; break;
+ case LXC_AUTO_PROC_RW: strprint(retv, inlen, "%sproc:rw", sep); sep = " "; break;
default: break;
}
switch (c->auto_mounts & LXC_AUTO_SYS_MASK) {
- case LXC_AUTO_SYS_RO: strprint(retv, inlen, "sys:ro"); break;
- case LXC_AUTO_SYS_RW: strprint(retv, inlen, "sys:rw"); break;
+ case LXC_AUTO_SYS_RO: strprint(retv, inlen, "%ssys:ro", sep); sep = " "; break;
+ case LXC_AUTO_SYS_RW: strprint(retv, inlen, "%ssys:rw", sep); sep = " "; break;
default: break;
}
switch (c->auto_mounts & LXC_AUTO_CGROUP_MASK) {
- case LXC_AUTO_CGROUP_MIXED: strprint(retv, inlen, "cgroup:mixed"); break;
- case LXC_AUTO_CGROUP_RO: strprint(retv, inlen, "cgroup:ro"); break;
- case LXC_AUTO_CGROUP_RW: strprint(retv, inlen, "cgroup:rw"); break;
- case LXC_AUTO_CGROUP_FULL_MIXED: strprint(retv, inlen, "cgroup-full:mixed"); break;
- case LXC_AUTO_CGROUP_FULL_RO: strprint(retv, inlen, "cgroup-full:ro"); break;
- case LXC_AUTO_CGROUP_FULL_RW: strprint(retv, inlen, "cgroup-full:rw"); break;
+ case LXC_AUTO_CGROUP_NOSPEC: strprint(retv, inlen, "%scgroup", sep); sep = " "; break;
+ case LXC_AUTO_CGROUP_MIXED: strprint(retv, inlen, "%scgroup:mixed", sep); sep = " "; break;
+ case LXC_AUTO_CGROUP_RO: strprint(retv, inlen, "%scgroup:ro", sep); sep = " "; break;
+ case LXC_AUTO_CGROUP_RW: strprint(retv, inlen, "%scgroup:rw", sep); sep = " "; break;
+ case LXC_AUTO_CGROUP_FULL_NOSPEC: strprint(retv, inlen, "%scgroup-full", sep); sep = " "; break;
+ case LXC_AUTO_CGROUP_FULL_MIXED: strprint(retv, inlen, "%scgroup-full:mixed", sep); sep = " "; break;
+ case LXC_AUTO_CGROUP_FULL_RO: strprint(retv, inlen, "%scgroup-full:ro", sep); sep = " "; break;
+ case LXC_AUTO_CGROUP_FULL_RW: strprint(retv, inlen, "%scgroup-full:rw", sep); sep = " "; break;
default: break;
}
+
return fulllen;
}
if (c->auto_mounts & LXC_AUTO_ALL_MASK) {
fprintf(fout, "lxc.mount.auto =");
switch (c->auto_mounts & LXC_AUTO_PROC_MASK) {
- case LXC_AUTO_PROC_MIXED: fprintf(fout, " proc:mixed"); break;
- case LXC_AUTO_PROC_RW: fprintf(fout, " proc:rw"); break;
+ case LXC_AUTO_PROC_MIXED: fprintf(fout, " proc:mixed"); break;
+ case LXC_AUTO_PROC_RW: fprintf(fout, " proc:rw"); break;
default: break;
}
switch (c->auto_mounts & LXC_AUTO_SYS_MASK) {
- case LXC_AUTO_SYS_RO: fprintf(fout, " sys:ro"); break;
- case LXC_AUTO_SYS_RW: fprintf(fout, " sys:rw"); break;
+ case LXC_AUTO_SYS_RO: fprintf(fout, " sys:ro"); break;
+ case LXC_AUTO_SYS_RW: fprintf(fout, " sys:rw"); break;
default: break;
}
switch (c->auto_mounts & LXC_AUTO_CGROUP_MASK) {
- case LXC_AUTO_CGROUP_MIXED: fprintf(fout, " cgroup:mixed"); break;
- case LXC_AUTO_CGROUP_RO: fprintf(fout, " cgroup:ro"); break;
- case LXC_AUTO_CGROUP_RW: fprintf(fout, " cgroup:rw"); break;
- case LXC_AUTO_CGROUP_FULL_MIXED: fprintf(fout, " cgroup-full:mixed"); break;
- case LXC_AUTO_CGROUP_FULL_RO: fprintf(fout, " cgroup-full:ro"); break;
- case LXC_AUTO_CGROUP_FULL_RW: fprintf(fout, " cgroup-full:rw"); break;
+ case LXC_AUTO_CGROUP_NOSPEC: fprintf(fout, " cgroup"); break;
+ case LXC_AUTO_CGROUP_MIXED: fprintf(fout, " cgroup:mixed"); break;
+ case LXC_AUTO_CGROUP_RO: fprintf(fout, " cgroup:ro"); break;
+ case LXC_AUTO_CGROUP_RW: fprintf(fout, " cgroup:rw"); break;
+ case LXC_AUTO_CGROUP_FULL_NOSPEC: fprintf(fout, " cgroup-full"); break;
+ case LXC_AUTO_CGROUP_FULL_MIXED: fprintf(fout, " cgroup-full:mixed"); break;
+ case LXC_AUTO_CGROUP_FULL_RO: fprintf(fout, " cgroup-full:ro"); break;
+ case LXC_AUTO_CGROUP_FULL_RW: fprintf(fout, " cgroup-full:rw"); break;
default: break;
}
fprintf(fout, "\n");