From 4cda177c6016565dda1f1c3f6cff8ab85ef0d016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Mar 2023 16:27:48 +0400 Subject: [PATCH] qmp: add 'get-win32-socket' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A process with enough capabilities can duplicate a socket to QEMU. Add a QMP command to import it and add it to the monitor fd list, so it can be later used by other commands. Signed-off-by: Marc-André Lureau Acked-by: Markus Armbruster Message-Id: <20230306122751.2355515-9-marcandre.lureau@redhat.com> --- monitor/fds.c | 76 +++++++++++++++++++++++++++++++++++++++----------- qapi/misc.json | 31 ++++++++++++++++++++ 2 files changed, 91 insertions(+), 16 deletions(-) diff --git a/monitor/fds.c b/monitor/fds.c index 7daf1064e135..9ed4197358fa 100644 --- a/monitor/fds.c +++ b/monitor/fds.c @@ -61,46 +61,55 @@ struct MonFdset { static QemuMutex mon_fdsets_lock; static QLIST_HEAD(, MonFdset) mon_fdsets; -void qmp_getfd(const char *fdname, Error **errp) +static bool monitor_add_fd(Monitor *mon, int fd, const char *fdname, Error **errp) { - Monitor *cur_mon = monitor_cur(); mon_fd_t *monfd; - int fd, tmp_fd; - - fd = qemu_chr_fe_get_msgfd(&cur_mon->chr); - if (fd == -1) { - error_setg(errp, "No file descriptor supplied via SCM_RIGHTS"); - return; - } if (qemu_isdigit(fdname[0])) { close(fd); error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdname", "a name not starting with a digit"); - return; + return false; } /* See close() call below. */ - qemu_mutex_lock(&cur_mon->mon_lock); - QLIST_FOREACH(monfd, &cur_mon->fds, next) { + qemu_mutex_lock(&mon->mon_lock); + QLIST_FOREACH(monfd, &mon->fds, next) { + int tmp_fd; + if (strcmp(monfd->name, fdname) != 0) { continue; } tmp_fd = monfd->fd; monfd->fd = fd; - qemu_mutex_unlock(&cur_mon->mon_lock); + qemu_mutex_unlock(&mon->mon_lock); /* Make sure close() is outside critical section */ close(tmp_fd); - return; + return true; } monfd = g_new0(mon_fd_t, 1); monfd->name = g_strdup(fdname); monfd->fd = fd; - QLIST_INSERT_HEAD(&cur_mon->fds, monfd, next); - qemu_mutex_unlock(&cur_mon->mon_lock); + QLIST_INSERT_HEAD(&mon->fds, monfd, next); + qemu_mutex_unlock(&mon->mon_lock); + return true; +} + +void qmp_getfd(const char *fdname, Error **errp) +{ + Monitor *cur_mon = monitor_cur(); + int fd; + + fd = qemu_chr_fe_get_msgfd(&cur_mon->chr); + if (fd == -1) { + error_setg(errp, "No file descriptor supplied via SCM_RIGHTS"); + return; + } + + monitor_add_fd(cur_mon, fd, fdname, errp); } void qmp_closefd(const char *fdname, Error **errp) @@ -214,6 +223,41 @@ AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, return NULL; } +#ifdef WIN32 +void qmp_get_win32_socket(const char *infos, const char *fdname, Error **errp) +{ + g_autofree WSAPROTOCOL_INFOW *info = NULL; + gsize len; + SOCKET sk; + int fd; + + info = (void *)g_base64_decode(infos, &len); + if (len != sizeof(*info)) { + error_setg(errp, "Invalid WSAPROTOCOL_INFOW value"); + return; + } + + sk = WSASocketW(FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + info, 0, 0); + if (sk == INVALID_SOCKET) { + error_setg_win32(errp, WSAGetLastError(), "Couldn't import socket"); + return; + } + + fd = _open_osfhandle(sk, _O_BINARY); + if (fd < 0) { + error_setg_errno(errp, errno, "Failed to associate a FD with the SOCKET"); + closesocket(sk); + return; + } + + monitor_add_fd(monitor_cur(), fd, fdname, errp); +} +#endif + + void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp) { MonFdset *mon_fdset; diff --git a/qapi/misc.json b/qapi/misc.json index f0217cfba05e..5ef6286af307 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -275,6 +275,37 @@ ## { 'command': 'getfd', 'data': {'fdname': 'str'} } +## +# @get-win32-socket: +# +# Add a socket that was duplicated to QEMU process with +# WSADuplicateSocketW() via WSASocket() & WSAPROTOCOL_INFOW structure +# and assign it a name (the SOCKET is associated with a CRT file +# descriptor) +# +# @info: the WSAPROTOCOL_INFOW structure (encoded in base64) +# +# @fdname: file descriptor name +# +# Returns: Nothing on success +# +# Since: 8.0 +# +# Notes: If @fdname already exists, the file descriptor assigned to +# it will be closed and replaced by the received file +# descriptor. +# +# The 'closefd' command can be used to explicitly close the +# file descriptor when it is no longer needed. +# +# Example: +# +# -> { "execute": "get-win32-socket", "arguments": { "info": "abcd123..", fdname": "skclient" } } +# <- { "return": {} } +# +## +{ 'command': 'get-win32-socket', 'data': {'info': 'str', 'fdname': 'str'}, 'if': 'CONFIG_WIN32' } + ## # @closefd: #