diff --git a/0003-refactor-patch-code-of-isulad-for-selinux-attach.patch b/0003-refactor-patch-code-of-isulad-for-selinux-attach.patch new file mode 100644 index 0000000000000000000000000000000000000000..6c2ecfae558e5e5b7cfdbe037529724aa093e3ca --- /dev/null +++ b/0003-refactor-patch-code-of-isulad-for-selinux-attach.patch @@ -0,0 +1,1245 @@ +From 44dd71a4d76eb464b81890ea3cfa2ac9c6c3d990 Mon Sep 17 00:00:00 2001 +From: haozi007 +Date: Tue, 19 Jul 2022 14:40:59 +0800 +Subject: [PATCH] refactor patch code of isulad for selinux/attach + +Signed-off-by: haozi007 +--- + src/lxc/exec_commands.c | 471 +++++++++++++++++++++++++++++++++++++ + src/lxc/lsm/selinux.c | 258 ++++++++++++++++++++ + src/lxc/tools/lxc_attach.c | 415 +++++++++++++++++++++++++++++++- + 3 files changed, 1143 insertions(+), 1 deletion(-) + create mode 100644 src/lxc/exec_commands.c + +diff --git a/src/lxc/exec_commands.c b/src/lxc/exec_commands.c +new file mode 100644 +index 0000000..50246fa +--- /dev/null ++++ b/src/lxc/exec_commands.c +@@ -0,0 +1,471 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved. ++ * Author: lifeng ++ * Create: 2019-12-08 ++ * Description: provide container definition ++ * lxc: linux Container library ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ ******************************************************************************/ ++ ++#ifndef _GNU_SOURCE ++#define _GNU_SOURCE 1 ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "af_unix.h" ++#include "cgroup.h" ++#include "exec_commands.h" ++#include "commands_utils.h" ++#include "conf.h" ++#include "config.h" ++#include "confile.h" ++#include "log.h" ++#include "lxc.h" ++#include "lxclock.h" ++#include "mainloop.h" ++#include "monitor.h" ++#include "terminal.h" ++#include "utils.h" ++ ++lxc_log_define(commands_exec, lxc); ++ ++static const char *lxc_exec_cmd_str(lxc_exec_cmd_t cmd) ++{ ++ static const char *const cmdname[LXC_EXEC_CMD_MAX] = { ++ [LXC_EXEC_CMD_SET_TERMINAL_WINCH] = "set_exec_terminal_winch", ++ }; ++ ++ if (cmd >= LXC_EXEC_CMD_MAX) ++ return "Invalid request"; ++ ++ return cmdname[cmd]; ++} ++ ++static int lxc_exec_cmd_rsp_recv(int sock, struct lxc_exec_cmd_rr *cmd) ++{ ++ int ret, rspfd; ++ struct lxc_exec_cmd_rsp *rsp = &cmd->rsp; ++ ++ ret = lxc_abstract_unix_recv_fds_timeout(sock, &rspfd, 1, rsp, sizeof(*rsp), 1000 * 1000); ++ if (ret < 0) { ++ SYSERROR("Failed to receive response for command \"%s\"", ++ lxc_exec_cmd_str(cmd->req.cmd)); ++ ++ if (errno == ECONNRESET || errno == EAGAIN || errno == EWOULDBLOCK) { ++ errno = ECONNRESET; /*isulad set errno ECONNRESET when timeout */ ++ return -1; ++ } ++ ++ return -1; ++ } ++ TRACE("Command \"%s\" received response", lxc_exec_cmd_str(cmd->req.cmd)); ++ ++ if (rsp->datalen == 0) { ++ DEBUG("Response data length for command \"%s\" is 0", ++ lxc_exec_cmd_str(cmd->req.cmd)); ++ return ret; ++ } ++ ++ if (rsp->datalen > LXC_CMD_DATA_MAX) { ++ ERROR("Response data for command \"%s\" is too long: %d bytes > %d", ++ lxc_exec_cmd_str(cmd->req.cmd), rsp->datalen, LXC_CMD_DATA_MAX); ++ return -1; ++ } ++ ++ rsp->data = malloc(rsp->datalen); ++ if (!rsp->data) { ++ errno = ENOMEM; ++ ERROR("Failed to allocate response buffer for command \"%s\"", ++ lxc_exec_cmd_str(cmd->req.cmd)); ++ return -1; ++ } ++ ++ ret = lxc_recv_nointr(sock, rsp->data, rsp->datalen, 0); ++ if (ret != rsp->datalen) { ++ SYSERROR("Failed to receive response data for command \"%s\"", ++ lxc_exec_cmd_str(cmd->req.cmd)); ++ return -1; ++ } ++ ++ return ret; ++} ++ ++static int lxc_exec_cmd_rsp_send(int fd, struct lxc_exec_cmd_rsp *rsp) ++{ ++ ssize_t ret; ++ ++ errno = EMSGSIZE; ++ ret = lxc_send_nointr(fd, rsp, sizeof(*rsp), MSG_NOSIGNAL); ++ if (ret < 0 || (size_t)ret != sizeof(*rsp)) { ++ SYSERROR("Failed to send command response %zd", ret); ++ return -1; ++ } ++ ++ if (!rsp->data || rsp->datalen <= 0) ++ return 0; ++ ++ errno = EMSGSIZE; ++ ret = lxc_send_nointr(fd, rsp->data, rsp->datalen, MSG_NOSIGNAL); ++ if (ret < 0 || ret != (ssize_t)rsp->datalen) { ++ SYSWARN("Failed to send command response data %zd", ret); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int lxc_exec_cmd_send(const char *name, struct lxc_exec_cmd_rr *cmd, ++ const char *lxcpath, const char *hashed_sock_name, const char *suffix) ++{ ++ int client_fd, saved_errno; ++ ssize_t ret = -1; ++ ++ client_fd = lxc_cmd_connect(name, lxcpath, hashed_sock_name, suffix); ++ if (client_fd < 0) ++ return -1; ++ ++ ret = lxc_abstract_unix_send_credential(client_fd, &cmd->req, ++ sizeof(cmd->req)); ++ if (ret < 0 || (size_t)ret != sizeof(cmd->req)) ++ goto on_error; ++ ++ if (cmd->req.datalen <= 0) ++ return client_fd; ++ ++ errno = EMSGSIZE; ++ ret = lxc_send_nointr(client_fd, (void *)cmd->req.data, ++ cmd->req.datalen, MSG_NOSIGNAL); ++ if (ret < 0 || ret != (ssize_t)cmd->req.datalen) ++ goto on_error; ++ ++ return client_fd; ++ ++on_error: ++ saved_errno = errno; ++ close(client_fd); ++ errno = saved_errno; ++ ++ return -1; ++} ++ ++static int lxc_exec_cmd(const char *name, struct lxc_exec_cmd_rr *cmd, const char *lxcpath, const char *hashed_sock_name, const char *suffix) ++{ ++ int client_fd = -1; ++ int saved_errno; ++ int ret = -1; ++ ++ client_fd = lxc_exec_cmd_send(name, cmd, lxcpath, hashed_sock_name, suffix); ++ if (client_fd < 0) { ++ SYSTRACE("Command \"%s\" failed to connect command socket", ++ lxc_exec_cmd_str(cmd->req.cmd)); ++ return -1; ++ } ++ ++ ret = lxc_exec_cmd_rsp_recv(client_fd, cmd); ++ ++ saved_errno = errno; ++ close(client_fd); ++ errno = saved_errno; ++ return ret; ++} ++ ++int lxc_exec_cmd_set_terminal_winch(const char *name, const char *lxcpath, const char *suffix, unsigned int height, unsigned int width) ++{ ++ int ret = 0; ++ struct lxc_exec_cmd_set_terminal_winch_request data = { 0 }; ++ ++ data.height = height; ++ data.width = width; ++ ++ struct lxc_exec_cmd_rr cmd = { ++ .req = { ++ .cmd = LXC_EXEC_CMD_SET_TERMINAL_WINCH, ++ .datalen = sizeof(struct lxc_exec_cmd_set_terminal_winch_request), ++ .data = &data, ++ }, ++ }; ++ ++ ret = lxc_exec_cmd(name, &cmd, lxcpath, NULL, suffix); ++ if (ret < 0) { ++ ERROR("Failed to send command to container"); ++ return -1; ++ } ++ ++ if (cmd.rsp.ret != 0) { ++ ERROR("Command response error:%d", cmd.rsp.ret); ++ return -1; ++ } ++ return 0; ++} ++ ++static int lxc_exec_cmd_set_terminal_winch_callback(int fd, struct lxc_exec_cmd_req *req, ++ struct lxc_exec_command_handler *handler) ++{ ++ struct lxc_exec_cmd_rsp rsp; ++ struct lxc_exec_cmd_set_terminal_winch_request *data = (struct lxc_exec_cmd_set_terminal_winch_request *)(req->data); ++ memset(&rsp, 0, sizeof(rsp)); ++ ++ rsp.ret = lxc_set_terminal_winsz(handler->terminal, data->height, data->width);; ++ ++ return lxc_exec_cmd_rsp_send(fd, &rsp); ++ ++} ++ ++static int lxc_exec_cmd_process(int fd, struct lxc_exec_cmd_req *req, ++ struct lxc_exec_command_handler *handler) ++{ ++ typedef int (*callback)(int, struct lxc_exec_cmd_req *, struct lxc_exec_command_handler *); ++ ++ callback cb[LXC_EXEC_CMD_MAX] = { ++ [LXC_EXEC_CMD_SET_TERMINAL_WINCH] = lxc_exec_cmd_set_terminal_winch_callback, ++ }; ++ ++ if (req->cmd >= LXC_EXEC_CMD_MAX) { ++ ERROR("Undefined command id %d", req->cmd); ++ return -1; ++ } ++ return cb[req->cmd](fd, req, handler); ++} ++ ++static void lxc_exec_cmd_fd_cleanup(int fd, struct lxc_epoll_descr *descr) ++{ ++ lxc_mainloop_del_handler(descr, fd); ++ close(fd); ++ return; ++} ++ ++static int lxc_exec_cmd_handler(int fd, uint32_t events, void *data, ++ struct lxc_epoll_descr *descr) ++{ ++ int ret; ++ struct lxc_exec_cmd_req req; ++ void *reqdata = NULL; ++ struct lxc_exec_command_handler *handler = 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_exec_cmd_str(req.cmd)); ++ ++ if (errno == EACCES) { ++ /* We don't care for the peer, just send and close. */ ++ struct lxc_exec_cmd_rsp rsp = {.ret = ret}; ++ ++ lxc_exec_cmd_rsp_send(fd, &rsp); ++ } ++ ++ goto out_close; ++ } ++ ++ if (ret == 0) ++ goto out_close; ++ ++ if (ret != sizeof(req)) { ++ WARN("Failed to receive full command request. Ignoring request " ++ "for \"%s\"", lxc_exec_cmd_str(req.cmd)); ++ ret = -1; ++ goto out_close; ++ } ++ ++ if (req.datalen > LXC_CMD_DATA_MAX) { ++ ERROR("Received command data length %d is too large for " ++ "command \"%s\"", req.datalen, lxc_exec_cmd_str(req.cmd)); ++ errno = EFBIG; ++ ret = -EFBIG; ++ goto out_close; ++ } ++ ++ if (req.datalen > 0) { ++ reqdata = alloca(req.datalen); ++ if (!reqdata) { ++ ERROR("Failed to allocate memory for \"%s\" command", ++ lxc_exec_cmd_str(req.cmd)); ++ errno = ENOMEM; ++ ret = -ENOMEM; ++ goto out_close; ++ } ++ ++ 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_exec_cmd_str(req.cmd)); ++ ret = LXC_MAINLOOP_ERROR; ++ goto out_close; ++ } ++ ++ req.data = reqdata; ++ } ++ ++ ret = lxc_exec_cmd_process(fd, &req, handler); ++ if (ret) { ++ /* This is not an error, but only a request to close fd. */ ++ ret = LXC_MAINLOOP_CONTINUE; ++ goto out_close; ++ } ++ ++out: ++ return ret; ++ ++out_close: ++ lxc_exec_cmd_fd_cleanup(fd, descr); ++ goto out; ++} ++ ++static int lxc_exec_cmd_accept(int fd, uint32_t events, void *data, ++ struct lxc_epoll_descr *descr) ++{ ++ int connection = -1; ++ int opt = 1, ret = -1; ++ ++ connection = accept(fd, NULL, 0); ++ if (connection < 0) { ++ SYSERROR("Failed to accept connection to run command"); ++ return LXC_MAINLOOP_ERROR; ++ } ++ ++ ret = fcntl(connection, F_SETFD, FD_CLOEXEC); ++ if (ret < 0) { ++ SYSERROR("Failed to set close-on-exec on incoming command connection"); ++ goto out_close; ++ } ++ ++ ret = setsockopt(connection, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt)); ++ if (ret < 0) { ++ SYSERROR("Failed to enable necessary credentials on command socket"); ++ goto out_close; ++ } ++ ++ ret = lxc_mainloop_add_handler(descr, connection, lxc_exec_cmd_handler, data); ++ if (ret) { ++ ERROR("Failed to add command handler"); ++ goto out_close; ++ } ++ ++out: ++ return ret; ++ ++out_close: ++ close(connection); ++ goto out; ++} ++#ifdef HAVE_ISULAD ++int lxc_exec_unix_sock_delete(const char *name, const char *suffix) ++{ ++ char path[LXC_AUDS_ADDR_LEN] = {0}; ++ ++ if (name == NULL || suffix == NULL) ++ return -1; ++ ++ if (generate_named_unix_sock_path(name, suffix, path, sizeof(path)) != 0) ++ return -1; ++ ++ (void)unlink(path); ++ ++ return 0; ++} ++ ++int lxc_exec_cmd_init(const char *name, const char *lxcpath, const char *suffix) ++{ ++ __do_close int fd = -EBADF; ++ int ret; ++ char path[LXC_AUDS_ADDR_LEN] = {0}; ++ __do_free char *exec_sock_dir = NULL; ++ ++ exec_sock_dir = generate_named_unix_sock_dir(name); ++ if (exec_sock_dir == NULL) ++ return -1; ++ ++ if (mkdir_p(exec_sock_dir, 0600) < 0) ++ return log_error_errno(-1, errno, "Failed to create exec sock directory %s", path); ++ ++ if (generate_named_unix_sock_path(name, suffix, path, sizeof(path)) != 0) ++ return -1; ++ ++ TRACE("Creating unix socket \"%s\"", path); ++ ++ fd = lxc_named_unix_open(path, SOCK_STREAM, 0); ++ if (fd < 0) { ++ if (errno == EADDRINUSE) { ++ WARN("Container \"%s\" exec unix sock is occupied", name); ++ (void)unlink(path); ++ fd = lxc_named_unix_open(path, SOCK_STREAM, 0); ++ if (fd < 0) ++ return log_error_errno(-1, errno, "Failed to create command socket %s", path); ++ } else { ++ return log_error_errno(-1, errno, "Failed to create command socket %s", path); ++ } ++ } ++ ++ ret = fcntl(fd, F_SETFD, FD_CLOEXEC); ++ if (ret < 0) ++ return log_error_errno(-1, errno, "Failed to set FD_CLOEXEC on command socket file descriptor"); ++ ++ return log_trace(move_fd(fd), "Created unix socket \"%s\"", path); ++} ++#else ++int lxc_exec_cmd_init(const char *name, const char *lxcpath, const char *suffix) ++{ ++ int fd, ret; ++ char path[LXC_AUDS_ADDR_LEN] = {0}; ++ ++ ret = lxc_make_abstract_socket_name(path, sizeof(path), name, lxcpath, NULL, suffix); ++ if (ret < 0) ++ return -1; ++ TRACE("Creating abstract unix socket \"%s\"", &path[1]); ++ ++ fd = lxc_abstract_unix_open(path, SOCK_STREAM, 0); ++ if (fd < 0) { ++ SYSERROR("Failed to create command socket %s", &path[1]); ++ if (errno == EADDRINUSE) ++ ERROR("Container \"%s\" appears to be already running", name); ++ ++ return -1; ++ } ++ ++ ret = fcntl(fd, F_SETFD, FD_CLOEXEC); ++ if (ret < 0) { ++ SYSERROR("Failed to set FD_CLOEXEC on command socket file descriptor"); ++ close(fd); ++ return -1; ++ } ++ ++ return fd; ++} ++#endif ++ ++int lxc_exec_cmd_mainloop_add(struct lxc_epoll_descr *descr, struct lxc_exec_command_handler *handler) ++{ ++ int ret; ++ int fd = handler->maincmd_fd; ++ ++ ret = lxc_mainloop_add_handler(descr, fd, lxc_exec_cmd_accept, handler); ++ if (ret < 0) { ++ ERROR("Failed to add handler for command socket"); ++ close(fd); ++ } ++ ++ return ret; ++} +diff --git a/src/lxc/lsm/selinux.c b/src/lxc/lsm/selinux.c +index dba0ab5..bd4f449 100644 +--- a/src/lxc/lsm/selinux.c ++++ b/src/lxc/lsm/selinux.c +@@ -16,6 +16,10 @@ + #include "log.h" + #include "lsm.h" + ++#ifdef HAVE_ISULAD ++#include ++#endif ++ + #define DEFAULT_LABEL "unconfined_t" + + lxc_log_define(selinux, lsm); +@@ -85,6 +89,256 @@ static int selinux_process_label_set(const char *inlabel, struct lxc_conf *conf, + return 0; + } + ++#ifdef HAVE_ISULAD ++/* ++ * selinux_file_label_set: Set SELinux context of a file ++ * ++ * @path : a file ++ * @label : label string ++ * ++ * Returns 0 on success, < 0 on failure ++ */ ++static int selinux_file_label_set(const char *path, const char *label) ++{ ++ if (path == NULL || label == NULL || strcmp(label, "unconfined_t") == 0) { ++ return 0; ++ } ++ ++ if (!is_selinux_enabled()) { ++ return 0; ++ } ++ ++ if (lsetfilecon(path, label) != 0) { ++ SYSERROR("Failed to setSELinux context to \"%s\": %s", label, path); ++ return -1; ++ } ++ ++ INFO("Changed SELinux context to \"%s\": %s", label, path); ++ return 0; ++} ++ ++/* ++ * is_exclude_relabel_path: Determine whether it is a excluded path to label ++ * ++ * @path : a file or directory ++ * ++ * Returns 0 on success, < 0 on failure ++ */ ++static bool is_exclude_relabel_path(const char *path) ++{ ++ const char *exclude_path[] = { "/", "/usr", "/etc", "/tmp", "/home", "/run", "/var", "/root" }; ++ size_t i; ++ ++ for (i = 0; i < sizeof(exclude_path) / sizeof(char *); i++) { ++ if (strcmp(path, exclude_path[i]) == 0) { ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++/* ++ * bad_prefix: Prevent users from relabing system files ++ * ++ * @path : a file or directory ++ * ++ * Returns 0 on success, < 0 on failure ++ */ ++static int bad_prefix(const char *fpath) ++{ ++ const char *bad_prefixes = "/usr"; ++ ++ if (fpath == NULL) { ++ ERROR("Empty file path"); ++ return -1; ++ } ++ ++ if (strncmp(fpath, bad_prefixes, strlen(bad_prefixes)) == 0) { ++ ERROR("relabeling content in %s is not allowed", bad_prefixes); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * recurse_set_file_label: Recursively label files or folders ++ * ++ * @path : a file or directory ++ * @label : label string ++ * ++ * Returns 0 on success, < 0 on failure ++ */ ++static int recurse_set_file_label(const char *basePath, const char *label) ++{ ++ int ret = 0; ++ __do_closedir DIR *dir = NULL; ++ struct dirent *ptr = NULL; ++ char base[PATH_MAX] = { 0 }; ++ ++ if ((dir = opendir(basePath)) == NULL) { ++ ERROR("Failed to Open dir: %s", basePath); ++ return -1; ++ } ++ ++ ret = lsetfilecon(basePath, label); ++ if (ret != 0) { ++ ERROR("Failed to set file label"); ++ return ret; ++ } ++ ++ while ((ptr = readdir(dir)) != NULL) { ++ if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) { ++ continue; ++ } else { ++ int nret = snprintf(base, sizeof(base), "%s/%s", basePath, ptr->d_name); ++ if (nret < 0 || nret >= sizeof(base)) { ++ ERROR("Failed to get path"); ++ return -1; ++ } ++ if (ptr->d_type == DT_DIR) { ++ ret = recurse_set_file_label(base, label); ++ if (ret != 0) { ++ ERROR("Failed to set dir label"); ++ return ret; ++ } ++ } else { ++ ret = lsetfilecon(base, label); ++ if (ret != 0) { ++ ERROR("Failed to set file label"); ++ return ret; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * selinux_chcon: Chcon changes the `fpath` file object to the SELinux label `label`. ++ * If `fpath` is a directory and `recurse`` is true, Chcon will walk the ++ * directory tree setting the label. ++ * ++ * @fpath : a file or directory ++ * @label : label string ++ * @recurse : whether to recurse ++ * ++ * Returns 0 on success, < 0 on failure ++ */ ++static int selinux_chcon(const char *fpath, const char *label, bool recurse) ++{ ++ struct stat s_buf; ++ ++ if (fpath == NULL || label == NULL) { ++ ERROR("Invalid parameters!"); ++ return -1; ++ } ++ ++ if (bad_prefix(fpath) != 0) { ++ return -1; ++ } ++ if (stat(fpath, &s_buf) != 0) { ++ return -1; ++ } ++ if (recurse && S_ISDIR(s_buf.st_mode)) { ++ return recurse_set_file_label(fpath, label); ++ } ++ ++ if (lsetfilecon(fpath, label) != 0) { ++ ERROR("Failed to set file label"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * convert_context_to_share_mode: set sensitivity to s0 and remove categories ++ * user:role:type:sensitivity[:categories] => user:role:type:s0 ++ * ++ * @label : label string ++ * ++ * Returns label with share mode on success, NULL on failure ++ */ ++static char *convert_context_to_share_mode(const char *label) { ++ __do_free char *converted_label = strdup(label); ++ char *s = converted_label; ++ const char *shared_level = "s0"; ++ int cnt = 0; ++ ++ // selinux label format: user:role:type:sensitivity[:categories] ++ // locates the ":" position in front of the sensitivity ++ while (cnt++ < 3 && (s = strchr(s, ':')) != NULL) { ++ s++; ++ } ++ ++ // make sure sensitivity can set s0 value ++ if (s == NULL || strlen(s) < strlen(shared_level)) { ++ ERROR("Invalid selinux file context: %s", label); ++ return NULL; ++ } ++ ++ if (strcmp(s, shared_level) == 0) { ++ return move_ptr(converted_label); ++ } ++ ++ *s = '\0'; ++ strcat(converted_label, shared_level); ++ ++ return move_ptr(converted_label); ++} ++ ++/* ++ * selinux_relabel: Relabel changes the label of path to the filelabel string. ++ * It changes the MCS label to s0 if shared is true. ++ * This will allow all containers to share the content. ++ * ++ * @path : a file or directory ++ * @label : label string ++ * @shared : whether to use share mode ++ * ++ * Returns 0 on success, < 0 on failure ++ */ ++static int selinux_relabel(const char *path, const char *label, bool shared) ++{ ++ __do_free char *tmp_file_label = NULL; ++ ++ if (path == NULL || label == NULL) { ++ return 0; ++ } ++ ++ if (!is_selinux_enabled()) { ++ return 0; ++ } ++ ++ if (is_exclude_relabel_path(path)) { ++ ERROR("SELinux relabeling of %s is not allowed", path); ++ return -1; ++ } ++ ++ if (shared) { ++ tmp_file_label = convert_context_to_share_mode(label); ++ if (tmp_file_label == NULL) { ++ ERROR("Failed to convert context to share mode: %s", label); ++ return -1; ++ } ++ } else { ++ tmp_file_label = strdup(label); ++ } ++ ++ ++ if (selinux_chcon(path, tmp_file_label, true) != 0) { ++ ERROR("Failed to modify %s's selinux context: %s", path, tmp_file_label); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++#endif ++ + /* + * selinux_keyring_label_set: Set SELinux context that will be assigned to the keyring + * +@@ -103,6 +357,10 @@ static struct lsm_drv selinux_drv = { + .process_label_get = selinux_process_label_get, + .process_label_set = selinux_process_label_set, + .keyring_label_set = selinux_keyring_label_set, ++#ifdef HAVE_ISULAD ++ .file_label_set = selinux_file_label_set, ++ .relabel = selinux_relabel, ++#endif + }; + + struct lsm_drv *lsm_selinux_drv_init(void) +diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c +index a8f493a..58e19aa 100644 +--- a/src/lxc/tools/lxc_attach.c ++++ b/src/lxc/tools/lxc_attach.c +@@ -72,8 +72,20 @@ static const struct option my_longopts[] = { + {"set-var", required_argument, 0, 'v'}, + {"pty-log", required_argument, 0, 'L'}, + {"rcfile", required_argument, 0, 'f'}, ++#ifndef HAVE_ISULAD + {"uid", required_argument, 0, 'u'}, + {"gid", required_argument, 0, 'g'}, ++#else ++ {"workdir", required_argument, 0, 'w'}, ++ {"user", required_argument, 0, 'u'}, ++ {"in-fifo", required_argument, 0, OPT_INPUT_FIFO}, /* isulad add terminal fifos*/ ++ {"out-fifo", required_argument, 0, OPT_OUTPUT_FIFO}, ++ {"err-fifo", required_argument, 0, OPT_STDERR_FIFO}, ++ {"suffix", required_argument, 0, OPT_ATTACH_SUFFIX}, ++ {"timeout", required_argument, 0, OPT_ATTACH_TIMEOUT}, ++ {"disable-pty", no_argument, 0, OPT_DISABLE_PTY}, ++ {"open-stdin", no_argument, 0, OPT_OPEN_STDIN}, ++#endif + LXC_COMMON_OPTIONS + }; + +@@ -124,9 +136,26 @@ Options :\n\ + multiple times.\n\ + -f, --rcfile=FILE\n\ + Load configuration file FILE\n\ ++" ++#ifndef HAVE_ISULAD ++"\ + -u, --uid=UID Execute COMMAND with UID inside the container\n\ + -g, --gid=GID Execute COMMAND with GID inside the container\n\ +-", ++" ++#else ++"\ ++ -w, --workdir Working directory inside the container.\n\ ++ -u, --user User ID (format: UID[:GID])\n\ ++ --in-fifo Stdin fifo path\n\ ++ --out-fifo Stdout fifo path\n\ ++ --err-fifo Stderr fifo path\n\ ++ --suffi ID for mutli-attach on one container\n\ ++ --timeout Timeout in seconds (default: 0)\n\ ++ --disable-pty Disable pty for attach\n\ ++ --open-stdin Open stdin for attach\n\ ++" ++#endif ++, + .options = my_longopts, + .parser = my_parser, + .checker = NULL, +@@ -136,6 +165,71 @@ Options :\n\ + .gid = LXC_INVALID_GID, + }; + ++#ifdef HAVE_ISULAD ++static int parse_user_id(const char *username, char **uid, char **gid, char **tmp_dup) ++{ ++ char *tmp = NULL; ++ char *pdot = NULL; ++ ++ if (uid == NULL || gid == NULL || tmp_dup == NULL) { ++ return -1; ++ } ++ ++ if (username != NULL) { ++ tmp = strdup(username); ++ if (tmp == NULL) { ++ ERROR("Failed to duplicate user name"); ++ return -1; ++ } ++ ++ // for free tmp in caller ++ *tmp_dup = tmp; ++ pdot = strstr(tmp, ":"); ++ if (pdot != NULL) { ++ *pdot = '\0'; ++ if (pdot != tmp) { ++ // uid found ++ *uid = tmp; ++ } ++ ++ if (*(pdot + 1) != '\0') { ++ // gid found ++ *gid = pdot + 1; ++ } ++ } else { ++ // No : found ++ if (*tmp != '\0') { ++ *uid = tmp; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int get_attach_uid_gid(const char *username, uid_t *user_id, gid_t *group_id) ++{ ++ char *tmp = NULL; ++ char *uid = NULL; ++ char *gid = NULL; ++ ++ // parse uid and gid by username ++ if (parse_user_id(username, &uid, &gid, &tmp) != 0) { ++ return -1; ++ } ++ ++ if (uid != NULL) { ++ *user_id = (unsigned int)atoll(uid); ++ } ++ if (gid != NULL) { ++ *group_id = (unsigned int)atoll(gid); ++ } ++ ++ free(tmp); ++ return 0; ++} ++#endif ++ + static int my_parser(struct lxc_arguments *args, int c, char *arg) + { + int ret; +@@ -193,6 +287,7 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) + case 'f': + args->rcfile = arg; + break; ++#ifndef HAVE_ISULAD + case 'u': + if (lxc_safe_uint(arg, &args->uid) < 0) + return -1; +@@ -201,6 +296,42 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) + if (lxc_safe_uint(arg, &args->gid) < 0) + return -1; + break; ++#else ++ case 'u': ++ if (get_attach_uid_gid(arg, &args->uid, &args->gid) != 0) { ++ ERROR("Failed to get attach user U/GID"); ++ return -1; ++ } ++ break; ++ case 'w': ++ args->workdir=arg; ++ break; ++ case OPT_INPUT_FIFO: ++ args->terminal_fifos[0] = arg; ++ break; ++ case OPT_OUTPUT_FIFO: ++ args->terminal_fifos[1] = arg; ++ break; ++ case OPT_STDERR_FIFO: ++ args->terminal_fifos[2] = arg; ++ break; ++ case OPT_ATTACH_SUFFIX: ++ args->suffix = arg; ++ break; ++ case OPT_ATTACH_TIMEOUT: ++ if(!is_non_negative_num(arg)) { ++ ERROR("Error attach timeout parameter:%s.\n", arg); ++ return -1; ++ } ++ args->attach_timeout = (unsigned int)atoll(arg); ++ break; ++ case OPT_DISABLE_PTY: ++ args->disable_pty = 1; ++ break; ++ case OPT_OPEN_STDIN: ++ args->open_stdin = 1; ++ break; ++#endif + } + + return 0; +@@ -264,6 +395,287 @@ static int lxc_attach_create_log_file(const char *log_file) + return fd; + } + ++#ifdef HAVE_ISULAD ++// isulad: send '128 + signal' if container is killed by signal. ++#define EXIT_SIGNAL_OFFSET 128 ++ ++/*isulad: attach with terminal*/ ++static int do_attach_foreground(struct lxc_container *c, lxc_attach_command_t *command, ++ lxc_attach_options_t *attach_options, ++ char **errmsg) ++{ ++ int ret = 0; ++ pid_t pid; ++ int wexit = -1; ++ int signal; ++ ++ if (command->program) ++ ret = c->attach(c, lxc_attach_run_command, command, attach_options, &pid); ++ else ++ ret = c->attach(c, lxc_attach_run_shell, NULL, attach_options, &pid); ++ if (ret < 0) { ++ *errmsg = safe_strdup("Internal error, failed to call attach"); ++ goto out; ++ } ++ ++ ret = lxc_wait_for_pid_status(pid); ++ if (ret < 0) { ++ free(*errmsg); ++ *errmsg = safe_strdup("Internal error, failed to wait attached process"); ++ goto out; ++ } ++ ++ if (WIFEXITED(ret)) ++ wexit = WEXITSTATUS(ret); ++ else ++ wexit = -1; ++ ++ if (WIFSIGNALED(ret)) { ++ signal = WTERMSIG(ret); ++ wexit = EXIT_SIGNAL_OFFSET + signal; ++ } ++ ++ WARN("Execd pid %d exit with %d", pid, wexit); ++ ++out: ++ if (c->lxc_conf->errmsg) { ++ free(*errmsg); ++ *errmsg = safe_strdup(c->lxc_conf->errmsg); ++ } ++ return wexit; ++} ++ ++static void close_msg_pipe(int *errpipe) ++{ ++ if (errpipe[0] >= 0) { ++ close(errpipe[0]); ++ errpipe[0] = -1; ++ } ++ if (errpipe[1] >= 0) { ++ close(errpipe[1]); ++ errpipe[1] = -1; ++ } ++} ++ ++/*isulad: attach without terminal in background */ ++static int do_attach_background(struct lxc_container *c, lxc_attach_command_t *command, ++ lxc_attach_options_t *attach_options, ++ char **errmsg) ++{ ++ int ret = 0; ++ int msgpipe[2]; ++ pid_t pid = 0; ++ ssize_t size_read; ++ char msgbuf[BUFSIZ + 1] = {0}; ++ ++ //pipdfd for get error message of child or grandchild process. ++ if (pipe2(msgpipe, O_CLOEXEC) != 0) { ++ SYSERROR("Failed to init msgpipe"); ++ return -1; ++ } ++ ++ pid = fork(); ++ if (pid < 0) { ++ close_msg_pipe(msgpipe); ++ return -1; ++ } ++ ++ if (pid != 0) { ++ close(msgpipe[1]); ++ msgpipe[1] = -1; ++ size_read = read(msgpipe[0], msgbuf, BUFSIZ); ++ if (size_read > 0) { ++ *errmsg = safe_strdup(msgbuf); ++ ret = -1; ++ } ++ ++ close(msgpipe[0]); ++ msgpipe[0] = -1; ++ ++ return ret; ++ } ++ ++ /* second fork to be reparented by init */ ++ pid = fork(); ++ if (pid < 0) { ++ SYSERROR("Error doing dual-fork"); ++ close_msg_pipe(msgpipe); ++ exit(1); ++ } ++ if (pid != 0) { ++ close_msg_pipe(msgpipe); ++ exit(0); ++ } ++ ++ close(msgpipe[0]); ++ msgpipe[0] = -1; ++ ++ if (null_stdfds() < 0) { ++ ERROR("failed to close fds"); ++ exit(1); ++ } ++ setsid(); ++ ++ if (command->program) ++ ret = c->attach(c, lxc_attach_run_command, command, attach_options, &pid); ++ else ++ ret = c->attach(c, lxc_attach_run_shell, NULL, attach_options, &pid); ++ if (ret < 0) { ++ if (c->lxc_conf->errmsg) ++ lxc_write_error_message(msgpipe[1], "%s", c->lxc_conf->errmsg); ++ else ++ lxc_write_error_message(msgpipe[1], "Failed to attach container"); ++ close(msgpipe[1]); ++ msgpipe[1] = -1; ++ ret = -1; ++ goto out; ++ } ++ ++ close(msgpipe[1]); ++ msgpipe[1] = -1; ++ ++ ret = wait_for_pid(pid); ++out: ++ lxc_container_put(c); ++ if (ret) ++ exit(EXIT_FAILURE); ++ else ++ exit(0); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int wexit = 0; ++ struct lxc_log log; ++ char *errmsg = NULL; ++ lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; ++ lxc_attach_command_t command = (lxc_attach_command_t){.program = NULL}; ++ ++ if (lxc_caps_init()) ++ exit(EXIT_FAILURE); ++ ++ if (lxc_arguments_parse(&my_args, argc, argv)) ++ exit(EXIT_FAILURE); ++ ++ log.name = my_args.name; ++ log.file = my_args.log_file; ++ log.level = my_args.log_priority; ++ log.prefix = my_args.progname; ++ log.quiet = my_args.quiet; ++ log.lxcpath = my_args.lxcpath[0]; ++ ++ if (lxc_log_init(&log)) ++ exit(EXIT_FAILURE); ++ ++ if (geteuid()) ++ if (access(my_args.lxcpath[0], O_RDONLY) < 0) { ++ ERROR("You lack access to %s", my_args.lxcpath[0]); ++ exit(EXIT_FAILURE); ++ } ++ ++ struct lxc_container *c = lxc_container_new(my_args.name, my_args.lxcpath[0]); ++ if (!c) ++ exit(EXIT_FAILURE); ++ ++ if (my_args.rcfile) { ++ c->clear_config(c); ++ if (!c->load_config(c, my_args.rcfile)) { ++ ERROR("Failed to load rcfile"); ++ lxc_container_put(c); ++ exit(EXIT_FAILURE); ++ } ++ ++ c->configfile = strdup(my_args.rcfile); ++ if (!c->configfile) { ++ ERROR("Out of memory setting new config filename"); ++ lxc_container_put(c); ++ exit(EXIT_FAILURE); ++ } ++ } ++ ++ if (!c->may_control(c)) { ++ ERROR("Insufficent privileges to control %s", c->name); ++ lxc_container_put(c); ++ exit(EXIT_FAILURE); ++ } ++ ++ if (remount_sys_proc) ++ attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS; ++ ++ if (elevated_privileges) ++ attach_options.attach_flags &= ~(elevated_privileges); ++ ++ if (my_args.terminal_fifos[0] || my_args.terminal_fifos[1] || my_args.terminal_fifos[2]) { ++ attach_options.init_fifo[0] = my_args.terminal_fifos[0]; ++ attach_options.init_fifo[1] = my_args.terminal_fifos[1]; ++ attach_options.init_fifo[2] = my_args.terminal_fifos[2]; ++ attach_options.attach_flags |= LXC_ATTACH_TERMINAL; ++ } else if (stdfd_is_pty()) { ++ attach_options.attach_flags |= LXC_ATTACH_TERMINAL; ++ } ++ ++ attach_options.namespaces = namespace_flags; ++ attach_options.personality = new_personality; ++ attach_options.env_policy = env_policy; ++ attach_options.extra_env_vars = extra_env; ++ attach_options.extra_keep_env = extra_keep; ++ attach_options.timeout = my_args.attach_timeout; ++ ++ if (my_args.argc > 0) { ++ command.program = my_args.argv[0]; ++ command.argv = (char**)my_args.argv; ++ } ++ ++ if (my_args.console_log) { ++ attach_options.log_fd = lxc_attach_create_log_file(my_args.console_log); ++ if (attach_options.log_fd < 0) { ++ ERROR("Failed to create log file for %s", c->name); ++ lxc_container_put(c); ++ exit(EXIT_FAILURE); ++ } ++ } ++ ++ if (my_args.uid != LXC_INVALID_UID) ++ attach_options.uid = my_args.uid; ++ ++ if (my_args.gid != LXC_INVALID_GID) ++ attach_options.gid = my_args.gid; ++ ++ attach_options.suffix = my_args.suffix; ++ ++ if (my_args.disable_pty) { ++ attach_options.disable_pty = true; ++ } ++ ++ if (my_args.open_stdin) { ++ attach_options.open_stdin = true; ++ } ++ ++#ifdef HAVE_ISULAD ++ if (my_args.workdir) { ++ attach_options.initial_cwd = my_args.workdir; ++ } ++#endif ++ ++ /* isulad: add do attach background */ ++ if (attach_options.attach_flags & LXC_ATTACH_TERMINAL) ++ wexit = do_attach_foreground(c, &command, &attach_options, &errmsg); ++ else ++ wexit = do_attach_background(c, &command, &attach_options, &errmsg); ++ ++ if (errmsg) { ++ fprintf(stderr, "%s:%s:%s:%d starting container process caused \"%s\"", c->name, ++ __FILE__, __func__, __LINE__, errmsg); ++ free(errmsg); ++ } ++ ++ lxc_container_put(c); ++ if (wexit >= 0) ++ exit(wexit); ++ ++ exit(EXIT_FAILURE); ++} ++#else + int main(int argc, char *argv[]) + { + int ret = -1; +@@ -377,3 +789,4 @@ out: + + exit(EXIT_FAILURE); + } ++#endif +-- +2.25.1 + diff --git a/lxc.spec b/lxc.spec index 67c38dc0872942da4861d7aead77b51b8f7f55af..413b15a999d33c46108867a2efa72a94da21a969 100644 --- a/lxc.spec +++ b/lxc.spec @@ -1,4 +1,4 @@ -%global _release 2022071801 +%global _release 2022071901 Name: lxc Version: 4.0.3 @@ -10,6 +10,7 @@ Source0: https://linuxcontainers.org/downloads/lxc/lxc-4.0.3.tar.gz Patch0001: 0001-refactor-patch-code-of-utils-commands-and-so-on.patch Patch0002: 0002-refactor-patch-code-of-isulad-for-conf-exec-attach.patch +Patch0003: 0003-refactor-patch-code-of-isulad-for-selinux-attach.patch BuildRequires: systemd-units git libtool graphviz docbook2X doxygen chrpath BuildRequires: pkgconfig(libseccomp) @@ -181,6 +182,12 @@ make check %{_mandir}/*/man7/%{name}* %changelog +* Thu Jul 19 2022 haozi007 - 4.0.3-2022071901 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: refactor patch code of isulad for selinux/attach + * Mon Jul 18 2022 haozi007 - 4.0.3-2022071801 - Type:bugfix - ID:NA