cgroups: fix attaching to the unified cgroup

parent 65146c97
...@@ -1174,7 +1174,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1174,7 +1174,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
* If this is the unified hierarchy cgroup_attach() is * If this is the unified hierarchy cgroup_attach() is
* enough. * enough.
*/ */
ret = cgroup_attach(name, lxcpath, pid); ret = cgroup_attach(conf, name, lxcpath, pid);
if (ret) { if (ret) {
call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL; call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL;
...@@ -1182,7 +1182,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1182,7 +1182,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
if (!cgroup_ops) if (!cgroup_ops)
goto on_error; goto on_error;
if (!cgroup_ops->attach(cgroup_ops, name, lxcpath, pid)) if (!cgroup_ops->attach(cgroup_ops, conf, name, lxcpath, pid))
goto on_error; goto on_error;
} }
TRACE("Moved intermediate process %d into container's cgroups", pid); TRACE("Moved intermediate process %d into container's cgroups", pid);
......
...@@ -2057,12 +2057,11 @@ static inline char *build_full_cgpath_from_monitorpath(struct hierarchy *h, ...@@ -2057,12 +2057,11 @@ static inline char *build_full_cgpath_from_monitorpath(struct hierarchy *h,
return must_make_path(h->mountpoint, inpath, filename, NULL); return must_make_path(h->mountpoint, inpath, filename, NULL);
} }
static int cgroup_attach_leaf(int unified_fd, int64_t pid) static int cgroup_attach_leaf(const struct lxc_conf *conf, int unified_fd, pid_t pid)
{ {
int idx = 1; int idx = 1;
int ret; int ret;
char pidstr[INTTYPE_TO_STRLEN(int64_t) + 1]; char pidstr[INTTYPE_TO_STRLEN(int64_t) + 1];
char attach_cgroup[STRLITERALLEN("lxc-1000/cgroup.procs") + 1];
size_t pidstr_len; size_t pidstr_len;
/* Create leaf cgroup. */ /* Create leaf cgroup. */
...@@ -2070,7 +2069,7 @@ static int cgroup_attach_leaf(int unified_fd, int64_t pid) ...@@ -2070,7 +2069,7 @@ static int cgroup_attach_leaf(int unified_fd, int64_t pid)
if (ret < 0 && errno != EEXIST) if (ret < 0 && errno != EEXIST)
return log_error_errno(-1, errno, "Failed to create leaf cgroup \"lxc\""); return log_error_errno(-1, errno, "Failed to create leaf cgroup \"lxc\"");
pidstr_len = sprintf(pidstr, INT64_FMT, pid); pidstr_len = sprintf(pidstr, INT64_FMT, (int64_t)pid);
ret = lxc_writeat(unified_fd, "lxc/cgroup.procs", pidstr, pidstr_len); ret = lxc_writeat(unified_fd, "lxc/cgroup.procs", pidstr, pidstr_len);
if (ret < 0) if (ret < 0)
ret = lxc_writeat(unified_fd, "cgroup.procs", pidstr, pidstr_len); ret = lxc_writeat(unified_fd, "cgroup.procs", pidstr, pidstr_len);
...@@ -2082,6 +2081,8 @@ static int cgroup_attach_leaf(int unified_fd, int64_t pid) ...@@ -2082,6 +2081,8 @@ static int cgroup_attach_leaf(int unified_fd, int64_t pid)
return log_error_errno(-1, errno, "Failed to attach to unified cgroup"); return log_error_errno(-1, errno, "Failed to attach to unified cgroup");
do { do {
bool rm = false;
char attach_cgroup[STRLITERALLEN("lxc-1000/cgroup.procs") + 1];
char *slash; char *slash;
sprintf(attach_cgroup, "lxc-%d/cgroup.procs", idx); sprintf(attach_cgroup, "lxc-%d/cgroup.procs", idx);
...@@ -2091,6 +2092,8 @@ static int cgroup_attach_leaf(int unified_fd, int64_t pid) ...@@ -2091,6 +2092,8 @@ static int cgroup_attach_leaf(int unified_fd, int64_t pid)
ret = mkdirat(unified_fd, attach_cgroup, 0755); ret = mkdirat(unified_fd, attach_cgroup, 0755);
if (ret < 0 && errno != EEXIST) if (ret < 0 && errno != EEXIST)
return log_error_errno(-1, errno, "Failed to create cgroup %s", attach_cgroup); return log_error_errno(-1, errno, "Failed to create cgroup %s", attach_cgroup);
if (ret == 0)
rm = true;
*slash = '/'; *slash = '/';
...@@ -2098,6 +2101,9 @@ static int cgroup_attach_leaf(int unified_fd, int64_t pid) ...@@ -2098,6 +2101,9 @@ static int cgroup_attach_leaf(int unified_fd, int64_t pid)
if (ret == 0) if (ret == 0)
return 0; return 0;
if (rm && unlinkat(unified_fd, attach_cgroup, AT_REMOVEDIR))
SYSERROR("Failed to remove cgroup \"%d(%s)\"", unified_fd, attach_cgroup);
/* this is a non-leaf node */ /* this is a non-leaf node */
if (errno != EBUSY) if (errno != EBUSY)
return log_error_errno(-1, errno, "Failed to attach to unified cgroup"); return log_error_errno(-1, errno, "Failed to attach to unified cgroup");
...@@ -2108,15 +2114,66 @@ static int cgroup_attach_leaf(int unified_fd, int64_t pid) ...@@ -2108,15 +2114,66 @@ static int cgroup_attach_leaf(int unified_fd, int64_t pid)
return log_error_errno(-1, errno, "Failed to attach to unified cgroup"); return log_error_errno(-1, errno, "Failed to attach to unified cgroup");
} }
int cgroup_attach(const char *name, const char *lxcpath, int64_t pid) struct userns_exec_unified_attach_data {
const struct lxc_conf *conf;
int unified_fd;
pid_t pid;
uid_t origuid;
};
static int cgroup_unified_attach_wrapper(void *data)
{
struct userns_exec_unified_attach_data *args = data;
uid_t nsuid = (args->conf->root_nsuid_map != NULL) ? 0 : args->conf->init_uid;
gid_t nsgid = (args->conf->root_nsgid_map != NULL) ? 0 : args->conf->init_gid;
int ret;
if (!args->conf || args->unified_fd < 0 || args->pid <= 0)
return ret_errno(EINVAL);
if (!lxc_setgroups(0, NULL) && errno != EPERM)
return log_error_errno(-1, errno, "Failed to setgroups(0, NULL)");
ret = setresgid(nsgid, nsgid, nsgid);
if (ret < 0)
return log_error_errno(-1, errno, "Failed to setresgid(%d, %d, %d)",
(int)nsgid, (int)nsgid, (int)nsgid);
ret = setresuid(nsuid, nsuid, nsuid);
if (ret < 0)
return log_error_errno(-1, errno, "Failed to setresuid(%d, %d, %d)",
(int)nsuid, (int)nsuid, (int)nsuid);
return cgroup_attach_leaf(args->conf, args->unified_fd, args->pid);
}
int cgroup_attach(const struct lxc_conf *conf, const char *name,
const char *lxcpath, pid_t pid)
{ {
__do_close int unified_fd = -EBADF; __do_close int unified_fd = -EBADF;
int ret;
if (!conf || !name || !lxcpath || pid <= 0)
return ret_errno(EINVAL);
unified_fd = lxc_cmd_get_cgroup2_fd(name, lxcpath); unified_fd = lxc_cmd_get_cgroup2_fd(name, lxcpath);
if (unified_fd < 0) if (unified_fd < 0)
return -1; return ret_errno(EBADF);
if (!lxc_list_empty(&conf->id_map)) {
struct userns_exec_unified_attach_data args = {
.conf = conf,
.unified_fd = unified_fd,
.pid = pid,
};
ret = userns_exec_1(conf, cgroup_unified_attach_wrapper, &args,
"cgroup_unified_attach_wrapper");
} else {
ret = cgroup_attach_leaf(conf, unified_fd, pid);
}
return cgroup_attach_leaf(unified_fd, pid); return ret;
} }
/* Technically, we're always at a delegation boundary here (This is especially /* Technically, we're always at a delegation boundary here (This is especially
...@@ -2128,14 +2185,18 @@ int cgroup_attach(const char *name, const char *lxcpath, int64_t pid) ...@@ -2128,14 +2185,18 @@ int cgroup_attach(const char *name, const char *lxcpath, int64_t pid)
* created when we started the container in the latter case we create our own * created when we started the container in the latter case we create our own
* cgroup for the attaching process. * cgroup for the attaching process.
*/ */
static int __cg_unified_attach(const struct hierarchy *h, const char *name, static int __cg_unified_attach(const struct hierarchy *h,
const struct lxc_conf *conf, const char *name,
const char *lxcpath, pid_t pid, const char *lxcpath, pid_t pid,
const char *controller) const char *controller)
{ {
__do_close int unified_fd = -EBADF; __do_close int unified_fd = -EBADF;
int ret; int ret;
ret = cgroup_attach(name, lxcpath, pid); if (!conf || !name || !lxcpath || pid <= 0)
return ret_errno(EINVAL);
ret = cgroup_attach(conf, name, lxcpath, pid);
if (ret < 0) { if (ret < 0) {
__do_free char *path = NULL, *cgroup = NULL; __do_free char *path = NULL, *cgroup = NULL;
...@@ -2148,13 +2209,28 @@ static int __cg_unified_attach(const struct hierarchy *h, const char *name, ...@@ -2148,13 +2209,28 @@ static int __cg_unified_attach(const struct hierarchy *h, const char *name,
unified_fd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC); unified_fd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
} }
if (unified_fd < 0) if (unified_fd < 0)
return -1; return ret_errno(EBADF);
return cgroup_attach_leaf(unified_fd, pid); if (!lxc_list_empty(&conf->id_map)) {
struct userns_exec_unified_attach_data args = {
.conf = conf,
.unified_fd = unified_fd,
.pid = pid,
};
ret = userns_exec_1(conf, cgroup_unified_attach_wrapper, &args,
"cgroup_unified_attach_wrapper");
} else {
ret = cgroup_attach_leaf(conf, unified_fd, pid);
}
return ret;
} }
__cgfsng_ops static bool cgfsng_attach(struct cgroup_ops *ops, const char *name, __cgfsng_ops static bool cgfsng_attach(struct cgroup_ops *ops,
const char *lxcpath, pid_t pid) const struct lxc_conf *conf,
const char *name, const char *lxcpath,
pid_t pid)
{ {
int len, ret; int len, ret;
char pidstr[INTTYPE_TO_STRLEN(pid_t)]; char pidstr[INTTYPE_TO_STRLEN(pid_t)];
...@@ -2174,7 +2250,7 @@ __cgfsng_ops static bool cgfsng_attach(struct cgroup_ops *ops, const char *name, ...@@ -2174,7 +2250,7 @@ __cgfsng_ops static bool cgfsng_attach(struct cgroup_ops *ops, const char *name,
struct hierarchy *h = ops->hierarchies[i]; struct hierarchy *h = ops->hierarchies[i];
if (h->version == CGROUP2_SUPER_MAGIC) { if (h->version == CGROUP2_SUPER_MAGIC) {
ret = __cg_unified_attach(h, name, lxcpath, pid, ret = __cg_unified_attach(h, conf, name, lxcpath, pid,
h->controllers[0]); h->controllers[0]);
if (ret < 0) if (ret < 0)
return false; return false;
......
...@@ -160,8 +160,8 @@ struct cgroup_ops { ...@@ -160,8 +160,8 @@ struct cgroup_ops {
struct lxc_conf *conf, bool with_devices); struct lxc_conf *conf, bool with_devices);
bool (*setup_limits)(struct cgroup_ops *ops, struct lxc_handler *handler); bool (*setup_limits)(struct cgroup_ops *ops, struct lxc_handler *handler);
bool (*chown)(struct cgroup_ops *ops, struct lxc_conf *conf); bool (*chown)(struct cgroup_ops *ops, struct lxc_conf *conf);
bool (*attach)(struct cgroup_ops *ops, const char *name, bool (*attach)(struct cgroup_ops *ops, const struct lxc_conf *conf,
const char *lxcpath, pid_t pid); const char *name, const char *lxcpath, pid_t pid);
bool (*mount)(struct cgroup_ops *ops, struct lxc_handler *handler, bool (*mount)(struct cgroup_ops *ops, struct lxc_handler *handler,
const char *root, int type); const char *root, int type);
bool (*devices_activate)(struct cgroup_ops *ops, bool (*devices_activate)(struct cgroup_ops *ops,
...@@ -178,7 +178,8 @@ define_cleanup_function(struct cgroup_ops *, cgroup_exit); ...@@ -178,7 +178,8 @@ define_cleanup_function(struct cgroup_ops *, cgroup_exit);
extern void prune_init_scope(char *cg); extern void prune_init_scope(char *cg);
extern int cgroup_attach(const char *name, const char *lxcpath, int64_t pid); extern int cgroup_attach(const struct lxc_conf *conf, const char *name,
const char *lxcpath, pid_t pid);
static inline bool pure_unified_layout(const struct cgroup_ops *ops) static inline bool pure_unified_layout(const struct cgroup_ops *ops)
{ {
......
...@@ -1440,7 +1440,7 @@ static int lxc_setup_rootfs_switch_root(const struct lxc_rootfs *rootfs) ...@@ -1440,7 +1440,7 @@ static int lxc_setup_rootfs_switch_root(const struct lxc_rootfs *rootfs)
return lxc_pivot_root(rootfs->mount); return lxc_pivot_root(rootfs->mount);
} }
static const struct id_map *find_mapped_nsid_entry(struct lxc_conf *conf, static const struct id_map *find_mapped_nsid_entry(const struct lxc_conf *conf,
unsigned id, unsigned id,
enum idtype idtype) enum idtype idtype)
{ {
...@@ -2845,7 +2845,7 @@ int mapped_hostid(unsigned id, const struct lxc_conf *conf, enum idtype idtype) ...@@ -2845,7 +2845,7 @@ int mapped_hostid(unsigned id, const struct lxc_conf *conf, enum idtype idtype)
return -1; return -1;
} }
int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype) int find_unmapped_nsid(const struct lxc_conf *conf, enum idtype idtype)
{ {
struct id_map *map; struct id_map *map;
struct lxc_list *it; struct lxc_list *it;
...@@ -3869,7 +3869,7 @@ static int run_userns_fn(void *data) ...@@ -3869,7 +3869,7 @@ static int run_userns_fn(void *data)
return d->fn(d->arg); return d->fn(d->arg);
} }
static struct id_map *mapped_nsid_add(struct lxc_conf *conf, unsigned id, static struct id_map *mapped_nsid_add(const struct lxc_conf *conf, unsigned id,
enum idtype idtype) enum idtype idtype)
{ {
const struct id_map *map; const struct id_map *map;
...@@ -3887,7 +3887,7 @@ static struct id_map *mapped_nsid_add(struct lxc_conf *conf, unsigned id, ...@@ -3887,7 +3887,7 @@ static struct id_map *mapped_nsid_add(struct lxc_conf *conf, unsigned id,
return retmap; return retmap;
} }
static struct id_map *find_mapped_hostid_entry(struct lxc_conf *conf, static struct id_map *find_mapped_hostid_entry(const struct lxc_conf *conf,
unsigned id, enum idtype idtype) unsigned id, enum idtype idtype)
{ {
struct id_map *map; struct id_map *map;
...@@ -3911,7 +3911,7 @@ static struct id_map *find_mapped_hostid_entry(struct lxc_conf *conf, ...@@ -3911,7 +3911,7 @@ static struct id_map *find_mapped_hostid_entry(struct lxc_conf *conf,
/* Allocate a new {g,u}id mapping for the given {g,u}id. Re-use an already /* Allocate a new {g,u}id mapping for the given {g,u}id. Re-use an already
* existing one or establish a new one. * existing one or establish a new one.
*/ */
static struct id_map *mapped_hostid_add(struct lxc_conf *conf, uid_t id, static struct id_map *mapped_hostid_add(const struct lxc_conf *conf, uid_t id,
enum idtype type) enum idtype type)
{ {
__do_free struct id_map *entry = NULL; __do_free struct id_map *entry = NULL;
...@@ -3940,7 +3940,7 @@ static struct id_map *mapped_hostid_add(struct lxc_conf *conf, uid_t id, ...@@ -3940,7 +3940,7 @@ static struct id_map *mapped_hostid_add(struct lxc_conf *conf, uid_t id,
return move_ptr(entry); return move_ptr(entry);
} }
struct lxc_list *get_minimal_idmap(struct lxc_conf *conf) static struct lxc_list *get_minimal_idmap(const struct lxc_conf *conf)
{ {
__do_free struct id_map *container_root_uid = NULL, __do_free struct id_map *container_root_uid = NULL,
*container_root_gid = NULL, *container_root_gid = NULL,
...@@ -4044,7 +4044,7 @@ struct lxc_list *get_minimal_idmap(struct lxc_conf *conf) ...@@ -4044,7 +4044,7 @@ struct lxc_list *get_minimal_idmap(struct lxc_conf *conf)
* retrieve from the container's configured {g,u}id mappings as it must have been * retrieve from the container's configured {g,u}id mappings as it must have been
* there to start the container in the first place. * there to start the container in the first place.
*/ */
int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data, int userns_exec_1(const struct lxc_conf *conf, int (*fn)(void *), void *data,
const char *fn_name) const char *fn_name)
{ {
pid_t pid; pid_t pid;
......
...@@ -436,12 +436,12 @@ extern int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf, ...@@ -436,12 +436,12 @@ extern int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf,
extern int lxc_setup(struct lxc_handler *handler); extern int lxc_setup(struct lxc_handler *handler);
extern int lxc_setup_parent(struct lxc_handler *handler); extern int lxc_setup_parent(struct lxc_handler *handler);
extern int setup_resource_limits(struct lxc_list *limits, pid_t pid); extern int setup_resource_limits(struct lxc_list *limits, pid_t pid);
extern int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype); extern int find_unmapped_nsid(const struct lxc_conf *conf, enum idtype idtype);
extern int mapped_hostid(unsigned id, const struct lxc_conf *conf, extern int mapped_hostid(unsigned id, const struct lxc_conf *conf,
enum idtype idtype); enum idtype idtype);
extern int chown_mapped_root(const char *path, const struct lxc_conf *conf); extern int chown_mapped_root(const char *path, const struct lxc_conf *conf);
extern int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data, extern int userns_exec_1(const struct lxc_conf *conf, int (*fn)(void *),
const char *fn_name); void *data, const char *fn_name);
extern int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), extern int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *),
void *data, const char *fn_name); void *data, const char *fn_name);
extern int parse_mntopts(const char *mntopts, unsigned long *mntflags, extern int parse_mntopts(const char *mntopts, unsigned long *mntflags,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment