diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in index 4c72a4326..7b599e54d 100644 --- a/doc/lxc.container.conf.sgml.in +++ b/doc/lxc.container.conf.sgml.in @@ -246,6 +246,39 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Init ID + + Sets the UID/GID to use for the init system, and subsequent command, executed by lxc-execute. + + These options are only used when lxc-execute is started in a private user namespace. + + Defaults to: UID(0), GID(0) + + + + + + + + + UID to use within a private user namesapce for init. + + + + + + + + + + GID to use within a private user namesapce for init. + + + + + + Network diff --git a/src/lxc/arguments.h b/src/lxc/arguments.h index 30aa06a21..bf03dc5db 100644 --- a/src/lxc/arguments.h +++ b/src/lxc/arguments.h @@ -88,6 +88,10 @@ struct lxc_arguments { char *lvname, *vgname, *thinpool; char *zfsroot, *lowerdir, *dir; + /* lxc-execute */ + uid_t uid; + gid_t gid; + /* auto-start */ int all; int ignore_auto; diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 3519f57ab..c1236b4f1 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -2537,6 +2537,11 @@ struct lxc_conf *lxc_conf_init(void) for (i = 0; i < LXC_NS_MAX; i++) new->inherit_ns_fd[i] = -1; + /* if running in a new user namespace, init and COMMAND + * default to running as UID/GID 0 when using lxc-execute */ + new->init_uid = 0; + new->init_gid = 0; + return new; } diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 2d67f0da6..dc5328a3f 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -365,6 +365,11 @@ struct lxc_conf { /* init command */ char *init_cmd; + + /* if running in a new user namespace, the UID/GID that init and COMMAND + * should run under when using lxc-execute */ + uid_t init_uid; + gid_t init_gid; }; #ifdef HAVE_TLS diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 5599f53c7..ca3b8d85a 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -106,6 +106,8 @@ static int config_start(const char *, const char *, struct lxc_conf *); static int config_group(const char *, const char *, struct lxc_conf *); static int config_environment(const char *, const char *, struct lxc_conf *); 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 struct lxc_config_t config[] = { @@ -172,6 +174,8 @@ static struct lxc_config_t config[] = { { "lxc.group", config_group }, { "lxc.environment", config_environment }, { "lxc.init_cmd", config_init_cmd }, + { "lxc.init_uid", config_init_uid }, + { "lxc.init_gid", config_init_gid }, }; struct signame { @@ -1038,11 +1042,25 @@ static int config_init_cmd(const char *key, const char *value, return config_path_item(&lxc_conf->init_cmd, value); } +static int config_init_uid(const char *key, const char *value, + struct lxc_conf *lxc_conf) +{ + lxc_conf->init_uid = atoi(value); + return 0; +} + +static int config_init_gid(const char *key, const char *value, + struct lxc_conf *lxc_conf) +{ + lxc_conf->init_gid = atoi(value); + return 0; +} + static int config_hook(const char *key, const char *value, struct lxc_conf *lxc_conf) { char *copy; - + if (!value || strlen(value) == 0) return lxc_clear_hooks(lxc_conf, key); @@ -2468,6 +2486,10 @@ int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv, return lxc_get_item_environment(c, retv, inlen); else if (strcmp(key, "lxc.init_cmd") == 0) v = c->init_cmd; + else if (strcmp(key, "lxc.init_uid") == 0) + return lxc_get_conf_int(c, retv, inlen, c->init_uid); + else if (strcmp(key, "lxc.init_gid") == 0) + return lxc_get_conf_int(c, retv, inlen, c->init_gid); else return -1; if (!v) diff --git a/src/lxc/lxc_execute.c b/src/lxc/lxc_execute.c index d2c1248cd..50d481f0e 100644 --- a/src/lxc/lxc_execute.c +++ b/src/lxc/lxc_execute.c @@ -59,7 +59,9 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg) { switch (c) { case 'f': args->rcfile = arg; break; - case 's': return lxc_config_define_add(&defines, arg); + case 's': return lxc_config_define_add(&defines, arg); break; + case 'u': args->uid = atoi(arg); break; + case 'g': args->gid = atoi(arg); } return 0; } @@ -67,6 +69,8 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg) static const struct option my_longopts[] = { {"rcfile", required_argument, 0, 'f'}, {"define", required_argument, 0, 's'}, + {"uid", required_argument, 0, 'u'}, + {"gid", required_argument, 0, 'g'}, LXC_COMMON_OPTIONS }; @@ -81,7 +85,9 @@ and execs COMMAND into this container.\n\ Options :\n\ -n, --name=NAME NAME of the container\n\ -f, --rcfile=FILE Load configuration file FILE\n\ - -s, --define KEY=VAL Assign VAL to configuration variable KEY\n", + -s, --define KEY=VAL Assign VAL to configuration variable KEY\n\ + -u, --uid=UID Execute COMMAND with UID inside the container\n\ + -g, --gid=GID Execute COMMAND with GID inside the container\n", .options = my_longopts, .parser = my_parser, .checker = my_checker, @@ -139,6 +145,12 @@ int main(int argc, char *argv[]) if (lxc_config_define_load(&defines, conf)) return 1; + if (my_args.uid) + conf->init_uid = my_args.uid; + + if (my_args.gid) + conf->init_gid = my_args.gid; + ret = lxc_execute(my_args.name, my_args.argv, my_args.quiet, conf, my_args.lxcpath[0], false); lxc_conf_free(conf); diff --git a/src/lxc/start.c b/src/lxc/start.c index ad8867eb5..b85da2df1 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -664,15 +664,25 @@ static int do_start(void *data) /* * if we are in a new user namespace, become root there to have - * privilege over our namespace + * privilege over our namespace. When using lxc-execute we default to root, + * but this can be overriden using the lxc.init_uid and lxc.init_gid + * configuration options. */ if (!lxc_list_empty(&handler->conf->id_map)) { - NOTICE("switching to gid/uid 0 in new user namespace"); - if (setgid(0)) { + gid_t new_gid = 0; + if (handler->conf->is_execute && handler->conf->init_gid) + new_gid = handler->conf->init_gid; + + uid_t new_uid = 0; + if (handler->conf->is_execute && handler->conf->init_uid) + new_uid = handler->conf->init_uid; + + NOTICE("switching to gid/uid %d/%d in new user namespace", new_gid, new_uid); + if (setgid(new_gid)) { SYSERROR("setgid"); goto out_warn_father; } - if (setuid(0)) { + if (setuid(new_uid)) { SYSERROR("setuid"); goto out_warn_father; } diff --git a/src/tests/get_item.c b/src/tests/get_item.c index 943583cdd..270ced908 100644 --- a/src/tests/get_item.c +++ b/src/tests/get_item.c @@ -88,6 +88,32 @@ int main(int argc, char *argv[]) } printf("lxc.arch returned %d %s\n", ret, v2); + if (!c->set_config_item(c, "lxc.init_uid", "100")) { + fprintf(stderr, "%d: failed to set init_uid\n", __LINE__); + ret = 1; + goto out; + } + ret = c->get_config_item(c, "lxc.init_uid", v2, 255); + if (ret < 0) { + fprintf(stderr, "%d: get_config_item(lxc.init_uid) returned %d\n", __LINE__, ret); + ret = 1; + goto out; + } + printf("lxc.init_uid returned %d %s\n", ret, v2); + + if (!c->set_config_item(c, "lxc.init_gid", "100")) { + fprintf(stderr, "%d: failed to set init_gid\n", __LINE__); + ret = 1; + goto out; + } + ret = c->get_config_item(c, "lxc.init_gid", v2, 255); + if (ret < 0) { + fprintf(stderr, "%d: get_config_item(lxc.init_gid) returned %d\n", __LINE__, ret); + ret = 1; + goto out; + } + printf("lxc.init_gid returned %d %s\n", ret, v2); + #define HNAME "hostname1" // demonstrate proper usage: char *alloced;