From d1bb169f38282acf9ae38ef000c2f5c658b4f325 Mon Sep 17 00:00:00 2001 From: LiFeng Date: Fri, 11 Jan 2019 01:51:25 -0500 Subject: [PATCH 003/138] confile: add lxc.isulad.populate.device interface Signed-off-by: LiFeng --- src/lxc/conf.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++--- src/lxc/conf.h | 28 +++++++++++- src/lxc/confile.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 269 insertions(+), 8 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index f20d629..20b7aba 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -2745,6 +2745,10 @@ struct lxc_conf *lxc_conf_init(void) memset(&new->cgroup_meta, 0, sizeof(struct lxc_cgroup)); memset(&new->ns_share, 0, sizeof(char *) * LXC_NS_MAX); + /* isulad add begin */ + lxc_list_init(&new->populate_devs); + /* isulad add end */ + return new; } @@ -3487,6 +3491,85 @@ static bool execveat_supported(void) return true; } +/* isulad: setup devices which will be populated in the container.*/ +static int setup_populate_devs(const struct lxc_rootfs *rootfs, struct lxc_list *devs) +{ + int ret; + char *pathdirname; + char path[MAXPATHLEN]; + mode_t cmask; + mode_t file_mode = 0; + struct lxc_populate_devs *dev_elem; + struct lxc_list *it; + + INFO("Populating devices into container"); + cmask = umask(S_IXUSR | S_IXGRP | S_IXOTH); + lxc_list_for_each(it, devs) { + dev_elem = it->elem; + + ret = snprintf(path, MAXPATHLEN, "%s/%s", rootfs->path ? rootfs->mount : "", dev_elem->name); + if (ret < 0 || ret >= MAXPATHLEN) + return -1; + + /* create any missing directories */ + pathdirname = strdup(path); + pathdirname = dirname(pathdirname); + ret = mkdir_p(pathdirname, 0750); + free(pathdirname); + if (ret < 0) { + WARN("Failed to create target directory"); + return -1; + } + + if (!strcmp(dev_elem->type, "c")) { + file_mode = dev_elem->file_mode | S_IFCHR; + } else if (!strcmp(dev_elem->type, "b")) { + file_mode = dev_elem->file_mode | S_IFBLK; + } else { + ERROR("Failed to parse devices type '%s'", dev_elem->type); + return -1; + } + + DEBUG("Try to mknod '%s':'%d':'%d':'%d'\n", path, + file_mode, dev_elem->maj, dev_elem->min); + + ret = mknod(path, file_mode, makedev(dev_elem->maj, dev_elem->min)); + if (ret && errno != EEXIST) { + SYSERROR("Failed to mknod '%s':'%d':'%d':'%d'", dev_elem->name, + file_mode, dev_elem->maj, dev_elem->min); + + char hostpath[MAXPATHLEN]; + FILE *pathfile; + + // Unprivileged containers cannot create devices, so + // try to bind mount the device from the host + ret = snprintf(hostpath, MAXPATHLEN, "/dev/%s", dev_elem->name); + if (ret < 0 || ret >= MAXPATHLEN) + return -1; + pathfile = fopen(path, "wb"); + if (!pathfile) { + SYSERROR("Failed to create device mount target '%s'", path); + return -1; + } + fclose(pathfile); + if (safe_mount(hostpath, path, 0, MS_BIND, NULL, + rootfs->path ? rootfs->mount : NULL) != 0) { + SYSERROR("Failed bind mounting device %s from host into container", + dev_elem->name); + return -1; + } + } + if (chown(path, dev_elem->uid, dev_elem->gid) < 0) { + ERROR("Error chowning %s", path); + return -1; + } + } + umask(cmask); + + INFO("Populated devices into container /dev"); + return 0; +} + int lxc_setup(struct lxc_handler *handler) { int ret; @@ -3584,6 +3667,16 @@ int lxc_setup(struct lxc_handler *handler) return -1; } + /*isulad: move mount entrues here, before we do lxc_fill_autodev and populate devices */ + if (!lxc_list_empty(&lxc_conf->mount_list)) { + ret = setup_mount_entries(lxc_conf, &lxc_conf->rootfs, + &lxc_conf->mount_list, name, lxcpath); + if (ret < 0) { + ERROR("Failed to setup mount entries"); + return -1; + } + } + ret = run_lxc_hooks(name, "mount", lxc_conf, NULL); if (ret < 0) { ERROR("Failed to run mount hooks"); @@ -3604,12 +3697,11 @@ int lxc_setup(struct lxc_handler *handler) } } - if (!lxc_list_empty(&lxc_conf->mount_list)) { - ret = setup_mount_entries(lxc_conf, &lxc_conf->rootfs, - &lxc_conf->mount_list, name, lxcpath); - if (ret < 0) { - ERROR("Failed to setup mount entries"); - return -1; + /* isulad: setup devices which will be populated in the container. */ + if (!lxc_list_empty(&lxc_conf->populate_devs)) { + if (setup_populate_devs(&lxc_conf->rootfs, &lxc_conf->populate_devs)) { + ERROR("Failed to setup devices in the container"); + return -1;; } } @@ -4026,6 +4118,22 @@ int lxc_clear_init_args(struct lxc_conf *lxc_conf) return 0; } +/*isulad: clear populate devices*/ +int lxc_clear_populate_devices(struct lxc_conf *c) +{ + struct lxc_list *it,*next; + + lxc_list_for_each_safe(it, &c->populate_devs, next) { + struct lxc_populate_devs *dev_elem = it->elem; + lxc_list_del(it); + free(dev_elem->name); + free(dev_elem->type); + free(dev_elem); + free(it); + } + return 0; +} + void lxc_conf_free(struct lxc_conf *conf) { if (!conf) @@ -4069,9 +4177,12 @@ void lxc_conf_free(struct lxc_conf *conf) lxc_clear_limits(conf, "lxc.prlimit"); lxc_clear_sysctls(conf, "lxc.sysctl"); lxc_clear_procs(conf, "lxc.proc"); - lxc_clear_init_args(conf); free(conf->cgroup_meta.dir); free(conf->cgroup_meta.controllers); + /* isulad add begin */ + lxc_clear_init_args(conf); + lxc_clear_populate_devices(conf); + /* isulad add end */ free(conf); } diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 95c3027..cced868 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -171,6 +171,26 @@ struct lxc_rootfs { }; /* + * iSulad: Defines a structure to store the devices which will + * be attached in container + * @name : the target device name in container + * @type : the type of target device "c" or "b" + * @mode : file mode for the device + * @maj : major number for the device + * @min : minor number for the device + */ +struct lxc_populate_devs { + char *name; + char *type; + mode_t file_mode; + int maj; + int min; + uid_t uid; + gid_t gid; +}; + + +/* * Automatic mounts for LXC to perform inside the container */ enum { @@ -377,9 +397,13 @@ struct lxc_conf { /* procs */ struct lxc_list procs; - /* isulad add: init args used to repalce init_cmd*/ + /* isulad add begin */ + /* init args used to repalce init_cmd*/ char **init_argv; size_t init_argc; + /* populate devices*/ + struct lxc_list populate_devs; + /* isulad add end */ }; extern int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf, @@ -448,6 +472,8 @@ extern int lxc_clear_procs(struct lxc_conf *c, const char *key); /* isulad add begin */ int lxc_clear_init_args(struct lxc_conf *lxc_conf); +int lxc_clear_populate_devices(struct lxc_conf *c); + /* isulad add end */ #endif /* __LXC_CONF_H */ diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 7297b35..e3212d3 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -152,6 +152,7 @@ lxc_config_define(sysctl); lxc_config_define(proc); /*isulad add begin*/ lxc_config_define(init_args); +lxc_config_define(populate_device); /*isulad add end*/ @@ -241,6 +242,7 @@ static struct lxc_config_t config_jump_table[] = { /*isulad add begin*/ { "lxc.isulad.init.args", set_config_init_args, get_config_init_args, clr_config_init_args, }, + { "lxc.isulad.populate.device", set_config_populate_device, get_config_populate_device, clr_config_populate_device, }, /*isulad add end*/ }; @@ -2219,6 +2221,93 @@ static int set_config_init_args(const char *key, const char *value, return 0; } +/* isulad: set config for init args */ +static int set_config_populate_device(const char *key, const char *value, + struct lxc_conf *lxc_conf, void *data) +{ + int ret = 0, major = 0, minor = 0; + uid_t uid = (uid_t)-1; + gid_t gid = (gid_t)-1; + char name[PATH_MAX] = {0}; + char type[3] = {0}; + char *replace_value = NULL; + mode_t filemode = 0; + struct lxc_list *iter; + struct lxc_list *dev_list = NULL; + struct lxc_populate_devs *dev_elem = NULL; + + if (lxc_config_value_empty(value)) + return lxc_clear_populate_devices(lxc_conf); + + /* lxc.populate.device = PATH_IN_CONTAINER:DEVICETYPE:MAJOR:MINOR:MODE:UID:GID + * For e.g. lxc.populate.device = /dev/sda:b:8:0:0666:0:0 + */ + ret = sscanf(value, "%[^:]:%2[^:]:%i:%i:%i:%u:%u", name, type, &major, &minor, &filemode, &uid, &gid); + if (ret != 7) + return -1; + + /* find existing list element */ + lxc_list_for_each(iter, &lxc_conf->populate_devs) { + dev_elem = iter->elem; + + if (strcmp(name, dev_elem->name) != 0) + continue; + + replace_value = strdup(type); + if (!replace_value) + return -1; + + free(dev_elem->type); + dev_elem->type = replace_value; + dev_elem->file_mode = filemode; + dev_elem->maj = major; + dev_elem->min = minor; + dev_elem->uid = (uid_t)uid; + dev_elem->gid = (gid_t)gid; + return 0; + } + + /* allocate list element */ + dev_list = malloc(sizeof(*dev_list)); + if (!dev_list) + goto on_error; + + lxc_list_init(dev_list); + + dev_elem = malloc(sizeof(*dev_elem)); + if (!dev_elem) + goto on_error; + memset(dev_elem, 0, sizeof(*dev_elem)); + + dev_elem->name = strdup(name); + if (!dev_elem->name) + goto on_error; + + dev_elem->type = strdup(type); + if (!dev_elem->type) + goto on_error; + + dev_elem->file_mode = filemode; + dev_elem->maj = major; + dev_elem->min = minor; + + lxc_list_add_elem(dev_list, dev_elem); + + lxc_list_add_tail(&lxc_conf->populate_devs, dev_list); + + return 0; + +on_error: + free(dev_list); + if (dev_elem) { + free(dev_elem->name); + free(dev_elem->type); + free(dev_elem); + } + return -1; + +} + struct parse_line_conf { struct lxc_conf *conf; bool from_include; @@ -3770,6 +3859,34 @@ static int get_config_init_args(const char *key, char *retv, int inlen, return fulllen; } +/* isulad: get config populate device + * If you ask for 'lxc.populate.device', then all populate device + * entries will be printed, in 'lxc.populate.device = path_in_container:type:major:minor:mode:uid:gid' format. + * For e.g. lxc.populate.device = /dev/sda:b:8:0:0666:0:0 + */ +static int get_config_populate_device(const char *key, char *retv, int inlen, + struct lxc_conf *c, void *data) +{ + int len; + struct lxc_list *it; + int fulllen = 0; + + if (!retv) + inlen = 0; + else + memset(retv, 0, inlen); + + lxc_list_for_each(it, &c->populate_devs) { + struct lxc_populate_devs *elem = it->elem; + strprint(retv, inlen, "lxc.populate.device = %s:%s:%d:%d:%o:%u:%u\n", + elem->name, elem->type, elem->maj, + elem->min, elem->file_mode, elem->uid, elem->gid); + } + + return fulllen; +} + + /* Callbacks to clear config items. */ static inline int clr_config_personality(const char *key, struct lxc_conf *c, void *data) @@ -4581,6 +4698,13 @@ static inline int clr_config_init_args(const char *key, struct lxc_conf *c, return lxc_clear_init_args(c); } +/* isulad: clr config populate devices*/ +static inline int clr_config_populate_device(const char *key, struct lxc_conf *c, + void *data) +{ + return lxc_clear_populate_devices(c); +} + static int get_config_net_nic(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { -- 1.8.3.1