From 1d73c5f04f2e7e82d216e69621749c8ea9661c78 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Sun, 17 May 2026 18:22:20 +0100 Subject: [PATCH] dhcp-client: clear overloaded sname/file fields after parsing When SD_DHCP_OPTION_OVERLOAD indicates that the sname and/or file header fields are overloaded with extra DHCP options, dhcp_message_parse() merges those options into message->options but leaves the raw bytes untouched in the header. As a result, dhcp_message_build() emits the header (including the overloaded bytes) verbatim, and the next parse re-parses those bytes, appending duplicate entries to the options map (each tag's iov list grows). Subsequent builds then differ from the first, breaking the parse/build roundtrip. This was caught by fuzz-dhcp-client, which asserts that two consecutive build calls produce identical output. Zero out the overloaded fields after parsing them, since their content has already been merged into the options map. This makes the roundtrip idempotent and avoids re-emitting stale overloaded data in the rebuilt header. The JSON build/parse path was already correct (it omits sname/file from the JSON when the overload bit is set), so only the binary path needed fixing. Fixes https://github.com/systemd/systemd/issues/42139 Co-developed-by: Claude Opus 4.7 --- src/libsystemd-network/dhcp-message.c | 7 +++++++ .../fuzz/fuzz-dhcp-client/overload-file-roundtrip | Bin 0 -> 243 bytes 2 files changed, 7 insertions(+) create mode 100644 test/fuzz/fuzz-dhcp-client/overload-file-roundtrip diff --git a/src/libsystemd-network/dhcp-message.c b/src/libsystemd-network/dhcp-message.c index ae12c5b46a9..a3ba05688df 100644 --- a/src/libsystemd-network/dhcp-message.c +++ b/src/libsystemd-network/dhcp-message.c @@ -1409,12 +1409,19 @@ int dhcp_message_parse( r = tlv_parse(&message->options, &IOVEC_MAKE(message->header.file, sizeof(message->header.file))); if (r < 0) return r; + + /* The content of the overloaded field has been merged into options. Clear it so that the + * field is not re-parsed (which would duplicate the options) and not re-emitted verbatim + * by dhcp_message_build(), ensuring parse/build is idempotent. */ + memzero(message->header.file, sizeof(message->header.file)); } if (FLAGS_SET(overload, DHCP_OVERLOAD_SNAME)) { r = tlv_parse(&message->options, &IOVEC_MAKE(message->header.sname, sizeof(message->header.sname))); if (r < 0) return r; + + memzero(message->header.sname, sizeof(message->header.sname)); } *ret = TAKE_PTR(message); diff --git a/test/fuzz/fuzz-dhcp-client/overload-file-roundtrip b/test/fuzz/fuzz-dhcp-client/overload-file-roundtrip new file mode 100644 index 0000000000000000000000000000000000000000..43cee115a2e127bbcaece7cfd018f964f440ebf1 GIT binary patch literal 243 zcmZQ#WK&>ZU|>=}2mclRJ32WV8X2QYVB`PCCWtQfUjb?sA=ME1{}7