[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v7 12/19] tools: add simple vchan-socket-proxy



On 19/05/2020 02:54, Jason Andryuk wrote:
> +static int connect_socket(const char *path_or_fd) {
> +    int fd;
> +    char *endptr;
> +    struct sockaddr_un addr;
> +
> +    fd = strtoll(path_or_fd, &endptr, 0);
> +    if (*endptr == '\0') {
> +        set_nonblocking(fd, 1);
> +        return fd;
> +    }
> +
> +    fd = socket(AF_UNIX, SOCK_STREAM, 0);
> +    if (fd == -1)
> +        return -1;
> +
> +    addr.sun_family = AF_UNIX;
> +    strncpy(addr.sun_path, path_or_fd, sizeof(addr.sun_path));

Coverity has identified issues, some perhaps more concerning than others.

Here, addr.sun_path not necessarily NUL terminated.

> +    if (connect(fd, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
> +        close(fd);
> +        return -1;
> +    }
> +
> +    set_nonblocking(fd, 1);
> +
> +    return fd;
> +}
> +
> +static int listen_socket(const char *path_or_fd) {
> +    int fd;
> +    char *endptr;
> +    struct sockaddr_un addr;
> +
> +    fd = strtoll(path_or_fd, &endptr, 0);
> +    if (*endptr == '\0') {
> +        return fd;
> +    }
> +
> +    /* if not a number, assume a socket path */
> +    fd = socket(AF_UNIX, SOCK_STREAM, 0);
> +    if (fd == -1)
> +        return -1;
> +
> +    addr.sun_family = AF_UNIX;
> +    strncpy(addr.sun_path, path_or_fd, sizeof(addr.sun_path));

And here.

> +    if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
> +        close(fd);
> +        return -1;
> +    }
> +    if (listen(fd, 5) != 0) {
> +        close(fd);
> +        return -1;
> +    }
> +
> +    return fd;
> +}
> +
> +static struct libxenvchan *connect_vchan(int domid, const char *path) {
> +    struct libxenvchan *ctrl = NULL;
> +    struct xs_handle *xs = NULL;
> +    xc_interface *xc = NULL;
> +    xc_dominfo_t dominfo;
> +    char **watch_ret;
> +    unsigned int watch_num;
> +    int ret;
> +
> +    xs = xs_open(XS_OPEN_READONLY);
> +    if (!xs) {
> +        perror("xs_open");
> +        goto out;
> +    }
> +    xc = xc_interface_open(NULL, NULL, XC_OPENFLAG_NON_REENTRANT);
> +    if (!xc) {
> +        perror("xc_interface_open");
> +        goto out;
> +    }
> +    /* wait for vchan server to create *path* */
> +    xs_watch(xs, path, "path");
> +    xs_watch(xs, "@releaseDomain", "release");

Return values not checked.

> +    while ((watch_ret = xs_read_watch(xs, &watch_num))) {
> +        /* don't care about exact which fired the watch */
> +        free(watch_ret);
> +        ctrl = libxenvchan_client_init(NULL, domid, path);
> +        if (ctrl)
> +            break;
> +
> +        ret = xc_domain_getinfo(xc, domid, 1, &dominfo);
> +        /* break the loop if domain is definitely not there anymore, but
> +         * continue if it is or the call failed (like EPERM) */
> +        if (ret == -1 && errno == ESRCH)
> +            break;
> +        if (ret == 1 && (dominfo.domid != (uint32_t)domid || dominfo.dying))
> +            break;
> +    }
> +
> +out:
> +    if (xc)
> +        xc_interface_close(xc);
> +    if (xs)
> +        xs_close(xs);
> +    return ctrl;
> +}
> +
> +
> +static void discard_buffers(struct libxenvchan *ctrl) {
> +    /* discard local buffers */
> +    insiz = 0;
> +    outsiz = 0;
> +
> +    /* discard remaining incoming data */
> +    while (libxenvchan_data_ready(ctrl)) {
> +        if (libxenvchan_read(ctrl, inbuf, BUFSIZE) == -1) {
> +            perror("vchan read");
> +            exit(1);
> +        }
> +    }
> +}
> +
> +int data_loop(struct libxenvchan *ctrl, int input_fd, int output_fd)
> +{
> +    int ret;
> +    int libxenvchan_fd;
> +    int max_fd;
> +
> +    libxenvchan_fd = libxenvchan_fd_for_select(ctrl);
> +    for (;;) {
> +        fd_set rfds;
> +        fd_set wfds;
> +        FD_ZERO(&rfds);
> +        FD_ZERO(&wfds);
> +
> +        max_fd = -1;
> +        if (input_fd != -1 && insiz != BUFSIZE) {
> +            FD_SET(input_fd, &rfds);
> +            if (input_fd > max_fd)
> +                max_fd = input_fd;
> +        }
> +        if (output_fd != -1 && outsiz) {
> +            FD_SET(output_fd, &wfds);
> +            if (output_fd > max_fd)
> +                max_fd = output_fd;
> +        }
> +        FD_SET(libxenvchan_fd, &rfds);
> +        if (libxenvchan_fd > max_fd)
> +            max_fd = libxenvchan_fd;
> +        ret = select(max_fd + 1, &rfds, &wfds, NULL, NULL);
> +        if (ret < 0) {
> +            perror("select");
> +            exit(1);
> +        }
> +        if (FD_ISSET(libxenvchan_fd, &rfds)) {
> +            libxenvchan_wait(ctrl);
> +            if (!libxenvchan_is_open(ctrl)) {
> +                if (verbose)
> +                    fprintf(stderr, "vchan client disconnected\n");
> +                while (outsiz)
> +                    socket_wr(output_fd);
> +                close(output_fd);
> +                close(input_fd);
> +                discard_buffers(ctrl);
> +                break;
> +            }
> +            vchan_wr(ctrl);
> +        }
> +
> +        if (FD_ISSET(input_fd, &rfds)) {
> +            ret = read(input_fd, inbuf + insiz, BUFSIZE - insiz);
> +            if (ret < 0 && errno != EAGAIN)
> +                exit(1);
> +            if (verbose)
> +                fprintf(stderr, "from-unix: %.*s\n", ret, inbuf + insiz);
> +            if (ret == 0) {
> +                /* EOF on socket, write everything in the buffer and close 
> the
> +                 * input_fd socket */
> +                while (insiz) {
> +                    vchan_wr(ctrl);
> +                    libxenvchan_wait(ctrl);
> +                }
> +                close(input_fd);
> +                input_fd = -1;

Dead store.

> +                /* TODO: maybe signal the vchan client somehow? */
> +                break;
> +            }
> +            if (ret)
> +                insiz += ret;
> +            vchan_wr(ctrl);
> +        }
> +        if (FD_ISSET(output_fd, &wfds))
> +            socket_wr(output_fd);
> +        while (libxenvchan_data_ready(ctrl) && outsiz < BUFSIZE) {
> +            ret = libxenvchan_read(ctrl, outbuf + outsiz, BUFSIZE - outsiz);
> +            if (ret < 0)
> +                exit(1);
> +            if (verbose)
> +                fprintf(stderr, "from-vchan: %.*s\n", ret, outbuf + outsiz);
> +            outsiz += ret;
> +            socket_wr(output_fd);
> +        }
> +    }
> +    return 0;
> +}
> +
> +/**
> +    Simple libxenvchan application, both client and server.
> +    Both sides may write and read, both from the libxenvchan and from
> +    stdin/stdout (just like netcat).
> +*/
> +
> +static struct option options[] = {
> +    { "mode",       required_argument, NULL, 'm' },
> +    { "verbose",          no_argument, NULL, 'v' },
> +    { "state-path", required_argument, NULL, 's' },
> +    { }
> +};
> +
> +int main(int argc, char **argv)
> +{
> +    int is_server = 0;
> +    int socket_fd = -1;
> +    int input_fd, output_fd;
> +    struct libxenvchan *ctrl = NULL;
> +    const char *socket_path;
> +    int domid;
> +    const char *vchan_path;
> +    const char *state_path = NULL;
> +    int opt;
> +
> +    while ((opt = getopt_long(argc, argv, "m:vs:", options, NULL)) != -1) {
> +        switch (opt) {
> +            case 'm':
> +                if (strcmp(optarg, "server") == 0)
> +                    is_server = 1;
> +                else if (strcmp(optarg, "client") == 0)
> +                    is_server = 0;
> +                else {
> +                    fprintf(stderr, "invalid argument for --mode: %s\n", 
> optarg);
> +                    usage(argv);
> +                    return 1;
> +                }
> +                break;
> +            case 'v':
> +                verbose = 1;
> +                break;
> +            case 's':
> +                state_path = optarg;
> +                break;
> +            case '?':
> +                usage(argv);
> +        }
> +    }
> +
> +    if (argc-optind != 3)
> +        usage(argv);
> +
> +    domid = atoi(argv[optind]);
> +    vchan_path = argv[optind+1];
> +    socket_path = argv[optind+2];
> +
> +    if (is_server) {
> +        ctrl = libxenvchan_server_init(NULL, domid, vchan_path, 0, 0);
> +        if (!ctrl) {
> +            perror("libxenvchan_server_init");
> +            exit(1);
> +        }
> +    } else {
> +        if (strcmp(socket_path, "-") == 0) {
> +            input_fd = 0;
> +            output_fd = 1;
> +        } else {
> +            socket_fd = listen_socket(socket_path);
> +            if (socket_fd == -1) {
> +                perror("listen socket");
> +                return 1;
> +            }
> +        }
> +    }
> +
> +    if (state_path) {
> +        struct xs_handle *xs;
> +
> +        xs = xs_open(0);
> +        if (!xs) {
> +            perror("xs_open");
> +            return 1;
> +        }
> +        if (!xs_write(xs, XBT_NULL, state_path, "running", 
> strlen("running"))) {
> +            perror("xs_write");
> +            return 1;
> +        }
> +        xs_close(xs);
> +    }
> +
> +    for (;;) {
> +        if (is_server) {
> +            /* wait for vchan connection */
> +            while (libxenvchan_is_open(ctrl) != 1)
> +                libxenvchan_wait(ctrl);
> +            /* vchan client connected, setup local FD if needed */
> +            if (strcmp(socket_path, "-") == 0) {
> +                input_fd = 0;
> +                output_fd = 1;
> +            } else {
> +                input_fd = output_fd = connect_socket(socket_path);
> +            }
> +            if (input_fd == -1) {
> +                perror("connect socket");
> +                return 1;
> +            }
> +            if (data_loop(ctrl, input_fd, output_fd) != 0)
> +                break;
> +            /* keep it running only when get UNIX socket path */
> +            if (socket_path[0] != '/')
> +                break;
> +        } else {
> +            /* wait for local socket connection */
> +            if (strcmp(socket_path, "-") != 0)
> +                input_fd = output_fd = accept(socket_fd, NULL, NULL);
> +            if (input_fd == -1) {
> +                perror("accept");

Leakage of scoket_fd, and ...

> +                return 1;
> +            }
> +            set_nonblocking(input_fd, 1);
> +            set_nonblocking(output_fd, 1);
> +            ctrl = connect_vchan(domid, vchan_path);
> +            if (!ctrl) {
> +                perror("vchan client init");

All 3 FDs here.

~Andrew

> +                return 1;
> +            }
> +            if (data_loop(ctrl, input_fd, output_fd) != 0)
> +                break;
> +            /* don't reconnect if output was stdout */
> +            if (strcmp(socket_path, "-") == 0)
> +                break;
> +
> +            libxenvchan_close(ctrl);
> +            ctrl = NULL;
> +        }
> +    }
> +    return 0;
> +}




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.