]> git.proxmox.com Git - lxc.git/commitdiff
merge resource limits and additional fixes
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Wed, 31 May 2017 12:00:13 +0000 (14:00 +0200)
committerWolfgang Bumiller <w.bumiller@proxmox.com>
Wed, 31 May 2017 12:00:13 +0000 (14:00 +0200)
14 files changed:
debian/patches/0001-lxc.service-start-after-a-potential-syslog.service.patch
debian/patches/0002-jessie-systemd-remove-Delegate-flag-to-silence-warni.patch
debian/patches/0003-pve-run-lxcnetaddbr-when-instantiating-veths.patch
debian/patches/0004-deny-rw-mounting-of-sys-and-proc.patch
debian/patches/0005-separate-the-limiting-from-the-namespaced-cgroup-roo.patch
debian/patches/0006-start-initutils-make-cgroupns-separation-level-confi.patch
debian/patches/0007-rename-cgroup-namespace-directory-to-ns.patch
debian/patches/0008-possibility-to-run-lxc-monitord-as-a-regular-daemon.patch
debian/patches/0009-conf-implement-resource-limits.patch [new file with mode: 0644]
debian/patches/0010-doc-add-lxc.limit-to-lxc.container.conf.patch [new file with mode: 0644]
debian/patches/0011-test-resource-limit-config-entries.patch [new file with mode: 0644]
debian/patches/0012-start-fix-error-handling-when-limits-fail-to-apply.patch [new file with mode: 0644]
debian/patches/0013-start-don-t-call-lxc_map_ids-without-id-map.patch [new file with mode: 0644]
debian/patches/0014-Fix-the-bug-of-ts-stdoutfd-did-not-fill-with-paramet.patch [new file with mode: 0644]

index fb6d2ffd0db51eb8289e43bf9bf3392209797478..849217ce0f3816fef5eeb592a89ab2d19b3b8de7 100644 (file)
@@ -1,7 +1,7 @@
 From a070120ceba622b1834ad2693376256ba177f249 Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Fri, 10 Feb 2017 09:13:40 +0100
-Subject: [PATCH 1/8] lxc.service: start after a potential syslog.service
+Subject: [PATCH 01/14] lxc.service: start after a potential syslog.service
 
 Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
 ---
index af17f847ca93a6102759be3428f0887573dd3eda..36cadd5b453ea5579a95f3a0c33444ad666ad65d 100644 (file)
@@ -1,7 +1,8 @@
 From de03e2bff16699c10f1c3a80e4c84a44c0a32bc0 Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Fri, 10 Feb 2017 09:14:55 +0100
-Subject: [PATCH 2/8] jessie/systemd: remove Delegate flag to silence warnings
+Subject: [PATCH 02/14] jessie/systemd: remove Delegate flag to silence
+ warnings
 
 Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
 ---
index 4dafb93e16e73ae42dd98430da4348b1c54e80f4..2912a1c964b4255fd546a4aba8de093d05760815 100644 (file)
@@ -1,7 +1,7 @@
 From 405bcb676e3eb07e2e2efab45b15cdc8b799b15c Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Fri, 10 Feb 2017 09:15:37 +0100
-Subject: [PATCH 3/8] pve: run lxcnetaddbr when instantiating veths
+Subject: [PATCH 03/14] pve: run lxcnetaddbr when instantiating veths
 
 FIXME: Why aren't we using regular up-scripts?
 
index 656ed0c40a3d40d183839e04f41cf3ca6a261905..26543f875e21379c75452f6e4c2a1ab07387d0c6 100644 (file)
@@ -1,7 +1,7 @@
 From 05337fbce533630e978904db57601eedf498b776 Mon Sep 17 00:00:00 2001
 From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= <f.gruenbichler@proxmox.com>
 Date: Wed, 9 Nov 2016 09:14:26 +0100
-Subject: [PATCH 4/8] deny rw mounting of /sys and /proc
+Subject: [PATCH 04/14] deny rw mounting of /sys and /proc
 
 this would allow root in a privileged container to change
 the permissions of /sys on the host, which could lock out
index 76054d418fc8c5dd99ec6e82685de43b580d7721..e89a9698a3fe1e60f2a3dd992774292911ef6f6f 100644 (file)
@@ -1,7 +1,7 @@
 From 5ceb26ec765edb81aba25b9db4fc5ede0d7a0375 Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Tue, 15 Nov 2016 09:20:24 +0100
-Subject: [PATCH 5/8] separate the limiting from the namespaced cgroup root
+Subject: [PATCH 05/14] separate the limiting from the namespaced cgroup root
 
 When cgroup namespaces are enabled a privileged container
 with mixed cgroups has full write access to its own root
index 739cf9f00a8bb563416c6f8c050273e8257a2d6b..b60f8b3e5e29f1a912fca4a920a86244bf920b19 100644 (file)
@@ -1,7 +1,7 @@
 From 2b4c8a851ae299a840af3e5e0cdf128ea205b5a4 Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Wed, 16 Nov 2016 09:53:42 +0100
-Subject: [PATCH 6/8] start/initutils: make cgroupns separation level
+Subject: [PATCH 06/14] start/initutils: make cgroupns separation level
  configurable
 
 Adds a new global config variable `lxc.cgroup.separate`
index 1e6edbb9bce9aa87afca5b2d847607e8d0c01d1d..ce331d27a6f95f5a4cde7e709581b822f3c688d6 100644 (file)
@@ -1,7 +1,7 @@
 From adf5f6720c85fe7059ff98942c136846b16880eb Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Fri, 23 Dec 2016 15:57:24 +0100
-Subject: [PATCH 7/8] rename cgroup namespace directory to ns
+Subject: [PATCH 07/14] rename cgroup namespace directory to ns
 
 Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
 ---
index 708122035cfac35f9467fb5eb203b7f83f1b3b30..9181fecacbc318c72ce102a3819b7b42f2c23cb4 100644 (file)
@@ -1,7 +1,7 @@
 From eea36cafdc53b5ed2200ea0910f4222bc4e7891f Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Fri, 10 Feb 2017 10:23:36 +0100
-Subject: [PATCH 8/8] possibility to run lxc-monitord as a regular daemon
+Subject: [PATCH 08/14] possibility to run lxc-monitord as a regular daemon
 
 This includes an lxc-monitord.service, required by
 lxc@.service which is now of Type=forking.
diff --git a/debian/patches/0009-conf-implement-resource-limits.patch b/debian/patches/0009-conf-implement-resource-limits.patch
new file mode 100644 (file)
index 0000000..1ed26d1
--- /dev/null
@@ -0,0 +1,513 @@
+From 67a23f3f3fa65f1646ad20a8591b15895cada0a4 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Fri, 4 Nov 2016 10:19:07 +0100
+Subject: [PATCH 09/14] conf: implement resource limits
+
+This adds lxc.limit.<name> options consisting of one or two
+colon separated numerical values (soft and optional hard
+limit). If only one number is specified it'll be used for
+both soft and hard limit. Additionally the word 'unlimited'
+can be used instead of numbers.
+
+Eg.
+  lxc.limit.nofile = 30000:32768
+  lxc.limit.stack = unlimited
+
+Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
+---
+ configure.ac      |   2 +-
+ src/lxc/attach.c  |   5 ++
+ src/lxc/conf.c    | 122 +++++++++++++++++++++++++++++++++++++++++
+ src/lxc/conf.h    |  26 +++++++++
+ src/lxc/confile.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/lxc/start.c   |   5 ++
+ 6 files changed, 320 insertions(+), 1 deletion(-)
+
+diff --git a/configure.ac b/configure.ac
+index fa3926a9..2857d5ae 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -633,7 +633,7 @@ AM_CONDITIONAL([IS_BIONIC], [test "x$is_bionic" = "xyes"])
+ AC_CHECK_DECLS([PR_CAPBSET_DROP], [], [], [#include <sys/prctl.h>])
+ # Check for some headers
+-AC_CHECK_HEADERS([sys/signalfd.h pty.h ifaddrs.h sys/memfd.h sys/personality.h utmpx.h sys/timerfd.h])
++AC_CHECK_HEADERS([sys/signalfd.h pty.h ifaddrs.h sys/memfd.h sys/personality.h utmpx.h sys/timerfd.h sys/resource.h])
+ # lookup major()/minor()/makedev()
+ AC_HEADER_MAJOR
+diff --git a/src/lxc/attach.c b/src/lxc/attach.c
+index 119b9c14..6fdc6e8a 100644
+--- a/src/lxc/attach.c
++++ b/src/lxc/attach.c
+@@ -854,6 +854,11 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
+                               goto on_error;
+               }
++              /* Setup resource limits */
++              if (!lxc_list_empty(&init_ctx->container->lxc_conf->limits) && setup_resource_limits(&init_ctx->container->lxc_conf->limits, pid)) {
++                      goto on_error;
++              }
++
+               /* Open /proc before setns() to the containers namespace so we
+                * don't rely on any information from inside the container.
+                */
+diff --git a/src/lxc/conf.c b/src/lxc/conf.c
+index 3bedcf0f..d68ab2e2 100644
+--- a/src/lxc/conf.c
++++ b/src/lxc/conf.c
+@@ -243,6 +243,11 @@ struct caps_opt {
+       int value;
+ };
++struct limit_opt {
++      char *name;
++      int value;
++};
++
+ /*
+  * The lxc_conf of the container currently being worked on in an
+  * API call
+@@ -376,6 +381,57 @@ static struct caps_opt caps_opt[] = {
+ static struct caps_opt caps_opt[] = {};
+ #endif
++static struct limit_opt limit_opt[] = {
++#ifdef RLIMIT_AS
++      { "as",          RLIMIT_AS          },
++#endif
++#ifdef RLIMIT_CORE
++      { "core",        RLIMIT_CORE        },
++#endif
++#ifdef RLIMIT_CPU
++      { "cpu",         RLIMIT_CPU         },
++#endif
++#ifdef RLIMIT_DATA
++      { "data",        RLIMIT_DATA        },
++#endif
++#ifdef RLIMIT_FSIZE
++      { "fsize",       RLIMIT_FSIZE       },
++#endif
++#ifdef RLIMIT_LOCKS
++      { "locks",       RLIMIT_LOCKS       },
++#endif
++#ifdef RLIMIT_MEMLOCK
++      { "memlock",     RLIMIT_MEMLOCK     },
++#endif
++#ifdef RLIMIT_MSGQUEUE
++      { "msgqueue",    RLIMIT_MSGQUEUE    },
++#endif
++#ifdef RLIMIT_NICE
++      { "nice",        RLIMIT_NICE        },
++#endif
++#ifdef RLIMIT_NOFILE
++      { "nofile",      RLIMIT_NOFILE      },
++#endif
++#ifdef RLIMIT_NPROC
++      { "nproc",       RLIMIT_NPROC       },
++#endif
++#ifdef RLIMIT_RSS
++      { "rss",         RLIMIT_RSS         },
++#endif
++#ifdef RLIMIT_RTPRIO
++      { "rtprio",      RLIMIT_RTPRIO      },
++#endif
++#ifdef RLIMIT_RTTIME
++      { "rttime",      RLIMIT_RTTIME      },
++#endif
++#ifdef RLIMIT_SIGPENDING
++      { "sigpending",  RLIMIT_SIGPENDING  },
++#endif
++#ifdef RLIMIT_STACK
++      { "stack",       RLIMIT_STACK       },
++#endif
++};
++
+ static int run_buffer(char *buffer)
+ {
+       struct lxc_popen_FILE *f;
+@@ -2534,6 +2590,45 @@ static int setup_network(struct lxc_list *network)
+       return 0;
+ }
++static int parse_resource(const char *res) {
++      size_t i;
++      int resid = -1;
++
++      for (i = 0; i < sizeof(limit_opt)/sizeof(limit_opt[0]); ++i) {
++              if (strcmp(res, limit_opt[i].name) == 0)
++                      return limit_opt[i].value;
++      }
++
++      /* try to see if it's numeric, so the user may specify
++       * resources that the running kernel knows about but
++       * we don't */
++      if (lxc_safe_int(res, &resid) == 0)
++              return resid;
++      return -1;
++}
++
++int setup_resource_limits(struct lxc_list *limits, pid_t pid) {
++      struct lxc_list *it;
++      struct lxc_limit *lim;
++      int resid;
++
++      lxc_list_for_each(it, limits) {
++              lim = it->elem;
++
++              resid = parse_resource(lim->resource);
++              if (resid < 0) {
++                      ERROR("unknown resource %s", lim->resource);
++                      return -1;
++              }
++
++              if (prlimit(pid, resid, &lim->limit, NULL) != 0) {
++                      ERROR("failed to set limit %s: %s", lim->resource, strerror(errno));
++                      return -1;
++              }
++      }
++      return 0;
++}
++
+ /* try to move physical nics to the init netns */
+ void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf)
+ {
+@@ -2620,6 +2715,7 @@ struct lxc_conf *lxc_conf_init(void)
+       lxc_list_init(&new->includes);
+       lxc_list_init(&new->aliens);
+       lxc_list_init(&new->environment);
++      lxc_list_init(&new->limits);
+       for (i=0; i<NUM_LXC_HOOKS; i++)
+               lxc_list_init(&new->hooks[i]);
+       lxc_list_init(&new->groups);
+@@ -4317,6 +4413,31 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key)
+       return 0;
+ }
++int lxc_clear_limits(struct lxc_conf *c, const char *key)
++{
++      struct lxc_list *it, *next;
++      bool all = false;
++      const char *k = NULL;
++
++      if (strcmp(key, "lxc.limit") == 0)
++              all = true;
++      else if (strncmp(key, "lxc.limit.", sizeof("lxc.limit.")-1) == 0)
++              k = key + sizeof("lxc.limit.")-1;
++      else
++              return -1;
++
++      lxc_list_for_each_safe(it, &c->limits, next) {
++              struct lxc_limit *lim = it->elem;
++              if (!all && strcmp(lim->resource, k) != 0)
++                      continue;
++              lxc_list_del(it);
++              free(lim->resource);
++              free(lim);
++              free(it);
++      }
++      return 0;
++}
++
+ int lxc_clear_groups(struct lxc_conf *c)
+ {
+       struct lxc_list *it,*next;
+@@ -4462,6 +4583,7 @@ void lxc_conf_free(struct lxc_conf *conf)
+       lxc_clear_includes(conf);
+       lxc_clear_aliens(conf);
+       lxc_clear_environment(conf);
++      lxc_clear_limits(conf, "lxc.limit");
+       free(conf);
+ }
+diff --git a/src/lxc/conf.h b/src/lxc/conf.h
+index c790bf7c..7dc05288 100644
+--- a/src/lxc/conf.h
++++ b/src/lxc/conf.h
+@@ -30,6 +30,9 @@
+ #include <net/if.h>
+ #include <sys/param.h>
+ #include <sys/types.h>
++#if HAVE_SYS_RESOURCE_H
++#include <sys/resource.h>
++#endif
+ #include <stdbool.h>
+ #include "list.h"
+@@ -149,6 +152,23 @@ struct lxc_cgroup {
+       char *value;
+ };
++#if !HAVE_SYS_RESOURCE_H
++# define RLIM_INFINITY ((unsigned long)-1)
++struct rlimit {
++      unsigned long rlim_cur;
++      unsigned long rlim_max;
++};
++#endif
++/*
++ * Defines a structure to configure resource limits to set via setrlimit().
++ * @resource : the resource name in lowercase without the RLIMIT_ prefix
++ * @limit    : the limit to set
++ */
++struct lxc_limit {
++      char *resource;
++      struct rlimit limit;
++};
++
+ enum idtype {
+       ID_TYPE_UID,
+       ID_TYPE_GID
+@@ -378,6 +398,9 @@ struct lxc_conf {
+       /* indicator if the container will be destroyed on shutdown */
+       unsigned int ephemeral;
++
++      /* RLIMIT_* limits */
++      struct lxc_list limits;
+ };
+ #ifdef HAVE_TLS
+@@ -421,6 +444,7 @@ extern int lxc_clear_hooks(struct lxc_conf *c, const char *key);
+ extern int lxc_clear_idmaps(struct lxc_conf *c);
+ extern int lxc_clear_groups(struct lxc_conf *c);
+ extern int lxc_clear_environment(struct lxc_conf *c);
++extern int lxc_clear_limits(struct lxc_conf *c, const char *key);
+ extern int lxc_delete_autodev(struct lxc_handler *handler);
+ extern int do_rootfs_setup(struct lxc_conf *conf, const char *name,
+@@ -433,6 +457,8 @@ extern int do_rootfs_setup(struct lxc_conf *conf, const char *name,
+ struct cgroup_process_info;
+ extern int lxc_setup(struct lxc_handler *handler);
++extern int setup_resource_limits(struct lxc_list *limits, pid_t pid);
++
+ extern void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf);
+ extern int find_unmapped_nsuid(struct lxc_conf *conf, enum idtype idtype);
+diff --git a/src/lxc/confile.c b/src/lxc/confile.c
+index 9b22c6d3..89f8c625 100644
+--- a/src/lxc/confile.c
++++ b/src/lxc/confile.c
+@@ -112,6 +112,7 @@ static int config_init_cmd(const char *, const char *, struct lxc_conf *);
+ static int config_init_uid(const char *, const char *, struct lxc_conf *);
+ static int config_init_gid(const char *, const char *, struct lxc_conf *);
+ static int config_ephemeral(const char *, const char *, struct lxc_conf *);
++static int config_limit(const char *, const char *, struct lxc_conf *);
+ static struct lxc_config_t config[] = {
+@@ -184,6 +185,7 @@ static struct lxc_config_t config[] = {
+       { "lxc.init_uid",             config_init_uid             },
+       { "lxc.init_gid",             config_init_gid             },
+       { "lxc.ephemeral",            config_ephemeral            },
++      { "lxc.limit",                config_limit                },
+ };
+ struct signame {
+@@ -1500,6 +1502,110 @@ out:
+       return -1;
+ }
++static bool parse_limit_value(const char **value, unsigned long *res) {
++      char *endptr = NULL;
++
++      if (strncmp(*value, "unlimited", sizeof("unlimited")-1) == 0) {
++              *res = RLIM_INFINITY;
++              *value += sizeof("unlimited")-1;
++              return true;
++      }
++
++      errno = 0;
++      *res = strtoul(*value, &endptr, 10);
++      if (errno || !endptr)
++              return false;
++      *value = endptr;
++
++      return true;
++}
++
++static int config_limit(const char *key, const char *value,
++                       struct lxc_conf *lxc_conf)
++{
++      struct lxc_list *limlist = NULL;
++      struct lxc_limit *limelem = NULL;
++      struct lxc_list *iter;
++      struct rlimit limit;
++      unsigned long limit_value;
++
++      if (!value || strlen(value) == 0)
++              return lxc_clear_limits(lxc_conf, key);
++
++      if (strncmp(key, "lxc.limit.", sizeof("lxc.limit.")-1) != 0)
++              return -1;
++
++      key += sizeof("lxc.limit.")-1;
++
++      /* soft limit comes first in the value */
++      if (!parse_limit_value(&value, &limit_value))
++              return -1;
++      limit.rlim_cur = limit_value;
++
++      /* skip spaces and a colon */
++      while (isspace(*value))
++              ++value;
++      if (*value == ':')
++              ++value;
++      else if (*value) /* any other character is an error here */
++              return -1;
++      while (isspace(*value))
++              ++value;
++
++      /* optional hard limit */
++      if (*value) {
++              if (!parse_limit_value(&value, &limit_value))
++                      return -1;
++              limit.rlim_max = limit_value;
++              /* check for trailing garbage */
++              while (isspace(*value))
++                      ++value;
++              if (*value)
++                      return -1;
++      } else {
++              /* a single value sets both hard and soft limit */
++              limit.rlim_max = limit.rlim_cur;
++      }
++
++      /* find existing list element */
++      lxc_list_for_each(iter, &lxc_conf->limits) {
++              limelem = iter->elem;
++              if (!strcmp(key, limelem->resource)) {
++                      limelem->limit = limit;
++                      return 0;
++              }
++      }
++
++      /* allocate list element */
++      limlist = malloc(sizeof(*limlist));
++      if (!limlist)
++              goto out;
++      
++      limelem = malloc(sizeof(*limelem));
++      if (!limelem)
++              goto out;
++      memset(limelem, 0, sizeof(*limelem));
++
++      limelem->resource = strdup(key);
++      if (!limelem->resource)
++              goto out;
++      limelem->limit = limit;
++
++      limlist->elem = limelem;
++
++      lxc_list_add_tail(&lxc_conf->limits, limlist);
++
++      return 0;
++
++out:
++      free(limlist);
++      if (limelem) {
++              free(limelem->resource);
++              free(limelem);
++      }
++      return -1;
++}
++
+ static int config_idmap(const char *key, const char *value, struct lxc_conf *lxc_conf)
+ {
+       char *token = "lxc.id_map";
+@@ -2233,6 +2339,55 @@ static int lxc_get_cgroup_entry(struct lxc_conf *c, char *retv, int inlen,
+       return fulllen;
+ }
++/*
++ * If you ask for a specific value, i.e. lxc.limit.nofile, then just the value
++ * will be printed. If you ask for 'lxc.limit', then all limit entries will be
++ * printed, in 'lxc.limit.resource = value' format.
++ */
++static int lxc_get_limit_entry(struct lxc_conf *c, char *retv, int inlen,
++                              const char *key)
++{
++      int fulllen = 0, len;
++      int all = 0;
++      struct lxc_list *it;
++
++      if (!retv)
++              inlen = 0;
++      else
++              memset(retv, 0, inlen);
++
++      if (strcmp(key, "all") == 0)
++              all = 1;
++
++      lxc_list_for_each(it, &c->limits) {
++              char buf[LXC_NUMSTRLEN64*2+2]; /* 2 colon separated 64 bit integers or the word 'unlimited' */
++              int partlen;
++              struct lxc_limit *lim = it->elem;
++
++              if (lim->limit.rlim_cur == RLIM_INFINITY) {
++                      memcpy(buf, "unlimited", sizeof("unlimited"));
++                      partlen = sizeof("unlimited")-1;
++              } else {
++                      partlen = sprintf(buf, "%lu", lim->limit.rlim_cur);
++              }
++              if (lim->limit.rlim_cur != lim->limit.rlim_max) {
++                      if (lim->limit.rlim_max == RLIM_INFINITY) {
++                              memcpy(buf+partlen, ":unlimited", sizeof(":unlimited"));
++                      } else {
++                              sprintf(buf+partlen, ":%lu", lim->limit.rlim_max);
++                      }
++              }
++
++              if (all) {
++                      strprint(retv, inlen, "lxc.limit.%s = %s\n", lim->resource, buf);
++              } else if (strcmp(lim->resource, key) == 0) {
++                      strprint(retv, inlen, "%s", buf);
++              }
++      }
++
++      return fulllen;
++}
++
+ static int lxc_get_item_hooks(struct lxc_conf *c, char *retv, int inlen,
+                             const char *key)
+ {
+@@ -2594,6 +2749,10 @@ int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv,
+               return lxc_get_conf_int(c, retv, inlen, c->init_gid);
+       else if (strcmp(key, "lxc.ephemeral") == 0)
+               return lxc_get_conf_int(c, retv, inlen, c->ephemeral);
++      else if (strcmp(key, "lxc.limit") == 0) // all limits
++              return lxc_get_limit_entry(c, retv, inlen, "all");
++      else if (strncmp(key, "lxc.limit.", 10) == 0) // specific limit
++              return lxc_get_limit_entry(c, retv, inlen, key + 10);
+       else return -1;
+       if (!v)
+@@ -2627,6 +2786,8 @@ int lxc_clear_config_item(struct lxc_conf *c, const char *key)
+               return lxc_clear_environment(c);
+       else if (strncmp(key, "lxc.id_map", 10) == 0)
+               return lxc_clear_idmaps(c);
++      else if (strncmp(key, "lxc.limit", 9) == 0)
++              return lxc_clear_limits(c, key);
+       return -1;
+ }
+diff --git a/src/lxc/start.c b/src/lxc/start.c
+index a909c631..29edb8f7 100644
+--- a/src/lxc/start.c
++++ b/src/lxc/start.c
+@@ -1244,6 +1244,11 @@ static int lxc_spawn(struct lxc_handler *handler)
+       if (lxc_sync_barrier_child(handler, LXC_SYNC_POST_CONFIGURE))
+               goto out_delete_net;
++      if (!lxc_list_empty(&handler->conf->limits) && setup_resource_limits(&handler->conf->limits, handler->pid)) {
++              ERROR("failed to setup resource limits for '%s'", name);
++              return -1;
++      }
++
+       if (!cgroup_setup_limits(handler, true)) {
+               ERROR("Failed to setup the devices cgroup for container \"%s\".", name);
+               goto out_delete_net;
+-- 
+2.11.0
+
diff --git a/debian/patches/0010-doc-add-lxc.limit-to-lxc.container.conf.patch b/debian/patches/0010-doc-add-lxc.limit-to-lxc.container.conf.patch
new file mode 100644 (file)
index 0000000..13ab3ee
--- /dev/null
@@ -0,0 +1,58 @@
+From cd637b14e945486fb5be97b89102f679487584b5 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Fri, 4 Nov 2016 12:03:28 +0100
+Subject: [PATCH 10/14] doc: add lxc.limit to lxc.container.conf
+
+Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
+---
+ doc/lxc.container.conf.sgml.in | 34 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 34 insertions(+)
+
+diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in
+index a4ef46d6..13e0d66c 100644
+--- a/doc/lxc.container.conf.sgml.in
++++ b/doc/lxc.container.conf.sgml.in
+@@ -1189,6 +1189,40 @@ proc proc proc nodev,noexec,nosuid 0 0
+     </refsect2>
+     <refsect2>
++      <title>Resource limits</title>
++      <para>
++        The soft and hard resource limits for the container can be changed.
++        Unprivileged containers can only lower them. Resources which are not
++        explicitly specified will be inherited.
++      </para>
++      <variablelist>
++        <varlistentry>
++          <term>
++            <option>lxc.limit.[limit name]</option>
++          </term>
++          <listitem>
++            <para>
++              Specify the resource limit to be set. A limit is specified as two
++              colon separated values which are either numeric or the word
++              'unlimited'. A single value can be used as a shortcut to set both
++              soft and hard limit to the same value. The permitted names the
++              "RLIMIT_" resource names in lowercase without the "RLIMIT_"
++              prefix, eg. RLIMIT_NOFILE should be specified as "nofile". See
++              <citerefentry>
++                <refentrytitle><command>setrlimit</command></refentrytitle>
++                <manvolnum>2</manvolnum>
++              </citerefentry>.
++              If used with no value, lxc will clear the resource limit
++              specified up to this point. A resource with no explicitly
++              configured limitation will be inherited from the process starting
++              up the container.
++            </para>
++          </listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++
++    <refsect2>
+       <title>Apparmor profile</title>
+       <para>
+         If lxc was compiled and installed with apparmor support, and the host
+-- 
+2.11.0
+
diff --git a/debian/patches/0011-test-resource-limit-config-entries.patch b/debian/patches/0011-test-resource-limit-config-entries.patch
new file mode 100644 (file)
index 0000000..fe50c91
--- /dev/null
@@ -0,0 +1,88 @@
+From fd224d9bff0b269ea1524cf7546314488014c018 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Fri, 4 Nov 2016 11:45:47 +0100
+Subject: [PATCH 11/14] test: resource limit config entries
+
+Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
+---
+ src/tests/get_item.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 64 insertions(+)
+
+diff --git a/src/tests/get_item.c b/src/tests/get_item.c
+index 9750f312..93f2d965 100644
+--- a/src/tests/get_item.c
++++ b/src/tests/get_item.c
+@@ -149,6 +149,70 @@ int main(int argc, char *argv[])
+       }
+       printf("lxc.mount.entry returned %d %s\n", ret, v2);
++      ret = c->get_config_item(c, "lxc.limit", v3, 2047);
++      if (ret != 0) {
++              fprintf(stderr, "%d: get_config_item(limit) returned %d\n", __LINE__, ret);
++              goto out;
++      }
++
++      if (!c->set_config_item(c, "lxc.limit.nofile", "1234:unlimited")) {
++              fprintf(stderr, "%d: failed to set limit.nofile\n", __LINE__);
++              goto out;
++      }
++      ret = c->get_config_item(c, "lxc.limit.nofile", v2, 255);
++      if (ret < 0) {
++              fprintf(stderr, "%d: get_config_item(lxc.limit.nofile) returned %d\n", __LINE__, ret);
++              goto out;
++      }
++      if (strcmp(v2, "1234:unlimited")) {
++              fprintf(stderr, "%d: lxc.limit.nofile returned wrong value: %d %s not 14 1234:unlimited\n", __LINE__, ret, v2);
++              goto out;
++      }
++      printf("lxc.limit.nofile returned %d %s\n", ret, v2);
++
++      if (!c->set_config_item(c, "lxc.limit.stack", "unlimited")) {
++              fprintf(stderr, "%d: failed to set limit.stack\n", __LINE__);
++              goto out;
++      }
++      ret = c->get_config_item(c, "lxc.limit.stack", v2, 255);
++      if (ret < 0) {
++              fprintf(stderr, "%d: get_config_item(lxc.limit.stack) returned %d\n", __LINE__, ret);
++              goto out;
++      }
++      if (strcmp(v2, "unlimited")) {
++              fprintf(stderr, "%d: lxc.limit.stack returned wrong value: %d %s not 9 unlimited\n", __LINE__, ret, v2);
++              goto out;
++      }
++      printf("lxc.limit.stack returned %d %s\n", ret, v2);
++
++#define LIMIT_STACK "lxc.limit.stack = unlimited\n"
++#define ALL_LIMITS "lxc.limit.nofile = 1234:unlimited\n" LIMIT_STACK
++      ret = c->get_config_item(c, "lxc.limit", v3, 2047);
++      if (ret != sizeof(ALL_LIMITS)-1) {
++              fprintf(stderr, "%d: get_config_item(limit) returned %d\n", __LINE__, ret);
++              goto out;
++      }
++      if (strcmp(v3, ALL_LIMITS)) {
++              fprintf(stderr, "%d: lxc.limit returned wrong value: %d %s not %d %s\n", __LINE__, ret, v3, (int)sizeof(ALL_LIMITS)-1, ALL_LIMITS);
++              goto out;
++      }
++      printf("lxc.limit returned %d %s\n", ret, v3);
++
++      if (!c->clear_config_item(c, "lxc.limit.nofile")) {
++              fprintf(stderr, "%d: failed clearing limit.nofile\n", __LINE__);
++              goto out;
++      }
++      ret = c->get_config_item(c, "lxc.limit", v3, 2047);
++      if (ret != sizeof(LIMIT_STACK)-1) {
++              fprintf(stderr, "%d: get_config_item(limit) returned %d\n", __LINE__, ret);
++              goto out;
++      }
++      if (strcmp(v3, LIMIT_STACK)) {
++              fprintf(stderr, "%d: lxc.limit returned wrong value: %d %s not %d %s\n", __LINE__, ret, v3, (int)sizeof(LIMIT_STACK)-1, LIMIT_STACK);
++              goto out;
++      }
++      printf("lxc.limit returned %d %s\n", ret, v3);
++
+       if (!c->set_config_item(c, "lxc.aa_profile", "unconfined")) {
+               fprintf(stderr, "%d: failed to set aa_profile\n", __LINE__);
+               goto out;
+-- 
+2.11.0
+
diff --git a/debian/patches/0012-start-fix-error-handling-when-limits-fail-to-apply.patch b/debian/patches/0012-start-fix-error-handling-when-limits-fail-to-apply.patch
new file mode 100644 (file)
index 0000000..c4fc534
--- /dev/null
@@ -0,0 +1,29 @@
+From 4b5238d5a7422f71abc4dbe8a7f01ab54dc9599b Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Tue, 11 Apr 2017 16:42:01 +0200
+Subject: [PATCH 12/14] start: fix error handling when limits fail to apply
+
+(The code was moved here from the child side of the startup
+without adapting the error case.)
+
+Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
+---
+ src/lxc/start.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/lxc/start.c b/src/lxc/start.c
+index 29edb8f7..8c2d2182 100644
+--- a/src/lxc/start.c
++++ b/src/lxc/start.c
+@@ -1246,7 +1246,7 @@ static int lxc_spawn(struct lxc_handler *handler)
+       if (!lxc_list_empty(&handler->conf->limits) && setup_resource_limits(&handler->conf->limits, handler->pid)) {
+               ERROR("failed to setup resource limits for '%s'", name);
+-              return -1;
++              goto out_delete_net;
+       }
+       if (!cgroup_setup_limits(handler, true)) {
+-- 
+2.11.0
+
diff --git a/debian/patches/0013-start-don-t-call-lxc_map_ids-without-id-map.patch b/debian/patches/0013-start-don-t-call-lxc_map_ids-without-id-map.patch
new file mode 100644 (file)
index 0000000..e80544c
--- /dev/null
@@ -0,0 +1,70 @@
+From c1cf0e26f6dee988d73b4da760dc3f52f9c9a83b Mon Sep 17 00:00:00 2001
+From: Christian Brauner <christian.brauner@ubuntu.com>
+Date: Sat, 13 May 2017 17:16:25 +0200
+Subject: [PATCH 13/14] start: don't call lxc_map_ids() without id map
+
+So far, we somehow always called lxc_map_ids(), even when no id map was
+configured. Let's not do this.
+
+Closes #1555.
+
+Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
+
+Conflicts:
+    namespace spearation patches
+Squashed:
+    0ee3505984e (start: pin rootfs when privileged)
+
+Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
+---
+ src/lxc/start.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/src/lxc/start.c b/src/lxc/start.c
+index 8c2d2182..c8947f18 100644
+--- a/src/lxc/start.c
++++ b/src/lxc/start.c
+@@ -1061,9 +1061,12 @@ static int lxc_spawn(struct lxc_handler *handler)
+       int saved_ns_fd[LXC_NS_MAX];
+       int preserve_mask = 0, i, flags;
+       int netpipepair[2], nveths;
+-      bool privileged = lxc_list_empty(&handler->conf->id_map);
++      bool wants_to_map_ids;
++      struct lxc_list *id_map;
+       netpipe = -1;
++      id_map = &handler->conf->id_map;
++      wants_to_map_ids = !lxc_list_empty(id_map);
+       for (i = 0; i < LXC_NS_MAX; i++)
+               if (handler->conf->inherit_ns_fd[i] != -1)
+@@ -1125,7 +1128,7 @@ static int lxc_spawn(struct lxc_handler *handler)
+        * it readonly.
+        * If the container is unprivileged then skip rootfs pinning.
+        */
+-      if (privileged) {
++      if (!wants_to_map_ids) {
+               handler->pinfd = pin_rootfs(handler->conf->rootfs.path);
+               if (handler->pinfd == -1)
+                       INFO("Failed to pin the rootfs for container \"%s\".", handler->name);
+@@ -1179,7 +1182,7 @@ static int lxc_spawn(struct lxc_handler *handler)
+        * mapped to something else on the host.) later to become a valid uid
+        * again.
+        */
+-      if (lxc_map_ids(&handler->conf->id_map, handler->pid)) {
++      if (wants_to_map_ids && lxc_map_ids(id_map, handler->pid)) {
+               ERROR("Failed to set up id mapping.");
+               goto out_delete_net;
+       }
+@@ -1256,7 +1259,7 @@ static int lxc_spawn(struct lxc_handler *handler)
+       if (cgns_supported()) {
+               const char *tmp = lxc_global_config_value("lxc.cgroup.protect_limits");
+-              if (!strcmp(tmp, "both") || !strcmp(tmp, privileged ? "privileged" : "unprivileged")) {
++              if (!strcmp(tmp, "both") || !strcmp(tmp, wants_to_map_ids ? "unprivileged" : "privileged")) {
+                       if (!cgroup_create(handler, true)) {
+                               ERROR("failed to create inner cgroup separation layer");
+                               goto out_delete_net;
+-- 
+2.11.0
+
diff --git a/debian/patches/0014-Fix-the-bug-of-ts-stdoutfd-did-not-fill-with-paramet.patch b/debian/patches/0014-Fix-the-bug-of-ts-stdoutfd-did-not-fill-with-paramet.patch
new file mode 100644 (file)
index 0000000..d76e7a8
--- /dev/null
@@ -0,0 +1,29 @@
+From c29c4928c88cf5bf88115b787f04cccc1664bfd1 Mon Sep 17 00:00:00 2001
+From: Li Feng <lifeng68@huawei.com>
+Date: Fri, 19 May 2017 22:40:07 +0800
+Subject: [PATCH 14/14] Fix the bug of 'ts->stdoutfd' did not fill with
+ parameters 'stdoutfd'
+
+Signed-off-by: Li Feng <lifeng68@huawei.com>
+---
+ src/lxc/console.c | 1 +
+ 1 file changed, 1 insertion(+)
+ mode change 100644 => 100755 src/lxc/console.c
+
+diff --git a/src/lxc/console.c b/src/lxc/console.c
+old mode 100644
+new mode 100755
+index 3baaed49..ad88a0ba
+--- a/src/lxc/console.c
++++ b/src/lxc/console.c
+@@ -697,6 +697,7 @@ int lxc_console(struct lxc_container *c, int ttynum,
+       ts->escape = escape;
+       ts->winch_proxy = c->name;
+       ts->winch_proxy_lxcpath = c->config_path;
++      ts->stdoutfd = stdoutfd;
+       lxc_console_winsz(stdinfd, masterfd);
+       lxc_cmd_console_winch(ts->winch_proxy, ts->winch_proxy_lxcpath);
+-- 
+2.11.0
+