s2n_quic_core/
havoc.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{
5    frame::{self, new_connection_id::STATELESS_RESET_TOKEN_LEN},
6    stream::StreamType,
7    varint,
8};
9use core::ops::Range;
10pub use s2n_codec::{Encoder, EncoderBuffer, EncoderValue};
11
12pub trait Random {
13    fn fill(&mut self, bytes: &mut [u8]);
14
15    fn gen_range(&mut self, range: Range<u64>) -> u64;
16
17    #[inline]
18    fn shuffle(&mut self, bytes: &mut [u8]) {
19        if bytes.is_empty() {
20            return;
21        }
22
23        let len = bytes.len() as u64;
24
25        let count = self.gen_range(0..len);
26        for _ in 0..count {
27            let from = self.gen_range(0..len);
28            let to = self.gen_range(0..len);
29            bytes.swap(from as usize, to as usize);
30        }
31    }
32
33    #[inline]
34    fn gen_slice<'a>(&mut self, bytes: &'a mut [u8]) -> &'a mut [u8] {
35        if bytes.is_empty() {
36            return bytes;
37        }
38
39        let len = bytes.len() as u64;
40        let len = self.gen_range(0..len);
41        let bytes = &mut bytes[..len as usize];
42        self.fill(bytes);
43        bytes
44    }
45
46    #[inline]
47    fn gen_bool(&mut self) -> bool {
48        self.gen_u8() & 0b1 == 0b1
49    }
50
51    #[inline]
52    fn gen_u8(&mut self) -> u8 {
53        let mut o = [0];
54        self.fill(&mut o);
55        o[0]
56    }
57
58    #[inline]
59    fn gen_u32(&mut self) -> u32 {
60        let mut o = [0; 4];
61        self.fill(&mut o);
62        u32::from_le_bytes(o)
63    }
64
65    #[inline]
66    fn gen_u64(&mut self) -> u64 {
67        let mut o = [0; 8];
68        self.fill(&mut o);
69        u64::from_le_bytes(o)
70    }
71
72    #[inline]
73    fn gen_varint(&mut self) -> varint::VarInt {
74        use varint::VarInt;
75        let max = VarInt::MAX.as_u64();
76        let v = self.gen_range(0..(max + 1));
77        unsafe { VarInt::new_unchecked(v as _) }
78    }
79}
80
81pub trait Strategy: Sized {
82    /// Applies the havoc strategy to the supplied buffer
83    fn havoc<R: Random>(&mut self, rand: &mut R, buffer: &mut EncoderBuffer);
84
85    /// Applies the havoc strategy to the supplied buffer slice and returns the new buffer length
86    #[inline]
87    fn havoc_slice<R: Random>(&mut self, rand: &mut R, buffer: &mut [u8]) -> usize {
88        let mut buffer = EncoderBuffer::new(buffer);
89        self.havoc(rand, &mut buffer);
90        buffer.len()
91    }
92
93    /// Applies the havoc strategy to the given `u16` value and returns the new `u16` result
94    #[inline]
95    fn havoc_u16<R: Random>(&mut self, rand: &mut R, input: u16) -> u16 {
96        let buffer = &mut [0; 2];
97        let mut buffer = EncoderBuffer::new(buffer);
98        buffer.encode(&input);
99
100        self.havoc(rand, &mut buffer);
101
102        buffer
103            .as_mut_slice()
104            .try_into()
105            .map(u16::from_be_bytes)
106            .unwrap_or(input)
107    }
108
109    /// Alternate between two strategies with the supplied `period`
110    fn alternate<B: Strategy>(self, b: B, period: Range<usize>) -> Alternate<Self, B> {
111        Alternate::new(self, b, period)
112    }
113
114    /// Apply the strategy `count` times
115    fn repeat(self, count: Range<usize>) -> Repeat<Self> {
116        Repeat::new(self, count)
117    }
118
119    /// Randomly apply the strategy
120    fn randomly(self) -> Randomly<Self> {
121        Randomly { strategy: self }
122    }
123
124    /// Toggle the strategy on and off for the supplied `period`
125    fn toggle(self, period: Range<usize>) -> Toggle<Self> {
126        Toggle::new(self, period)
127    }
128
129    /// Applies two strategies in order
130    fn and_then<B: Strategy>(self, b: B) -> AndThen<Self, B> {
131        AndThen { a: self, b }
132    }
133
134    /// Repeatedly applies the strategy as long as the buffer has capacity
135    fn while_has_capacity(self) -> WhileHasCapacity<Self> {
136        WhileHasCapacity { strategy: self }
137    }
138
139    /// Applies the strategy and holds the result `count` times
140    #[cfg(feature = "alloc")]
141    fn hold(self, count: Range<usize>) -> Hold<Self> {
142        Hold::new(self, count)
143    }
144}
145
146impl<T: Strategy> Strategy for Option<T> {
147    fn havoc<R: Random>(&mut self, rand: &mut R, buffer: &mut EncoderBuffer) {
148        if let Some(strategy) = self.as_mut() {
149            strategy.havoc(rand, buffer);
150        }
151    }
152}
153
154#[derive(Clone, Copy, Debug, Default)]
155pub struct Alternate<A: Strategy, B: Strategy> {
156    a: A,
157    b: B,
158    min: u64,
159    max: u64,
160    is_a: bool,
161    remaining: u64,
162    init: bool,
163}
164
165impl<A: Strategy, B: Strategy> Alternate<A, B> {
166    pub fn new(a: A, b: B, range: Range<usize>) -> Self {
167        debug_assert_ne!(range.start, 0);
168        debug_assert!(range.start <= range.end);
169        Self {
170            a,
171            b,
172            min: range.start as _,
173            max: range.end as _,
174            is_a: false,
175            remaining: 0,
176            init: false,
177        }
178    }
179}
180
181impl<A: Strategy, B: Strategy> Strategy for Alternate<A, B> {
182    #[inline]
183    fn havoc<R: Random>(&mut self, rand: &mut R, buffer: &mut EncoderBuffer) {
184        // initialize the strategy to a random arm
185        if !self.init {
186            self.init = true;
187            self.is_a = rand.gen_bool();
188        }
189
190        loop {
191            if let Some(remaining) = self.remaining.checked_sub(1) {
192                self.remaining = remaining;
193
194                if self.is_a {
195                    self.a.havoc(rand, buffer);
196                } else {
197                    self.b.havoc(rand, buffer);
198                }
199
200                break;
201            }
202
203            self.remaining = rand.gen_range(self.min..self.max);
204            self.is_a = !self.is_a;
205        }
206    }
207}
208
209#[derive(Clone, Copy, Debug, Default)]
210pub struct AndThen<A: Strategy, B: Strategy> {
211    pub a: A,
212    pub b: B,
213}
214
215impl<A: Strategy, B: Strategy> Strategy for AndThen<A, B> {
216    #[inline]
217    fn havoc<R: Random>(&mut self, rand: &mut R, buffer: &mut EncoderBuffer) {
218        self.a.havoc(rand, buffer);
219        self.b.havoc(rand, buffer);
220    }
221}
222
223#[derive(Clone, Copy, Debug, Default)]
224pub struct Repeat<S: Strategy> {
225    strategy: S,
226    min: u64,
227    max: u64,
228}
229
230impl<S: Strategy> Repeat<S> {
231    pub fn new(strategy: S, range: Range<usize>) -> Self {
232        Self {
233            strategy,
234            min: range.start as _,
235            max: range.end as _,
236        }
237    }
238}
239
240impl<S: Strategy> Strategy for Repeat<S> {
241    #[inline]
242    fn havoc<R: Random>(&mut self, rand: &mut R, buffer: &mut EncoderBuffer) {
243        let count = rand.gen_range(self.min..self.max);
244        for _ in 0..count {
245            self.strategy.havoc(rand, buffer);
246        }
247    }
248}
249
250#[derive(Clone, Copy, Debug, Default)]
251pub struct WhileHasCapacity<S: Strategy> {
252    strategy: S,
253}
254
255impl<S: Strategy> WhileHasCapacity<S> {
256    pub fn new(strategy: S) -> Self {
257        Self { strategy }
258    }
259}
260
261impl<S: Strategy> Strategy for WhileHasCapacity<S> {
262    #[inline]
263    fn havoc<R: Random>(&mut self, rand: &mut R, buffer: &mut EncoderBuffer) {
264        // limit the number of iterations in case the strategy isn't filling the buffer
265        for _ in 0..25 {
266            if !buffer.remaining_capacity() == 0 {
267                break;
268            }
269
270            self.strategy.havoc(rand, buffer);
271        }
272    }
273}
274
275#[derive(Clone, Copy, Debug, Default)]
276pub struct Toggle<S: Strategy> {
277    alt: Alternate<Disabled, S>,
278}
279
280impl<S: Strategy> Toggle<S> {
281    pub fn new(strategy: S, range: Range<usize>) -> Self {
282        Self {
283            alt: Alternate::new(Disabled, strategy, range),
284        }
285    }
286}
287
288impl<S: Strategy> Strategy for Toggle<S> {
289    #[inline]
290    fn havoc<R: Random>(&mut self, rand: &mut R, buffer: &mut EncoderBuffer) {
291        self.alt.havoc(rand, buffer);
292    }
293}
294
295#[derive(Clone, Copy, Debug, Default)]
296pub struct Randomly<S: Strategy> {
297    pub strategy: S,
298}
299
300impl<S: Strategy> Strategy for Randomly<S> {
301    #[inline]
302    fn havoc<R: Random>(&mut self, rand: &mut R, buffer: &mut EncoderBuffer) {
303        if rand.gen_bool() {
304            self.strategy.havoc(rand, buffer);
305        }
306    }
307}
308
309#[derive(Clone, Copy, Debug, Default)]
310pub struct Reset;
311
312impl Strategy for Reset {
313    #[inline]
314    fn havoc<R: Random>(&mut self, _rand: &mut R, buffer: &mut EncoderBuffer) {
315        buffer.set_position(0);
316    }
317}
318
319#[derive(Clone, Copy, Debug, Default)]
320pub struct Zero;
321
322impl Strategy for Zero {
323    #[inline]
324    fn havoc<R: Random>(&mut self, _rand: &mut R, buffer: &mut EncoderBuffer) {
325        for byte in buffer.as_mut_slice() {
326            *byte = 0;
327        }
328    }
329}
330
331#[derive(Clone, Copy, Debug, Default)]
332pub struct Shuffle;
333
334impl Strategy for Shuffle {
335    #[inline]
336    fn havoc<R: Random>(&mut self, rand: &mut R, buffer: &mut EncoderBuffer) {
337        if !buffer.is_empty() {
338            rand.shuffle(buffer.as_mut_slice());
339        }
340    }
341}
342
343#[derive(Clone, Copy, Debug, Default)]
344pub struct Swap;
345
346impl Strategy for Swap {
347    #[inline]
348    fn havoc<R: Random>(&mut self, rand: &mut R, buffer: &mut EncoderBuffer) {
349        let len = buffer.len() as u64;
350        if len > 0 {
351            let from = rand.gen_range(0..len) as usize;
352            let to = rand.gen_range(0..len) as usize;
353            buffer.as_mut_slice().swap(from, to);
354        }
355    }
356}
357
358#[derive(Clone, Copy, Debug, Default)]
359pub struct Truncate;
360
361impl Strategy for Truncate {
362    #[inline]
363    fn havoc<R: Random>(&mut self, rand: &mut R, buffer: &mut EncoderBuffer) {
364        let len = buffer.capacity() as u64;
365        if len > 0 {
366            let new_len = rand.gen_range(0..len) as usize;
367            buffer.set_position(new_len);
368        }
369    }
370}
371
372#[derive(Clone, Copy, Debug, Default)]
373pub struct Mutate;
374
375impl Strategy for Mutate {
376    #[inline]
377    fn havoc<R: Random>(&mut self, rand: &mut R, buffer: &mut EncoderBuffer) {
378        let len = buffer.len() as u64;
379        if len > 0 {
380            let index = rand.gen_range(0..len) as usize;
381            let value = rand.gen_u8();
382            buffer.as_mut_slice()[index] = value;
383        }
384    }
385}
386
387#[derive(Clone, Copy, Debug, Default)]
388pub struct Disabled;
389
390impl Strategy for Disabled {
391    #[inline]
392    fn havoc<R: Random>(&mut self, _rand: &mut R, _buffer: &mut EncoderBuffer) {}
393}
394
395#[cfg(feature = "alloc")]
396pub use hold::Hold;
397
398#[cfg(feature = "alloc")]
399mod hold {
400    use super::*;
401    use alloc::vec::Vec;
402
403    #[derive(Clone, Debug, Default)]
404    pub struct Hold<S: Strategy> {
405        strategy: S,
406        min: u64,
407        max: u64,
408        value: Vec<u8>,
409        remaining: u64,
410    }
411
412    impl<S: Strategy> Hold<S> {
413        pub fn new(strategy: S, range: Range<usize>) -> Self {
414            debug_assert!(range.start <= range.end);
415            Self {
416                strategy,
417                min: range.start as _,
418                max: range.end as _,
419                value: Vec::new(),
420                remaining: 0,
421            }
422        }
423    }
424
425    impl<S: Strategy> Strategy for Hold<S> {
426        #[inline]
427        fn havoc<R: Random>(&mut self, rand: &mut R, buffer: &mut EncoderBuffer) {
428            if self.remaining == 0 {
429                self.strategy.havoc(rand, buffer);
430                // store the value after the strategy has been applied
431                self.value.clear();
432                self.value.extend_from_slice(buffer.as_mut_slice());
433                self.remaining = rand.gen_range(self.min..self.max);
434            } else {
435                if !self.value.is_empty() {
436                    // restore the value from the first application of the strategy
437                    let len = buffer.capacity().min(self.value.len());
438                    buffer.set_position(0);
439                    buffer.write_slice(&self.value.as_mut_slice()[..len]);
440                }
441                self.remaining -= 1;
442            }
443        }
444    }
445}
446
447#[derive(Clone, Copy, Debug, Default)]
448pub struct VarInt {
449    min: u64,
450    max: u64,
451}
452
453impl VarInt {
454    pub fn new(range: Range<varint::VarInt>) -> Self {
455        let min = range.start.as_u64();
456        let max = range.end.as_u64();
457        Self { min, max }
458    }
459}
460
461impl Strategy for VarInt {
462    #[inline]
463    fn havoc<R: Random>(&mut self, rand: &mut R, buffer: &mut EncoderBuffer) {
464        let value = rand.gen_range(self.min..self.max);
465        let value: varint::VarInt = value.try_into().unwrap();
466        if value.encoding_size() <= buffer.remaining_capacity() {
467            buffer.encode(&value);
468        }
469    }
470}
471
472#[derive(Clone, Debug)]
473pub struct Frame;
474
475impl Strategy for Frame {
476    #[inline]
477    fn havoc<R: Random>(&mut self, rand: &mut R, buffer: &mut EncoderBuffer) {
478        type GenFrame<R> = for<'a> fn(
479            rand: &'a mut R,
480            payload: &'a mut [u8],
481            remaining_capacity: usize,
482        ) -> frame::Frame<'a, AckRanges<'a, R>, &'a mut [u8]>;
483
484        let frames: &[GenFrame<R>] = &[
485            |rand, _data, cap| {
486                frame::Padding {
487                    length: rand.gen_range(1..cap as _) as _,
488                }
489                .into()
490            },
491            |_rand, _data, _cap| frame::Ping.into(),
492            // TODO ACK
493            |rand, _data, _cap| {
494                frame::ResetStream {
495                    stream_id: rand.gen_varint(),
496                    application_error_code: rand.gen_varint(),
497                    final_size: rand.gen_varint(),
498                }
499                .into()
500            },
501            |rand, _data, _cap| {
502                frame::StopSending {
503                    stream_id: rand.gen_varint(),
504                    application_error_code: rand.gen_varint(),
505                }
506                .into()
507            },
508            |rand, data, cap| {
509                let data = rand.gen_slice(&mut data[..cap]);
510                frame::Crypto {
511                    offset: rand.gen_varint(),
512                    data,
513                }
514                .into()
515            },
516            |rand, data, cap| {
517                let token = rand.gen_slice(&mut data[..cap]);
518                frame::NewToken { token }.into()
519            },
520            |rand, data, cap| {
521                let data = rand.gen_slice(&mut data[..cap]);
522                frame::Stream {
523                    stream_id: rand.gen_varint(),
524                    offset: rand.gen_varint(),
525                    data,
526                    is_last_frame: rand.gen_bool(),
527                    is_fin: rand.gen_bool(),
528                }
529                .into()
530            },
531            |rand, _data, _cap| {
532                frame::MaxData {
533                    maximum_data: rand.gen_varint(),
534                }
535                .into()
536            },
537            |rand, _data, _cap| {
538                frame::MaxStreamData {
539                    stream_id: rand.gen_varint(),
540                    maximum_stream_data: rand.gen_varint(),
541                }
542                .into()
543            },
544            |rand, _data, _cap| {
545                frame::MaxStreams {
546                    stream_type: if rand.gen_bool() {
547                        StreamType::Unidirectional
548                    } else {
549                        StreamType::Bidirectional
550                    },
551                    maximum_streams: rand.gen_varint(),
552                }
553                .into()
554            },
555            |rand, _data, _cap| {
556                frame::DataBlocked {
557                    data_limit: rand.gen_varint(),
558                }
559                .into()
560            },
561            |rand, _data, _cap| {
562                frame::StreamDataBlocked {
563                    stream_id: rand.gen_varint(),
564                    stream_data_limit: rand.gen_varint(),
565                }
566                .into()
567            },
568            |rand, _data, _cap| {
569                frame::StreamsBlocked {
570                    stream_type: if rand.gen_bool() {
571                        StreamType::Unidirectional
572                    } else {
573                        StreamType::Bidirectional
574                    },
575                    stream_limit: rand.gen_varint(),
576                }
577                .into()
578            },
579            |rand, data, cap| {
580                let (stateless_reset_token, data) = data.split_at_mut(STATELESS_RESET_TOKEN_LEN);
581
582                rand.fill(stateless_reset_token);
583                let stateless_reset_token = (&*stateless_reset_token).try_into().unwrap();
584
585                // connection ID lengths are encoded with a u8
586                let cap = cap.min(u8::MAX as usize);
587                let connection_id = rand.gen_slice(&mut data[..cap]);
588
589                frame::NewConnectionId {
590                    sequence_number: rand.gen_varint(),
591                    retire_prior_to: rand.gen_varint(),
592                    connection_id,
593                    stateless_reset_token,
594                }
595                .into()
596            },
597            |rand, _data, _cap| {
598                frame::RetireConnectionId {
599                    sequence_number: rand.gen_varint(),
600                }
601                .into()
602            },
603            |rand, data, _cap| {
604                let data = &mut data[..frame::path_challenge::DATA_LEN];
605                rand.fill(data);
606                let data = (&*data).try_into().unwrap();
607                frame::PathChallenge { data }.into()
608            },
609            |rand, data, _cap| {
610                let data = &mut data[..frame::path_challenge::DATA_LEN];
611                rand.fill(data);
612                let data = (&*data).try_into().unwrap();
613                frame::PathResponse { data }.into()
614            },
615            |rand, data, cap| {
616                frame::ConnectionClose {
617                    error_code: rand.gen_varint(),
618                    frame_type: if rand.gen_bool() {
619                        Some(rand.gen_varint())
620                    } else {
621                        None
622                    },
623                    reason: if rand.gen_bool() {
624                        let reason = rand.gen_slice(&mut data[..cap]);
625                        Some(reason)
626                    } else {
627                        None
628                    },
629                }
630                .into()
631            },
632            |_rand, _data, _cap| frame::HandshakeDone.into(),
633            |rand, data, cap| {
634                let data = rand.gen_slice(&mut data[..cap]);
635                frame::Datagram {
636                    is_last_frame: rand.gen_bool(),
637                    data,
638                }
639                .into()
640            },
641        ];
642
643        let index = rand.gen_range(0..frames.len() as u64) as usize;
644        let mut payload = [0u8; 16_000];
645        let frame = frames[index](rand, &mut payload, buffer.remaining_capacity());
646
647        if frame.encoding_size() <= buffer.remaining_capacity() {
648            buffer.encode(&frame);
649        }
650    }
651}
652
653// TODO implement this without allocating a bunch for the entries
654struct AckRanges<'a, R> {
655    #[allow(dead_code)]
656    rand: &'a mut R,
657}
658
659impl<'a, R> frame::ack::AckRanges for AckRanges<'a, R> {
660    type Iter = frame::ack::AckRangesIter<'a>;
661
662    fn ack_ranges(&self) -> Self::Iter {
663        todo!()
664    }
665
666    fn largest_acknowledged(&self) -> crate::varint::VarInt {
667        todo!()
668    }
669}
670
671#[cfg(any(test, feature = "testing"))]
672pub mod testing {
673    use super::*;
674
675    pub struct RandomSlice<'a>(core::iter::Cycle<core::slice::Iter<'a, u8>>);
676
677    impl<'a> RandomSlice<'a> {
678        pub fn new(slice: &'a [u8]) -> Self {
679            Self(slice.iter().cycle())
680        }
681    }
682
683    impl Random for RandomSlice<'_> {
684        #[inline]
685        fn fill(&mut self, bytes: &mut [u8]) {
686            for byte in bytes.iter_mut() {
687                *byte = *self.0.next().unwrap_or(&0);
688            }
689        }
690
691        #[inline]
692        fn gen_range(&mut self, range: Range<u64>) -> u64 {
693            let start = range.start.min(range.end);
694            let end = range.start.max(range.end);
695
696            // this method is biased and should not be used outside of this test
697
698            let variance = end - start;
699
700            // check to see if they're the same number
701            if variance == 0 {
702                return start;
703            }
704
705            let value = self.gen_u64();
706            start + value % variance
707        }
708    }
709}
710
711#[cfg(test)]
712mod tests {
713    use super::{testing::RandomSlice, *};
714    use bolero::check;
715
716    macro_rules! test {
717        ($name:ident, $strategy:expr) => {
718            #[test]
719            #[cfg_attr(miri, ignore)] // no need to test with miri as there isn't any unsafe
720            fn $name() {
721                check!().for_each(|bytes| {
722                    let mut rand = RandomSlice::new(bytes);
723                    let mut buffer = [0u8; 256];
724                    let buffer = &mut buffer[..rand.gen_u8() as usize];
725                    let mut buffer = EncoderBuffer::new(buffer);
726
727                    let mut strategy = $strategy;
728
729                    for _ in 0..rand.gen_range(1..10) {
730                        strategy.havoc(&mut rand, &mut buffer);
731                    }
732                });
733            }
734        };
735    }
736
737    test!(disabled_test, Disabled);
738    test!(truncate_test, Truncate);
739    test!(reset_test, Reset);
740    test!(zero_test, Zero);
741    test!(swap_test, Swap);
742    test!(shuffle_test, Shuffle);
743    test!(mutate_test, Mutate);
744    test!(alternate_test, Disabled.alternate(Disabled, 1..5));
745    test!(and_then_test, Disabled.and_then(Disabled));
746    test!(repeat_test, Disabled.repeat(0..5));
747    test!(varint_test, VarInt::new(0u8.into()..42u8.into()));
748    test!(frame_test, Frame);
749    test!(while_has_capacity_test, Frame.while_has_capacity());
750    test!(toggle_test, Disabled.toggle(1..5));
751    test!(randomly_test, Disabled.randomly());
752    test!(hold_test, Disabled.hold(0..5));
753}