Browse Source

Fix heap enumeration on arm64e

opa334 6 years ago
parent
commit
2a8cdbdb84

+ 5 - 16
Classes/Utility/FLEXHeapEnumerator.m

@@ -7,6 +7,7 @@
 //
 
 #import "FLEXHeapEnumerator.h"
+#import "FLEXObjcInternal.h"
 #import <malloc/malloc.h>
 #import <mach/mach.h>
 #import <objc/runtime.h>
@@ -84,26 +85,14 @@ static kern_return_t reader(__unused task_t remote_task, vm_address_t remote_add
                 block(object, actualClass);
                 lock_zone(zone);
             };
-
-            // The largest realistic memory address varies by platform.
-            // Only 48 bits are used by 64 bit machines while
-            // 32 bit machines use all bits.
-            //
-            // __LP64__ is defined as 1 for both arm64 and x86_64
-            // via: clang -dM -arch [arm64|x86_64] -E -x c /dev/null | grep LP
-#if __LP64__
-            static uintptr_t MAX_REALISTIC_ADDRESS = 0x0000FFFFFFFFFFFF;
-            BOOL lockZoneValid = lock_zone != nil && (uintptr_t)lock_zone < MAX_REALISTIC_ADDRESS;
-            BOOL unlockZoneValid = unlock_zone != nil && (uintptr_t)unlock_zone < MAX_REALISTIC_ADDRESS;
-#else
-            BOOL lockZoneValid = lock_zone != nil;
-            BOOL unlockZoneValid = unlock_zone != nil;
-#endif
+            
+            BOOL lockZoneValid = FLEXPointerIsReadable(lock_zone);
+            BOOL unlockZoneValid =  FLEXPointerIsReadable(unlock_zone);
 
             // There is little documentation on when and why
             // any of these function pointers might be NULL
             // or garbage, so we resort to checking for NULL
-            // and impossible memory addresses at least
+            // and whether the pointer is readable
             if (introspection->enumerator && lockZoneValid && unlockZoneValid) {
                 lock_zone(zone);
                 introspection->enumerator(TASK_NULL, (void *)&callback, MALLOC_PTR_IN_USE_RANGE_TYPE, (vm_address_t)zone, reader, &range_callback);

+ 2 - 0
Classes/Utility/Runtime/Objc/FLEXObjcInternal.h

@@ -11,6 +11,8 @@
 extern "C" {
 #endif
 
+BOOL FLEXPointerIsReadable(const void *inPtr);
+
 /// @brief Assumes memory is valid and readable.
 /// @discussion objc-internal.h, objc-private.h, and objc-config.h
 /// https://blog.timac.org/2016/1124-testing-if-an-arbitrary-pointer-is-a-valid-objective-c-object/

+ 14 - 1
Classes/Utility/Runtime/Objc/FLEXObjcInternal.mm

@@ -35,6 +35,10 @@
 // For vm_region_64
 #include <mach/mach.h>
 
+#if __arm64e__
+#include <ptrauth.h>
+#endif
+
 #define ALWAYS_INLINE inline __attribute__((always_inline))
 #define NEVER_INLINE inline __attribute__((noinline))
 
@@ -98,11 +102,16 @@ static BOOL flex_isExtTaggedPointer(const void *ptr)  {
 
 extern "C" {
 
-static BOOL FLEXPointerIsReadable(const void *inPtr) {
+BOOL FLEXPointerIsReadable(const void *inPtr) {
     kern_return_t error = KERN_SUCCESS;
 
     vm_size_t vmsize;
+#if __arm64e__
+    // On arm64e, we need to strip the PAC from the pointer so the adress is readable
+    vm_address_t address = (vm_address_t)ptrauth_strip(inPtr, ptrauth_key_function_pointer);
+#else
     vm_address_t address = (vm_address_t)inPtr;
+#endif
     vm_region_basic_info_data_t info;
     mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
     memory_object_name_t object;
@@ -127,7 +136,11 @@ static BOOL FLEXPointerIsReadable(const void *inPtr) {
     // Read the memory
     vm_offset_t readMem = 0;
     mach_msg_type_number_t size = 0;
+#if __arm64e__
+    address = (vm_address_t)ptrauth_strip(inPtr, ptrauth_key_function_pointer);
+#else
     address = (vm_address_t)inPtr;
+#endif
     error = vm_read(mach_task_self(), address, sizeof(uintptr_t), &readMem, &size);
     if (error != KERN_SUCCESS) {
         // vm_read returned an error