| From 2a6e3cf63f58e289802a11faad5fb495e2d04e97 Mon Sep 17 00:00:00 2001 |
| From: vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> |
| Date: Wed, 9 Dec 2020 18:59:04 +0000 |
| Subject: [PATCH] Runtime/memobj-r0drv-linux.c: Changes to support the upcoming |
| 5.10 kernel, bugref:9879 |
| |
| Upstream-Status: Backport |
| |
| git-svn-id: http://www.virtualbox.org/svn/vbox@87074 cfe28804-0f27-0410-a406-dd0f0b0b656f |
| |
| Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com> |
| --- |
| .../Runtime/r0drv/linux/memobj-r0drv-linux.c | 68 ++++++++++++++++++- |
| 1 file changed, 67 insertions(+), 1 deletion(-) |
| |
| --- a/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c |
| +++ b/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c |
| @@ -56,9 +56,19 @@ |
| * Whether we use alloc_vm_area (3.2+) for executable memory. |
| * This is a must for 5.8+, but we enable it all the way back to 3.2.x for |
| * better W^R compliance (fExecutable flag). */ |
| -#if RTLNX_VER_MIN(3,2,0) || defined(DOXYGEN_RUNNING) |
| +#if RTLNX_VER_RANGE(3,2,0, 5,10,0) || defined(DOXYGEN_RUNNING) |
| # define IPRT_USE_ALLOC_VM_AREA_FOR_EXEC |
| #endif |
| +/** @def IPRT_USE_APPLY_TO_PAGE_RANGE_FOR_EXEC |
| + * alloc_vm_area was removed with 5.10 so we have to resort to a different way |
| + * to allocate executable memory. |
| + * It would be possible to remove IPRT_USE_ALLOC_VM_AREA_FOR_EXEC and use |
| + * this path execlusively for 3.2+ but no time to test it really works on every |
| + * supported kernel, so better play safe for now. |
| + */ |
| +#if RTLNX_VER_MIN(5,10,0) || defined(DOXYGEN_RUNNING) |
| +# define IPRT_USE_APPLY_TO_PAGE_RANGE_FOR_EXEC |
| +#endif |
| |
| /* |
| * 2.6.29+ kernels don't work with remap_pfn_range() anymore because |
| @@ -502,6 +512,46 @@ static void rtR0MemObjLinuxFreePages(PRT |
| } |
| |
| |
| +#ifdef IPRT_USE_APPLY_TO_PAGE_RANGE_FOR_EXEC |
| +/** |
| + * User data passed to the apply_to_page_range() callback. |
| + */ |
| +typedef struct LNXAPPLYPGRANGE |
| +{ |
| + /** Pointer to the memory object. */ |
| + PRTR0MEMOBJLNX pMemLnx; |
| + /** The page protection flags to apply. */ |
| + pgprot_t fPg; |
| +} LNXAPPLYPGRANGE; |
| +/** Pointer to the user data. */ |
| +typedef LNXAPPLYPGRANGE *PLNXAPPLYPGRANGE; |
| +/** Pointer to the const user data. */ |
| +typedef const LNXAPPLYPGRANGE *PCLNXAPPLYPGRANGE; |
| + |
| +/** |
| + * Callback called in apply_to_page_range(). |
| + * |
| + * @returns Linux status code. |
| + * @param pPte Pointer to the page table entry for the given address. |
| + * @param uAddr The address to apply the new protection to. |
| + * @param pvUser The opaque user data. |
| + */ |
| +#ifdef __i386__ |
| +static int rtR0MemObjLinuxApplyPageRange(pte_t *pPte, unsigned long uAddr, void *pvUser) |
| +#else |
| +static DECLCALLBACK(int) rtR0MemObjLinuxApplyPageRange(pte_t *pPte, unsigned long uAddr, void *pvUser) |
| +#endif |
| +{ |
| + PCLNXAPPLYPGRANGE pArgs = (PCLNXAPPLYPGRANGE)pvUser; |
| + PRTR0MEMOBJLNX pMemLnx = pArgs->pMemLnx; |
| + size_t idxPg = (uAddr - (unsigned long)pMemLnx->Core.pv) >> PAGE_SHIFT; |
| + |
| + set_pte(pPte, mk_pte(pMemLnx->apPages[idxPg], pArgs->fPg)); |
| + return 0; |
| +} |
| +#endif |
| + |
| + |
| /** |
| * Maps the allocation into ring-0. |
| * |
| @@ -584,6 +634,11 @@ static int rtR0MemObjLinuxVMap(PRTR0MEMO |
| else |
| # endif |
| { |
| +# if defined(IPRT_USE_APPLY_TO_PAGE_RANGE_FOR_EXEC) |
| + if (fExecutable) |
| + pgprot_val(fPg) |= _PAGE_NX; /* Uses RTR0MemObjProtect to clear NX when memory ready, W^X fashion. */ |
| +# endif |
| + |
| # ifdef VM_MAP |
| pMemLnx->Core.pv = vmap(&pMemLnx->apPages[0], pMemLnx->cPages, VM_MAP, fPg); |
| # else |
| @@ -1851,6 +1906,21 @@ DECLHIDDEN(int) rtR0MemObjNativeProtect( |
| preempt_enable(); |
| return VINF_SUCCESS; |
| } |
| +# elif defined(IPRT_USE_APPLY_TO_PAGE_RANGE_FOR_EXEC) |
| + PRTR0MEMOBJLNX pMemLnx = (PRTR0MEMOBJLNX)pMem; |
| + if ( pMemLnx->fExecutable |
| + && pMemLnx->fMappedToRing0) |
| + { |
| + LNXAPPLYPGRANGE Args; |
| + Args.pMemLnx = pMemLnx; |
| + Args.fPg = rtR0MemObjLinuxConvertProt(fProt, true /*fKernel*/); |
| + int rcLnx = apply_to_page_range(current->active_mm, (unsigned long)pMemLnx->Core.pv + offSub, cbSub, |
| + rtR0MemObjLinuxApplyPageRange, (void *)&Args); |
| + if (rcLnx) |
| + return VERR_NOT_SUPPORTED; |
| + |
| + return VINF_SUCCESS; |
| + } |
| # endif |
| |
| NOREF(pMem); |