Skip to content

Commit 31fda8f

Browse files
committed
fix lladdr parse panic
The `RawHardwareAddress::parse()` method panics if the length of the address is invalid. More specific, for an Ethernet address, the length should exactly be 6 bytes, and for an IEEE 802.15.4 address, the length should exactly be 8 bytes. Previously, we only checked if the size of the input was at least the size of the link layer address. Since `Ethernet::from_bytes()` does a copy_from_slice, the length of the input should be exactly 6 bytes. A panic can be triggered when the length is for example 7 bytes, while the `medium-ethernet` and `medium-ieee802154` features are enabled. This commit fixes the panic by checking if the length of the input is exactly the size of the link layer address. This panic was discovered by people from Radically Open Security. Signed-off-by: Thibaut Vandervelden <thvdveld@vub.be>
1 parent 104898b commit 31fda8f

File tree

1 file changed

+40
-2
lines changed

1 file changed

+40
-2
lines changed

src/wire/mod.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,10 @@ pub struct RawHardwareAddress {
478478

479479
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
480480
impl RawHardwareAddress {
481+
/// Create a new `RawHardwareAddress` from a byte slice.
482+
///
483+
/// # Panics
484+
/// Panics if `addr.len() > MAX_HARDWARE_ADDRESS_LEN`.
481485
pub fn from_bytes(addr: &[u8]) -> Self {
482486
let mut data = [0u8; MAX_HARDWARE_ADDRESS_LEN];
483487
data[..addr.len()].copy_from_slice(addr);
@@ -504,7 +508,7 @@ impl RawHardwareAddress {
504508
match medium {
505509
#[cfg(feature = "medium-ethernet")]
506510
Medium::Ethernet => {
507-
if self.len() < 6 {
511+
if self.len() != 6 {
508512
return Err(Error);
509513
}
510514
Ok(HardwareAddress::Ethernet(EthernetAddress::from_bytes(
@@ -513,7 +517,7 @@ impl RawHardwareAddress {
513517
}
514518
#[cfg(feature = "medium-ieee802154")]
515519
Medium::Ieee802154 => {
516-
if self.len() < 8 {
520+
if self.len() != 8 {
517521
return Err(Error);
518522
}
519523
Ok(HardwareAddress::Ieee802154(Ieee802154Address::from_bytes(
@@ -559,3 +563,37 @@ impl From<HardwareAddress> for RawHardwareAddress {
559563
Self::from_bytes(addr.as_bytes())
560564
}
561565
}
566+
567+
#[cfg(test)]
568+
mod tests {
569+
use super::*;
570+
use rstest::rstest;
571+
572+
#[rstest]
573+
#[cfg(feature = "medium-ethernet")]
574+
#[case((Medium::Ethernet, &[0u8; 6][..]), Ok(HardwareAddress::Ethernet(EthernetAddress([0, 0, 0, 0, 0, 0]))))]
575+
#[cfg(feature = "medium-ethernet")]
576+
#[case((Medium::Ethernet, &[1u8; 5][..]), Err(Error))]
577+
#[cfg(feature = "medium-ethernet")]
578+
#[case((Medium::Ethernet, &[1u8; 7][..]), Err(Error))]
579+
#[cfg(feature = "medium-ieee802154")]
580+
#[case((Medium::Ieee802154, &[0u8; 8][..]), Ok(HardwareAddress::Ieee802154(Ieee802154Address::Extended([0, 0, 0, 0, 0, 0, 0, 0]))))]
581+
#[cfg(feature = "medium-ieee802154")]
582+
#[case((Medium::Ieee802154, &[1u8; 2][..]), Err(Error))]
583+
#[cfg(feature = "medium-ieee802154")]
584+
#[case((Medium::Ieee802154, &[1u8; 1][..]), Err(Error))]
585+
fn parse_hardware_address(
586+
#[case] input: (Medium, &[u8]),
587+
#[case] expected: Result<HardwareAddress>,
588+
) {
589+
let (medium, input) = input;
590+
591+
// NOTE: we check the length since `RawHardwareAddress::parse()` panics if the length is
592+
// invalid. MAX_HARDWARE_ADDRESS_LEN is based on the medium, and depending on the feature
593+
// flags, it can be different.
594+
if input.len() < MAX_HARDWARE_ADDRESS_LEN {
595+
let raw = RawHardwareAddress::from_bytes(input);
596+
assert_eq!(raw.parse(medium), expected);
597+
}
598+
}
599+
}

0 commit comments

Comments
 (0)