From 8e471c6a9ffdbc1f7f9fc054ef911aeeccdc7241 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 5 Jan 2024 16:32:59 +0100 Subject: [PATCH] socket-util: add more careful parsers for AF_VSOCK cid/port Let's handle the magic CIDs, and filter out invalid ports. --- src/basic/socket-util.c | 50 ++++++++++++++++++++++++++++++++++++++--- src/basic/socket-util.h | 3 +++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 98133a2ecda..9c87fb4ce81 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -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, diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 032d73857ed..39a6677c12b 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -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. */ -- 2.47.3