If the hostname supplied by a DHCPv4 client doesn't pass the
test if being an allowed hostname (ie without metacharacters) it
is ignored, but still passed to the environment variable
DNSMASQ_SUPPLIED_HOSTNAME in the dhcp-script.
Change this so that only valid hostnames appear in thos variable,
to avoid security problems with scripts that son't sanitise.
This brings DHCPv4 behaviour in line with DHCPv6.
Thanks to Daniel Birtwhistle for spotting the problem.
print_mac() used to output into caller-supplied buffer with no
length checking. The various callers supplied different
length buffers and did their own, ad-hoc, length checking before
calling print_mac(). This was an accident waiting to happen and
it had actually happened in couple of places, with buffer
overflows possible.
print_mac() now returns the address of its own buffer, which
is grown as required.
Thanks to Nicholas Carlini <npc@anthropic.com> for spotting this problem.
This is the stable release fix for CVE-2026-2291
Dnsmasq recieves and sends domain names within DNS packets in RFC-1035
format, a string of counted labels terminated by a zero length label.
Internally to dnsmasq, domain names are represented as zero-terminated C strings
with the labels seperated by '.' characters, like the normal presentation
format for domain names.
The RFC-1035 limit for a domain name in wire format is 255 octets, and
when converted to presentation format, this makes a string of
maximum 253 characters. However dnsmasq needs to be able to
represent any 8-bit character within a label, and this causes
problems with /000 (which would terminate the c-string early) and
'.' (which would terminate a label early). To avoid this, dnsmasq
escapes both of these characters, which means that they take two bytes
in the string. The domain name with must charaters in it has four labels
and the 255 octet wire length limits these four labels to a total of
250 characters. The other five octets are the four label length bytes
and the zero length byte terminator. If all 250 characters need escaping
that makes the maximum length of the dnsmasq internal format 503
characters (250 escaped characters in labels, amd three dots between
four labels) Since this format is zero-terminated c-string, buffers
have to be allocated as 504 bytes.
This arrangement grew in a somewhat ad-hoc manner and early dnsmasq
didn't do the escaping trick, and didn't really differentiate between
the lengths of the wire format and the presentation format, since
they were very similar. It also, for reasons lost in time, inherited
a defintion for MAXDNAME from early BIND headers, set at 1025 bytes.
This value was used as the buffer size for both wire and presentation
formats.
This patch makes everything consistent. It declares two constants
MAXDNAME 255 /* max size of wire format domain name */
MAXDNAMESTR 503 /* max size of internal format created from a 255 octet wire format name */
All internal name buffers are allocated as MAXDNAMESTR+1 bytes,
to hold a maximum size internal format name and zero termination.
Names parsed out of incoming packets are rejected if their
wire format is greater than 255 bytes, which ensures that
their internal representation cannot exceed 503 characters.
Names inserted into outgoing packets are failed similarly if
they exceed 255 bytes. (this would in theory be possible
for a legal internal-representaion name if it has at least
one unescaped character in a label.
After copying the 128-byte DHCP file field into dhcp_buff2, the
sentinel was written to index 129 instead of 128. The byte at
index 128 was therefore left holding stale data from the previous
DHCP exchange, so a client that fills the entire file field with
non-NUL bytes would produce a 129-character netid tag whose last
byte is heap garbage. In theory this allows incorrect netid-tag
matching; in practice it requires the client to know the heap
state of a prior transaction and BOOTP use is uncommon.
Security: very-low-severity heap-content exposure that could
influence DHCP option selection via tag mismatch; no memory
corruption or crash.
Signed-off-by: Dominik <dl6er@dl6er.de>
This acts almost exactly like --dhcp-option except that the defined option
is only sent when replying to PXE clients. More importantly, these
options are sent in reply PXE clients when dnsmasq in acting in PXE
proxy mode. In PXE proxy mode, the set of options sent is defined by
the PXE standard and the normal set of options is not sent. This config
allows arbitrary options in PXE-proxy replies. A typical use-case is
to send option 175 to iPXE. Thanks to Jason Berry for finding the
requirement for this.
As defined in the C standard:
In all cases the argument is an int, the value of which shall
be representable as an unsigned char or shall equal the value
of the macro EOF. If the argument has any other value, the
behavior is undefined.
This is because they're designed to work with the int values returned
by getc or fgetc; they need extra work to handle a char value.
If EOF is -1 (as it almost always is), with 8-bit bytes, the allowed
inputs to the ctype(3) functions are:
{-1, 0, 1, 2, 3, ..., 255}.
However, on platforms where char is signed, such as x86 with the
usual ABI, code like
char *arg = ...;
... isspace(*arg) ...
may pass in values in the range:
{-128, -127, -126, ..., -2, -1, 0, 1, ..., 127}.
This has two problems:
1. Inputs in the set {-128, -127, -126, ..., -2} are forbidden.
2. The non-EOF byte 0xff is conflated with the value EOF = -1, so
even though the input is not forbidden, it may give the wrong
answer.
Casting char to int first before passing the result to ctype(3)
doesn't help: inputs like -128 are unchanged by this cast. It is
necessary to cast char inputs to unsigned char first; you can then
cast to int if you like but there's no need because the functions
will always convert the argument to int by definition. So the above
fragment needs to be:
char *arg = ...;
... isspace((unsigned char)*arg) ...
This patch inserts unsigned char casts where necessary, and changes
int casts to unsigned char casts where the input is char.
I left alone int casts where the input is unsigned char already --
they're not immediately harmful, although they would have the effect
of suppressing some compiler warnings if the input is ever changed to
be char instead of unsigned char, so it might be better to remove
those casts too.
I also left alone calls where the input is int to begin with because
it came from getc; casting to unsigned char here would be wrong, of
course.
1) Cosmetic: don't log the tags twice.
2) Functional. If a host has an old lease for a different address,
the rapid-commit will appear to work, but the old lease will
not be removed and the new lease will not be recorded, so
the client and server will have conflicting state, leading to
problems later.
From 606d638918edb0e0ec07fe27eb68d06fb5ebd981 Mon Sep 17 00:00:00 2001
From: Miao Wang <shankerwangmiao@gmail.com>
Date: Fri, 4 Dec 2020 09:59:37 +0800
Subject: [PATCH v2] pxe: support pxe clients with custom vendor-class
According to UEFI[1] and PXE[2] specs, PXE clients are required to have
`PXEClient` identfier in the vendor-class field of DHCP requests, and
PXE servers should also include that identifier in their responses.
However, the firmware of servers from a few vendors[3] are customized to
include a different identifier. This patch adds an option named
`dhcp-pxe-vendor` to provide a list of such identifiers. The identifier
used in responses sent from dnsmasq is identical to that in the coresponding
request.
[1]: https://uefi.org/sites/default/files/resources/UEFI%20Spec%202.8B%20May%202020.pdf
[2]: http://www.pix.net/software/pxeboot/archive/pxespec.pdf
[3]: For instance, TaiShan servers from Huawei, which are Arm64-based,
send `HW-Client` in PXE requests up to now.
Signed-off-by: Miao Wang <shankerwangmiao@gmail.com>
The idea of this option was already discussed years ago on the mailing
list:
https://dnsmasq-discuss.thekelleys.org.narkive.com/ZoFQNaGo/always-ignore-client-identifier#post4
In our production environnement, we discovered that some devices are
using 'client identifier' not unique at all, resulting on IP addresses
conflicts between several devices (we saw up to four devices using same
IP address).
The root cause is probably a buggy operating system/configuration of
decices, but this patch add a configuration workaround on server side
when fixing clients is impossible.
Signed-off-by: Charles Daymand <charles.daymand@wifirst.fr>
Signed-off-by: Florent Fourcot <florent.fourcot@wifirst.fr>