smoltcp/phy/
fuzz_injector.rs

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