From 5a2f378362f2b16f8d837aec4c44532eed737a03 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 12 Mar 2024 01:47:17 +0900 Subject: [PATCH] sd-dhcp-server: refuse invalid hostname in request Currently, the received hostname is not used for assigning an address to the host, or options in the subsequent reply message. But, the parsed hostname is exposed through DBus, and possibly Varlink in the future. Let's ignore spurious hostname. --- src/libsystemd-network/dhcp-option.c | 31 +++++++++++++++++++++++++ src/libsystemd-network/dhcp-option.h | 1 + src/libsystemd-network/sd-dhcp-server.c | 14 ++++++----- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c index 4a6fa462f12..e4ba77ae296 100644 --- a/src/libsystemd-network/dhcp-option.c +++ b/src/libsystemd-network/dhcp-option.c @@ -10,6 +10,8 @@ #include "alloc-util.h" #include "dhcp-option.h" #include "dhcp-server-internal.h" +#include "dns-domain.h" +#include "hostname-util.h" #include "memory-util.h" #include "ordered-set.h" #include "strv.h" @@ -420,6 +422,35 @@ int dhcp_option_parse_string(const uint8_t *option, size_t len, char **ret) { return 0; } +int dhcp_option_parse_hostname(const uint8_t *option, size_t len, char **ret) { + _cleanup_free_ char *hostname = NULL; + int r; + + assert(option); + assert(ret); + + r = dhcp_option_parse_string(option, len, &hostname); + if (r < 0) + return r; + + if (!hostname) { + *ret = NULL; + return 0; + } + + if (!hostname_is_valid(hostname, 0)) + return -EINVAL; + + r = dns_name_is_valid(hostname); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; + + *ret = TAKE_PTR(hostname); + return 0; +} + static sd_dhcp_option* dhcp_option_free(sd_dhcp_option *i) { if (!i) return NULL; diff --git a/src/libsystemd-network/dhcp-option.h b/src/libsystemd-network/dhcp-option.h index 425f5b50162..aaa8f847b1a 100644 --- a/src/libsystemd-network/dhcp-option.h +++ b/src/libsystemd-network/dhcp-option.h @@ -44,3 +44,4 @@ int dhcp_option_parse( char **ret_error_message); int dhcp_option_parse_string(const uint8_t *option, size_t len, char **ret); +int dhcp_option_parse_hostname(const uint8_t *option, size_t len, char **ret); diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index d59bf430d7a..dd4cbd3064b 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -746,14 +746,16 @@ static int parse_request(uint8_t code, uint8_t len, const void *option, void *us req->agent_info_option = (uint8_t*)option - 2; break; - case SD_DHCP_OPTION_HOST_NAME: - r = dhcp_option_parse_string(option, len, &req->hostname); - if (r < 0) { - log_debug_errno(r, "Failed to parse hostname, ignoring: %m"); - return 0; - } + case SD_DHCP_OPTION_HOST_NAME: { + _cleanup_free_ char *p = NULL; + r = dhcp_option_parse_hostname(option, len, &p); + if (r < 0) + log_debug_errno(r, "Failed to parse hostname, ignoring: %m"); + else + free_and_replace(req->hostname, p); break; + } case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST: req->parameter_request_list = option; req->parameter_request_list_len = len; -- 2.47.3