|
@@ -0,0 +1,240 @@
|
|
|
+#![no_main]
|
|
|
+use libfuzzer_sys::fuzz_target;
|
|
|
+use smoltcp::{phy::ChecksumCapabilities, wire::*};
|
|
|
+
|
|
|
+#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, arbitrary::Arbitrary)]
|
|
|
+pub enum AddressFuzzer {
|
|
|
+ Absent,
|
|
|
+ Short([u8; 2]),
|
|
|
+ Extended([u8; 8]),
|
|
|
+}
|
|
|
+
|
|
|
+impl From<AddressFuzzer> for Ieee802154Address {
|
|
|
+ fn from(val: AddressFuzzer) -> Self {
|
|
|
+ match val {
|
|
|
+ AddressFuzzer::Absent => Ieee802154Address::Absent,
|
|
|
+ AddressFuzzer::Short(b) => Ieee802154Address::Short(b),
|
|
|
+ AddressFuzzer::Extended(b) => Ieee802154Address::Extended(b),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Debug, arbitrary::Arbitrary)]
|
|
|
+struct SixlowpanPacketFuzzer<'a> {
|
|
|
+ data: &'a [u8],
|
|
|
+ ll_src_addr: Option<AddressFuzzer>,
|
|
|
+ ll_dst_addr: Option<AddressFuzzer>,
|
|
|
+}
|
|
|
+
|
|
|
+fuzz_target!(|fuzz: SixlowpanPacketFuzzer| {
|
|
|
+ match SixlowpanPacket::dispatch(fuzz.data) {
|
|
|
+ Ok(SixlowpanPacket::FragmentHeader) => {
|
|
|
+ if let Ok(frame) = SixlowpanFragPacket::new_checked(fuzz.data) {
|
|
|
+ if let Ok(repr) = SixlowpanFragRepr::parse(&frame) {
|
|
|
+ let mut buffer = vec![0; repr.buffer_len()];
|
|
|
+ let mut frame = SixlowpanFragPacket::new_unchecked(&mut buffer[..]);
|
|
|
+ repr.emit(&mut frame);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Ok(SixlowpanPacket::IphcHeader) => {
|
|
|
+ if let Ok(frame) = SixlowpanIphcPacket::new_checked(fuzz.data) {
|
|
|
+ if let Ok(iphc_repr) = SixlowpanIphcRepr::parse(
|
|
|
+ &frame,
|
|
|
+ fuzz.ll_src_addr.map(Into::into),
|
|
|
+ fuzz.ll_dst_addr.map(Into::into),
|
|
|
+ ) {
|
|
|
+ let mut buffer = vec![0; iphc_repr.buffer_len()];
|
|
|
+ let mut iphc_frame = SixlowpanIphcPacket::new_unchecked(&mut buffer[..]);
|
|
|
+ iphc_repr.emit(&mut iphc_frame);
|
|
|
+
|
|
|
+ let payload = frame.payload();
|
|
|
+ match iphc_repr.next_header {
|
|
|
+ SixlowpanNextHeader::Compressed => {
|
|
|
+ if let Ok(p) = SixlowpanNhcPacket::dispatch(payload) {
|
|
|
+ match p {
|
|
|
+ SixlowpanNhcPacket::ExtHeader => {
|
|
|
+ if let Ok(frame) =
|
|
|
+ SixlowpanExtHeaderPacket::new_checked(payload)
|
|
|
+ {
|
|
|
+ if let Ok(repr) = SixlowpanExtHeaderRepr::parse(&frame)
|
|
|
+ {
|
|
|
+ let mut buffer = vec![0; repr.buffer_len()];
|
|
|
+ let mut ext_header_frame =
|
|
|
+ SixlowpanExtHeaderPacket::new_unchecked(
|
|
|
+ &mut buffer[..],
|
|
|
+ );
|
|
|
+ repr.emit(&mut ext_header_frame);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ SixlowpanNhcPacket::UdpHeader => {
|
|
|
+ if let Ok(frame) =
|
|
|
+ SixlowpanUdpNhcPacket::new_checked(payload)
|
|
|
+ {
|
|
|
+ if let Ok(repr) = SixlowpanUdpNhcRepr::parse(
|
|
|
+ &frame,
|
|
|
+ &iphc_repr.src_addr,
|
|
|
+ &iphc_repr.dst_addr,
|
|
|
+ ) {
|
|
|
+ let mut buffer = vec![
|
|
|
+ 0;
|
|
|
+ repr.header_len()
|
|
|
+ + frame.payload().len()
|
|
|
+ ];
|
|
|
+ let mut udp_packet =
|
|
|
+ SixlowpanUdpNhcPacket::new_unchecked(
|
|
|
+ &mut buffer[..],
|
|
|
+ );
|
|
|
+ repr.emit(
|
|
|
+ &mut udp_packet,
|
|
|
+ &iphc_repr.src_addr,
|
|
|
+ &iphc_repr.dst_addr,
|
|
|
+ frame.payload().len(),
|
|
|
+ |b| b.copy_from_slice(frame.payload()),
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ SixlowpanNextHeader::Uncompressed(proto) => match proto {
|
|
|
+ IpProtocol::HopByHop => {
|
|
|
+ if let Ok(frame) = Ipv6HopByHopHeader::new_checked(payload) {
|
|
|
+ if let Ok(repr) = Ipv6HopByHopRepr::parse(&frame) {
|
|
|
+ let mut buffer = vec![0; repr.buffer_len()];
|
|
|
+ let mut hop_by_hop_frame =
|
|
|
+ Ipv6HopByHopHeader::new_unchecked(&mut buffer[..]);
|
|
|
+ repr.emit(&mut hop_by_hop_frame);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ IpProtocol::Icmp => {
|
|
|
+ if let Ok(frame) = Icmpv4Packet::new_checked(payload) {
|
|
|
+ if let Ok(repr) =
|
|
|
+ Icmpv4Repr::parse(&frame, &ChecksumCapabilities::default())
|
|
|
+ {
|
|
|
+ let mut buffer = vec![0; repr.buffer_len()];
|
|
|
+ let mut icmpv4_packet =
|
|
|
+ Icmpv4Packet::new_unchecked(&mut buffer[..]);
|
|
|
+ repr.emit(
|
|
|
+ &mut icmpv4_packet,
|
|
|
+ &ChecksumCapabilities::default(),
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ IpProtocol::Igmp => {
|
|
|
+ if let Ok(frame) = IgmpPacket::new_checked(payload) {
|
|
|
+ if let Ok(repr) = IgmpRepr::parse(&frame) {
|
|
|
+ let mut buffer = vec![0; repr.buffer_len()];
|
|
|
+ let mut frame = IgmpPacket::new_unchecked(&mut buffer[..]);
|
|
|
+ repr.emit(&mut frame);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ IpProtocol::Tcp => {
|
|
|
+ if let Ok(frame) = TcpPacket::new_checked(payload) {
|
|
|
+ if let Ok(repr) = TcpRepr::parse(
|
|
|
+ &frame,
|
|
|
+ &iphc_repr.src_addr.into_address(),
|
|
|
+ &iphc_repr.dst_addr.into_address(),
|
|
|
+ &ChecksumCapabilities::default(),
|
|
|
+ ) {
|
|
|
+ let mut buffer = vec![0; repr.buffer_len()];
|
|
|
+ let mut frame = TcpPacket::new_unchecked(&mut buffer[..]);
|
|
|
+ repr.emit(
|
|
|
+ &mut frame,
|
|
|
+ &iphc_repr.src_addr.into_address(),
|
|
|
+ &iphc_repr.dst_addr.into_address(),
|
|
|
+ &ChecksumCapabilities::default(),
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ IpProtocol::Udp => {
|
|
|
+ if let Ok(frame) = UdpPacket::new_checked(payload) {
|
|
|
+ if let Ok(repr) = UdpRepr::parse(
|
|
|
+ &frame,
|
|
|
+ &iphc_repr.src_addr.into_address(),
|
|
|
+ &iphc_repr.dst_addr.into_address(),
|
|
|
+ &ChecksumCapabilities::default(),
|
|
|
+ ) {
|
|
|
+ let mut buffer =
|
|
|
+ vec![0; repr.header_len() + frame.payload().len()];
|
|
|
+ let mut packet = UdpPacket::new_unchecked(&mut buffer[..]);
|
|
|
+ repr.emit(
|
|
|
+ &mut packet,
|
|
|
+ &iphc_repr.src_addr.into_address(),
|
|
|
+ &iphc_repr.dst_addr.into_address(),
|
|
|
+ frame.payload().len(),
|
|
|
+ |b| b.copy_from_slice(frame.payload()),
|
|
|
+ &ChecksumCapabilities::default(),
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ IpProtocol::Ipv6Route => {
|
|
|
+ if let Ok(frame) = Ipv6RoutingHeader::new_checked(payload) {
|
|
|
+ if let Ok(repr) = Ipv6RoutingRepr::parse(&frame) {
|
|
|
+ let mut buffer = vec![0; repr.buffer_len()];
|
|
|
+ let mut packet = Ipv6RoutingHeader::new(&mut buffer[..]);
|
|
|
+ repr.emit(&mut packet);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ IpProtocol::Ipv6Frag => {
|
|
|
+ if let Ok(frame) = Ipv6FragmentHeader::new_checked(payload) {
|
|
|
+ if let Ok(repr) = Ipv6FragmentRepr::parse(&frame) {
|
|
|
+ let mut buffer = vec![0; repr.buffer_len()];
|
|
|
+ let mut frame =
|
|
|
+ Ipv6FragmentHeader::new_unchecked(&mut buffer[..]);
|
|
|
+ repr.emit(&mut frame);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ IpProtocol::Icmpv6 => {
|
|
|
+ if let Ok(packet) = Icmpv6Packet::new_checked(payload) {
|
|
|
+ if let Ok(repr) = Icmpv6Repr::parse(
|
|
|
+ &iphc_repr.src_addr.into_address(),
|
|
|
+ &iphc_repr.dst_addr.into_address(),
|
|
|
+ &packet,
|
|
|
+ &ChecksumCapabilities::default(),
|
|
|
+ ) {
|
|
|
+ let mut buffer = vec![0; repr.buffer_len()];
|
|
|
+ let mut packet =
|
|
|
+ Icmpv6Packet::new_unchecked(&mut buffer[..]);
|
|
|
+ repr.emit(
|
|
|
+ &iphc_repr.src_addr.into_address(),
|
|
|
+ &iphc_repr.dst_addr.into_address(),
|
|
|
+ &mut packet,
|
|
|
+ &ChecksumCapabilities::default(),
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ IpProtocol::Ipv6NoNxt => (),
|
|
|
+ IpProtocol::Ipv6Opts => {
|
|
|
+ if let Ok(packet) = Ipv6Option::new_checked(payload) {
|
|
|
+ if let Ok(repr) = Ipv6OptionRepr::parse(&packet) {
|
|
|
+ let mut buffer = vec![0; repr.buffer_len()];
|
|
|
+ let mut packet = Ipv6Option::new_unchecked(&mut buffer[..]);
|
|
|
+ repr.emit(&mut packet);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ IpProtocol::Unknown(_) => (),
|
|
|
+ },
|
|
|
+ };
|
|
|
+
|
|
|
+ let mut buffer = vec![0; iphc_repr.buffer_len()];
|
|
|
+
|
|
|
+ let mut frame = SixlowpanIphcPacket::new_unchecked(&mut buffer[..]);
|
|
|
+ iphc_repr.emit(&mut frame);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+ Err(_) => (),
|
|
|
+ }
|
|
|
+});
|