@@ -5,7 +5,20 @@ use std::collections::HashMap;
55use std:: io:: Read ;
66use std:: sync:: Arc ;
77
8- use bincode:: { DefaultOptions , Options } ;
8+ use bincode:: config;
9+ use bincode:: config:: { Configuration , Fixint , Limit , LittleEndian } ;
10+
11+ // This byte limit is passed to `bincode` to guard against a potential memory
12+ // allocation DOS caused by binary filters that are too large.
13+ // This limit can be safely determined since the maximum length of a BPF
14+ // filter is 4096 instructions and Firecracker has a finite number of threads.
15+ const DESERIALIZATION_BYTES_LIMIT : usize = 100_000 ;
16+
17+ const BINCODE_CONFIG : Configuration < LittleEndian , Fixint , Limit < DESERIALIZATION_BYTES_LIMIT > > =
18+ config:: standard ( )
19+ . with_fixed_int_encoding ( )
20+ . with_limit :: < DESERIALIZATION_BYTES_LIMIT > ( )
21+ . with_little_endian ( ) ;
922
1023/// Each BPF instruction is 8 bytes long and 4 byte aligned.
1124/// This alignment needs to be satisfied in order for a BPF code to be accepted
@@ -22,7 +35,7 @@ pub type BpfProgramRef<'a> = &'a [BpfInstruction];
2235pub type BpfThreadMap = HashMap < String , Arc < BpfProgram > > ;
2336
2437/// Binary filter deserialization errors.
25- pub type DeserializationError = bincode:: Error ;
38+ pub type DeserializationError = bincode:: error :: DecodeError ;
2639
2740/// Retrieve empty seccomp filters.
2841pub fn get_empty_filters ( ) -> BpfThreadMap {
@@ -34,19 +47,8 @@ pub fn get_empty_filters() -> BpfThreadMap {
3447}
3548
3649/// Deserialize binary with bpf filters
37- pub fn deserialize_binary < R : Read > (
38- reader : R ,
39- bytes_limit : Option < u64 > ,
40- ) -> Result < BpfThreadMap , DeserializationError > {
41- let result = match bytes_limit {
42- Some ( limit) => DefaultOptions :: new ( )
43- . with_fixint_encoding ( )
44- . allow_trailing_bytes ( )
45- . with_limit ( limit)
46- . deserialize_from :: < R , HashMap < String , BpfProgram > > ( reader) ,
47- // No limit is the default.
48- None => bincode:: deserialize_from :: < R , HashMap < String , BpfProgram > > ( reader) ,
49- } ?;
50+ pub fn deserialize_binary < R : Read > ( mut reader : R ) -> Result < BpfThreadMap , DeserializationError > {
51+ let result: HashMap < String , _ > = bincode:: decode_from_std_read ( & mut reader, BINCODE_CONFIG ) ?;
5052
5153 Ok ( result
5254 . into_iter ( )
@@ -134,49 +136,28 @@ mod tests {
134136 #[ test]
135137 fn test_deserialize_binary ( ) {
136138 // Malformed bincode binary.
137- {
138- let data = "adassafvc" . to_string ( ) ;
139- deserialize_binary ( data. as_bytes ( ) , None ) . unwrap_err ( ) ;
140- }
139+ let data = "adassafvc" . to_string ( ) ;
140+ deserialize_binary ( data. as_bytes ( ) ) . unwrap_err ( ) ;
141141
142142 // Test that the binary deserialization is correct, and that the thread keys
143143 // have been lowercased.
144- {
145- let bpf_prog = vec ! [ 0 ; 2 ] ;
146- let mut filter_map: HashMap < String , BpfProgram > = HashMap :: new ( ) ;
147- filter_map. insert ( "VcpU" . to_string ( ) , bpf_prog. clone ( ) ) ;
148- let bytes = bincode:: serialize ( & filter_map) . unwrap ( ) ;
149-
150- let mut expected_res = BpfThreadMap :: new ( ) ;
151- expected_res. insert ( "vcpu" . to_string ( ) , Arc :: new ( bpf_prog) ) ;
152- assert_eq ! ( deserialize_binary( & bytes[ ..] , None ) . unwrap( ) , expected_res) ;
153- }
154-
155- // Test deserialization with binary_limit.
156- {
157- let bpf_prog = vec ! [ 0 ; 2 ] ;
158-
159- let mut filter_map: HashMap < String , BpfProgram > = HashMap :: new ( ) ;
160- filter_map. insert ( "t1" . to_string ( ) , bpf_prog. clone ( ) ) ;
161-
162- let bytes = bincode:: serialize ( & filter_map) . unwrap ( ) ;
163-
164- // Binary limit too low.
165- assert ! ( matches!(
166- deserialize_binary( & bytes[ ..] , Some ( 20 ) ) . unwrap_err( ) ,
167- error
168- if error. to_string( ) == "the size limit has been reached"
169- ) ) ;
170-
171- let mut expected_res = BpfThreadMap :: new ( ) ;
172- expected_res. insert ( "t1" . to_string ( ) , Arc :: new ( bpf_prog) ) ;
173-
174- // Correct binary limit.
175- assert_eq ! (
176- deserialize_binary( & bytes[ ..] , Some ( 50 ) ) . unwrap( ) ,
177- expected_res
178- ) ;
179- }
144+ let bpf_prog = vec ! [ 0 ; 2 ] ;
145+ let mut filter_map: HashMap < String , BpfProgram > = HashMap :: new ( ) ;
146+ filter_map. insert ( "VcpU" . to_string ( ) , bpf_prog. clone ( ) ) ;
147+ let bytes = bincode:: serde:: encode_to_vec ( & filter_map, BINCODE_CONFIG ) . unwrap ( ) ;
148+
149+ let mut expected_res = BpfThreadMap :: new ( ) ;
150+ expected_res. insert ( "vcpu" . to_string ( ) , Arc :: new ( bpf_prog) ) ;
151+ assert_eq ! ( deserialize_binary( & bytes[ ..] ) . unwrap( ) , expected_res) ;
152+
153+ let bpf_prog = vec ! [ 0 ; DESERIALIZATION_BYTES_LIMIT + 1 ] ;
154+ let mut filter_map: HashMap < String , BpfProgram > = HashMap :: new ( ) ;
155+ filter_map. insert ( "VcpU" . to_string ( ) , bpf_prog. clone ( ) ) ;
156+ let bytes = bincode:: serde:: encode_to_vec ( & filter_map, BINCODE_CONFIG ) . unwrap ( ) ;
157+ assert ! ( matches!(
158+ deserialize_binary( & bytes[ ..] ) . unwrap_err( ) ,
159+ bincode:: error:: DecodeError :: LimitExceeded
160+ ) ) ;
180161 }
181162
182163 #[ test]
0 commit comments