From 678e6e41e9883afdd30341a4e21d791d61c0b9a5 Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 8 Sep 2026 09:40:46 +0100 Subject: [PATCH] dhcpcd: size the escaped-SSID buffers for the worst case print_string() renders each non-printable byte as \NNN - four characters plus terminating NUL, failing with ENOBUFS if there is no room for it. An SSID is up to IF_SSIDLEN (32) bytes, so an escaped SSID needs up to (IF_SSIDLEN * 4) + 1 = 129 bytes. Add IF_SSIDSTRLEN for this and use it everywhere an escaped SSID is stored. dhcpcd_selectprofile() used PROFILE_LEN, which is 64 causing: dhcpcd_selectprofile: No buffer space available in the log, the resulting call to read_config() then gets an empty SSID, so no `ssid ...` block matches. dhcpcd_reportssid() and make_env() used IF_SSIDLEN * 4, which is 128 and correct except for the NUL, so they fail only on a 32-byte SSID whose every byte escapes. The former then logs an error instead of the "connected to Access Point" line and the latter omits ifssid from the hook environment. dhcp_set_leasefile() and the lease file name buffers were already sized correctly, so switching them is only for consistency. Signed-off-by: Alex Kiernan --- src/dhcp-common.c | 2 +- src/dhcp.h | 2 +- src/dhcp6.h | 2 +- src/dhcpcd.c | 4 ++-- src/dhcpcd.h | 2 ++ src/script.c | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/dhcp-common.c b/src/dhcp-common.c index e87094de3..fd090f05f 100644 --- a/src/dhcp-common.c +++ b/src/dhcp-common.c @@ -1013,7 +1013,7 @@ dhcp_set_leasefile(char *leasefile, size_t len, int family, const struct interface *ifp) { char ifname[(sizeof(ifp->name) * 4) + 1]; - char ssid[1 + (IF_SSIDLEN * 4) + 1]; /* - prefix and NUL terminated. */ + char ssid[1 + IF_SSIDSTRLEN]; /* - prefix and escaped SSID. */ if (ifp->name[0] == '\0') { strlcpy(leasefile, ifp->ctx->pidfile, len); diff --git a/src/dhcp.h b/src/dhcp.h index 5dbea7d5e..73ac5e9ce 100644 --- a/src/dhcp.h +++ b/src/dhcp.h @@ -229,7 +229,7 @@ struct dhcp_state { struct ipv4_addr *addr; uint8_t added; - char leasefile[sizeof(LEASEFILE) + IF_NAMESIZE + (IF_SSIDLEN * 4)]; + char leasefile[sizeof(LEASEFILE) + IF_NAMESIZE + IF_SSIDSTRLEN]; struct timespec started; unsigned char *clientid; struct authstate auth; diff --git a/src/dhcp6.h b/src/dhcp6.h index 75e80a0d3..01af741ce 100644 --- a/src/dhcp6.h +++ b/src/dhcp6.h @@ -212,7 +212,7 @@ struct dhcp6_state { struct ipv6_addrhead addrs; uint32_t lowpl; /* The +3 is for the possible .pd extension for prefix delegation */ - char leasefile[sizeof(LEASEFILE6) + IF_NAMESIZE + (IF_SSIDLEN * 4) + 3]; + char leasefile[sizeof(LEASEFILE6) + IF_NAMESIZE + IF_SSIDSTRLEN + 3]; const char *reason; uint16_t lerror; /* Last error received from DHCPv6 reply. */ bool has_no_binding; diff --git a/src/dhcpcd.c b/src/dhcpcd.c index bf277bbca..9cc1bb899 100644 --- a/src/dhcpcd.c +++ b/src/dhcpcd.c @@ -628,7 +628,7 @@ int dhcpcd_selectprofile(struct interface *ifp, const char *profile) { struct if_options *ifo; - char pssid[PROFILE_LEN]; + char pssid[IF_SSIDSTRLEN]; if (ifp->ssid_len) { ssize_t r; @@ -717,7 +717,7 @@ dhcpcd_initstate(struct interface *ifp, unsigned long long options) static void dhcpcd_reportssid(struct interface *ifp) { - char pssid[IF_SSIDLEN * 4]; + char pssid[IF_SSIDSTRLEN]; if (print_string(pssid, sizeof(pssid), OT_ESCSTRING, ifp->ssid, ifp->ssid_len) == -1) { diff --git a/src/dhcpcd.h b/src/dhcpcd.h index f097c95f3..b0f38d40e 100644 --- a/src/dhcpcd.h +++ b/src/dhcpcd.h @@ -45,6 +45,8 @@ #define IF_SSIDLEN 32 #define PROFILE_LEN 64 #define SECRET_LEN 64 +/* An escaped SSID needs four characters per-octet, plus terminating NUL */ +#define IF_SSIDSTRLEN ((IF_SSIDLEN * 4) + 1) #define IF_INACTIVE 0 #define IF_ACTIVE 1 diff --git a/src/script.c b/src/script.c index e059472e2..2464643f0 100644 --- a/src/script.c +++ b/src/script.c @@ -393,7 +393,7 @@ make_env(struct dhcpcd_ctx *ctx, const struct interface *ifp, if (efprintf(fp, "ifmtu=%d", if_getmtu(ifp)) == -1) goto eexit; if (ifp->wireless) { - char pssid[IF_SSIDLEN * 4]; + char pssid[IF_SSIDSTRLEN]; if (print_string(pssid, sizeof(pssid), OT_ESCSTRING, ifp->ssid, ifp->ssid_len) != -1) {