From 8278e30c459e21db93c17d2182ad8352ec2dd4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 21 Feb 2023 16:47:46 +0400 Subject: util: drop qemu_fork() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fortunately, qemu_fork() is no longer used since commit a95570e3e4d6 ("io/command: use glib GSpawn, instead of open-coding fork/exec"). (GSpawn uses posix_spawn() whenever possible instead) Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230221124802.4103554-2-marcandre.lureau@redhat.com> --- util/oslib-posix.c | 70 ------------------------------------------------------ util/oslib-win32.c | 9 ------- 2 files changed, 79 deletions(-) (limited to 'util') diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 77d882e..760390b 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -583,76 +583,6 @@ char *qemu_get_pid_name(pid_t pid) } -pid_t qemu_fork(Error **errp) -{ - sigset_t oldmask, newmask; - struct sigaction sig_action; - int saved_errno; - pid_t pid; - - /* - * Need to block signals now, so that child process can safely - * kill off caller's signal handlers without a race. - */ - sigfillset(&newmask); - if (pthread_sigmask(SIG_SETMASK, &newmask, &oldmask) != 0) { - error_setg_errno(errp, errno, - "cannot block signals"); - return -1; - } - - pid = fork(); - saved_errno = errno; - - if (pid < 0) { - /* attempt to restore signal mask, but ignore failure, to - * avoid obscuring the fork failure */ - (void)pthread_sigmask(SIG_SETMASK, &oldmask, NULL); - error_setg_errno(errp, saved_errno, - "cannot fork child process"); - errno = saved_errno; - return -1; - } else if (pid) { - /* parent process */ - - /* Restore our original signal mask now that the child is - * safely running. Only documented failures are EFAULT (not - * possible, since we are using just-grabbed mask) or EINVAL - * (not possible, since we are using correct arguments). */ - (void)pthread_sigmask(SIG_SETMASK, &oldmask, NULL); - } else { - /* child process */ - size_t i; - - /* Clear out all signal handlers from parent so nothing - * unexpected can happen in our child once we unblock - * signals */ - sig_action.sa_handler = SIG_DFL; - sig_action.sa_flags = 0; - sigemptyset(&sig_action.sa_mask); - - for (i = 1; i < NSIG; i++) { - /* Only possible errors are EFAULT or EINVAL The former - * won't happen, the latter we expect, so no need to check - * return value */ - (void)sigaction(i, &sig_action, NULL); - } - - /* Unmask all signals in child, since we've no idea what the - * caller's done with their signal mask and don't want to - * propagate that to children */ - sigemptyset(&newmask); - if (pthread_sigmask(SIG_SETMASK, &newmask, NULL) != 0) { - Error *local_err = NULL; - error_setg_errno(&local_err, errno, - "cannot unblock signals"); - error_report_err(local_err); - _exit(1); - } - } - return pid; -} - void *qemu_alloc_stack(size_t *sz) { void *ptr, *guardpage; diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 07ade41..528c9ee 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -283,15 +283,6 @@ char *qemu_get_pid_name(pid_t pid) } -pid_t qemu_fork(Error **errp) -{ - errno = ENOSYS; - error_setg_errno(errp, errno, - "cannot fork child process"); - return -1; -} - - #undef connect int qemu_connect_wrap(int sockfd, const struct sockaddr *addr, socklen_t addrlen) -- cgit v1.1 From 3ffef1a55ca3b55fa64d43cd35af5adb2c260463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 21 Feb 2023 16:47:50 +0400 Subject: error: add global &error_warn destination MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This can help debugging issues or develop, when error handling is introduced. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Message-Id: <20230221124802.4103554-6-marcandre.lureau@redhat.com> --- util/error.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'util') diff --git a/util/error.c b/util/error.c index 1e7af66..5537245 100644 --- a/util/error.c +++ b/util/error.c @@ -27,8 +27,9 @@ struct Error Error *error_abort; Error *error_fatal; +Error *error_warn; -static void error_handle_fatal(Error **errp, Error *err) +static void error_handle(Error **errp, Error *err) { if (errp == &error_abort) { fprintf(stderr, "Unexpected error in %s() at %s:%d:\n", @@ -43,6 +44,9 @@ static void error_handle_fatal(Error **errp, Error *err) error_report_err(err); exit(1); } + if (errp == &error_warn) { + warn_report_err(err); + } } G_GNUC_PRINTF(6, 0) @@ -71,7 +75,7 @@ static void error_setv(Error **errp, err->line = line; err->func = func; - error_handle_fatal(errp, err); + error_handle(errp, err); *errp = err; errno = saved_errno; @@ -284,7 +288,7 @@ void error_propagate(Error **dst_errp, Error *local_err) if (!local_err) { return; } - error_handle_fatal(dst_errp, local_err); + error_handle(dst_errp, local_err); if (dst_errp && !*dst_errp) { *dst_errp = local_err; } else { -- cgit v1.1 From f5fd677ae7cf7cfb07b12adbfd479c460ddc3ac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 21 Feb 2023 16:47:51 +0400 Subject: win32/socket: introduce qemu_socket_select() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a wrapper for WSAEventSelect, with Error handling. By default, it will produce a warning, so callers don't have to be modified now, and yet we can spot potential mis-use. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Message-Id: <20230221124802.4103554-7-marcandre.lureau@redhat.com> --- util/aio-win32.c | 2 +- util/main-loop.c | 6 +++--- util/oslib-win32.c | 17 ++++++++++++++++- 3 files changed, 20 insertions(+), 5 deletions(-) (limited to 'util') diff --git a/util/aio-win32.c b/util/aio-win32.c index 80cfe01..be5136e 100644 --- a/util/aio-win32.c +++ b/util/aio-win32.c @@ -115,7 +115,7 @@ void aio_set_fd_handler(AioContext *ctx, QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, node, node); event = event_notifier_get_handle(&ctx->notifier); - WSAEventSelect(node->pfd.fd, event, bitmask); + qemu_socket_select(node->pfd.fd, event, bitmask, NULL); } if (old_node) { aio_remove_fd_handler(ctx, old_node); diff --git a/util/main-loop.c b/util/main-loop.c index 3c0f525..16e837f 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -416,9 +416,9 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) void qemu_fd_register(int fd) { - WSAEventSelect(fd, event_notifier_get_handle(&qemu_aio_context->notifier), - FD_READ | FD_ACCEPT | FD_CLOSE | - FD_CONNECT | FD_WRITE | FD_OOB); + qemu_socket_select(fd, event_notifier_get_handle(&qemu_aio_context->notifier), + FD_READ | FD_ACCEPT | FD_CLOSE | + FD_CONNECT | FD_WRITE | FD_OOB, NULL); } static int pollfds_fill(GArray *pollfds, fd_set *rfds, fd_set *wfds, diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 528c9ee..df752fc 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -180,7 +180,7 @@ static int socket_error(void) void qemu_socket_set_block(int fd) { unsigned long opt = 0; - WSAEventSelect(fd, NULL, 0); + qemu_socket_select(fd, NULL, 0, NULL); ioctlsocket(fd, FIONBIO, &opt); } @@ -283,6 +283,21 @@ char *qemu_get_pid_name(pid_t pid) } +bool qemu_socket_select(SOCKET s, WSAEVENT hEventObject, + long lNetworkEvents, Error **errp) +{ + if (errp == NULL) { + errp = &error_warn; + } + + if (WSAEventSelect(s, hEventObject, lNetworkEvents) != 0) { + error_setg_win32(errp, WSAGetLastError(), "failed to WSAEventSelect()"); + return false; + } + + return true; +} + #undef connect int qemu_connect_wrap(int sockfd, const struct sockaddr *addr, socklen_t addrlen) -- cgit v1.1 From a4aafea26152b58c61c8105ffc574661cdfeb17b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 21 Feb 2023 16:47:52 +0400 Subject: win32/socket: introduce qemu_socket_unselect() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A more explicit version of qemu_socket_select() with no events. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Message-Id: <20230221124802.4103554-8-marcandre.lureau@redhat.com> --- util/oslib-win32.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'util') diff --git a/util/oslib-win32.c b/util/oslib-win32.c index df752fc..dbd32ac 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -180,7 +180,7 @@ static int socket_error(void) void qemu_socket_set_block(int fd) { unsigned long opt = 0; - qemu_socket_select(fd, NULL, 0, NULL); + qemu_socket_unselect(fd, NULL); ioctlsocket(fd, FIONBIO, &opt); } @@ -298,6 +298,11 @@ bool qemu_socket_select(SOCKET s, WSAEVENT hEventObject, return true; } +bool qemu_socket_unselect(SOCKET s, Error **errp) +{ + return qemu_socket_select(s, NULL, 0, errp); +} + #undef connect int qemu_connect_wrap(int sockfd, const struct sockaddr *addr, socklen_t addrlen) -- cgit v1.1 From 6eeef4477a8588f44a15458ab560c68d373d1033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 21 Feb 2023 16:47:53 +0400 Subject: aio: make aio_set_fd_poll() static to aio-posix.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Message-Id: <20230221124802.4103554-9-marcandre.lureau@redhat.com> --- util/aio-posix.c | 6 +++--- util/aio-win32.c | 7 ------- 2 files changed, 3 insertions(+), 10 deletions(-) (limited to 'util') diff --git a/util/aio-posix.c b/util/aio-posix.c index 6cc6256..a8be940 100644 --- a/util/aio-posix.c +++ b/util/aio-posix.c @@ -180,9 +180,9 @@ void aio_set_fd_handler(AioContext *ctx, } } -void aio_set_fd_poll(AioContext *ctx, int fd, - IOHandler *io_poll_begin, - IOHandler *io_poll_end) +static void aio_set_fd_poll(AioContext *ctx, int fd, + IOHandler *io_poll_begin, + IOHandler *io_poll_end) { AioHandler *node = find_aio_handler(ctx, fd); diff --git a/util/aio-win32.c b/util/aio-win32.c index be5136e..74d63fa 100644 --- a/util/aio-win32.c +++ b/util/aio-win32.c @@ -125,13 +125,6 @@ void aio_set_fd_handler(AioContext *ctx, aio_notify(ctx); } -void aio_set_fd_poll(AioContext *ctx, int fd, - IOHandler *io_poll_begin, - IOHandler *io_poll_end) -{ - /* Not implemented */ -} - void aio_set_event_notifier(AioContext *ctx, EventNotifier *e, bool is_external, -- cgit v1.1 From e2a3a2193ef2d252a1b3553e90895189a248bd22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 21 Feb 2023 16:47:54 +0400 Subject: aio/win32: aio_set_fd_handler() only supports SOCKET MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's check if the argument is actually a SOCKET, else report an error and return. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Message-Id: <20230221124802.4103554-10-marcandre.lureau@redhat.com> --- util/aio-win32.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'util') diff --git a/util/aio-win32.c b/util/aio-win32.c index 74d63fa..08e8f56 100644 --- a/util/aio-win32.c +++ b/util/aio-win32.c @@ -22,6 +22,7 @@ #include "qemu/sockets.h" #include "qapi/error.h" #include "qemu/rcu_queue.h" +#include "qemu/error-report.h" struct AioHandler { EventNotifier *e; @@ -70,10 +71,14 @@ void aio_set_fd_handler(AioContext *ctx, IOHandler *io_poll_ready, void *opaque) { - /* fd is a SOCKET in our case */ AioHandler *old_node; AioHandler *node = NULL; + if (!fd_is_socket(fd)) { + error_report("fd=%d is not a socket, AIO implementation is missing", fd); + return; + } + qemu_lockcnt_lock(&ctx->list_lock); QLIST_FOREACH(old_node, &ctx->aio_handlers, node) { if (old_node->pfd.fd == fd && !old_node->deleted) { -- cgit v1.1 From faa4ec16419c62d616fcc2dfc02d74d7fcc513d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 21 Feb 2023 16:47:56 +0400 Subject: main-loop: remove qemu_fd_register(), win32/slirp/socket specific MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Open-code the socket registration where it's needed, to avoid artificially used or unclear generic interface. Furthermore, the following patches are going to make socket handling use FD-only inside QEMU, but we need to handle win32 SOCKET from libslirp. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Message-Id: <20230221124802.4103554-12-marcandre.lureau@redhat.com> --- util/main-loop.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'util') diff --git a/util/main-loop.c b/util/main-loop.c index 16e837f..e180c85 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -252,10 +252,6 @@ static int max_priority; static int glib_pollfds_idx; static int glib_n_poll_fds; -void qemu_fd_register(int fd) -{ -} - static void glib_pollfds_fill(int64_t *cur_timeout) { GMainContext *context = g_main_context_default(); @@ -414,13 +410,6 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) } } -void qemu_fd_register(int fd) -{ - qemu_socket_select(fd, event_notifier_get_handle(&qemu_aio_context->notifier), - FD_READ | FD_ACCEPT | FD_CLOSE | - FD_CONNECT | FD_WRITE | FD_OOB, NULL); -} - static int pollfds_fill(GArray *pollfds, fd_set *rfds, fd_set *wfds, fd_set *xfds) { -- cgit v1.1 From abe34282b088499f4e86fff9bb6d6dafd57ae1d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 21 Feb 2023 16:47:59 +0400 Subject: win32: avoid mixing SOCKET and file descriptor space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Until now, a win32 SOCKET handle is often cast to an int file descriptor, as this is what other OS use for sockets. When necessary, QEMU eventually queries whether it's a socket with the help of fd_is_socket(). However, there is no guarantee of conflict between the fd and SOCKET space. Such conflict would have surprising consequences, we shouldn't mix them. Also, it is often forgotten that SOCKET must be closed with closesocket(), and not close(). Instead, let's make the win32 socket wrapper functions return and take a file descriptor, and let util/ wrappers do the fd/SOCKET conversion as necessary. A bit of adaptation is necessary in io/ as well. Unfortunately, we can't drop closesocket() usage, despite _open_osfhandle() documentation claiming transfer of ownership, testing shows bad behaviour if you forget to call closesocket(). Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Message-Id: <20230221124802.4103554-15-marcandre.lureau@redhat.com> --- util/aio-win32.c | 9 ++- util/oslib-win32.c | 219 +++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 192 insertions(+), 36 deletions(-) (limited to 'util') diff --git a/util/aio-win32.c b/util/aio-win32.c index 08e8f56..6bded00 100644 --- a/util/aio-win32.c +++ b/util/aio-win32.c @@ -73,15 +73,18 @@ void aio_set_fd_handler(AioContext *ctx, { AioHandler *old_node; AioHandler *node = NULL; + SOCKET s; if (!fd_is_socket(fd)) { error_report("fd=%d is not a socket, AIO implementation is missing", fd); return; } + s = _get_osfhandle(fd); + qemu_lockcnt_lock(&ctx->list_lock); QLIST_FOREACH(old_node, &ctx->aio_handlers, node) { - if (old_node->pfd.fd == fd && !old_node->deleted) { + if (old_node->pfd.fd == s && !old_node->deleted) { break; } } @@ -92,7 +95,7 @@ void aio_set_fd_handler(AioContext *ctx, /* Alloc and insert if it's not already there */ node = g_new0(AioHandler, 1); - node->pfd.fd = fd; + node->pfd.fd = s; node->pfd.events = 0; if (node->io_read) { @@ -120,7 +123,7 @@ void aio_set_fd_handler(AioContext *ctx, QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, node, node); event = event_notifier_get_handle(&ctx->notifier); - qemu_socket_select(node->pfd.fd, event, bitmask, NULL); + qemu_socket_select(fd, event, bitmask, NULL); } if (old_node) { aio_remove_fd_handler(ctx, old_node); diff --git a/util/oslib-win32.c b/util/oslib-win32.c index dbd32ac..7836fb0 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -283,13 +283,20 @@ char *qemu_get_pid_name(pid_t pid) } -bool qemu_socket_select(SOCKET s, WSAEVENT hEventObject, +bool qemu_socket_select(int sockfd, WSAEVENT hEventObject, long lNetworkEvents, Error **errp) { + SOCKET s = _get_osfhandle(sockfd); + if (errp == NULL) { errp = &error_warn; } + if (s == INVALID_SOCKET) { + error_setg(errp, "invalid socket fd=%d", sockfd); + return false; + } + if (WSAEventSelect(s, hEventObject, lNetworkEvents) != 0) { error_setg_win32(errp, WSAGetLastError(), "failed to WSAEventSelect()"); return false; @@ -298,9 +305,9 @@ bool qemu_socket_select(SOCKET s, WSAEVENT hEventObject, return true; } -bool qemu_socket_unselect(SOCKET s, Error **errp) +bool qemu_socket_unselect(int sockfd, Error **errp) { - return qemu_socket_select(s, NULL, 0, errp); + return qemu_socket_select(sockfd, NULL, 0, errp); } #undef connect @@ -308,7 +315,13 @@ int qemu_connect_wrap(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { int ret; - ret = connect(sockfd, addr, addrlen); + SOCKET s = _get_osfhandle(sockfd); + + if (s == INVALID_SOCKET) { + return -1; + } + + ret = connect(s, addr, addrlen); if (ret < 0) { if (WSAGetLastError() == WSAEWOULDBLOCK) { errno = EINPROGRESS; @@ -324,7 +337,13 @@ int qemu_connect_wrap(int sockfd, const struct sockaddr *addr, int qemu_listen_wrap(int sockfd, int backlog) { int ret; - ret = listen(sockfd, backlog); + SOCKET s = _get_osfhandle(sockfd); + + if (s == INVALID_SOCKET) { + return -1; + } + + ret = listen(s, backlog); if (ret < 0) { errno = socket_error(); } @@ -337,7 +356,13 @@ int qemu_bind_wrap(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { int ret; - ret = bind(sockfd, addr, addrlen); + SOCKET s = _get_osfhandle(sockfd); + + if (s == INVALID_SOCKET) { + return -1; + } + + ret = bind(s, addr, addrlen); if (ret < 0) { errno = socket_error(); } @@ -345,28 +370,108 @@ int qemu_bind_wrap(int sockfd, const struct sockaddr *addr, } -#undef socket -int qemu_socket_wrap(int domain, int type, int protocol) +#undef closesocket +int qemu_closesocket_wrap(int fd) { int ret; - ret = socket(domain, type, protocol); + DWORD flags = 0; + SOCKET s = _get_osfhandle(fd); + + if (s == INVALID_SOCKET) { + return -1; + } + + /* + * If we were to just call _close on the descriptor, it would close the + * HANDLE, but it wouldn't free any of the resources associated to the + * SOCKET, and we can't call _close after calling closesocket, because + * closesocket has already closed the HANDLE, and _close would attempt to + * close the HANDLE again, resulting in a double free. We can however + * protect the HANDLE from actually being closed long enough to close the + * file descriptor, then close the socket itself. + */ + if (!GetHandleInformation((HANDLE)s, &flags)) { + errno = EACCES; + return -1; + } + + if (!SetHandleInformation((HANDLE)s, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE)) { + errno = EACCES; + return -1; + } + + ret = close(fd); + + if (!SetHandleInformation((HANDLE)s, flags, flags)) { + errno = EACCES; + return -1; + } + + /* + * close() returns EBADF since we PROTECT_FROM_CLOSE the underlying handle, + * but the FD is actually freed + */ + if (ret < 0 && errno != EBADF) { + return ret; + } + + ret = closesocket(s); if (ret < 0) { errno = socket_error(); } + return ret; } +#undef socket +int qemu_socket_wrap(int domain, int type, int protocol) +{ + SOCKET s; + int fd; + + s = socket(domain, type, protocol); + if (s == -1) { + errno = socket_error(); + return -1; + } + + fd = _open_osfhandle(s, _O_BINARY); + if (fd < 0) { + closesocket(s); + /* _open_osfhandle may not set errno, and closesocket() may override it */ + errno = ENOMEM; + } + + return fd; +} + + #undef accept int qemu_accept_wrap(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { - int ret; - ret = accept(sockfd, addr, addrlen); - if (ret < 0) { + int fd; + SOCKET s = _get_osfhandle(sockfd); + + if (s == INVALID_SOCKET) { + return -1; + } + + s = accept(s, addr, addrlen); + if (s == -1) { errno = socket_error(); + return -1; } - return ret; + + fd = _open_osfhandle(s, _O_BINARY); + if (fd < 0) { + closesocket(s); + /* _open_osfhandle may not set errno, and closesocket() may override it */ + errno = ENOMEM; + } + + return fd; } @@ -374,7 +479,13 @@ int qemu_accept_wrap(int sockfd, struct sockaddr *addr, int qemu_shutdown_wrap(int sockfd, int how) { int ret; - ret = shutdown(sockfd, how); + SOCKET s = _get_osfhandle(sockfd); + + if (s == INVALID_SOCKET) { + return -1; + } + + ret = shutdown(s, how); if (ret < 0) { errno = socket_error(); } @@ -386,19 +497,13 @@ int qemu_shutdown_wrap(int sockfd, int how) int qemu_ioctlsocket_wrap(int fd, int req, void *val) { int ret; - ret = ioctlsocket(fd, req, val); - if (ret < 0) { - errno = socket_error(); - } - return ret; -} + SOCKET s = _get_osfhandle(fd); + if (s == INVALID_SOCKET) { + return -1; + } -#undef closesocket -int qemu_closesocket_wrap(int fd) -{ - int ret; - ret = closesocket(fd); + ret = ioctlsocket(s, req, val); if (ret < 0) { errno = socket_error(); } @@ -411,7 +516,13 @@ int qemu_getsockopt_wrap(int sockfd, int level, int optname, void *optval, socklen_t *optlen) { int ret; - ret = getsockopt(sockfd, level, optname, optval, optlen); + SOCKET s = _get_osfhandle(sockfd); + + if (s == INVALID_SOCKET) { + return -1; + } + + ret = getsockopt(s, level, optname, optval, optlen); if (ret < 0) { errno = socket_error(); } @@ -424,7 +535,13 @@ int qemu_setsockopt_wrap(int sockfd, int level, int optname, const void *optval, socklen_t optlen) { int ret; - ret = setsockopt(sockfd, level, optname, optval, optlen); + SOCKET s = _get_osfhandle(sockfd); + + if (s == INVALID_SOCKET) { + return -1; + } + + ret = setsockopt(s, level, optname, optval, optlen); if (ret < 0) { errno = socket_error(); } @@ -437,7 +554,13 @@ int qemu_getpeername_wrap(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { int ret; - ret = getpeername(sockfd, addr, addrlen); + SOCKET s = _get_osfhandle(sockfd); + + if (s == INVALID_SOCKET) { + return -1; + } + + ret = getpeername(s, addr, addrlen); if (ret < 0) { errno = socket_error(); } @@ -450,7 +573,13 @@ int qemu_getsockname_wrap(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { int ret; - ret = getsockname(sockfd, addr, addrlen); + SOCKET s = _get_osfhandle(sockfd); + + if (s == INVALID_SOCKET) { + return -1; + } + + ret = getsockname(s, addr, addrlen); if (ret < 0) { errno = socket_error(); } @@ -462,7 +591,13 @@ int qemu_getsockname_wrap(int sockfd, struct sockaddr *addr, ssize_t qemu_send_wrap(int sockfd, const void *buf, size_t len, int flags) { int ret; - ret = send(sockfd, buf, len, flags); + SOCKET s = _get_osfhandle(sockfd); + + if (s == INVALID_SOCKET) { + return -1; + } + + ret = send(s, buf, len, flags); if (ret < 0) { errno = socket_error(); } @@ -475,7 +610,13 @@ ssize_t qemu_sendto_wrap(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen) { int ret; - ret = sendto(sockfd, buf, len, flags, addr, addrlen); + SOCKET s = _get_osfhandle(sockfd); + + if (s == INVALID_SOCKET) { + return -1; + } + + ret = sendto(s, buf, len, flags, addr, addrlen); if (ret < 0) { errno = socket_error(); } @@ -487,7 +628,13 @@ ssize_t qemu_sendto_wrap(int sockfd, const void *buf, size_t len, int flags, ssize_t qemu_recv_wrap(int sockfd, void *buf, size_t len, int flags) { int ret; - ret = recv(sockfd, buf, len, flags); + SOCKET s = _get_osfhandle(sockfd); + + if (s == INVALID_SOCKET) { + return -1; + } + + ret = recv(s, buf, len, flags); if (ret < 0) { errno = socket_error(); } @@ -500,7 +647,13 @@ ssize_t qemu_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen) { int ret; - ret = recvfrom(sockfd, buf, len, flags, addr, addrlen); + SOCKET s = _get_osfhandle(sockfd); + + if (s == INVALID_SOCKET) { + return -1; + } + + ret = recvfrom(s, buf, len, flags, addr, addrlen); if (ret < 0) { errno = socket_error(); } -- cgit v1.1 From 25657fc6c1b693096e2ceadaa53cd10c1e81c8d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 21 Feb 2023 16:48:01 +0400 Subject: win32: replace closesocket() with close() wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a close() wrapper instead, so that we don't need to worry about closesocket() vs close() anymore, let's hope. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Message-Id: <20230221124802.4103554-17-marcandre.lureau@redhat.com> --- util/oslib-win32.c | 56 +++++++++++++++++++++++++++-------------------------- util/qemu-sockets.c | 22 ++++++++++----------- 2 files changed, 40 insertions(+), 38 deletions(-) (limited to 'util') diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 7836fb0..29a667a 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -370,39 +370,39 @@ int qemu_bind_wrap(int sockfd, const struct sockaddr *addr, } -#undef closesocket -int qemu_closesocket_wrap(int fd) +#undef close +int qemu_close_wrap(int fd) { int ret; DWORD flags = 0; - SOCKET s = _get_osfhandle(fd); + SOCKET s = INVALID_SOCKET; - if (s == INVALID_SOCKET) { - return -1; - } + if (fd_is_socket(fd)) { + s = _get_osfhandle(fd); - /* - * If we were to just call _close on the descriptor, it would close the - * HANDLE, but it wouldn't free any of the resources associated to the - * SOCKET, and we can't call _close after calling closesocket, because - * closesocket has already closed the HANDLE, and _close would attempt to - * close the HANDLE again, resulting in a double free. We can however - * protect the HANDLE from actually being closed long enough to close the - * file descriptor, then close the socket itself. - */ - if (!GetHandleInformation((HANDLE)s, &flags)) { - errno = EACCES; - return -1; - } + /* + * If we were to just call _close on the descriptor, it would close the + * HANDLE, but it wouldn't free any of the resources associated to the + * SOCKET, and we can't call _close after calling closesocket, because + * closesocket has already closed the HANDLE, and _close would attempt to + * close the HANDLE again, resulting in a double free. We can however + * protect the HANDLE from actually being closed long enough to close the + * file descriptor, then close the socket itself. + */ + if (!GetHandleInformation((HANDLE)s, &flags)) { + errno = EACCES; + return -1; + } - if (!SetHandleInformation((HANDLE)s, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE)) { - errno = EACCES; - return -1; + if (!SetHandleInformation((HANDLE)s, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE)) { + errno = EACCES; + return -1; + } } ret = close(fd); - if (!SetHandleInformation((HANDLE)s, flags, flags)) { + if (s != INVALID_SOCKET && !SetHandleInformation((HANDLE)s, flags, flags)) { errno = EACCES; return -1; } @@ -411,13 +411,15 @@ int qemu_closesocket_wrap(int fd) * close() returns EBADF since we PROTECT_FROM_CLOSE the underlying handle, * but the FD is actually freed */ - if (ret < 0 && errno != EBADF) { + if (ret < 0 && (s == INVALID_SOCKET || errno != EBADF)) { return ret; } - ret = closesocket(s); - if (ret < 0) { - errno = socket_error(); + if (s != INVALID_SOCKET) { + ret = closesocket(s); + if (ret < 0) { + errno = socket_error(); + } } return ret; diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 6538859..c06a4dc 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -326,7 +326,7 @@ static int inet_listen_saddr(InetSocketAddress *saddr, * recover from this situation, so we need to recreate the * socket to allow bind attempts for subsequent ports: */ - closesocket(slisten); + close(slisten); slisten = -1; } } @@ -337,7 +337,7 @@ static int inet_listen_saddr(InetSocketAddress *saddr, listen_failed: saved_errno = errno; if (slisten >= 0) { - closesocket(slisten); + close(slisten); } freeaddrinfo(res); errno = saved_errno; @@ -380,7 +380,7 @@ static int inet_connect_addr(const InetSocketAddress *saddr, if (rc < 0) { error_setg_errno(errp, errno, "Failed to connect to '%s:%s'", saddr->host, saddr->port); - closesocket(sock); + close(sock); return -1; } @@ -483,7 +483,7 @@ int inet_connect_saddr(InetSocketAddress *saddr, Error **errp) if (ret < 0) { error_setg_errno(errp, errno, "Unable to set KEEPALIVE"); - closesocket(sock); + close(sock); return -1; } } @@ -580,7 +580,7 @@ static int inet_dgram_saddr(InetSocketAddress *sraddr, err: if (sock != -1) { - closesocket(sock); + close(sock); } if (local) { freeaddrinfo(local); @@ -777,7 +777,7 @@ static int vsock_connect_addr(const VsockSocketAddress *vaddr, if (rc < 0) { error_setg_errno(errp, errno, "Failed to connect to '%s:%s'", vaddr->cid, vaddr->port); - closesocket(sock); + close(sock); return -1; } @@ -814,13 +814,13 @@ static int vsock_listen_saddr(VsockSocketAddress *vaddr, if (bind(slisten, (const struct sockaddr *)&svm, sizeof(svm)) != 0) { error_setg_errno(errp, errno, "Failed to bind socket"); - closesocket(slisten); + close(slisten); return -1; } if (listen(slisten, num) != 0) { error_setg_errno(errp, errno, "Failed to listen on socket"); - closesocket(slisten); + close(slisten); return -1; } return slisten; @@ -978,7 +978,7 @@ static int unix_listen_saddr(UnixSocketAddress *saddr, err: g_free(pathbuf); - closesocket(sock); + close(sock); return -1; } @@ -1041,7 +1041,7 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp) return sock; err: - closesocket(sock); + close(sock); return -1; } @@ -1238,7 +1238,7 @@ int socket_listen(SocketAddress *addr, int num, Error **errp) */ if (listen(fd, num) != 0) { error_setg_errno(errp, errno, "Failed to listen on fd socket"); - closesocket(fd); + close(fd); return -1; } break; -- cgit v1.1 From 0a237f4de45b8addbc35a316ee1c0bc7a4887da7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Mar 2023 16:27:44 +0400 Subject: osdep: implement qemu_socketpair() for win32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Manually implement a socketpair() function, using UNIX sockets and simple peer credential checking. QEMU doesn't make much use of socketpair, beside vhost-user which is not available for win32 at this point. However, I intend to use it for writing some new portable tests. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230306122751.2355515-5-marcandre.lureau@redhat.com> --- util/oslib-win32.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) (limited to 'util') diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 29a667a..16f8a67 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -310,6 +310,116 @@ bool qemu_socket_unselect(int sockfd, Error **errp) return qemu_socket_select(sockfd, NULL, 0, errp); } +int qemu_socketpair(int domain, int type, int protocol, int sv[2]) +{ + struct sockaddr_un addr = { + 0, + }; + socklen_t socklen; + int listener = -1; + int client = -1; + int server = -1; + g_autofree char *path = NULL; + int tmpfd; + u_long arg; + int ret = -1; + + g_return_val_if_fail(sv != NULL, -1); + + addr.sun_family = AF_UNIX; + socklen = sizeof(addr); + + tmpfd = g_file_open_tmp(NULL, &path, NULL); + if (tmpfd == -1 || !path) { + errno = EACCES; + goto out; + } + + close(tmpfd); + + if (strlen(path) >= sizeof(addr.sun_path)) { + errno = EINVAL; + goto out; + } + + strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); + + listener = socket(domain, type, protocol); + if (listener == -1) { + goto out; + } + + if (DeleteFile(path) == 0 && GetLastError() != ERROR_FILE_NOT_FOUND) { + errno = EACCES; + goto out; + } + g_clear_pointer(&path, g_free); + + if (bind(listener, (struct sockaddr *)&addr, socklen) == -1) { + goto out; + } + + if (listen(listener, 1) == -1) { + goto out; + } + + client = socket(domain, type, protocol); + if (client == -1) { + goto out; + } + + arg = 1; + if (ioctlsocket(client, FIONBIO, &arg) != NO_ERROR) { + goto out; + } + + if (connect(client, (struct sockaddr *)&addr, socklen) == -1 && + WSAGetLastError() != WSAEWOULDBLOCK) { + goto out; + } + + server = accept(listener, NULL, NULL); + if (server == -1) { + goto out; + } + + arg = 0; + if (ioctlsocket(client, FIONBIO, &arg) != NO_ERROR) { + goto out; + } + + arg = 0; + if (ioctlsocket(client, SIO_AF_UNIX_GETPEERPID, &arg) != NO_ERROR) { + goto out; + } + + if (arg != GetCurrentProcessId()) { + errno = EPERM; + goto out; + } + + sv[0] = server; + server = -1; + sv[1] = client; + client = -1; + ret = 0; + +out: + if (listener != -1) { + close(listener); + } + if (client != -1) { + close(client); + } + if (server != -1) { + close(server); + } + if (path) { + DeleteFile(path); + } + return ret; +} + #undef connect int qemu_connect_wrap(int sockfd, const struct sockaddr *addr, socklen_t addrlen) -- cgit v1.1