From nobody Sat Feb 7 08:23:19 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 205.139.110.120 as permitted sender) client-ip=205.139.110.120; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-1.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 205.139.110.120 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) by mx.zohomail.com with SMTPS id 1580217132356640.7092137368066; Tue, 28 Jan 2020 05:12:12 -0800 (PST) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-28-hhCweK6GOhelMKz2wKrVIg-1; Tue, 28 Jan 2020 08:12:06 -0500 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 4E122801E6C; Tue, 28 Jan 2020 13:12:01 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 1DCA11001B08; Tue, 28 Jan 2020 13:12:01 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id CA8C618089CE; Tue, 28 Jan 2020 13:12:00 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 00SDBui8019162 for ; Tue, 28 Jan 2020 08:11:56 -0500 Received: by smtp.corp.redhat.com (Postfix) id 0AD3F1001B3F; Tue, 28 Jan 2020 13:11:56 +0000 (UTC) Received: from domokun.gsslab.fab.redhat.com (unknown [10.33.8.110]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4B1A01001DD8; Tue, 28 Jan 2020 13:11:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1580217131; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=fXhxP+L3voh3txAC/frk+Rgcl+9pXCgYwrm+KyFMeEo=; b=ei7TI1uqRv6lk40nsh+0tMKyu1ZG3Lg33n6yWQl7xPbJImO2pfDxNn5JViEdqPCrG2EVRt QAPahaywMnpnBCmKHjJJcu+cgkqpZVOYsNVEKat5dxc5h1qt2J6y1HdmeI1W6hQEUEuuTC mozwQP2qVeJo+filgnkP0HsOZTBWvC0= From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: libvir-list@redhat.com Subject: [libvirt PATCH v2 11/56] src: implement APIs for passing FDs over UNIX sockets Date: Tue, 28 Jan 2020 13:10:52 +0000 Message-Id: <20200128131137.1762449-12-berrange@redhat.com> In-Reply-To: <20200128131137.1762449-1-berrange@redhat.com> References: <20200128131137.1762449-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-loop: libvir-list@redhat.com Cc: Pavel Hrdina X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-MC-Unique: hhCweK6GOhelMKz2wKrVIg-1 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) Content-Type: text/plain; charset="utf-8" This is a simplified variant of gnulib's passfd module without the portability code that we do not require. Reviewed-by: Pavel Hrdina Signed-off-by: Daniel P. Berrang=C3=A9 --- src/libvirt_private.syms | 5 ++ src/qemu/qemu_interface.c | 4 +- src/rpc/virnetsocket.c | 5 +- src/util/virfile.c | 5 +- src/util/virsocket.c | 139 +++++++++++++++++++++++++++++++++++++- src/util/virsocket.h | 3 + 6 files changed, 151 insertions(+), 10 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index ed451f7bfc..022ab29aa0 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3006,6 +3006,11 @@ virSecretLookupFormatSecret; virSecretLookupParseSecret; =20 =20 +# util/virsocket.h +virSocketRecvFD; +virSocketSendFD; + + # util/virsocketaddr.h virSocketAddrBroadcast; virSocketAddrBroadcastByPrefix; diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c index bb62b53c04..48bb0043fe 100644 --- a/src/qemu/qemu_interface.c +++ b/src/qemu/qemu_interface.c @@ -25,7 +25,6 @@ #include "domain_audit.h" #include "domain_nwfilter.h" #include "qemu_interface.h" -#include "passfd.h" #include "viralloc.h" #include "virlog.h" #include "virstring.h" @@ -34,6 +33,7 @@ #include "virnetdevmacvlan.h" #include "virnetdevbridge.h" #include "virnetdevvportprofile.h" +#include "virsocket.h" =20 #include #include @@ -347,7 +347,7 @@ qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr= cfg, } =20 do { - *tapfd =3D recvfd(pair[0], 0); + *tapfd =3D virSocketRecvFD(pair[0], 0); } while (*tapfd < 0 && errno =3D=3D EINTR); =20 if (*tapfd < 0) { diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index 23384e5250..b25c57d01e 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -56,7 +56,6 @@ #include "virprobe.h" #include "virprocess.h" #include "virstring.h" -#include "passfd.h" =20 #if WITH_SSH2 # include "virnetsshsession.h" @@ -2029,7 +2028,7 @@ int virNetSocketSendFD(virNetSocketPtr sock, int fd) virObjectLock(sock); PROBE(RPC_SOCKET_SEND_FD, "sock=3D%p fd=3D%d", sock, fd); - if (sendfd(sock->fd, fd) < 0) { + if (virSocketSendFD(sock->fd, fd) < 0) { if (errno =3D=3D EAGAIN) ret =3D 0; else @@ -2062,7 +2061,7 @@ int virNetSocketRecvFD(virNetSocketPtr sock, int *fd) } virObjectLock(sock); =20 - if ((*fd =3D recvfd(sock->fd, O_CLOEXEC)) < 0) { + if ((*fd =3D virSocketRecvFD(sock->fd, O_CLOEXEC)) < 0) { if (errno =3D=3D EAGAIN) ret =3D 0; else diff --git a/src/util/virfile.c b/src/util/virfile.c index b3a63fa2ea..51a0d40b50 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -25,7 +25,6 @@ #include #include "internal.h" =20 -#include #include #ifndef WIN32 # include @@ -2268,7 +2267,7 @@ virFileOpenForked(const char *path, int openflags, mo= de_t mode, } =20 do { - ret =3D sendfd(pair[1], fd); + ret =3D virSocketSendFD(pair[1], fd); } while (ret < 0 && errno =3D=3D EINTR); =20 if (ret < 0) { @@ -2302,7 +2301,7 @@ virFileOpenForked(const char *path, int openflags, mo= de_t mode, VIR_FORCE_CLOSE(pair[1]); =20 do { - fd =3D recvfd(pair[0], 0); + fd =3D virSocketRecvFD(pair[0], 0); } while (fd < 0 && errno =3D=3D EINTR); VIR_FORCE_CLOSE(pair[0]); /* NB: this preserves errno */ if (fd < 0) diff --git a/src/util/virsocket.c b/src/util/virsocket.c index 96b9ece2b7..9aa29f1eb6 100644 --- a/src/util/virsocket.c +++ b/src/util/virsocket.c @@ -19,10 +19,12 @@ #include =20 #include "virsocket.h" +#include "virutil.h" +#include "virfile.h" =20 -#ifdef WIN32 +#include =20 -# include +#ifdef WIN32 =20 # define FD2SK(fd) _get_osfhandle(fd) # define SK2FD(sk) (_open_osfhandle((intptr_t) (sk), O_RDWR | O_BINARY)) @@ -365,3 +367,136 @@ vir_socket(int domain, int type, int protocol) } =20 #endif /* WIN32 */ + + +/* The following two methods are derived from GNULIB's + * passfd code */ + +/* MSG_CMSG_CLOEXEC is defined only on Linux, as of 2011. */ +#ifndef MSG_CMSG_CLOEXEC +# define MSG_CMSG_CLOEXEC 0 +#endif + +#ifndef WIN32 +/* virSocketSendFD sends the file descriptor fd along the socket + to a process calling virSocketRecvFD on the other end. + + Return 0 on success, or -1 with errno set in case of error. +*/ +int +virSocketSendFD(int sock, int fd) +{ + char byte =3D 0; + struct iovec iov; + struct msghdr msg; + struct cmsghdr *cmsg; + char buf[CMSG_SPACE(sizeof(fd))]; + + /* send at least one char */ + memset(&msg, 0, sizeof(msg)); + iov.iov_base =3D &byte; + iov.iov_len =3D 1; + msg.msg_iov =3D &iov; + msg.msg_iovlen =3D 1; + msg.msg_name =3D NULL; + msg.msg_namelen =3D 0; + + msg.msg_control =3D buf; + msg.msg_controllen =3D sizeof(buf); + cmsg =3D CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level =3D SOL_SOCKET; + cmsg->cmsg_type =3D SCM_RIGHTS; + cmsg->cmsg_len =3D CMSG_LEN(sizeof(fd)); + /* Initialize the payload: */ + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + msg.msg_controllen =3D cmsg->cmsg_len; + + if (sendmsg(sock, &msg, 0) !=3D iov.iov_len) + return -1; + return 0; +} + + +/* virSocketRecvFD receives a file descriptor through the socket. + The flags are a bitmask, possibly including O_CLOEXEC (defined in ). + + Return the fd on success, or -1 with errno set in case of error. +*/ +int +virSocketRecvFD(int sock, int fdflags) +{ + char byte =3D 0; + struct iovec iov; + struct msghdr msg; + int fd =3D -1; + ssize_t len; + struct cmsghdr *cmsg; + char buf[CMSG_SPACE(sizeof(fd))]; + int fdflags_recvmsg =3D fdflags & O_CLOEXEC ? MSG_CMSG_CLOEXEC : 0; + + if ((fdflags & ~O_CLOEXEC) !=3D 0) { + errno =3D EINVAL; + return -1; + } + + /* send at least one char */ + memset(&msg, 0, sizeof(msg)); + iov.iov_base =3D &byte; + iov.iov_len =3D 1; + msg.msg_iov =3D &iov; + msg.msg_iovlen =3D 1; + msg.msg_name =3D NULL; + msg.msg_namelen =3D 0; + + msg.msg_control =3D buf; + msg.msg_controllen =3D sizeof(buf); + cmsg =3D CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level =3D SOL_SOCKET; + cmsg->cmsg_type =3D SCM_RIGHTS; + cmsg->cmsg_len =3D CMSG_LEN(sizeof(fd)); + /* Initialize the payload: */ + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + msg.msg_controllen =3D cmsg->cmsg_len; + + len =3D recvmsg(sock, &msg, fdflags_recvmsg); + if (len < 0) + return -1; + + cmsg =3D CMSG_FIRSTHDR(&msg); + /* be paranoiac */ + if (len =3D=3D 0 || cmsg =3D=3D NULL || cmsg->cmsg_len !=3D CMSG_LEN(s= izeof(fd)) + || cmsg->cmsg_level !=3D SOL_SOCKET || cmsg->cmsg_type !=3D SCM_RI= GHTS) { + /* fake errno: at end the file is not available */ + errno =3D len ? EACCES : ENOTCONN; + return -1; + } + + memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); + + /* set close-on-exec flag */ + if (!MSG_CMSG_CLOEXEC && (fdflags & O_CLOEXEC)) { + if (virSetCloseExec(fd) < 0) { + int saved_errno =3D errno; + VIR_FORCE_CLOSE(fd); + errno =3D saved_errno; + return -1; + } + } + + return fd; +} +#else /* WIN32 */ +int +virSocketSendFD(int sock G_GNUC_UNUSED, int fd G_GNUC_UNUSED) +{ + errno =3D ENOSYS; + return -1; +} + +int +virSocketRecvFD(int sock G_GNUC_UNUSED, int fdflags G_GNUC_UNUSED) +{ + errno =3D ENOSYS; + return -1; +} +#endif /* WIN32 */ diff --git a/src/util/virsocket.h b/src/util/virsocket.h index 33f237886f..e1e7d08bb4 100644 --- a/src/util/virsocket.h +++ b/src/util/virsocket.h @@ -20,6 +20,9 @@ =20 #include "internal.h" =20 +int virSocketSendFD(int sock, int fd); +int virSocketRecvFD(int sock, int fdflags); + #ifdef WIN32 =20 # define WIN32_LEAN_AND_MEAN --=20 2.24.1