﻿id	summary	reporter	owner	description	type	status	component	version	resolution	keywords	cc	guest	host
18945	Linux 5.4: no more arbitrary executable pages and more changes	Frank Batschulat (Oracle)	Frank Batschulat (Oracle)	"It was kindly pointed out that the Linux 5.4 kernel will no longer make interfaces available so that arbitrary kernel modules may modify page attributes to turn the executable bit on/off. Virtualbox currently is one of such kernel modules doing that.
{{{
From: ""Larry Finger"" <Larry.Finger@xxxxxxxx>
To: vbox-dev@virtualbox.org
Subject: [vbox-dev] Problem with kernel 5.4
Date: Wed, 18 Sep 2019 21:16:12 +0200

In kernel 5.4, the wrapper routines set_pages_x() and set_pages_nx() that enable/disable execution of memory are removed. The underlying routines set_memory_x() and set_memory_nx() are not, and will not be exported. See
[http://lkml.iu.edu/hypermail/linux/kernel/1909.2/02763.html]
for a   discussion of the issue.

I have currently disabled the only calls to these routines, which occur in alloc-r0drv-linux.c. My test VMs appear to work OK.

Is there some case where allocated pages really need to be executable? If  so, then the developers at Oracle will need to consult with Linus to develop a method that will be acceptable. In the meantime, I have developed a patch that allows a build with kernel 5.4 that eliminates the offending calls.

Larry
}}}

[https://www.virtualbox.org/pipermail/vbox-dev/2019-September/015343.html][[BR]]
[http://lkml.iu.edu/hypermail/linux/kernel/1909.2/02763.html][[BR]]
[http://lkml.iu.edu/hypermail/linux/kernel/1909.2/02837.html][[BR]]

Lets see where and how we get that:

trunk/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h
{{{
339 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
340 # define MY_SET_PAGES_EXEC(pPages, cPages)    set_pages_x(pPages, cPages)
341 # define MY_SET_PAGES_NOEXEC(pPages, cPages)  set_pages_nx(pPages, cPages)
342 #else
343 # define MY_SET_PAGES_EXEC(pPages, cPages) \
344     do { \
345         if (pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL)) \
346             MY_CHANGE_PAGE_ATTR(pPages, cPages, MY_PAGE_KERNEL_EXEC); \
347     } while (0)
348 # define MY_SET_PAGES_NOEXEC(pPages, cPages) \
349     do { \
350         if (pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL)) \
351             MY_CHANGE_PAGE_ATTR(pPages, cPages, PAGE_KERNEL); \
352     } while (0)
353 #endif
}}}
C symbol: MY_SET_PAGES_EXEC
{{{
  File                 Function                  Line
0 the-linux-kernel.h   <global>                  340 #define MY_SET_PAGES_EXEC(pPages, cPages) set_pages_x(pPages,
                                                     cPages)
1 the-linux-kernel.h   <global>                  343 #define MY_SET_PAGES_EXEC(pPages, cPages) \
2 alloc-r0drv-linux.c  RTMemContAlloc            447 MY_SET_PAGES_EXEC(&paPages[iPage], 1);
3 memobj-r0drv-linux.c rtR0MemObjLinuxAllocPages 374 MY_SET_PAGES_EXEC(pMemLnx->apPages[iPage], 1);
}}}
trunk/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c
{{{
385  * Allocates physical contiguous memory (below 4GB).
386  * The allocation is page aligned and the content is undefined.
387  *
388  * @returns Pointer to the memory block. This is page aligned.
389  * @param   pPhys   Where to store the physical address.
390  * @param   cb      The allocation size in bytes. This is always
391  *                  rounded up to PAGE_SIZE.
392  */
393 RTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb)
[...]
428          * Reserve the pages and mark them executable.
429          */            
430         unsigned iPage;                         
431         for (iPage = 0; iPage < cPages; iPage++)
[...]
445             SetPageReserved(&paPages[iPage]);                                                                       446 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 20) /** @todo find the exact kernel where change_page_attr was introdu    ced. */        
447             MY_SET_PAGES_EXEC(&paPages[iPage], 1);
448 #endif   
449         }  
}}}
trunk/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c
{{{
 282  * Internal worker that allocates physical pages and creates the memory object for them.
 283  *
 284  * @returns IPRT status code.
 285  * @param   ppMemLnx    Where to store the memory object pointer.
 286  * @param   enmType     The object type.
 287  * @param   cb          The number of bytes to allocate.
 288  * @param   uAlignment  The alignment of the physical memory.
 289  *                      Only valid if fContiguous == true, ignored otherwise.
 290  * @param   fFlagsLnx   The page allocation flags (GPFs).
 291  * @param   fContiguous Whether the allocation must be contiguous.
 292  * @param   rcNoMem     What to return when we're out of pages.
 293  */
 294 static int rtR0MemObjLinuxAllocPages(PRTR0MEMOBJLNX *ppMemLnx, RTR0MEMOBJTYPE enmType, size_t cb,
 295                                      size_t uAlignment, gfp_t fFlagsLnx, bool fContiguous, int rcNoMem)
 296 {
[...]
 323      * Allocate the pages.
 324      * For small allocations we'll try contiguous first and then fall back on page by page.
 325      */
 326 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
 327     if (    fContiguous
 328         ||  cb <= PAGE_SIZE * 2)
 329     {  
[...]
 363 #else /* < 2.4.22 */
 364     /** @todo figure out why we didn't allocate page-by-page on 2.4.21 and older... */
 365     paPages = alloc_pages(fFlagsLnx, rtR0MemObjLinuxOrder(cPages));
 366     if (!paPages)
 367     {
 368         rtR0MemObjDelete(&pMemLnx->Core);
 369         return rcNoMem;
 370     }
 371     for (iPage = 0; iPage < cPages; iPage++)
 372     {
 373         pMemLnx->apPages[iPage] = &paPages[iPage];
 374         MY_SET_PAGES_EXEC(pMemLnx->apPages[iPage], 1);
 375         if (PageHighMem(pMemLnx->apPages[iPage]))
 376             BUG();
 377     }
 378 
 379     fContiguous = true;
 380 #endif /* < 2.4.22 */
}}}

I'll investigate why we'd possibly think we need this anyways and seek to remove that code.
"	defect	closed	host support	VirtualBox 6.0.12	fixed	linux54 exec page		other	Linux
