VirtualBox

Ignore:
Timestamp:
Feb 13, 2020 9:21:02 PM (5 years ago)
Author:
vboxsync
Message:

IPRT/memobj-r0drv-darwin.cpp: Workarounds for vm_fault misbehaving on kernel allocations in processes with hardened runtime enabled. bugref:9466

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r0drv/darwin/memobj-r0drv-darwin.cpp

    r82968 r83070  
    4444#include <iprt/param.h>
    4545#include <iprt/process.h>
     46#include <iprt/semaphore.h>
    4647#include <iprt/string.h>
    4748#include <iprt/thread.h>
     
    7273    IOMemoryMap        *pMemMap;
    7374} RTR0MEMOBJDARWIN, *PRTR0MEMOBJDARWIN;
     75
     76/**
     77 * Common thread_call_allocate/thread_call_enter argument package.
     78 */
     79typedef struct RTR0MEMOBJDARWINTHREADARGS
     80{
     81    int32_t volatile        rc;
     82    RTSEMEVENTMULTI         hEvent;
     83} RTR0MEMOBJDARWINTHREADARGS;
     84
     85
     86/**
     87 * Arguments for rtR0MemObjNativeAllockWorkOnKernelThread.
     88 */
     89typedef struct RTR0MEMOBJDARWINALLOCARGS
     90{
     91    RTR0MEMOBJDARWINTHREADARGS Core;
     92    PPRTR0MEMOBJINTERNAL    ppMem;
     93    size_t                  cb;
     94    bool                    fExecutable;
     95    bool                    fContiguous;
     96    mach_vm_address_t       PhysMask;
     97    uint64_t                MaxPhysAddr;
     98    RTR0MEMOBJTYPE          enmType;
     99    size_t                  uAlignment;
     100} RTR0MEMOBJDARWINALLOCARGS;
     101
     102/**
     103 * Arguments for rtR0MemObjNativeProtectWorkOnKernelThread.
     104 */
     105typedef struct RTR0MEMOBJDARWINPROTECTARGS
     106{
     107    RTR0MEMOBJDARWINTHREADARGS Core;
     108    PRTR0MEMOBJINTERNAL     pMem;
     109    size_t                  offSub;
     110    size_t                  cbSub;
     111    uint32_t                fProt;
     112} RTR0MEMOBJDARWINPROTECTARGS;
     113
     114
     115/*********************************************************************************************************************************
     116*   Internal Functions                                                                                                           *
     117*********************************************************************************************************************************/
     118static void rtR0MemObjNativeAllockWorkerOnKernelThread(void *pvUser0, void *pvUser1);
     119static int  rtR0MemObjNativeProtectWorker(PRTR0MEMOBJINTERNAL pMem, size_t offSub, size_t cbSub, uint32_t fProt);
     120static void rtR0MemObjNativeProtectWorkerOnKernelThread(void *pvUser0, void *pvUser1);
    74121
    75122
     
    440487
    441488
     489/**
     490 * This is a helper function to executes @a pfnWorker in the context of the
     491 * kernel_task
     492 *
     493 * @returns IPRT status code - result from pfnWorker or dispatching error.
     494 * @param   pfnWorker       The function to call.
     495 * @param   pArgs           The arguments to pass to the function.
     496 */
     497static int rtR0MemObjDarwinDoInKernelTaskThread(thread_call_func_t pfnWorker, RTR0MEMOBJDARWINTHREADARGS *pArgs)
     498{
     499    pArgs->rc     = VERR_IPE_UNINITIALIZED_STATUS;
     500    pArgs->hEvent = NIL_RTSEMEVENTMULTI;
     501    int rc = RTSemEventMultiCreate(&pArgs->hEvent);
     502    if (RT_SUCCESS(rc))
     503    {
     504        thread_call_t hCall = thread_call_allocate(pfnWorker, (void *)pArgs);
     505        if (hCall)
     506        {
     507            boolean_t fRc = thread_call_enter(hCall);
     508            AssertLogRel(fRc == FALSE);
     509
     510            rc = RTSemEventMultiWaitEx(pArgs->hEvent, RTSEMWAIT_FLAGS_INDEFINITE | RTSEMWAIT_FLAGS_UNINTERRUPTIBLE,
     511                                       RT_INDEFINITE_WAIT);
     512            AssertLogRelRC(rc);
     513
     514            rc = pArgs->rc;
     515            thread_call_free(hCall);
     516        }
     517        else
     518            rc = VERR_NO_MEMORY;
     519        RTSemEventMultiDestroy(pArgs->hEvent);
     520    }
     521    return rc;
     522}
     523
     524
     525/**
     526 * Signals result to thread waiting in rtR0MemObjDarwinDoInKernelTaskThread.
     527 *
     528 * @param   pArgs           The argument structure.
     529 * @param   rc              The IPRT status code to signal.
     530 */
     531static void rtR0MemObjDarwinSignalThreadWaitinOnTask(RTR0MEMOBJDARWINTHREADARGS volatile *pArgs, int rc)
     532{
     533    if (ASMAtomicCmpXchgS32(&pArgs->rc, rc, VERR_IPE_UNINITIALIZED_STATUS))
     534    {
     535        rc = RTSemEventMultiSignal(pArgs->hEvent);
     536        AssertLogRelRC(rc);
     537    }
     538}
     539
    442540
    443541/**
     
    457555 * @param   enmType         The object type.
    458556 * @param   uAlignment      The allocation alignment (in bytes).
     557 * @param   fOnKernelThread Set if we're already on the kernel thread.
    459558 */
    460559static int rtR0MemObjNativeAllocWorker(PPRTR0MEMOBJINTERNAL ppMem, size_t cb,
    461560                                       bool fExecutable, bool fContiguous,
    462561                                       mach_vm_address_t PhysMask, uint64_t MaxPhysAddr,
    463                                        RTR0MEMOBJTYPE enmType, size_t uAlignment)
     562                                       RTR0MEMOBJTYPE enmType, size_t uAlignment, bool fOnKernelThread)
    464563{
    465564    int rc;
     565
     566    /*
     567     * Because of process code signing properties leaking into kernel space in
     568     * in XNU's vm_fault.c code, we have to defer allocations of exec memory to
     569     * a thread running in the kernel_task to get consistent results here.
     570     * Believing is trouble is caused by the page_nx() + exec check, it was
     571     * introduced in 10.10.5 (or 10.11.0).
     572     * (PS. Doubt this is in anyway intentional behaviour, but rather unforseen
     573     * consequences from a pragmatic approach to modifying the complicate VM code.)
     574     */
     575    if (!fExecutable || fOnKernelThread)
     576    { /* likely */ }
     577    else
     578    {
     579        RTR0MEMOBJDARWINALLOCARGS Args;
     580        Args.ppMem          = ppMem;
     581        Args.cb             = cb;
     582        Args.fExecutable    = fExecutable;
     583        Args.fContiguous    = fContiguous;
     584        Args.PhysMask       = PhysMask;
     585        Args.MaxPhysAddr    = MaxPhysAddr;
     586        Args.enmType        = enmType;
     587        Args.uAlignment     = uAlignment;
     588        return rtR0MemObjDarwinDoInKernelTaskThread(rtR0MemObjNativeAllockWorkerOnKernelThread, &Args.Core);
     589    }
    466590
    467591    /*
     
    494618    if (version_major >= 12 /* 12 = 10.8.x = Mountain Kitten */)
    495619        fOptions |= kIOMemoryMapperNone;
     620
     621#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 && 0 /* enable when/if necessary */
     622    /* Paranoia: Don't misrepresent our intentions, we won't map kernel executable memory into ring-0. */
     623    if (fExecutable && version_major >= 11 /* 10.7.x = Lion, as below */)
     624    {
     625        fOptions &= ~kIOMemoryKernelUserShared;
     626        if (uAlignment < PAGE_SIZE)
     627            uAlignment = PAGE_SIZE;
     628    }
     629#endif
    496630
    497631    /* The public initWithPhysicalMask virtual method appeared in 10.7.0, in
     
    618752                    }
    619753
    620 #if 1 /* Experimental code. */
    621754                    if (fExecutable)
    622755                    {
    623                         rc = rtR0MemObjNativeProtect(&pMemDarwin->Core, 0, cb, RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC);
    624 # ifdef RT_STRICT
    625                         /* check that the memory is actually mapped. */
    626                         RTTHREADPREEMPTSTATE State2 = RTTHREADPREEMPTSTATE_INITIALIZER;
    627                         RTThreadPreemptDisable(&State2);
    628                         rtR0MemObjDarwinTouchPages(pv, cb);
    629                         RTThreadPreemptRestore(&State2);
    630 # endif
    631 
     756                        rc = rtR0MemObjNativeProtectWorker(&pMemDarwin->Core, 0, cb,
     757                                                           RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC);
     758#ifdef RT_STRICT
     759                        if (RT_SUCCESS(rc))
     760                        {
     761                            /* check that the memory is actually mapped. */
     762                            RTTHREADPREEMPTSTATE State2 = RTTHREADPREEMPTSTATE_INITIALIZER;
     763                            RTThreadPreemptDisable(&State2);
     764                            rtR0MemObjDarwinTouchPages(pv, cb);
     765                            RTThreadPreemptRestore(&State2);
     766                        }
     767#endif
    632768                        /* Bug 6226: Ignore KERN_PROTECTION_FAILURE on Leopard and older. */
    633769                        if (   rc == VERR_PERMISSION_DENIED
     
    636772                    }
    637773                    else
    638 #endif
    639774                        rc = VINF_SUCCESS;
    640775                    if (RT_SUCCESS(rc))
     
    673808
    674809
     810/**
     811 * rtR0MemObjNativeAllocWorker kernel_task wrapper function.
     812 */
     813static void rtR0MemObjNativeAllockWorkerOnKernelThread(void *pvUser0, void *pvUser1)
     814{
     815    AssertPtr(pvUser0); Assert(pvUser1 == NULL); NOREF(pvUser1);
     816    RTR0MEMOBJDARWINALLOCARGS volatile *pArgs = (RTR0MEMOBJDARWINALLOCARGS volatile *)pvUser0;
     817    int rc = rtR0MemObjNativeAllocWorker(pArgs->ppMem, pArgs->cb, pArgs->fExecutable, pArgs->fContiguous, pArgs->PhysMask,
     818                                         pArgs->MaxPhysAddr, pArgs->enmType, pArgs->uAlignment, true /*fOnKernelThread*/);
     819    rtR0MemObjDarwinSignalThreadWaitinOnTask(&pArgs->Core, rc);
     820}
     821
     822
    675823DECLHIDDEN(int) rtR0MemObjNativeAllocPage(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
    676824{
    677825    IPRT_DARWIN_SAVE_EFL_AC();
    678826
    679     int rc = rtR0MemObjNativeAllocWorker(ppMem, cb, fExecutable, false /* fContiguous */,
    680                                          0 /* PhysMask */, UINT64_MAX, RTR0MEMOBJTYPE_PAGE, PAGE_SIZE);
     827    int rc = rtR0MemObjNativeAllocWorker(ppMem, cb, fExecutable, false /* fContiguous */, 0 /* PhysMask */, UINT64_MAX,
     828                                         RTR0MEMOBJTYPE_PAGE, PAGE_SIZE, false /*fOnKernelThread*/);
    681829
    682830    IPRT_DARWIN_RESTORE_EFL_AC();
     
    696844     * (See bug comment in the worker and IOBufferMemoryDescriptor::initWithPhysicalMask.)
    697845     */
    698     int rc = rtR0MemObjNativeAllocWorker(ppMem, cb, fExecutable, false /* fContiguous */,
    699                                          ~(uint32_t)PAGE_OFFSET_MASK, _4G - PAGE_SIZE, RTR0MEMOBJTYPE_LOW, PAGE_SIZE);
     846    int rc = rtR0MemObjNativeAllocWorker(ppMem, cb, fExecutable, false /* fContiguous */, ~(uint32_t)PAGE_OFFSET_MASK,
     847                                         _4G - PAGE_SIZE, RTR0MEMOBJTYPE_LOW, PAGE_SIZE, false /*fOnKernelThread*/);
    700848    if (rc == VERR_ADDRESS_TOO_BIG)
    701         rc = rtR0MemObjNativeAllocWorker(ppMem, cb, fExecutable, false /* fContiguous */,
    702                                          0 /* PhysMask */, _4G - PAGE_SIZE, RTR0MEMOBJTYPE_LOW, PAGE_SIZE);
     849        rc = rtR0MemObjNativeAllocWorker(ppMem, cb, fExecutable, false /* fContiguous */, 0 /* PhysMask */,
     850                                         _4G - PAGE_SIZE, RTR0MEMOBJTYPE_LOW, PAGE_SIZE, false /*fOnKernelThread*/);
    703851
    704852    IPRT_DARWIN_RESTORE_EFL_AC();
     
    713861    int rc = rtR0MemObjNativeAllocWorker(ppMem, cb, fExecutable, true /* fContiguous */,
    714862                                         ~(uint32_t)PAGE_OFFSET_MASK, _4G - PAGE_SIZE,
    715                                          RTR0MEMOBJTYPE_CONT, PAGE_SIZE);
     863                                         RTR0MEMOBJTYPE_CONT, PAGE_SIZE, false /*fOnKernelThread*/);
    716864
    717865    /*
     
    722870        rc = rtR0MemObjNativeAllocWorker(ppMem, cb + PAGE_SIZE, fExecutable, true /* fContiguous */,
    723871                                         ~(uint32_t)PAGE_OFFSET_MASK, _4G - PAGE_SIZE,
    724                                          RTR0MEMOBJTYPE_CONT, PAGE_SIZE);
     872                                         RTR0MEMOBJTYPE_CONT, PAGE_SIZE, false /*fOnKernelThread*/);
    725873    IPRT_DARWIN_RESTORE_EFL_AC();
    726874    return rc;
     
    746894        rc = rtR0MemObjNativeAllocWorker(ppMem, cb, false /* fExecutable */, true /* fContiguous */,
    747895                                         uAlignment <= PAGE_SIZE ? 0 : ~(mach_vm_address_t)(uAlignment - 1) /* PhysMask*/,
    748                                          UINT64_MAX, RTR0MEMOBJTYPE_PHYS, uAlignment);
     896                                         UINT64_MAX, RTR0MEMOBJTYPE_PHYS, uAlignment, false /*fOnKernelThread*/);
    749897    else
    750898    {
     
    757905
    758906        rc = rtR0MemObjNativeAllocWorker(ppMem, cb, false /* fExecutable */, true /* fContiguous */,
    759                                          PhysMask, PhysHighest, RTR0MEMOBJTYPE_PHYS, uAlignment);
     907                                         PhysMask, PhysHighest, RTR0MEMOBJTYPE_PHYS, uAlignment, false /*fOnKernelThread*/);
    760908    }
    761909
     
    11601308
    11611309
    1162 DECLHIDDEN(int) rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub, size_t cbSub, uint32_t fProt)
     1310/**
     1311 * Worker for rtR0MemObjNativeProtect that's typically called in a different
     1312 * context.
     1313 */
     1314static int rtR0MemObjNativeProtectWorker(PRTR0MEMOBJINTERNAL pMem, size_t offSub, size_t cbSub, uint32_t fProt)
    11631315{
    11641316    IPRT_DARWIN_SAVE_EFL_AC();
     
    12611413
    12621414
     1415/**
     1416 * rtR0MemObjNativeProtect kernel_task wrapper function.
     1417 */
     1418static void rtR0MemObjNativeProtectWorkerOnKernelThread(void *pvUser0, void *pvUser1)
     1419{
     1420    AssertPtr(pvUser0); Assert(pvUser1 == NULL); NOREF(pvUser1);
     1421    RTR0MEMOBJDARWINPROTECTARGS *pArgs = (RTR0MEMOBJDARWINPROTECTARGS *)pvUser0;
     1422    int rc = rtR0MemObjNativeProtectWorker(pArgs->pMem, pArgs->offSub, pArgs->cbSub, pArgs->fProt);
     1423    rtR0MemObjDarwinSignalThreadWaitinOnTask(&pArgs->Core, rc);
     1424}
     1425
     1426
     1427DECLHIDDEN(int) rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub, size_t cbSub, uint32_t fProt)
     1428{
     1429    /*
     1430     * The code won't work right because process codesigning properties leaks
     1431     * into kernel_map memory management.  So, if the user process we're running
     1432     * in has CS restrictions active, we cannot play around with the EXEC
     1433     * protection because some vm_fault.c think we're modifying the process map
     1434     * or something.  Looks like this problem was introduced in 10.10.5 or/and
     1435     * 10.11.0, so for for Yosemite and up we'll just push the work off to a thread
     1436     * running in the kernel_task context and hope it has be better chance of
     1437     * consistent results.
     1438     */
     1439    int rc;
     1440    if (   version_major >= 14 /* 10.10 = Yosemite */
     1441        && rtR0MemObjDarwinGetMap(pMem) == kernel_map)
     1442    {
     1443        RTR0MEMOBJDARWINPROTECTARGS Args;
     1444        Args.pMem       = pMem;
     1445        Args.offSub     = offSub;
     1446        Args.cbSub      = cbSub;
     1447        Args.fProt      = fProt;
     1448        rc = rtR0MemObjDarwinDoInKernelTaskThread(rtR0MemObjNativeProtectWorkerOnKernelThread, &Args.Core);
     1449    }
     1450    else
     1451        rc = rtR0MemObjNativeProtectWorker(pMem, offSub, cbSub, fProt);
     1452    return rc;
     1453}
     1454
     1455
    12631456DECLHIDDEN(RTHCPHYS) rtR0MemObjNativeGetPagePhysAddr(PRTR0MEMOBJINTERNAL pMem, size_t iPage)
    12641457{
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette