123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- //
- // FLEXObjcInternal.mm
- // FLEX
- //
- // Created by Tanner Bennett on 11/1/18.
- //
- /*
- * Copyright (c) 2005-2007 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
- #import "FLEXObjcInternal.h"
- #import <objc/runtime.h>
- // For malloc_size
- #import <malloc/malloc.h>
- // 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))
- // The macros below are copied straight from
- // objc-internal.h, objc-private.h, objc-object.h, and objc-config.h with
- // as few modifications as possible. Changes are noted in boxed comments.
- // https://opensource.apple.com/source/objc4/objc4-723/
- // https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-internal.h.auto.html
- // https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-object.h.auto.html
- /////////////////////
- // objc-internal.h //
- /////////////////////
- #if OBJC_HAVE_TAGGED_POINTERS
- ///////////////////
- // objc-object.h //
- ///////////////////
- ////////////////////////////////////////////////
- // originally objc_object::isExtTaggedPointer //
- ////////////////////////////////////////////////
- NS_INLINE BOOL flex_isExtTaggedPointer(const void *ptr) {
- return ((uintptr_t)ptr & _OBJC_TAG_EXT_MASK) == _OBJC_TAG_EXT_MASK;
- }
- #endif // OBJC_HAVE_TAGGED_POINTERS
- /////////////////////////////////////
- // FLEXObjectInternal //
- // No Apple code beyond this point //
- /////////////////////////////////////
- extern "C" {
- 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;
- error = vm_region_64(
- mach_task_self(),
- &address,
- &vmsize,
- VM_REGION_BASIC_INFO,
- (vm_region_info_t)&info,
- &info_count,
- &object
- );
- if (error != KERN_SUCCESS) {
- // vm_region/vm_region_64 returned an error
- return NO;
- } else if (!(BOOL)(info.protection & VM_PROT_READ)) {
- return NO;
- }
- // 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
- return NO;
- }
- return YES;
- }
- /// Accepts addresses that may or may not be readable.
- /// https://blog.timac.org/2016/1124-testing-if-an-arbitrary-pointer-is-a-valid-objective-c-object/
- BOOL FLEXPointerIsValidObjcObject(const void *ptr) {
- uintptr_t pointer = (uintptr_t)ptr;
- if (!ptr) {
- return NO;
- }
- #if OBJC_HAVE_TAGGED_POINTERS
- // Tagged pointers have 0x1 set, no other valid pointers do
- // objc-internal.h -> _objc_isTaggedPointer()
- if (flex_isTaggedPointer(ptr) || flex_isExtTaggedPointer(ptr)) {
- return YES;
- }
- #endif
- // Check pointer alignment
- if ((pointer % sizeof(uintptr_t)) != 0) {
- return NO;
- }
- // From LLDB:
- // Pointers in a class_t will only have bits 0 through 46 set,
- // so if any pointer has bits 47 through 63 high, we know that this is not a valid isa
- // https://llvm.org/svn/llvm-project/lldb/trunk/examples/summaries/cocoa/objc_runtime.py
- if ((pointer & 0xFFFF800000000000) != 0) {
- return NO;
- }
- // Make sure dereferencing this address won't crash
- if (!FLEXPointerIsReadable(ptr)) {
- return NO;
- }
- // http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html
- // We check if the returned class is readable because object_getClass
- // can return a garbage value when given a non-nil pointer to a non-object
- Class cls = object_getClass((__bridge id)ptr);
- if (cls && FLEXPointerIsReadable((__bridge void *)cls)) {
- // Just because this pointer is readable doesn't mean whatever is at
- // it's ISA offset is readable. We need to do the same checks on it's ISA.
- // Even this isn't perfect, because once we call object_isClass, we're
- // going to dereference a member of the metaclass, which may or may not
- // be readable itself. For the time being there is no way to access it
- // to check here, and I have yet to hard-code a solution.
- Class metaclass = object_getClass(cls);
- if (metaclass && FLEXPointerIsReadable((__bridge void *)metaclass)) {
- if (object_isClass(cls)) {
- return YES;
- }
- }
- }
- return NO;
- }
- } // End extern "C"
|