aboutgitcodebugslistschat
path: root/pasta.c
diff options
context:
space:
mode:
Diffstat (limited to 'pasta.c')
-rw-r--r--pasta.c114
1 files changed, 79 insertions, 35 deletions
diff --git a/pasta.c b/pasta.c
index 61feaa9..a117704 100644
--- a/pasta.c
+++ b/pasta.c
@@ -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);