Unverified Commit 07f89a4f by Stéphane Graber Committed by GitHub

Merge pull request #3647 from brauner/2021-02-02/fixes

cgroup2: only rely on command socket when getting cgroup values
parents b22ae843 b7aeda96
...@@ -1208,6 +1208,7 @@ __noreturn static void do_attach(struct attach_payload *ap) ...@@ -1208,6 +1208,7 @@ __noreturn static void do_attach(struct attach_payload *ap)
ret = lxc_seccomp_send_notifier_fd(&conf->seccomp, ap->ipc_socket); ret = lxc_seccomp_send_notifier_fd(&conf->seccomp, ap->ipc_socket);
if (ret < 0) if (ret < 0)
goto on_error; goto on_error;
lxc_seccomp_close_notifier_fd(&conf->seccomp);
} }
if (!lxc_switch_uid_gid(ctx->target_ns_uid, ctx->target_ns_gid)) if (!lxc_switch_uid_gid(ctx->target_ns_uid, ctx->target_ns_gid))
...@@ -1522,7 +1523,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1522,7 +1523,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
* enough. * enough.
*/ */
ret = cgroup_attach(conf, name, lxcpath, pid); ret = cgroup_attach(conf, name, lxcpath, pid);
if (ret) { if (ret == -ENOCGROUP2) {
call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL; call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL;
cgroup_ops = cgroup_init(conf); cgroup_ops = cgroup_init(conf);
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "cgroup2_devices.h" #include "cgroup2_devices.h"
#include "cgroup_utils.h" #include "cgroup_utils.h"
#include "commands.h" #include "commands.h"
#include "commands_utils.h"
#include "conf.h" #include "conf.h"
#include "config.h" #include "config.h"
#include "log.h" #include "log.h"
...@@ -2026,24 +2027,15 @@ static bool cg_legacy_freeze(struct cgroup_ops *ops) ...@@ -2026,24 +2027,15 @@ static bool cg_legacy_freeze(struct cgroup_ops *ops)
static int freezer_cgroup_events_cb(int fd, uint32_t events, void *cbdata, static int freezer_cgroup_events_cb(int fd, uint32_t events, void *cbdata,
struct lxc_epoll_descr *descr) struct lxc_epoll_descr *descr)
{ {
__do_close int duped_fd = -EBADF;
__do_free char *line = NULL; __do_free char *line = NULL;
__do_fclose FILE *f = NULL; __do_fclose FILE *f = NULL;
int state = PTR_TO_INT(cbdata); int state = PTR_TO_INT(cbdata);
size_t len; size_t len;
const char *state_string; const char *state_string;
duped_fd = dup(fd); f = fdopen_at(fd, "", "re", PROTECT_OPEN, PROTECT_LOOKUP_BENEATH);
if (duped_fd < 0)
return LXC_MAINLOOP_ERROR;
if (lseek(duped_fd, 0, SEEK_SET) < (off_t)-1)
return LXC_MAINLOOP_ERROR;
f = fdopen(duped_fd, "re");
if (!f) if (!f)
return LXC_MAINLOOP_ERROR; return LXC_MAINLOOP_ERROR;
move_fd(duped_fd);
if (state == 1) if (state == 1)
state_string = "frozen 1"; state_string = "frozen 1";
...@@ -2054,6 +2046,8 @@ static int freezer_cgroup_events_cb(int fd, uint32_t events, void *cbdata, ...@@ -2054,6 +2046,8 @@ static int freezer_cgroup_events_cb(int fd, uint32_t events, void *cbdata,
if (strncmp(line, state_string, STRLITERALLEN("frozen") + 2) == 0) if (strncmp(line, state_string, STRLITERALLEN("frozen") + 2) == 0)
return LXC_MAINLOOP_CLOSE; return LXC_MAINLOOP_CLOSE;
rewind(f);
return LXC_MAINLOOP_CONTINUE; return LXC_MAINLOOP_CONTINUE;
} }
...@@ -2356,42 +2350,6 @@ static int cgroup_unified_attach_parent_wrapper(void *data) ...@@ -2356,42 +2350,6 @@ static int cgroup_unified_attach_parent_wrapper(void *data)
args->pid); 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;
int ret;
if (!conf || !name || !lxcpath || pid <= 0)
return ret_errno(EINVAL);
unified_fd = lxc_cmd_get_cgroup2_fd(name, lxcpath);
if (unified_fd < 0)
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 = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, args.sk_pair);
if (ret < 0)
return -errno;
ret = userns_exec_minimal(conf,
cgroup_unified_attach_parent_wrapper,
&args,
cgroup_unified_attach_child_wrapper,
&args);
} else {
ret = cgroup_attach_leaf(conf, 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
* true when cgroup namespaces are available.). The reasoning is that in order * true when cgroup namespaces are available.). The reasoning is that in order
* for us to have been able to start a container in the first place the root * for us to have been able to start a container in the first place the root
...@@ -2664,8 +2622,9 @@ __cgfsng_ops static int cgfsng_set(struct cgroup_ops *ops, ...@@ -2664,8 +2622,9 @@ __cgfsng_ops static int cgfsng_set(struct cgroup_ops *ops,
struct hierarchy *h; struct hierarchy *h;
int ret = -1; int ret = -1;
if (!ops || !key || !value || !name || !lxcpath) if (!ops || is_empty_string(key) || is_empty_string(value) ||
return ret_errno(ENOENT); is_empty_string(name) || is_empty_string(lxcpath))
return ret_errno(EINVAL);
controller = must_copy_string(key); controller = must_copy_string(key);
p = strchr(controller, '.'); p = strchr(controller, '.');
...@@ -3500,3 +3459,186 @@ struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf) ...@@ -3500,3 +3459,186 @@ struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf)
return move_ptr(cgfsng_ops); return move_ptr(cgfsng_ops);
} }
int cgroup_attach(const struct lxc_conf *conf, const char *name,
const char *lxcpath, pid_t pid)
{
__do_close int unified_fd = -EBADF;
int ret;
if (!conf || is_empty_string(name) || !is_empty_string(lxcpath) || pid <= 0)
return ret_errno(EINVAL);
unified_fd = lxc_cmd_get_cgroup2_fd(name, lxcpath);
if (unified_fd < 0)
return ret_errno(ENOCGROUP2);
if (!lxc_list_empty(&conf->id_map)) {
struct userns_exec_unified_attach_data args = {
.conf = conf,
.unified_fd = unified_fd,
.pid = pid,
};
ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, args.sk_pair);
if (ret < 0)
return -errno;
ret = userns_exec_minimal(conf,
cgroup_unified_attach_parent_wrapper,
&args,
cgroup_unified_attach_child_wrapper,
&args);
} else {
ret = cgroup_attach_leaf(conf, unified_fd, pid);
}
return ret;
}
/* Connects to command socket therefore isn't callable from command handler. */
int cgroup_get(const char *name, const char *lxcpath,
const char *filename, char *buf, size_t len)
{
__do_close int unified_fd = -EBADF;
ssize_t ret;
if (is_empty_string(filename) || is_empty_string(name) ||
is_empty_string(lxcpath))
return ret_errno(EINVAL);
if ((buf && !len) || (len && !buf))
return ret_errno(EINVAL);
unified_fd = lxc_cmd_get_limiting_cgroup2_fd(name, lxcpath);
if (unified_fd < 0)
return ret_errno(ENOCGROUP2);
ret = lxc_read_try_buf_at(unified_fd, filename, buf, len);
if (ret < 0)
SYSERROR("Failed to read cgroup value");
return ret;
}
/* Connects to command socket therefore isn't callable from command handler. */
int cgroup_set(const char *name, const char *lxcpath,
const char *filename, const char *value)
{
__do_close int unified_fd = -EBADF;
ssize_t ret;
if (is_empty_string(filename) || is_empty_string(value) ||
is_empty_string(name) || is_empty_string(lxcpath))
return ret_errno(EINVAL);
unified_fd = lxc_cmd_get_limiting_cgroup2_fd(name, lxcpath);
if (unified_fd < 0)
return ret_errno(ENOCGROUP2);
if (strncmp(filename, "devices.", STRLITERALLEN("devices.")) == 0) {
struct device_item device = {};
ret = device_cgroup_rule_parse(&device, filename, value);
if (ret < 0)
return log_error_errno(-1, EINVAL, "Failed to parse device string %s=%s", filename, value);
ret = lxc_cmd_add_bpf_device_cgroup(name, lxcpath, &device);
} else {
ret = lxc_writeat(unified_fd, filename, value, strlen(value));
}
return ret;
}
static int do_cgroup_freeze(int unified_fd,
const char *state_string,
int state_num,
int timeout,
const char *epoll_error,
const char *wait_error)
{
__do_close int events_fd = -EBADF;
call_cleaner(lxc_mainloop_close) struct lxc_epoll_descr *descr_ptr = NULL;
int ret;
struct lxc_epoll_descr descr = {};
if (timeout != 0) {
ret = lxc_mainloop_open(&descr);
if (ret)
return log_error_errno(-1, errno, "%s", epoll_error);
/* automatically cleaned up now */
descr_ptr = &descr;
events_fd = open_at(unified_fd, "cgroup.events", PROTECT_OPEN, PROTECT_LOOKUP_BENEATH, 0);
if (events_fd < 0)
return log_error_errno(-errno, errno, "Failed to open cgroup.events file");
ret = lxc_mainloop_add_handler_events(&descr, events_fd, EPOLLPRI, freezer_cgroup_events_cb, INT_TO_PTR(state_num));
if (ret < 0)
return log_error_errno(-1, errno, "Failed to add cgroup.events fd handler to mainloop");
}
ret = lxc_writeat(unified_fd, "cgroup.freeze", state_string, 1);
if (ret < 0)
return log_error_errno(-1, errno, "Failed to open cgroup.freeze file");
if (timeout != 0) {
ret = lxc_mainloop(&descr, timeout);
if (ret)
return log_error_errno(-1, errno, "%s", wait_error);
}
return log_trace(0, "Container now %s", (state_num == 1) ? "frozen" : "unfrozen");
}
static inline int __cgroup_freeze(int unified_fd, int timeout)
{
return do_cgroup_freeze(unified_fd, "1", 1, timeout,
"Failed to create epoll instance to wait for container freeze",
"Failed to wait for container to be frozen");
}
int cgroup_freeze(const char *name, const char *lxcpath, int timeout)
{
__do_close int unified_fd = -EBADF;
int ret;
if (is_empty_string(name) || is_empty_string(lxcpath))
return ret_errno(EINVAL);
unified_fd = lxc_cmd_get_limiting_cgroup2_fd(name, lxcpath);
if (unified_fd < 0)
return ret_errno(ENOCGROUP2);
lxc_cmd_notify_state_listeners(name, lxcpath, FREEZING);
ret = __cgroup_freeze(unified_fd, timeout);
lxc_cmd_notify_state_listeners(name, lxcpath, !ret ? FROZEN : RUNNING);
return ret;
}
int __cgroup_unfreeze(int unified_fd, int timeout)
{
return do_cgroup_freeze(unified_fd, "0", 0, timeout,
"Failed to create epoll instance to wait for container freeze",
"Failed to wait for container to be frozen");
}
int cgroup_unfreeze(const char *name, const char *lxcpath, int timeout)
{
__do_close int unified_fd = -EBADF;
int ret;
if (is_empty_string(name) || is_empty_string(lxcpath))
return ret_errno(EINVAL);
unified_fd = lxc_cmd_get_limiting_cgroup2_fd(name, lxcpath);
if (unified_fd < 0)
return ret_errno(ENOCGROUP2);
lxc_cmd_notify_state_listeners(name, lxcpath, THAWED);
ret = __cgroup_unfreeze(unified_fd, timeout);
lxc_cmd_notify_state_listeners(name, lxcpath, !ret ? RUNNING : FROZEN);
return ret;
}
...@@ -191,6 +191,13 @@ __hidden extern void prune_init_scope(char *cg); ...@@ -191,6 +191,13 @@ __hidden extern void prune_init_scope(char *cg);
__hidden extern int cgroup_attach(const struct lxc_conf *conf, const char *name, __hidden extern int cgroup_attach(const struct lxc_conf *conf, const char *name,
const char *lxcpath, pid_t pid); const char *lxcpath, pid_t pid);
__hidden extern int cgroup_get(const char *name, const char *lxcpath,
const char *filename, char *buf, size_t len);
__hidden extern int cgroup_set(const char *name, const char *lxcpath,
const char *filename, const char *value);
__hidden extern int cgroup_freeze(const char *name, const char *lxcpath, int timeout);
__hidden extern int cgroup_unfreeze(const char *name, const char *lxcpath, int timeout);
__hidden extern int __cgroup_unfreeze(int unified_fd, int timeout);
static inline bool pure_unified_layout(const struct cgroup_ops *ops) static inline bool pure_unified_layout(const struct cgroup_ops *ops)
{ {
......
...@@ -897,7 +897,10 @@ static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req, ...@@ -897,7 +897,10 @@ static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req,
else else
TRACE("Sent signal %d to pidfd %d", stopsignal, handler->pid); TRACE("Sent signal %d to pidfd %d", stopsignal, handler->pid);
ret = cgroup_ops->unfreeze(cgroup_ops, -1); if (pure_unified_layout(cgroup_ops))
ret = __cgroup_unfreeze(cgroup_ops->unified->cgfd_limit, -1);
else
ret = cgroup_ops->unfreeze(cgroup_ops, -1);
if (ret) if (ret)
WARN("Failed to unfreeze container \"%s\"", handler->name); WARN("Failed to unfreeze container \"%s\"", handler->name);
...@@ -1531,6 +1534,25 @@ int lxc_cmd_get_cgroup2_fd(const char *name, const char *lxcpath) ...@@ -1531,6 +1534,25 @@ int lxc_cmd_get_cgroup2_fd(const char *name, const char *lxcpath)
return PTR_TO_INT(cmd.rsp.data); return PTR_TO_INT(cmd.rsp.data);
} }
int lxc_cmd_get_limiting_cgroup2_fd(const char *name, const char *lxcpath)
{
int ret, stopped;
struct lxc_cmd_rr cmd = {
.req = {
.cmd = LXC_CMD_GET_LIMITING_CGROUP2_FD,
},
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0)
return -1;
if (cmd.rsp.ret < 0)
return log_debug_errno(cmd.rsp.ret, -cmd.rsp.ret, "Failed to receive cgroup2 fd");
return PTR_TO_INT(cmd.rsp.data);
}
static int lxc_cmd_get_cgroup2_fd_callback_do(int fd, struct lxc_cmd_req *req, static int lxc_cmd_get_cgroup2_fd_callback_do(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler, struct lxc_handler *handler,
struct lxc_epoll_descr *descr, struct lxc_epoll_descr *descr,
......
...@@ -190,3 +190,10 @@ int lxc_add_state_client(int state_client_fd, struct lxc_handler *handler, ...@@ -190,3 +190,10 @@ int lxc_add_state_client(int state_client_fd, struct lxc_handler *handler,
TRACE("Added state client fd %d to state client list", state_client_fd); TRACE("Added state client fd %d to state client list", state_client_fd);
return MAX_STATE; return MAX_STATE;
} }
void lxc_cmd_notify_state_listeners(const char *name, const char *lxcpath,
lxc_state_t state)
{
(void)lxc_cmd_serve_state_clients(name, lxcpath, state);
(void)lxc_monitor_send_state(name, state, lxcpath);
}
...@@ -62,4 +62,7 @@ __hidden extern int lxc_add_state_client(int state_client_fd, struct lxc_handler ...@@ -62,4 +62,7 @@ __hidden extern int lxc_add_state_client(int state_client_fd, struct lxc_handler
__hidden extern int lxc_cmd_connect(const char *name, const char *lxcpath, __hidden extern int lxc_cmd_connect(const char *name, const char *lxcpath,
const char *hashed_sock_name, const char *suffix); const char *hashed_sock_name, const char *suffix);
__hidden extern void lxc_cmd_notify_state_listeners(const char *name,
const char *lxcpath,
lxc_state_t state);
#endif /* __LXC_COMMANDS_UTILS_H */ #endif /* __LXC_COMMANDS_UTILS_H */
...@@ -122,6 +122,32 @@ int lxc_read_from_file(const char *filename, void *buf, size_t count) ...@@ -122,6 +122,32 @@ int lxc_read_from_file(const char *filename, void *buf, size_t count)
return ret; return ret;
} }
ssize_t lxc_read_try_buf_at(int dfd, const char *path, void *buf, size_t count)
{
__do_close int fd = -EBADF;
ssize_t ret;
fd = open_at(dfd, path, PROTECT_OPEN_W, PROTECT_LOOKUP_BENEATH, 0);
if (fd < 0)
return -errno;
if (!buf || !count) {
char buf2[100];
size_t count2 = 0;
while ((ret = lxc_read_nointr(fd, buf2, 100)) > 0)
count2 += ret;
if (ret >= 0)
ret = count2;
} else {
memset(buf, 0, count);
ret = lxc_read_nointr(fd, buf, count);
}
return ret;
}
ssize_t lxc_write_nointr(int fd, const void *buf, size_t count) ssize_t lxc_write_nointr(int fd, const void *buf, size_t count)
{ {
ssize_t ret; ssize_t ret;
......
...@@ -94,5 +94,7 @@ __hidden int fd_make_nonblocking(int fd); ...@@ -94,5 +94,7 @@ __hidden int fd_make_nonblocking(int fd);
__hidden extern char *read_file_at(int dfd, const char *fnam, __hidden extern char *read_file_at(int dfd, const char *fnam,
unsigned int o_flags, unsigned int o_flags,
unsigned resolve_flags); unsigned resolve_flags);
__hidden extern ssize_t lxc_read_try_buf_at(int dfd, const char *path,
void *buf, size_t count);
#endif /* __LXC_FILE_UTILS_H */ #endif /* __LXC_FILE_UTILS_H */
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "cgroups/cgroup.h" #include "cgroups/cgroup.h"
#include "cgroups/cgroup_utils.h" #include "cgroups/cgroup_utils.h"
#include "commands.h" #include "commands.h"
#include "commands_utils.h"
#include "config.h" #include "config.h"
#include "error.h" #include "error.h"
#include "log.h" #include "log.h"
...@@ -25,13 +26,6 @@ ...@@ -25,13 +26,6 @@
lxc_log_define(freezer, lxc); lxc_log_define(freezer, lxc);
static void notify_state_listeners(const char *name, const char *lxcpath,
lxc_state_t state)
{
(void)lxc_cmd_serve_state_clients(name, lxcpath, state);
(void)lxc_monitor_send_state(name, state, lxcpath);
}
static int do_freeze_thaw(bool freeze, struct lxc_conf *conf, const char *name, static int do_freeze_thaw(bool freeze, struct lxc_conf *conf, const char *name,
const char *lxcpath) const char *lxcpath)
{ {
...@@ -64,7 +58,7 @@ static int do_freeze_thaw(bool freeze, struct lxc_conf *conf, const char *name, ...@@ -64,7 +58,7 @@ static int do_freeze_thaw(bool freeze, struct lxc_conf *conf, const char *name,
cur_state[lxc_char_right_gc(cur_state, strlen(cur_state))] = '\0'; cur_state[lxc_char_right_gc(cur_state, strlen(cur_state))] = '\0';
ret = strncmp(cur_state, state, state_len); ret = strncmp(cur_state, state, state_len);
if (ret == 0) { if (ret == 0) {
notify_state_listeners(name, lxcpath, new_state); lxc_cmd_notify_state_listeners(name, lxcpath, new_state);
return 0; return 0;
} }
...@@ -78,12 +72,9 @@ int lxc_freeze(struct lxc_conf *conf, const char *name, const char *lxcpath) ...@@ -78,12 +72,9 @@ int lxc_freeze(struct lxc_conf *conf, const char *name, const char *lxcpath)
{ {
int ret; int ret;
notify_state_listeners(name, lxcpath, FREEZING); lxc_cmd_notify_state_listeners(name, lxcpath, FREEZING);
if (unified_cgroup_hierarchy() > 0) ret = do_freeze_thaw(true, conf, name, lxcpath);
ret = lxc_cmd_freeze(name, lxcpath, -1); lxc_cmd_notify_state_listeners(name, lxcpath, !ret ? FROZEN : RUNNING);
else
ret = do_freeze_thaw(true, conf, name, lxcpath);
notify_state_listeners(name, lxcpath, !ret ? FROZEN : RUNNING);
return ret; return ret;
} }
...@@ -91,11 +82,8 @@ int lxc_unfreeze(struct lxc_conf *conf, const char *name, const char *lxcpath) ...@@ -91,11 +82,8 @@ int lxc_unfreeze(struct lxc_conf *conf, const char *name, const char *lxcpath)
{ {
int ret; int ret;
notify_state_listeners(name, lxcpath, THAWED); lxc_cmd_notify_state_listeners(name, lxcpath, THAWED);
if (unified_cgroup_hierarchy() > 0) ret = do_freeze_thaw(false, conf, name, lxcpath);
ret = lxc_cmd_unfreeze(name, lxcpath, -1); lxc_cmd_notify_state_listeners(name, lxcpath, !ret ? RUNNING : FROZEN);
else
ret = do_freeze_thaw(false, conf, name, lxcpath);
notify_state_listeners(name, lxcpath, !ret ? RUNNING : FROZEN);
return ret; return ret;
} }
...@@ -507,32 +507,41 @@ WRAP_API(bool, lxcapi_is_running) ...@@ -507,32 +507,41 @@ WRAP_API(bool, lxcapi_is_running)
static bool do_lxcapi_freeze(struct lxc_container *c) static bool do_lxcapi_freeze(struct lxc_container *c)
{ {
int ret = 0;
lxc_state_t s; lxc_state_t s;
if (!c || !c->lxc_conf) if (!c || !c->lxc_conf)
return false; return false;
s = lxc_getstate(c->name, c->config_path); s = lxc_getstate(c->name, c->config_path);
if (s != FROZEN) if (s != FROZEN) {
return lxc_freeze(c->lxc_conf, c->name, c->config_path) == 0; ret = cgroup_freeze(c->name, c->config_path, -1);
if (ret == -ENOCGROUP2)
ret = lxc_freeze(c->lxc_conf, c->name, c->config_path);
}
return true; return ret == 0;
} }
WRAP_API(bool, lxcapi_freeze) WRAP_API(bool, lxcapi_freeze)
static bool do_lxcapi_unfreeze(struct lxc_container *c) static bool do_lxcapi_unfreeze(struct lxc_container *c)
{ {
int ret = 0;
lxc_state_t s; lxc_state_t s;
if (!c || !c->lxc_conf) if (!c || !c->lxc_conf)
return false; return false;
s = lxc_getstate(c->name, c->config_path); s = lxc_getstate(c->name, c->config_path);
if (s == FROZEN) if (s == FROZEN) {
return lxc_unfreeze(c->lxc_conf, c->name, c->config_path) == 0; ret = cgroup_unfreeze(c->name, c->config_path, -1);
if (ret == -ENOCGROUP2)
ret = lxc_unfreeze(c->lxc_conf, c->name, c->config_path);
}
return true;
return ret == 0;
} }
WRAP_API(bool, lxcapi_unfreeze) WRAP_API(bool, lxcapi_unfreeze)
...@@ -3277,6 +3286,7 @@ WRAP_API_1(bool, lxcapi_set_config_path, const char *) ...@@ -3277,6 +3286,7 @@ WRAP_API_1(bool, lxcapi_set_config_path, const char *)
static bool do_lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsys, const char *value) static bool do_lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsys, const char *value)
{ {
call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL; call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL;
int ret;
if (!c) if (!c)
return false; return false;
...@@ -3284,12 +3294,16 @@ static bool do_lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsy ...@@ -3284,12 +3294,16 @@ static bool do_lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsy
if (is_stopped(c)) if (is_stopped(c))
return false; return false;
cgroup_ops = cgroup_init(c->lxc_conf); ret = cgroup_set(c->name, c->config_path, subsys, value);
if (!cgroup_ops) if (ret == -ENOCGROUP2) {
return false; cgroup_ops = cgroup_init(c->lxc_conf);
if (!cgroup_ops)
return false;
ret = cgroup_ops->set(cgroup_ops, subsys, value, c->name, c->config_path);
}
return cgroup_ops->set(cgroup_ops, subsys, value, c->name, return ret == 0;
c->config_path) == 0;
} }
WRAP_API_2(bool, lxcapi_set_cgroup_item, const char *, const char *) WRAP_API_2(bool, lxcapi_set_cgroup_item, const char *, const char *)
...@@ -3297,6 +3311,7 @@ WRAP_API_2(bool, lxcapi_set_cgroup_item, const char *, const char *) ...@@ -3297,6 +3311,7 @@ WRAP_API_2(bool, lxcapi_set_cgroup_item, const char *, const char *)
static int do_lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys, char *retv, int inlen) static int do_lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys, char *retv, int inlen)
{ {
call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL; call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL;
int ret;
if (!c) if (!c)
return -1; return -1;
...@@ -3304,12 +3319,16 @@ static int do_lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys ...@@ -3304,12 +3319,16 @@ static int do_lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys
if (is_stopped(c)) if (is_stopped(c))
return -1; return -1;
cgroup_ops = cgroup_init(c->lxc_conf); ret = cgroup_get(c->name, c->config_path, subsys, retv, inlen);
if (!cgroup_ops) if (ret == -ENOCGROUP2) {
return -1; cgroup_ops = cgroup_init(c->lxc_conf);
if (!cgroup_ops)
return -1;
return cgroup_ops->get(cgroup_ops, subsys, retv, inlen, c->name, return cgroup_ops->get(cgroup_ops, subsys, retv, inlen, c->name, c->config_path);
c->config_path); }
return ret;
} }
WRAP_API_3(int, lxcapi_get_cgroup_item, const char *, char *, int) WRAP_API_3(int, lxcapi_get_cgroup_item, const char *, char *, int)
......
...@@ -91,6 +91,14 @@ __hidden extern int lxc_seccomp_send_notifier_fd(struct lxc_seccomp *seccomp, in ...@@ -91,6 +91,14 @@ __hidden extern int lxc_seccomp_send_notifier_fd(struct lxc_seccomp *seccomp, in
__hidden extern int lxc_seccomp_recv_notifier_fd(struct lxc_seccomp *seccomp, int socket_fd); __hidden extern int lxc_seccomp_recv_notifier_fd(struct lxc_seccomp *seccomp, int socket_fd);
__hidden extern int lxc_seccomp_add_notifier(const char *name, const char *lxcpath, __hidden extern int lxc_seccomp_add_notifier(const char *name, const char *lxcpath,
struct lxc_seccomp *seccomp); struct lxc_seccomp *seccomp);
static inline void lxc_seccomp_close_notifier_fd(struct lxc_seccomp *seccomp)
{
#if HAVE_DECL_SECCOMP_NOTIFY_FD
if (seccomp->notifier.wants_supervision)
close_prot_errno_disarm(seccomp->notifier.notify_fd);
#endif
}
static inline int lxc_seccomp_get_notify_fd(struct lxc_seccomp *seccomp) static inline int lxc_seccomp_get_notify_fd(struct lxc_seccomp *seccomp)
{ {
#if HAVE_DECL_SECCOMP_NOTIFY_FD #if HAVE_DECL_SECCOMP_NOTIFY_FD
...@@ -162,5 +170,9 @@ static inline int lxc_seccomp_get_notify_fd(struct lxc_seccomp *seccomp) ...@@ -162,5 +170,9 @@ static inline int lxc_seccomp_get_notify_fd(struct lxc_seccomp *seccomp)
return -EBADF; return -EBADF;
} }
static inline void lxc_seccomp_close_notifier_fd(struct lxc_seccomp *seccomp)
{
}
#endif /* HAVE_SECCOMP */ #endif /* HAVE_SECCOMP */
#endif /* __LXC_LXCSECCOMP_H */ #endif /* __LXC_LXCSECCOMP_H */
...@@ -670,4 +670,6 @@ enum { ...@@ -670,4 +670,6 @@ enum {
#endif #endif
#endif #endif
#define ENOCGROUP2 ENOMEDIUM
#endif /* __LXC_MACRO_H */ #endif /* __LXC_MACRO_H */
...@@ -1638,7 +1638,6 @@ int lxc_seccomp_recv_notifier_fd(struct lxc_seccomp *seccomp, int socket_fd) ...@@ -1638,7 +1638,6 @@ int lxc_seccomp_recv_notifier_fd(struct lxc_seccomp *seccomp, int socket_fd)
int lxc_seccomp_add_notifier(const char *name, const char *lxcpath, int lxc_seccomp_add_notifier(const char *name, const char *lxcpath,
struct lxc_seccomp *seccomp) struct lxc_seccomp *seccomp)
{ {
#if HAVE_DECL_SECCOMP_NOTIFY_FD #if HAVE_DECL_SECCOMP_NOTIFY_FD
if (seccomp->notifier.wants_supervision) { if (seccomp->notifier.wants_supervision) {
int ret; int ret;
......
...@@ -275,7 +275,54 @@ lxc_test_createtest_SOURCES = createtest.c ...@@ -275,7 +275,54 @@ lxc_test_createtest_SOURCES = createtest.c
lxc_test_criu_check_feature_SOURCES = criu_check_feature.c lxctest.h lxc_test_criu_check_feature_SOURCES = criu_check_feature.c lxctest.h
lxc_test_cve_2019_5736_SOURCES = cve-2019-5736.c lxctest.h lxc_test_cve_2019_5736_SOURCES = cve-2019-5736.c lxctest.h
lxc_test_destroytest_SOURCES = destroytest.c lxc_test_destroytest_SOURCES = destroytest.c
lxc_test_device_add_remove_SOURCES = device_add_remove.c lxc_test_device_add_remove_SOURCES = device_add_remove.c \
../lxc/af_unix.c ../lxc/af_unix.h \
../lxc/caps.c ../lxc/caps.h \
../lxc/cgroups/cgfsng.c \
../lxc/cgroups/cgroup.c ../lxc/cgroups/cgroup.h \
../lxc/cgroups/cgroup2_devices.c ../lxc/cgroups/cgroup2_devices.h \
../lxc/cgroups/cgroup_utils.c ../lxc/cgroups/cgroup_utils.h \
../lxc/commands.c ../lxc/commands.h \
../lxc/commands_utils.c ../lxc/commands_utils.h \
../lxc/conf.c ../lxc/conf.h \
../lxc/confile.c ../lxc/confile.h \
../lxc/confile_utils.c ../lxc/confile_utils.h \
../lxc/error.c ../lxc/error.h \
../lxc/file_utils.c ../lxc/file_utils.h \
../include/netns_ifaddrs.c ../include/netns_ifaddrs.h \
../lxc/initutils.c ../lxc/initutils.h \
../lxc/log.c ../lxc/log.h \
../lxc/lxclock.c ../lxc/lxclock.h \
../lxc/mainloop.c ../lxc/mainloop.h \
../lxc/monitor.c ../lxc/monitor.h \
../lxc/namespace.c ../lxc/namespace.h \
../lxc/network.c ../lxc/network.h \
../lxc/nl.c ../lxc/nl.h \
../lxc/parse.c ../lxc/parse.h \
../lxc/process_utils.c ../lxc/process_utils.h \
../lxc/ringbuf.c ../lxc/ringbuf.h \
../lxc/start.c ../lxc/start.h \
../lxc/state.c ../lxc/state.h \
../lxc/storage/btrfs.c ../lxc/storage/btrfs.h \
../lxc/storage/dir.c ../lxc/storage/dir.h \
../lxc/storage/loop.c ../lxc/storage/loop.h \
../lxc/storage/lvm.c ../lxc/storage/lvm.h \
../lxc/storage/nbd.c ../lxc/storage/nbd.h \
../lxc/storage/overlay.c ../lxc/storage/overlay.h \
../lxc/storage/rbd.c ../lxc/storage/rbd.h \
../lxc/storage/rsync.c ../lxc/storage/rsync.h \
../lxc/storage/storage.c ../lxc/storage/storage.h \
../lxc/storage/storage_utils.c ../lxc/storage/storage_utils.h \
../lxc/storage/zfs.c ../lxc/storage/zfs.h \
../lxc/sync.c ../lxc/sync.h \
../lxc/string_utils.c ../lxc/string_utils.h \
../lxc/terminal.c ../lxc/terminal.h \
../lxc/utils.c ../lxc/utils.h \
../lxc/uuid.c ../lxc/uuid.h \
$(LSM_SOURCES)
if ENABLE_SECCOMP
lxc_test_device_add_remove_SOURCES += ../lxc/seccomp.c ../lxc/lxcseccomp.h
endif
lxc_test_getkeys_SOURCES = getkeys.c lxc_test_getkeys_SOURCES = getkeys.c
lxc_test_get_item_SOURCES = get_item.c lxc_test_get_item_SOURCES = get_item.c
lxc_test_list_SOURCES = list.c lxc_test_list_SOURCES = list.c
......
...@@ -30,8 +30,10 @@ ...@@ -30,8 +30,10 @@
#include <sys/stat.h> #include <sys/stat.h>
#include "cgroup.h" #include "cgroup.h"
#include "lxc.h"
#include "commands.h" #include "commands.h"
#include "lxc.h"
#include "lxctest.h"
#include "utils.h"
#ifndef HAVE_STRLCPY #ifndef HAVE_STRLCPY
#include "include/strlcpy.h" #include "include/strlcpy.h"
...@@ -50,13 +52,32 @@ ...@@ -50,13 +52,32 @@
*/ */
static int test_running_container(const char *lxcpath, const char *name) static int test_running_container(const char *lxcpath, const char *name)
{ {
__do_close int fd_log = -EBADF;
int ret = -1; int ret = -1;
struct lxc_container *c = NULL; struct lxc_container *c = NULL;
struct lxc_log log = {};
char template[sizeof(P_tmpdir"/attach_XXXXXX")];
char *cgrelpath; char *cgrelpath;
char relpath[PATH_MAX+1]; char relpath[PATH_MAX+1];
char value[NAME_MAX], value_save[NAME_MAX]; char value[NAME_MAX], value_save[NAME_MAX];
struct cgroup_ops *cgroup_ops; struct cgroup_ops *cgroup_ops;
(void)strlcpy(template, P_tmpdir"/attach_XXXXXX", sizeof(template));
fd_log = lxc_make_tmpfile(template, false);
if (fd_log < 0) {
lxc_error("Failed to create temporary log file for container %s\n", name);
exit(EXIT_FAILURE);
}
log.name = name;
log.file = template;
log.level = "TRACE";
log.prefix = "cgpath";
log.quiet = false;
log.lxcpath = NULL;
if (lxc_log_init(&log))
goto err1;
sprintf(relpath, DEFAULT_PAYLOAD_CGROUP_PREFIX "%s", name); sprintf(relpath, DEFAULT_PAYLOAD_CGROUP_PREFIX "%s", name);
if ((c = lxc_container_new(name, lxcpath)) == NULL) { if ((c = lxc_container_new(name, lxcpath)) == NULL) {
...@@ -83,33 +104,33 @@ static int test_running_container(const char *lxcpath, const char *name) ...@@ -83,33 +104,33 @@ static int test_running_container(const char *lxcpath, const char *name)
goto err3; goto err3;
/* test get/set value using memory.soft_limit_in_bytes file */ /* test get/set value using memory.soft_limit_in_bytes file */
ret = cgroup_ops->get(cgroup_ops, "memory.soft_limit_in_bytes", value, ret = cgroup_ops->get(cgroup_ops, "pids.max", value, sizeof(value),
sizeof(value), c->name, c->config_path); c->name, c->config_path);
if (ret < 0) { if (ret < 0) {
TSTERR("cgroup_get failed"); TSTERR("cgroup_get failed");
goto err3; goto err3;
} }
(void)strlcpy(value_save, value, NAME_MAX); (void)strlcpy(value_save, value, NAME_MAX);
ret = cgroup_ops->set(cgroup_ops, "memory.soft_limit_in_bytes", "512M", ret = cgroup_ops->set(cgroup_ops, "pids.max", "10000",
c->name, c->config_path); c->name, c->config_path);
if (ret < 0) { if (ret < 0) {
TSTERR("cgroup_set failed %d %d", ret, errno); TSTERR("cgroup_set failed %d %d", ret, errno);
goto err3; goto err3;
} }
ret = cgroup_ops->get(cgroup_ops, "memory.soft_limit_in_bytes", value, ret = cgroup_ops->get(cgroup_ops, "pids.max", value,
sizeof(value), c->name, c->config_path); sizeof(value), c->name, c->config_path);
if (ret < 0) { if (ret < 0) {
TSTERR("cgroup_get failed"); TSTERR("cgroup_get failed");
goto err3; goto err3;
} }
if (strcmp(value, "536870912\n")) { if (strcmp(value, "10000\n")) {
TSTERR("cgroup_set_bypath failed to set value >%s<", value); TSTERR("cgroup_set_bypath failed to set value >%s<", value);
goto err3; goto err3;
} }
/* restore original value */ /* restore original value */
ret = cgroup_ops->set(cgroup_ops, "memory.soft_limit_in_bytes", ret = cgroup_ops->set(cgroup_ops, "pids.max",
value_save, c->name, c->config_path); value_save, c->name, c->config_path);
if (ret < 0) { if (ret < 0) {
TSTERR("cgroup_set failed"); TSTERR("cgroup_set failed");
...@@ -123,6 +144,17 @@ err3: ...@@ -123,6 +144,17 @@ err3:
err2: err2:
lxc_container_put(c); lxc_container_put(c);
err1: err1:
if (ret != 0) {
char buf[4096];
ssize_t buflen;
while ((buflen = read(fd_log, buf, 1024)) > 0) {
buflen = write(STDERR_FILENO, buf, buflen);
if (buflen <= 0)
break;
}
}
(void)unlink(template);
return ret; return ret;
} }
......
...@@ -20,14 +20,41 @@ ...@@ -20,14 +20,41 @@
#include <stdlib.h> #include <stdlib.h>
#include <lxc/lxccontainer.h> #include <lxc/lxccontainer.h>
#include "lxctest.h"
#include "memory_utils.h"
#include "utils.h"
#ifndef HAVE_STRLCPY
#include "include/strlcpy.h"
#endif
#define NAME "device_add_remove_test" #define NAME "device_add_remove_test"
#define DEVICE "/dev/loop-control" #define DEVICE "/dev/loop-control"
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
__do_close int fd_log = -EBADF;
int ret = 1; int ret = 1;
struct lxc_log log = {};
char template[sizeof(P_tmpdir"/attach_XXXXXX")];
struct lxc_container *c; struct lxc_container *c;
(void)strlcpy(template, P_tmpdir"/attach_XXXXXX", sizeof(template));
fd_log = lxc_make_tmpfile(template, false);
if (fd_log < 0) {
lxc_error("Failed to create temporary log file for container %s\n", NAME);
exit(EXIT_FAILURE);
}
log.name = NAME;
log.file = template;
log.level = "TRACE";
log.prefix = "device_add_remove";
log.quiet = false;
log.lxcpath = NULL;
if (lxc_log_init(&log))
goto out;
c = lxc_container_new(NAME, NULL); c = lxc_container_new(NAME, NULL);
if (!c) { if (!c) {
fprintf(stderr, "Unable to instantiate container (%s)...\n", NAME); fprintf(stderr, "Unable to instantiate container (%s)...\n", NAME);
...@@ -69,6 +96,17 @@ int main(int argc, char *argv[]) ...@@ -69,6 +96,17 @@ int main(int argc, char *argv[])
ret = 0; ret = 0;
out: out:
if (ret != 0) {
char buf[4096];
ssize_t buflen;
while ((buflen = read(fd_log, buf, 1024)) > 0) {
buflen = write(STDERR_FILENO, buf, buflen);
if (buflen <= 0)
break;
}
}
(void)unlink(template);
lxc_container_put(c); lxc_container_put(c);
return ret; return ret;
} }
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