From cd04c0ce204a4607e86497095b8bba02219654c3 Mon Sep 17 00:00:00 2001 From: Dominik Date: Thu, 19 Mar 2026 23:11:46 +0100 Subject: [PATCH] lease: check parse_hex() return value before use as length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit parse_hex() returns -1 on malformed input. Three call sites in read_leases() used the return value directly as a length argument without checking for the error sentinel: opt_len → lease_set_vendorclass() / lease_set_agent_id() whine_malloc(-1) attempts a ~4 GB allocation, likely crashing the process. hw_len → lease_set_hwaddr() memcpy(lease->hwaddr, hwaddr, (size_t)-1) performs an ~18 EB write, causing an immediate crash. clid_len → lease_set_hwaddr() (same path as hw_len) Exploitation requires a corrupted or attacker-controlled lease file; it is not directly network-triggerable. However, any process that can write to the lease file (e.g. a compromised helper) can crash or potentially gain code execution in the dnsmasq process at next startup or lease-file re-read. Fix: mirror the existing duid path (which already guards its parse_hex call) by checking for < 0. For opt_len, skip the record (continue) to match the "invalid line" behaviour. For hw_len and clid_len, treat the failure as a zero-length field so the lease is still created with the correct address. Co-Authored-By: Claude Sonnet 4.6 --- src/lease.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/lease.c b/src/lease.c index 00748ad..3e2bc33 100644 --- a/src/lease.c +++ b/src/lease.c @@ -73,7 +73,9 @@ static int read_leases(time_t now, FILE *leasestream) if (lease) { opt_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL); - + if (opt_len < 0) + continue; + if (strcmp(daemon->dhcp_buff3, "vendorclass") == 0) lease_set_vendorclass(lease, (unsigned char *)daemon->packet, opt_len); else if (strcmp(daemon->dhcp_buff3, "agent-info") == 0) @@ -99,6 +101,8 @@ static int read_leases(time_t now, FILE *leasestream) hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type); + if (hw_len < 0) + hw_len = 0; /* For backwards compatibility, no explicit MAC address type means ether. */ if (hw_type == 0 && hw_len != 0) hw_type = ARPHRD_ETHER; @@ -131,7 +135,11 @@ static int read_leases(time_t now, FILE *leasestream) die (_("too many stored leases"), NULL, EC_MISC); if (strcmp(daemon->packet, "*") != 0) - clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL); + { + clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL); + if (clid_len < 0) + clid_len = 0; + } lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len, now, 0);