From 9a8cc5a98d608fb8080ed91ace2f27c13ae1aca0 Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Mon, 13 Nov 2023 23:33:23 +0000 Subject: [PATCH] LibDNS: Ensure DNS name and label sizes are within expected limits Previously, the DNS packet parser would happily parse a DNS packet containing an arbitrarily large domain name. We now limit each segment of a domain name to 63 characters and the total domain name length to 253 characters. This is consistent with RFC1035, which specifies that the maximum name length is 255 octets. This includes the initial length byte and final null byte, which accounts for the 2 byte difference. --- Userland/Libraries/LibDNS/Name.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Userland/Libraries/LibDNS/Name.cpp b/Userland/Libraries/LibDNS/Name.cpp index 0769845236a..0dfef512e3d 100644 --- a/Userland/Libraries/LibDNS/Name.cpp +++ b/Userland/Libraries/LibDNS/Name.cpp @@ -23,6 +23,9 @@ Name::Name(DeprecatedString const& name) ErrorOr Name::parse(ReadonlyBytes data, size_t& offset, size_t recursion_level) { + static constexpr size_t MAX_LABEL_SIZE = 63; + static constexpr size_t MAX_NAME_SIZE = 253; + if (recursion_level > 4) return Name {}; @@ -32,6 +35,8 @@ ErrorOr Name::parse(ReadonlyBytes data, size_t& offset, size_t recursion_l return Error::from_string_literal("Unexpected EOF when parsing name"); u8 b = data[offset++]; if (b == '\0') { + if (builder.length() > MAX_NAME_SIZE) + return Error::from_string_literal("Domain name exceeds maximum allowed length"); // This terminates the name. return builder.to_deprecated_string(); } else if ((b & 0xc0) == 0xc0) { @@ -41,13 +46,19 @@ ErrorOr Name::parse(ReadonlyBytes data, size_t& offset, size_t recursion_l size_t dummy = (b & 0x3f) << 8 | data[offset++]; auto rest_of_name = TRY(parse(data, dummy, recursion_level + 1)); builder.append(rest_of_name.as_string()); + if (builder.length() > MAX_NAME_SIZE) + return Error::from_string_literal("Domain name exceeds maximum allowed length"); return builder.to_deprecated_string(); } else { // This is the length of a part. if (offset + b >= data.size()) return Error::from_string_literal("Unexpected EOF when parsing name"); + if (b > MAX_LABEL_SIZE) + return Error::from_string_literal("DNS label exceeds maximum allowed length"); builder.append({ data.offset_pointer(offset), b }); builder.append('.'); + if (builder.length() > MAX_NAME_SIZE) + return Error::from_string_literal("Domain name exceeds maximum allowed length"); offset += b; } }