From nobody Sat Sep 26 09:21:25 2026 Received: from mail-oo1-f43.google.com (mail-oo1-f43.google.com [209.85.161.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6D4AB453A29 for ; Wed, 2 Sep 2026 23:01:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.161.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788390080; cv=none; b=JAMCAzTLPduWyny0qVrpCvQKXtxLPXJz4NdNBA6AYgt0BYQ5d2FgbG4xygtqOoTymTXOxzq1DQ0eVNGkoTOOQE1NXyziQUtH41ZdA4VNqC3msQ6miT9mYIGRs4/3gUbd+2kNuoyhPpPwfchx7OyoHwR5UAPx+frv3GhLyQoF9i4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788390080; c=relaxed/simple; bh=dqBzikGa14hqqrjBAPe6y9B3zxWzEgOKtDsMRinPnZo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=KSA9WcJkA6FcN+DKD4iUqSobFuagsxYxjbBrXiUews+ru1DZK0MAWFstohieP3BlXGqL2s0Uu1YEwebRc22NS9mcu6KYVPQVEY8877JZlTAq8fdz4KHUmd4GhFFCvrcpbK8gCgqgau1uam02CHrnFt4kfDldKNS1JQigCkdLdRs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=NS/oc9Hs; arc=none smtp.client-ip=209.85.161.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="NS/oc9Hs" Received: by mail-oo1-f43.google.com with SMTP id 006d021491bc7-6b145a9623fso681510eaf.3 for ; Wed, 02 Sep 2026 16:01:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788390071; x=1788994871; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=SMJ26BWtmMrRnikBYx5aKuMSmpbwrNZ5wPGOE3sWg+I=; b=NS/oc9Hs/kVwiejmZ7MPNrn6+wn+zRHOWaT93IT2LjLmJ+RO0MmW77B7NylKm0NVkt YagYJoRDEQxQxwoHPluJ3u1ibpr7/CQXyfoymvj4rnDBjNTEsN3ehMjTVnzKDLVicAqU Ik9SMedEsF/hVxj5knJ8kTChfDbSnZKdf9EIs03LmDZ4swRlJZRQMe19iULPOArImK23 h2tTXXM0k84o5RUa0YitPwSz/udjr/wTvdE31p0X60UdHj+8yZ4u+xao8fDgi3vxX7m2 3O6lWpzLFLuVsrT//36AjsL0vg9UZ8iBt+lTAy0iZlcDbHfbYWk4eAXWm8+ioPHtBF2m J1/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788390071; x=1788994871; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=SMJ26BWtmMrRnikBYx5aKuMSmpbwrNZ5wPGOE3sWg+I=; b=dg6xWQU5H/xemLCU27on6YPjpHjCkM1+JHEbdv2W0nFjAjRn+7ZPQX48T8FKGo2GMR pAMA2yNVQG0eq8JpsjpqaLuYBRl6p4qtDS8vRpvByoBDNeR0ysh1x+6C0W+6abFJfwl/ RIbhmFrOkT1X8vHfX0ltmSVxTjptaP7TbfWAaK1swUKX3vSRRq7VzuQqJJ4HHAKJgZ+J 0G7eH5gunWrFdSs2w8R2W7Ihe12Fm8F4qDAHthBNEEsQ7YttVcj7DXO6wGe2Q7d7S/V1 Kupd/JDUgiAEK9ajMQXX1LisU/Ximmowjz0hoyIxMkwq6w0AR/tQ3D/dcdBcESXV2pmk a25g== X-Forwarded-Encrypted: i=1; AKwUvBxYYrkGeBe9RV0emMKobOkU+FOFvbTx5Laj1aAcLxlZQNXnT8IySlmUVRhQaT/+ao3MBhonAwKx32fmnes=@vger.kernel.org X-Gm-Message-State: AFuF++nK5+/uElTI2kfAEKtcKwga+cTyoRHohitADQXZup4QMw5LHeCK BZ5nUbtfboS0OwDLnN4BqLw4sMPRF4XU5YYzkK5/LEoGVhaadZgeb7TQ X-Gm-Gg: AYBFou0LjgcjaZllxlQRB9WrvAAjjSJVqohmSf3NnUi5pMc+th4yo9+5vi4t+/gkoQj dKByVsmA7kChK4rJco9Q5Qb4w4kpoenLZGUbtiimSvnN6MCa9xniJ7gYLFnumZkC1Dxd0H/hH8F GLahtJKhIRhlQQ+UKAgtNzDjoexxeuS/RhBzl26/sbQrwDGaPWNOItlWW3zI8CZ3XOSGj0k275D mtk45NCWc0od884X8/DmzqJfkSId5fo8SM+XgnPhzzOdyDg9/m5u2OYJ42H5Y8vpxlgPvnNjlW4 bqD81Rp2DqOfvqxkbFxEhUaf9xK2RhlDE311uKxyDKz1qILEg2lmtUxtAlTERlxjlAf53sX+5SE BjllSL5QE33VFkTFGPpg+/uSGFUudJwYu7KHJOzv34esu2FK0tYMHdGTm5+Kt7koYJbOSXnyrsi GYgMnCrxjlRUamRfRC8ro6Q3Ru11DgV3gi3VHQL13C0Ae7QV7qt0LO8zQUG5qv1oy9A10= X-Received: by 2002:a05:6820:1898:b0:6ae:4131:98c6 with SMTP id 006d021491bc7-6b47ecdabc4mr6868224eaf.2.1788390070886; Wed, 02 Sep 2026 16:01:10 -0700 (PDT) Received: from localhost ([2a03:2880:ff:1d::]) by smtp.gmail.com with ESMTPSA id 006d021491bc7-6b40f92004fsm3807143eaf.15.2026.09.02.16.01.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 02 Sep 2026 16:01:09 -0700 (PDT) From: Bobby Eshleman Date: Wed, 02 Sep 2026 16:00:47 -0700 Subject: [PATCH net-next 1/6] vsock: constify the transport in vsock_for_each_connected_socket() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260902-vsock-guest-ns-v1-1-9995383e9a8b@meta.com> References: <20260902-vsock-guest-ns-v1-0-9995383e9a8b@meta.com> In-Reply-To: <20260902-vsock-guest-ns-v1-0-9995383e9a8b@meta.com> To: Stefano Garzarella , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan , Stefan Hajnoczi , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , =?utf-8?q?Eugenio_P=C3=A9rez?= , Shuah Khan , Randy Dunlap Cc: virtualization@lists.linux.dev, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org, sargun@sargun.me, jlinbox@meta.com, Bobby Eshleman X-Mailer: b4 0.14.3 From: Bobby Eshleman Allow const transports to be passed too. The function only compares the pointer against vsk->transport, which is itself const, and never writes through it. No functional change. Signed-off-by: Bobby Eshleman Reviewed-by: Stefano Garzarella Suggested-by: Stefano Garzarella --- include/net/af_vsock.h | 2 +- net/vmw_vsock/af_vsock.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h index 3357ee62d10b..87fdec60ba45 100644 --- a/include/net/af_vsock.h +++ b/include/net/af_vsock.h @@ -230,7 +230,7 @@ struct sock *vsock_find_connected_socket_net(struct soc= kaddr_vm *src, struct sockaddr_vm *dst, struct net *net); void vsock_remove_sock(struct vsock_sock *vsk); -void vsock_for_each_connected_socket(struct vsock_transport *transport, +void vsock_for_each_connected_socket(const struct vsock_transport *transpo= rt, void (*fn)(struct sock *sk)); int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk); bool vsock_find_cid(unsigned int cid); diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index a33b2a2d381d..29cde17e08f3 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -448,7 +448,7 @@ void vsock_remove_sock(struct vsock_sock *vsk) } EXPORT_SYMBOL_GPL(vsock_remove_sock); =20 -void vsock_for_each_connected_socket(struct vsock_transport *transport, +void vsock_for_each_connected_socket(const struct vsock_transport *transpo= rt, void (*fn)(struct sock *sk)) { int i; --=20 2.53.0-Meta From nobody Sat Sep 26 09:21:25 2026 Received: from mail-oi1-f178.google.com (mail-oi1-f178.google.com [209.85.167.178]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0630D395DBF for ; Wed, 2 Sep 2026 23:01:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788390082; cv=none; b=K7r/pPcMrco0i3IJhTWLKlAkSdhV+YLoOeoqYLuHy9fIz719u2NZJ7giWwjebp4PRKGCfZtOQs/iuzEL2vvzwGzgHZKbij3/uIFJ2wLs8UZX24M+JfadF9y42W4XNew7WL2KDrML+iwGUinOVRQ9WbCy2HHiWa83QsLfiIrQlJs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788390082; c=relaxed/simple; bh=Tm571x8d4LFXskh9AVAPtA2pZHrNF5O4xRS9FN3mKz8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=o7pJcLbDibTsuc8fqTjR5oSzKSXymJG+yiIulWwysDbHc5nRtQkofu1eOfsebl5V++C81i76VhvmjRuA+vqHY2g37esfOoI1xTNXlvcQFQB9Ipb29/u3I9v4SB2qXmKzW27oJdYkOauUKvCOxX5gkljqSGbnttX3NU4KQZfLpxw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=h7xu2gNz; arc=none smtp.client-ip=209.85.167.178 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="h7xu2gNz" Received: by mail-oi1-f178.google.com with SMTP id 5614622812f47-4b5b727be96so1041988b6e.3 for ; Wed, 02 Sep 2026 16:01:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788390073; x=1788994873; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=lb48jI6YWiGxZr2/rI2vDfkbai+SxzsoH9XQp9q03Ts=; b=h7xu2gNznp0EJC7376hiL0MBQP7FBcRPKIVLUvSEPeRMYj82QgiEuit8/OX15/IfUe dzrTByAYUjepGkiOGNUXy8hC/Yijz0w2d/gruIomqkk87AmN+kxgLQ/up/rgrPiIe48n dS40sz8uAghhGqFaiLSWbxXs+Ziv5TldOw/Ymipp04r43dgU6X4pcYHyGzTN94QtlPDN tlBMD5MX0ictc6kwTQ56vNVDkrSCMujszM03oOfUrPw14+27ROwi+AGncjkQsocQOJMj gh/5LDHIIra5+DV3o6Aw7lWGN9kyo7Ov7Oulg1X6UMkX+1UdW5Y8WPZqYBElQ5pkDY1t /mpA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788390073; x=1788994873; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=lb48jI6YWiGxZr2/rI2vDfkbai+SxzsoH9XQp9q03Ts=; b=dzqe2UJobqS8dWncgMF7N4p0fiYox77PM9IAQ/tAXfoepCpBW3Zg5O/oEC1Q6V+fW+ fHGDqMUrUvSAl0vnEs5sdvOooFj1SGAIrVaTY0W1Pr5Gek8PNwbWk/JMEnayhL2IHNHM fY+xTXNNeBHrKIlrqn/vVCsLuqvNjlPsT5R847RlayAx3ri7Y26GFFuAuVauokoXXx/3 mS3G/Xoq6cV+EdTLPkeZ26P61A/IZLp8gqKbcEAeuoTpvGNc7uIdTyKlLNEw+M7Q69ft k+B5gez4n9yMur/CPbjveggk4QGPViUhsH3MOzgz9NXSgb0kOxAv7qtnd95nGPcDylCQ Fvdw== X-Forwarded-Encrypted: i=1; AKwUvBzqkH5EkVUqdcrW05r3f4kj1ByKjZk/DHbiZYEif1mFaDVKxMKBDNe7toeijQNI24tKDx0vcAMnsLXbsAQ=@vger.kernel.org X-Gm-Message-State: AFuF++mepG8KtNmbp4A5pwDZdQBb5OQPr6UQ0bufqznI1opnPCHsEPwW L9MGiR57PZpWmiHzMC4PCj1hDqHSinBONPV8LhAaCrorQZ+r1d37Ac3J X-Gm-Gg: AYBFou2p3G72avrgeoNR8wDJFY36d7u9rULouV9nCWWLS7hxLiqA0NFQWKkWZd8eYS4 FnzY7dd4ZFefaZaw0tqVIPHq8d4JkNqlKTjpEUEK3b5iMhJT23NRYSkqdAQ6xc4qGIQyv6upRTy yDDVYfkwI5kQsAY4C9MFGJN0ln0RwB6Wt4k5+gMKUq5HuIgcZ9dC71TMY/vl4yA4hUDkUtCN7Rd WdLH3Spzy0oVAMSwUIeCQx4lUHlFdU7SDu7Ygq3BPhfWuwhK3VOmKNZvKe5zqCxIDw7iJ2q5kQn yyBacXd5u2LPj3CoprVkUnGULmD3yvElvYh5V97/swT1IPdPwozvAIERYjlQLvHyia8MIgEmuzK 4k8FVjRgGkdKAhSUDh2kTnnRDE2RicQhQWItGqEq79ynRXx0Labf/20u4E1VDhUEuHBrpZ7jdKZ m7Yy5BAkoSmBcwwijEcRR32N2lzWmCBEKtINu/NA9uv7yvVN6juv2GVF6s X-Received: by 2002:a05:6808:50a9:b0:490:315d:e0d5 with SMTP id 5614622812f47-4b6bee73ae3mr8725875b6e.16.1788390072924; Wed, 02 Sep 2026 16:01:12 -0700 (PDT) Received: from localhost ([2a03:2880:ff:53::]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4b698a34576sm3444957b6e.5.2026.09.02.16.01.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 02 Sep 2026 16:01:12 -0700 (PDT) From: Bobby Eshleman Date: Wed, 02 Sep 2026 16:00:48 -0700 Subject: [PATCH net-next 2/6] vsock: add IOCTL_VM_SOCKETS_ASSIGN_G2H_NETNS Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260902-vsock-guest-ns-v1-2-9995383e9a8b@meta.com> References: <20260902-vsock-guest-ns-v1-0-9995383e9a8b@meta.com> In-Reply-To: <20260902-vsock-guest-ns-v1-0-9995383e9a8b@meta.com> To: Stefano Garzarella , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan , Stefan Hajnoczi , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , =?utf-8?q?Eugenio_P=C3=A9rez?= , Shuah Khan , Randy Dunlap Cc: virtualization@lists.linux.dev, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org, sargun@sargun.me, jlinbox@meta.com, Bobby Eshleman X-Mailer: b4 0.14.3 From: Bobby Eshleman Namespaces let a host isolate a VM's vsock traffic to a specific namespace, but in a guest vsock traffic cannot be isolated to a namespace. The vsock device is hardcoded to global mode and can't be moved into a local-mode namespace. Introduce ioctl IOCTL_VM_SOCKETS_ASSIGN_G2H_NETNS on /dev/vsock that gives userspace a way to move the device to the calling pid's namespace. The call requires CAP_NET_ADMIN in the root user namespace. A privileged user wishing to "unassign" the device can move it to the init_netns, which is hardcoded to global mode (so no unassign call is necessary). A getter to read the current assignment back was considered, returning either the namespace's net_cookie or its nsfs inode number, but neither seemed useful enough to bake into the uAPI now. It can be added later if a user turns up that needs it. Add a transport hook to indicate support for guest namespacing, so that transports may opt in/out. A transport that opts out keeps the reachability rules it had before this ioctl existed. Sockets are reset when the underlying device moves to a different namespace, so as to prevent reachability from the previous and now disallowed namespace. Following the approach of netdevs, the device returns to init_net when its namespace is removed. Care is taken to not break flows when the device is inside a global namespace that is being torn down and alive sockets are in a different global namespace. In this scenario, the device's netns getter pre-emptively falls back to the init_net (always global) so that these flows are not disrupted. If init_netns ever supports local-mode in the future, this logic will have to be changed. Suggested-by: Stefano Garzarella Link: https://lore.kernel.org/all/20200427142518.uwssa6dtasrp3bfc@steredhat/ Signed-off-by: Bobby Eshleman --- Documentation/admin-guide/sysctl/net.rst | 18 +++ include/net/af_vsock.h | 7 ++ include/uapi/linux/vm_sockets.h | 6 + net/vmw_vsock/af_vsock.c | 198 +++++++++++++++++++++++++++= +++- 4 files changed, 228 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/sysctl/net.rst b/Documentation/admin= -guide/sysctl/net.rst index e586e17fc7a5..1e9c0d2be7b8 100644 --- a/Documentation/admin-guide/sysctl/net.rst +++ b/Documentation/admin-guide/sysctl/net.rst @@ -515,6 +515,24 @@ their hosts. The behavior of VSOCK sockets in a networ= k namespace is determined by the namespace's mode (``global`` or ``local``), which controls how CIDs (Context IDs) are allocated and how sockets interact across namespaces. =20 +In a guest, the vsock device owned by the guest-to-host (G2H) transport be= longs +to one network namespace at a time. The ``IOCTL_VM_SOCKETS_ASSIGN_G2H_NETN= S`` +ioctl on ``/dev/vsock`` moves it to the namespace of the calling process, = which +requires ``CAP_NET_ADMIN`` in the initial user namespace. The namespace's = mode +decides who may then use the device: + +- ``global`` - every ``global`` mode namespace may use it. +- ``local`` - only that namespace may use it, which reserves the connectio= n to + the host for it alone. + +The device starts out in the initial namespace, so until the ioctl is issu= ed +nothing has moved and no mode has changed. + +Connections made before the move, from a namespace that can no longer reac= h the +device, are reset. The device returns to the initial namespace when the +namespace it was moved to is deleted, so assigning it to the initial names= pace +is how an assignment is undone. + ns_mode ------- =20 diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h index 87fdec60ba45..64c4b205a11b 100644 --- a/include/net/af_vsock.h +++ b/include/net/af_vsock.h @@ -190,6 +190,9 @@ struct vsock_transport { =20 /* Zero-copy. */ bool (*msgzerocopy_allow)(void); + + /* True if the transport honours IOCTL_VM_SOCKETS_ASSIGN_G2H_NETNS. */ + bool (*netns_assign_allow)(void); }; =20 /**** CORE ****/ @@ -235,6 +238,10 @@ void vsock_for_each_connected_socket(const struct vsoc= k_transport *transport, int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk); bool vsock_find_cid(unsigned int cid); void vsock_linger(struct sock *sk); +struct net *vsock_g2h_net_get(void); +bool vsock_g2h_net_reachable(struct net *net); +bool vsock_g2h_reachable_sk(struct vsock_sock *vsk); +bool vsock_maybe_set_connected(struct vsock_sock *vsk); =20 /**** TAP ****/ =20 diff --git a/include/uapi/linux/vm_sockets.h b/include/uapi/linux/vm_socket= s.h index e05280e41522..894b0d65b458 100644 --- a/include/uapi/linux/vm_sockets.h +++ b/include/uapi/linux/vm_sockets.h @@ -195,6 +195,12 @@ struct sockaddr_vm { =20 #define IOCTL_VM_SOCKETS_GET_LOCAL_CID _IO(7, 0xb9) =20 +/* Assign the guest's vsock device to the network namespace of the calling + * process. Requires CAP_NET_ADMIN in the initial user namespace. To undo = an + * assignment, assign the device to the initial network namespace. + */ +#define IOCTL_VM_SOCKETS_ASSIGN_G2H_NETNS _IO(7, 0xba) + /* MSG_ZEROCOPY notifications are encoded in the standard error format, * sock_extended_err. See Documentation/networking/msg_zerocopy.rst in * kernel source tree for more details. diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 29cde17e08f3..ad11f0f56eb8 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -130,6 +130,24 @@ * a different transport that *does* support local mode. For * example, virtio-vsock may not support local mode, but the socket * may still accept a connection from vhost-vsock which does. + * + * - A guest has a single vsock device, owned by the guest->host transport. + * IOCTL_VM_SOCKETS_ASSIGN_G2H_NETNS on /dev/vsock assigns it to the + * namespace of the caller. It starts out in init_net. The mode rules th= en + * decide who may use it, and which namespace packets from the host are + * delivered to: + * + * - assigned to a global mode namespace - every global mode namespace m= ay + * use it. Until the ioctl is issued nothing has moved and no mode has + * changed, so the default is the behaviour that predates it. + * - assigned to a local mode namespace - only that namespace may use it. + * This is how a nested VM is isolated from the rest of the guest. + * + * Connections made before an assignment, from a namespace that can no + * longer reach the device, are reset. + * + * No reference is taken on the assigned namespace. As is done for netde= vs, + * the device is moved back to init_net when that namespace is destroyed. */ =20 #include @@ -208,6 +226,11 @@ static const struct vsock_transport *transport_dgram; static const struct vsock_transport *transport_local; static DEFINE_MUTEX(vsock_register_mutex); =20 +/* Network namespace of the g2h device. Protected by + * vsock_register_mutex/RCU. + */ +static struct net __rcu *vsock_g2h_net =3D RCU_INITIALIZER(&init_net); + /**** UTILS ****/ =20 /* Each bound VSocket is stored in the bind hash table and each connected @@ -548,6 +571,17 @@ static void vsock_deassign_transport(struct vsock_sock= *vsk) vsk->transport =3D NULL; } =20 +/* Return true if the loaded g2h transport honours namespace assignment. O= ne + * that does not keeps the reachability rules it had before the ioctl exis= ted. + * + * Must be called with vsock_register_mutex held. + */ +static bool vsock_g2h_netns_assignable(void) +{ + return transport_g2h && transport_g2h->netns_assign_allow && + transport_g2h->netns_assign_allow(); +} + /* Assign a transport to a socket and call the .init transport callback. * * Note: for connection oriented socket this must be called when vsk->remo= te_addr @@ -622,6 +656,13 @@ int vsock_assign_transport(struct vsock_sock *vsk, str= uct vsock_sock *psk) goto err; } =20 + if (new_transport && new_transport =3D=3D transport_g2h && + vsock_g2h_netns_assignable() && + !vsock_g2h_net_reachable(sock_net(sk))) { + ret =3D -ENETUNREACH; + goto err; + } + /* We increase the module refcnt to prevent the transport unloading * while there are open sockets assigned to it. */ @@ -710,6 +751,140 @@ bool vsock_find_cid(unsigned int cid) } EXPORT_SYMBOL_GPL(vsock_find_cid); =20 +/* Return the g2h devices' namespace with a reference held, or NULL if that + * namespace is being destroyed. + */ +struct net *vsock_g2h_net_get(void) +{ + struct net *assigned; + struct net *net; + + rcu_read_lock(); + assigned =3D rcu_dereference(vsock_g2h_net); + net =3D maybe_get_net(assigned); + + /* !net means the net is about to be destroyed, at which point the g2h + * device will move to the init_net. If the init_net and the dying net + * are both global mode, we use the init_net as a fallback to avoid + * disrupting global-mode flows. The per-net destructor hook will + * eventually move the g2h device to the init_net anyway. + */ + if (!net && vsock_net_check_mode(&init_net, assigned)) + net =3D get_net(&init_net); + rcu_read_unlock(); + + return net; +} +EXPORT_SYMBOL_GPL(vsock_g2h_net_get); + +bool vsock_g2h_net_reachable(struct net *net) +{ + bool reachable; + + rcu_read_lock(); + reachable =3D vsock_net_check_mode(net, rcu_dereference(vsock_g2h_net)); + rcu_read_unlock(); + + return reachable; +} +EXPORT_SYMBOL_GPL(vsock_g2h_net_reachable); + +bool vsock_g2h_reachable_sk(struct vsock_sock *vsk) +{ + const struct vsock_transport *t =3D vsk->transport; + + if (!t || !t->netns_assign_allow || !t->netns_assign_allow()) + return true; + + return vsock_g2h_net_reachable(sock_net(sk_vsock(vsk))); +} +EXPORT_SYMBOL_GPL(vsock_g2h_reachable_sk); + +/* Move @vsk to TCP_ESTABLISHED and into the connected table, unless the d= evice + * has moved to a namespace @vsk cannot reach. Returns false without doing + * either in that case. + * + * vsock_g2h_net_assign() resets the sockets it finds in the same table un= der + * the same lock. Either vsock_g2h_net_assign() sees the vsk in the table = and + * resets it, or it does not see the @vsk in the table and this function + * refuses to add it. This avoids netns assignment racing with outstanding + * connection responses and incoming connection requests. + */ +bool vsock_maybe_set_connected(struct vsock_sock *vsk) +{ + struct list_head *list =3D vsock_connected_sockets(&vsk->remote_addr, + &vsk->local_addr); + bool reachable; + + spin_lock_bh(&vsock_table_lock); + reachable =3D vsock_g2h_reachable_sk(vsk); + if (reachable) { + sk_vsock(vsk)->sk_state =3D TCP_ESTABLISHED; + __vsock_insert_connected(list, vsk); + } + spin_unlock_bh(&vsock_table_lock); + + return reachable; +} +EXPORT_SYMBOL_GPL(vsock_maybe_set_connected); + +static void vsock_reset_unreachable_sock(struct sock *sk) +{ + if (vsock_g2h_net_reachable(sock_net(sk))) + return; + + sk->sk_state =3D TCP_CLOSE; + sk->sk_err =3D ECONNRESET; + sk_error_report(sk); +} + +/* Move the g2h device to @net. Returns -ENODEV if no g2h transport is loa= ded + * and -EOPNOTSUPP if the loaded one cannot be moved. + */ +static int vsock_g2h_net_assign(struct net *net) +{ + int ret =3D 0; + + mutex_lock(&vsock_register_mutex); + if (!transport_g2h) { + ret =3D -ENODEV; + } else if (!vsock_g2h_netns_assignable()) { + ret =3D -EOPNOTSUPP; + } else { + /* See vsock_maybe_set_connected() comment about synchronizing + * with connecting sockets. + */ + rcu_assign_pointer(vsock_g2h_net, net); + vsock_for_each_connected_socket(transport_g2h, + vsock_reset_unreachable_sock); + } + mutex_unlock(&vsock_register_mutex); + + return ret; +} + +/* Move the g2h device back to init_net if it lives in @net, which is abou= t to + * be destroyed. + */ +static void vsock_g2h_net_reset(struct net *net) +{ + bool reset =3D false; + + /* Avoid taking the mutex if the namespaces don't match. */ + if (likely(rcu_access_pointer(vsock_g2h_net) !=3D net)) + return; + + mutex_lock(&vsock_register_mutex); + if (rcu_access_pointer(vsock_g2h_net) =3D=3D net) { + rcu_assign_pointer(vsock_g2h_net, &init_net); + reset =3D true; + } + mutex_unlock(&vsock_register_mutex); + + if (reset) + synchronize_rcu(); +} + static struct sock *vsock_dequeue_accept(struct sock *listener) { struct vsock_sock *vlistener; @@ -2745,6 +2920,15 @@ static long vsock_dev_do_ioctl(struct file *filp, retval =3D -EFAULT; break; =20 + case IOCTL_VM_SOCKETS_ASSIGN_G2H_NETNS: + if (!capable(CAP_NET_ADMIN)) { + retval =3D -EPERM; + break; + } + + retval =3D vsock_g2h_net_assign(current->nsproxy->net_ns); + break; + default: retval =3D -ENOIOCTLCMD; } @@ -2978,6 +3162,7 @@ static __net_init int vsock_sysctl_init_net(struct ne= t *net) =20 static __net_exit void vsock_sysctl_exit_net(struct net *net) { + vsock_g2h_net_reset(net); vsock_sysctl_unregister(net); } =20 @@ -3104,13 +3289,21 @@ EXPORT_SYMBOL_GPL(vsock_core_register); =20 void vsock_core_unregister(const struct vsock_transport *t) { + bool g2h_net_reset =3D false; + mutex_lock(&vsock_register_mutex); =20 if (transport_h2g =3D=3D t) transport_h2g =3D NULL; =20 - if (transport_g2h =3D=3D t) + if (transport_g2h =3D=3D t) { transport_g2h =3D NULL; + /* The device is gone, so is its namespace assignment. */ + if (rcu_access_pointer(vsock_g2h_net) !=3D &init_net) { + rcu_assign_pointer(vsock_g2h_net, &init_net); + g2h_net_reset =3D true; + } + } =20 if (transport_dgram =3D=3D t) transport_dgram =3D NULL; @@ -3119,6 +3312,9 @@ void vsock_core_unregister(const struct vsock_transpo= rt *t) transport_local =3D NULL; =20 mutex_unlock(&vsock_register_mutex); + + if (g2h_net_reset) + synchronize_rcu(); } EXPORT_SYMBOL_GPL(vsock_core_unregister); =20 --=20 2.53.0-Meta From nobody Sat Sep 26 09:21:25 2026 Received: from mail-oa1-f44.google.com (mail-oa1-f44.google.com [209.85.160.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BD1144508F8 for ; Wed, 2 Sep 2026 23:01:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788390088; cv=none; b=nKX0a/kYPrDhOGmWnVd00k7CrDRIb2Riw7tHAxPEGdf7rY/gQEq6RU0wGtoWs5RttzKdp7tZ2hymXXira6uJm70MRGorxZhRaOJ32IvtI/5mtC/U+HLfG2ouhBpB3LTWYfAteWIINp4pqa1gf7/fgDBqq00DXCbusJ95sdlfuwI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788390088; c=relaxed/simple; bh=5V1mBK4+6n/Zucyqo2XDfm7ZN3GwgggVQjapNBOVBBY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=JogLAezvdT6BmI4lla8PqGoqcnDPj7+QDezulxPHW9SUpvIs8CSeBsWA45stN22oyyHl7QaUDnprvChjEVSpDHNF+/84przC2qOtE0jlwQTZhand4xb9iNpE9V4eaw3ePNDU08DkDp4JN9r6yEuGGT5DJw/w6JI6Bvf8y2wf+HA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=pgomh2cv; arc=none smtp.client-ip=209.85.160.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="pgomh2cv" Received: by mail-oa1-f44.google.com with SMTP id 586e51a60fabf-46adfc80ff6so904738fac.2 for ; Wed, 02 Sep 2026 16:01:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788390078; x=1788994878; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=64gotFInHj04XMQZ+QbhT+/KY6QtyB9D0mjA1FukM2E=; b=pgomh2cvCEW8S6vbOWL2tHCAxRU0uzU/qvGdbmqBlfxjyMN4wynU+sxMAffjTYBW+c fD6+mTGb9gE0BjGtGU0IpaGtgViXwOOQsEuM3xvg1ndyShefVzrwpr2W+O1r0Pjs3ax8 bDz2OlsU3bxoEV4EU8bwIVWYW5xz2D71LmVUZR7R2OIkJ0ySloJwbJ3Ie/gnM4mld/n9 U0EeJFTlXqPr74Rq/vPsKRDSYcqVokFTRcOhJmZWnvbWcGSCOwuHnLZX0xrIdXvnPcSr 5POcleCRingDR0565+s2PsGo7ghDdByqBrkhlR6DfgxK+248nRqa7RsjtOdDK1hw5BJI lXXQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788390078; x=1788994878; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=64gotFInHj04XMQZ+QbhT+/KY6QtyB9D0mjA1FukM2E=; b=Fn/lHh2ACLMJfrFxLczHa2n4t8nlGLtIpt6WSEI3/t+JeyKe5epN78zCdhlrnaWDh3 ktOxr5mCLAXagAKRBeltF4YikbbpN4r0nj1wHpSKFJtlHuNSb+DdBaFeoFOqKUq4kzu9 EI3tMK56d3G0IZqqwRTmuNlo+hS8fAODArI/2qY6SjFD9EcdA3K9jHK7lHHK0YXC+yvc a7EtjPk+w690epA1AC/mcZHisFl9Kbs8k1hGZ1BGEk1E3ganeC3uM1TyigR2QVJ0q8Dh wMKoW9tz+VeyA7uTyxj/ve8k27Vw2u9hO34Fdxo2GcWLGkiwK+LlYaH0KC1pZxB2QFKy caSA== X-Forwarded-Encrypted: i=1; AKwUvBzvWrhVray4Rc8qh9CDMfIMbiaVUd9A7E9ap5Ly0jvwPBfoB7xFZQyXt3DkUbznuPzuxUYoB+yuWM2hP3g=@vger.kernel.org X-Gm-Message-State: AFuF++kBWWsZl7/N3/GMF/o9lO58l8Ds6sxsTfCDDn4DXYSwiJKHVu1P qqN+7FURIWatRl1lAXdYcYHACf1b2YHyAp4gMCYRbGLxZUaQD5Z/qq70 X-Gm-Gg: AYBFou35ubSfb6b96idzlFc3MAaMUjY7yIR4znBDHYkmV6CN7TlfmYmIivnO8bQ1V5E JgTYVZRQu6G9G83SYdr9+SySkvAIUp5nOUEapzGR17r4qUfv4F0zVokq98m3277OVAWSF5B5QQa hVle/gq2xUt0XsFNZyRIwkfxIHJ2FrgZC31NSoIf7cKY7rM6y7MgTGsrR5989l7bzt/ouY3SO+R J6cqQORCwf1Cebm1WpD1m49Uf7Ir4oe/6n+eO2d4V0fqSXx8Qgw0DVhOJULQ1TDSn10tCoP+CzU eZ3TBAM3J8ZWyCtfGaj13qcK8xhZJCr+M3G5zW6bfGG5jCNCKBzLZiXdjdyZsguZi0W1cnuJluw dfdIG1GPQZ0LGEsDTfPgFcIDU6DSxq79xTrB/r7V6RFsJ+oPm6hnBXjI3w4Pn4KCTktOPUdJUAP 0jwsH1yaGHO3Dng82hdLdw355ubOGhTby+H4ClYI2SRIWsCup9QAOIBBGU53IkxjTQ1zJt9w== X-Received: by 2002:a05:6870:1b8b:b0:448:a3d6:c2d2 with SMTP id 586e51a60fabf-46f8a4343eemr7642312fac.10.1788390077649; Wed, 02 Sep 2026 16:01:17 -0700 (PDT) Received: from localhost ([2a03:2880:ff:5e::]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-46f30baa0d4sm5546944fac.6.2026.09.02.16.01.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 02 Sep 2026 16:01:15 -0700 (PDT) From: Bobby Eshleman Date: Wed, 02 Sep 2026 16:00:49 -0700 Subject: [PATCH net-next 3/6] vsock/virtio: support guest device network namespace Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260902-vsock-guest-ns-v1-3-9995383e9a8b@meta.com> References: <20260902-vsock-guest-ns-v1-0-9995383e9a8b@meta.com> In-Reply-To: <20260902-vsock-guest-ns-v1-0-9995383e9a8b@meta.com> To: Stefano Garzarella , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan , Stefan Hajnoczi , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , =?utf-8?q?Eugenio_P=C3=A9rez?= , Shuah Khan , Randy Dunlap Cc: virtualization@lists.linux.dev, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org, sargun@sargun.me, jlinbox@meta.com, Bobby Eshleman X-Mailer: b4 0.14.3 From: Bobby Eshleman virtio-vsock did not have namespace support (the device was always accessible to any global namespace). Make the virtio-vsock device assignable to a namespace and initialize it to init_net. Because virtio-vsock and init_net are both hardcoded to global mode, nothing changes until the assign ioctl is issued. When the device's local-mode namespace is being destroyed, received packets are reset until new valid a namespace has been assigned and/or automatically returned to, and the next RX batch begins (in virtio_transport_rx_work). They are reset rather than dropped because vsock does not retransmit, so a silent drop would leave the host waiting for a timeout, and a connection request arriving in that window has no socket whose teardown would tell it otherwise. This requires making virtio_transport_reset_no_sock() available outside of the common code. When a device is assigned to a namespace, every already established vsock socket that is no longer able to reach the device is forcibly reset. For that reason, adding new sockets to the connected table must be performed atomically with regards to namespace assignment. This ensures that when the socket is added to the connected table that it actually passes the new reachability conditions set by ns assignment. If it wins the race to the table and does NOT pass the reachability tests, then the reset sweep will correctly catch it. This is the purpose of the new helper 'vsock_maybe_set_connected()'. Signed-off-by: Bobby Eshleman Suggested-by: Stefano Garzarella --- include/linux/virtio_vsock.h | 2 ++ net/vmw_vsock/virtio_transport.c | 28 ++++++++++++++++++++++------ net/vmw_vsock/virtio_transport_common.c | 28 +++++++++++++++++++++------- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h index f91704731057..9c68ce1d7fb4 100644 --- a/include/linux/virtio_vsock.h +++ b/include/linux/virtio_vsock.h @@ -286,6 +286,8 @@ void virtio_transport_inc_tx_pkt(struct virtio_vsock_so= ck *vvs, struct sk_buff * u32 virtio_transport_get_credit(struct virtio_vsock_sock *vvs, u32 wanted); void virtio_transport_put_credit(struct virtio_vsock_sock *vvs, u32 credit= ); void virtio_transport_deliver_tap_pkt(struct sk_buff *skb); +int virtio_transport_reset_no_sock(const struct virtio_transport *t, + struct sk_buff *skb, struct net *net); int virtio_transport_purge_skbs(void *vsk, struct sk_buff_head *list); int virtio_transport_read_skb(struct vsock_sock *vsk, skb_read_actor_t rea= d_actor); int virtio_transport_notify_set_rcvlowat(struct vsock_sock *vsk, int val); diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transp= ort.c index 4f9aa9c4c3aa..a453a4f828dc 100644 --- a/net/vmw_vsock/virtio_transport.c +++ b/net/vmw_vsock/virtio_transport.c @@ -540,9 +540,14 @@ static bool virtio_transport_msgzerocopy_allow(void) return true; } =20 +static bool virtio_transport_netns_assign_allow(void) +{ + return true; +} + bool virtio_transport_stream_allow(struct vsock_sock *vsk, u32 cid, u32 po= rt) { - return vsock_net_mode_global(vsk); + return vsock_g2h_net_reachable(sock_net(sk_vsock(vsk))); } =20 static bool virtio_transport_seqpacket_allow(struct vsock_sock *vsk, @@ -587,6 +592,7 @@ static struct virtio_transport virtio_transport =3D { .seqpacket_has_data =3D virtio_transport_seqpacket_has_data, =20 .msgzerocopy_allow =3D virtio_transport_msgzerocopy_allow, + .netns_assign_allow =3D virtio_transport_netns_assign_allow, =20 .notify_poll_in =3D virtio_transport_notify_poll_in, .notify_poll_out =3D virtio_transport_notify_poll_out, @@ -616,7 +622,7 @@ virtio_transport_seqpacket_allow(struct vsock_sock *vsk= , u32 remote_cid) struct virtio_vsock *vsock; bool seqpacket_allow; =20 - if (!vsock_net_mode_global(vsk)) + if (!vsock_g2h_net_reachable(sock_net(sk_vsock(vsk)))) return false; =20 seqpacket_allow =3D false; @@ -634,6 +640,9 @@ static void virtio_transport_rx_work(struct work_struct= *work) struct virtio_vsock *vsock =3D container_of(work, struct virtio_vsock, rx_work); struct virtqueue *vq; + struct net *net; + + net =3D vsock_g2h_net_get(); =20 mutex_lock(&vsock->rx_lock); =20 @@ -682,10 +691,14 @@ static void virtio_transport_rx_work(struct work_stru= ct *work) =20 virtio_transport_deliver_tap_pkt(skb); =20 - /* Force virtio-transport into global mode since it - * does not yet support local-mode namespacing. - */ - virtio_transport_recv_pkt(&virtio_transport, skb, NULL); + if (unlikely(!net)) { + virtio_transport_reset_no_sock( + &virtio_transport, skb, &init_net); + kfree_skb(skb); + continue; + } + + virtio_transport_recv_pkt(&virtio_transport, skb, net); } } while (!virtqueue_enable_cb(vq)); =20 @@ -694,6 +707,9 @@ static void virtio_transport_rx_work(struct work_struct= *work) virtio_vsock_rx_fill(vsock); out_nofill: mutex_unlock(&vsock->rx_lock); + + if (net) + put_net(net); } =20 static int virtio_vsock_vqs_init(struct virtio_vsock *vsock) diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio= _transport_common.c index 88df82364f77..313ef263fd2d 100644 --- a/net/vmw_vsock/virtio_transport_common.c +++ b/net/vmw_vsock/virtio_transport_common.c @@ -1315,8 +1315,8 @@ static int virtio_transport_reset(struct vsock_sock *= vsk, * loopback, this is the namespace of the socket. For vhost, this is the * namespace of the VM (i.e., vhost_vsock). */ -static int virtio_transport_reset_no_sock(const struct virtio_transport *t, - struct sk_buff *skb, struct net *net) +int virtio_transport_reset_no_sock(const struct virtio_transport *t, + struct sk_buff *skb, struct net *net) { struct virtio_vsock_hdr *hdr =3D virtio_vsock_hdr(skb); struct virtio_vsock_pkt_info info =3D { @@ -1355,6 +1355,7 @@ static int virtio_transport_reset_no_sock(const struc= t virtio_transport *t, =20 return t->send_pkt(reply, net); } +EXPORT_SYMBOL_GPL(virtio_transport_reset_no_sock); =20 /* This function should be called with sk_lock held and SOCK_DONE set */ static void virtio_transport_remove_sock(struct vsock_sock *vsk) @@ -1478,9 +1479,14 @@ virtio_transport_recv_connecting(struct sock *sk, =20 switch (le16_to_cpu(hdr->op)) { case VIRTIO_VSOCK_OP_RESPONSE: - sk->sk_state =3D TCP_ESTABLISHED; + /* An assign cannot see a socket that is not connected yet. */ + if (!vsock_maybe_set_connected(vsk)) { + skerr =3D ECONNRESET; + err =3D -ENETUNREACH; + goto destroy; + } + sk->sk_socket->state =3D SS_CONNECTED; - vsock_insert_connected(vsk); sk->sk_state_change(sk); break; case VIRTIO_VSOCK_OP_INVALID: @@ -1736,8 +1742,6 @@ virtio_transport_recv_listen(struct sock *sk, struct = sk_buff *skb, =20 lock_sock_nested(child, SINGLE_DEPTH_NESTING); =20 - child->sk_state =3D TCP_ESTABLISHED; - vchild =3D vsock_sk(child); vsock_addr_init(&vchild->local_addr, le64_to_cpu(hdr->dst_cid), le32_to_cpu(hdr->dst_port)); @@ -1758,7 +1762,17 @@ virtio_transport_recv_listen(struct sock *sk, struct= sk_buff *skb, if (virtio_transport_space_update(child, skb)) child->sk_write_space(child); =20 - vsock_insert_connected(vchild); + /* An assign cannot see a socket that is not connected yet, and the + * check in vsock_assign_transport() above has since dropped + * vsock_register_mutex. + */ + if (!vsock_maybe_set_connected(vchild)) { + release_sock(child); + virtio_transport_reset_no_sock(t, skb, sock_net(sk)); + sock_put(child); + return -ENETUNREACH; + } + vsock_enqueue_accept(sk, child); virtio_transport_send_response(vchild, skb); =20 --=20 2.53.0-Meta From nobody Sat Sep 26 09:21:25 2026 Received: from mail-oa1-f51.google.com (mail-oa1-f51.google.com [209.85.160.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EDD7C4570EE for ; Wed, 2 Sep 2026 23:01:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788390090; cv=none; b=ogOxi2j7Il7hfKeE/Dz/ndO7pqpATuYGj01fLnmH0vzQBdpAU/es8U+CXgahGHL1MJOgdwCG+xTlTYK3r6rPmTjSZxTphR+PiVZH4L5FT5Y/wshuQxd9cTSAKwf267Kfyc6Chn8nLtjrrX8gkrmo0X3+EWSjerBRIXQd2er2xiM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788390090; c=relaxed/simple; bh=jkKXEIPOwBCki7hEhUKs4g/CFbe6ChFGK0eVQgaU6nU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mUZs/qsoZEftwZInycInt2ie9xhYgiVAIh/fsiHFDTpqBgpYNhjW0JhynDBc3MPCnpFXho6Q3cnhhIYuDSrAU7Om6SwJBPZOTtPstIPzRURr/eE+llCJQa6cwOp2BPkm3hZU7YMl6GANzc8giqQ6dz1WUrb7wZ7jawLjoIYWWEE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=hokODlGZ; arc=none smtp.client-ip=209.85.160.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hokODlGZ" Received: by mail-oa1-f51.google.com with SMTP id 586e51a60fabf-43bf9548df4so1400715fac.0 for ; Wed, 02 Sep 2026 16:01:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788390082; x=1788994882; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=0SPSwC6FIuR2igZB1JOk61BDdzgs1mNnqoV9+SaxkZ8=; b=hokODlGZV9B+JuieLJ932AouOKFaQ2dpL1Lsn2rq5uRPMKbvjRfvde7JU/JkC8in4L FsqxSbBcjNrPdOBVtEZFbZZqL6HzxyWFgMnuVYpDO9ER0TXs6KBrv0ga02eMvZpUvs3O KkDPRQUSlr7SwCS+ddFo1PzFE1jlNNq7zrncaV9Msp3a/vC31kWygiNUMt5FBhsiqJBV olYX9MDYVrjSPFF/6a4Je4LPqi4IJCGAkMZ6Y04XKtuIK1GvSMiAqLWHAZODx8Ru8c9K 3r8B62HofTd1NN1RU7U0Tb5TYiwUVBEGVtxCTqAJcENjd9c70vtmv/utkYStl9SObxxV LMhg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788390082; x=1788994882; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=0SPSwC6FIuR2igZB1JOk61BDdzgs1mNnqoV9+SaxkZ8=; b=lmjDQjzA5M2DC6B4ZLe9IWXLtGmBMplVd68AJrJwOOESoNbsh51O9JHwqaQ8c7/RUQ wltjWvY/S+CtsID1GKQNRErCvCczoxtOycZAM+mRGe6cbzCMx/l2phu8CRuhD+yW9LpB IcbiUqU9VFplb/4/5qXXQ3uhbpsYav/mu62h0dWhVpanuU8VUcGjU7VksLT25f9QE7j0 mzc9KQYzh2z3QXpTq2ECDGGf1memvL0BwpcnmiqYnpYtJl/pUSH1nCsDEoEKuO78cuEW EpafKCb3vekny7D6aJhvWKR3QgVW3CxqjC/cz0uoI7ocXGQwa4AFhN+I22QktkOlZcDB TGXA== X-Forwarded-Encrypted: i=1; AKwUvBwnSE7RwUInCrBM3tUwzNhhXS7dgL+zUhttAbjSJ1/boLRqrZJVmGYmSgibFP1CX3G3JFKUWORyYb+560I=@vger.kernel.org X-Gm-Message-State: AFuF++mxqGIT9ox/X+eVY8vl4mBbZCyrTaOyfKrIuv3o/PmlRz8/guFk 0lr59SkUVz9q9UhOvVJEbyJJ3GfavEW59EPStNREehP1hI1ci8RHaxgf X-Gm-Gg: AYBFou19htGIlwTWcH/9UGZoVXTM/6C5QW34YLsKuhva0x1lgOaFm/rQydLw6kMKbG0 9V0RQ1m/rX8PYhTH0rEV5iq/MQDyNfy6Jsx1XfLwTl+JQZJHCzU6sdA8oSaLUadNXYlXj61aecN 3QMLToE7h/J6QlY38LyBRhdmyv0jrgUuR27MD6eGn/9rKb3E9qT6SdXOfxYtdxoj0ezur9D+y1U poQIm9vvqWQRMtQYotFeDncdm8c9sywbEMYcThtoaLTJ2rvneV8dSnWEaGsTQ04RSEJgg5Saw0w 7/7KY7KTIUG1m4PTbOvlfDWKGg+cSfQzXjzr6o0KD+be7OLpNCEUDZ/M7JUqu/NPehZWVffEFIE 9y6xcX+AsQw1+laHQ9je3pTUjFmA3ee+uS8IvqUm7w5KooSj12DxeENLhVvE/ld+s7CZxrIuAXG iHpLMHRDjWEUU+/FFri3H8DBULErzWbS+gzKxV0GVphW2RLQsbsP4WPQn7 X-Received: by 2002:a05:6870:1426:b0:46a:dfdc:c77a with SMTP id 586e51a60fabf-46f86ce6964mr7916129fac.10.1788390081873; Wed, 02 Sep 2026 16:01:21 -0700 (PDT) Received: from localhost ([2a03:2880:ff:10::]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-46f336c72fdsm4762834fac.17.2026.09.02.16.01.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 02 Sep 2026 16:01:19 -0700 (PDT) From: Bobby Eshleman Date: Wed, 02 Sep 2026 16:00:50 -0700 Subject: [PATCH net-next 4/6] selftests/vsock: add a helper to assign the g2h device to a netns Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260902-vsock-guest-ns-v1-4-9995383e9a8b@meta.com> References: <20260902-vsock-guest-ns-v1-0-9995383e9a8b@meta.com> In-Reply-To: <20260902-vsock-guest-ns-v1-0-9995383e9a8b@meta.com> To: Stefano Garzarella , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan , Stefan Hajnoczi , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , =?utf-8?q?Eugenio_P=C3=A9rez?= , Shuah Khan , Randy Dunlap Cc: virtualization@lists.linux.dev, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org, sargun@sargun.me, jlinbox@meta.com, Bobby Eshleman X-Mailer: b4 0.14.3 From: Bobby Eshleman No shell tool can issue IOCTL_VM_SOCKETS_ASSIGN_G2H_NETNS, so anything that wants to move the guest's vsock device from a script needs a small program to do it. It exits with the ioctl's errno so a caller can differentiate the reasons for failure. Signed-off-by: Bobby Eshleman Suggested-by: Stefano Garzarella --- tools/testing/selftests/vsock/.gitignore | 1 + tools/testing/selftests/vsock/Makefile | 3 +- .../selftests/vsock/vsock_assign_g2h_netns.c | 45 ++++++++++++++++++= ++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/vsock/.gitignore b/tools/testing/selft= ests/vsock/.gitignore index 9c5bf379480f..ffca0d9c34b1 100644 --- a/tools/testing/selftests/vsock/.gitignore +++ b/tools/testing/selftests/vsock/.gitignore @@ -1,2 +1,3 @@ vmtest.log +vsock_assign_g2h_netns vsock_test diff --git a/tools/testing/selftests/vsock/Makefile b/tools/testing/selftes= ts/vsock/Makefile index c407c0afd938..d7170a15150f 100644 --- a/tools/testing/selftests/vsock/Makefile +++ b/tools/testing/selftests/vsock/Makefile @@ -11,7 +11,6 @@ $(OUTPUT)/vsock_test: $(VSOCK_TEST_DIR)/vsock_test $(VSOCK_TEST_DIR)/vsock_test: $(VSOCK_TEST_SRCS) $(MAKE) -C $(VSOCK_TEST_DIR) vsock_test TEST_PROGS +=3D vmtest.sh -TEST_GEN_FILES :=3D vsock_test +TEST_GEN_FILES :=3D vsock_test vsock_assign_g2h_netns =20 include ../lib.mk - diff --git a/tools/testing/selftests/vsock/vsock_assign_g2h_netns.c b/tools= /testing/selftests/vsock/vsock_assign_g2h_netns.c new file mode 100644 index 000000000000..6f15629af607 --- /dev/null +++ b/tools/testing/selftests/vsock/vsock_assign_g2h_netns.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Assign the guest->host vsock transport, i.e. the guest's virtio-vsock + * device, to the network namespace of the invoking process. + * + * Exits with the ioctl's errno, so that callers can tell why it was refus= ed. + * + * Copyright (c) 2026 Meta Platforms, Inc. and affiliates + */ + +#include +#include +#include +#include +#include +#include + +#include + +#ifndef IOCTL_VM_SOCKETS_ASSIGN_G2H_NETNS +#define IOCTL_VM_SOCKETS_ASSIGN_G2H_NETNS _IO(7, 0xba) +#endif + +int main(void) +{ + int fd, ret; + + fd =3D open("/dev/vsock", O_RDONLY); + if (fd < 0) { + fprintf(stderr, "open /dev/vsock: %s\n", strerror(errno)); + return -1; + } + + ret =3D ioctl(fd, IOCTL_VM_SOCKETS_ASSIGN_G2H_NETNS); + if (ret < 0) { + ret =3D errno; + fprintf(stderr, + "IOCTL_VM_SOCKETS_ASSIGN_G2H_NETNS: %s (errno %d)\n", + strerror(errno), errno); + } + + close(fd); + + return ret; +} --=20 2.53.0-Meta From nobody Sat Sep 26 09:21:25 2026 Received: from mail-ot1-f54.google.com (mail-ot1-f54.google.com [209.85.210.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5A67045DF70 for ; Wed, 2 Sep 2026 23:01:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788390100; cv=none; b=qY/FJYRWRl+D2XqTEjFafU+hCh5mIupaiSWrDO4n03XahkUpULoc7DFg3QUlQaKt6ILzQS9Ju3P1AJhpj6R3fR6hUhb1W3WSHP5zQrRffGMBgILT7ymAOD7bsLwVLuVpKKJgr2h3+Ecs8nxWJBzdexJRswDz0uYArDff8XpQ+oo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788390100; c=relaxed/simple; bh=RhRgkBeiEM5o/v9NM7SkiXJQPTZzpf6pbVeIeWURYxM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=cHTbhXSF57LjSYHMd9GSCSSs6BeCFR8UY9AQvlYajOMkNbt338OOqWKiePLBBKkwOpranzeIfq26rPJ7WF3XkPjBH+fimCAFNbNvmkMt9ZlwCRIoI8OAwtqJ49pVK2FVPOtYrQDI3bQNQMd3Vgzgn0OyagrD/s7VmWJaehJJd8s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=n/MmwmGS; arc=none smtp.client-ip=209.85.210.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="n/MmwmGS" Received: by mail-ot1-f54.google.com with SMTP id 46e09a7af769-7f6617c7536so816368a34.1 for ; Wed, 02 Sep 2026 16:01:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788390087; x=1788994887; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=fOl+dZ+q7hvvo0J5mVJmcvzg0LjyI9SaWnMmTPJSwo4=; b=n/MmwmGSJKa0/eLNMSW8+P9xuYcXVC1vu/me2G4ZWJLsJP2qktKjEMCJf3RlywS8me FmNMsquODb/to33CpvfM9J/KOx4jQWs0Mp3fiAaDaOcUPyjwUv61RPJLnoWPv3WfKPkz 9BgKbrJz0ETAMNtBk/6LJWDhpMYDv/VV88L2LpldX0lPcE2DJEEK57t7nk6qyZ7/vW0o wDdhDl4cyBA/Aa+vB6wgQXExDBLWYeNX4akuIGs9sCp4dqWzbKjcNgP6+qpLUrm7SRqu inl+xC/ekuC4kB2iCAnpIIu8He4hksR8/v5HS3TZ7fl65DEALZvCWxccvAufjsQKhzg/ f07w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788390087; x=1788994887; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=fOl+dZ+q7hvvo0J5mVJmcvzg0LjyI9SaWnMmTPJSwo4=; b=M1XHh+Vn3eSPl+8s0j0vPTSHHQ2agNqDUXVdc4jfVLhvHYOq0rf+FoQQMvRA8KlKfz K1y0EbzpMkXv8+na1waxduuXOIvJjGAioWDpy+FZ3DPVaSiwVw17H1tRXfyns0KNOv0f 9gkWiQfISPR+LTb5YziBzA1NUHxk3i+a0jSJ3GUmM2iGB2YrnZwpeBTybknYbU3jVyow RPd9NccylXb0nuyF4q189YKFmInodrueL04AtOj8wH0wvv9oR9+qycy4uoCVtWj7Okd/ tXLskBCr4ID6Gi92YWbi4LIoAUNhZB1pIoQ4TzQYPEnZPFbjDMz/luDq++jH8UxpbZgb PRpA== X-Forwarded-Encrypted: i=1; AKwUvBwodIeJOwOG0IwJjVKUoZ1HeLxyloPpEEo44QZhaqMUbIfddrhPRK1E3DvPdOx4i8LN0FLH30icL6N9s/U=@vger.kernel.org X-Gm-Message-State: AFuF++mTzLm6Hk/B1zSUojzrgUjyImmmwq9c4vwcJcyBnGjF/+HAmeJk 5pS0hPuTZ5NmVC+FHYjv0NYh6Suind/qKmWLtSQXHo1z2OC+h8u5muxa X-Gm-Gg: AYBFou08oEX/tIKNu1M4Scs0KyFWvXQoXIrdI7VvSKvdOAAlzmwFV9ZbH8W8+XLkjfz gRinmTT7hIeGh1btLuaabO7CRYt2vPFhkygyEP3Qyi3iL2KVM7RpuAjN6HrJ/twcyyw7OXVik/c p+9awiQxNY7tyAsZ9yBNA31zI4L/TOgCZ3L2YDn0/zjMGTy+gTDp7Ukru+S+mK2qrk1c14ddCEH fsAvMKdyAZZxmZxowcgWHZ/P7gGj0zll4Y/b/WwhbkHXfVOXlSfjqmBDhWUIyOer2e0535Q0Z+Q STQo3drmBNHhI2YA3QB5RuZSZMOs5CORThgdsoR86Q5jexaeEUwLrRf7OCqddU4bh/JKRl3Nh6+ dEJc734ODmLhzzsdncOzjVSYSL6mdQtMwAklSb8zicA0VVICp/MsX90XM9XPnETAKovOw8rZADL 5/pPsblhfXq/7P3uKp0bnyfkkgECCxT/Qf/s9ziznza6crx+i+eB4CQqXx0kSdlvG54uI= X-Received: by 2002:a05:6830:828e:b0:7f3:fb71:a4cc with SMTP id 46e09a7af769-7f7819a0e9emr7714131a34.14.1788390087207; Wed, 02 Sep 2026 16:01:27 -0700 (PDT) Received: from localhost ([2a03:2880:ff:53::]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f74f8f7fbcsm3519995a34.23.2026.09.02.16.01.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 02 Sep 2026 16:01:25 -0700 (PDT) From: Bobby Eshleman Date: Wed, 02 Sep 2026 16:00:51 -0700 Subject: [PATCH net-next 5/6] selftests/vsock: test the guest vsock device network namespace Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260902-vsock-guest-ns-v1-5-9995383e9a8b@meta.com> References: <20260902-vsock-guest-ns-v1-0-9995383e9a8b@meta.com> In-Reply-To: <20260902-vsock-guest-ns-v1-0-9995383e9a8b@meta.com> To: Stefano Garzarella , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan , Stefan Hajnoczi , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , =?utf-8?q?Eugenio_P=C3=A9rez?= , Shuah Khan , Randy Dunlap Cc: virtualization@lists.linux.dev, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org, sargun@sargun.me, jlinbox@meta.com, Bobby Eshleman X-Mailer: b4 0.14.3 From: Bobby Eshleman Add six tests covering basic cases and hopefully most edge cases: normal transfer in both directions, namespaces being deleted, device movement between namespaces mid-socket-lifetime. The namespaces are created with "unshare -n" and held open by a sleeping process rather than by ip netns because bind-mounting namespaces via ip netns is incompatible with the guest 9p rootfs. Signed-off-by: Bobby Eshleman Suggested-by: Stefano Garzarella --- tools/testing/selftests/vsock/vmtest.sh | 404 ++++++++++++++++++++++++++++= +++- 1 file changed, 394 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/vsock/vmtest.sh b/tools/testing/selfte= sts/vsock/vmtest.sh index 310dfc2a39ad..53591fa07f1a 100755 --- a/tools/testing/selftests/vsock/vmtest.sh +++ b/tools/testing/selftests/vsock/vmtest.sh @@ -17,6 +17,7 @@ readonly KERNEL_CHECKOUT=3D$(realpath "${SCRIPT_DIR}"/../= ../../../) source "${SCRIPT_DIR}"/../kselftest/ktap_helpers.sh =20 readonly VSOCK_TEST=3D"${SCRIPT_DIR}"/vsock_test +readonly VSOCK_ASSIGN_G2H_NETNS=3D"${SCRIPT_DIR}"/vsock_assign_g2h_netns readonly TEST_GUEST_PORT=3D51000 readonly TEST_HOST_PORT=3D50000 readonly TEST_HOST_PORT_LISTENER=3D50001 @@ -73,6 +74,12 @@ readonly TEST_NAMES=3D( ns_delete_vm_ok ns_delete_host_ok ns_delete_both_ok + ns_guest_local_connect_to_host_fails + ns_guest_assign_g2h_netns_connect_to_host_ok + ns_guest_assign_g2h_netns_init_ns_connect_fails + ns_guest_assign_g2h_netns_host_connect_ok + ns_guest_assign_g2h_netns_reset_on_ns_delete_ok + ns_guest_assign_g2h_netns_old_conn_send_fails ) readonly TEST_DESCS=3D( # vm_server_host_client @@ -149,12 +156,36 @@ readonly TEST_DESCS=3D( =20 # ns_delete_both_ok "Check that deleting the VM and host's namespaces does not break the sock= et connection" + + # ns_guest_local_connect_to_host_fails + "Check a guest process in a local ns cannot reach the host without the as= sign ioctl." + + # ns_guest_assign_g2h_netns_connect_to_host_ok + "Check a guest process in a local ns reaches the host once the vsock devi= ce is assigned to it." + + # ns_guest_assign_g2h_netns_init_ns_connect_fails + "Check the guest's initial ns loses vsock once the device is assigned to = another ns." + + # ns_guest_assign_g2h_netns_host_connect_ok + "Check the host reaches a guest listener in the ns the vsock device is as= signed to." + + # ns_guest_assign_g2h_netns_reset_on_ns_delete_ok + "Check the guest's vsock device returns to the initial ns when its ns is = deleted." + + # ns_guest_assign_g2h_netns_old_conn_send_fails + "Check connections made before the assign stop sending once they lose the= device." ) =20 readonly USE_SHARED_VM=3D( vm_server_host_client vm_client_host_server vm_loopback + ns_guest_local_connect_to_host_fails + ns_guest_assign_g2h_netns_connect_to_host_ok + ns_guest_assign_g2h_netns_init_ns_connect_fails + ns_guest_assign_g2h_netns_host_connect_ok + ns_guest_assign_g2h_netns_reset_on_ns_delete_ok + ns_guest_assign_g2h_netns_old_conn_send_fails ) readonly NS_MODES=3D("local" "global") =20 @@ -302,18 +333,20 @@ check_args() { } =20 check_deps() { - for dep in vng ${QEMU} busybox pkill ssh ss socat nsenter; do + for dep in vng ${QEMU} busybox pkill ssh ss socat nsenter unshare; do if [[ ! -x $(command -v "${dep}") ]]; then echo -e "skip: dependency ${dep} not found!\n" exit "${KSFT_SKIP}" fi done =20 - if [[ ! -x $(command -v "${VSOCK_TEST}") ]]; then - printf "skip: %s not found!" "${VSOCK_TEST}" - printf " Please build the kselftest vsock target.\n" - exit "${KSFT_SKIP}" - fi + for prog in "${VSOCK_TEST}" "${VSOCK_ASSIGN_G2H_NETNS}"; do + if [[ ! -x $(command -v "${prog}") ]]; then + printf "skip: %s not found!" "${prog}" + printf " Please build the kselftest vsock target.\n" + exit "${KSFT_SKIP}" + fi + done } =20 check_netns() { @@ -401,6 +434,7 @@ setup_home() { mkdir -p "$(dirname "${SSH_KEY_PATH}")" ssh-keygen -t ed25519 -f "${SSH_KEY_PATH}" -N "" -q cp "${VSOCK_TEST}" "${TEST_HOME}"/vsock_test + cp "${VSOCK_ASSIGN_G2H_NETNS}" "${TEST_HOME}"/vsock_assign_g2h_netns } =20 create_pidfile() { @@ -528,6 +562,58 @@ vm_wait_for_ssh() { done } =20 +# Create a local mode namespace in the VM and echo the pid holding it open. +vm_ns_start() { + local ns=3D$1 + + vm_ssh "${ns}" -- \ + "echo local > /proc/sys/net/vsock/child_ns_mode" &>/dev/null + + vm_ssh "${ns}" -- "unshare -n sleep infinity" \ + '>/dev/null 2>&1 & echo $!' +} + +# Returns once the holder is gone, so that the namespace is unreferenced a= nd +# the kernel can start tearing it down. +vm_ns_stop() { + local ns=3D$1 + local nspid=3D$2 + + vm_ssh "${ns}" <<-EOF &>/dev/null + kill ${nspid} + for ((i =3D 0; i < ${WAIT_PERIOD_MAX}; i++)); do + kill -0 ${nspid} 2>/dev/null || break + sleep 1 + done + EOF +} + +# Runs in the guest's initial namespace when is empty. The command= must +# not contain single quotes. +vm_ns_exec() { + local ns=3D$1 + local nspid=3D$2 + local cmd=3D$3 + + if [[ -z "${nspid}" ]]; then + vm_ssh "${ns}" -- "${cmd}" + return + fi + + vm_ssh "${ns}" -- nsenter -t "${nspid}" -n sh -c "'${cmd}'" +} + +vm_ns_assign_g2h() { + local ns=3D$1 + local nspid=3D$2 + + vm_ns_exec "${ns}" "${nspid}" ./vsock_assign_g2h_netns +} + +vm_reset_g2h() { + vm_ns_assign_g2h "init_ns" "" &>/dev/null +} + # derived from selftests/net/net_helper.sh wait_for_listener() { @@ -564,17 +650,31 @@ wait_for_listener() done } =20 -vm_wait_for_listener() { +# Runs in the guest's initial namespace when is empty. +vm_ns_wait_for_listener() { local ns=3D$1 - local port=3D$2 - local protocol=3D$3 + local nspid=3D$2 + local port=3D$3 + local protocol=3D$4 + local nsenter=3D + + [[ -n "${nspid}" ]] && nsenter=3D"nsenter -t ${nspid} -n" =20 vm_ssh "${ns}" <. +guest_send_to_host() { + local ns=3D$1 + local nspid=3D$2 + local port=3D$3 + local outfile=3D$4 + local cmd=3D"echo TEST | socat -u STDIN VSOCK-CONNECT:2:${port}" + local pid + + socat -u VSOCK-LISTEN:"${port}" STDOUT > "${outfile}" 2>/dev/null & + pid=3D$! + host_wait_for_listener "${ns}" "${port}" "vsock" + + vm_ns_exec "${ns}" "${nspid}" "${cmd}" 2>/dev/null + + timeout "${WAIT_PERIOD}" \ + bash -c 'while [[ ! -s '"${outfile}"' ]]; do sleep 1; done' + + terminate_pids "${pid}" +} + +# Send a string from the host to a listener in the guest and leave what the +# guest received in . +host_send_to_guest() { + local ns=3D$1 + local nspid=3D$2 + local port=3D$3 + local outfile=3D$4 + local cmd=3D"socat -u VSOCK-LISTEN:${port} STDOUT" + local dst=3D"VSOCK-CONNECT:${VSOCK_CID}:${port}" + local pid + + vm_ns_exec "${ns}" "${nspid}" "${cmd}" > "${outfile}" 2>/dev/null & + pid=3D$! + vm_ns_wait_for_listener "${ns}" "${nspid}" "${port}" "vsock" + + echo TEST | socat -u STDIN "${dst}" 2>/dev/null + + timeout "${WAIT_PERIOD}" \ + bash -c 'while [[ ! -s '"${outfile}"' ]]; do sleep 1; done' + + terminate_pids "${pid}" +} + +test_ns_guest_assign_g2h_netns_old_conn_send_fails() { + local gap=3D$(( WAIT_PERIOD * 3 )) + local port=3D12346 + local outfile + local result + local nspid + local pid + + nspid=3D$(vm_ns_start "init_ns") + if [[ -z "${nspid}" ]]; then + log_host "failed to create a namespace inside the guest" + return "${KSFT_FAIL}" + fi + + outfile=3D$(mktemp) + socat -u VSOCK-LISTEN:"${port}" STDOUT > "${outfile}" 2>/dev/null & + pid=3D$! + host_wait_for_listener "init_ns" "${port}" "vsock" + + # Send a message, wait, then send another. While waiting, assign the + # device to a namespace. Confirm the second message does not arrive. + vm_ssh "init_ns" -- \ + "(echo FIRST; sleep ${gap}; echo SECOND) |" \ + "socat -u STDIN VSOCK-CONNECT:2:${port}" &>/dev/null & + + sleep "${WAIT_PERIOD}" + + if ! vm_ns_assign_g2h "init_ns" "${nspid}"; then + log_host "failed to assign the vsock device to the guest ns" + terminate_pids "${pid}" + rm -f "${outfile}" + vm_ns_stop "init_ns" "${nspid}" + vm_reset_g2h + return "${KSFT_FAIL}" + fi + + # Let the second write happen and land, if it is going to. + sleep $(( gap + WAIT_PERIOD )) + + terminate_pids "${pid}" + result=3D$(cat "${outfile}") + rm -f "${outfile}" + + vm_ns_stop "init_ns" "${nspid}" + vm_reset_g2h + + if [[ "${result}" !=3D *FIRST* ]]; then + log_host "connection did not work before the assign: [${result}]" + return "${KSFT_FAIL}" + fi + + if [[ "${result}" =3D=3D *SECOND* ]]; then + log_host "old connection still delivered after the assign" + return "${KSFT_FAIL}" + fi + + return "${KSFT_PASS}" +} + +test_ns_guest_local_connect_to_host_fails() { + local port=3D12345 + local outfile + local result + local nspid + + nspid=3D$(vm_ns_start "init_ns") + if [[ -z "${nspid}" ]]; then + log_host "failed to create a namespace inside the guest" + return "${KSFT_FAIL}" + fi + + outfile=3D$(mktemp) + guest_send_to_host "init_ns" "${nspid}" "${port}" "${outfile}" + + vm_ns_stop "init_ns" "${nspid}" + vm_reset_g2h + + result=3D$(cat "${outfile}") + rm -f "${outfile}" + + if [[ "${result}" =3D=3D TEST ]]; then + return "${KSFT_FAIL}" + fi + + return "${KSFT_PASS}" +} + +test_ns_guest_assign_g2h_netns_connect_to_host_ok() { + local port=3D12345 + local outfile + local result + local nspid + + nspid=3D$(vm_ns_start "init_ns") + if [[ -z "${nspid}" ]]; then + log_host "failed to create a namespace inside the guest" + return "${KSFT_FAIL}" + fi + + if ! vm_ns_assign_g2h "init_ns" "${nspid}"; then + log_host "failed to assign the vsock device to the guest ns" + vm_ns_stop "init_ns" "${nspid}" + vm_reset_g2h + return "${KSFT_FAIL}" + fi + + outfile=3D$(mktemp) + guest_send_to_host "init_ns" "${nspid}" "${port}" "${outfile}" + + vm_ns_stop "init_ns" "${nspid}" + vm_reset_g2h + + result=3D$(cat "${outfile}") + rm -f "${outfile}" + + if [[ "${result}" !=3D TEST ]]; then + return "${KSFT_FAIL}" + fi + + return "${KSFT_PASS}" +} + +test_ns_guest_assign_g2h_netns_init_ns_connect_fails() { + local port=3D12345 + local outfile + local result + local nspid + + nspid=3D$(vm_ns_start "init_ns") + if [[ -z "${nspid}" ]]; then + log_host "failed to create a namespace inside the guest" + return "${KSFT_FAIL}" + fi + + if ! vm_ns_assign_g2h "init_ns" "${nspid}"; then + log_host "failed to assign the vsock device to the guest ns" + vm_ns_stop "init_ns" "${nspid}" + vm_reset_g2h + return "${KSFT_FAIL}" + fi + + # The device now belongs to a local-mode namespace, so the guest's + # initial namespace must no longer reach the host. + outfile=3D$(mktemp) + guest_send_to_host "init_ns" "" "${port}" "${outfile}" + + vm_ns_stop "init_ns" "${nspid}" + vm_reset_g2h + + result=3D$(cat "${outfile}") + rm -f "${outfile}" + + if [[ "${result}" =3D=3D TEST ]]; then + return "${KSFT_FAIL}" + fi + + return "${KSFT_PASS}" +} + +test_ns_guest_assign_g2h_netns_host_connect_ok() { + local port=3D12345 + local outfile + local result + local nspid + + nspid=3D$(vm_ns_start "init_ns") + if [[ -z "${nspid}" ]]; then + log_host "failed to create a namespace inside the guest" + return "${KSFT_FAIL}" + fi + + if ! vm_ns_assign_g2h "init_ns" "${nspid}"; then + log_host "failed to assign the vsock device to the guest ns" + vm_ns_stop "init_ns" "${nspid}" + vm_reset_g2h + return "${KSFT_FAIL}" + fi + + outfile=3D$(mktemp) + host_send_to_guest "init_ns" "${nspid}" "${port}" "${outfile}" + + vm_ns_stop "init_ns" "${nspid}" + vm_reset_g2h + + result=3D$(cat "${outfile}") + rm -f "${outfile}" + + if [[ "${result}" !=3D TEST ]]; then + return "${KSFT_FAIL}" + fi + + return "${KSFT_PASS}" +} + +test_ns_guest_assign_g2h_netns_reset_on_ns_delete_ok() { + local port=3D12345 + local outfile + local result + local nspid + local i + + nspid=3D$(vm_ns_start "init_ns") + if [[ -z "${nspid}" ]]; then + log_host "failed to create a namespace inside the guest" + return "${KSFT_FAIL}" + fi + + if ! vm_ns_assign_g2h "init_ns" "${nspid}"; then + log_host "failed to assign the vsock device to the guest ns" + vm_ns_stop "init_ns" "${nspid}" + vm_reset_g2h + return "${KSFT_FAIL}" + fi + + vm_ns_stop "init_ns" "${nspid}" + + # The holder is gone, but the namespace itself is dismantled from a + # workqueue, so the device does not come back the same instant. Retry + # until it does, rather than expecting the first send to succeed. + outfile=3D$(mktemp) + for ((i =3D 0; i < 5; i++)); do + sleep "${WAIT_PERIOD}" + guest_send_to_host "init_ns" "" "$(( port + i ))" "${outfile}" + result=3D$(cat "${outfile}") + if [[ "${result}" =3D=3D TEST ]]; then + break + fi + done + + rm -f "${outfile}" + vm_reset_g2h + + if [[ "${result}" !=3D TEST ]]; then + return "${KSFT_FAIL}" + fi + + return "${KSFT_PASS}" +} + shared_vm_test() { local tname =20 --=20 2.53.0-Meta From nobody Sat Sep 26 09:21:25 2026 Received: from mail-oi1-f176.google.com (mail-oi1-f176.google.com [209.85.167.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0EF3A3F0A90 for ; Wed, 2 Sep 2026 23:01:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788390104; cv=none; b=QREJ0c51X5YCm+/hDVzLqoFVLUVLq7cqvv1V3CxueiNy6HESNvXTTfzfk1uxYcqU8c7vskzFRMJS/biGRDSx/Z/NjmmTEovwBrYJyvosrc91eHC/qWWxFzIUpi+lDMNRYO3SjBPzlyv2qO5T0OngpCz97Zz8jam1EshZlxCfL6E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788390104; c=relaxed/simple; bh=kcIMEAxlbhdfWGQi3kEqTjk3KEi3PkKRsRCd1DxpZ8k=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=cD/bXDqNUfGS71hPtx6I02/tso4yNSOyVIh9Qnnl/QCUrgu73a9Vc9ar5nHHsX0qbqwrtqkNRC2wp6b+xFa+THQpCgAHpIkEP2iBfex2Bz+8ImqWDQ1KdhkrPIspv/bkmQYB/kaQooV2AVtlXNNymZQnYhFHagHSS2CO4WRrhes= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=jtEMLlZq; arc=none smtp.client-ip=209.85.167.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="jtEMLlZq" Received: by mail-oi1-f176.google.com with SMTP id 5614622812f47-4af7283bf83so692894b6e.3 for ; Wed, 02 Sep 2026 16:01:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788390091; x=1788994891; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=7bD7DqrZxcDKFi14tO3Iywp9XBJtjTzYJFW9TgEI/w0=; b=jtEMLlZqbh5XoxZ+hKv7J7qrNerk3mPJJlwU0e3x9mRqLH8KV0Zl0oTzAcSGcH6BXy XARuMM9w8trkSpV0z0WKyOHwnWbSu8Li9tLpUo82HMxwARMHtLFYCAu3dAZf2Ve+uf3Z 46cR78RWPllWXa3TYSJY2SFo9eO+IJ09FBGzSYCYjf4nJ/aWPSD8OCnwxV4vUHLStcrl l5l4xIWNdwqPtK13gAKo11uqCj324hT3oX0hF/C4wvgVDquZ5U+OuLEsq6CozKso3Y5D FIpAGpf9xhDkwPH60evF7VIrbLaR0HDxJAbhup3iYaS2kFdR+uxjvaVXr/0asVKL/ifm J3ew== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788390091; x=1788994891; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=7bD7DqrZxcDKFi14tO3Iywp9XBJtjTzYJFW9TgEI/w0=; b=rQUysGTFLIc6EY2Lq4qC+LyFuP24qXKtsZQqKMPFBnPQuKAGcPg1egFRC4rkh6usdY STFmr7bm0VHtBh1fnn6fYG0p0KCRDSaFwBYGkstNNiKG/V3Dr3mrL9hXZn92VabVKKHF NiV0xh74eXB7yJhLwaOpH7EN+HqO6qGoCcwftBqdRlVswvpBJwBi/OxLDvNZGKRj28yZ RzTU7tQNAKrZjII4nychok2oPy+B03HCfODhPpOwBKIgeZOJ/JNGfaBNFwg2uAdAOB8E 8UPEyheFhAAZGDBNQEU3VSvhpCqH05uUsfpLxXXT3cMzd3qYeOzHdm900PqxUYudoCYN YDcQ== X-Forwarded-Encrypted: i=1; AKwUvBwdcroMzOynq00BYNfRaSO9jZ/XnGeZrCVcFpi/+MiZyHWsap+oSKDN3o+tL9h3oPoyrybxpPwRjSUr7mQ=@vger.kernel.org X-Gm-Message-State: AFuF++mAPeKlF8Hq5R0kNPRoFtk+YnW1WDlRHKxE0wZvBbz0h/q1/TM6 VfNHNA7oFGmbwIrOK8sQQTeyPo3myYOfmjhSC+NzkwDRi5OvgvZHgqMq X-Gm-Gg: AYBFou3x+yHStkqe0vrrj9dhUAyd2Ve997CaD1vYn+2xtlB5Iy0tli/cSgi/ptM90RQ cDIgzPNLJvHOflXr7NnoVa2MHg0v7EKOeVIbv5rTkORdkRaswFDf7tAzg4yL9N+7EUCUcWYKMQl hlBbJBfNWuQlRKWWgn9YYkH1XO9cj58RRXgxjOEDMcvjk9S2Mi0HmkLpxgfso4Yu6Lq7vXdYdi2 IHsYoBTV/GX6LkE7uRVAfcp/hfv5p/kLhNfN6Gti8tCkkfg02L1naaKtWu8LeVzdxgNFvaf4GnK 7UoPw4lra6U9zwkrVFcwx/6EfmH7Ixa/gM2edcWQnyz3FdmkQ/mEjVkVIkDZM8V+ET8CZfwtoXf iQLDho3pP3VeXIqInUZxQSqYyCaG7ot8NFbgMcfWrJvUN2e5GUbCeL6y37KXpDbcz5S9zan3yaX wS1SQUPsE25AVabwt6Ih97T+2jsCAhpUWbOXZxx/LGB9FSZsR4M1rOVO/T X-Received: by 2002:a05:6808:c1e8:b0:493:a860:5809 with SMTP id 5614622812f47-4b6bc459a08mr7099648b6e.4.1788390090927; Wed, 02 Sep 2026 16:01:30 -0700 (PDT) Received: from localhost ([2a03:2880:ff:12::]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4b69b820671sm3086593b6e.15.2026.09.02.16.01.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 02 Sep 2026 16:01:29 -0700 (PDT) From: Bobby Eshleman Date: Wed, 02 Sep 2026 16:00:52 -0700 Subject: [PATCH net-next 6/6] selftests/vsock: test the assign ioctl privilege checks Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260902-vsock-guest-ns-v1-6-9995383e9a8b@meta.com> References: <20260902-vsock-guest-ns-v1-0-9995383e9a8b@meta.com> In-Reply-To: <20260902-vsock-guest-ns-v1-0-9995383e9a8b@meta.com> To: Stefano Garzarella , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan , Stefan Hajnoczi , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , =?utf-8?q?Eugenio_P=C3=A9rez?= , Shuah Khan , Randy Dunlap Cc: virtualization@lists.linux.dev, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org, sargun@sargun.me, jlinbox@meta.com, Bobby Eshleman X-Mailer: b4 0.14.3 From: Bobby Eshleman /dev/vsock IOCTL_VM_SOCKETS_ASSIGN_G2H_NETNS has refuses callers without CAP_NET_ADMIN in the init user namespace. Add two tests: one confirms that CAP_NET_ADMIN is required even by a privileged user and the other confirms that CAP_NET_ADMIN in an unprivileged user ns alone is insufficient. CONFIG_USER_NS is needed to test the CAP_NET_ADMIN + unprivileged user ns case. Signed-off-by: Bobby Eshleman Suggested-by: Stefano Garzarella --- tools/testing/selftests/vsock/config | 1 + tools/testing/selftests/vsock/vmtest.sh | 59 +++++++++++++++++++++++++++++= +++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/vsock/config b/tools/testing/selftests= /vsock/config index 5f0a4f17dfc9..4b31085558fa 100644 --- a/tools/testing/selftests/vsock/config +++ b/tools/testing/selftests/vsock/config @@ -109,3 +109,4 @@ CONFIG_FS_DAX=3Dy CONFIG_MEMORY_HOTPLUG=3Dy CONFIG_MEMORY_HOTREMOVE=3Dy CONFIG_ZONE_DEVICE=3Dy +CONFIG_USER_NS=3Dy diff --git a/tools/testing/selftests/vsock/vmtest.sh b/tools/testing/selfte= sts/vsock/vmtest.sh index 53591fa07f1a..efb94d17d997 100755 --- a/tools/testing/selftests/vsock/vmtest.sh +++ b/tools/testing/selftests/vsock/vmtest.sh @@ -28,6 +28,7 @@ readonly WAIT_PERIOD=3D3 readonly WAIT_PERIOD_MAX=3D60 readonly WAIT_QEMU=3D5 readonly PIDFILE_TEMPLATE=3D/tmp/vsock_vmtest_XXXX.pid +readonly EPERM=3D1 declare -A PIDFILES =20 # virtme-ng offers a netdev for ssh when using "--ssh", but we also need a @@ -80,6 +81,8 @@ readonly TEST_NAMES=3D( ns_guest_assign_g2h_netns_host_connect_ok ns_guest_assign_g2h_netns_reset_on_ns_delete_ok ns_guest_assign_g2h_netns_old_conn_send_fails + ns_guest_assign_g2h_netns_no_cap_net_admin_fails + ns_guest_assign_g2h_netns_unpriv_user_ns_fails ) readonly TEST_DESCS=3D( # vm_server_host_client @@ -174,6 +177,12 @@ readonly TEST_DESCS=3D( =20 # ns_guest_assign_g2h_netns_old_conn_send_fails "Check connections made before the assign stop sending once they lose the= device." + + # ns_guest_assign_g2h_netns_no_cap_net_admin_fails + "Check assigning the guest's vsock device to a namespace needs CAP_NET_AD= MIN." + + # ns_guest_assign_g2h_netns_unpriv_user_ns_fails + "Check an unprivileged user cannot claim the guest's vsock device via a u= ser ns." ) =20 readonly USE_SHARED_VM=3D( @@ -186,6 +195,8 @@ readonly USE_SHARED_VM=3D( ns_guest_assign_g2h_netns_host_connect_ok ns_guest_assign_g2h_netns_reset_on_ns_delete_ok ns_guest_assign_g2h_netns_old_conn_send_fails + ns_guest_assign_g2h_netns_no_cap_net_admin_fails + ns_guest_assign_g2h_netns_unpriv_user_ns_fails ) readonly NS_MODES=3D("local" "global") =20 @@ -333,7 +344,8 @@ check_args() { } =20 check_deps() { - for dep in vng ${QEMU} busybox pkill ssh ss socat nsenter unshare; do + for dep in vng ${QEMU} busybox pkill ssh ss socat nsenter unshare \ + setpriv; do if [[ ! -x $(command -v "${dep}") ]]; then echo -e "skip: dependency ${dep} not found!\n" exit "${KSFT_SKIP}" @@ -1805,6 +1817,51 @@ test_ns_guest_assign_g2h_netns_reset_on_ns_delete_ok= () { return "${KSFT_PASS}" } =20 +test_ns_guest_assign_g2h_netns_no_cap_net_admin_fails() { + local cmd=3D"unshare -n setpriv --bounding-set=3D-net_admin" + local rc + + vm_ssh "init_ns" -- "${cmd}" ./vsock_assign_g2h_netns &>/dev/null + rc=3D$? + + if [[ "${rc}" -ne "${EPERM}" ]]; then + log_host "expected EPERM (${EPERM}) without CAP_NET_ADMIN, got ${rc}" + return "${KSFT_FAIL}" + fi + + return "${KSFT_PASS}" +} + +test_ns_guest_assign_g2h_netns_unpriv_user_ns_fails() { + local helper=3D/tmp/vsock_assign_g2h_netns + local unpriv_uid=3D65534 + local unpriv + local rc + + unpriv=3D"setpriv --reuid=3D${unpriv_uid} --regid=3D${unpriv_uid}" + unpriv=3D"${unpriv} --clear-groups" + + if ! vm_ssh "init_ns" -- "${unpriv} unshare -U true"; then + log_host "unprivileged user namespaces unavailable, skipping" + return "${KSFT_SKIP}" + fi + + # The home shared with the guest is root-only, so place the helper where + # an unprivileged user can execute it. + vm_ssh "init_ns" -- \ + "cp ./vsock_assign_g2h_netns ${helper} && chmod 755 ${helper}" + + vm_ssh "init_ns" -- "${unpriv} unshare -Urn ${helper}" &>/dev/null + rc=3D$? + + if [[ "${rc}" -ne "${EPERM}" ]]; then + log_host "expected EPERM (${EPERM}) for an unprivileged user, got ${rc}" + return "${KSFT_FAIL}" + fi + + return "${KSFT_PASS}" +} + shared_vm_test() { local tname =20 --=20 2.53.0-Meta