@@ -155,7 +155,7 @@ impl StreamPacket {
155
155
/// # Errors
156
156
/// 1. If the version of Stream Protocol doesn't match the hardcoded [stream version](constant.STREAM_VERSION.html)
157
157
/// 1. If the decrypted bytes cannot be parsed to an unencrypted [Stream Packet](./struct.StreamPacket.html)
158
- fn from_bytes_unencrypted ( buffer_unencrypted : BytesMut ) -> Result < Self , ParseError > {
158
+ fn from_bytes_unencrypted ( mut buffer_unencrypted : BytesMut ) -> Result < Self , ParseError > {
159
159
// TODO don't copy the whole packet again
160
160
let mut reader = & buffer_unencrypted[ ..] ;
161
161
let version = reader. read_u8 ( ) ?;
@@ -173,13 +173,28 @@ impl StreamPacket {
173
173
let num_frames = reader. read_var_uint ( ) ?;
174
174
let frames_offset = buffer_unencrypted. len ( ) - reader. len ( ) ;
175
175
176
- // Try reading through all the frames to make sure they can be parsed correctly
176
+ let mut reader = & buffer_unencrypted[ frames_offset..] ;
177
+ for _ in 0 ..num_frames {
178
+ // First byte is the frame type
179
+ reader. skip ( 1 ) ?;
180
+ reader. skip_var_octet_string ( ) ?;
181
+ }
182
+
183
+ let junk_data_len = reader. len ( ) ;
184
+
185
+ if junk_data_len > 0 {
186
+ // trailing bytes are supported for future compatibility, see
187
+ // https://github.com/interledger/rfcs/blob/master/0029-stream/0029-stream.md#52-stream-packet
188
+ let _ = buffer_unencrypted. split_off ( buffer_unencrypted. len ( ) - junk_data_len) ;
189
+ }
190
+
177
191
if num_frames
178
192
== ( FrameIterator {
179
193
buffer : & buffer_unencrypted[ frames_offset..] ,
180
194
} )
181
195
. count ( ) as u64
182
196
{
197
+ // Try reading through all the frames to make sure they can be parsed correctly
183
198
Ok ( StreamPacket {
184
199
buffer_unencrypted,
185
200
sequence,
@@ -305,14 +320,15 @@ impl<'a> Iterator for FrameIterator<'a> {
305
320
type Item = Frame < ' a > ;
306
321
307
322
fn next ( & mut self ) -> Option < Self :: Item > {
308
- while !self . buffer . is_empty ( ) {
309
- // TODO don't ignore errors if the packet is just invalid
323
+ if !self . buffer . is_empty ( ) {
310
324
match self . try_read_next_frame ( ) {
311
325
Ok ( frame) => return Some ( frame) ,
312
- Err ( err) => warn ! ( "Error reading STREAM frame: {:?}" , err) ,
326
+ Err ( err) => {
327
+ warn ! ( "Error reading STREAM frame: {:?}" , err) ;
328
+ return None ;
329
+ }
313
330
}
314
331
}
315
-
316
332
None
317
333
}
318
334
}
@@ -868,23 +884,25 @@ fn saturating_read_var_uint<'a>(reader: &mut impl BufOerExt<'a>) -> Result<u64,
868
884
#[ cfg( test) ]
869
885
mod fuzzing {
870
886
use super :: { StreamPacket , StreamPacketBuilder } ;
887
+ use bytes:: { Buf , BytesMut } ;
871
888
872
889
#[ test]
873
- #[ ignore]
874
890
fn fuzzed_0_extra_trailer_bytes ( ) {
875
- // junk trailer mentioned in RFC might be applicable here, see
876
- // fuzzed_1_unknown_frames_dont_roundtrip
877
- roundtrip ( & [
878
- 1 , 14 , 3 , 19 , 5 , 3 , 1 , 14 , 3 , 0 , 0 , 0 , 0 , 14 , 3 , 0 , 14 , 5 , 17 ,
879
- ] ) ;
880
-
881
- // roundtripped version looks like:
882
- //
883
- // [1, 14, 3, 19, 5, 3, 1, 14, 1, 0]
884
- // ^
885
- // differs, was 3
891
+ // From the [RFC]'s it sounds like the at least trailer junk should be kept around,
892
+ // but only under the condition that they are zero-bytes and MUST be ignored in parsing.
893
+ // For Fuzzing, at least, we remove the extra bytes for roundtripping support.
886
894
//
887
- // which is almost &input[0..10] except
895
+ // [RFC]: https://github.com/interledger/rfcs/blob/master/0029-stream/0029-stream.md#52-stream-packet
896
+ #[ rustfmt:: skip]
897
+ let input: & [ u8 ] = & [
898
+ // Version, packet type, sequence and prepare amount
899
+ 1 , 14 , 1 , 0 , 1 , 0 ,
900
+ // num frames
901
+ 1 , 0 ,
902
+ // junk data since zero frames
903
+ 0 , 31 , 31 , 31 , 0 , 96 , 17 ] ;
904
+
905
+ roundtrip ( input) ;
888
906
}
889
907
890
908
#[ test]
@@ -906,9 +924,63 @@ mod fuzzing {
906
924
// which is &input[0..12]
907
925
}
908
926
909
- fn roundtrip ( input : & [ u8 ] ) {
910
- use bytes:: { Buf , BytesMut } ;
927
+ #[ test]
928
+ fn fuzzed_2_frame_data_with_parse_error_should_error ( ) {
929
+ // TODO: The input for this test is from a test
930
+ // (fuzzed_1_unknown_frames_dont_roundtrip)
931
+ // identifying a roundtripping problem when Unknown frames are in the packet data.
932
+ // That problem is still present but needs new set of data
933
+
934
+ #[ rustfmt:: skip]
935
+ let input: & [ u8 ] = & [
936
+ // Version
937
+ 1 ,
938
+ // Packet type
939
+ 14 ,
940
+ // len + Sequence
941
+ 3 , 5 , 0 , 0 ,
942
+ // len + Prepare amount
943
+ 3 , 5 , 14 , 9 ,
944
+ // len + num frame
945
+ 1 , 3 ,
946
+ // frame type - ConnectionClose
947
+ 1 ,
948
+ // len + frame content
949
+ // This content does not parse successfully as ConnectionCloseFrame
950
+ 3 , 0 , 4 , 20 ,
951
+ // rest of frames and junk data
952
+ 3 , 7 , 14 , 5 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
953
+ ] ;
954
+ let b = BytesMut :: from ( input) ;
955
+ let pkt = StreamPacket :: from_decrypted ( b) ;
911
956
957
+ assert_eq ! (
958
+ "Invalid Packet: Incorrect number of frames or unable to parse all frames" ,
959
+ format!( "{}" , pkt. unwrap_err( ) )
960
+ ) ;
961
+ }
962
+
963
+ #[ test]
964
+ #[ ignore]
965
+ fn fuzzed_3 ( ) {
966
+ #[ rustfmt:: skip]
967
+ let input: & [ u8 ] = & [
968
+ // Version, packet type, sequence and prepare amount
969
+ 1 , 14 , 1 , 14 , 1 , 14 ,
970
+ // num frames
971
+ 1 , 1 ,
972
+ // frame data (frame type + content)
973
+ 1 , 14 , 1 , 0 , 1 , 1 , 4 , 0 , 255 , 255 , 255 , 255 , 255 , 128 , 255 , 128
974
+ ] ;
975
+
976
+ // roundtrip result
977
+ // [1, 14, 1, 14, 1, 14, 1, 1, 1, 2, 1, 0]
978
+ // ^ ----^
979
+ // Suspect due to content prefix length
980
+ roundtrip ( input) ;
981
+ }
982
+
983
+ fn roundtrip ( input : & [ u8 ] ) {
912
984
// this started off as almost copy of crate::fuzz_decrypted_stream_packet but should be
913
985
// extended if necessary
914
986
let b = BytesMut :: from ( input) ;
0 commit comments