[RFC PATCH 0/3] Use per-CPU temporary mappings for patching
Christophe Leroy
christophe.leroy at c-s.fr
Mon Mar 23 22:30:53 AEDT 2020
On 03/23/2020 04:52 AM, Christopher M. Riedl wrote:
> When compiled with CONFIG_STRICT_KERNEL_RWX, the kernel must create
> temporary mappings when patching itself. These mappings temporarily
> override the strict RWX text protections to permit a write. Currently,
> powerpc allocates a per-CPU VM area for patching. Patching occurs as
> follows:
>
> 1. Map page of text to be patched to per-CPU VM area w/
> PAGE_KERNEL protection
> 2. Patch text
> 3. Remove the temporary mapping
>
> While the VM area is per-CPU, the mapping is actually inserted into the
> kernel page tables. Presumably, this could allow another CPU to access
> the normally write-protected text - either malicously or accidentally -
> via this same mapping if the address of the VM area is known. Ideally,
> the mapping should be kept local to the CPU doing the patching (or any
> other sensitive operations requiring temporarily overriding memory
> protections) [0].
>
> x86 introduced "temporary mm" structs which allow the creation of
> mappings local to a particular CPU [1]. This series intends to bring the
> notion of a temporary mm to powerpc and harden powerpc by using such a
> mapping for patching a kernel with strict RWX permissions.
>
> The first patch introduces the temporary mm struct and API for powerpc
> along with a new function to retrieve a current hw breakpoint.
>
> The second patch uses the `poking_init` init hook added by the x86
> patches to initialize a temporary mm and patching address. The patching
> address is randomized between 0 and DEFAULT_MAP_WINDOW-PAGE_SIZE. The
> upper limit is necessary due to how the hash MMU operates - by default
> the space above DEFAULT_MAP_WINDOW is not available. For now, both hash
> and radix randomize inside this range. The number of possible random
> addresses is dependent on PAGE_SIZE and limited by DEFAULT_MAP_WINDOW.
>
> Bits of entropy with 64K page size on BOOK3S_64:
>
> bits-o-entropy = log2(DEFAULT_MAP_WINDOW_USER64 / PAGE_SIZE)
>
> PAGE_SIZE=64K, DEFAULT_MAP_WINDOW_USER64=128TB
> bits-o-entropy = log2(128TB / 64K)
> bits-o-entropy = 31
>
> Currently, randomization occurs only once during initialization at boot.
>
> The third patch replaces the VM area with the temporary mm in the
> patching code. The page for patching has to be mapped PAGE_SHARED with
> the hash MMU since hash prevents the kernel from accessing userspace
> pages with PAGE_PRIVILEGED bit set. There is on-going work on my side to
> explore if this is actually necessary in the hash codepath.
>
> Testing so far is limited to booting on QEMU (power8 and power9 targets)
> and a POWER8 VM along with setting some simple xmon breakpoints (which
> makes use of code-patching). A POC lkdtm test is in-progress to actually
> exploit the existing vulnerability (ie. the mapping during patching is
> exposed in kernel page tables and accessible by other CPUS) - this will
> accompany a future v1 of this series.
Got following failures on an 8xx. Note that "fault blocked by AP
register !" means an unauthorised access from Kernel to Userspace.
[ 6.113538] ------------[ cut here ]------------
[ 6.117852] Bug: fault blocked by AP register !
[ 6.117977] WARNING: CPU: 0 PID: 1 at
./arch/powerpc/include/asm/nohash/32/kup-8xx.h:67 do_page_fault+0x660/0x6ec
[ 6.132532] CPU: 0 PID: 1 Comm: swapper Tainted: G W
5.6.0-rc6-s3k-dev-00903-g70f8a9483ed5 #3524
[ 6.142484] NIP: c000f148 LR: c000f148 CTR: 00000000
[ 6.147490] REGS: c9023ca8 TRAP: 0700 Tainted: G W
(5.6.0-rc6-s3k-dev-00903-g70f8a9483ed5)
[ 6.157185] MSR: 00021032 <ME,IR,DR,RI> CR: 39023333 XER: a0002100
[ 6.163553]
[ 6.163553] GPR00: c000f148 c9023d60 c60ec000 00000023 c0924862
0000000b c0921f7a 6c742062
[ 6.163553] GPR08: 00001032 c088e534 00000000 00000004 39023333
00000000 c0003964 00000000
[ 6.163553] GPR16: 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000
[ 6.163553] GPR24: 00000000 00000000 c0730000 00000300 c60dc000
23085188 82000000 c9023db0
[ 6.198284] NIP [c000f148] do_page_fault+0x660/0x6ec
[ 6.203182] LR [c000f148] do_page_fault+0x660/0x6ec
[ 6.207958] Call Trace:
[ 6.210412] [c9023d60] [c000f148] do_page_fault+0x660/0x6ec (unreliable)
[ 6.217037] [c9023da0] [c000e2f0] handle_page_fault+0x8/0x34
[ 6.222684] --- interrupt: 301 at __patch_instruction+0x4/0x2c
[ 6.222684] LR = patch_instruction+0x144/0x324
[ 6.233138] [c9023e68] [c0013408] patch_instruction+0x120/0x324
(unreliable)
[ 6.240108] [c9023ee8] [c00114fc] mmu_mark_initmem_nx+0x44/0x124
[ 6.246039] [c9023f18] [c000f42c] free_initmem+0x20/0x58
[ 6.251292] [c9023f28] [c0003980] kernel_init+0x1c/0x130
[ 6.256538] [c9023f38] [c000e184] ret_from_kernel_thread+0x14/0x1c
[ 6.262605] Instruction dump:
[ 6.265542] 4182fc30 39200002 912a0610 7fa5eb78 38800002 38600007
4801e8a9 38600000
[ 6.273200] 4bfffa78 3c60c06d 38632f0c 4800eb95 <0fe00000> 3860000b
4bfffa60 73490040
[ 6.281034] ---[ end trace 18702eef58b6f5ff ]---
[ 6.285638] ------------[ cut here ]------------
[ 6.290233] WARNING: CPU: 0 PID: 1 at
arch/powerpc/lib/code-patching.c:182 patch_instruction+0x20c/0x324
[ 6.299575] CPU: 0 PID: 1 Comm: swapper Tainted: G W
5.6.0-rc6-s3k-dev-00903-g70f8a9483ed5 #3524
[ 6.309527] NIP: c00134f4 LR: c00134ec CTR: 00000000
[ 6.314533] REGS: c9023db0 TRAP: 0700 Tainted: G W
(5.6.0-rc6-s3k-dev-00903-g70f8a9483ed5)
[ 6.324229] MSR: 00021032 <ME,IR,DR,RI> CR: 55000933 XER: a0002100
[ 6.330597]
[ 6.330597] GPR00: 3d6a4000 c9023e68 c60ec000 00000001 c9023ea8
00000004 c0001188 00000004
[ 6.330597] GPR08: 00000000 00000000 00000000 c53720f0 33000333
00000000 c0003964 00000000
[ 6.330597] GPR16: 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000
[ 6.330597] GPR24: 00000000 00000000 c0730000 00009032 c0734b50
c0730000 c0001188 00000000
[ 6.365337] NIP [c00134f4] patch_instruction+0x20c/0x324
[ 6.370576] LR [c00134ec] patch_instruction+0x204/0x324
[ 6.375690] Call Trace:
[ 6.378150] [c9023e68] [c00134b8] patch_instruction+0x1d0/0x324
(unreliable)
[ 6.385121] [c9023ee8] [c00114fc] mmu_mark_initmem_nx+0x44/0x124
[ 6.391051] [c9023f18] [c000f42c] free_initmem+0x20/0x58
[ 6.396303] [c9023f28] [c0003980] kernel_init+0x1c/0x130
[ 6.401550] [c9023f38] [c000e184] ret_from_kernel_thread+0x14/0x1c
[ 6.407617] Instruction dump:
[ 6.410554] 2f890000 91220000 409e0010 81220070 712a0004 40820120
38a00004 38810040
[ 6.418212] 7fc3f378 4800086d 3123ffff 7c691910 <0f030000> 7f600124
7fe9fb78 80010084
[ 6.426046] ---[ end trace 18702eef58b6f600 ]---
[ 6.430941] ------------[ cut here ]------------
[ 6.435243] Bug: fault blocked by AP register !
[ 6.435363] WARNING: CPU: 0 PID: 1 at
./arch/powerpc/include/asm/nohash/32/kup-8xx.h:67 do_page_fault+0x660/0x6ec
[ 6.449923] CPU: 0 PID: 1 Comm: swapper Tainted: G W
5.6.0-rc6-s3k-dev-00903-g70f8a9483ed5 #3524
[ 6.459875] NIP: c000f148 LR: c000f148 CTR: 00000000
[ 6.464881] REGS: c9023ca8 TRAP: 0700 Tainted: G W
(5.6.0-rc6-s3k-dev-00903-g70f8a9483ed5)
[ 6.474577] MSR: 00021032 <ME,IR,DR,RI> CR: 39023333 XER: a0002100
[ 6.480945]
[ 6.480945] GPR00: c000f148 c9023d60 c60ec000 00000023 c0924862
0000000b c0921f7a 6c742062
[ 6.480945] GPR08: 00001032 c088e534 00000000 00000004 39023333
00000000 c0003964 00000000
[ 6.480945] GPR16: 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000
[ 6.480945] GPR24: 00000000 00000000 c0730000 00000300 c60dc000
2308511c 82000000 c9023db0
[ 6.515670] NIP [c000f148] do_page_fault+0x660/0x6ec
[ 6.520573] LR [c000f148] do_page_fault+0x660/0x6ec
[ 6.525350] Call Trace:
[ 6.527804] [c9023d60] [c000f148] do_page_fault+0x660/0x6ec (unreliable)
[ 6.534428] [c9023da0] [c000e2f0] handle_page_fault+0x8/0x34
[ 6.540072] --- interrupt: 301 at __patch_instruction+0x4/0x2c
[ 6.540072] LR = patch_instruction+0x144/0x324
[ 6.550531] [c9023e68] [c0013408] patch_instruction+0x120/0x324
(unreliable)
[ 6.557500] [c9023ee8] [c0011534] mmu_mark_initmem_nx+0x7c/0x124
[ 6.563431] [c9023f18] [c000f42c] free_initmem+0x20/0x58
[ 6.568683] [c9023f28] [c0003980] kernel_init+0x1c/0x130
[ 6.573931] [c9023f38] [c000e184] ret_from_kernel_thread+0x14/0x1c
[ 6.579996] Instruction dump:
[ 6.582934] 4182fc30 39200002 912a0610 7fa5eb78 38800002 38600007
4801e8a9 38600000
[ 6.590592] 4bfffa78 3c60c06d 38632f0c 4800eb95 <0fe00000> 3860000b
4bfffa60 73490040
[ 6.598425] ---[ end trace 18702eef58b6f601 ]---
[ 6.603026] ------------[ cut here ]------------
[ 6.607623] WARNING: CPU: 0 PID: 1 at
arch/powerpc/lib/code-patching.c:182 patch_instruction+0x20c/0x324
[ 6.616968] CPU: 0 PID: 1 Comm: swapper Tainted: G W
5.6.0-rc6-s3k-dev-00903-g70f8a9483ed5 #3524
[ 6.626919] NIP: c00134f4 LR: c00134ec CTR: 00000000
[ 6.631925] REGS: c9023db0 TRAP: 0700 Tainted: G W
(5.6.0-rc6-s3k-dev-00903-g70f8a9483ed5)
[ 6.641621] MSR: 00021032 <ME,IR,DR,RI> CR: 55000933 XER: a0002100
[ 6.647988]
[ 6.647988] GPR00: 2b8ac060 c9023e68 c60ec000 00000001 c9023ea8
00000004 c000111c 00000004
[ 6.647988] GPR08: 00000000 00000000 00000000 c53720f0 33000333
00000000 c0003964 00000000
[ 6.647988] GPR16: 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000
[ 6.647988] GPR24: 00000000 00000000 c0730000 00009032 c0734b50
c0730000 c000111c 00000000
[ 6.682728] NIP [c00134f4] patch_instruction+0x20c/0x324
[ 6.687968] LR [c00134ec] patch_instruction+0x204/0x324
[ 6.693082] Call Trace:
[ 6.695542] [c9023e68] [c00134b8] patch_instruction+0x1d0/0x324
(unreliable)
[ 6.702512] [c9023ee8] [c0011534] mmu_mark_initmem_nx+0x7c/0x124
[ 6.708443] [c9023f18] [c000f42c] free_initmem+0x20/0x58
[ 6.713694] [c9023f28] [c0003980] kernel_init+0x1c/0x130
[ 6.718942] [c9023f38] [c000e184] ret_from_kernel_thread+0x14/0x1c
[ 6.725008] Instruction dump:
[ 6.727946] 2f890000 91220000 409e0010 81220070 712a0004 40820120
38a00004 38810040
[ 6.735604] 7fc3f378 4800086d 3123ffff 7c691910 <0f030000> 7f600124
7fe9fb78 80010084
[ 6.743437] ---[ end trace 18702eef58b6f602 ]---
[ 6.759669] Freeing unused kernel memory: 496K
[ 6.764014] ------------[ cut here ]------------
[ 6.768382] Bug: fault blocked by AP register !
[ 6.768515] WARNING: CPU: 0 PID: 1 at
./arch/powerpc/include/asm/nohash/32/kup-8xx.h:67 do_page_fault+0x660/0x6ec
[ 6.783065] CPU: 0 PID: 1 Comm: swapper Tainted: G W
5.6.0-rc6-s3k-dev-00903-g70f8a9483ed5 #3524
[ 6.793016] NIP: c000f148 LR: c000f148 CTR: 00000000
[ 6.798022] REGS: c9023c98 TRAP: 0700 Tainted: G W
(5.6.0-rc6-s3k-dev-00903-g70f8a9483ed5)
[ 6.807717] MSR: 00021032 <ME,IR,DR,RI> CR: 39023333 XER: a0002100
[ 6.814085]
[ 6.814085] GPR00: c000f148 c9023d50 c60ec000 00000023 c0924862
0000000b c0921f7a 6c742062
[ 6.814085] GPR08: 00001032 c088e534 00000000 00000004 39023333
00000000 c0003964 00000000
[ 6.814085] GPR16: 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000
[ 6.814085] GPR24: 00000000 00000000 c0730000 00000300 c60dc000
230852b0 82000000 c9023da0
[ 6.848811] NIP [c000f148] do_page_fault+0x660/0x6ec
[ 6.853714] LR [c000f148] do_page_fault+0x660/0x6ec
[ 6.858491] Call Trace:
[ 6.860944] [c9023d50] [c000f148] do_page_fault+0x660/0x6ec (unreliable)
[ 6.867569] [c9023d90] [c000e2f0] handle_page_fault+0x8/0x34
[ 6.873215] --- interrupt: 301 at __patch_instruction+0x4/0x2c
[ 6.873215] LR = patch_instruction+0x144/0x324
[ 6.883670] [c9023e58] [c0013408] patch_instruction+0x120/0x324
(unreliable)
[ 6.890640] [c9023ed8] [c0011624] mmu_mark_rodata_ro+0x48/0xf8
[ 6.896401] [c9023f08] [c000fe50] mark_rodata_ro+0xc4/0xd8
[ 6.901824] [c9023f28] [c0003998] kernel_init+0x34/0x130
[ 6.907072] [c9023f38] [c000e184] ret_from_kernel_thread+0x14/0x1c
[ 6.913137] Instruction dump:
[ 6.916074] 4182fc30 39200002 912a0610 7fa5eb78 38800002 38600007
4801e8a9 38600000
[ 6.923732] 4bfffa78 3c60c06d 38632f0c 4800eb95 <0fe00000> 3860000b
4bfffa60 73490040
[ 6.931565] ---[ end trace 18702eef58b6f603 ]---
[ 6.936166] ------------[ cut here ]------------
[ 6.940763] WARNING: CPU: 0 PID: 1 at
arch/powerpc/lib/code-patching.c:182 patch_instruction+0x20c/0x324
[ 6.950108] CPU: 0 PID: 1 Comm: swapper Tainted: G W
5.6.0-rc6-s3k-dev-00903-g70f8a9483ed5 #3524
[ 6.960059] NIP: c00134f4 LR: c00134ec CTR: 00000000
[ 6.965067] REGS: c9023da0 TRAP: 0700 Tainted: G W
(5.6.0-rc6-s3k-dev-00903-g70f8a9483ed5)
[ 6.974761] MSR: 00021032 <ME,IR,DR,RI> CR: 99000333 XER: a0002100
[ 6.981129]
[ 6.981129] GPR00: 3d6aff80 c9023e58 c60ec000 00000001 c9023e98
00000004 c00012b0 00000004
[ 6.981129] GPR08: 00000000 fffffffe 00000000 00000000 39000335
00000000 c0003964 00000000
[ 6.981129] GPR16: 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000
[ 6.981129] GPR24: 00000000 00000000 c0730000 00009032 c0734b50
c0730000 c00012b0 00000000
[ 7.015870] NIP [c00134f4] patch_instruction+0x20c/0x324
[ 7.021109] LR [c00134ec] patch_instruction+0x204/0x324
[ 7.026222] Call Trace:
[ 7.028683] [c9023e58] [c00134b8] patch_instruction+0x1d0/0x324
(unreliable)
[ 7.035653] [c9023ed8] [c0011624] mmu_mark_rodata_ro+0x48/0xf8
[ 7.041415] [c9023f08] [c000fe50] mark_rodata_ro+0xc4/0xd8
[ 7.046835] [c9023f28] [c0003998] kernel_init+0x34/0x130
[ 7.052083] [c9023f38] [c000e184] ret_from_kernel_thread+0x14/0x1c
[ 7.058149] Instruction dump:
[ 7.061086] 2f890000 91220000 409e0010 81220070 712a0004 40820120
38a00004 38810040
[ 7.068744] 7fc3f378 4800086d 3123ffff 7c691910 <0f030000> 7f600124
7fe9fb78 80010084
[ 7.076578] ---[ end trace 18702eef58b6f604 ]---
Christophe
More information about the Linuxppc-dev
mailing list