@@ -41,13 +41,18 @@ pub struct Dex {
4141}
4242
4343impl Dex {
44- // the type of endianness used in the file
4544 const ENDIAN_CONSTANT : u32 = 0x12345678 ;
4645 const REVERSE_ENDIAN_CONSTANT : u32 = 0x78563412 ;
47-
48- // lack of information
46+ const DEX_HEADER_SIZE : u32 = 0x70 ;
4947 const NO_INDEX : u32 = 0xffffffff ;
5048
49+ const MAX_STRINGS : usize = 1_000_000 ;
50+ const MAX_TYPES : usize = 1_000_000 ;
51+ const MAX_PROTOS : usize = 1_000_000 ;
52+ const MAX_CLASSES : usize = 1_000_000 ;
53+ const MAX_METHODS : usize = 1_000_000 ;
54+ const MAX_FIELDS : usize = 1_000_000 ;
55+
5156 pub fn parse < ' a > ( data : & ' a [ u8 ] ) -> Result < Self , Err < Error < ' a > > > {
5257 // Extract dex header with information about data location
5358 let ( strings_offset, header) = Self :: parse_dex_header ( data) ?;
@@ -60,14 +65,9 @@ impl Dex {
6065 let ( proto_offset, types) =
6166 Self :: parse_types ( types_offset, & header, & strings) ?;
6267
63- // Exctract defined prototypes
64- let ( field_offset, proto_ids) = Self :: parse_proto_ids (
65- proto_offset,
66- data,
67- & header,
68- & strings,
69- & types,
70- ) ?;
68+ // Extract defined prototypes
69+ let ( field_offset, protos) =
70+ Self :: parse_protos ( proto_offset, data, & header, & strings, & types) ?;
7171
7272 // Extract defined fields
7373 let ( method_offset, fields) =
@@ -79,7 +79,7 @@ impl Dex {
7979 & header,
8080 & strings,
8181 & types,
82- & proto_ids ,
82+ & protos ,
8383 ) ?;
8484
8585 // Extract defined classes
@@ -93,7 +93,7 @@ impl Dex {
9393 header,
9494 strings,
9595 types,
96- protos : proto_ids ,
96+ protos,
9797 fields,
9898 methods,
9999 class_defs,
@@ -216,6 +216,7 @@ impl Dex {
216216
217217 let string_offsets = it
218218 . by_ref ( )
219+ . take ( Self :: MAX_STRINGS )
219220 . take ( header. string_ids_size as usize )
220221 . filter_map ( |offset| Self :: parse_string_from_offset ( data, offset) )
221222 . map ( Rc :: new)
@@ -230,12 +231,24 @@ impl Dex {
230231 ///
231232 /// idx - is an index in the string_ids_off table
232233 /// strings_ids_off[idx] -> string_data_item
234+ ///
235+ /// Strings larger than 64KB will be considered invalid and the result will
236+ /// be None.
233237 fn parse_string_from_offset (
234238 data : & [ u8 ] ,
235239 string_data_offset : u32 ,
236240 ) -> Option < String > {
241+ if string_data_offset < Self :: DEX_HEADER_SIZE {
242+ return None ;
243+ }
244+
237245 data. get ( string_data_offset as usize ..) . and_then ( |data| {
238246 let ( data, utf16_size) = uleb128 ( data) . ok ( ) ?;
247+
248+ if utf16_size > 65536 || ( utf16_size as usize ) > data. len ( ) {
249+ return None ;
250+ }
251+
239252 let ( _, bytes) =
240253 take :: < usize , & [ u8 ] , Error > ( utf16_size as usize ) ( data) . ok ( ) ?;
241254
@@ -268,6 +281,7 @@ impl Dex {
268281
269282 let type_indexes = it
270283 . by_ref ( )
284+ . take ( Self :: MAX_TYPES )
271285 . take ( header. type_ids_size as usize )
272286 . filter_map ( |idx| string_items. get ( idx as usize ) . cloned ( ) )
273287 . collect ( ) ;
@@ -281,7 +295,7 @@ impl Dex {
281295 ///
282296 /// See: https://source.android.com/docs/core/runtime/dex-format#proto-id-item
283297 /// See: https://source.android.com/docs/core/runtime/dex-format#type-list
284- fn parse_proto_ids < ' a > (
298+ fn parse_protos < ' a > (
285299 remainder : & ' a [ u8 ] ,
286300 data : & ' a [ u8 ] ,
287301 header : & DexHeader ,
@@ -298,13 +312,15 @@ impl Dex {
298312
299313 let proto_entries = it
300314 . by_ref ( )
315+ . take ( Self :: MAX_PROTOS )
301316 . take ( header. proto_ids_size as usize )
302317 . filter_map ( |( shorty_idx, return_type_idx, parameters_off) | {
303318 let shorty = string_items. get ( shorty_idx as usize ) ?. clone ( ) ;
304319 let return_type =
305320 type_items. get ( return_type_idx as usize ) ?. clone ( ) ;
306321
307- // According to the documentation, if parameters_off is 0, then the type has 0 parameters.
322+ // According to the documentation, if parameters_off is 0, then
323+ // the type has 0 parameters.
308324 let parameters = if parameters_off == 0 {
309325 Vec :: new ( )
310326 } else {
@@ -335,10 +351,15 @@ impl Dex {
335351 offset : u32 ,
336352 ) -> Option < Vec < Rc < String > > > {
337353 let remainder = data. get ( offset as usize ..) ?;
354+ let ( remainder, size) = le_u32 :: < & [ u8 ] , Error > ( remainder) . ok ( ) ?;
338355
339- let ( rem, size) = le_u32 :: < & [ u8 ] , Error > ( remainder) . ok ( ) ?;
356+ // The number of arguments can't be higher than 255 due to constraints
357+ // in the Dalvik bytecode instruction set itself.
358+ if size > 255 {
359+ return None ;
360+ }
340361
341- let mut it = iterator ( rem , le_u16 :: < & [ u8 ] , Error > ) ;
362+ let mut it = iterator ( remainder , le_u16 :: < & [ u8 ] , Error > ) ;
342363 let items = it
343364 . by_ref ( )
344365 . take ( size as usize )
@@ -369,6 +390,7 @@ impl Dex {
369390
370391 let field_entries = it
371392 . by_ref ( )
393+ . take ( Self :: MAX_FIELDS )
372394 . take ( header. field_ids_size as usize )
373395 . filter_map ( |( class_idx, type_idx, name_idx) | {
374396 let class = type_items. get ( class_idx as usize ) ?. clone ( ) ;
@@ -404,6 +426,7 @@ impl Dex {
404426
405427 let method_entries = it
406428 . by_ref ( )
429+ . take ( Self :: MAX_METHODS )
407430 . take ( header. method_ids_size as usize )
408431 . filter_map ( |( class_idx, proto_idx, name_idx) | {
409432 let class = type_items. get ( class_idx as usize ) ?. clone ( ) ;
@@ -442,6 +465,7 @@ impl Dex {
442465
443466 let class_entries = it
444467 . by_ref ( )
468+ . take ( Self :: MAX_CLASSES )
445469 . take ( header. class_defs_size as usize )
446470 . filter_map (
447471 |(
@@ -484,7 +508,6 @@ impl Dex {
484508 fn parse_map_items ( data : & [ u8 ] , header : & DexHeader ) -> Option < MapList > {
485509 data. get ( header. map_off as usize ..) . and_then ( |offset| {
486510 let ( items_offset, size) = le_u32 :: < & [ u8 ] , Error > ( offset) . ok ( ) ?;
487-
488511 let mut it = iterator ( items_offset, Self :: parse_map_item) ;
489512 let items = it. by_ref ( ) . take ( size as usize ) . collect ( ) ;
490513 let _ = it. finish ( ) ;
0 commit comments