]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/commands.c
cgroups: handle fallback gracefully
[mirror_lxc.git] / src / lxc / commands.c
CommitLineData
cc73685d 1/* SPDX-License-Identifier: LGPL-2.1+ */
724e753c 2
d38dd64a
CB
3#ifndef _GNU_SOURCE
4#define _GNU_SOURCE 1
5#endif
cf685555 6#include <caps.h>
724e753c 7#include <errno.h>
91480a0f 8#include <fcntl.h>
fe84a562 9#include <malloc.h>
37515ebd 10#include <poll.h>
fe84a562
CB
11#include <signal.h>
12#include <stdio.h>
13#include <stdlib.h>
fe84a562 14#include <sys/param.h>
724e753c
MN
15#include <sys/socket.h>
16#include <sys/un.h>
d38dd64a 17#include <unistd.h>
724e753c 18
fe84a562 19#include "af_unix.h"
5f126977 20#include "cgroups/cgroup.h"
2a63b5cb 21#include "cgroups/cgroup2_devices.h"
724e753c 22#include "commands.h"
bbf5cf35 23#include "commands_utils.h"
fe84a562 24#include "conf.h"
d38dd64a 25#include "config.h"
ef6e34ee 26#include "confile.h"
fe84a562
CB
27#include "log.h"
28#include "lxc.h"
dbc9832d 29#include "lxclock.h"
cdb2a47f 30#include "lxcseccomp.h"
724e753c 31#include "mainloop.h"
5265a60c 32#include "memory_utils.h"
dbc9832d 33#include "monitor.h"
fe84a562 34#include "start.h"
0ed9b1bc 35#include "terminal.h"
fe84a562 36#include "utils.h"
724e753c 37
ded1d23f 38/*
fe84a562
CB
39 * This file provides the different functions for clients to query/command the
40 * server. The client is typically some lxc tool and the server is typically the
41 * container (ie. lxc-start).
ded1d23f 42 *
fe84a562
CB
43 * Each command is transactional, the clients send a request to the server and
44 * the server answers the request with a message giving the request's status
45 * (zero or a negative errno value). Both the request and response may contain
46 * additional data.
ded1d23f 47 *
fe84a562
CB
48 * Each command is wrapped in a ancillary message in order to pass a credential
49 * making possible to the server to check if the client is allowed to ask for
50 * this command or not.
80bcb053 51 *
fe84a562
CB
52 * IMPORTANTLY: Note that semantics for current commands are fixed. If you wish
53 * to make any changes to how, say, LXC_CMD_GET_CONFIG_ITEM works by adding
54 * information to the end of cmd.data, then you must introduce a new
55 * LXC_CMD_GET_CONFIG_ITEM_V2 define with a new number. You may wish to also
56 * mark LXC_CMD_GET_CONFIG_ITEM deprecated in commands.h.
80bcb053
SH
57 *
58 * This is necessary in order to avoid having a newly compiled lxc command
59 * communicating with a running (old) monitor from crashing the running
60 * container.
ded1d23f
DL
61 */
62
ac2cecc4 63lxc_log_define(commands, lxc);
724e753c 64
ef6e34ee 65static const char *lxc_cmd_str(lxc_cmd_t cmd)
724e753c 66{
fe84a562 67 static const char *const cmdname[LXC_CMD_MAX] = {
2a63b5cb
CB
68 [LXC_CMD_CONSOLE] = "console",
69 [LXC_CMD_TERMINAL_WINCH] = "terminal_winch",
70 [LXC_CMD_STOP] = "stop",
71 [LXC_CMD_GET_STATE] = "get_state",
72 [LXC_CMD_GET_INIT_PID] = "get_init_pid",
73 [LXC_CMD_GET_CLONE_FLAGS] = "get_clone_flags",
74 [LXC_CMD_GET_CGROUP] = "get_cgroup",
75 [LXC_CMD_GET_CONFIG_ITEM] = "get_config_item",
76 [LXC_CMD_GET_NAME] = "get_name",
77 [LXC_CMD_GET_LXCPATH] = "get_lxcpath",
78 [LXC_CMD_ADD_STATE_CLIENT] = "add_state_client",
79 [LXC_CMD_CONSOLE_LOG] = "console_log",
80 [LXC_CMD_SERVE_STATE_CLIENTS] = "serve_state_clients",
81 [LXC_CMD_SECCOMP_NOTIFY_ADD_LISTENER] = "seccomp_notify_add_listener",
82 [LXC_CMD_ADD_BPF_DEVICE_CGROUP] = "add_bpf_device_cgroup",
018051e3
CB
83 [LXC_CMD_FREEZE] = "freeze",
84 [LXC_CMD_UNFREEZE] = "unfreeze",
bad788b0 85 [LXC_CMD_GET_CGROUP2_FD] = "get_cgroup2_fd",
746aab51 86 [LXC_CMD_GET_INIT_PIDFD] = "get_init_pidfd",
a900cbaf
WB
87 [LXC_CMD_GET_LIMITING_CGROUP] = "get_limiting_cgroup",
88 [LXC_CMD_GET_LIMITING_CGROUP2_FD] = "get_limiting_cgroup2_fd",
f797f05e 89 [LXC_CMD_GET_DEVPTS_FD] = "get_devpts_fd",
21405769 90 [LXC_CMD_GET_SECCOMP_NOTIFY_FD] = "get_seccomp_notify_fd",
ef6e048a 91 [LXC_CMD_GET_CGROUP_CTX] = "get_cgroup_ctx",
ef6e34ee 92 };
724e753c 93
f371aca9 94 if (cmd >= LXC_CMD_MAX)
a8007512 95 return "Invalid request";
fe84a562 96
ef6e34ee
DE
97 return cmdname[cmd];
98}
99
ef6e048a
CB
100static int __transfer_cgroup_ctx_fds(struct unix_fds *fds, struct cgroup_ctx *ctx)
101{
102 /* This shouldn't be able to happen but better safe than sorry. */
103 if (ctx->fd_len != fds->fd_count_ret ||
104 fds->fd_count_ret > CGROUP_CTX_MAX_FD)
105 return syswarn_set(-EINVAL, "Unexpected number of file descriptors received %u != %u",
106 ctx->fd_len, fds->fd_count_ret);
107
108 memcpy(ctx->fd, fds->fd, ctx->fd_len * sizeof(__s32));
109 fds->fd_count_ret = 0;
110 return 0;
111}
112
ef6e34ee
DE
113/*
114 * lxc_cmd_rsp_recv: Receive a response to a command
115 *
116 * @sock : the socket connected to the container
117 * @cmd : command to put response in
118 *
119 * Returns the size of the response message or < 0 on failure
120 *
121 * Note that if the command response datalen > 0, then data is
122 * a malloc()ed buffer and should be free()ed by the caller. If
123 * the response data is <= a void * worth of data, it will be
124 * stored directly in data and datalen will be 0.
125 *
126 * As a special case, the response for LXC_CMD_CONSOLE is created
36a94ce8 127 * here as it contains an fd for the ptx pty passed through the
0115f8fd 128 * unix socket.
ef6e34ee
DE
129 */
130static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
131{
f8cc4ae8 132 call_cleaner(put_unix_fds) struct unix_fds *fds = &(struct unix_fds){};
ef6e34ee 133 struct lxc_cmd_rsp *rsp = &cmd->rsp;
1454e5d9
CB
134 int cur_cmd = cmd->req.cmd;
135 const char *cur_cmdstr;
00df5330 136 int fret = 0;
f8cc4ae8 137 int ret;
ef6e34ee 138
1454e5d9
CB
139 cur_cmdstr = lxc_cmd_str(cur_cmd);
140 switch (cur_cmd) {
f8cc4ae8
CB
141 case LXC_CMD_GET_CGROUP2_FD:
142 __fallthrough;
143 case LXC_CMD_GET_LIMITING_CGROUP2_FD:
144 __fallthrough;
145 case LXC_CMD_GET_INIT_PIDFD:
146 __fallthrough;
147 case LXC_CMD_GET_SECCOMP_NOTIFY_FD:
148 __fallthrough;
149 case LXC_CMD_GET_DEVPTS_FD:
150 __fallthrough;
151 case LXC_CMD_CONSOLE:
152 fds->fd_count_max = 1;
153 break;
ef6e048a
CB
154 case LXC_CMD_GET_CGROUP_CTX:
155 fds->fd_count_max = CGROUP_CTX_MAX_FD;
f8cc4ae8
CB
156 break;
157 default:
158 fds->fd_count_max = 0;
ef6e048a 159 break;
f8cc4ae8 160 }
d17c815d 161 ret = lxc_abstract_unix_recv_fds(sock, fds, rsp, sizeof(*rsp));
23a917e5 162 if (ret < 0)
1454e5d9 163 return syserrno(ret, "Failed to receive response for command \"%s\"", cur_cmdstr);
00df5330
CB
164
165 if (fds->fd_count_max == 0) {
1454e5d9 166 TRACE("Command \"%s\" received response with %u file descriptors", cur_cmdstr, fds->fd_count_ret);
00df5330 167 } else if (fds->fd_count_ret == 0) {
1454e5d9 168 WARN("Command \"%s\" received response without expected file descriptors", cur_cmdstr);
00df5330
CB
169 fret = -EBADF;
170 }
ef6e34ee 171
1454e5d9 172 if (cur_cmd == LXC_CMD_CONSOLE) {
ef6e34ee
DE
173 struct lxc_cmd_console_rsp_data *rspdata;
174
0115f8fd
DE
175 /* recv() returns 0 bytes when a tty cannot be allocated,
176 * rsp->ret is < 0 when the peer permission check failed
177 */
178 if (ret == 0 || rsp->ret < 0)
179 return 0;
180
ef6e34ee 181 rspdata = malloc(sizeof(*rspdata));
23a917e5 182 if (!rspdata)
5dc24a8c 183 return syserrno_set(fret ?: -ENOMEM, "Failed to receive response for command \"%s\"", cur_cmdstr);
2a850b2c 184
d17c815d 185 rspdata->ptxfd = move_fd(fds->fd[0]);
ef6e34ee
DE
186 rspdata->ttynum = PTR_TO_INT(rsp->data);
187 rsp->data = rspdata;
188 }
189
1454e5d9 190 switch (cur_cmd) {
2092492c
CB
191 case LXC_CMD_GET_CGROUP2_FD:
192 __fallthrough;
193 case LXC_CMD_GET_LIMITING_CGROUP2_FD:
194 __fallthrough;
195 case LXC_CMD_GET_INIT_PIDFD:
196 __fallthrough;
197 case LXC_CMD_GET_DEVPTS_FD:
198 __fallthrough;
199 case LXC_CMD_GET_SECCOMP_NOTIFY_FD:
200 rsp->data = INT_TO_PTR(move_fd(fds->fd[0]));
1454e5d9 201 return log_debug(fret ?: ret, "Finished processing \"%s\"", cur_cmdstr);
ef6e048a 202 case LXC_CMD_GET_CGROUP_CTX:
7ec5eee4 203 if ((rsp->datalen == 0) || (rsp->datalen > sizeof(struct cgroup_ctx)))
1454e5d9 204 return syserrno_set(fret ?: -EINVAL, "Invalid response size from server for \"%s\"", cur_cmdstr);
ef6e048a
CB
205
206 /* Don't pointlessly allocate. */
207 rsp->data = (void *)cmd->req.data;
2092492c
CB
208 break;
209 default:
210 break;
21405769
CB
211 }
212
23a917e5 213 if (rsp->datalen == 0)
1454e5d9 214 return log_debug(fret ?: ret, "Response data length for command \"%s\" is 0", cur_cmdstr);
23a917e5 215
191d43cc 216 if ((rsp->datalen > LXC_CMD_DATA_MAX) &&
1454e5d9 217 (cur_cmd != LXC_CMD_CONSOLE_LOG))
5dc24a8c 218 return syserrno_set(fret ?: -E2BIG, "Response data for command \"%s\" is too long: %d bytes > %d",
1454e5d9 219 cur_cmdstr, rsp->datalen, LXC_CMD_DATA_MAX);
ef6e34ee 220
1454e5d9 221 if (cur_cmd == LXC_CMD_CONSOLE_LOG)
ef6e048a 222 rsp->data = zalloc(rsp->datalen + 1);
1454e5d9 223 else if (cur_cmd != LXC_CMD_GET_CGROUP_CTX)
191d43cc 224 rsp->data = malloc(rsp->datalen);
23a917e5 225 if (!rsp->data)
5dc24a8c 226 return syserrno_set(fret ?: -ENOMEM, "Failed to allocate response buffer for command \"%s\"", cur_cmdstr);
fe84a562 227
2a850b2c 228 ret = lxc_recv_nointr(sock, rsp->data, rsp->datalen, 0);
23a917e5 229 if (ret != rsp->datalen)
1454e5d9 230 return syserrno(-errno, "Failed to receive response data for command \"%s\"", cur_cmdstr);
ef6e048a 231
1454e5d9 232 if (cur_cmd == LXC_CMD_GET_CGROUP_CTX) {
ef6e048a
CB
233 ret = __transfer_cgroup_ctx_fds(fds, rsp->data);
234 if (ret < 0)
1454e5d9 235 return syserrno(ret, "Failed to transfer file descriptors for \"%s\"", cur_cmdstr);
ef6e048a 236 }
724e753c 237
00df5330 238 return fret ?: ret;
724e753c
MN
239}
240
ef6e34ee
DE
241/*
242 * lxc_cmd_rsp_send: Send a command response
243 *
244 * @fd : file descriptor of socket to send response on
245 * @rsp : response to send
246 *
247 * Returns 0 on success, < 0 on failure
248 */
4b5f4bdc 249static int __lxc_cmd_rsp_send(int fd, struct lxc_cmd_rsp *rsp)
ef6e34ee 250{
fe84a562 251 ssize_t ret;
ef6e34ee 252
7fbb15ec 253 ret = lxc_send_nointr(fd, rsp, sizeof(*rsp), MSG_NOSIGNAL);
6c6497ea 254 if (ret < 0 || (size_t)ret != sizeof(*rsp))
4b5f4bdc 255 return syserrno(-errno, "Failed to send command response %zd", ret);
ef6e34ee 256
a674dfe1 257 if (!rsp->data || rsp->datalen <= 0)
fe84a562
CB
258 return 0;
259
7fbb15ec 260 ret = lxc_send_nointr(fd, rsp->data, rsp->datalen, MSG_NOSIGNAL);
6c6497ea 261 if (ret < 0 || ret != (ssize_t)rsp->datalen)
4b5f4bdc 262 return syswarn(-errno, "Failed to send command response %zd", ret);
fe84a562 263
ef6e34ee
DE
264 return 0;
265}
266
4b5f4bdc
CB
267static inline int lxc_cmd_rsp_send_reap(int fd, struct lxc_cmd_rsp *rsp)
268{
269 int ret;
270
271 ret = __lxc_cmd_rsp_send(fd, rsp);
272 if (ret < 0)
273 return ret;
274
275 return LXC_CMD_REAP_CLIENT_FD;
276}
277
254a22e1
CB
278static inline int lxc_cmd_rsp_send_keep(int fd, struct lxc_cmd_rsp *rsp)
279{
280 int ret;
281
282 ret = __lxc_cmd_rsp_send(fd, rsp);
283 if (ret < 0)
284 return ret;
285
286 return 0;
287}
288
c2f40088
CB
289static inline int rsp_one_fd(int fd, int fd_send, struct lxc_cmd_rsp *rsp)
290{
291 int ret;
292
293 ret = lxc_abstract_unix_send_fds(fd, &fd_send, 1, rsp, sizeof(*rsp));
294 if (ret < 0)
295 return ret;
296
297 return LXC_CMD_REAP_CLIENT_FD;
298}
299
ef6e048a
CB
300static inline int rsp_many_fds(int fd, __u32 fds_len,
301 const __s32 fds[KERNEL_SCM_MAX_FD],
302 struct lxc_cmd_rsp *rsp)
9c3eb8d5 303{
ef6e048a
CB
304 ssize_t ret;
305
306 if (fds_len > KERNEL_SCM_MAX_FD) {
307 rsp->ret = -E2BIG;
308 return lxc_cmd_rsp_send_reap(fd, rsp);
309 } else if (fds_len == 0) {
310 rsp->ret = -ENOENT;
311 return lxc_cmd_rsp_send_reap(fd, rsp);
312 }
9c3eb8d5 313
ef6e048a 314 ret = lxc_abstract_unix_send_fds(fd, fds, fds_len, rsp, sizeof(*rsp));
9c3eb8d5
CB
315 if (ret < 0)
316 return ret;
317
ef6e048a
CB
318 if (rsp->data && rsp->datalen > 0) {
319 ret = lxc_send_nointr(fd, rsp->data, rsp->datalen, MSG_NOSIGNAL);
320 if (ret < 0 || ret != (ssize_t)rsp->datalen)
321 return syswarn(-errno, "Failed to send command response %zd", ret);
322 }
323
9c3eb8d5
CB
324 return LXC_CMD_REAP_CLIENT_FD;
325}
326
c01c2be6 327static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd,
fe84a562 328 const char *lxcpath, const char *hashed_sock_name)
c01c2be6 329{
f62cf1d4 330 __do_close int client_fd = -EBADF;
fe84a562 331 ssize_t ret = -1;
c01c2be6 332
9dfa4041 333 client_fd = lxc_cmd_connect(name, lxcpath, hashed_sock_name, "command");
2a850b2c 334 if (client_fd < 0)
fe84a562 335 return -1;
c01c2be6 336
fe84a562
CB
337 ret = lxc_abstract_unix_send_credential(client_fd, &cmd->req,
338 sizeof(cmd->req));
2a850b2c 339 if (ret < 0 || (size_t)ret != sizeof(cmd->req))
e96f9291 340 return -1;
9044b79e 341
cdb2a47f
CB
342 if (cmd->req.cmd == LXC_CMD_SECCOMP_NOTIFY_ADD_LISTENER) {
343 int notify_fd = PTR_TO_INT(cmd->req.data);
344 ret = lxc_abstract_unix_send_fds(client_fd, &notify_fd, 1, NULL, 0);
345 if (ret <= 0)
346 return -1;
347 } else {
348 if (cmd->req.datalen <= 0)
349 return move_fd(client_fd);
c01c2be6 350
cdb2a47f
CB
351 errno = EMSGSIZE;
352 ret = lxc_send_nointr(client_fd, (void *)cmd->req.data,
353 cmd->req.datalen, MSG_NOSIGNAL);
354 if (ret < 0 || ret != (ssize_t)cmd->req.datalen)
355 return -1;
356 }
c01c2be6 357
240fecd0 358 return move_fd(client_fd);
c01c2be6
CB
359}
360
ef6e34ee
DE
361/*
362 * lxc_cmd: Connect to the specified running container, send it a command
363 * request and collect the response
364 *
365 * @name : name of container to connect to
1e8cfdf6 366 * @cmd : command with initialized request to send
ef6e34ee
DE
367 * @stopped : output indicator if the container was not running
368 * @lxcpath : the lxcpath in which the container is running
369 *
370 * Returns the size of the response message on success, < 0 on failure
371 *
372 * Note that there is a special case for LXC_CMD_CONSOLE. For this command
373 * the fd cannot be closed because it is used as a placeholder to indicate
374 * that a particular tty slot is in use. The fd is also used as a signal to
375 * the container that when the caller dies or closes the fd, the container
0115f8fd
DE
376 * will notice the fd on its side of the socket in its mainloop select and
377 * then free the slot with lxc_cmd_fd_cleanup(). The socket fd will be
378 * returned in the cmd response structure.
ef6e34ee
DE
379 */
380static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped,
88556fd7 381 const char *lxcpath, const char *hashed_sock_name)
724e753c 382{
f62cf1d4 383 __do_close int client_fd = -EBADF;
fe84a562 384 int ret = -1;
dbc9832d
CB
385 bool stay_connected = false;
386
387 if (cmd->req.cmd == LXC_CMD_CONSOLE ||
54446942 388 cmd->req.cmd == LXC_CMD_ADD_STATE_CLIENT)
dbc9832d 389 stay_connected = true;
724e753c 390
0ecf64b5
SH
391 *stopped = 0;
392
c01c2be6
CB
393 client_fd = lxc_cmd_send(name, cmd, lxcpath, hashed_sock_name);
394 if (client_fd < 0) {
00e5ca13 395 if (errno == ECONNREFUSED || errno == EPIPE)
ef6e34ee 396 *stopped = 1;
3f903c04 397
6c6497ea
CB
398 return log_trace_errno(-1, errno, "Command \"%s\" failed to connect command socket",
399 lxc_cmd_str(cmd->req.cmd));
724e753c
MN
400 }
401
c01c2be6 402 ret = lxc_cmd_rsp_recv(client_fd, cmd);
2a850b2c 403 if (ret < 0 && errno == ECONNRESET)
6b7f85cb 404 *stopped = 1;
6a93ae77 405
ea2a070b
CB
406 TRACE("Opened new command socket connection fd %d for command \"%s\"",
407 client_fd, lxc_cmd_str(cmd->req.cmd));
408
c34ff119 409 if (stay_connected && ret > 0)
240fecd0 410 cmd->rsp.ret = move_fd(client_fd);
43eb6f29 411
1362f2eb 412 return ret;
724e753c
MN
413}
414
b494d2dd
SH
415int lxc_try_cmd(const char *name, const char *lxcpath)
416{
0ecf64b5 417 int stopped, ret;
b494d2dd
SH
418 struct lxc_cmd_rr cmd = {
419 .req = { .cmd = LXC_CMD_GET_INIT_PID },
420 };
421
88556fd7 422 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
b494d2dd
SH
423 if (stopped)
424 return 0;
425 if (ret > 0 && cmd.rsp.ret < 0) {
426 errno = cmd.rsp.ret;
427 return -1;
428 }
429 if (ret > 0)
430 return 0;
431
fe84a562
CB
432 /* At this point we weren't denied access, and the container *was*
433 * started. There was some inexplicable error in the protocol. I'm not
434 * clear on whether we should return -1 here, but we didn't receive a
435 * -EACCES, so technically it's not that we're not allowed to control
436 * the container - it's just not behaving.
b494d2dd
SH
437 */
438 return 0;
439}
440
e6bc68d6
WB
441/*
442 * Validate that the input is a proper string parameter. If not,
443 * send an EINVAL response and return -1.
444 *
445 * Precondition: there is non-zero-length data available.
446 */
447static int validate_string_request(int fd, const struct lxc_cmd_req *req)
448{
e6bc68d6
WB
449 size_t maxlen = req->datalen - 1;
450 const char *data = req->data;
451
452 if (data[maxlen] == 0 && strnlen(data, maxlen) == maxlen)
453 return 0;
454
455 struct lxc_cmd_rsp rsp = {
da63ea6b
CB
456 .ret = -EINVAL,
457 .datalen = 0,
458 .data = NULL,
e6bc68d6
WB
459 };
460
4b5f4bdc 461 return lxc_cmd_rsp_send_reap(fd, &rsp);
e6bc68d6
WB
462}
463
cc4c0832 464/* Implementations of the commands and their callbacks */
ef6e34ee
DE
465
466/*
467 * lxc_cmd_get_init_pid: Get pid of the container's init process
468 *
469 * @name : name of container to connect to
470 * @lxcpath : the lxcpath in which the container is running
471 *
472 * Returns the pid on success, < 0 on failure
473 */
474pid_t lxc_cmd_get_init_pid(const char *name, const char *lxcpath)
43eb6f29 475{
0ecf64b5 476 int ret, stopped;
565eb353 477 pid_t pid = -1;
ef6e34ee 478 struct lxc_cmd_rr cmd = {
e8cd1208
CB
479 .req = {
480 .cmd = LXC_CMD_GET_INIT_PID
481 },
482 .rsp = {
565eb353 483 .data = PID_TO_PTR(pid)
e8cd1208 484 }
ef6e34ee
DE
485 };
486
88556fd7 487 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
ef6e34ee 488 if (ret < 0)
8ed8a626 489 return -1;
ef6e34ee 490
565eb353 491 pid = PTR_TO_PID(cmd.rsp.data);
9234406b
CB
492 if (pid < 0)
493 return -1;
494
495 /* We need to assume that pid_t can actually hold any pid given to us
496 * by the kernel. If it can't it's a libc bug.
497 */
498 return (pid_t)pid;
43eb6f29
DL
499}
500
ef6e34ee 501static int lxc_cmd_get_init_pid_callback(int fd, struct lxc_cmd_req *req,
cdb2a47f
CB
502 struct lxc_handler *handler,
503 struct lxc_epoll_descr *descr)
43eb6f29 504{
9234406b 505 struct lxc_cmd_rsp rsp = {
4b5f4bdc 506 .data = PID_TO_PTR(handler->pid),
9234406b 507 };
ef6e34ee 508
4b5f4bdc 509 return lxc_cmd_rsp_send_reap(fd, &rsp);
43eb6f29
DL
510}
511
746aab51
CB
512int lxc_cmd_get_init_pidfd(const char *name, const char *lxcpath)
513{
8a95cd82 514 int pidfd;
746aab51
CB
515 int ret, stopped;
516 struct lxc_cmd_rr cmd = {
517 .req = {
518 .cmd = LXC_CMD_GET_INIT_PIDFD,
519 },
8a95cd82
CB
520 .rsp = {
521 .data = INT_TO_PTR(-EBADF),
522 .ret = ENOSYS,
523 },
746aab51
CB
524 };
525
526 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
527 if (ret < 0)
528 return log_debug_errno(-1, errno, "Failed to process init pidfd command");
529
530 if (cmd.rsp.ret < 0)
8a95cd82 531 return syserrno_set(cmd.rsp.ret, "Failed to receive init pidfd");
746aab51 532
8a95cd82
CB
533 pidfd = PTR_TO_INT(cmd.rsp.data);
534 if (pidfd < 0)
535 return syserrno_set(pidfd, "Failed to receive init pidfd");
536
537 return pidfd;
746aab51
CB
538}
539
540static int lxc_cmd_get_init_pidfd_callback(int fd, struct lxc_cmd_req *req,
541 struct lxc_handler *handler,
542 struct lxc_epoll_descr *descr)
543{
544 struct lxc_cmd_rsp rsp = {
4b5f4bdc 545 .ret = -EBADF,
746aab51 546 };
746aab51
CB
547
548 if (handler->pidfd < 0)
4b5f4bdc
CB
549 return lxc_cmd_rsp_send_reap(fd, &rsp);
550
551 rsp.ret = 0;
c2f40088 552 return rsp_one_fd(fd, handler->pidfd, &rsp);
746aab51
CB
553}
554
f797f05e
CB
555int lxc_cmd_get_devpts_fd(const char *name, const char *lxcpath)
556{
557 int ret, stopped;
558 struct lxc_cmd_rr cmd = {
559 .req = {
560 .cmd = LXC_CMD_GET_DEVPTS_FD,
561 },
562 };
563
564 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
565 if (ret < 0)
566 return log_debug_errno(-1, errno, "Failed to process devpts fd command");
567
568 if (cmd.rsp.ret < 0)
569 return log_debug_errno(-EBADF, errno, "Failed to receive devpts fd");
570
571 return PTR_TO_INT(cmd.rsp.data);
572}
573
574static int lxc_cmd_get_devpts_fd_callback(int fd, struct lxc_cmd_req *req,
575 struct lxc_handler *handler,
576 struct lxc_epoll_descr *descr)
577{
578 struct lxc_cmd_rsp rsp = {
4b5f4bdc 579 .ret = -EBADF,
f797f05e 580 };
f797f05e 581
4b5f4bdc
CB
582 if (!handler->conf || handler->conf->devpts_fd < 0)
583 return lxc_cmd_rsp_send_reap(fd, &rsp);
584
585 rsp.ret = 0;
c2f40088 586 return rsp_one_fd(fd, handler->conf->devpts_fd, &rsp);
f797f05e
CB
587}
588
21405769
CB
589int lxc_cmd_get_seccomp_notify_fd(const char *name, const char *lxcpath)
590{
a342b11f 591#ifdef HAVE_SECCOMP_NOTIFY
21405769
CB
592 int ret, stopped;
593 struct lxc_cmd_rr cmd = {
594 .req = {
595 .cmd = LXC_CMD_GET_SECCOMP_NOTIFY_FD,
596 },
597 };
598
599 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
600 if (ret < 0)
601 return log_debug_errno(-1, errno, "Failed to process seccomp notify fd command");
602
603 if (cmd.rsp.ret < 0)
604 return log_debug_errno(-EBADF, errno, "Failed to receive seccomp notify fd");
605
606 return PTR_TO_INT(cmd.rsp.data);
607#else
608 return ret_errno(EOPNOTSUPP);
609#endif
610}
611
612static int lxc_cmd_get_seccomp_notify_fd_callback(int fd, struct lxc_cmd_req *req,
613 struct lxc_handler *handler,
614 struct lxc_epoll_descr *descr)
615{
a342b11f 616#ifdef HAVE_SECCOMP_NOTIFY
21405769 617 struct lxc_cmd_rsp rsp = {
4b5f4bdc 618 .ret = -EBADF,
21405769 619 };
21405769
CB
620
621 if (!handler->conf || handler->conf->seccomp.notifier.notify_fd < 0)
4b5f4bdc
CB
622 return lxc_cmd_rsp_send_reap(fd, &rsp);
623
624 rsp.ret = 0;
c2f40088 625 return rsp_one_fd(fd, handler->conf->seccomp.notifier.notify_fd, &rsp);
21405769 626#else
4b5f4bdc 627 return syserrno_set(-EOPNOTSUPP, "Seccomp notifier not supported");
21405769
CB
628#endif
629}
630
ef6e048a
CB
631int lxc_cmd_get_cgroup_ctx(const char *name, const char *lxcpath,
632 const char *controller, bool batch,
633 size_t size_ret_ctx, struct cgroup_ctx *ret_ctx)
9c3eb8d5 634{
9c3eb8d5
CB
635 struct lxc_cmd_rr cmd = {
636 .req = {
ef6e048a
CB
637 .cmd = LXC_CMD_GET_CGROUP_CTX,
638 .datalen = size_ret_ctx,
639 .data = ret_ctx,
9c3eb8d5 640 },
d3be623e
CB
641 .rsp = {
642 .ret = -ENOSYS,
643 },
9c3eb8d5 644 };
ef6e048a 645 int ret, stopped;
9c3eb8d5
CB
646
647 if (batch && !is_empty_string(controller))
648 return ret_errno(EINVAL);
649
650 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
651 if (ret < 0)
d3be623e 652 return log_debug_errno(-1, errno, "Failed to process cgroup context command");
9c3eb8d5
CB
653
654 if (cmd.rsp.ret < 0)
655 return log_debug_errno(-EBADF, errno, "Failed to receive cgroup fds");
656
657 return 0;
658}
659
ef6e048a
CB
660static int lxc_cmd_get_cgroup_ctx_callback(int fd, struct lxc_cmd_req *req,
661 struct lxc_handler *handler,
662 struct lxc_epoll_descr *descr)
9c3eb8d5 663{
f8cc4ae8 664 struct lxc_cmd_rsp rsp = {
ef6e048a 665 .ret = EINVAL,
f8cc4ae8 666 };
9c3eb8d5 667 struct cgroup_ops *cgroup_ops = handler->cgroup_ops;
ef6e048a 668 struct cgroup_ctx ctx_server = {};
f8cc4ae8
CB
669 int ret;
670
ef6e048a
CB
671 ret = copy_struct_from_client(sizeof(struct cgroup_ctx), &ctx_server,
672 req->datalen, req->data);
f8cc4ae8 673 if (ret < 0)
ef6e048a
CB
674 return lxc_cmd_rsp_send_reap(fd, &rsp);
675
676 ret = prepare_cgroup_ctx(cgroup_ops, &ctx_server);
677 if (ret < 0) {
678 rsp.ret = ret;
679 return lxc_cmd_rsp_send_reap(fd, &rsp);
680 }
9c3eb8d5 681
ef6e048a
CB
682 rsp.data = &ctx_server;
683 rsp.datalen = min(sizeof(struct cgroup_ctx), (size_t)req->datalen);
684 return rsp_many_fds(fd, ctx_server.fd_len, ctx_server.fd, &rsp);
9c3eb8d5
CB
685}
686
ef6e34ee
DE
687/*
688 * lxc_cmd_get_clone_flags: Get clone flags container was spawned with
689 *
690 * @name : name of container to connect to
691 * @lxcpath : the lxcpath in which the container is running
692 *
693 * Returns the clone flags on success, < 0 on failure
694 */
695int lxc_cmd_get_clone_flags(const char *name, const char *lxcpath)
696{
0ecf64b5 697 int ret, stopped;
ef6e34ee 698 struct lxc_cmd_rr cmd = {
6c6497ea
CB
699 .req = {
700 .cmd = LXC_CMD_GET_CLONE_FLAGS,
701 },
ef6e34ee
DE
702 };
703
88556fd7 704 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
ef6e34ee
DE
705 if (ret < 0)
706 return ret;
43eb6f29 707
ef6e34ee
DE
708 return PTR_TO_INT(cmd.rsp.data);
709}
710
711static int lxc_cmd_get_clone_flags_callback(int fd, struct lxc_cmd_req *req,
cdb2a47f
CB
712 struct lxc_handler *handler,
713 struct lxc_epoll_descr *descr)
26b2d152 714{
6c6497ea
CB
715 struct lxc_cmd_rsp rsp = {
716 .data = INT_TO_PTR(handler->ns_clone_flags),
717 };
ef6e34ee 718
4b5f4bdc 719 return lxc_cmd_rsp_send_reap(fd, &rsp);
ef6e34ee
DE
720}
721
a900cbaf
WB
722static char *lxc_cmd_get_cgroup_path_do(const char *name, const char *lxcpath,
723 const char *subsystem,
724 lxc_cmd_t command)
ef6e34ee 725{
0ecf64b5 726 int ret, stopped;
ef6e34ee 727 struct lxc_cmd_rr cmd = {
b98f7d6e 728 .req = {
a900cbaf 729 .cmd = command,
b98f7d6e 730 .data = subsystem,
c2aed66d 731 .datalen = 0,
b98f7d6e 732 },
26b2d152
MN
733 };
734
c2aed66d
CB
735 cmd.req.data = subsystem;
736 cmd.req.datalen = 0;
737 if (subsystem)
738 cmd.req.datalen = strlen(subsystem) + 1;
739
88556fd7 740 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
fe84a562 741 if (ret < 0)
ef6e34ee
DE
742 return NULL;
743
400d579e
WB
744 if (ret == 0) {
745 if (command == LXC_CMD_GET_LIMITING_CGROUP) {
746 /*
747 * This may indicate that the container was started
748 * under an ealier version before
749 * `cgroup_advanced_isolation` as implemented, there
750 * it sees an unknown command and just closes the
751 * socket, sending us an EOF.
752 */
753 return lxc_cmd_get_cgroup_path_do(name, lxcpath,
754 subsystem,
755 LXC_CMD_GET_CGROUP);
756 }
ef6e34ee 757 return NULL;
400d579e 758 }
ef6e34ee 759
fe84a562 760 if (cmd.rsp.ret < 0 || cmd.rsp.datalen < 0)
ef6e34ee 761 return NULL;
3f903c04 762
ef6e34ee
DE
763 return cmd.rsp.data;
764}
765
a900cbaf
WB
766/*
767 * lxc_cmd_get_cgroup_path: Calculate a container's cgroup path for a
768 * particular subsystem. This is the cgroup path relative to the root
769 * of the cgroup filesystem.
770 *
771 * @name : name of container to connect to
772 * @lxcpath : the lxcpath in which the container is running
773 * @subsystem : the subsystem being asked about
774 *
775 * Returns the path on success, NULL on failure. The caller must free() the
776 * returned path.
777 */
778char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
779 const char *subsystem)
780{
781 return lxc_cmd_get_cgroup_path_do(name, lxcpath, subsystem,
782 LXC_CMD_GET_CGROUP);
783}
784
785/*
786 * lxc_cmd_get_limiting_cgroup_path: Calculate a container's limiting cgroup
787 * path for a particular subsystem. This is the cgroup path relative to the
788 * root of the cgroup filesystem. This may be the same as the path returned by
789 * lxc_cmd_get_cgroup_path if the container doesn't have a limiting path prefix
790 * set.
791 *
792 * @name : name of container to connect to
793 * @lxcpath : the lxcpath in which the container is running
794 * @subsystem : the subsystem being asked about
795 *
796 * Returns the path on success, NULL on failure. The caller must free() the
797 * returned path.
798 */
799char *lxc_cmd_get_limiting_cgroup_path(const char *name, const char *lxcpath,
800 const char *subsystem)
801{
802 return lxc_cmd_get_cgroup_path_do(name, lxcpath, subsystem,
803 LXC_CMD_GET_LIMITING_CGROUP);
804}
805
806static int lxc_cmd_get_cgroup_callback_do(int fd, struct lxc_cmd_req *req,
807 struct lxc_handler *handler,
808 struct lxc_epoll_descr *descr,
809 bool limiting_cgroup)
ef6e34ee 810{
ea2a070b 811 int ret;
4fb3cba5 812 const char *path;
a900cbaf 813 const void *reqdata;
fe84a562 814 struct lxc_cmd_rsp rsp;
2202afc9 815 struct cgroup_ops *cgroup_ops = handler->cgroup_ops;
a900cbaf 816 const char *(*get_fn)(struct cgroup_ops *ops, const char *controller);
b98f7d6e 817
e6bc68d6
WB
818 if (req->datalen > 0) {
819 ret = validate_string_request(fd, req);
820 if (ret != 0)
821 return ret;
a900cbaf 822 reqdata = req->data;
e6bc68d6 823 } else {
a900cbaf 824 reqdata = NULL;
e6bc68d6 825 }
a900cbaf 826
29d652a9
WB
827 get_fn = (limiting_cgroup ? cgroup_ops->get_limiting_cgroup
828 : cgroup_ops->get_cgroup);
a900cbaf
WB
829
830 path = get_fn(cgroup_ops, reqdata);
831
b98f7d6e
SH
832 if (!path)
833 return -1;
fe84a562 834
4f17323e 835 rsp.ret = 0;
fe84a562
CB
836 rsp.datalen = strlen(path) + 1;
837 rsp.data = (char *)path;
ef6e34ee 838
4b5f4bdc 839 return lxc_cmd_rsp_send_reap(fd, &rsp);
ef6e34ee
DE
840}
841
a900cbaf
WB
842static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
843 struct lxc_handler *handler,
844 struct lxc_epoll_descr *descr)
845{
846 return lxc_cmd_get_cgroup_callback_do(fd, req, handler, descr, false);
847}
848
849static int lxc_cmd_get_limiting_cgroup_callback(int fd, struct lxc_cmd_req *req,
850 struct lxc_handler *handler,
851 struct lxc_epoll_descr *descr)
852{
853 return lxc_cmd_get_cgroup_callback_do(fd, req, handler, descr, true);
854}
855
ef6e34ee
DE
856/*
857 * lxc_cmd_get_config_item: Get config item the running container
858 *
859 * @name : name of container to connect to
7fa3f2e9 860 * @item : the configuration item to retrieve (ex: lxc.net.0.veth.pair)
ef6e34ee
DE
861 * @lxcpath : the lxcpath in which the container is running
862 *
863 * Returns the item on success, NULL on failure. The caller must free() the
864 * returned item.
865 */
866char *lxc_cmd_get_config_item(const char *name, const char *item,
867 const char *lxcpath)
868{
0ecf64b5 869 int ret, stopped;
ef6e34ee
DE
870 struct lxc_cmd_rr cmd = {
871 .req = { .cmd = LXC_CMD_GET_CONFIG_ITEM,
872 .data = item,
fe84a562 873 .datalen = strlen(item) + 1,
ef6e34ee
DE
874 },
875 };
876
88556fd7 877 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
ef6e34ee
DE
878 if (ret < 0)
879 return NULL;
880
881 if (cmd.rsp.ret == 0)
882 return cmd.rsp.data;
fe84a562 883
ef6e34ee
DE
884 return NULL;
885}
886
887static int lxc_cmd_get_config_item_callback(int fd, struct lxc_cmd_req *req,
cdb2a47f
CB
888 struct lxc_handler *handler,
889 struct lxc_epoll_descr *descr)
ef6e34ee 890{
5265a60c 891 __do_free char *cidata = NULL;
ef6e34ee 892 int cilen;
30aec088 893 struct lxc_config_t *item;
fe84a562 894 struct lxc_cmd_rsp rsp;
ef6e34ee
DE
895
896 memset(&rsp, 0, sizeof(rsp));
300df83e 897 item = lxc_get_config(req->data);
30aec088
CB
898 if (!item)
899 goto err1;
fe84a562 900
cccd2219 901 cilen = item->get(req->data, NULL, 0, handler->conf, NULL);
ef6e34ee
DE
902 if (cilen <= 0)
903 goto err1;
904
5265a60c 905 cidata = must_realloc(NULL, cilen + 1);
cccd2219 906 if (item->get(req->data, cidata, cilen + 1, handler->conf, NULL) != cilen)
ef6e34ee 907 goto err1;
fe84a562 908
ef6e34ee
DE
909 cidata[cilen] = '\0';
910 rsp.data = cidata;
911 rsp.datalen = cilen + 1;
912 rsp.ret = 0;
913 goto out;
914
915err1:
916 rsp.ret = -1;
917out:
4b5f4bdc 918 return lxc_cmd_rsp_send_reap(fd, &rsp);
ef6e34ee
DE
919}
920
921/*
922 * lxc_cmd_get_state: Get current state of the container
923 *
924 * @name : name of container to connect to
925 * @lxcpath : the lxcpath in which the container is running
926 *
927 * Returns the state on success, < 0 on failure
928 */
dbc9832d 929int lxc_cmd_get_state(const char *name, const char *lxcpath)
ef6e34ee 930{
0ecf64b5 931 int ret, stopped;
ef6e34ee 932 struct lxc_cmd_rr cmd = {
6c6497ea
CB
933 .req = {
934 .cmd = LXC_CMD_GET_STATE,
935 },
ef6e34ee 936 };
26b2d152 937
88556fd7 938 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
ebdd307d 939 if (ret < 0 && stopped)
ef6e34ee
DE
940 return STOPPED;
941
942 if (ret < 0)
26b2d152 943 return -1;
26b2d152 944
6c6497ea
CB
945 if (!ret)
946 return log_warn(-1, "Container \"%s\" has stopped before sending its state", name);
fe84a562 947
6c6497ea
CB
948 return log_debug(PTR_TO_INT(cmd.rsp.data),
949 "Container \"%s\" is in \"%s\" state", name,
950 lxc_state2str(PTR_TO_INT(cmd.rsp.data)));
ef6e34ee
DE
951}
952
953static int lxc_cmd_get_state_callback(int fd, struct lxc_cmd_req *req,
cdb2a47f
CB
954 struct lxc_handler *handler,
955 struct lxc_epoll_descr *descr)
ef6e34ee 956{
6c6497ea
CB
957 struct lxc_cmd_rsp rsp = {
958 .data = INT_TO_PTR(handler->state),
959 };
ef6e34ee 960
4b5f4bdc 961 return lxc_cmd_rsp_send_reap(fd, &rsp);
ef6e34ee
DE
962}
963
964/*
965 * lxc_cmd_stop: Stop the container previously started with lxc_start. All
966 * the processes running inside this container will be killed.
967 *
968 * @name : name of container to connect to
969 * @lxcpath : the lxcpath in which the container is running
970 *
971 * Returns 0 on success, < 0 on failure
972 */
973int lxc_cmd_stop(const char *name, const char *lxcpath)
974{
0ecf64b5 975 int ret, stopped;
ef6e34ee 976 struct lxc_cmd_rr cmd = {
6c6497ea
CB
977 .req = {
978 .cmd = LXC_CMD_STOP,
979 },
ef6e34ee
DE
980 };
981
88556fd7 982 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
26b2d152 983 if (ret < 0) {
6c6497ea
CB
984 if (stopped)
985 return log_info(0, "Container \"%s\" is already stopped", name);
fe84a562 986
26b2d152
MN
987 return -1;
988 }
989
fe84a562
CB
990 /* We do not expect any answer, because we wait for the connection to be
991 * closed.
95d5b147 992 */
6c6497ea
CB
993 if (ret > 0)
994 return log_error_errno(-1, -cmd.rsp.ret, "Failed to stop container \"%s\"", name);
26b2d152 995
6c6497ea 996 return log_info(0, "Container \"%s\" has stopped", name);
26b2d152
MN
997}
998
ef6e34ee 999static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req,
cdb2a47f
CB
1000 struct lxc_handler *handler,
1001 struct lxc_epoll_descr *descr)
d5088cf2 1002{
ef6e34ee 1003 struct lxc_cmd_rsp rsp;
ef6e34ee 1004 int stopsignal = SIGKILL;
2202afc9 1005 struct cgroup_ops *cgroup_ops = handler->cgroup_ops;
ea2a070b 1006 int ret;
ef6e34ee
DE
1007
1008 if (handler->conf->stopsignal)
1009 stopsignal = handler->conf->stopsignal;
1010 memset(&rsp, 0, sizeof(rsp));
9837ee46 1011
8ad4fa68 1012 if (handler->pidfd >= 0)
9837ee46
CB
1013 rsp.ret = lxc_raw_pidfd_send_signal(handler->pidfd, stopsignal, NULL, 0);
1014 else
1015 rsp.ret = kill(handler->pid, stopsignal);
ef6e34ee 1016 if (!rsp.ret) {
9837ee46
CB
1017 if (handler->pidfd >= 0)
1018 TRACE("Sent signal %d to pidfd %d", stopsignal, handler->pidfd);
1019 else
1020 TRACE("Sent signal %d to pidfd %d", stopsignal, handler->pid);
1021
9d47970b 1022 if (pure_unified_layout(cgroup_ops))
c0af7b1c 1023 ret = __cgroup_unfreeze(cgroup_ops->unified->dfd_lim, -1);
9d47970b
CB
1024 else
1025 ret = cgroup_ops->unfreeze(cgroup_ops, -1);
8db8adea
CB
1026 if (ret)
1027 WARN("Failed to unfreeze container \"%s\"", handler->name);
fe84a562 1028
8db8adea 1029 return 0;
018051e3
CB
1030 } else {
1031 rsp.ret = -errno;
ef6e34ee
DE
1032 }
1033
4b5f4bdc 1034 return lxc_cmd_rsp_send_reap(fd, &rsp);
ef6e34ee 1035}
d5088cf2 1036
b5159817 1037/*
2bd158cc 1038 * lxc_cmd_terminal_winch: noop
b5159817
DE
1039 *
1040 * @name : name of container to connect to
1041 * @lxcpath : the lxcpath in which the container is running
1042 *
1043 * Returns 0 on success, < 0 on failure
1044 */
8ccbbf94 1045int lxc_cmd_terminal_winch(const char *name, const char *lxcpath)
b5159817 1046{
b5159817
DE
1047 return 0;
1048}
1049
8ccbbf94 1050static int lxc_cmd_terminal_winch_callback(int fd, struct lxc_cmd_req *req,
cdb2a47f
CB
1051 struct lxc_handler *handler,
1052 struct lxc_epoll_descr *descr)
b5159817 1053{
2bd158cc 1054 /* should never be called */
6c6497ea 1055 return log_error_errno(-1, ENOSYS, "Called lxc_cmd_terminal_winch_callback()");
b5159817
DE
1056}
1057
ef6e34ee
DE
1058/*
1059 * lxc_cmd_console: Open an fd to a tty in the container
1060 *
1061 * @name : name of container to connect to
1062 * @ttynum : in: the tty to open or -1 for next available
1063 * : out: the tty allocated
36a94ce8 1064 * @fd : out: file descriptor for ptx side of pty
ef6e34ee
DE
1065 * @lxcpath : the lxcpath in which the container is running
1066 *
0115f8fd 1067 * Returns fd holding tty allocated on success, < 0 on failure
ef6e34ee
DE
1068 */
1069int lxc_cmd_console(const char *name, int *ttynum, int *fd, const char *lxcpath)
1070{
8259d86d 1071 __do_free struct lxc_cmd_console_rsp_data *rspdata = NULL;
0ecf64b5 1072 int ret, stopped;
ef6e34ee 1073 struct lxc_cmd_rr cmd = {
6c6497ea
CB
1074 .req = {
1075 .cmd = LXC_CMD_CONSOLE,
1076 .data = INT_TO_PTR(*ttynum),
1077 },
ef6e34ee 1078 };
d5088cf2 1079
88556fd7 1080 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
ef6e34ee
DE
1081 if (ret < 0)
1082 return ret;
0115f8fd 1083
8259d86d 1084 rspdata = cmd.rsp.data;
6c6497ea
CB
1085 if (cmd.rsp.ret < 0)
1086 return log_error_errno(-1, -cmd.rsp.ret, "Denied access to tty");
d5088cf2 1087
6c6497ea
CB
1088 if (ret == 0)
1089 return log_error(-1, "tty number %d invalid, busy or all ttys busy", *ttynum);
ef6e34ee 1090
36a94ce8 1091 if (rspdata->ptxfd < 0)
6c6497ea 1092 return log_error(-1, "Unable to allocate fd for tty %d", rspdata->ttynum);
ef6e34ee 1093
fe84a562 1094 ret = cmd.rsp.ret; /* socket fd */
36a94ce8 1095 *fd = rspdata->ptxfd;
ef6e34ee 1096 *ttynum = rspdata->ttynum;
fe84a562 1097
6c6497ea 1098 return log_info(ret, "Alloced fd %d for tty %d via socket %d", *fd, rspdata->ttynum, ret);
ef6e34ee
DE
1099}
1100
1101static int lxc_cmd_console_callback(int fd, struct lxc_cmd_req *req,
cdb2a47f
CB
1102 struct lxc_handler *handler,
1103 struct lxc_epoll_descr *descr)
ef6e34ee 1104{
36a94ce8 1105 int ptxfd, ret;
4b5f4bdc
CB
1106 struct lxc_cmd_rsp rsp = {
1107 .ret = -EBADF,
1108 };
fe84a562 1109 int ttynum = PTR_TO_INT(req->data);
ef6e34ee 1110
36a94ce8
CB
1111 ptxfd = lxc_terminal_allocate(handler->conf, fd, &ttynum);
1112 if (ptxfd < 0)
4b5f4bdc 1113 return lxc_cmd_rsp_send_reap(fd, &rsp);
ef6e34ee 1114
4b5f4bdc 1115 rsp.ret = 0;
ef6e34ee 1116 rsp.data = INT_TO_PTR(ttynum);
36a94ce8 1117 ret = lxc_abstract_unix_send_fds(fd, &ptxfd, 1, &rsp, sizeof(rsp));
fe84a562 1118 if (ret < 0) {
3dfe6f8d 1119 lxc_terminal_free(handler->conf, fd);
4b5f4bdc 1120 return ret;
ef6e34ee
DE
1121 }
1122
4b5f4bdc 1123 return log_debug(0, "Send tty to client");
d5088cf2
CS
1124}
1125
88556fd7
ÇO
1126/*
1127 * lxc_cmd_get_name: Returns the name of the container
1128 *
1129 * @hashed_sock_name: hashed socket name
1130 *
1131 * Returns the name on success, NULL on failure.
1132 */
1133char *lxc_cmd_get_name(const char *hashed_sock_name)
1134{
1135 int ret, stopped;
1136 struct lxc_cmd_rr cmd = {
6c6497ea
CB
1137 .req = {
1138 .cmd = LXC_CMD_GET_NAME,
1139 },
88556fd7
ÇO
1140 };
1141
1142 ret = lxc_cmd(NULL, &cmd, &stopped, NULL, hashed_sock_name);
fe84a562 1143 if (ret < 0)
88556fd7 1144 return NULL;
88556fd7
ÇO
1145
1146 if (cmd.rsp.ret == 0)
1147 return cmd.rsp.data;
fe84a562 1148
88556fd7
ÇO
1149 return NULL;
1150}
1151
1152static int lxc_cmd_get_name_callback(int fd, struct lxc_cmd_req *req,
cdb2a47f
CB
1153 struct lxc_handler *handler,
1154 struct lxc_epoll_descr *descr)
88556fd7
ÇO
1155{
1156 struct lxc_cmd_rsp rsp;
1157
1158 memset(&rsp, 0, sizeof(rsp));
1159
f0ecc19d 1160 rsp.data = (char *)handler->name;
88556fd7
ÇO
1161 rsp.datalen = strlen(handler->name) + 1;
1162 rsp.ret = 0;
1163
4b5f4bdc 1164 return lxc_cmd_rsp_send_reap(fd, &rsp);
88556fd7
ÇO
1165}
1166
1167/*
1168 * lxc_cmd_get_lxcpath: Returns the lxcpath of the container
1169 *
1170 * @hashed_sock_name: hashed socket name
1171 *
1172 * Returns the lxcpath on success, NULL on failure.
1173 */
1174char *lxc_cmd_get_lxcpath(const char *hashed_sock_name)
1175{
1176 int ret, stopped;
1177 struct lxc_cmd_rr cmd = {
6c6497ea
CB
1178 .req = {
1179 .cmd = LXC_CMD_GET_LXCPATH,
1180 },
88556fd7 1181 };
724e753c 1182
88556fd7 1183 ret = lxc_cmd(NULL, &cmd, &stopped, NULL, hashed_sock_name);
fe84a562 1184 if (ret < 0)
88556fd7 1185 return NULL;
88556fd7
ÇO
1186
1187 if (cmd.rsp.ret == 0)
1188 return cmd.rsp.data;
fe84a562 1189
88556fd7
ÇO
1190 return NULL;
1191}
1192
1193static int lxc_cmd_get_lxcpath_callback(int fd, struct lxc_cmd_req *req,
cdb2a47f
CB
1194 struct lxc_handler *handler,
1195 struct lxc_epoll_descr *descr)
88556fd7 1196{
6c6497ea
CB
1197 struct lxc_cmd_rsp rsp = {
1198 .ret = 0,
1199 .data = (char *)handler->lxcpath,
1200 .datalen = strlen(handler->lxcpath) + 1,
1201 };
88556fd7 1202
4b5f4bdc 1203 return lxc_cmd_rsp_send_reap(fd, &rsp);
88556fd7 1204}
ef6e34ee 1205
54446942 1206int lxc_cmd_add_state_client(const char *name, const char *lxcpath,
92e35018
CB
1207 lxc_state_t states[MAX_STATE],
1208 int *state_client_fd)
dbc9832d 1209{
f62cf1d4 1210 __do_close int clientfd = -EBADF;
bc631984 1211 int state, stopped;
dbc9832d 1212 ssize_t ret;
dbc9832d 1213 struct lxc_cmd_rr cmd = {
6c6497ea
CB
1214 .req = {
1215 .cmd = LXC_CMD_ADD_STATE_CLIENT,
1216 .data = states,
1217 .datalen = (sizeof(lxc_state_t) * MAX_STATE)
1218 },
dbc9832d
CB
1219 };
1220
dbc9832d 1221 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
bc631984
CB
1222 if (states[STOPPED] != 0 && stopped != 0)
1223 return STOPPED;
1224
dbc9832d 1225 if (ret < 0) {
f577e061 1226 if (errno != ECONNREFUSED)
6d1400b5 1227 SYSERROR("Failed to execute command");
1228
dbc9832d
CB
1229 return -1;
1230 }
fe84a562 1231
dbc9832d
CB
1232 /* We should now be guaranteed to get an answer from the state sending
1233 * function.
1234 */
cd889e57 1235 clientfd = cmd.rsp.ret;
6c6497ea
CB
1236 if (clientfd < 0)
1237 return log_error_errno(-1, -clientfd, "Failed to receive socket fd");
dbc9832d 1238
bc631984 1239 state = PTR_TO_INT(cmd.rsp.data);
6c6497ea
CB
1240 if (state < MAX_STATE)
1241 return log_trace(state, "Container is already in requested state %s", lxc_state2str(state));
bc631984 1242
240fecd0 1243 *state_client_fd = move_fd(clientfd);
ea2a070b
CB
1244 TRACE("State connection fd %d ready to listen for container state changes", *state_client_fd);
1245 return MAX_STATE;
dbc9832d
CB
1246}
1247
ebbca852 1248static int lxc_cmd_add_state_client_callback(__owns int fd, struct lxc_cmd_req *req,
cdb2a47f
CB
1249 struct lxc_handler *handler,
1250 struct lxc_epoll_descr *descr)
dbc9832d 1251{
4b5f4bdc
CB
1252 struct lxc_cmd_rsp rsp = {
1253 .ret = -EINVAL,
1254 };
dbc9832d 1255
fe84a562 1256 if (req->datalen < 0)
254a22e1 1257 goto reap_fd;
dbc9832d 1258
71fc9c04 1259 if (req->datalen != (sizeof(lxc_state_t) * MAX_STATE))
254a22e1 1260 goto reap_fd;
dbc9832d 1261
fe84a562 1262 if (!req->data)
254a22e1 1263 goto reap_fd;
dbc9832d 1264
c01c2be6 1265 rsp.ret = lxc_add_state_client(fd, handler, (lxc_state_t *)req->data);
44552fb2 1266 if (rsp.ret < 0)
254a22e1 1267 goto reap_fd;
44552fb2 1268
bc631984 1269 rsp.data = INT_TO_PTR(rsp.ret);
dbc9832d 1270
254a22e1
CB
1271 return lxc_cmd_rsp_send_keep(fd, &rsp);
1272
1273reap_fd:
4b5f4bdc 1274 return lxc_cmd_rsp_send_reap(fd, &rsp);
dbc9832d
CB
1275}
1276
2a63b5cb
CB
1277int lxc_cmd_add_bpf_device_cgroup(const char *name, const char *lxcpath,
1278 struct device_item *device)
1279{
2a63b5cb
CB
1280 int stopped = 0;
1281 struct lxc_cmd_rr cmd = {
6c6497ea
CB
1282 .req = {
1283 .cmd = LXC_CMD_ADD_BPF_DEVICE_CGROUP,
1284 .data = device,
1285 .datalen = sizeof(struct device_item),
1286 },
2a63b5cb
CB
1287 };
1288 int ret;
1289
1290 if (strlen(device->access) > STRLITERALLEN("rwm"))
3d0327ed 1291 return log_error_errno(-1, EINVAL, "Invalid access mode specified %s",
2a63b5cb
CB
1292 device->access);
1293
1294 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
1295 if (ret < 0 || cmd.rsp.ret < 0)
3d0327ed 1296 return log_error_errno(-1, errno, "Failed to add new bpf device cgroup rule");
2a63b5cb
CB
1297
1298 return 0;
2a63b5cb
CB
1299}
1300
1301static int lxc_cmd_add_bpf_device_cgroup_callback(int fd, struct lxc_cmd_req *req,
1302 struct lxc_handler *handler,
1303 struct lxc_epoll_descr *descr)
1304{
4b5f4bdc
CB
1305 struct lxc_cmd_rsp rsp = {
1306 .ret = -EINVAL,
1307 };
0a150695 1308 struct lxc_conf *conf;
2a63b5cb
CB
1309
1310 if (req->datalen <= 0)
4b5f4bdc 1311 goto out;
2a63b5cb
CB
1312
1313 if (req->datalen != sizeof(struct device_item))
4b5f4bdc 1314 goto out;
2a63b5cb
CB
1315
1316 if (!req->data)
4b5f4bdc 1317 goto out;
2a63b5cb 1318
0a150695 1319 conf = handler->conf;
a134099d
CB
1320 if (!bpf_cgroup_devices_update(handler->cgroup_ops,
1321 &conf->bpf_devices,
1322 (struct device_item *)req->data))
0a150695
CB
1323 rsp.ret = -1;
1324 else
1325 rsp.ret = 0;
2a63b5cb 1326
4b5f4bdc
CB
1327out:
1328 return lxc_cmd_rsp_send_reap(fd, &rsp);
2a63b5cb
CB
1329}
1330
191d43cc
CB
1331int lxc_cmd_console_log(const char *name, const char *lxcpath,
1332 struct lxc_console_log *log)
1333{
1334 int ret, stopped;
1335 struct lxc_cmd_console_log data;
1336 struct lxc_cmd_rr cmd;
1337
1338 data.clear = log->clear;
1339 data.read = log->read;
1340 data.read_max = *log->read_max;
1341
1342 cmd.req.cmd = LXC_CMD_CONSOLE_LOG;
1343 cmd.req.data = &data;
1344 cmd.req.datalen = sizeof(struct lxc_cmd_console_log);
1345
1346 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
1347 if (ret < 0)
1348 return ret;
1349
1350 /* There is nothing to be read from the buffer. So clear any values we
1351 * where passed to clearly indicate to the user that nothing went wrong.
1352 */
63b74cda 1353 if (cmd.rsp.ret == -ENODATA || cmd.rsp.ret == -EFAULT || cmd.rsp.ret == -ENOENT) {
191d43cc
CB
1354 *log->read_max = 0;
1355 log->data = NULL;
1356 }
1357
1358 /* This is a proper error so don't touch any values we were passed. */
1359 if (cmd.rsp.ret < 0)
1360 return cmd.rsp.ret;
1361
1362 *log->read_max = cmd.rsp.datalen;
1363 log->data = cmd.rsp.data;
1364
1365 return 0;
1366}
1367
1368static int lxc_cmd_console_log_callback(int fd, struct lxc_cmd_req *req,
cdb2a47f
CB
1369 struct lxc_handler *handler,
1370 struct lxc_epoll_descr *descr)
191d43cc
CB
1371{
1372 struct lxc_cmd_rsp rsp;
28f3b1cd 1373 uint64_t buffer_size = handler->conf->console.buffer_size;
191d43cc
CB
1374 const struct lxc_cmd_console_log *log = req->data;
1375 struct lxc_ringbuf *buf = &handler->conf->console.ringbuf;
1376
1377 rsp.ret = -EFAULT;
1378 rsp.datalen = 0;
1379 rsp.data = NULL;
28f3b1cd 1380 if (buffer_size <= 0)
191d43cc
CB
1381 goto out;
1382
5928191e
CB
1383 if (log->read || log->write_logfile)
1384 rsp.datalen = lxc_ringbuf_used(buf);
1385
191d43cc
CB
1386 if (log->read)
1387 rsp.data = lxc_ringbuf_get_read_addr(buf);
1388
1389 if (log->read_max > 0 && (log->read_max <= rsp.datalen))
1390 rsp.datalen = log->read_max;
1391
1392 /* there's nothing to read */
63b74cda 1393 rsp.ret = -ENODATA;
191d43cc 1394 if (log->read && (buf->r_off == buf->w_off))
63b74cda
CB
1395 goto out;
1396
63b74cda 1397 rsp.ret = 0;
23e0d9af 1398 if (log->clear)
43366ca2 1399 lxc_ringbuf_clear(buf); /* clear the ringbuffer */
23e0d9af 1400 else if (rsp.datalen > 0)
191d43cc
CB
1401 lxc_ringbuf_move_read_addr(buf, rsp.datalen);
1402
1403out:
4b5f4bdc 1404 return lxc_cmd_rsp_send_reap(fd, &rsp);
191d43cc
CB
1405}
1406
974a8aba
CB
1407int lxc_cmd_serve_state_clients(const char *name, const char *lxcpath,
1408 lxc_state_t state)
1409{
1410 int stopped;
1411 ssize_t ret;
1412 struct lxc_cmd_rr cmd = {
6c6497ea
CB
1413 .req = {
1414 .cmd = LXC_CMD_SERVE_STATE_CLIENTS,
1415 .data = INT_TO_PTR(state)
1416 },
974a8aba
CB
1417 };
1418
1419 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
6c6497ea
CB
1420 if (ret < 0)
1421 return log_error_errno(-1, errno, "Failed to serve state clients");
974a8aba
CB
1422
1423 return 0;
1424}
1425
1426static int lxc_cmd_serve_state_clients_callback(int fd, struct lxc_cmd_req *req,
cdb2a47f
CB
1427 struct lxc_handler *handler,
1428 struct lxc_epoll_descr *descr)
974a8aba
CB
1429{
1430 int ret;
1431 lxc_state_t state = PTR_TO_INT(req->data);
1432 struct lxc_cmd_rsp rsp = {0};
1433
1434 ret = lxc_serve_state_clients(handler->name, handler, state);
1435 if (ret < 0)
4b5f4bdc 1436 return ret;
974a8aba 1437
4b5f4bdc 1438 return lxc_cmd_rsp_send_reap(fd, &rsp);
974a8aba
CB
1439}
1440
cdb2a47f
CB
1441int lxc_cmd_seccomp_notify_add_listener(const char *name, const char *lxcpath,
1442 int fd,
1443 /* unused */ unsigned int command,
1444 /* unused */ unsigned int flags)
1445{
1446
c3e3c21a 1447#ifdef HAVE_SECCOMP_NOTIFY
cdb2a47f
CB
1448 int ret, stopped;
1449 struct lxc_cmd_rr cmd = {
1450 .req = {
1451 .cmd = LXC_CMD_SECCOMP_NOTIFY_ADD_LISTENER,
1452 .data = INT_TO_PTR(fd),
1453 },
1454 };
1455
1456 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
6c6497ea
CB
1457 if (ret < 0)
1458 return log_error_errno(-1, errno, "Failed to add seccomp listener");
cdb2a47f
CB
1459
1460 return cmd.rsp.ret;
1461#else
3d0327ed 1462 return ret_set_errno(-1, ENOSYS);
cdb2a47f
CB
1463#endif
1464}
1465
1466static int lxc_cmd_seccomp_notify_add_listener_callback(int fd,
1467 struct lxc_cmd_req *req,
1468 struct lxc_handler *handler,
1469 struct lxc_epoll_descr *descr)
1470{
1471 struct lxc_cmd_rsp rsp = {0};
cdb2a47f 1472
c3e3c21a
CB
1473#ifdef HAVE_SECCOMP_NOTIFY
1474 int ret;
f62cf1d4 1475 __do_close int recv_fd = -EBADF;
cdb2a47f 1476
d17c815d 1477 ret = lxc_abstract_unix_recv_one_fd(fd, &recv_fd, NULL, 0);
c3e3c21a
CB
1478 if (ret <= 0) {
1479 rsp.ret = -errno;
1480 goto out;
cdb2a47f
CB
1481 }
1482
c3e3c21a
CB
1483 if (!handler->conf->seccomp.notifier.wants_supervision ||
1484 handler->conf->seccomp.notifier.proxy_fd < 0) {
1485 SYSERROR("No seccomp proxy fd specified");
1486 rsp.ret = -EINVAL;
1487 goto out;
1488 }
cdb2a47f 1489
c3e3c21a 1490 ret = lxc_mainloop_add_handler(descr, recv_fd, seccomp_notify_handler,
cdb2a47f 1491 handler);
c3e3c21a
CB
1492 if (ret < 0) {
1493 rsp.ret = -errno;
1494 goto out;
1495 }
68a9e3eb 1496 move_fd(recv_fd);
cdb2a47f 1497
c3e3c21a 1498out:
cdb2a47f
CB
1499#else
1500 rsp.ret = -ENOSYS;
cdb2a47f 1501
c3e3c21a 1502#endif
4b5f4bdc 1503 return lxc_cmd_rsp_send_reap(fd, &rsp);
cdb2a47f
CB
1504}
1505
018051e3
CB
1506int lxc_cmd_freeze(const char *name, const char *lxcpath, int timeout)
1507{
1508 int ret, stopped;
1509 struct lxc_cmd_rr cmd = {
1510 .req = {
1511 .cmd = LXC_CMD_FREEZE,
1512 .data = INT_TO_PTR(timeout),
1513 },
1514 };
1515
1516 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
1517 if (ret <= 0 || cmd.rsp.ret < 0)
3d0327ed 1518 return log_error_errno(-1, errno, "Failed to freeze container");
018051e3
CB
1519
1520 return cmd.rsp.ret;
1521}
1522
1523static int lxc_cmd_freeze_callback(int fd, struct lxc_cmd_req *req,
1524 struct lxc_handler *handler,
1525 struct lxc_epoll_descr *descr)
1526{
1527 int timeout = PTR_TO_INT(req->data);
1528 struct lxc_cmd_rsp rsp = {
6c6497ea 1529 .ret = -ENOENT,
018051e3
CB
1530 };
1531 struct cgroup_ops *ops = handler->cgroup_ops;
1532
1973b62a 1533 if (pure_unified_layout(ops))
018051e3
CB
1534 rsp.ret = ops->freeze(ops, timeout);
1535
4b5f4bdc 1536 return lxc_cmd_rsp_send_reap(fd, &rsp);
018051e3
CB
1537}
1538
1539int lxc_cmd_unfreeze(const char *name, const char *lxcpath, int timeout)
1540{
1541 int ret, stopped;
1542 struct lxc_cmd_rr cmd = {
1543 .req = {
1544 .cmd = LXC_CMD_UNFREEZE,
1545 .data = INT_TO_PTR(timeout),
1546 },
1547 };
1548
1549 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
1550 if (ret <= 0 || cmd.rsp.ret < 0)
3d0327ed 1551 return log_error_errno(-1, errno, "Failed to unfreeze container");
018051e3
CB
1552
1553 return cmd.rsp.ret;
1554}
1555
1556static int lxc_cmd_unfreeze_callback(int fd, struct lxc_cmd_req *req,
1557 struct lxc_handler *handler,
1558 struct lxc_epoll_descr *descr)
1559{
1560 int timeout = PTR_TO_INT(req->data);
1561 struct lxc_cmd_rsp rsp = {
6c6497ea 1562 .ret = -ENOENT,
018051e3
CB
1563 };
1564 struct cgroup_ops *ops = handler->cgroup_ops;
1565
1973b62a 1566 if (pure_unified_layout(ops))
018051e3
CB
1567 rsp.ret = ops->unfreeze(ops, timeout);
1568
4b5f4bdc 1569 return lxc_cmd_rsp_send_reap(fd, &rsp);
018051e3
CB
1570}
1571
bad788b0
CB
1572int lxc_cmd_get_cgroup2_fd(const char *name, const char *lxcpath)
1573{
1574 int ret, stopped;
1575 struct lxc_cmd_rr cmd = {
1576 .req = {
1577 .cmd = LXC_CMD_GET_CGROUP2_FD,
1578 },
d3be623e
CB
1579 .rsp = {
1580 ret = -ENOSYS,
1581 },
bad788b0
CB
1582 };
1583
1584 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
23a917e5
CB
1585 if (ret < 0)
1586 return -1;
1587
1588 if (cmd.rsp.ret < 0)
a5263e59 1589 return log_debug_errno(cmd.rsp.ret, -cmd.rsp.ret, "Failed to receive cgroup2 fd");
6f7f2966
CB
1590
1591 return PTR_TO_INT(cmd.rsp.data);
1592}
1593
1594int lxc_cmd_get_limiting_cgroup2_fd(const char *name, const char *lxcpath)
1595{
1596 int ret, stopped;
1597 struct lxc_cmd_rr cmd = {
1598 .req = {
1599 .cmd = LXC_CMD_GET_LIMITING_CGROUP2_FD,
1600 },
d3be623e
CB
1601 .rsp = {
1602 .ret = -ENOSYS,
1603 },
6f7f2966
CB
1604 };
1605
1606 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
1607 if (ret < 0)
1608 return -1;
1609
1610 if (cmd.rsp.ret < 0)
d3be623e 1611 return syswarn_set(cmd.rsp.ret, "Failed to receive cgroup2 limit fd");
bad788b0
CB
1612
1613 return PTR_TO_INT(cmd.rsp.data);
1614}
1615
a900cbaf
WB
1616static int lxc_cmd_get_cgroup2_fd_callback_do(int fd, struct lxc_cmd_req *req,
1617 struct lxc_handler *handler,
1618 struct lxc_epoll_descr *descr,
1619 bool limiting_cgroup)
bad788b0
CB
1620{
1621 struct lxc_cmd_rsp rsp = {
1622 .ret = -EINVAL,
1623 };
1624 struct cgroup_ops *ops = handler->cgroup_ops;
c2f40088 1625 int send_fd;
bad788b0 1626
1973b62a 1627 if (!pure_unified_layout(ops) || !ops->unified)
4b5f4bdc 1628 return lxc_cmd_rsp_send_reap(fd, &rsp);
bad788b0 1629
c0af7b1c 1630 send_fd = limiting_cgroup ? ops->unified->dfd_lim
e33870e5 1631 : ops->unified->dfd_con;
a900cbaf 1632
4b5f4bdc
CB
1633 if (send_fd < 0) {
1634 rsp.ret = -EBADF;
1635 return lxc_cmd_rsp_send_reap(fd, &rsp);
1636 }
1637
bad788b0 1638 rsp.ret = 0;
c2f40088 1639 return rsp_one_fd(fd, send_fd, &rsp);
bad788b0
CB
1640}
1641
a900cbaf
WB
1642static int lxc_cmd_get_cgroup2_fd_callback(int fd, struct lxc_cmd_req *req,
1643 struct lxc_handler *handler,
1644 struct lxc_epoll_descr *descr)
1645{
1646 return lxc_cmd_get_cgroup2_fd_callback_do(fd, req, handler, descr,
1647 false);
1648}
1649
1650static int lxc_cmd_get_limiting_cgroup2_fd_callback(int fd,
1651 struct lxc_cmd_req *req,
1652 struct lxc_handler *handler,
1653 struct lxc_epoll_descr *descr)
1654{
1655 return lxc_cmd_get_cgroup2_fd_callback_do(fd, req, handler, descr,
1656 true);
1657}
1658
ebc548a1
CB
1659static int lxc_cmd_rsp_send_enosys(int fd, int id)
1660{
1661 struct lxc_cmd_rsp rsp = {
1662 .ret = -ENOSYS,
1663 };
1664
1665 __lxc_cmd_rsp_send(fd, &rsp);
1666 return syserrno_set(-ENOSYS, "Invalid command id %d", id);
1667}
1668
ef6e34ee 1669static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
cdb2a47f
CB
1670 struct lxc_handler *handler,
1671 struct lxc_epoll_descr *descr)
724e753c 1672{
cdb2a47f
CB
1673 typedef int (*callback)(int, struct lxc_cmd_req *, struct lxc_handler *,
1674 struct lxc_epoll_descr *);
ef6e34ee
DE
1675
1676 callback cb[LXC_CMD_MAX] = {
2a63b5cb
CB
1677 [LXC_CMD_CONSOLE] = lxc_cmd_console_callback,
1678 [LXC_CMD_TERMINAL_WINCH] = lxc_cmd_terminal_winch_callback,
1679 [LXC_CMD_STOP] = lxc_cmd_stop_callback,
1680 [LXC_CMD_GET_STATE] = lxc_cmd_get_state_callback,
1681 [LXC_CMD_GET_INIT_PID] = lxc_cmd_get_init_pid_callback,
1682 [LXC_CMD_GET_CLONE_FLAGS] = lxc_cmd_get_clone_flags_callback,
1683 [LXC_CMD_GET_CGROUP] = lxc_cmd_get_cgroup_callback,
1684 [LXC_CMD_GET_CONFIG_ITEM] = lxc_cmd_get_config_item_callback,
1685 [LXC_CMD_GET_NAME] = lxc_cmd_get_name_callback,
1686 [LXC_CMD_GET_LXCPATH] = lxc_cmd_get_lxcpath_callback,
1687 [LXC_CMD_ADD_STATE_CLIENT] = lxc_cmd_add_state_client_callback,
1688 [LXC_CMD_CONSOLE_LOG] = lxc_cmd_console_log_callback,
1689 [LXC_CMD_SERVE_STATE_CLIENTS] = lxc_cmd_serve_state_clients_callback,
1690 [LXC_CMD_SECCOMP_NOTIFY_ADD_LISTENER] = lxc_cmd_seccomp_notify_add_listener_callback,
1691 [LXC_CMD_ADD_BPF_DEVICE_CGROUP] = lxc_cmd_add_bpf_device_cgroup_callback,
018051e3
CB
1692 [LXC_CMD_FREEZE] = lxc_cmd_freeze_callback,
1693 [LXC_CMD_UNFREEZE] = lxc_cmd_unfreeze_callback,
bad788b0 1694 [LXC_CMD_GET_CGROUP2_FD] = lxc_cmd_get_cgroup2_fd_callback,
746aab51 1695 [LXC_CMD_GET_INIT_PIDFD] = lxc_cmd_get_init_pidfd_callback,
a900cbaf
WB
1696 [LXC_CMD_GET_LIMITING_CGROUP] = lxc_cmd_get_limiting_cgroup_callback,
1697 [LXC_CMD_GET_LIMITING_CGROUP2_FD] = lxc_cmd_get_limiting_cgroup2_fd_callback,
f797f05e 1698 [LXC_CMD_GET_DEVPTS_FD] = lxc_cmd_get_devpts_fd_callback,
21405769 1699 [LXC_CMD_GET_SECCOMP_NOTIFY_FD] = lxc_cmd_get_seccomp_notify_fd_callback,
ef6e048a 1700 [LXC_CMD_GET_CGROUP_CTX] = lxc_cmd_get_cgroup_ctx_callback,
724e753c
MN
1701 };
1702
23a917e5 1703 if (req->cmd >= LXC_CMD_MAX)
ebc548a1 1704 return lxc_cmd_rsp_send_enosys(fd, req->cmd);
23a917e5 1705
cdb2a47f 1706 return cb[req->cmd](fd, req, handler, descr);
724e753c
MN
1707}
1708
ef6e34ee 1709static void lxc_cmd_fd_cleanup(int fd, struct lxc_handler *handler,
cdb2a47f 1710 struct lxc_epoll_descr *descr, const lxc_cmd_t cmd)
724e753c 1711{
3dfe6f8d 1712 lxc_terminal_free(handler->conf, fd);
724e753c 1713 lxc_mainloop_del_handler(descr, fd);
f6fc1565 1714
cd5369b0 1715 if (cmd == LXC_CMD_ADD_STATE_CLIENT) {
ab92468c
CB
1716 struct lxc_list *cur, *next;
1717
cdb2a47f
CB
1718 lxc_list_for_each_safe(cur, &handler->conf->state_clients, next) {
1719 struct lxc_state_client *client = cur->elem;
1720
1721 if (client->clientfd != fd)
1722 continue;
1723
ab92468c
CB
1724 /*
1725 * Only kick client from list so it can't be found
1726 * anymore. The actual close happens, as for all other
1727 * file descriptors, below.
1728 */
cdb2a47f 1729 lxc_list_del(cur);
cdb2a47f
CB
1730 free(cur->elem);
1731 free(cur);
ab92468c 1732
39e2a438
CB
1733 /*
1734 * No need to walk the whole list. If we found the state
cdb2a47f
CB
1735 * client fd there can't be a second one.
1736 */
ea2a070b 1737 TRACE("Found state client fd %d in state client list for command \"%s\"", fd, lxc_cmd_str(cmd));
ab92468c 1738 break;
cdb2a47f 1739 }
39e2a438
CB
1740
1741 /*
1742 * We didn't add the state client to the list. Either because
1743 * we failed to allocate memory (unlikely) or because the state
1744 * was already reached by the time we were ready to add it. So
1745 * fallthrough and clean it up.
1746 */
ea2a070b 1747 TRACE("Closing state client fd %d for command \"%s\"", fd, lxc_cmd_str(cmd));
f6fc1565 1748 }
cd5369b0 1749
ea2a070b 1750 TRACE("Closing client fd %d for command \"%s\"", fd, lxc_cmd_str(cmd));
cd5369b0 1751 close(fd);
724e753c
MN
1752}
1753
84c92abd
DE
1754static int lxc_cmd_handler(int fd, uint32_t events, void *data,
1755 struct lxc_epoll_descr *descr)
724e753c 1756{
5265a60c 1757 __do_free void *reqdata = NULL;
724e753c 1758 int ret;
ef6e34ee 1759 struct lxc_cmd_req req;
724e753c
MN
1760 struct lxc_handler *handler = data;
1761
aae93dd3 1762 ret = lxc_abstract_unix_rcv_credential(fd, &req, sizeof(req));
ded1d23f 1763 if (ret < 0) {
ea2a070b 1764 SYSERROR("Failed to receive data on command socket for command \"%s\"", lxc_cmd_str(req.cmd));
9044b79e 1765
1766 if (errno == EACCES) {
1767 /* We don't care for the peer, just send and close. */
ea2a070b 1768 struct lxc_cmd_rsp rsp = {
f7a97743 1769 .ret = -EPERM,
ea2a070b 1770 };
9044b79e 1771
4b5f4bdc 1772 __lxc_cmd_rsp_send(fd, &rsp);
9044b79e 1773 }
1774
724e753c
MN
1775 goto out_close;
1776 }
1777
fe84a562 1778 if (ret == 0)
724e753c 1779 goto out_close;
724e753c 1780
ef6e34ee 1781 if (ret != sizeof(req)) {
ea2a070b 1782 WARN("Failed to receive full command request. Ignoring request for \"%s\"", lxc_cmd_str(req.cmd));
ef6e34ee
DE
1783 goto out_close;
1784 }
1785
ea2a070b
CB
1786 if ((req.datalen > LXC_CMD_DATA_MAX) && (req.cmd != LXC_CMD_CONSOLE_LOG)) {
1787 ERROR("Received command data length %d is too large for command \"%s\"", req.datalen, lxc_cmd_str(req.cmd));
724e753c
MN
1788 goto out_close;
1789 }
1790
ef6e34ee 1791 if (req.datalen > 0) {
5265a60c 1792 reqdata = must_realloc(NULL, req.datalen);
e3233f26 1793 ret = lxc_recv_nointr(fd, reqdata, req.datalen, 0);
ef6e34ee 1794 if (ret != req.datalen) {
ea2a070b 1795 WARN("Failed to receive full command request. Ignoring request for \"%s\"", lxc_cmd_str(req.cmd));
ef6e34ee
DE
1796 goto out_close;
1797 }
fe84a562 1798
ef6e34ee
DE
1799 req.data = reqdata;
1800 }
1801
cdb2a47f 1802 ret = lxc_cmd_process(fd, &req, handler, descr);
32fd8d4f
CB
1803 if (ret < 0) {
1804 DEBUG("Failed to process command %s; cleaning up client fd %d", lxc_cmd_str(req.cmd), fd);
1805 goto out_close;
1806 } else if (ret == LXC_CMD_REAP_CLIENT_FD) {
1807 TRACE("Processed command %s; cleaning up client fd %d", lxc_cmd_str(req.cmd), fd);
724e753c 1808 goto out_close;
32fd8d4f
CB
1809 } else {
1810 TRACE("Processed command %s; keeping client fd %d", lxc_cmd_str(req.cmd), fd);
724e753c
MN
1811 }
1812
1813out:
f7a97743 1814 return LXC_MAINLOOP_CONTINUE;
fe84a562 1815
724e753c 1816out_close:
f6fc1565 1817 lxc_cmd_fd_cleanup(fd, handler, descr, req.cmd);
724e753c
MN
1818 goto out;
1819}
1820
84c92abd
DE
1821static int lxc_cmd_accept(int fd, uint32_t events, void *data,
1822 struct lxc_epoll_descr *descr)
724e753c 1823{
f62cf1d4 1824 __do_close int connection = -EBADF;
fe84a562 1825 int opt = 1, ret = -1;
724e753c
MN
1826
1827 connection = accept(fd, NULL, 0);
6c6497ea
CB
1828 if (connection < 0)
1829 return log_error_errno(LXC_MAINLOOP_ERROR, errno, "Failed to accept connection to run command");
724e753c 1830
fe84a562 1831 ret = fcntl(connection, F_SETFD, FD_CLOEXEC);
6c6497ea
CB
1832 if (ret < 0)
1833 return log_error_errno(ret, errno, "Failed to set close-on-exec on incoming command connection");
9ccb2dbc 1834
fe84a562 1835 ret = setsockopt(connection, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt));
6c6497ea
CB
1836 if (ret < 0)
1837 return log_error_errno(ret, errno, "Failed to enable necessary credentials on command socket");
724e753c 1838
ef6e34ee 1839 ret = lxc_mainloop_add_handler(descr, connection, lxc_cmd_handler, data);
6c6497ea
CB
1840 if (ret)
1841 return log_error(ret, "Failed to add command handler");
724e753c 1842
ea2a070b 1843 TRACE("Accepted new client as fd %d on command server fd %d", connection, fd);
240fecd0 1844 move_fd(connection);
724e753c 1845 return ret;
724e753c
MN
1846}
1847
9dfa4041 1848int lxc_cmd_init(const char *name, const char *lxcpath, const char *suffix)
724e753c 1849{
f62cf1d4 1850 __do_close int fd = -EBADF;
c13e7111 1851 int ret;
b1234129 1852 char path[LXC_AUDS_ADDR_LEN] = {0};
724e753c 1853
5b46db1a 1854 ret = lxc_make_abstract_socket_name(path, sizeof(path), name, lxcpath, NULL, suffix);
fe84a562 1855 if (ret < 0)
9ba8130c 1856 return -1;
724e753c 1857
aae93dd3 1858 fd = lxc_abstract_unix_open(path, SOCK_STREAM, 0);
724e753c 1859 if (fd < 0) {
08aa08fe 1860 if (errno == EADDRINUSE)
fe84a562 1861 ERROR("Container \"%s\" appears to be already running", name);
6d1400b5 1862
6c6497ea 1863 return log_error_errno(-1, errno, "Failed to create command socket %s", &path[1]);
724e753c
MN
1864 }
1865
fe84a562 1866 ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
6c6497ea
CB
1867 if (ret < 0)
1868 return log_error_errno(-1, errno, "Failed to set FD_CLOEXEC on command socket file descriptor");
91480a0f 1869
6c6497ea 1870 return log_trace(move_fd(fd), "Created abstract unix socket \"%s\"", &path[1]);
d2e30e99
DE
1871}
1872
fe84a562 1873int lxc_cmd_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
ef6e34ee 1874 struct lxc_handler *handler)
d2e30e99 1875{
fe84a562 1876 int ret;
d2e30e99 1877
ea2a070b 1878 ret = lxc_mainloop_add_handler(descr, handler->conf->maincmd_fd, lxc_cmd_accept, handler);
6c6497ea 1879 if (ret < 0)
ea2a070b 1880 return log_error(ret, "Failed to add handler for command socket fd %d", handler->conf->maincmd_fd);
724e753c
MN
1881
1882 return ret;
1883}