Skip to content

Commit

Permalink
Merge pull request #1276 from Blub/limits
Browse files Browse the repository at this point in the history
Resource Limits
  • Loading branch information
Christian Brauner committed Apr 11, 2017
2 parents 359f86f + a6390f0 commit 64f26a8
Show file tree
Hide file tree
Showing 8 changed files with 428 additions and 3 deletions.
2 changes: 1 addition & 1 deletion configure.ac
Expand Up @@ -639,7 +639,7 @@ AC_CHECK_DECLS([PR_SET_NO_NEW_PRIVS], [], [], [#include <sys/prctl.h>])
AC_CHECK_DECLS([PR_GET_NO_NEW_PRIVS], [], [], [#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
Expand Down
34 changes: 34 additions & 0 deletions doc/lxc.container.conf.sgml.in
Expand Up @@ -1183,6 +1183,40 @@ proc proc proc nodev,noexec,nosuid 0 0
</variablelist>
</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>
Expand Down
5 changes: 5 additions & 0 deletions src/lxc/attach.c
Expand Up @@ -894,6 +894,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.
*/
Expand Down
134 changes: 132 additions & 2 deletions src/lxc/conf.c
Expand Up @@ -239,6 +239,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
Expand Down Expand Up @@ -371,6 +376,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;
Expand Down Expand Up @@ -2473,6 +2529,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)
{
Expand Down Expand Up @@ -2559,6 +2654,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);
Expand Down Expand Up @@ -4160,10 +4256,14 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key)
{
struct lxc_list *it,*next;
bool all = false;
const char *k = key + 11;
const char *k = NULL;

if (strcmp(key, "lxc.cgroup") == 0)
all = true;
else if (strncmp(key, "lxc.cgroup.", sizeof("lxc.cgroup.")-1) == 0)
k = key + sizeof("lxc.cgroup.")-1;
else
return -1;

lxc_list_for_each_safe(it, &c->cgroup, next) {
struct lxc_cgroup *cg = it->elem;
Expand All @@ -4178,6 +4278,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;
Expand Down Expand Up @@ -4225,11 +4350,15 @@ int lxc_clear_hooks(struct lxc_conf *c, const char *key)
{
struct lxc_list *it,*next;
bool all = false, done = false;
const char *k = key + 9;
const char *k = NULL;
int i;

if (strcmp(key, "lxc.hook") == 0)
all = true;
else if (strncmp(key, "lxc.hook.", sizeof("lxc.hook.")-1) == 0)
k = key + sizeof("lxc.hook.")-1;
else
return -1;

for (i=0; i<NUM_LXC_HOOKS; i++) {
if (all || strcmp(k, lxchook_names[i]) == 0) {
Expand Down Expand Up @@ -4320,6 +4449,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);
}

Expand Down
26 changes: 26 additions & 0 deletions src/lxc/conf.h
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -385,6 +405,9 @@ struct lxc_conf {

/* Whether PR_SET_NO_NEW_PRIVS will be set for the container. */
bool no_new_privs;

/* RLIMIT_* limits */
struct lxc_list limits;
};

#ifdef HAVE_TLS
Expand Down Expand Up @@ -428,6 +451,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,
Expand All @@ -440,6 +464,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);
Expand Down

0 comments on commit 64f26a8

Please sign in to comment.