Skip to main content

smoltcp/phy/
fuzz_injector.rs

1use crate::phy::{self, Device, DeviceCapabilities};
2use crate::time::Instant;
3use alloc::vec::Vec;
4
5// This could be fixed once associated consts are stable.
6const MTU: usize = 1536;
7
8/// Represents a fuzzer. It is expected to replace bytes in the packet with fuzzed data.
9pub trait Fuzzer {
10    /// Modify a single packet with fuzzed data.
11    fn fuzz_packet(&self, packet_data: &mut [u8]);
12}
13
14/// A fuzz injector device.
15///
16/// A fuzz injector is a device that alters packets traversing through it according to the
17/// directions of a guided fuzzer. It is designed to support fuzzing internal state machines inside
18/// smoltcp, and is not for production use.
19#[allow(unused)]
20#[derive(Debug)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22pub struct FuzzInjector<D: Device, FTx: Fuzzer, FRx: Fuzzer> {
23    inner: D,
24    fuzz_tx: FTx,
25    fuzz_rx: FRx,
26}
27
28#[allow(unused)]
29impl<D: Device, FTx: Fuzzer, FRx: Fuzzer> FuzzInjector<D, FTx, FRx> {
30    /// Create a fuzz injector device.
31    pub fn new(inner: D, fuzz_tx: FTx, fuzz_rx: FRx) -> FuzzInjector<D, FTx, FRx> {
32        FuzzInjector {
33            inner,
34            fuzz_tx,
35            fuzz_rx,
36        }
37    }
38
39    /// Return the underlying device, consuming the fuzz injector.
40    pub fn into_inner(self) -> D {
41        self.inner
42    }
43}
44
45impl<D: Device, FTx, FRx> Device for FuzzInjector<D, FTx, FRx>
46where
47    FTx: Fuzzer,
48    FRx: Fuzzer,
49{
50    type RxToken<'a>
51        = RxToken<'a, D::RxToken<'a>, FRx>
52    where
53        Self: 'a;
54    type TxToken<'a>
55        = TxToken<'a, D::TxToken<'a>, FTx>
56    where
57        Self: 'a;
58
59    fn capabilities(&self) -> DeviceCapabilities {
60        let mut caps = self.inner.capabilities();
61        if caps.max_transmission_unit > MTU {
62            caps.max_transmission_unit = MTU;
63        }
64        caps
65    }
66
67    fn receive(&mut self, timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
68        self.inner.receive(timestamp).map(|(rx_token, tx_token)| {
69            let rx = RxToken {
70                fuzzer: &mut self.fuzz_rx,
71                token: rx_token,
72            };
73            let tx = TxToken {
74                fuzzer: &mut self.fuzz_tx,
75                token: tx_token,
76            };
77            (rx, tx)
78        })
79    }
80
81    fn transmit(&mut self, timestamp: Instant) -> Option<Self::TxToken<'_>> {
82        self.inner.transmit(timestamp).map(|token| TxToken {
83            fuzzer: &mut self.fuzz_tx,
84            token: token,
85        })
86    }
87}
88
89#[doc(hidden)]
90pub struct RxToken<'a, Rx: phy::RxToken, F: Fuzzer + 'a> {
91    fuzzer: &'a F,
92    token: Rx,
93}
94
95impl<'a, Rx: phy::RxToken, FRx: Fuzzer> phy::RxToken for RxToken<'a, Rx, FRx> {
96    fn consume<R, F>(self, f: F) -> R
97    where
98        F: FnOnce(&[u8]) -> R,
99    {
100        self.token.consume(|buffer| {
101            let mut new_buffer: Vec<u8> = buffer.to_vec();
102            self.fuzzer.fuzz_packet(&mut new_buffer);
103            f(&mut new_buffer)
104        })
105    }
106
107    fn meta(&self) -> phy::PacketMeta {
108        self.token.meta()
109    }
110}
111
112#[doc(hidden)]
113pub struct TxToken<'a, Tx: phy::TxToken, F: Fuzzer + 'a> {
114    fuzzer: &'a F,
115    token: Tx,
116}
117
118impl<'a, Tx: phy::TxToken, FTx: Fuzzer> phy::TxToken for TxToken<'a, Tx, FTx> {
119    fn consume<R, F>(self, len: usize, f: F) -> R
120    where
121        F: FnOnce(&mut [u8]) -> R,
122    {
123        self.token.consume(len, |buf| {
124            let result = f(buf);
125            self.fuzzer.fuzz_packet(buf);
126            result
127        })
128    }
129
130    fn set_meta(&mut self, meta: phy::PacketMeta) {
131        self.token.set_meta(meta)
132    }
133}