]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
vsock-util: allow VMADDR_CID_ANY as local CID if enabled in hwdb main
authorChitoku <odango@chitoku.jp>
Wed, 10 Jun 2026 15:06:33 +0000 (00:06 +0900)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sat, 13 Jun 2026 13:54:50 +0000 (15:54 +0200)
On Hyper-V guests, `VMADDR_CID_ANY` is valid as per implementation in
kernel driver: net/vmw_vsock/hyperv_transport.c.

Fixes https://github.com/systemd/systemd/issues/42496

Follow-up for 83359c4da02a82d2972cf957d9855ea957359287

hwdb.d/70-vsock.hwdb [new file with mode: 0644]
hwdb.d/meson.build
hwdb.d/parse_hwdb.py
src/basic/socket-util.c
src/basic/socket-util.h
src/hostname/hostnamed.c
src/machine/machined.c
src/shared/meson.build
src/shared/vsock-util.c [new file with mode: 0644]
src/shared/vsock-util.h [new file with mode: 0644]
src/ssh-generator/ssh-util.c

diff --git a/hwdb.d/70-vsock.hwdb b/hwdb.d/70-vsock.hwdb
new file mode 100644 (file)
index 0000000..ca2b8e5
--- /dev/null
@@ -0,0 +1,10 @@
+# This file is part of systemd.
+#
+# Database for AF_VSOCK driver implementations.
+#
+# Permitted keys:
+#   Specify if the driver uses VMADDR_CID_ANY as the local CID.
+#   VSOCK_ACCEPT_VMADDR_CID_ANY=1|0
+
+dmi:bvnMicrosoftCorporation:*:pvrHyper-V*
+ VSOCK_ACCEPT_VMADDR_CID_ANY=1
index 3299eaf8a75bfc36b0bb300d7b027e677b46b2a9..2c0fc6839da1d36aa3d3c47fe0f4d6a9ef3b65e9 100644 (file)
@@ -41,6 +41,7 @@ hwdb_files_test = files(
         '70-software-radio.hwdb',
         '70-sound-card.hwdb',
         '70-touchpad.hwdb',
+        '70-vsock.hwdb',
         '80-ieee1394-unit-function.hwdb',
         '82-net-auto-link-local.hwdb')
 
index 5b9d528119f87d4d1c3fd051c66e12594013c906..fc4b93e510b56f563f65f1c28f0114b40543efe4 100755 (executable)
@@ -260,6 +260,7 @@ def property_grammar():
         ('IMDS_KEY_USERDATA', name_literal),
         ('IMDS_KEY_USERDATA_BASE', name_literal),
         ('IMDS_KEY_USERDATA_BASE64', name_literal),
+        ('VSOCK_ACCEPT_VMADDR_CID_ANY', zero_one),
     )
     fixed_props = [Literal(name)('NAME') - Suppress('=') - val('VALUE') for name, val in props]
     kbd_props = [
index c48ffbc3d0e59eff915951fccdcaeb233480c729..614f762b57df88d9124a453327343bc0a8789e80 100644 (file)
@@ -1798,30 +1798,6 @@ int socket_address_parse_vsock(SocketAddress *ret_address, const char *s) {
         return 0;
 }
 
-int vsock_get_local_cid(unsigned *ret) {
-        _cleanup_close_ int vsock_fd = -EBADF;
-
-        vsock_fd = open("/dev/vsock", O_RDONLY|O_CLOEXEC);
-        if (vsock_fd < 0)
-                return log_debug_errno(errno, "Failed to open %s: %m", "/dev/vsock");
-
-        unsigned tmp;
-        if (ioctl(vsock_fd, IOCTL_VM_SOCKETS_GET_LOCAL_CID, &tmp) < 0)
-                return log_debug_errno(errno, "Failed to query local AF_VSOCK CID: %m");
-        log_debug("Local AF_VSOCK CID: %u", tmp);
-
-        /* If ret == NULL, we're just want to check if AF_VSOCK is available, so accept
-         * any address. Otherwise, filter out special addresses that are cannot be used
-         * to identify _this_ machine from the outside. */
-        if (ret && IN_SET(tmp, VMADDR_CID_LOCAL, VMADDR_CID_HOST, VMADDR_CID_ANY))
-                return log_debug_errno(SYNTHETIC_ERRNO(EADDRNOTAVAIL),
-                                       "IOCTL_VM_SOCKETS_GET_LOCAL_CID returned special value (%u), ignoring.", tmp);
-
-        if (ret)
-                *ret = tmp;
-        return 0;
-}
-
 int netlink_socket_get_multicast_groups(int fd, size_t *ret_len, uint32_t **ret_groups) {
         _cleanup_free_ uint32_t *groups = NULL;
         socklen_t len = 0, old_len;
index 1703a518e48dee7fab6c57db8848eba83a83fa01..b3a2733b74a0ea2779cb5096b46f53074623c7be 100644 (file)
@@ -261,8 +261,6 @@ int socket_address_equal_unix(const char *a, const char *b);
  * authoritative. */
 #define SOMAXCONN_DELUXE INT_MAX
 
-int vsock_get_local_cid(unsigned *ret);
-
 int netlink_socket_get_multicast_groups(int fd, size_t *ret_len, uint32_t **ret_groups);
 
 int socket_get_cookie(int fd, uint64_t *ret);
index a39bf5a57eac53f99fb15f1d9c5f7624efea16a0..73c0f2e8efe97000434e20bf3bdc8ffc1a2c60e0 100644 (file)
@@ -38,7 +38,6 @@
 #include "parse-util.h"
 #include "path-util.h"
 #include "service-util.h"
-#include "socket-util.h"
 #include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
@@ -47,6 +46,7 @@
 #include "varlink-io.systemd.service.h"
 #include "varlink-util.h"
 #include "virt.h"
+#include "vsock-util.h"
 
 #define VALID_DEPLOYMENT_CHARS (ALPHANUMERICAL "-.:")
 
index c419571deed9ec274686b9378ae1423b2ba57ef7..954e26069214ed457291b34572cc715f25c539f7 100644 (file)
@@ -32,9 +32,9 @@
 #include "service-util.h"
 #include "set.h"
 #include "signal-util.h"
-#include "socket-util.h"
 #include "special.h"
 #include "string-util.h"
+#include "vsock-util.h"
 
 static Manager* manager_unref(Manager *m);
 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_unref);
index 82072b06b64db86671482f439a7be04d2d7e8f90..9359b4fee0e290f495afc6c8928c42ec8d6f4122 100644 (file)
@@ -261,6 +261,7 @@ shared_sources = files(
         'vlan-util.c',
         'volatile-util.c',
         'vpick.c',
+        'vsock-util.c',
         'wall.c',
         'watchdog.c',
         'web-util.c',
diff --git a/src/shared/vsock-util.c b/src/shared/vsock-util.c
new file mode 100644 (file)
index 0000000..1fd0590
--- /dev/null
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include "sd-hwdb.h"
+
+#include "fd-util.h"
+#include "fileio.h"
+#include "log.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "vsock-util.h"
+
+static int smbios_get_modalias(char **ret) {
+        int r;
+
+        assert(ret);
+
+        _cleanup_free_ char *modalias = NULL;
+        r = read_virtual_file("/sys/devices/virtual/dmi/id/modalias", SIZE_MAX, &modalias, /* ret_size= */ NULL);
+        if (r < 0)
+                return r;
+
+        truncate_nl(modalias);
+
+        *ret = TAKE_PTR(modalias);
+        return 0;
+}
+
+static int smbios_get_accepts_any(void) {
+        static int accepts_any = -1;
+        int r;
+
+        if (accepts_any >= 0)
+                return accepts_any;
+
+        _cleanup_free_ char *modalias = NULL;
+        r = smbios_get_modalias(&modalias);
+        if (r == -ENOENT)
+                return (accepts_any = false);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to read DMI modalias: %m");
+
+        _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
+        r = sd_hwdb_new(&hwdb);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to open hwdb: %m");
+
+        const char *value;
+        r = sd_hwdb_get(hwdb, modalias, "VSOCK_ACCEPT_VMADDR_CID_ANY", &value);
+        if (r < 0) {
+                if (r != -ENOENT)
+                        log_debug_errno(r, "Failed to get VSOCK_ACCEPT_VMADDR_CID_ANY, ignoring: %m");
+                return (accepts_any = false);
+        }
+        log_debug("VSOCK_ACCEPT_VMADDR_CID_ANY: %s", value);
+
+        r = parse_boolean(value);
+        if (r < 0) {
+                log_debug_errno(r, "Failed to parse VSOCK_ACCEPT_VMADDR_CID_ANY, ignoring: %m");
+                return (accepts_any = false);
+        }
+
+        return (accepts_any = r);
+}
+
+int vsock_get_local_cid(unsigned *ret) {
+        _cleanup_close_ int vsock_fd = -EBADF;
+
+        vsock_fd = open("/dev/vsock", O_RDONLY|O_CLOEXEC);
+        if (vsock_fd < 0)
+                return log_debug_errno(errno, "Failed to open %s: %m", "/dev/vsock");
+
+        unsigned tmp;
+        if (ioctl(vsock_fd, IOCTL_VM_SOCKETS_GET_LOCAL_CID, &tmp) < 0)
+                return log_debug_errno(errno, "Failed to query local AF_VSOCK CID: %m");
+        log_debug("Local AF_VSOCK CID: %u", tmp);
+
+        /* If ret == NULL, we just want to check if AF_VSOCK is available, so accept any
+         * address. Otherwise, filter out special addresses that cannot be used to identify
+         * _this_ machine from the outside. */
+        if (ret &&
+            (IN_SET(tmp, VMADDR_CID_LOCAL, VMADDR_CID_HOST) ||
+             (tmp == VMADDR_CID_ANY && smbios_get_accepts_any() <= 0)))
+                return log_debug_errno(SYNTHETIC_ERRNO(EADDRNOTAVAIL),
+                                       "IOCTL_VM_SOCKETS_GET_LOCAL_CID returned special value (%u), ignoring.", tmp);
+
+        if (ret)
+                *ret = tmp;
+        return 0;
+}
diff --git a/src/shared/vsock-util.h b/src/shared/vsock-util.h
new file mode 100644 (file)
index 0000000..7733296
--- /dev/null
@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <linux/vm_sockets.h> /* IWYU pragma: export */
+
+int vsock_get_local_cid(unsigned *ret);
index b7af0454870ede7326531b6f96e77af507a40665..a3863b2805eb11e38f6a1306aac6fd4f3e254ec8 100644 (file)
@@ -5,8 +5,8 @@
 
 #include "errno-util.h"
 #include "log.h"
-#include "socket-util.h"
 #include "ssh-util.h"
+#include "vsock-util.h"
 
 int vsock_open_or_warn(int *ret) {
         int fd = RET_NERRNO(socket(AF_VSOCK, SOCK_STREAM|SOCK_CLOEXEC, 0));