Check remaining length when parsing open-ended RDATA. (#664)

This PR adds checks to the parse functions of open-ended RDATA types to
make sure they will not exceed the maximum RDATA length of 65,535 bytes.

Specifically, these checks are added to all types that return an
error-result of LongRecordData in their new function. I hope that covers
all such types.
This commit is contained in:
Martin Hoffmann
2026-05-29 12:44:45 +02:00
committed by GitHub
parent e40b09a8cb
commit f4a4dbf651
8 changed files with 23 additions and 4 deletions
+8 -4
View File
@@ -13,10 +13,13 @@ Improvements
Bug fixes
* Detect when an attempt is made to create an dnssec::sign::records::Rrset
with records that have different TTLs. Unfortuantely error handling is
poor so the code currently panics. At least this prevents bad signatures
but the error handling needs to be fixed later. ([#660])
* Added a length check when parsing open-ended record types like
`Dnskey<_>` which are supposed to never be too large. ([#664])
* Detect when an attempt is made to create a
`dnssec::sign::records::Rrset` with records that have different TTLs.
Unfortuantely error handling is poor so the code currently panics. At
least this prevents bad signatures but the error handling needs to be
fixed later. ([#660])
Unstable features
@@ -28,6 +31,7 @@ Other changes
[#641]: https://github.com/NLnetLabs/domain/pull/641
[#659]: https://github.com/NLnetLabs/domain/pull/659
[#660]: https://github.com/NLnetLabs/domain/pull/660
[#664]: https://github.com/NLnetLabs/domain/pull/664
[@soywod]: https://github.com/soywod
+6
View File
@@ -529,6 +529,12 @@ impl LongRecordData {
}
}
impl From<LongRecordData> for ParseError {
fn from(src: LongRecordData) -> ParseError {
ParseError::form_error(src.as_str())
}
}
impl fmt::Display for LongRecordData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
+2
View File
@@ -137,6 +137,7 @@ impl<Octs> Cdnskey<Octs> {
Some(len) => len,
None => return Err(ParseError::ShortInput),
};
LongRecordData::check_len(len)?;
Ok(unsafe {
Self::new_unchecked(
u16::parse(parser)?,
@@ -470,6 +471,7 @@ impl<Octs> Cds<Octs> {
Some(len) => len,
None => return Err(ParseError::ShortInput),
};
LongRecordData::check_len(len)?;
Ok(unsafe {
Self::new_unchecked(
u16::parse(parser)?,
+3
View File
@@ -245,6 +245,7 @@ impl<Octs> Dnskey<Octs> {
Some(len) => len,
None => return Err(ParseError::ShortInput),
};
LongRecordData::check_len(len)?;
Ok(unsafe {
Self::new_unchecked(
u16::parse(parser)?,
@@ -1042,6 +1043,7 @@ impl<Octs> Rrsig<Octs, ParsedName<Octs>> {
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized + 'a>(
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
LongRecordData::check_len(parser.remaining())?;
let type_covered = Rtype::parse(parser)?;
let algorithm = SecurityAlgorithm::parse(parser)?;
let labels = u8::parse(parser)?;
@@ -1826,6 +1828,7 @@ impl<Octs> Ds<Octs> {
Some(len) => len,
None => return Err(ParseError::ShortInput),
};
LongRecordData::check_len(parser.remaining())?;
Ok(unsafe {
Self::new_unchecked(
u16::parse(parser)?,
+1
View File
@@ -137,6 +137,7 @@ impl<Octs> Null<Octs> {
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
let len = parser.remaining();
LongRecordData::check_len(len)?;
parser
.parse_octets(len)
.map(|res| unsafe { Self::from_octets_unchecked(res) })
+1
View File
@@ -185,6 +185,7 @@ impl<Octs> Txt<Octs> {
Octs: AsRef<[u8]>,
{
let len = parser.remaining();
LongRecordData::check_len(len)?;
let text = parser.parse_octets(len)?;
let mut tmp = Parser::from_ref(text.as_ref());
while tmp.remaining() != 0 {
+1
View File
@@ -175,6 +175,7 @@ impl<Variant, Octs: AsRef<[u8]>> SvcbRdata<Variant, Octs, ParsedName<Octs>> {
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized + 'a>(
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
LongRecordData::check_len(parser.remaining())?;
let priority = u16::parse(parser)?;
let target = ParsedName::parse(parser)?;
let params = SvcParams::parse(parser)?;
+1
View File
@@ -307,6 +307,7 @@ impl<Octs> Tsig<Octs, ParsedName<Octs>> {
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized + 'a>(
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
LongRecordData::check_len(parser.remaining())?;
let algorithm = ParsedName::parse(parser)?;
let time_signed = Time48::parse(parser)?;
let fudge = u16::parse(parser)?;