Re: [PATCH v2] x86/mm: Refuse W^X violations

From: Guenter Roeck
Date: Wed Sep 21 2022 - 23:09:31 EST


On 9/21/22 15:59, Guenter Roeck wrote:
On 9/21/22 13:59, Dave Hansen wrote:
On 9/21/22 13:07, Guenter Roeck wrote:
[    2.042861] CPA refuse W^X violation: 8000000000000063 -> 0000000000000063 range: 0x00000000c00a0000 - 0x00000000c00a0fff PFN a0
ILLOPC: cbc65efa: 0f 0b
[    2.043267] WARNING: CPU: 0 PID: 1 at arch/x86/mm/pat/set_memory.c:600 __change_page_attr_set_clr+0xdca/0xdd0
...
[    2.050307] ---[ end trace 0000000000000000 ]---
[    2.050762] PCI: PCI BIOS area is rw and x. Use pci=nobios if you want it NX.
[    2.051115] kernel tried to execute NX-protected page - exploit attempt? (uid: 0)
[    2.051115] BUG: unable to handle page fault for address: c00fd2bf

This _looks_ like it is working as intended.  The PCI BIOS code tried to
make a RWX page.  The CPA code refused to do it and presumably returned
an error, leaving a RW page, non-executable page.  The PCI code didn't
check the set_memory_x() return code and tried to go execute anyway.
That resulted in the oops.

I was able to reproduce this pretty easily.  The workaround from dmesg
is pci=nobios.  That seems to do the trick for me, although that advise
was sandwiched between a warning and an oops, so not the easiest to find.

I'm a bit torn what to do on this one.  Breaking the boot is bad, but so
is leaving RWX memory around.

Thoughts?

For my part I'll do what the above suggests, ie run tests with PAE enabled
with pci=nobios command line option. AFAICS that hides the problem in my tests.
I am just not sure if that is really appropriate.


Oh well, that "helped" to hide one of the crashes. Here is another one.
This is with PAE enabled and booting through efi32.

Guenter

---
[ 1.080779] ------------[ cut here ]------------
[ 1.080959] CPA refuse W^X violation: 8000000000000063 -> 0000000000000063 range: 0x00000000d0770000 - 0x00000000d0770fff PFN edcd
ILLOPC: c7465efa: 0f 0b
[ 1.081467] WARNING: CPU: 0 PID: 0 at arch/x86/mm/pat/set_memory.c:600 __change_page_attr_set_clr+0xdca/0xdd0
[ 1.082120] Modules linked in:
[ 1.082476] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 6.0.0-rc6-next-20220921 #1
[ 1.082706] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 0.0.0 02/06/2015
[ 1.082988] EIP: __change_page_attr_set_clr+0xdca/0xdd0
[ 1.083187] Code: 10 8b 45 ac 89 7c 24 04 89 74 24 14 89 4c 24 1c 8d 8e ff 0f 00 00 89 4c 24 18 89 44 24 08 c7 04 24 38 67 88 c8 e8 56 38 fb 00 <0f> 0b eb 83 66 90 55 89 e5 57 56 89 d6 53 89 c3 83 ec 58 31 d2 8b
[ 1.083672] EAX: 00000076 EBX: 0edcd063 ECX: 00000000 EDX: 00000003
[ 1.083830] ESI: d0770000 EDI: 00000063 EBP: c8a3dea8 ESP: c8a3dd90
[ 1.083984] DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 EFLAGS: 00200296
[ 1.084286] CR0: 80050033 CR2: ffbff000 CR3: 08d7c000 CR4: 000006b0
[ 1.084501] Call Trace:
[ 1.084849] ? __this_cpu_preempt_check+0xf/0x11
[ 1.085053] ? __purge_vmap_area_lazy+0x6c/0x640
[ 1.085269] ? _vm_unmap_aliases.part.0+0x1d8/0x1f0
[ 1.085415] ? __mutex_unlock_slowpath+0x2b/0x2b0
[ 1.085536] ? purge_fragmented_blocks_allcpus+0x64/0x2c0
[ 1.085696] ? _vm_unmap_aliases.part.0+0x1d8/0x1f0
[ 1.085820] ? _vm_unmap_aliases.part.0+0x54/0x1f0
[ 1.086004] change_page_attr_set_clr+0x11d/0x2d0
[ 1.086313] ? __efi_memmap_init+0x70/0xd3
[ 1.086475] set_memory_x+0x56/0x60
[ 1.086592] efi_runtime_update_mappings+0x36/0x42
[ 1.086717] efi_enter_virtual_mode+0x351/0x36e
[ 1.086860] start_kernel+0x57d/0x60f
[ 1.086956] ? set_intr_gate+0x42/0x55
[ 1.087079] i386_start_kernel+0x43/0x45
[ 1.087272] startup_32_smp+0x161/0x164
[ 1.087491] irq event stamp: 6582
[ 1.087593] hardirqs last enabled at (6590): [<c74e7119>] __up_console_sem+0x69/0x80
[ 1.087824] hardirqs last disabled at (6597): [<c74e70fd>] __up_console_sem+0x4d/0x80
[ 1.088010] softirqs last enabled at (6571): [<c7429a94>] call_on_stack+0x14/0x60
[ 1.088278] softirqs last disabled at (6614): [<c7429a94>] call_on_stack+0x14/0x60
[ 1.088466] ---[ end trace 0000000000000000 ]---
[ 1.089237] kernel tried to execute NX-protected page - exploit attempt? (uid: 0)
[ 1.089237] BUG: unable to handle page fault for address: d0810e2a
[ 1.089237] #PF: supervisor instruction fetch in kernel mode
[ 1.089237] #PF: error_code(0x0011) - permissions violation
[ 1.089237] *pdpt = 0000000008d78001 *pde = 000000000eec6067 *pte = 800000000fe98063
[ 1.089237] Oops: 0011 [#1] PREEMPT SMP PTI
[ 1.089237] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 6.0.0-rc6-next-20220921 #1
[ 1.089237] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 0.0.0 02/06/2015
[ 1.089237] EIP: 0xd0810e2a
[ 1.089237] Code: 75 0c ff 75 08 68 c1 45 81 d0 6a 40 e8 ef ce ff ff 83 c4 20 83 ec 0c 53 e8 d4 cf ff ff 83 c4 10 31 c0 8d 65 f4 5b 5e 5f 5d c3 <55> 89 e5 57 56 53 bb 02 00 00 80 83 ec 5c 8b 7d 08 85 ff 0f 84 ed
[ 1.089237] EAX: d0810e2a EBX: 00200202 ECX: 00000049 EDX: 00000000
[ 1.089237] ESI: c8a3df30 EDI: c84c5000 EBP: c8a3df20 ESP: c8a3def8
[ 1.089237] DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 EFLAGS: 00200202
[ 1.089237] CR0: 80050033 CR2: d0810e2a CR3: 08d7c000 CR4: 000006b0
[ 1.089237] Call Trace:
[ 1.089237] ? virt_efi_set_variable_nonblocking+0x80/0xf0
[ 1.089237] ? virt_efi_reset_system+0xe0/0xe0
[ 1.089237] efi_delete_dummy_variable+0x55/0x70
[ 1.089237] efi_enter_virtual_mode+0x356/0x36e
[ 1.089237] start_kernel+0x57d/0x60f
[ 1.089237] ? set_intr_gate+0x42/0x55
[ 1.089237] i386_start_kernel+0x43/0x45
[ 1.089237] startup_32_smp+0x161/0x164
[ 1.089237] Modules linked in:
[ 1.089237] CR2: 00000000d0810e2a
[ 1.089237] ---[ end trace 0000000000000000 ]---
[ 1.089237] EIP: 0xd0810e2a