Skip to content

Commit 29d0fcc

Browse files
bors[bot]thvdveld
andauthored
Merge #566
566: Add fuzz tests for 6LoWPAN_IPHC and 6LoWPAN_UDP r=thibautvdv a=thibautvdv (Some more fuzzing!!) Adding fuzz tests for 6LoWPAN_IPHC and 6LoWPAN_UDP. Some bugs were found. Ran for 10 minutes. Co-authored-by: Thibaut Vandervelden <thvdveld@vub.be>
2 parents ca69642 + b540ec3 commit 29d0fcc

File tree

4 files changed

+136
-11
lines changed

4 files changed

+136
-11
lines changed

fuzz/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ cargo-fuzz = true
1010

1111
[dependencies]
1212
libfuzzer-sys = "0.4"
13+
arbitrary = { version = "1", features = ["derive"] }
1314
getopts = "0.2"
1415
smoltcp = { path = "..", features = [ "medium-ethernet" ] }
1516

@@ -40,3 +41,15 @@ name = "ieee802154_header"
4041
path = "fuzz_targets/ieee802154_header.rs"
4142
test = false
4243
doc = false
44+
45+
[[bin]]
46+
name = "sixlowpan_udp_header"
47+
path = "fuzz_targets/sixlowpan_udp_header.rs"
48+
test = false
49+
doc = false
50+
51+
[[bin]]
52+
name = "sixlowpan_iphc_header"
53+
path = "fuzz_targets/sixlowpan_iphc_header.rs"
54+
test = false
55+
doc = false
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#![no_main]
2+
use libfuzzer_sys::fuzz_target;
3+
use smoltcp::wire::{Ieee802154Address, SixlowpanIphcPacket, SixlowpanIphcRepr};
4+
5+
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, arbitrary::Arbitrary)]
6+
pub enum AddressFuzzer {
7+
Absent,
8+
Short([u8; 2]),
9+
Extended([u8; 8]),
10+
}
11+
12+
impl From<AddressFuzzer> for Ieee802154Address {
13+
fn from(val: AddressFuzzer) -> Self {
14+
match val {
15+
AddressFuzzer::Absent => Ieee802154Address::Absent,
16+
AddressFuzzer::Short(b) => Ieee802154Address::Short(b),
17+
AddressFuzzer::Extended(b) => Ieee802154Address::Extended(b),
18+
}
19+
}
20+
}
21+
22+
#[derive(Debug, arbitrary::Arbitrary)]
23+
struct SixlowpanIphcPacketFuzzer<'a> {
24+
data: &'a [u8],
25+
ll_src_addr: Option<AddressFuzzer>,
26+
ll_dst_addr: Option<AddressFuzzer>,
27+
}
28+
29+
fuzz_target!(|fuzz: SixlowpanIphcPacketFuzzer| {
30+
if let Ok(ref frame) = SixlowpanIphcPacket::new_checked(fuzz.data) {
31+
if let Ok(repr) = SixlowpanIphcRepr::parse(
32+
frame,
33+
fuzz.ll_src_addr.map(Into::into),
34+
fuzz.ll_dst_addr.map(Into::into),
35+
) {
36+
let mut buffer = vec![0; repr.buffer_len()];
37+
38+
let mut frame = SixlowpanIphcPacket::new_unchecked(&mut buffer[..]);
39+
repr.emit(&mut frame);
40+
}
41+
};
42+
});
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#![no_main]
2+
use libfuzzer_sys::fuzz_target;
3+
use smoltcp::wire::{Ipv6Address, SixlowpanUdpPacket, SixlowpanUdpRepr};
4+
5+
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, arbitrary::Arbitrary)]
6+
pub struct AddressFuzzer(pub [u8; 16]);
7+
8+
impl From<AddressFuzzer> for Ipv6Address {
9+
fn from(val: AddressFuzzer) -> Self {
10+
Ipv6Address(val.0)
11+
}
12+
}
13+
14+
#[derive(Debug, arbitrary::Arbitrary)]
15+
struct SixlowpanUdpPacketFuzzer<'a> {
16+
data: &'a [u8],
17+
src_addr: AddressFuzzer,
18+
dst_addr: AddressFuzzer,
19+
checksum: Option<u16>,
20+
}
21+
22+
fuzz_target!(|fuzz: SixlowpanUdpPacketFuzzer| {
23+
if let Ok(ref frame) = SixlowpanUdpPacket::new_checked(fuzz.data) {
24+
if let Ok(repr) = SixlowpanUdpRepr::parse(
25+
frame,
26+
&fuzz.src_addr.into(),
27+
&fuzz.dst_addr.into(),
28+
fuzz.checksum,
29+
) {
30+
let payload = frame.payload();
31+
let mut buffer = vec![0; repr.header_len() + payload.len()];
32+
33+
let mut frame = SixlowpanUdpPacket::new_unchecked(&mut buffer[..]);
34+
repr.emit(
35+
&mut frame,
36+
&fuzz.src_addr.into(),
37+
&fuzz.dst_addr.into(),
38+
payload.len(),
39+
|b| b.copy_from_slice(payload),
40+
);
41+
}
42+
};
43+
});

src/wire/sixlowpan.rs

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,21 @@ pub mod iphc {
128128
pub fn check_len(&self) -> Result<()> {
129129
let buffer = self.buffer.as_ref();
130130
if buffer.len() < 2 {
131-
Err(Error::Truncated)
132-
} else {
133-
Ok(())
131+
return Err(Error::Truncated);
134132
}
133+
134+
let mut offset = self.ip_fields_start()
135+
+ self.traffic_class_size()
136+
+ self.next_header_size()
137+
+ self.hop_limit_size();
138+
offset += self.src_address_size();
139+
offset += self.dst_address_size();
140+
141+
if offset as usize > buffer.len() {
142+
return Err(Error::Truncated);
143+
}
144+
145+
Ok(())
135146
}
136147

137148
/// Consumes the frame, returning the underlying buffer.
@@ -797,6 +808,12 @@ pub mod iphc {
797808
1 // The next header field is inlined
798809
};
799810

811+
// Hop Limit size
812+
len += match self.hop_limit {
813+
255 | 64 | 1 => 0, // We can inline the hop limit
814+
_ => 1,
815+
};
816+
800817
// Add the lenght of the source address
801818
len += if self.src_addr == ipv6::Address::UNSPECIFIED {
802819
0
@@ -1279,11 +1296,17 @@ pub mod nhc {
12791296
/// Returns `Err(Error::Truncated)` if the buffer is too short.
12801297
pub fn check_len(&self) -> Result<()> {
12811298
let buffer = self.buffer.as_ref();
1299+
12821300
if buffer.is_empty() {
1283-
Err(Error::Truncated)
1284-
} else {
1285-
Ok(())
1301+
return Err(Error::Truncated);
1302+
}
1303+
1304+
let index = 1 + self.ports_size() + self.checksum_size();
1305+
if index > buffer.len() {
1306+
return Err(Error::Truncated);
12861307
}
1308+
1309+
Ok(())
12871310
}
12881311

12891312
/// Consumes the frame, returning the underlying buffer.
@@ -1357,7 +1380,7 @@ pub mod nhc {
13571380
let data = self.buffer.as_ref();
13581381
let start = self.nhc_fields_start();
13591382

1360-
0xf0b0 + (NetworkEndian::read_u16(&data[start..start + 1]) & 0xff)
1383+
0xf0b0 + (data[start] & 0xff) as u16
13611384
}
13621385
_ => unreachable!(),
13631386
}
@@ -1501,10 +1524,14 @@ pub mod nhc {
15011524
checksum::data(packet.payload()),
15021525
]);
15031526

1504-
// TODO(thvdveld): remove the unwrap
1505-
if chk_sum != packet.checksum().unwrap() {
1506-
return Err(Error::Checksum);
1507-
}
1527+
if let Some(checksum) = packet.checksum() {
1528+
if chk_sum != checksum {
1529+
return Err(Error::Checksum);
1530+
}
1531+
} else {
1532+
net_trace!("Currently we do not support ellided checksums.");
1533+
return Err(Error::Unrecognized);
1534+
};
15081535

15091536
Ok(UdpNhcRepr(UdpRepr {
15101537
src_port: packet.src_port(),

0 commit comments

Comments
 (0)