X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Fnspawn%2Fnspawn.c;h=a4eefe5eb88c071d53981734bfcbd4351f09e763;hb=6bedfcbb2970e06a4d3280c8fb62083d252ede73;hp=5702df8ab47c6716ae83afb461803038eec91f3d;hpb=16a012b1d073b11dfd88c1af6e034252bd2a1486;p=thirdparty%2Fsystemd.git diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 5702df8ab47..a4eefe5eb88 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -50,7 +50,6 @@ #include "base-filesystem.h" #include "blkid-util.h" #include "btrfs-util.h" -#include "build.h" #include "cap-list.h" #include "capability.h" #include "cgroup-util.h" @@ -58,6 +57,7 @@ #include "dev-setup.h" #include "env-util.h" #include "event-util.h" +#include "fd-util.h" #include "fdset.h" #include "fileio.h" #include "formats-util.h" @@ -70,6 +70,14 @@ #include "missing.h" #include "mkdir.h" #include "netlink-util.h" +#include "nspawn-cgroup.h" +#include "nspawn-expose-ports.h" +#include "nspawn-mount.h" +#include "nspawn-network.h" +#include "nspawn-register.h" +#include "nspawn-settings.h" +#include "nspawn-setuid.h" +#include "parse-util.h" #include "path-util.h" #include "process-util.h" #include "ptyfwd.h" @@ -79,19 +87,14 @@ #include "seccomp-util.h" #endif #include "signal-util.h" +#include "socket-util.h" +#include "string-util.h" #include "strv.h" #include "terminal-util.h" #include "udev-util.h" +#include "user-util.h" #include "util.h" -#include "nspawn-settings.h" -#include "nspawn-mount.h" -#include "nspawn-network.h" -#include "nspawn-expose-ports.h" -#include "nspawn-cgroup.h" -#include "nspawn-register.h" -#include "nspawn-setuid.h" - typedef enum ContainerStatus { CONTAINER_TERMINATED, CONTAINER_REBOOTED @@ -277,27 +280,6 @@ static int custom_mounts_prepare(void) { return 0; } -static int set_sanitized_path(char **b, const char *path) { - char *p; - - assert(b); - assert(path); - - p = canonicalize_file_name(path); - if (!p) { - if (errno != ENOENT) - return -errno; - - p = path_make_absolute_cwd(path); - if (!p) - return -ENOMEM; - } - - free(*b); - *b = path_kill_slashes(p); - return 0; -} - static int detect_unified_cgroup_hierarchy(void) { const char *e; int r; @@ -414,29 +396,24 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case 'D': - r = set_sanitized_path(&arg_directory, optarg); + r = parse_path_argument_and_warn(optarg, false, &arg_directory); if (r < 0) - return log_error_errno(r, "Invalid root directory: %m"); - + return r; break; case ARG_TEMPLATE: - r = set_sanitized_path(&arg_template, optarg); + r = parse_path_argument_and_warn(optarg, false, &arg_template); if (r < 0) - return log_error_errno(r, "Invalid template directory: %m"); - + return r; break; case 'i': - r = set_sanitized_path(&arg_image, optarg); + r = parse_path_argument_and_warn(optarg, false, &arg_image); if (r < 0) - return log_error_errno(r, "Invalid image path: %m"); - + return r; break; case 'x': @@ -1264,16 +1241,7 @@ static int setup_dev_console(const char *dest, const char *console) { static int setup_kmsg(const char *dest, int kmsg_socket) { const char *from, *to; _cleanup_umask_ mode_t u; - int fd, k; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(int))]; - } control = {}; - struct msghdr mh = { - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg; + int fd, r; assert(kmsg_socket >= 0); @@ -1298,21 +1266,13 @@ static int setup_kmsg(const char *dest, int kmsg_socket) { if (fd < 0) return log_error_errno(errno, "Failed to open fifo: %m"); - cmsg = CMSG_FIRSTHDR(&mh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); - - mh.msg_controllen = cmsg->cmsg_len; - /* Store away the fd in the socket, so that it stays open as * long as we run the child */ - k = sendmsg(kmsg_socket, &mh, MSG_NOSIGNAL); + r = send_one_fd(kmsg_socket, fd, 0); safe_close(fd); - if (k < 0) - return log_error_errno(errno, "Failed to send FIFO fd: %m"); + if (r < 0) + return log_error_errno(r, "Failed to send FIFO fd: %m"); /* And now make the FIFO unavailable as /run/kmsg... */ (void) unlink(from); @@ -2299,8 +2259,6 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) { return r; } -static void nop_handler(int sig) {} - static int on_orderly_shutdown(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { pid_t pid; @@ -2344,9 +2302,9 @@ static int determine_names(void) { } if (i->type == IMAGE_RAW) - r = set_sanitized_path(&arg_image, i->path); + r = free_and_strdup(&arg_image, i->path); else - r = set_sanitized_path(&arg_directory, i->path); + r = free_and_strdup(&arg_directory, i->path); if (r < 0) return log_error_errno(r, "Invalid image directory: %m"); @@ -2472,7 +2430,11 @@ static int inner_child( } } - r = mount_all(NULL, true, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context); + r = mount_all(NULL, arg_userns, true, arg_uid_shift, arg_private_network, arg_uid_range, arg_selinux_apifs_context); + if (r < 0) + return r; + + r = mount_sysfs(NULL); if (r < 0) return r; @@ -2723,7 +2685,7 @@ static int outer_child( return log_error_errno(r, "Failed to make tree read-only: %m"); } - r = mount_all(directory, false, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context); + r = mount_all(directory, arg_userns, false, arg_private_network, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context); if (r < 0) return r; @@ -2804,6 +2766,8 @@ static int outer_child( } pid_socket = safe_close(pid_socket); + kmsg_socket = safe_close(kmsg_socket); + rtnl_socket = safe_close(rtnl_socket); return 0; } @@ -2928,11 +2892,17 @@ static int load_settings(void) { } if ((arg_settings_mask & SETTING_CAPABILITY) == 0) { + uint64_t plus; - if (!arg_settings_trusted && settings->capability != 0) - log_warning("Ignoring Capability= setting, file %s is not trusted.", p); - else - arg_retain |= settings->capability; + plus = settings->capability; + if (settings_private_network(settings)) + plus |= (1ULL << CAP_NET_ADMIN); + + if (!arg_settings_trusted && plus != 0) { + if (settings->capability != 0) + log_warning("Ignoring Capability= setting, file %s is not trusted.", p); + } else + arg_retain |= plus; arg_retain &= ~settings->drop_capability; } @@ -2988,6 +2958,9 @@ static int load_settings(void) { if (!arg_settings_trusted) log_warning("Ignoring network settings, file %s is not trusted.", p); else { + arg_network_veth = settings_private_network(settings); + arg_private_network = settings_private_network(settings); + strv_free(arg_network_interfaces); arg_network_interfaces = settings->network_interfaces; settings->network_interfaces = NULL; @@ -3003,10 +2976,6 @@ static int load_settings(void) { free(arg_network_bridge); arg_network_bridge = settings->network_bridge; settings->network_bridge = NULL; - - arg_network_veth = settings->network_veth > 0 || settings->network_bridge; - - arg_private_network = true; /* all these settings imply private networking */ } } @@ -3112,7 +3081,7 @@ int main(int argc, char *argv[]) { goto finish; } - r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE); + r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA); if (r < 0) { log_error_errno(r, "Failed to create snapshot %s from %s: %m", np, arg_directory); goto finish; @@ -3136,7 +3105,7 @@ int main(int argc, char *argv[]) { } if (arg_template) { - r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE); + r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA); if (r == -EEXIST) { if (!arg_quiet) log_info("Directory %s already exists, not populating from template %s.", arg_directory, arg_template); @@ -3159,10 +3128,9 @@ int main(int argc, char *argv[]) { } else { const char *p; - p = strjoina(arg_directory, - argc > optind && path_is_absolute(argv[optind]) ? argv[optind] : "/usr/bin/"); - if (access(p, F_OK) < 0) { - log_error("Directory %s lacks the binary to execute or doesn't look like a binary tree. Refusing.", arg_directory); + p = strjoina(arg_directory, "/usr/"); + if (laccess(p, F_OK) < 0) { + log_error("Directory %s doesn't look like it has an OS tree. Refusing.", arg_directory); r = -EINVAL; goto finish; } @@ -3256,7 +3224,7 @@ int main(int argc, char *argv[]) { ContainerStatus container_status; _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL; static const struct sigaction sa = { - .sa_handler = nop_handler, + .sa_handler = nop_signal_handler, .sa_flags = SA_NOCLDSTOP, }; int ifi = 0; @@ -3353,8 +3321,7 @@ int main(int argc, char *argv[]) { barrier_set_role(&barrier, BARRIER_PARENT); - fdset_free(fds); - fds = NULL; + fds = fdset_free(fds); kmsg_socket_pair[1] = safe_close(kmsg_socket_pair[1]); rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]); @@ -3489,8 +3456,8 @@ int main(int argc, char *argv[]) { } /* Let the child know that we are ready and wait that the child is completely ready now. */ - if (!barrier_place_and_sync(&barrier)) { /* #5 */ - log_error("Client died too early."); + if (!barrier_place_and_sync(&barrier)) { /* #4 */ + log_error("Child died too early."); r = -ESRCH; goto finish; } @@ -3529,7 +3496,7 @@ int main(int argc, char *argv[]) { rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); - r = pty_forward_new(event, master, true, !interactive, &forward); + r = pty_forward_new(event, master, PTY_FORWARD_IGNORE_VHANGUP | (interactive ? 0 : PTY_FORWARD_READ_ONLY), &forward); if (r < 0) { log_error_errno(r, "Failed to create PTY forwarder: %m"); goto finish; @@ -3608,7 +3575,7 @@ finish: if (remove_subvol && arg_directory) { int k; - k = btrfs_subvol_remove(arg_directory, true); + k = btrfs_subvol_remove(arg_directory, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA); if (k < 0) log_warning_errno(k, "Cannot remove subvolume '%s', ignoring: %m", arg_directory); }