3
3
target_vendor = "apple" ,
4
4
all( target_arch = "aarch64" , target_os = "android" )
5
5
) ) ]
6
- use std:: io;
7
- use std:: { collections:: BTreeMap , ffi:: c_void, num:: NonZeroUsize } ;
6
+ use std:: { collections:: BTreeMap , ffi:: c_void} ;
8
7
9
8
use backtrace:: Backtrace ;
10
9
use frida_gum:: { PageProtection , RangeDetails } ;
@@ -15,11 +14,8 @@ use libafl_bolts::cli::FuzzerOptions;
15
14
target_vendor = "apple" ,
16
15
all( target_arch = "aarch64" , target_os = "android" )
17
16
) ) ]
18
- use libc:: { sysconf, _SC_PAGESIZE} ;
19
- use nix:: {
20
- libc:: memset,
21
- sys:: mman:: { mmap, MapFlags , ProtFlags } ,
22
- } ;
17
+ use mmap_rs:: { MemoryAreas , MmapFlags , MmapMut , MmapOptions , ReservedMut } ;
18
+ use nix:: libc:: memset;
23
19
use rangemap:: RangeSet ;
24
20
use serde:: { Deserialize , Serialize } ;
25
21
@@ -38,10 +34,12 @@ pub struct Allocator {
38
34
shadow_offset : usize ,
39
35
/// The shadow bit
40
36
shadow_bit : usize ,
41
- /// If the shadow is pre-allocated
42
- pre_allocated_shadow : bool ,
37
+ /// The reserved ( pre-allocated) shadow mapping
38
+ pre_allocated_shadow_mappings : HashMap < ( usize , usize ) , ReservedMut > ,
43
39
/// All tracked allocations
44
40
allocations : HashMap < usize , AllocationMetadata > ,
41
+ /// All mappings
42
+ mappings : HashMap < usize , MmapMut > ,
45
43
/// The shadow memory pages
46
44
shadow_pages : RangeSet < usize > ,
47
45
/// A list of allocations
@@ -56,11 +54,6 @@ pub struct Allocator {
56
54
current_mapping_addr : usize ,
57
55
}
58
56
59
- #[ cfg( target_vendor = "apple" ) ]
60
- const ANONYMOUS_FLAG : MapFlags = MapFlags :: MAP_ANON ;
61
- #[ cfg( not( target_vendor = "apple" ) ) ]
62
- const ANONYMOUS_FLAG : MapFlags = MapFlags :: MAP_ANONYMOUS ;
63
-
64
57
macro_rules! map_to_shadow {
65
58
( $self: expr, $address: expr) => {
66
59
$self. shadow_offset + ( ( $address >> 3 ) & ( ( 1 << ( $self. shadow_bit + 1 ) ) - 1 ) )
@@ -89,6 +82,7 @@ pub struct AllocationMetadata {
89
82
impl Allocator {
90
83
/// Creates a new [`Allocator`] (not supported on this platform!)
91
84
#[ cfg( not( any(
85
+ windows,
92
86
target_os = "linux" ,
93
87
target_vendor = "apple" ,
94
88
all( target_arch = "aarch64" , target_os = "android" )
@@ -100,6 +94,7 @@ impl Allocator {
100
94
101
95
/// Creates a new [`Allocator`]
102
96
#[ cfg( any(
97
+ windows,
103
98
target_os = "linux" ,
104
99
target_vendor = "apple" ,
105
100
all( target_arch = "aarch64" , target_os = "android" )
@@ -181,29 +176,32 @@ impl Allocator {
181
176
metadata
182
177
} else {
183
178
// log::trace!("{:x}, {:x}", self.current_mapping_addr, rounded_up_size);
184
- let mapping = match mmap (
185
- NonZeroUsize :: new ( self . current_mapping_addr ) ,
186
- NonZeroUsize :: new_unchecked ( rounded_up_size) ,
187
- ProtFlags :: PROT_READ | ProtFlags :: PROT_WRITE ,
188
- ANONYMOUS_FLAG
189
- | MapFlags :: MAP_PRIVATE
190
- | MapFlags :: MAP_FIXED
191
- | MapFlags :: MAP_NORESERVE ,
192
- -1 ,
193
- 0 ,
194
- ) {
195
- Ok ( mapping) => mapping as usize ,
179
+ let mapping = match MmapOptions :: new ( rounded_up_size)
180
+ . unwrap ( )
181
+ . with_address ( self . current_mapping_addr )
182
+ . map_mut ( )
183
+ {
184
+ Ok ( mapping) => mapping,
196
185
Err ( err) => {
197
186
log:: error!( "An error occurred while mapping memory: {err:?}" ) ;
198
187
return std:: ptr:: null_mut ( ) ;
199
188
}
200
189
} ;
201
- self . current_mapping_addr += rounded_up_size;
202
-
203
- self . map_shadow_for_region ( mapping, mapping + rounded_up_size, false ) ;
190
+ self . current_mapping_addr += ( ( rounded_up_size
191
+ + MmapOptions :: allocation_granularity ( ) )
192
+ / MmapOptions :: allocation_granularity ( ) )
193
+ * MmapOptions :: allocation_granularity ( ) ;
194
+
195
+ self . map_shadow_for_region (
196
+ mapping. as_ptr ( ) as usize ,
197
+ mapping. as_ptr ( ) . add ( rounded_up_size) as usize ,
198
+ false ,
199
+ ) ;
200
+ let address = mapping. as_ptr ( ) as usize ;
201
+ self . mappings . insert ( address, mapping) ;
204
202
205
203
let mut metadata = AllocationMetadata {
206
- address : mapping ,
204
+ address,
207
205
size,
208
206
actual_size : rounded_up_size,
209
207
..AllocationMetadata :: default ( )
@@ -223,8 +221,7 @@ impl Allocator {
223
221
) ;
224
222
let address = ( metadata. address + self . page_size ) as * mut c_void ;
225
223
226
- self . allocations
227
- . insert ( metadata. address + self . page_size , metadata) ;
224
+ self . allocations . insert ( address as usize , metadata) ;
228
225
// log::trace!("serving address: {:?}, size: {:x}", address, size);
229
226
address
230
227
}
@@ -373,31 +370,50 @@ impl Allocator {
373
370
374
371
let shadow_mapping_start = map_to_shadow ! ( self , start) ;
375
372
376
- if !self . pre_allocated_shadow {
377
- let shadow_start = self . round_down_to_page ( shadow_mapping_start) ;
378
- let shadow_end =
379
- self . round_up_to_page ( ( end - start) / 8 ) + self . page_size + shadow_start;
373
+ let shadow_start = self . round_down_to_page ( shadow_mapping_start) ;
374
+ let shadow_end = self . round_up_to_page ( ( end - start) / 8 ) + self . page_size + shadow_start;
375
+ if self . pre_allocated_shadow_mappings . is_empty ( ) {
380
376
for range in self . shadow_pages . gaps ( & ( shadow_start..shadow_end) ) {
381
377
/*
382
378
log::trace!(
383
379
"range: {:x}-{:x}, pagesize: {}",
384
380
range.start, range.end, self.page_size
385
381
);
386
382
*/
387
- unsafe {
388
- mmap (
389
- NonZeroUsize :: new ( range. start ) ,
390
- NonZeroUsize :: new ( range. end - range. start ) . unwrap ( ) ,
391
- ProtFlags :: PROT_READ | ProtFlags :: PROT_WRITE ,
392
- ANONYMOUS_FLAG | MapFlags :: MAP_FIXED | MapFlags :: MAP_PRIVATE ,
393
- -1 ,
394
- 0 ,
395
- )
383
+ let mapping = MmapOptions :: new ( range. end - range. start - 1 )
384
+ . unwrap ( )
385
+ . with_address ( range. start )
386
+ . map_mut ( )
396
387
. expect ( "An error occurred while mapping shadow memory" ) ;
397
- }
388
+
389
+ self . mappings . insert ( range. start , mapping) ;
398
390
}
399
391
400
392
self . shadow_pages . insert ( shadow_start..shadow_end) ;
393
+ } else {
394
+ let mut new_shadow_mappings = Vec :: new ( ) ;
395
+ for range in self . shadow_pages . gaps ( & ( shadow_start..shadow_end) ) {
396
+ for ( ( start, end) , shadow_mapping) in & mut self . pre_allocated_shadow_mappings {
397
+ if * start <= range. start && range. start < * start + shadow_mapping. len ( ) {
398
+ let mut start_mapping =
399
+ shadow_mapping. split_off ( range. start - * start) . unwrap ( ) ;
400
+ let end_mapping = start_mapping
401
+ . split_off ( range. end - ( range. start - * start) )
402
+ . unwrap ( ) ;
403
+ new_shadow_mappings. push ( ( ( range. end , * end) , end_mapping) ) ;
404
+ self . mappings
405
+ . insert ( range. start , start_mapping. try_into ( ) . unwrap ( ) ) ;
406
+
407
+ break ;
408
+ }
409
+ }
410
+ }
411
+ for new_shadow_mapping in new_shadow_mappings {
412
+ self . pre_allocated_shadow_mappings
413
+ . insert ( new_shadow_mapping. 0 , new_shadow_mapping. 1 ) ;
414
+ self . shadow_pages
415
+ . insert ( new_shadow_mapping. 0 . 0 ..new_shadow_mapping. 0 . 1 ) ;
416
+ }
401
417
}
402
418
403
419
// log::trace!("shadow_mapping_start: {:x}, shadow_size: {:x}", shadow_mapping_start, (end - start) / 8);
@@ -438,7 +454,7 @@ impl Allocator {
438
454
if range. protection ( ) as u32 & PageProtection :: ReadWrite as u32 != 0 {
439
455
let start = range. memory_range ( ) . base_address ( ) . 0 as usize ;
440
456
let end = start + range. memory_range ( ) . size ( ) ;
441
- if self . pre_allocated_shadow && start == 1 << self . shadow_bit {
457
+ if ! self . pre_allocated_shadow_mappings . is_empty ( ) && start == 1 << self . shadow_bit {
442
458
return true ;
443
459
}
444
460
self . map_shadow_for_region ( start, end, true ) ;
@@ -461,31 +477,28 @@ impl Allocator {
461
477
let mut userspace_max: usize = 0 ;
462
478
463
479
// Enumerate memory ranges that are already occupied.
464
- for prot in [
465
- PageProtection :: Read ,
466
- PageProtection :: Write ,
467
- PageProtection :: Execute ,
468
- ] {
469
- RangeDetails :: enumerate_with_prot ( prot, & mut |details| {
470
- let start = details. memory_range ( ) . base_address ( ) . 0 as usize ;
471
- let end = start + details. memory_range ( ) . size ( ) ;
472
- occupied_ranges. push ( ( start, end) ) ;
473
- log:: trace!( "{:x} {:x}" , start, end) ;
474
- let base: usize = 2 ;
475
- // On x64, if end > 2**48, then that's in vsyscall or something.
476
- #[ cfg( target_arch = "x86_64" ) ]
477
- if end <= base. pow ( 48 ) && end > userspace_max {
478
- userspace_max = end;
479
- }
480
+ for area in MemoryAreas :: open ( None ) . unwrap ( ) {
481
+ let start = area. as_ref ( ) . unwrap ( ) . start ( ) ;
482
+ let end = area. unwrap ( ) . end ( ) ;
483
+ occupied_ranges. push ( ( start, end) ) ;
484
+ log:: trace!( "{:x} {:x}" , start, end) ;
485
+ let base: usize = 2 ;
486
+ // On x64, if end > 2**48, then that's in vsyscall or something.
487
+ #[ cfg( all( unix, target_arch = "x86_64" ) ) ]
488
+ if end <= base. pow ( 48 ) && end > userspace_max {
489
+ userspace_max = end;
490
+ }
480
491
481
- // On x64, if end > 2**52, then range is not in userspace
482
- #[ cfg( target_arch = "aarch64" ) ]
483
- if end <= base. pow ( 52 ) && end > userspace_max {
484
- userspace_max = end;
485
- }
492
+ #[ cfg( all( not( unix) , target_arch = "x86_64" ) ) ]
493
+ if ( end >> 3 ) <= base. pow ( 44 ) && ( end >> 3 ) > userspace_max {
494
+ userspace_max = end >> 3 ;
495
+ }
486
496
487
- true
488
- } ) ;
497
+ // On aarch64, if end > 2**52, then range is not in userspace
498
+ #[ cfg( target_arch = "aarch64" ) ]
499
+ if end <= base. pow ( 52 ) && end > userspace_max {
500
+ userspace_max = end;
501
+ }
489
502
}
490
503
491
504
let mut maxbit = 0 ;
@@ -498,7 +511,7 @@ impl Allocator {
498
511
}
499
512
500
513
{
501
- for try_shadow_bit in & [ maxbit - 4 , maxbit - 3 , maxbit - 2 ] {
514
+ for try_shadow_bit in & [ maxbit, maxbit - 4 , maxbit - 3 , maxbit - 2 ] {
502
515
let addr: usize = 1 << try_shadow_bit;
503
516
let shadow_start = addr;
504
517
let shadow_end = addr + addr + addr;
@@ -512,48 +525,27 @@ impl Allocator {
512
525
}
513
526
}
514
527
515
- if unsafe {
516
- mmap (
517
- NonZeroUsize :: new ( addr) ,
518
- NonZeroUsize :: new_unchecked ( self . page_size ) ,
519
- ProtFlags :: PROT_READ | ProtFlags :: PROT_WRITE ,
520
- MapFlags :: MAP_PRIVATE
521
- | ANONYMOUS_FLAG
522
- | MapFlags :: MAP_FIXED
523
- | MapFlags :: MAP_NORESERVE ,
524
- -1 ,
525
- 0 ,
526
- )
527
- }
528
- . is_ok ( )
528
+ if let Ok ( mapping) = MmapOptions :: new ( 1 << ( * try_shadow_bit + 1 ) )
529
+ . unwrap ( )
530
+ . with_flags ( MmapFlags :: NO_RESERVE )
531
+ . with_address ( addr)
532
+ . reserve_mut ( )
529
533
{
530
534
shadow_bit = ( * try_shadow_bit) . try_into ( ) . unwrap ( ) ;
535
+
536
+ log:: warn!( "shadow_bit {shadow_bit:x} is suitable" ) ;
537
+ self . pre_allocated_shadow_mappings
538
+ . insert ( ( addr, ( addr + ( 1 << shadow_bit) ) ) , mapping) ;
531
539
break ;
532
540
}
533
541
}
534
542
}
535
543
536
- log:: warn!( "shadow_bit {shadow_bit:x} is suitable" ) ;
537
544
// assert!(shadow_bit != 0);
538
545
// attempt to pre-map the entire shadow-memory space
539
546
540
547
let addr: usize = 1 << shadow_bit;
541
- let pre_allocated_shadow = unsafe {
542
- mmap (
543
- NonZeroUsize :: new ( addr) ,
544
- NonZeroUsize :: new_unchecked ( addr + addr) ,
545
- ProtFlags :: PROT_READ | ProtFlags :: PROT_WRITE ,
546
- ANONYMOUS_FLAG
547
- | MapFlags :: MAP_FIXED
548
- | MapFlags :: MAP_PRIVATE
549
- | MapFlags :: MAP_NORESERVE ,
550
- -1 ,
551
- 0 ,
552
- )
553
- }
554
- . is_ok ( ) ;
555
548
556
- self . pre_allocated_shadow = pre_allocated_shadow;
557
549
self . shadow_offset = 1 << shadow_bit;
558
550
self . shadow_bit = shadow_bit;
559
551
self . base_mapping_addr = addr + addr + addr;
@@ -564,6 +556,7 @@ impl Allocator {
564
556
impl Default for Allocator {
565
557
/// Creates a new [`Allocator`] (not supported on this platform!)
566
558
#[ cfg( not( any(
559
+ windows,
567
560
target_os = "linux" ,
568
561
target_vendor = "apple" ,
569
562
all( target_arch = "aarch64" , target_os = "android" )
@@ -572,25 +565,17 @@ impl Default for Allocator {
572
565
todo ! ( "Shadow region not yet supported for this platform!" ) ;
573
566
}
574
567
575
- #[ allow( clippy:: too_many_lines) ]
576
568
fn default ( ) -> Self {
577
- let ret = unsafe { sysconf ( _SC_PAGESIZE) } ;
578
- assert ! (
579
- ret >= 0 ,
580
- "Failed to read pagesize {:?}" ,
581
- io:: Error :: last_os_error( )
582
- ) ;
583
-
584
- #[ allow( clippy:: cast_sign_loss) ]
585
- let page_size = ret as usize ;
569
+ let page_size = MmapOptions :: page_size ( ) ;
586
570
587
571
Self {
588
572
max_allocation : 1 << 30 ,
589
573
max_allocation_panics : false ,
590
574
max_total_allocation : 1 << 32 ,
591
575
allocation_backtraces : false ,
592
576
page_size,
593
- pre_allocated_shadow : false ,
577
+ pre_allocated_shadow_mappings : HashMap :: new ( ) ,
578
+ mappings : HashMap :: new ( ) ,
594
579
shadow_offset : 0 ,
595
580
shadow_bit : 0 ,
596
581
allocations : HashMap :: new ( ) ,
0 commit comments