aboutgitcodebugslistschat
path: root/pasta.c
diff options
context:
space:
mode:
Diffstat (limited to 'pasta.c')
-rw-r--r--pasta.c69
1 files changed, 46 insertions, 23 deletions
diff --git a/pasta.c b/pasta.c
index f15084d..c307b8a 100644
--- a/pasta.c
+++ b/pasta.c
@@ -27,7 +27,6 @@
#include <stdint.h>
#include <unistd.h>
#include <syslog.h>
-#include <sys/epoll.h>
#include <sys/inotify.h>
#include <sys/mount.h>
#include <sys/timerfd.h>
@@ -41,6 +40,7 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#include <net/ethernet.h>
+#include <sys/prctl.h>
#include <sys/syscall.h>
#include <linux/magic.h>
@@ -49,6 +49,7 @@
#include "isolation.h"
#include "netlink.h"
#include "log.h"
+#include "epoll_ctl.h"
#define HOSTNAME_PREFIX "pasta-"
@@ -57,15 +58,13 @@ int pasta_child_pid;
/**
* pasta_child_handler() - Exit once shell exits (if we started it), reap clones
- * @signal: Unused, handler deals with SIGCHLD only
+ * @signal: Signal number; this handler deals with SIGCHLD only
*/
void pasta_child_handler(int signal)
{
int errno_save = errno;
siginfo_t infop;
- (void)signal;
-
if (signal != SIGCHLD)
return;
@@ -73,12 +72,12 @@ void pasta_child_handler(int signal)
!waitid(P_PID, pasta_child_pid, &infop, WEXITED | WNOHANG)) {
if (infop.si_pid == pasta_child_pid) {
if (infop.si_code == CLD_EXITED)
- _exit(infop.si_status);
+ passt_exit(infop.si_status);
/* If killed by a signal, si_status is the number.
* Follow common shell convention of returning it + 128.
*/
- _exit(infop.si_status + 128);
+ passt_exit(infop.si_status + 128);
/* Nothing to do, detached PID namespace going away */
}
@@ -169,10 +168,12 @@ void pasta_open_ns(struct ctx *c, const char *netns)
* struct pasta_spawn_cmd_arg - Argument for pasta_spawn_cmd()
* @exe: Executable to run
* @argv: Command and arguments to run
+ * @ctx: Context to read config from
*/
struct pasta_spawn_cmd_arg {
const char *exe;
char *const *argv;
+ struct ctx *c;
};
/**
@@ -186,8 +187,13 @@ static int pasta_spawn_cmd(void *arg)
{
char hostname[HOST_NAME_MAX + 1] = HOSTNAME_PREFIX;
const struct pasta_spawn_cmd_arg *a;
+ size_t conf_hostname_len;
sigset_t set;
+ /* If the parent dies with an error, so should we */
+ if (prctl(PR_SET_PDEATHSIG, SIGKILL))
+ die_perror("Couldn't set PR_SET_PDEATHSIG");
+
/* We run in a detached PID and mount namespace: mount /proc over */
if (mount("", "/proc", "proc", 0, NULL))
warn_perror("Couldn't mount /proc");
@@ -195,9 +201,15 @@ static int pasta_spawn_cmd(void *arg)
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) {
+ a = (const struct pasta_spawn_cmd_arg *)arg;
+
+ conf_hostname_len = strlen(a->c->hostname);
+ if (conf_hostname_len > 0) {
+ if (sethostname(a->c->hostname, conf_hostname_len))
+ warn("Unable to set configured hostname");
+ } else 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");
@@ -208,7 +220,12 @@ static int pasta_spawn_cmd(void *arg)
sigaddset(&set, SIGUSR1);
sigwaitinfo(&set, NULL);
- a = (const struct pasta_spawn_cmd_arg *)arg;
+ /* Once exec()ed this process is more valuable, and easier to see and
+ * clean up. Let us outlive our parent now.
+ */
+ if (prctl(PR_SET_PDEATHSIG, 0))
+ die_perror("Couldn't clear PR_SET_PDEATHSIG");
+
execvp(a->exe, a->argv);
die_perror("Failed to start command or shell");
@@ -230,6 +247,7 @@ void pasta_start_ns(struct ctx *c, uid_t uid, gid_t gid,
struct pasta_spawn_cmd_arg arg = {
.exe = argv[0],
.argv = argv,
+ .c = c,
};
char uidmap[BUFSIZ], gidmap[BUFSIZ];
char *sh_argv[] = { NULL, NULL };
@@ -310,7 +328,7 @@ void pasta_ns_conf(struct ctx *c)
if (c->pasta_conf_ns) {
unsigned int flags = IFF_UP;
- if (c->mtu != -1)
+ if (c->mtu)
nl_link_set_mtu(nl_sock_ns, c->pasta_ifi, c->mtu);
if (c->ifi6) /* Avoid duplicate address detection on link up */
@@ -402,7 +420,7 @@ void pasta_ns_conf(struct ctx *c)
}
}
- proto_update_l2_buf(c->guest_mac, NULL);
+ proto_update_l2_buf(c->guest_mac);
}
/**
@@ -435,7 +453,6 @@ static int pasta_netns_quit_timer(void)
*/
void pasta_netns_quit_init(const struct ctx *c)
{
- struct epoll_event ev = { .events = EPOLLIN };
int flags = O_NONBLOCK | O_CLOEXEC;
struct statfs s = { 0 };
bool try_inotify = true;
@@ -478,8 +495,8 @@ void pasta_netns_quit_init(const struct ctx *c)
die("netns monitor file number %i too big, exiting", fd);
ref.fd = fd;
- ev.data.u64 = ref.u64;
- epoll_ctl(c->epollfd, EPOLL_CTL_ADD, fd, &ev);
+
+ epoll_add(c->epollfd, EPOLLIN, ref);
}
/**
@@ -489,17 +506,23 @@ void pasta_netns_quit_init(const struct ctx *c)
*/
void pasta_netns_quit_inotify_handler(struct ctx *c, int inotify_fd)
{
- char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
- const struct inotify_event *in_ev = (struct inotify_event *)buf;
+ char buf[sizeof(struct inotify_event) + NAME_MAX + 1]
+ __attribute__ ((aligned(__alignof__(struct inotify_event))));
+ const struct inotify_event *ev;
+ ssize_t n;
+ char *p;
- if (read(inotify_fd, buf, sizeof(buf)) < (ssize_t)sizeof(*in_ev))
+ if ((n = read(inotify_fd, buf, sizeof(buf))) < (ssize_t)sizeof(*ev))
return;
- if (strncmp(in_ev->name, c->netns_base, sizeof(c->netns_base)))
- return;
+ for (p = buf; p < buf + n; p += sizeof(*ev) + ev->len) {
+ ev = (const struct inotify_event *)p;
- info("Namespace %s is gone, exiting", c->netns_base);
- _exit(EXIT_SUCCESS);
+ if (!strncmp(ev->name, c->netns_base, sizeof(c->netns_base))) {
+ info("Namespace %s is gone, exiting", c->netns_base);
+ passt_exit(EXIT_SUCCESS);
+ }
+ }
}
/**
@@ -525,7 +548,7 @@ void pasta_netns_quit_timer_handler(struct ctx *c, union epoll_ref ref)
return;
info("Namespace %s is gone, exiting", c->netns_base);
- _exit(EXIT_SUCCESS);
+ passt_exit(EXIT_SUCCESS);
}
close(fd);