From ccdf81b55817ecf69850aae62ce285b63f24d456 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 31 May 2017 14:00:13 +0200 Subject: [PATCH] merge resource limits and additional fixes --- ...art-after-a-potential-syslog.service.patch | 2 +- ...emove-Delegate-flag-to-silence-warni.patch | 3 +- ...lxcnetaddbr-when-instantiating-veths.patch | 2 +- ...004-deny-rw-mounting-of-sys-and-proc.patch | 2 +- ...iting-from-the-namespaced-cgroup-roo.patch | 2 +- ...make-cgroupns-separation-level-confi.patch | 2 +- ...ame-cgroup-namespace-directory-to-ns.patch | 2 +- ...run-lxc-monitord-as-a-regular-daemon.patch | 2 +- .../0009-conf-implement-resource-limits.patch | 513 ++++++++++++++++++ ...-add-lxc.limit-to-lxc.container.conf.patch | 58 ++ ...1-test-resource-limit-config-entries.patch | 88 +++ ...r-handling-when-limits-fail-to-apply.patch | 29 + ...on-t-call-lxc_map_ids-without-id-map.patch | 70 +++ ...s-stdoutfd-did-not-fill-with-paramet.patch | 29 + 14 files changed, 796 insertions(+), 8 deletions(-) create mode 100644 debian/patches/0009-conf-implement-resource-limits.patch create mode 100644 debian/patches/0010-doc-add-lxc.limit-to-lxc.container.conf.patch create mode 100644 debian/patches/0011-test-resource-limit-config-entries.patch create mode 100644 debian/patches/0012-start-fix-error-handling-when-limits-fail-to-apply.patch create mode 100644 debian/patches/0013-start-don-t-call-lxc_map_ids-without-id-map.patch create mode 100644 debian/patches/0014-Fix-the-bug-of-ts-stdoutfd-did-not-fill-with-paramet.patch diff --git a/debian/patches/0001-lxc.service-start-after-a-potential-syslog.service.patch b/debian/patches/0001-lxc.service-start-after-a-potential-syslog.service.patch index fb6d2ff..849217c 100644 --- a/debian/patches/0001-lxc.service-start-after-a-potential-syslog.service.patch +++ b/debian/patches/0001-lxc.service-start-after-a-potential-syslog.service.patch @@ -1,7 +1,7 @@ From a070120ceba622b1834ad2693376256ba177f249 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller 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 --- diff --git a/debian/patches/0002-jessie-systemd-remove-Delegate-flag-to-silence-warni.patch b/debian/patches/0002-jessie-systemd-remove-Delegate-flag-to-silence-warni.patch index af17f84..36cadd5 100644 --- a/debian/patches/0002-jessie-systemd-remove-Delegate-flag-to-silence-warni.patch +++ b/debian/patches/0002-jessie-systemd-remove-Delegate-flag-to-silence-warni.patch @@ -1,7 +1,8 @@ From de03e2bff16699c10f1c3a80e4c84a44c0a32bc0 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller 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 --- diff --git a/debian/patches/0003-pve-run-lxcnetaddbr-when-instantiating-veths.patch b/debian/patches/0003-pve-run-lxcnetaddbr-when-instantiating-veths.patch index 4dafb93..2912a1c 100644 --- a/debian/patches/0003-pve-run-lxcnetaddbr-when-instantiating-veths.patch +++ b/debian/patches/0003-pve-run-lxcnetaddbr-when-instantiating-veths.patch @@ -1,7 +1,7 @@ From 405bcb676e3eb07e2e2efab45b15cdc8b799b15c Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller 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? diff --git a/debian/patches/0004-deny-rw-mounting-of-sys-and-proc.patch b/debian/patches/0004-deny-rw-mounting-of-sys-and-proc.patch index 656ed0c..26543f8 100644 --- a/debian/patches/0004-deny-rw-mounting-of-sys-and-proc.patch +++ b/debian/patches/0004-deny-rw-mounting-of-sys-and-proc.patch @@ -1,7 +1,7 @@ From 05337fbce533630e978904db57601eedf498b776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= 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 diff --git a/debian/patches/0005-separate-the-limiting-from-the-namespaced-cgroup-roo.patch b/debian/patches/0005-separate-the-limiting-from-the-namespaced-cgroup-roo.patch index 76054d4..e89a969 100644 --- a/debian/patches/0005-separate-the-limiting-from-the-namespaced-cgroup-roo.patch +++ b/debian/patches/0005-separate-the-limiting-from-the-namespaced-cgroup-roo.patch @@ -1,7 +1,7 @@ From 5ceb26ec765edb81aba25b9db4fc5ede0d7a0375 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller 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 diff --git a/debian/patches/0006-start-initutils-make-cgroupns-separation-level-confi.patch b/debian/patches/0006-start-initutils-make-cgroupns-separation-level-confi.patch index 739cf9f..b60f8b3 100644 --- a/debian/patches/0006-start-initutils-make-cgroupns-separation-level-confi.patch +++ b/debian/patches/0006-start-initutils-make-cgroupns-separation-level-confi.patch @@ -1,7 +1,7 @@ From 2b4c8a851ae299a840af3e5e0cdf128ea205b5a4 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller 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` diff --git a/debian/patches/0007-rename-cgroup-namespace-directory-to-ns.patch b/debian/patches/0007-rename-cgroup-namespace-directory-to-ns.patch index 1e6edbb..ce331d2 100644 --- a/debian/patches/0007-rename-cgroup-namespace-directory-to-ns.patch +++ b/debian/patches/0007-rename-cgroup-namespace-directory-to-ns.patch @@ -1,7 +1,7 @@ From adf5f6720c85fe7059ff98942c136846b16880eb Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller 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 --- diff --git a/debian/patches/0008-possibility-to-run-lxc-monitord-as-a-regular-daemon.patch b/debian/patches/0008-possibility-to-run-lxc-monitord-as-a-regular-daemon.patch index 7081220..9181fec 100644 --- a/debian/patches/0008-possibility-to-run-lxc-monitord-as-a-regular-daemon.patch +++ b/debian/patches/0008-possibility-to-run-lxc-monitord-as-a-regular-daemon.patch @@ -1,7 +1,7 @@ From eea36cafdc53b5ed2200ea0910f4222bc4e7891f Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller 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 index 0000000..1ed26d1 --- /dev/null +++ b/debian/patches/0009-conf-implement-resource-limits.patch @@ -0,0 +1,513 @@ +From 67a23f3f3fa65f1646ad20a8591b15895cada0a4 Mon Sep 17 00:00:00 2001 +From: Wolfgang Bumiller +Date: Fri, 4 Nov 2016 10:19:07 +0100 +Subject: [PATCH 09/14] conf: implement resource limits + +This adds lxc.limit. 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 +--- + 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 ]) + + # 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; ihooks[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 + #include + #include ++#if HAVE_SYS_RESOURCE_H ++#include ++#endif + #include + + #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 index 0000000..13ab3ee --- /dev/null +++ b/debian/patches/0010-doc-add-lxc.limit-to-lxc.container.conf.patch @@ -0,0 +1,58 @@ +From cd637b14e945486fb5be97b89102f679487584b5 Mon Sep 17 00:00:00 2001 +From: Wolfgang Bumiller +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 +--- + 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 + + + ++ Resource limits ++ ++ 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. ++ ++ ++ ++ ++ ++ ++ ++ ++ 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 ++ ++ setrlimit ++ 2 ++ . ++ 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. ++ ++ ++ ++ ++ ++ ++ + Apparmor profile + + 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 index 0000000..fe50c91 --- /dev/null +++ b/debian/patches/0011-test-resource-limit-config-entries.patch @@ -0,0 +1,88 @@ +From fd224d9bff0b269ea1524cf7546314488014c018 Mon Sep 17 00:00:00 2001 +From: Wolfgang Bumiller +Date: Fri, 4 Nov 2016 11:45:47 +0100 +Subject: [PATCH 11/14] test: resource limit config entries + +Signed-off-by: Wolfgang Bumiller +--- + 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 index 0000000..c4fc534 --- /dev/null +++ b/debian/patches/0012-start-fix-error-handling-when-limits-fail-to-apply.patch @@ -0,0 +1,29 @@ +From 4b5238d5a7422f71abc4dbe8a7f01ab54dc9599b Mon Sep 17 00:00:00 2001 +From: Wolfgang Bumiller +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 +--- + 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 index 0000000..e80544c --- /dev/null +++ b/debian/patches/0013-start-don-t-call-lxc_map_ids-without-id-map.patch @@ -0,0 +1,70 @@ +From c1cf0e26f6dee988d73b4da760dc3f52f9c9a83b Mon Sep 17 00:00:00 2001 +From: Christian Brauner +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 + +Conflicts: + namespace spearation patches +Squashed: + 0ee3505984e (start: pin rootfs when privileged) + +Signed-off-by: Wolfgang Bumiller +--- + 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 index 0000000..d76e7a8 --- /dev/null +++ b/debian/patches/0014-Fix-the-bug-of-ts-stdoutfd-did-not-fill-with-paramet.patch @@ -0,0 +1,29 @@ +From c29c4928c88cf5bf88115b787f04cccc1664bfd1 Mon Sep 17 00:00:00 2001 +From: Li Feng +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 +--- + 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 +