Coverage Report

Created: 2025-12-08 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quiche/fuzz/src/lib.rs
Line
Count
Source
1
use std::path::Path;
2
use std::path::PathBuf;
3
4
use quiche::h3::NameValue;
5
6
pub struct PktsData<'a> {
7
    pub data: &'a [u8],
8
}
9
10
pub struct PktIterator<'a> {
11
    data: &'a [u8],
12
    index: usize,
13
}
14
15
impl<'a> Iterator for PktIterator<'a> {
16
    type Item = &'a [u8];
17
18
8.88M
    fn next(&mut self) -> Option<Self::Item> {
19
8.88M
        if self.index < self.data.len() {
20
8.86M
            let start = self.index;
21
8.86M
            if self.index + 4 <= self.data.len() {
22
365M
                for i in self.index..self.data.len() - 4 {
23
365M
                    if &self.data[i..i + 4] == b"fuzz" {
24
8.84M
                        self.index = i + 4;
25
8.84M
                        return Some(&self.data[start..i]);
26
356M
                    }
27
                }
28
985
            }
29
19.7k
            self.index = self.data.len();
30
19.7k
            Some(&self.data[start..])
31
        } else {
32
19.7k
            None
33
        }
34
8.88M
    }
35
}
36
37
impl<'a> PktsData<'a> {
38
19.7k
    pub fn iter(&self) -> PktIterator<'_> {
39
19.7k
        PktIterator {
40
19.7k
            data: self.data,
41
19.7k
            index: 0,
42
19.7k
        }
43
19.7k
    }
44
}
45
46
31.5k
pub fn reset_rand_for_fuzzing() {
47
    extern "C" {
48
        fn RAND_reset_for_fuzzing();
49
    }
50
51
31.5k
    unsafe { RAND_reset_for_fuzzing() };
52
31.5k
}
53
54
/// Returns the path to the X.509 certificate and key.
55
///
56
/// If `QUICHE_FUZZ_CRT` and / or `QUICHE_FUZZ_KEY` are set, their value is
57
/// used, otherwise in order to accomodate different fuzzing environments, this
58
/// either returns relative paths (e.g. "fuzz/cert.crt") when running from a
59
/// clone of the git repository, or absolute paths based on `argv[0]` when
60
/// running bare executable (as used by OSS-Fuzz).
61
3
pub fn get_cert_path() -> (String, String) {
62
3
    let fuzz_dir = if Path::new("fuzz/").exists() {
63
3
        PathBuf::from("fuzz/")
64
    } else {
65
        // Get directory the fuzzer is running from.
66
0
        let mut fuzz_dir = PathBuf::from(std::env::args().next().unwrap());
67
        // Remove executable file name.
68
0
        fuzz_dir.pop();
69
        // Add "fuzz" subdirectory.
70
0
        fuzz_dir.push("fuzz");
71
72
0
        fuzz_dir
73
    };
74
75
3
    let crt_path = std::env::var("QUICHE_FUZZ_CRT").unwrap_or_else(|_| {
76
3
        let mut crt_path = fuzz_dir.clone();
77
3
        crt_path.push("cert.crt");
78
3
        crt_path.to_str().unwrap().to_string()
79
3
    });
80
81
3
    let key_path = std::env::var("QUICHE_FUZZ_KEY").unwrap_or_else(|_| {
82
3
        let mut key_path = fuzz_dir.clone();
83
3
        key_path.push("cert.key");
84
3
        key_path.to_str().unwrap().to_string()
85
3
    });
86
87
3
    (crt_path, key_path)
88
3
}
89
90
8.86M
pub fn server_process(
91
8.86M
    pkt: &[u8], conn: &mut quiche::Connection,
92
8.86M
    h3_conn: &mut Option<quiche::h3::Connection>, info: quiche::RecvInfo,
93
8.86M
) {
94
8.86M
    let mut buf = pkt.to_vec();
95
8.86M
    conn.recv(&mut buf, info).ok();
96
97
8.86M
    if (conn.is_in_early_data() || conn.is_established()) && h3_conn.is_none() {
98
17.8k
        let h3_config = quiche::h3::Config::new().unwrap();
99
100
17.8k
        if let Ok(c) = quiche::h3::Connection::with_transport(conn, &h3_config) {
101
13.5k
            *h3_conn = Some(c);
102
13.5k
        }
103
8.84M
    }
104
105
8.86M
    if h3_conn.is_some() {
106
4.64M
        let h3c = h3_conn.as_mut().unwrap();
107
        loop {
108
4.64M
            let r = h3c.poll(conn);
109
110
6.48k
            match r {
111
                Ok((
112
260
                    _stream_id,
113
                    quiche::h3::Event::Headers {
114
260
                        list,
115
                        more_frames: _,
116
                    },
117
                )) => {
118
260
                    let mut headers = list.into_iter();
119
120
                    // Look for the request's method.
121
291
                    let method = headers.find(|h| h.name() == b":method");
122
260
                    if method.is_none() {
123
241
                        break;
124
19
                    }
125
19
                    let method = method.unwrap();
126
127
                    // Look for the request's path.
128
37
                    let path = headers.find(|h| h.name() == b":path");
129
19
                    if path.is_none() {
130
14
                        break;
131
5
                    }
132
5
                    let path = path.unwrap();
133
134
5
                    if method.value() == b"GET" && path.value() == b"/" {
135
3
                        let _resp = vec![
136
3
                            quiche::h3::Header::new(
137
3
                                b":status",
138
3
                                200.to_string().as_bytes(),
139
3
                            ),
140
3
                            quiche::h3::Header::new(b"server", b"quiche"),
141
3
                        ];
142
3
                    }
143
                },
144
145
203
                Ok((_stream_id, quiche::h3::Event::Data)) => {},
146
147
1.68k
                Ok((_stream_id, quiche::h3::Event::Finished)) => {},
148
149
4.32k
                Ok((_stream_id, quiche::h3::Event::Reset(_err))) => {},
150
151
0
                Ok((_flow_id, quiche::h3::Event::PriorityUpdate)) => {},
152
153
16
                Ok((_goaway_id, quiche::h3::Event::GoAway)) => {
154
16
                    // Peer signalled it is going away, handle it.
155
16
                },
156
157
                Err(quiche::h3::Error::Done) => {
158
                    // Done reading.
159
4.64M
                    break;
160
                },
161
162
711
                Err(_e) => {
163
                    // An error occurred, handle it.
164
711
                    break;
165
                },
166
            }
167
        }
168
4.22M
    }
169
170
8.86M
    let mut out_buf = [0; 1500];
171
10.2M
    while conn.send(&mut out_buf).is_ok() {}
172
8.86M
}