[lxc-devel] [lxc/master] commands: add ability to audit fd connection and cleanup path

brauner on Github lxc-bot at linuxcontainers.org
Wed Mar 11 11:47:38 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200311/102e1dad/attachment-0001.bin>
-------------- next part --------------
From ea2a070bc5666ef7b3fc23023c3a5214b0dafc9c Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 11 Mar 2020 12:02:10 +0100
Subject: [PATCH] commands: add ability to audit fd connection and cleanup path

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/commands.c       | 145 +++++++++++++++++++++------------------
 src/lxc/commands.h       |   7 ++
 src/lxc/commands_utils.c |   3 +-
 src/lxc/lxccontainer.c   |  14 ++--
 4 files changed, 94 insertions(+), 75 deletions(-)

diff --git a/src/lxc/commands.c b/src/lxc/commands.c
index 1feae25aab..b11c3c7fc8 100644
--- a/src/lxc/commands.c
+++ b/src/lxc/commands.c
@@ -284,6 +284,9 @@ static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped,
 	if (ret < 0 && errno == ECONNRESET)
 		*stopped = 1;
 
+	TRACE("Opened new command socket connection fd %d for command \"%s\"",
+	      client_fd, lxc_cmd_str(cmd->req.cmd));
+
 	if (stay_connected && ret > 0)
 		cmd->rsp.ret = move_fd(client_fd);
 
@@ -357,11 +360,16 @@ static int lxc_cmd_get_init_pid_callback(int fd, struct lxc_cmd_req *req,
 					 struct lxc_handler *handler,
 					 struct lxc_epoll_descr *descr)
 {
+	int ret;
 	struct lxc_cmd_rsp rsp = {
 		.data = PID_TO_PTR(handler->pid)
 	};
 
-	return lxc_cmd_rsp_send(fd, &rsp);
+	ret = lxc_cmd_rsp_send(fd, &rsp);
+	if (ret < 0)
+		return LXC_CMD_REAP_CLIENT_FD;
+
+	return 0;
 }
 
 /*
@@ -392,11 +400,16 @@ static int lxc_cmd_get_clone_flags_callback(int fd, struct lxc_cmd_req *req,
 					    struct lxc_handler *handler,
 					    struct lxc_epoll_descr *descr)
 {
+	int ret;
 	struct lxc_cmd_rsp rsp = {
 		.data = INT_TO_PTR(handler->ns_clone_flags),
 	};
 
-	return lxc_cmd_rsp_send(fd, &rsp);
+	ret = lxc_cmd_rsp_send(fd, &rsp);
+	if (ret < 0)
+		return LXC_CMD_REAP_CLIENT_FD;
+
+	return 0;
 }
 
 /*
@@ -445,6 +458,7 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
 				       struct lxc_handler *handler,
 				       struct lxc_epoll_descr *descr)
 {
+	int ret;
 	const char *path;
 	struct lxc_cmd_rsp rsp;
 	struct cgroup_ops *cgroup_ops = handler->cgroup_ops;
@@ -460,7 +474,11 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
 	rsp.datalen = strlen(path) + 1;
 	rsp.data = (char *)path;
 
-	return lxc_cmd_rsp_send(fd, &rsp);
+	ret = lxc_cmd_rsp_send(fd, &rsp);
+	if (ret < 0)
+		return LXC_CMD_REAP_CLIENT_FD;
+
+	return 0;
 }
 
 /*
@@ -525,7 +543,11 @@ static int lxc_cmd_get_config_item_callback(int fd, struct lxc_cmd_req *req,
 err1:
 	rsp.ret = -1;
 out:
-	return lxc_cmd_rsp_send(fd, &rsp);
+	cilen = lxc_cmd_rsp_send(fd, &rsp);
+	if (cilen < 0)
+		return LXC_CMD_REAP_CLIENT_FD;
+
+	return 0;
 }
 
 /*
@@ -564,11 +586,16 @@ static int lxc_cmd_get_state_callback(int fd, struct lxc_cmd_req *req,
 				      struct lxc_handler *handler,
 				      struct lxc_epoll_descr *descr)
 {
+	int ret;
 	struct lxc_cmd_rsp rsp = {
 		.data = INT_TO_PTR(handler->state),
 	};
 
-	return lxc_cmd_rsp_send(fd, &rsp);
+	ret = lxc_cmd_rsp_send(fd, &rsp);
+	if (ret < 0)
+		return LXC_CMD_REAP_CLIENT_FD;
+
+	return 0;
 }
 
 /*
@@ -613,6 +640,7 @@ static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req,
 	struct lxc_cmd_rsp rsp;
 	int stopsignal = SIGKILL;
 	struct cgroup_ops *cgroup_ops = handler->cgroup_ops;
+	int ret;
 
 	if (handler->conf->stopsignal)
 		stopsignal = handler->conf->stopsignal;
@@ -629,7 +657,11 @@ static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req,
 		rsp.ret = -errno;
 	}
 
-	return lxc_cmd_rsp_send(fd, &rsp);
+	ret = lxc_cmd_rsp_send(fd, &rsp);
+	if (ret < 0)
+		return LXC_CMD_REAP_CLIENT_FD;
+
+	return 0;
 }
 
 /*
@@ -706,24 +738,18 @@ static int lxc_cmd_console_callback(int fd, struct lxc_cmd_req *req,
 
 	masterfd = lxc_terminal_allocate(handler->conf, fd, &ttynum);
 	if (masterfd < 0)
-		goto out_close;
+		return LXC_CMD_REAP_CLIENT_FD;
 
 	memset(&rsp, 0, sizeof(rsp));
 	rsp.data = INT_TO_PTR(ttynum);
 	ret = lxc_abstract_unix_send_fds(fd, &masterfd, 1, &rsp, sizeof(rsp));
 	if (ret < 0) {
-		SYSERROR("Failed to send tty to client");
 		lxc_terminal_free(handler->conf, fd);
-		goto out_close;
+		return log_error_errno(LXC_CMD_REAP_CLIENT_FD, errno,
+				       "Failed to send tty to client");
 	}
 
 	return 0;
-
-out_close:
-	/* Special indicator to lxc_cmd_handler() to close the fd and do
-	 * related cleanup.
-	 */
-	return 1;
 }
 
 /*
@@ -756,6 +782,7 @@ static int lxc_cmd_get_name_callback(int fd, struct lxc_cmd_req *req,
 				     struct lxc_handler *handler,
 				     struct lxc_epoll_descr *descr)
 {
+	int ret;
 	struct lxc_cmd_rsp rsp;
 
 	memset(&rsp, 0, sizeof(rsp));
@@ -764,7 +791,11 @@ static int lxc_cmd_get_name_callback(int fd, struct lxc_cmd_req *req,
 	rsp.datalen = strlen(handler->name) + 1;
 	rsp.ret = 0;
 
-	return lxc_cmd_rsp_send(fd, &rsp);
+	ret = lxc_cmd_rsp_send(fd, &rsp);
+	if (ret < 0)
+		return LXC_CMD_REAP_CLIENT_FD;
+
+	return 0;
 }
 
 /*
@@ -797,13 +828,18 @@ static int lxc_cmd_get_lxcpath_callback(int fd, struct lxc_cmd_req *req,
 					struct lxc_handler *handler,
 					struct lxc_epoll_descr *descr)
 {
+	int ret;
 	struct lxc_cmd_rsp rsp = {
 		.ret		= 0,
 		.data		= (char *)handler->lxcpath,
 		.datalen	= strlen(handler->lxcpath) + 1,
 	};
 
-	return lxc_cmd_rsp_send(fd, &rsp);
+	ret = lxc_cmd_rsp_send(fd, &rsp);
+	if (ret < 0)
+		return LXC_CMD_REAP_CLIENT_FD;
+
+	return 0;
 }
 
 int lxc_cmd_add_state_client(const char *name, const char *lxcpath,
@@ -844,7 +880,8 @@ int lxc_cmd_add_state_client(const char *name, const char *lxcpath,
 		return log_trace(state, "Container is already in requested state %s", lxc_state2str(state));
 
 	*state_client_fd = move_fd(clientfd);
-	return log_trace(MAX_STATE, "Added state client %d to state client list", *state_client_fd);
+	TRACE("State connection fd %d ready to listen for container state changes", *state_client_fd);
+	return MAX_STATE;
 }
 
 static int lxc_cmd_add_state_client_callback(__owns int fd, struct lxc_cmd_req *req,
@@ -855,31 +892,25 @@ static int lxc_cmd_add_state_client_callback(__owns int fd, struct lxc_cmd_req *
 	struct lxc_cmd_rsp rsp = {0};
 
 	if (req->datalen < 0)
-		goto reap_client_fd;
+		return LXC_CMD_REAP_CLIENT_FD;
 
 	if (req->datalen != (sizeof(lxc_state_t) * MAX_STATE))
-		goto reap_client_fd;
+		return LXC_CMD_REAP_CLIENT_FD;
 
 	if (!req->data)
-		goto reap_client_fd;
+		return LXC_CMD_REAP_CLIENT_FD;
 
 	rsp.ret = lxc_add_state_client(fd, handler, (lxc_state_t *)req->data);
 	if (rsp.ret < 0)
-		goto reap_client_fd;
+		return LXC_CMD_REAP_CLIENT_FD;
 
 	rsp.data = INT_TO_PTR(rsp.ret);
 
 	ret = lxc_cmd_rsp_send(fd, &rsp);
 	if (ret < 0)
-		goto reap_client_fd;
+		return LXC_CMD_REAP_CLIENT_FD;
 
 	return 0;
-
-reap_client_fd:
-	/* Special indicator to lxc_cmd_handler() to close the fd and do related
-	 * cleanup.
-	 */
-	return 1;
 }
 
 int lxc_cmd_add_bpf_device_cgroup(const char *name, const char *lxcpath,
@@ -925,13 +956,13 @@ static int lxc_cmd_add_bpf_device_cgroup_callback(int fd, struct lxc_cmd_req *re
 	struct bpf_program *devices_old;
 
 	if (req->datalen <= 0)
-		goto reap_client_fd;
+		return LXC_CMD_REAP_CLIENT_FD;
 
 	if (req->datalen != sizeof(struct device_item))
-		goto reap_client_fd;
+		return LXC_CMD_REAP_CLIENT_FD;
 
 	if (!req->data)
-		goto reap_client_fd;
+		return LXC_CMD_REAP_CLIENT_FD;
 	device = (struct device_item *)req->data;
 
 	rsp.ret = -1;
@@ -978,15 +1009,9 @@ static int lxc_cmd_add_bpf_device_cgroup_callback(int fd, struct lxc_cmd_req *re
 respond:
 	ret = lxc_cmd_rsp_send(fd, &rsp);
 	if (ret < 0)
-		goto reap_client_fd;
+		return LXC_CMD_REAP_CLIENT_FD;
 
 	return 0;
-
-reap_client_fd:
-	/* Special indicator to lxc_cmd_handler() to close the fd and do related
-	 * cleanup.
-	 */
-	return 1;
 #else
 	return ret_set_errno(-1, ENOSYS);
 #endif
@@ -1097,20 +1122,13 @@ static int lxc_cmd_serve_state_clients_callback(int fd, struct lxc_cmd_req *req,
 
 	ret = lxc_serve_state_clients(handler->name, handler, state);
 	if (ret < 0)
-		goto reap_client_fd;
+		return LXC_CMD_REAP_CLIENT_FD;
 
 	ret = lxc_cmd_rsp_send(fd, &rsp);
 	if (ret < 0)
-		goto reap_client_fd;
+		return LXC_CMD_REAP_CLIENT_FD;
 
 	return 0;
-
-reap_client_fd:
-	/*
-	 * Special indicator to lxc_cmd_handler() to close the fd and do
-	 * related cleanup.
-	 */
-	return 1;
 }
 
 int lxc_cmd_seccomp_notify_add_listener(const char *name, const char *lxcpath,
@@ -1347,7 +1365,7 @@ static void lxc_cmd_fd_cleanup(int fd, struct lxc_handler *handler,
 			 * No need to walk the whole list. If we found the state
 			 * client fd there can't be a second one.
 			 */
-			TRACE("Found state client fd %d in state client list", fd);
+			TRACE("Found state client fd %d in state client list for command \"%s\"", fd, lxc_cmd_str(cmd));
 			break;
 		}
 
@@ -1357,9 +1375,10 @@ static void lxc_cmd_fd_cleanup(int fd, struct lxc_handler *handler,
 		 * was already reached by the time we were ready to add it. So
 		 * fallthrough and clean it up.
 		 */
-		TRACE("Closing state client fd %d", fd);
+		TRACE("Closing state client fd %d for command \"%s\"", fd, lxc_cmd_str(cmd));
 	}
 
+	TRACE("Closing client fd %d for command \"%s\"", fd, lxc_cmd_str(cmd));
 	close(fd);
 }
 
@@ -1373,12 +1392,13 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
 
 	ret = lxc_abstract_unix_rcv_credential(fd, &req, sizeof(req));
 	if (ret < 0) {
-		SYSERROR("Failed to receive data on command socket for command "
-		         "\"%s\"", lxc_cmd_str(req.cmd));
+		SYSERROR("Failed to receive data on command socket for command \"%s\"", lxc_cmd_str(req.cmd));
 
 		if (errno == EACCES) {
 			/* We don't care for the peer, just send and close. */
-			struct lxc_cmd_rsp rsp = {.ret = ret};
+			struct lxc_cmd_rsp rsp = {
+				.ret = ret,
+			};
 
 			lxc_cmd_rsp_send(fd, &rsp);
 		}
@@ -1390,16 +1410,13 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
 		goto out_close;
 
 	if (ret != sizeof(req)) {
-		WARN("Failed to receive full command request. Ignoring request "
-		     "for \"%s\"", lxc_cmd_str(req.cmd));
+		WARN("Failed to receive full command request. Ignoring request for \"%s\"", lxc_cmd_str(req.cmd));
 		ret = -1;
 		goto out_close;
 	}
 
-	if ((req.datalen > LXC_CMD_DATA_MAX) &&
-	    (req.cmd != LXC_CMD_CONSOLE_LOG)) {
-		ERROR("Received command data length %d is too large for "
-		      "command \"%s\"", req.datalen, lxc_cmd_str(req.cmd));
+	if ((req.datalen > LXC_CMD_DATA_MAX) && (req.cmd != LXC_CMD_CONSOLE_LOG)) {
+		ERROR("Received command data length %d is too large for command \"%s\"", req.datalen, lxc_cmd_str(req.cmd));
 		errno = EFBIG;
 		ret = -EFBIG;
 		goto out_close;
@@ -1409,8 +1426,7 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
 		reqdata = must_realloc(NULL, req.datalen);
 		ret = lxc_recv_nointr(fd, reqdata, req.datalen, 0);
 		if (ret != req.datalen) {
-			WARN("Failed to receive full command request. Ignoring "
-			     "request for \"%s\"", lxc_cmd_str(req.cmd));
+			WARN("Failed to receive full command request. Ignoring request for \"%s\"", lxc_cmd_str(req.cmd));
 			ret = LXC_MAINLOOP_ERROR;
 			goto out_close;
 		}
@@ -1455,6 +1471,7 @@ static int lxc_cmd_accept(int fd, uint32_t events, void *data,
 	if (ret)
 		return log_error(ret, "Failed to add command handler");
 
+	TRACE("Accepted new client as fd %d on command server fd %d", connection, fd);
 	move_fd(connection);
 	return ret;
 }
@@ -1487,13 +1504,11 @@ int lxc_cmd_init(const char *name, const char *lxcpath, const char *suffix)
 int lxc_cmd_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
 			 struct lxc_handler *handler)
 {
-	__do_close_prot_errno int fd = handler->conf->maincmd_fd;
 	int ret;
 
-	ret = lxc_mainloop_add_handler(descr, fd, lxc_cmd_accept, handler);
+	ret = lxc_mainloop_add_handler(descr, handler->conf->maincmd_fd, lxc_cmd_accept, handler);
 	if (ret < 0)
-		return log_error(ret, "Failed to add handler for command socket");
+		return log_error(ret, "Failed to add handler for command socket fd %d", handler->conf->maincmd_fd);
 
-	move_fd(fd);
 	return ret;
 }
diff --git a/src/lxc/commands.h b/src/lxc/commands.h
index c386c21bef..cd78a61a21 100644
--- a/src/lxc/commands.h
+++ b/src/lxc/commands.h
@@ -11,6 +11,13 @@
 #include "macro.h"
 #include "state.h"
 
+/*
+ * Value command callbacks should return when they want the client fd to be
+ * cleaned up by the main loop. This is most certainly what you want unless you
+ * have specific reasons to keep the file descriptor alive.
+ */
+#define LXC_CMD_REAP_CLIENT_FD 1
+
 typedef enum {
 	LXC_CMD_CONSOLE,
 	LXC_CMD_TERMINAL_WINCH,
diff --git a/src/lxc/commands_utils.c b/src/lxc/commands_utils.c
index 884a18ea1c..dbc06bf334 100644
--- a/src/lxc/commands_utils.c
+++ b/src/lxc/commands_utils.c
@@ -185,5 +185,6 @@ int lxc_add_state_client(int state_client_fd, struct lxc_handler *handler,
 
 	move_ptr(newclient);
 	move_ptr(tmplist);
-	return log_trace(MAX_STATE, "Added state client %d to state client list", state_client_fd);
+	TRACE("Added state client fd %d to state client list", state_client_fd);
+	return MAX_STATE;
 }
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 68e5b3400a..bf0c44d217 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -2064,10 +2064,11 @@ WRAP_API_1(bool, lxcapi_reboot2, int)
 
 static bool do_lxcapi_shutdown(struct lxc_container *c, int timeout)
 {
+	__do_close_prot_errno int state_client_fd = -EBADF;
+	int haltsignal = SIGPWR;
+	lxc_state_t states[MAX_STATE] = {0};
 	int killret, ret;
 	pid_t pid;
-	int haltsignal = SIGPWR, state_client_fd = -EBADF;
-	lxc_state_t states[MAX_STATE] = {0};
 
 	if (!c)
 		return false;
@@ -2107,20 +2108,15 @@ static bool do_lxcapi_shutdown(struct lxc_container *c, int timeout)
 
 	/* Send shutdown signal to container. */
 	killret = kill(pid, haltsignal);
-	if (killret < 0) {
-		if (state_client_fd >= 0)
-			close(state_client_fd);
+	if (killret < 0)
+		return log_warn(false, "Failed to send signal %d to pid %d", haltsignal, pid);
 
-		WARN("Failed to send signal %d to pid %d", haltsignal, pid);
-		return false;
-	}
 	TRACE("Sent signal %d to pid %d", haltsignal, pid);
 
 	if (timeout == 0)
 		return true;
 
 	ret = lxc_cmd_sock_rcv_state(state_client_fd, timeout);
-	close(state_client_fd);
 	if (ret < 0)
 		return false;
 


More information about the lxc-devel mailing list