在 macOS 中安全检查指针的有效性?

问题描述 投票:0回答:2

是否有一种方法(操作系统调用等)在运行时让 macOS 应用程序检查指针是否有效(用于读取和/或写入),而不会在指针无效时崩溃或导致信号? (指向进程地址空间之外、NULL+1 等)

无论是在 C ((char *)someLongInt) 中,还是在 Swift 中(对于不安全的原始绑定)。

c swift macos pointers
2个回答
1
投票

是的,这可以使用

mach_vm_region
调用来实现。请参阅下面的示例代码:

#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <stdio.h>
#include <stdbool.h>

bool ptr_is_valid(void *ptr, vm_prot_t needs_access) {
    vm_map_t task = mach_task_self();
    mach_vm_address_t address = (mach_vm_address_t)ptr;
    mach_vm_size_t size = 0;
    vm_region_basic_info_data_64_t info;
    mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
    mach_port_t object_name;
    kern_return_t ret = mach_vm_region(task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &count, &object_name);
    if (ret != KERN_SUCCESS) return false;
    return ((mach_vm_address_t)ptr) >= address && ((info.protection & needs_access) == needs_access);
}

#define TEST(ptr,acc) printf("ptr_is_valid(%p,access=%d)=%d\n", (void*)(ptr), (acc), ptr_is_valid((void*)(ptr),(acc)))

int main(int argc, char**argv) {
    TEST(0,0);
    TEST(0,VM_PROT_READ);
    TEST(123456789,VM_PROT_READ);
    TEST(main,0);
    TEST(main,VM_PROT_READ);
    TEST(main,VM_PROT_READ|VM_PROT_EXECUTE);
    TEST(main,VM_PROT_EXECUTE);
    TEST(main,VM_PROT_WRITE);
    TEST((void*)(-1),0);
    return 0;
}

对于内存地址,如果地址有效,则

mach_vm_region
返回包含内存区域的起始位置、大小和属性;如果地址无效,则返回下一个最高有效地址的信息,否则,如果没有更高的有效地址,则调用失败。因此,通过检查调用是否成功,以及您传递的内存地址是否大于或等于返回的地址,您可以判断该地址是否有效。

此外,人们可能想要读/写/执行该地址,因此检查包含内存区域的内存保护是否允许您这样做也很重要。


0
投票
bool VmIsBadPtr(void* ptr)
{
    vm_map_t task = mach_task_self();
    mach_vm_address_t address = (mach_vm_address_t)ptr;
    mach_vm_size_t size = 0;
    vm_region_basic_info_data_64_t info;
    mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
    mach_port_t object_name;
    kern_return_t ret = mach_vm_region(task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &count, &object_name);
    // Check if the mach_vm_region call was successful and the pointer is within a valid memory region.
    if (ret != KERN_SUCCESS || (mach_vm_address_t)ptr < address || (mach_vm_address_t)ptr >= address + size)
        return true;  // Pointer is invalid

    // Check if the protection bits indicate no permissions (not readable, writable, or executable).
    if ((info.protection & (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)) == 0)
        return true;  // Pointer is invalid

    // Pointer is considered valid
    return false;
}

我采用了 Simon 发布的原始代码,并对其进行了一些改进。希望对其他人有用。

© www.soinside.com 2019 - 2024. All rights reserved.