diff --git a/usr.sbin/bhyve/uart_emul.c b/usr.sbin/bhyve/uart_emul.c --- a/usr.sbin/bhyve/uart_emul.c +++ b/usr.sbin/bhyve/uart_emul.c @@ -28,6 +28,9 @@ */ #include +#include +#include +#include #include #ifndef WITHOUT_CAPSICUM #include @@ -705,19 +708,97 @@ return (0); } +static void +tcp_handler(int fd, enum ev_type type __unused, void *arg) { + struct uart_softc *sc = (struct uart_softc *)arg; + struct sockaddr_in dst_addr; + socklen_t len = sizeof(dst_addr); + int conn_fd; + + mevent_delete(sc->mev); + + conn_fd = accept(fd, (struct sockaddr *)&dst_addr, &len); + if(conn_fd == -1) { + errx(EX_OSERR, "Unable to accept the connection"); + return; + } + assert(fcntl(conn_fd, F_SETFL, O_NONBLOCK) == 0); + + pthread_mutex_lock(&sc->mtx); + + sc->tty.rfd = sc->tty.wfd = conn_fd; + sc->tty.opened = true; + uart_opentty(sc); + + pthread_mutex_unlock(&sc->mtx); +} + +// Listen to address and add to kqueue. +// If connected (e.g. tcp_handler is triggered), we replace the handler to the connected handler +static int +uart_tcp_backend(struct uart_softc *sc, const char *path) +{ +#ifndef WITHOUT_CAPSICUM + cap_rights_t rights; + cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; +#endif + int bind_fd; + struct sockaddr_in src_addr; + char addr[256]; + int port; + + sscanf(path, "tcp:%255[^:]:%d", addr, &port); + + bind_fd = socket(PF_INET, SOCK_STREAM, 0); + if (bind_fd < 0) + return (-1); + + memset(&src_addr, 0, sizeof(src_addr)); + src_addr.sin_family = AF_INET; + src_addr.sin_port = htons(port); + inet_aton(addr, &src_addr.sin_addr); + + if (bind(bind_fd, (struct sockaddr *)&src_addr, (socklen_t)sizeof(src_addr)) == -1) + errx(EX_OSERR, "Unable to bind to asddress %s:%d", addr, port); + + if (listen(bind_fd, 1) == -1) + return (-1); + + sc->mev = mevent_add(bind_fd, EVF_READ, tcp_handler, (void *)sc); + + if (sc->mev == NULL) + return (-1); + +#ifndef WITHOUT_CAPSICUM + cap_rights_init(&rights, CAP_EVENT, CAP_ACCEPT, CAP_RECV, CAP_SEND, CAP_FCNTL, CAP_IOCTL); + if (caph_rights_limit(bind_fd, &rights) == -1) + errx(EX_OSERR, "Unable to apply rights for sandbox"); + if (caph_ioctls_limit(bind_fd, cmds, nitems(cmds)) == -1) + errx(EX_OSERR, "Unable to apply ioctls for sandbox"); + if (caph_fcntls_limit(bind_fd, CAP_FCNTL_SETFL) == -1) + errx(EX_OSERR, "Unable to apply fcntls for sandbox"); +#endif + + return (0); +} + int uart_set_backend(struct uart_softc *sc, const char *device) { int retval; + bool conn_based = false; if (device == NULL) return (0); if (strcmp("stdio", device) == 0) retval = uart_stdio_backend(sc); - else + else if (strncmp("tcp", device, 3) == 0) { + retval = uart_tcp_backend(sc, device); + conn_based = true; + } else retval = uart_tty_backend(sc, device); - if (retval == 0) + if (retval == 0 && !conn_based) uart_opentty(sc); return (retval);