Package: lxc
Version: 1:2.0.7-2+deb9u1
Followup-For: Bug #875733

Hi folks,

I also ran into this exact issue. It seems upstream fixed this bug, see
https://github.com/lxc/lxc/issues/1737

I've backported this fix (along with some other commits it needs) to the
Debian stretch version, which works as expected. I've attached a patch
to the Debian packaging that does this. Since this is a regression from
earlier Debian versions, I guess this would be worth including in
stretch update?

One caveat to note: In my setup, I had `lxc.cgroup.use=@all` in my
`lxc.conf` file, which prevented this fix from working. See
https://github.com/lxc/lxc/issues/2084 for more details.

Gr.

Matthijs
From f1aa85a4b1c1c38211a9fa15afac72b3df142b3d Mon Sep 17 00:00:00 2001
From: Matthijs Kooijman <matth...@stdin.nl>
Date: Sun, 14 Jan 2018 15:47:31 +0100
Subject: [PATCH] Backport upstream commits to fix running without
 CAP_SYS_ADMIN

Closes: #875733
---
 .../0011-lxc-cgroups-move-helper-functions.patch   | 166 ++++++++++
 .../0012-lxc-cgroups-handle-hubrid-layouts.patch   | 358 +++++++++++++++++++++
 .../0013-lxc-cgroups-without-cap-sys-admin.patch   | 157 +++++++++
 debian/patches/series                              |   3 +
 4 files changed, 684 insertions(+)
 create mode 100644 debian/patches/0011-lxc-cgroups-move-helper-functions.patch
 create mode 100644 debian/patches/0012-lxc-cgroups-handle-hubrid-layouts.patch
 create mode 100644 debian/patches/0013-lxc-cgroups-without-cap-sys-admin.patch

diff --git a/debian/patches/0011-lxc-cgroups-move-helper-functions.patch 
b/debian/patches/0011-lxc-cgroups-move-helper-functions.patch
new file mode 100644
index 0000000..b1e7cea
--- /dev/null
+++ b/debian/patches/0011-lxc-cgroups-move-helper-functions.patch
@@ -0,0 +1,166 @@
+commit 04ad7ffe2a42fb2fa2e78e694990b385fd2dd5e0
+Author: Christian Brauner <christian.brau...@ubuntu.com>
+Date:   Wed Jul 26 14:57:35 2017 +0200
+
+    utils: move helpers from cgfsng.c to utils.{c,h}
+    
+    Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com>
+
+---
+
+This commit was backported from upstream to Debian without changes, to
+make the patch 0013-lxc-cgroups-without-cap-sys-admin.patch apply.
+
+--- a/src/lxc/cgroups/cgfsng.c
++++ b/src/lxc/cgroups/cgfsng.c
+@@ -112,36 +112,12 @@ static void free_string_list(char **clis
+       }
+ }
+ 
+-/* Re-alllocate a pointer, do not fail */
+-static void *must_realloc(void *orig, size_t sz)
+-{
+-      void *ret;
+-
+-      do {
+-              ret = realloc(orig, sz);
+-      } while (!ret);
+-      return ret;
+-}
+-
+ /* Allocate a pointer, do not fail */
+ static void *must_alloc(size_t sz)
+ {
+       return must_realloc(NULL, sz);
+ }
+ 
+-/* return copy of string @entry;  do not fail. */
+-static char *must_copy_string(const char *entry)
+-{
+-      char *ret;
+-
+-      if (!entry)
+-              return NULL;
+-      do {
+-              ret = strdup(entry);
+-      } while (!ret);
+-      return ret;
+-}
+-
+ /*
+  * This is a special case - return a copy of @entry
+  * prepending 'name='.  I.e. turn systemd into name=systemd.
+@@ -253,8 +229,6 @@ struct hierarchy *get_hierarchy(const ch
+       return NULL;
+ }
+ 
+-static char *must_make_path(const char *first, ...) __attribute__((sentinel));
+-
+ #define BATCH_SIZE 50
+ static void batch_realloc(char **mem, size_t oldlen, size_t newlen)
+ {
+@@ -1165,33 +1139,6 @@ out_free:
+       return NULL;
+ }
+ 
+-/*
+- * Concatenate all passed-in strings into one path.  Do not fail.  If any 
piece is
+- * not prefixed with '/', add a '/'.
+- */
+-static char *must_make_path(const char *first, ...)
+-{
+-      va_list args;
+-      char *cur, *dest;
+-      size_t full_len = strlen(first);
+-
+-      dest = must_copy_string(first);
+-
+-      va_start(args, first);
+-      while ((cur = va_arg(args, char *)) != NULL) {
+-              full_len += strlen(cur);
+-              if (cur[0] != '/')
+-                      full_len++;
+-              dest = must_realloc(dest, full_len + 1);
+-              if (cur[0] != '/')
+-                      strcat(dest, "/");
+-              strcat(dest, cur);
+-      }
+-      va_end(args);
+-
+-      return dest;
+-}
+-
+ static int cgroup_rmdir(char *dirname)
+ {
+       struct dirent *direntp;
+--- a/src/lxc/utils.c
++++ b/src/lxc/utils.c
+@@ -2083,3 +2083,50 @@ int lxc_setgroups(int size, gid_t list[]
+ 
+       return 0;
+ }
++
++char *must_make_path(const char *first, ...)
++{
++      va_list args;
++      char *cur, *dest;
++      size_t full_len = strlen(first);
++
++      dest = must_copy_string(first);
++
++      va_start(args, first);
++      while ((cur = va_arg(args, char *)) != NULL) {
++              full_len += strlen(cur);
++              if (cur[0] != '/')
++                      full_len++;
++              dest = must_realloc(dest, full_len + 1);
++              if (cur[0] != '/')
++                      strcat(dest, "/");
++              strcat(dest, cur);
++      }
++      va_end(args);
++
++      return dest;
++}
++
++char *must_copy_string(const char *entry)
++{
++      char *ret;
++
++      if (!entry)
++              return NULL;
++      do {
++              ret = strdup(entry);
++      } while (!ret);
++
++      return ret;
++}
++
++void *must_realloc(void *orig, size_t sz)
++{
++      void *ret;
++
++      do {
++              ret = realloc(orig, sz);
++      } while (!ret);
++
++      return ret;
++}
+--- a/src/lxc/utils.h
++++ b/src/lxc/utils.h
+@@ -331,4 +331,15 @@ int lxc_safe_long(const char *numstr, lo
+ int lxc_switch_uid_gid(uid_t uid, gid_t gid);
+ int lxc_setgroups(int size, gid_t list[]);
+ 
++/* Concatenate all passed-in strings into one path. Do not fail. If any piece
++ * is not prefixed with '/', add a '/'.
++ */
++char *must_make_path(const char *first, ...) __attribute__((sentinel));
++
++/* return copy of string @entry;  do not fail. */
++char *must_copy_string(const char *entry);
++
++/* Re-alllocate a pointer, do not fail */
++void *must_realloc(void *orig, size_t sz);
++
+ #endif /* __LXC_UTILS_H */
diff --git a/debian/patches/0012-lxc-cgroups-handle-hubrid-layouts.patch 
b/debian/patches/0012-lxc-cgroups-handle-hubrid-layouts.patch
new file mode 100644
index 0000000..9d37525
--- /dev/null
+++ b/debian/patches/0012-lxc-cgroups-handle-hubrid-layouts.patch
@@ -0,0 +1,358 @@
+commit 6328fd9c05d2730182eb738ffd320de716f062bb
+Author: Christian Brauner <christian.brau...@ubuntu.com>
+Date:   Wed Jul 26 15:15:27 2017 +0200
+
+    cgroups: handle hybrid cgroup layouts
+    
+    Closes #1669.
+    Closes #1678.
+    Relates to https://github.com/systemd/systemd/issues/6408.
+    
+    Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com>
+
+---
+
+This commit was backported from upstream to Debian without changes, to
+make the patch 0013-lxc-cgroups-without-cap-sys-admin.patch apply.
+
+--- a/src/lxc/Makefile.am
++++ b/src/lxc/Makefile.am
+@@ -18,6 +18,7 @@ noinst_HEADERS = \
+       bdev/lxcrsync.h \
+       bdev/lxczfs.h \
+       cgroups/cgroup.h \
++      cgroups/cgroup_utils.h \
+       caps.h \
+       conf.h \
+       console.h \
+@@ -82,6 +83,7 @@ liblxc_la_SOURCES = \
+       bdev/lxczfs.c bdev/lxczfs.h \
+       cgroups/cgfs.c \
+       cgroups/cgfsng.c \
++      cgroups/cgroup_utils.c cgroups/cgroup_utils.h \
+       cgroups/cgroup.c cgroups/cgroup.h \
+       commands.c commands.h \
+       start.c start.h \
+--- a/src/lxc/cgroups/cgfsng.c
++++ b/src/lxc/cgroups/cgfsng.c
+@@ -49,6 +49,7 @@
+ 
+ #include "bdev.h"
+ #include "cgroup.h"
++#include "cgroup_utils.h"
+ #include "commands.h"
+ #include "log.h"
+ #include "utils.h"
+@@ -72,6 +73,7 @@ struct hierarchy {
+       char *mountpoint;
+       char *base_cgroup;
+       char *fullcgpath;
++      bool is_cgroup_v2;
+ };
+ 
+ /*
+@@ -594,7 +596,8 @@ static bool handle_cpuset_hierarchy(stru
+       }
+ 
+       clonechildrenpath = must_make_path(cgpath, "cgroup.clone_children", 
NULL);
+-      if (!file_exists(clonechildrenpath)) { /* unified hierarchy doesn't 
have clone_children */
++      /* unified hierarchy doesn't have clone_children */
++      if (!file_exists(clonechildrenpath)) {
+               free(clonechildrenpath);
+               free(cgpath);
+               return true;
+@@ -736,10 +739,14 @@ static bool is_lxcfs(const char *line)
+  */
+ static char **get_controllers(char **klist, char **nlist, char *line)
+ {
+-      // the fourth field is /sys/fs/cgroup/comma-delimited-controller-list
++      /* the fourth field is /sys/fs/cgroup/comma-delimited-controller-list */
+       int i;
+       char *p = line, *p2, *tok, *saveptr = NULL;
+       char **aret = NULL;
++      bool is_cgroup_v2;
++
++      /* handle cgroup v2 */
++      is_cgroup_v2 = is_cgroupfs_v2(line);
+ 
+       for (i = 0; i < 4; i++) {
+               p = strchr(p, ' ');
+@@ -760,6 +767,13 @@ static char **get_controllers(char **kli
+               return NULL;
+       }
+       *p2 = '\0';
++
++      /* cgroup v2 does not have separate mountpoints for controllers */
++      if (is_cgroup_v2) {
++              must_append_controller(klist, nlist, &aret, "cgroup2");
++              return aret;
++      }
++
+       for (tok = strtok_r(p, ",", &saveptr); tok;
+                       tok = strtok_r(NULL, ",", &saveptr)) {
+               must_append_controller(klist, nlist, &aret, tok);
+@@ -768,15 +782,6 @@ static char **get_controllers(char **kli
+       return aret;
+ }
+ 
+-/* return true if the fstype is cgroup */
+-static bool is_cgroupfs(char *line)
+-{
+-      char *p = strstr(line, " - ");
+-      if (!p)
+-              return false;
+-      return strncmp(p, " - cgroup ", 10) == 0;
+-}
+-
+ /* Add a controller to our list of hierarchies */
+ static void add_controller(char **clist, char *mountpoint, char *base_cgroup)
+ {
+@@ -789,6 +794,12 @@ static void add_controller(char **clist,
+       new->base_cgroup = base_cgroup;
+       new->fullcgpath = NULL;
+ 
++      /* record if this is the cgroup v2 hierarchy */
++      if (!strcmp(base_cgroup, "cgroup2"))
++              new->is_cgroup_v2 = true;
++      else
++              new->is_cgroup_v2 = false;
++
+       newentry = append_null_to_list((void ***)&hierarchies);
+       hierarchies[newentry] = new;
+ }
+@@ -870,13 +881,21 @@ static bool controller_in_clist(char *cg
+ static char *get_current_cgroup(char *basecginfo, char *controller)
+ {
+       char *p = basecginfo;
++      bool is_cgroup_v2;
++      bool is_cgroup_v2_base_cgroup;
++
++      is_cgroup_v2 = !strcmp(controller, "cgroup2");
++      while (true) {
++              is_cgroup_v2_base_cgroup = false;
++              /* cgroup v2 entry in "/proc/<pid>/cgroup": "0::/some/path" */
++              if (is_cgroup_v2 && (*p == '0'))
++                      is_cgroup_v2_base_cgroup = true;
+ 
+-      while (1) {
+               p = strchr(p, ':');
+               if (!p)
+                       return NULL;
+               p++;
+-              if (controller_in_clist(p, controller)) {
++              if (is_cgroup_v2_base_cgroup || controller_in_clist(p, 
controller)) {
+                       p = strchr(p, ':');
+                       if (!p)
+                               return NULL;
+@@ -891,20 +910,6 @@ static char *get_current_cgroup(char *ba
+       }
+ }
+ 
+-/*
+- * Given a hierarchy @mountpoint and base @path, verify that we can create
+- * directories underneath it.
+- */
+-static bool test_writeable(char *mountpoint, char *path)
+-{
+-      char *fullpath = must_make_path(mountpoint, path, NULL);
+-      int ret;
+-
+-      ret = access(fullpath, W_OK);
+-      free(fullpath);
+-      return ret == 0;
+-}
+-
+ static void must_append_string(char ***list, char *entry)
+ {
+       int newentry = append_null_to_list((void ***)list);
+@@ -933,16 +938,17 @@ static void get_existing_subsystems(char
+                       continue;
+               *p2 = '\0';
+ 
+-              /* If we have a mixture between cgroup v1 and cgroup v2
+-               * hierarchies, then /proc/self/cgroup contains entries of the
+-               * form:
++              /* If the kernel has cgroup v2 support, then /proc/self/cgroup
++               * contains an entry of the form:
+                *
+                *      0::/some/path
+                *
+-               * We need to skip those.
++               * In this case we use "cgroup2" as controller name.
+                */
+-              if ((p2 - p) == 0)
++              if ((p2 - p) == 0) {
++                      must_append_string(klist, "cgroup2");
+                       continue;
++              }
+ 
+               for (tok = strtok_r(p, ",", &saveptr); tok;
+                               tok = strtok_r(NULL, ",", &saveptr)) {
+@@ -1044,8 +1050,10 @@ static bool parse_hierarchies(void)
+       while (getline(&line, &len, f) != -1) {
+               char **controller_list = NULL;
+               char *mountpoint, *base_cgroup;
++              bool is_cgroup_v2, writeable;
+ 
+-              if (!is_lxcfs(line) && !is_cgroupfs(line))
++              is_cgroup_v2 = is_cgroupfs_v2(line);
++              if (!is_lxcfs(line) && !is_cgroupfs_v1(line) && !is_cgroup_v2)
+                       continue;
+ 
+               controller_list = get_controllers(klist, nlist, line);
+@@ -1071,9 +1079,14 @@ static bool parse_hierarchies(void)
+                       free(mountpoint);
+                       continue;
+               }
++
+               trim(base_cgroup);
+               prune_init_scope(base_cgroup);
+-              if (!test_writeable(mountpoint, base_cgroup)) {
++              if (is_cgroup_v2)
++                      writeable = test_writeable_v2(mountpoint, base_cgroup);
++              else
++                      writeable = test_writeable_v1(mountpoint, base_cgroup);
++              if (!writeable) {
+                       free_string_list(controller_list);
+                       free(mountpoint);
+                       free(base_cgroup);
+--- /dev/null
++++ b/src/lxc/cgroups/cgroup_utils.c
+@@ -0,0 +1,86 @@
++/*
++ * lxc: linux Container library
++ *
++ * Copyright © 2017 Canonical Ltd.
++ *
++ * Authors:
++ * Serge Hallyn <serge.hal...@ubuntu.com>
++ * Christian Brauner <christian.brau...@ubuntu.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
USA
++ */
++
++#include "config.h"
++
++#include <stdbool.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++
++#include "cgroup_utils.h"
++#include "utils.h"
++
++bool is_cgroupfs_v1(char *line)
++{
++      char *p = strstr(line, " - ");
++      if (!p)
++              return false;
++      return strncmp(p, " - cgroup ", 10) == 0;
++}
++
++bool is_cgroupfs_v2(char *line)
++{
++      char *p = strstr(line, " - ");
++      if (!p)
++              return false;
++
++      return strncmp(p, " - cgroup2 ", 11) == 0;
++}
++
++bool test_writeable_v1(char *mountpoint, char *path)
++{
++      char *fullpath = must_make_path(mountpoint, path, NULL);
++      int ret;
++
++      ret = access(fullpath, W_OK);
++      free(fullpath);
++      return ret == 0;
++}
++
++bool test_writeable_v2(char *mountpoint, char *path)
++{
++      /* In order to move ourselves into an appropriate sub-cgroup we need to
++       * have write access to the parent cgroup's "cgroup.procs" file, i.e. we
++       * need to have write access to the our current cgroups's "cgroup.procs"
++       * file.
++       */
++      int ret;
++      char *cgroup_path, *cgroup_procs_file;
++
++      cgroup_path = must_make_path(mountpoint, path, NULL);
++      cgroup_procs_file = must_make_path(cgroup_path, "cgroup.procs", NULL);
++
++      ret = access(cgroup_path, W_OK);
++      free(cgroup_path);
++      if (ret < 0) {
++              free(cgroup_procs_file);
++              return false;
++      }
++
++      ret = access(cgroup_procs_file, W_OK);
++      free(cgroup_procs_file);
++
++      return ret == 0;
++}
+--- /dev/null
++++ b/src/lxc/cgroups/cgroup_utils.h
+@@ -0,0 +1,48 @@
++/*
++ * lxc: linux Container library
++ *
++ * Copyright © 2017 Canonical Ltd.
++ *
++ * Authors:
++ * Serge Hallyn <serge.hal...@ubuntu.com>
++ * Christian Brauner <christian.brau...@ubuntu.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
USA
++ */
++
++#ifndef __LXC_CGROUP_UTILS_H
++#define __LXC_CGROUP_UTILS_H
++
++#include <stdbool.h>
++#include <stdio.h>
++
++/* Check if given entry from /proc/<pid>/mountinfo is a cgroupfs v1 mount. */
++extern bool is_cgroupfs_v1(char *line);
++
++/* Check if given entry from /proc/<pid>/mountinfo is a cgroupfs v2 mount. */
++extern bool is_cgroupfs_v2(char *line);
++
++/* Given a v1 hierarchy @mountpoint and base @path, verify that we can create
++ * directories underneath it.
++ */
++extern bool test_writeable_v1(char *mountpoint, char *path);
++
++/* Given a v2 hierarchy @mountpoint and base @path, verify that we can create
++ * directories underneath it and that we have write access to the cgroup's
++ * "cgroup.procs" file.
++ */
++extern bool test_writeable_v2(char *mountpoint, char *path);
++
++#endif /* __LXC_CGROUP_UTILS_H */
diff --git a/debian/patches/0013-lxc-cgroups-without-cap-sys-admin.patch 
b/debian/patches/0013-lxc-cgroups-without-cap-sys-admin.patch
new file mode 100644
index 0000000..a56b38b
--- /dev/null
+++ b/debian/patches/0013-lxc-cgroups-without-cap-sys-admin.patch
@@ -0,0 +1,157 @@
+From: Matthijs Kooijman <matth...@stdin.nl>
+Date: Sun, 14 Jan 2018 15:38:49 +0100
+Subject: lxc-start: Support containers withoug cap_sys_admin on kernel 4.6 and 
above
+
+When running systemd in a container running on kernel 4.6 or newer, it
+requires some additional cgroup filesystems to be mounted. When running
+without cap_sys_admin, systemd cannot mount these itself, and thus
+fails on startup saying "Failed to mount API filesystems, freezing.".
+
+This bug is reported as https://bugs.debian.org/875733 and
+https://github.com/lxc/lxc/issues/1737 and fixed upstream by
+https://github.com/lxc/lxc/pull/1888
+
+This backports the two commits from that PR:
+cdfe90a49f516b0f1210d181980f14a4765e10da and
+b635e92d21d2a4d71a553388f18cfa08f44bf1ba (with some trivial changes to
+make it merge).
+
+--- a/src/lxc/cgroups/cgfs.c
++++ b/src/lxc/cgroups/cgfs.c
+@@ -1418,11 +1418,12 @@ static bool cgroupfs_mount_cgroup(void *
+       struct cgfs_data *cgfs_d;
+       struct cgroup_process_info *info, *base_info;
+       int r, saved_errno = 0;
++      struct lxc_handler *handler = hdata;
+ 
+       if (cgns_supported())
+               return true;
+ 
+-      cgfs_d = hdata;
++      cgfs_d = handler->cgroup_data;
+       if (!cgfs_d)
+               return false;
+       base_info = cgfs_d->info;
+--- a/src/lxc/cgroups/cgfsng.c
++++ b/src/lxc/cgroups/cgfsng.c
+@@ -48,6 +48,7 @@
+ #include <sys/types.h>
+ 
+ #include "bdev.h"
++#include "caps.h"
+ #include "cgroup.h"
+ #include "cgroup_utils.h"
+ #include "commands.h"
+@@ -795,7 +796,7 @@ static void add_controller(char **clist,
+       new->fullcgpath = NULL;
+ 
+       /* record if this is the cgroup v2 hierarchy */
+-      if (!strcmp(base_cgroup, "cgroup2"))
++      if (clist && !strcmp(*clist, "cgroup2"))
+               new->is_cgroup_v2 = true;
+       else
+               new->is_cgroup_v2 = false;
+@@ -1535,17 +1536,49 @@ do_secondstage_mounts_if_needed(int type
+       return 0;
+ }
+ 
++static int mount_cgroup_cgns_supported(struct hierarchy *h, const char 
*controllerpath)
++{
++       int ret;
++       char *controllers = NULL;
++       char *type = "cgroup2";
++
++      if (!h->is_cgroup_v2) {
++              controllers = lxc_string_join(",", (const char 
**)h->controllers, false);
++              if (!controllers)
++                      return -ENOMEM;
++              type = "cgroup";
++      }
++
++      ret = mount("cgroup", controllerpath, type, 
MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RELATIME, controllers);
++      free(controllers);
++      if (ret < 0) {
++              SYSERROR("Failed to mount %s with cgroup filesystem type %s", 
controllerpath, type);
++              return -1;
++      }
++
++      DEBUG("Mounted %s with cgroup filesystem type %s", controllerpath, 
type);
++      return 0;
++}
++
+ static bool cgfsng_mount(void *hdata, const char *root, int type)
+ {
+-      struct cgfsng_handler_data *d = hdata;
++      int i;
+       char *tmpfspath = NULL;
+       bool retval = false;
+-      int i;
++      struct lxc_handler *handler = hdata;
++      struct cgfsng_handler_data *d = handler->cgroup_data;
++      bool has_cgns = false, has_sys_admin = true;
+ 
+       if ((type & LXC_AUTO_CGROUP_MASK) == 0)
+               return true;
+ 
+-      if (cgns_supported())
++      has_cgns = cgns_supported();
++      if (!lxc_list_empty(&handler->conf->keepcaps))
++              has_sys_admin = in_caplist(CAP_SYS_ADMIN, 
&handler->conf->keepcaps);
++      else
++              has_sys_admin = !in_caplist(CAP_SYS_ADMIN, 
&handler->conf->caps);
++
++      if (has_cgns && has_sys_admin)
+               return true;
+ 
+       tmpfspath = must_make_path(root, "/sys/fs/cgroup", NULL);
+@@ -1581,6 +1614,19 @@ static bool cgfsng_mount(void *hdata, co
+                       free(controllerpath);
+                       goto bad;
+               }
++
++              if (has_cgns && !has_sys_admin) {
++                      /* If cgroup namespaces are supported but the container
++                       * will not have CAP_SYS_ADMIN after it has started we
++                       * need to mount the cgroups manually.
++                       */
++                      r = mount_cgroup_cgns_supported(h, controllerpath);
++                      free(controllerpath);
++                      if (r < 0)
++                              goto bad;
++                      continue;
++              }
++
+               if (mount_cgroup_full(type, h, controllerpath, 
d->container_cgroup) < 0) {
+                       free(controllerpath);
+                       goto bad;
+--- a/src/lxc/cgroups/cgroup.c
++++ b/src/lxc/cgroups/cgroup.c
+@@ -160,7 +160,7 @@ bool cgroup_chown(struct lxc_handler *ha
+ bool cgroup_mount(const char *root, struct lxc_handler *handler, int type)
+ {
+       if (ops) {
+-              return ops->mount_cgroup(handler->cgroup_data, root, type);
++              return ops->mount_cgroup(handler, root, type);
+       }
+       return false;
+ }
+--- a/src/lxc/conf.c
++++ b/src/lxc/conf.c
+@@ -252,9 +252,6 @@ __thread struct lxc_conf *current_config
+ struct lxc_conf *current_config;
+ #endif
+ 
+-/* 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 instantiate_veth(struct lxc_handler *, struct lxc_netdev *);
+ static int instantiate_macvlan(struct lxc_handler *, struct lxc_netdev *);
+ static int instantiate_vlan(struct lxc_handler *, struct lxc_netdev *);
+--- a/src/lxc/conf.h
++++ b/src/lxc/conf.h
+@@ -447,4 +447,5 @@ void remount_all_slave(void);
+ extern void suggest_default_idmap(void);
+ FILE *make_anonymous_mount_file(struct lxc_list *mount);
+ struct lxc_list *sort_cgroup_settings(struct lxc_list* cgroup_settings);
++extern int in_caplist(int cap, struct lxc_list *caps);
+ #endif
diff --git a/debian/patches/series b/debian/patches/series
index 5e0bb25..8cf2130 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -2,3 +2,6 @@
 lxc-2.0-CVE-2017-5985-Ensure-target-netns-is-caller-owned.patch
 0003-lxc-debian-don-t-hardcode-valid-releases.patch
 0004-lxc-debian-don-t-write-C.-locales-to-etc-locale.gen.patch
+0011-lxc-cgroups-move-helper-functions.patch
+0012-lxc-cgroups-handle-hubrid-layouts.patch
+0013-lxc-cgroups-without-cap-sys-admin.patch
-- 
2.11.0

Reply via email to