]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
socket-util: add more careful parsers for AF_VSOCK cid/port 30794/head
authorLennart Poettering <lennart@poettering.net>
Fri, 5 Jan 2024 15:32:59 +0000 (16:32 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 5 Jan 2024 21:29:55 +0000 (22:29 +0100)
Let's handle the magic CIDs, and filter out invalid ports.

src/basic/socket-util.c
src/basic/socket-util.h

index 98133a2ecda7686e851dbeab76ced51bf75656e5..9c87fb4ce81f5e47404ee26440b64197bc4b9559 100644 (file)
@@ -1656,6 +1656,50 @@ int socket_address_parse_unix(SocketAddress *ret_address, const char *s) {
         return 0;
 }
 
+int vsock_parse_port(const char *s, unsigned *ret) {
+        int r;
+
+        assert(ret);
+
+        if (!s)
+                return -EINVAL;
+
+        unsigned u;
+        r = safe_atou(s, &u);
+        if (r < 0)
+                return r;
+
+        /* Port 0 is apparently valid and not special in AF_VSOCK (unlike on IP). But VMADDR_PORT_ANY
+         * (UINT32_MAX) is. Hence refuse that. */
+
+        if (u == VMADDR_PORT_ANY)
+                return -EINVAL;
+
+        *ret = u;
+        return 0;
+}
+
+int vsock_parse_cid(const char *s, unsigned *ret) {
+        assert(ret);
+
+        if (!s)
+                return -EINVAL;
+
+        /* Parsed an AF_VSOCK "CID". This is a 32bit entity, and the usual type is "unsigned". We recognize
+         * the three special CIDs as strings, and otherwise parse the numeric CIDs. */
+
+        if (streq(s, "hypervisor"))
+                *ret = VMADDR_CID_HYPERVISOR;
+        else if (streq(s, "local"))
+                *ret = VMADDR_CID_LOCAL;
+        else if (streq(s, "host"))
+                *ret = VMADDR_CID_HOST;
+        else
+                return safe_atou(s, ret);
+
+        return 0;
+}
+
 int socket_address_parse_vsock(SocketAddress *ret_address, const char *s) {
         /* AF_VSOCK socket in vsock:cid:port notation */
         _cleanup_free_ char *n = NULL;
@@ -1681,7 +1725,7 @@ int socket_address_parse_vsock(SocketAddress *ret_address, const char *s) {
         if (!e)
                 return -EINVAL;
 
-        r = safe_atou(e+1, &port);
+        r = vsock_parse_port(e+1, &port);
         if (r < 0)
                 return r;
 
@@ -1692,15 +1736,15 @@ int socket_address_parse_vsock(SocketAddress *ret_address, const char *s) {
         if (isempty(n))
                 cid = VMADDR_CID_ANY;
         else {
-                r = safe_atou(n, &cid);
+                r = vsock_parse_cid(n, &cid);
                 if (r < 0)
                         return r;
         }
 
         *ret_address = (SocketAddress) {
                 .sockaddr.vm = {
-                        .svm_cid = cid,
                         .svm_family = AF_VSOCK,
+                        .svm_cid = cid,
                         .svm_port = port,
                 },
                 .type = type,
index 032d73857ed7f43d790d3df9d070cac4148c7926..39a6677c12b4de89e477683a1e116c054601cf27 100644 (file)
@@ -374,6 +374,9 @@ int socket_get_mtu(int fd, int af, size_t *ret);
 
 int connect_unix_path(int fd, int dir_fd, const char *path);
 
+int vsock_parse_port(const char *s, unsigned *ret);
+int vsock_parse_cid(const char *s, unsigned *ret);
+
 /* Parses AF_UNIX and AF_VSOCK addresses. AF_INET[6] require some netlink calls, so it cannot be in
  * src/basic/ and is done from 'socket_local_address from src/shared/. Return -EPROTO in case of
  * protocol mismatch. */