diff options
Diffstat (limited to 'pasta.c')
-rw-r--r-- | pasta.c | 114 |
1 files changed, 79 insertions, 35 deletions
@@ -12,8 +12,8 @@ * Author: Stefano Brivio <sbrivio@redhat.com> * * #syscalls:pasta clone waitid exit exit_group rt_sigprocmask - * #syscalls:pasta rt_sigreturn|sigreturn armv6l:sigreturn armv7l:sigreturn - * #syscalls:pasta ppc64:sigreturn s390x:sigreturn + * #syscalls:pasta rt_sigreturn|sigreturn + * #syscalls:pasta arm:sigreturn ppc64:sigreturn s390x:sigreturn i686:sigreturn */ #include <sched.h> @@ -50,6 +50,8 @@ #include "netlink.h" #include "log.h" +#define HOSTNAME_PREFIX "pasta-" + /* PID of child, in case we created a namespace */ int pasta_child_pid; @@ -59,6 +61,7 @@ int pasta_child_pid; */ void pasta_child_handler(int signal) { + int errno_save = errno; siginfo_t infop; (void)signal; @@ -83,6 +86,8 @@ void pasta_child_handler(int signal) waitid(P_ALL, 0, NULL, WEXITED | WNOHANG); waitid(P_ALL, 0, NULL, WEXITED | WNOHANG); + + errno = errno_save; } /** @@ -97,7 +102,9 @@ static int pasta_wait_for_ns(void *arg) int flags = O_RDONLY | O_CLOEXEC; char ns[PATH_MAX]; - snprintf(ns, PATH_MAX, "/proc/%i/ns/net", pasta_child_pid); + if (snprintf_check(ns, PATH_MAX, "/proc/%i/ns/net", pasta_child_pid)) + die_perror("Can't build netns path"); + do { while ((c->pasta_netns_fd = open(ns, flags)) < 0) { if (errno != ENOENT) @@ -138,17 +145,15 @@ void pasta_open_ns(struct ctx *c, const char *netns) int nfd = -1; nfd = open(netns, O_RDONLY | O_CLOEXEC); - if (nfd < 0) { - die("Couldn't open network namespace %s: %s", - netns, strerror(errno)); - } + if (nfd < 0) + die_perror("Couldn't open network namespace %s", netns); c->pasta_netns_fd = nfd; NS_CALL(ns_check, c); if (c->pasta_netns_fd < 0) - die("Couldn't switch to pasta namespaces: %s", strerror(errno)); + die_perror("Couldn't switch to pasta namespaces"); if (!c->no_netns_quit) { char buf[PATH_MAX] = { 0 }; @@ -176,18 +181,28 @@ struct pasta_spawn_cmd_arg { * * Return: this function never returns */ +/* cppcheck-suppress [constParameterCallback, unmatchedSuppression] */ static int pasta_spawn_cmd(void *arg) { + char hostname[HOST_NAME_MAX + 1] = HOSTNAME_PREFIX; const struct pasta_spawn_cmd_arg *a; sigset_t set; /* We run in a detached PID and mount namespace: mount /proc over */ if (mount("", "/proc", "proc", 0, NULL)) - warn("Couldn't mount /proc: %s", strerror(errno)); + warn_perror("Couldn't mount /proc"); if (write_file("/proc/sys/net/ipv4/ping_group_range", "0 0")) warn("Cannot set ping_group_range, ICMP requests might fail"); + if (!gethostname(hostname + sizeof(HOSTNAME_PREFIX) - 1, + HOST_NAME_MAX + 1 - sizeof(HOSTNAME_PREFIX)) || + errno == ENAMETOOLONG) { + hostname[HOST_NAME_MAX] = '\0'; + if (sethostname(hostname, strlen(hostname))) + warn("Unable to set pasta-prefixed hostname"); + } + /* Wait for the parent to be ready: see main() */ sigemptyset(&set); sigaddset(&set, SIGUSR1); @@ -196,8 +211,7 @@ static int pasta_spawn_cmd(void *arg) a = (const struct pasta_spawn_cmd_arg *)arg; execvp(a->exe, a->argv); - perror("execvp"); - exit(EXIT_FAILURE); + die_perror("Failed to start command or shell"); } /** @@ -211,12 +225,13 @@ static int pasta_spawn_cmd(void *arg) void pasta_start_ns(struct ctx *c, uid_t uid, gid_t gid, int argc, char *argv[]) { + char ns_fn_stack[NS_FN_STACK_SIZE] + __attribute__ ((aligned(__alignof__(max_align_t)))); struct pasta_spawn_cmd_arg arg = { .exe = argv[0], .argv = argv, }; char uidmap[BUFSIZ], gidmap[BUFSIZ]; - char ns_fn_stack[NS_FN_STACK_SIZE]; char *sh_argv[] = { NULL, NULL }; char sh_arg0[PATH_MAX + 1]; sigset_t set; @@ -226,8 +241,11 @@ void pasta_start_ns(struct ctx *c, uid_t uid, gid_t gid, c->quiet = 1; /* Configure user and group mappings */ - snprintf(uidmap, BUFSIZ, "0 %u 1", uid); - snprintf(gidmap, BUFSIZ, "0 %u 1", gid); + if (snprintf_check(uidmap, BUFSIZ, "0 %u 1", uid)) + die_perror("Can't build uidmap"); + + if (snprintf_check(gidmap, BUFSIZ, "0 %u 1", gid)) + die_perror("Can't build gidmap"); if (write_file("/proc/self/uid_map", uidmap) || write_file("/proc/self/setgroups", "deny") || @@ -259,14 +277,12 @@ void pasta_start_ns(struct ctx *c, uid_t uid, gid_t gid, CLONE_NEWUTS | CLONE_NEWNS | SIGCHLD, (void *)&arg); - if (pasta_child_pid == -1) { - perror("clone"); - exit(EXIT_FAILURE); - } + if (pasta_child_pid == -1) + die_perror("Failed to clone process with detached namespaces"); NS_CALL(pasta_wait_for_ns, c); if (c->pasta_netns_fd < 0) - die("Failed to join network namespace: %s", strerror(errno)); + die_perror("Failed to join network namespace"); } /** @@ -277,25 +293,33 @@ void pasta_ns_conf(struct ctx *c) { int rc = 0; - rc = nl_link_up(nl_sock_ns, 1 /* lo */, 0); + rc = nl_link_set_flags(nl_sock_ns, 1 /* lo */, IFF_UP, IFF_UP); if (rc < 0) die("Couldn't bring up loopback interface in namespace: %s", strerror(-rc)); /* Get or set MAC in target namespace */ - if (MAC_IS_ZERO(c->mac_guest)) - nl_link_get_mac(nl_sock_ns, c->pasta_ifi, c->mac_guest); + if (MAC_IS_ZERO(c->guest_mac)) + nl_link_get_mac(nl_sock_ns, c->pasta_ifi, c->guest_mac); else - rc = nl_link_set_mac(nl_sock_ns, c->pasta_ifi, c->mac_guest); + rc = nl_link_set_mac(nl_sock_ns, c->pasta_ifi, c->guest_mac); if (rc < 0) die("Couldn't set MAC address in namespace: %s", strerror(-rc)); if (c->pasta_conf_ns) { - nl_link_up(nl_sock_ns, c->pasta_ifi, c->mtu); + unsigned int flags = IFF_UP; + + if (c->mtu != -1) + nl_link_set_mtu(nl_sock_ns, c->pasta_ifi, c->mtu); + + if (c->ifi6) /* Avoid duplicate address detection on link up */ + flags |= IFF_NOARP; + + nl_link_set_flags(nl_sock_ns, c->pasta_ifi, flags, flags); if (c->ifi4) { - if (c->no_copy_addrs) { + if (c->ip4.no_copy_addrs) { rc = nl_addr_set(nl_sock_ns, c->pasta_ifi, AF_INET, &c->ip4.addr, @@ -311,9 +335,10 @@ void pasta_ns_conf(struct ctx *c) strerror(-rc)); } - if (c->no_copy_routes) { + if (c->ip4.no_copy_routes) { rc = nl_route_set_def(nl_sock_ns, c->pasta_ifi, - AF_INET, &c->ip4.gw); + AF_INET, + &c->ip4.guest_gw); } else { rc = nl_route_dup(nl_sock, c->ifi4, nl_sock_ns, c->pasta_ifi, AF_INET); @@ -326,7 +351,24 @@ void pasta_ns_conf(struct ctx *c) } if (c->ifi6) { - if (c->no_copy_addrs) { + rc = nl_addr_get_ll(nl_sock_ns, c->pasta_ifi, + &c->ip6.addr_ll_seen); + if (rc < 0) { + warn("Can't get LL address from namespace: %s", + strerror(-rc)); + } + + rc = nl_addr_set_ll_nodad(nl_sock_ns, c->pasta_ifi); + if (rc < 0) { + warn("Can't set nodad for LL in namespace: %s", + strerror(-rc)); + } + + /* We dodged DAD: re-enable neighbour solicitations */ + nl_link_set_flags(nl_sock_ns, c->pasta_ifi, + 0, IFF_NOARP); + + if (c->ip6.no_copy_addrs) { rc = nl_addr_set(nl_sock_ns, c->pasta_ifi, AF_INET6, &c->ip6.addr, 64); } else { @@ -340,9 +382,10 @@ void pasta_ns_conf(struct ctx *c) strerror(-rc)); } - if (c->no_copy_routes) { + if (c->ip6.no_copy_routes) { rc = nl_route_set_def(nl_sock_ns, c->pasta_ifi, - AF_INET6, &c->ip6.gw); + AF_INET6, + &c->ip6.guest_gw); } else { rc = nl_route_dup(nl_sock, c->ifi6, nl_sock_ns, c->pasta_ifi, @@ -356,7 +399,7 @@ void pasta_ns_conf(struct ctx *c) } } - proto_update_l2_buf(c->mac_guest, NULL); + proto_update_l2_buf(c->guest_mac, NULL); } /** @@ -370,12 +413,12 @@ static int pasta_netns_quit_timer(void) struct itimerspec it = { { 1, 0 }, { 1, 0 } }; /* one-second interval */ if (fd == -1) { - err("timerfd_create(): %s", strerror(errno)); + err_perror("Failed to create timerfd for quit timer"); return -errno; } if (timerfd_settime(fd, 0, &it, NULL) < 0) { - err("timerfd_settime(): %s", strerror(errno)); + err_perror("Failed to set interval for quit timer"); close(fd); return -errno; } @@ -389,12 +432,12 @@ static int pasta_netns_quit_timer(void) */ void pasta_netns_quit_init(const struct ctx *c) { - union epoll_ref ref = { .type = EPOLL_TYPE_NSQUIT_INOTIFY }; struct epoll_event ev = { .events = EPOLLIN }; int flags = O_NONBLOCK | O_CLOEXEC; struct statfs s = { 0 }; bool try_inotify = true; int fd = -1, dir_fd; + union epoll_ref ref; if (c->mode != MODE_PASTA || c->no_netns_quit || !*c->netns_base) return; @@ -425,6 +468,7 @@ void pasta_netns_quit_init(const struct ctx *c) ref.type = EPOLL_TYPE_NSQUIT_TIMER; } else { close(dir_fd); + ref.type = EPOLL_TYPE_NSQUIT_INOTIFY; } if (fd > FD_REF_MAX) @@ -468,7 +512,7 @@ void pasta_netns_quit_timer_handler(struct ctx *c, union epoll_ref ref) n = read(ref.fd, &expirations, sizeof(expirations)); if (n < 0) - die("Namespace watch timer read() error: %s", strerror(errno)); + die_perror("Namespace watch timer read() error"); if ((size_t)n < sizeof(expirations)) warn("Namespace watch timer: short read(): %zi", n); |