From: Jordan Niethe <hidden> Date: 2021-06-09 01:35:43
From: Russell Currey <redacted>
The set_memory_{ro/rw/nx/x}() functions are required for
STRICT_MODULE_RWX, and are generally useful primitives to have. This
implementation is designed to be generic across powerpc's many MMUs.
It's possible that this could be optimised to be faster for specific
MMUs.
This implementation does not handle cases where the caller is attempting
to change the mapping of the page it is executing from, or if another
CPU is concurrently using the page being altered. These cases likely
shouldn't happen, but a more complex implementation with MMU-specific code
could safely handle them.
On hash, the linear mapping is not kept in the linux pagetable, so this
will not change the protection if used on that range. Currently these
functions are not used on the linear map so just WARN for now.
apply_to_existing_page_range() does not work on huge pages so for now
disallow changing the protection of huge pages.
Reviewed-by: Daniel Axtens <redacted>
Signed-off-by: Russell Currey <redacted>
Signed-off-by: Christophe Leroy <redacted>
[jpn: - Allow set memory functions to be used without Strict RWX
- Hash: Disallow certain regions
- Have change_page_attr() take function pointers to manipulate ptes
- Radix: Add ptesync after set_pte_at()]
Signed-off-by: Jordan Niethe <redacted>
---
v10: WARN if trying to change the hash linear map
v11: - Update copywrite dates
- Allow set memory functions to be used without Strict RWX
- Hash: Disallow certain regions and add comment explaining why
- Have change_page_attr() take function pointers to manipulate ptes
- Clarify change_page_attr()'s comment
- Radix: Add ptesync after set_pte_at()
v12: - change_page_attr() back to taking an action value
- disallow operating on huge pages
v14: - only check is_vm_area_hugepages() for virtual memory
---
arch/powerpc/Kconfig | 1 +
arch/powerpc/include/asm/set_memory.h | 32 ++++++++
arch/powerpc/mm/Makefile | 2 +-
arch/powerpc/mm/pageattr.c | 101 ++++++++++++++++++++++++++
4 files changed, 135 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/include/asm/set_memory.h
create mode 100644 arch/powerpc/mm/pageattr.c
@@ -0,0 +1,101 @@+// SPDX-License-Identifier: GPL-2.0++/*+*MMU-genericset_memoryimplementationforpowerpc+*+*Copyright2019-2021,IBMCorporation.+*/++#include<linux/mm.h>+#include<linux/vmalloc.h>+#include<linux/set_memory.h>++#include<asm/mmu.h>+#include<asm/page.h>+#include<asm/pgtable.h>+++/*+*Updatestheattributesofapageinthreesteps:+*+*1.invalidatethepagetableentry+*2.flushtheTLB+*3.installthenewentrywiththeupdatedattributes+*+*Invalidatingtheptemeanstherearesituationswherethiswillnotwork+*whenintheoryitshould.+*Forexample:+*-removingwritefrompagewhilstitisbeingexecuted+*-settingapageread-onlywhilstitisbeingreadbyanotherCPU+*+*/+staticintchange_page_attr(pte_t*ptep,unsignedlongaddr,void*data)+{+longaction=(long)data;+pte_tpte;++spin_lock(&init_mm.page_table_lock);++/* invalidate the PTE so it's safe to modify */+pte=ptep_get_and_clear(&init_mm,addr,ptep);+flush_tlb_kernel_range(addr,addr+PAGE_SIZE);++/* modify the PTE bits as desired, then apply */+switch(action){+caseSET_MEMORY_RO:+pte=pte_wrprotect(pte);+break;+caseSET_MEMORY_RW:+pte=pte_mkwrite(pte_mkdirty(pte));+break;+caseSET_MEMORY_NX:+pte=pte_exprotect(pte);+break;+caseSET_MEMORY_X:+pte=pte_mkexec(pte);+break;+default:+WARN_ON_ONCE(1);+break;+}++set_pte_at(&init_mm,addr,ptep,pte);++/* See ptesync comment in radix__set_pte_at() */+if(radix_enabled())+asmvolatile("ptesync":::"memory");+spin_unlock(&init_mm.page_table_lock);++return0;+}++intchange_memory_attr(unsignedlongaddr,intnumpages,longaction)+{+unsignedlongstart=ALIGN_DOWN(addr,PAGE_SIZE);+unsignedlongsize=numpages*PAGE_SIZE;++if(!numpages)+return0;++if(WARN_ON_ONCE(is_vmalloc_or_module_addr((void*)addr)&&+is_vm_area_hugepages((void*)addr)))+return-EINVAL;++#ifdef CONFIG_PPC_BOOK3S_64+/*+*Onhash,thelinearmappingisnotintheLinuxpagetableso+*apply_to_existing_page_range()willhavenoeffect.Ifinthefuture+*theset_memory_*functionsareusedonthelinearmapthiswillneed+*tobeupdated.+*/+if(!radix_enabled()){+intregion=get_region_id(addr);++if(WARN_ON_ONCE(region!=VMALLOC_REGION_ID&®ion!=IO_REGION_ID))+return-EINVAL;+}+#endif++returnapply_to_existing_page_range(&init_mm,start,size,+change_page_attr,(void*)action);+}
From: Jordan Niethe <hidden> Date: 2021-06-09 01:36:13
setup_text_poke_area() is a late init call so it runs before
mark_rodata_ro() and after the init calls. This lets all the init code
patching simply write to their locations. In the future, kprobes is
going to allocate its instruction pages RO which means they will need
setup_text__poke_area() to have been already called for their code
patching. However, init_kprobes() (which allocates and patches some
instruction pages) is an early init call so it happens before
setup_text__poke_area().
start_kernel() calls poking_init() before any of the init calls. On
powerpc, poking_init() is currently a nop. setup_text_poke_area() relies
on kernel virtual memory, cpu hotplug and per_cpu_areas being setup.
setup_per_cpu_areas(), boot_cpu_hotplug_init() and mm_init() are called
before poking_init().
Turn setup_text_poke_area() into poking_init().
Reviewed-by: Christophe Leroy <redacted>
Reviewed-by: Russell Currey <redacted>
Signed-off-by: Jordan Niethe <redacted>
---
v9: New to series
---
arch/powerpc/lib/code-patching.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
@@ -70,14 +70,11 @@ static int text_area_cpu_down(unsigned int cpu)}/*-*Runasalateinitcall.Thisallowsalltheboottimepatchingtobedone-*simplybypatchingthecode,andthenwe'recalledherepriorto-*mark_rodata_ro(),whichhappensafterallinitcallsarerun.Although-*BUG_ON()isrude,inthiscaseitshouldonlyhappenifENOMEM,andwejudge-*itasbeingpreferabletoakernelthatwillcrashlaterwhensomeonetries-*tousepatch_instruction().+*AlthoughBUG_ON()isrude,inthiscaseitshouldonlyhappenifENOMEM,and+*wejudgeitasbeingpreferabletoakernelthatwillcrashlaterwhen+*someonetriestousepatch_instruction().*/-staticint__initsetup_text_poke_area(void)+int__initpoking_init(void){BUG_ON(!cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,"powerpc/text_poke:online",text_area_cpu_up,
@@ -85,7 +82,6 @@ static int __init setup_text_poke_area(void)return0;}-late_initcall(setup_text_poke_area);/**Thiscanbecalledforkerneltextoramodule.
From: Jordan Niethe <hidden> Date: 2021-06-09 01:36:38
Make module_alloc() use PAGE_KERNEL protections instead of
PAGE_KERNEL_EXEX if Strict Module RWX is enabled.
Signed-off-by: Jordan Niethe <redacted>
---
v14: - Split out from powerpc: Set ARCH_HAS_STRICT_MODULE_RWX
- Add and use strict_module_rwx_enabled() helper
---
arch/powerpc/include/asm/mmu.h | 5 +++++
arch/powerpc/kernel/module.c | 4 +++-
2 files changed, 8 insertions(+), 1 deletion(-)
@@ -345,6 +345,11 @@ static inline bool strict_kernel_rwx_enabled(void)returnfalse;}#endif++staticinlineboolstrict_module_rwx_enabled(void)+{+returnIS_ENABLED(CONFIG_STRICT_MODULE_RWX)&&strict_kernel_rwx_enabled();+}#endif /* !__ASSEMBLY__ *//* The kernel use the constants below to index in the page sizes array.
From: Jordan Niethe <hidden> Date: 2021-06-09 01:37:01
From: Russell Currey <redacted>
Add the arch specific insn page allocator for powerpc. This allocates
ROX pages if STRICT_KERNEL_RWX is enabled. These pages are only written
to with patch_instruction() which is able to write RO pages.
Reviewed-by: Daniel Axtens <redacted>
Signed-off-by: Russell Currey <redacted>
Signed-off-by: Christophe Leroy <redacted>
[jpn: Reword commit message, switch to __vmalloc_node_range()]
Signed-off-by: Jordan Niethe <redacted>
---
v9: - vmalloc_exec() no longer exists
- Set the page to RW before freeing it
v10: - use __vmalloc_node_range()
v11: - Neaten up
v12: - Switch from __vmalloc_node_range() to module_alloc()
v13: Use strict_kernel_rwx_enabled()
v14: Use strict_module_rwx_enabled()
---
arch/powerpc/kernel/kprobes.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
From: Jordan Niethe <hidden> Date: 2021-06-09 01:37:25
Commit 74451e66d516 ("bpf: make jited programs visible in traces") added
a default bpf_jit_free() implementation. Powerpc did not use the default
bpf_jit_free() as powerpc did not set the images read-only. The default
bpf_jit_free() called bpf_jit_binary_unlock_ro() is why it could not be
used for powerpc.
Commit d53d2f78cead ("bpf: Use vmalloc special flag") moved keeping
track of read-only memory to vmalloc. This included removing
bpf_jit_binary_unlock_ro(). Therefore there is no reason powerpc needs
its own bpf_jit_free(). Remove it.
Reviewed-by: Christophe Leroy <redacted>
Signed-off-by: Jordan Niethe <redacted>
---
v11: New to series
---
arch/powerpc/net/bpf_jit_comp.c | 12 ------------
1 file changed, 12 deletions(-)
From: Jordan Niethe <hidden> Date: 2021-06-09 01:37:54
Add the necessary call to bpf_jit_binary_lock_ro() to remove write and
add exec permissions to the JIT image after it has finished being
written.
Without CONFIG_STRICT_MODULE_RWX the image will be writable and
executable until the call to bpf_jit_binary_lock_ro().
Reviewed-by: Christophe Leroy <redacted>
Signed-off-by: Jordan Niethe <redacted>
---
v10: New to series
v11: Remove CONFIG_STRICT_MODULE_RWX conditional
---
arch/powerpc/net/bpf_jit_comp.c | 1 +
1 file changed, 1 insertion(+)
From: Jordan Niethe <hidden> Date: 2021-06-09 01:38:18
From: Russell Currey <redacted>
To enable strict module RWX on powerpc, set:
CONFIG_STRICT_MODULE_RWX=y
You should also have CONFIG_STRICT_KERNEL_RWX=y set to have any real
security benefit.
ARCH_HAS_STRICT_MODULE_RWX is set to require ARCH_HAS_STRICT_KERNEL_RWX.
This is due to a quirk in arch/Kconfig and arch/powerpc/Kconfig that
makes STRICT_MODULE_RWX *on by default* in configurations where
STRICT_KERNEL_RWX is *unavailable*.
Since this doesn't make much sense, and module RWX without kernel RWX
doesn't make much sense, having the same dependencies as kernel RWX
works around this problem.
Book3s/32 603 and 604 core processors are not able to write protect
kernel pages so do not set ARCH_HAS_STRICT_MODULE_RWX for Book3s/32.
Reviewed-by: Christophe Leroy <redacted>
Signed-off-by: Russell Currey <redacted>
[jpn: - predicate on !PPC_BOOK3S_604
- make module_alloc() use PAGE_KERNEL protection]
Signed-off-by: Jordan Niethe <redacted>
---
v10: - Predicate on !PPC_BOOK3S_604
- Make module_alloc() use PAGE_KERNEL protection
v11: - Neaten up
v13: Use strict_kernel_rwx_enabled()
v14: Make changes to module_alloc() its own commit
v15: - Force STRICT_KERNEL_RWX if STRICT_MODULE_RWX is selected
- Predicate on !PPC_BOOK3S_32 instead
---
arch/powerpc/Kconfig | 2 ++
1 file changed, 2 insertions(+)
From: Jordan Niethe <hidden> Date: 2021-06-09 01:38:41
From: Christophe Leroy <redacted>
In addition to the set_memory_xx() functions which allows to change
the memory attributes of not (yet) used memory regions, implement a
set_memory_attr() function to:
- set the final memory protection after init on currently used
kernel regions.
- enable/disable kernel memory regions in the scope of DEBUG_PAGEALLOC.
Unlike the set_memory_xx() which can act in three step as the regions
are unused, this function must modify 'on the fly' as the kernel is
executing from them. At the moment only PPC32 will use it and changing
page attributes on the fly is not an issue.
Signed-off-by: Christophe Leroy <redacted>
Reported-by: kbuild test robot <redacted>
[ruscur: cast "data" to unsigned long instead of int]
Signed-off-by: Russell Currey <redacted>
Signed-off-by: Jordan Niethe <redacted>
---
arch/powerpc/include/asm/set_memory.h | 2 ++
arch/powerpc/mm/pageattr.c | 33 +++++++++++++++++++++++++++
2 files changed, 35 insertions(+)
@@ -29,4 +29,6 @@ static inline int set_memory_x(unsigned long addr, int numpages)returnchange_memory_attr(addr,numpages,SET_MEMORY_X);}+intset_memory_attr(unsignedlongaddr,intnumpages,pgprot_tprot);+#endif
@@ -99,3 +99,36 @@ int change_memory_attr(unsigned long addr, int numpages, long action)returnapply_to_existing_page_range(&init_mm,start,size,change_page_attr,(void*)action);}++/*+*Settheattributesofapage:+*+*ThisfunctionisusedbyPPC32attheendofinittosetfinalkernelmemory+*protection.Itincludeschangingthemapingofthepageitisexecutingfrom+*anddatapagesitisusing.+*/+staticintset_page_attr(pte_t*ptep,unsignedlongaddr,void*data)+{+pgprot_tprot=__pgprot((unsignedlong)data);++spin_lock(&init_mm.page_table_lock);++set_pte_at(&init_mm,addr,ptep,pte_modify(*ptep,prot));+flush_tlb_kernel_range(addr,addr+PAGE_SIZE);++spin_unlock(&init_mm.page_table_lock);++return0;+}++intset_memory_attr(unsignedlongaddr,intnumpages,pgprot_tprot)+{+unsignedlongstart=ALIGN_DOWN(addr,PAGE_SIZE);+unsignedlongsz=numpages*PAGE_SIZE;++if(numpages<=0)+return0;++returnapply_to_existing_page_range(&init_mm,start,sz,set_page_attr,+(void*)pgprot_val(prot));+}
From: Jordan Niethe <hidden> Date: 2021-06-09 01:39:06
From: Christophe Leroy <redacted>
Use set_memory_attr() instead of the PPC32 specific change_page_attr()
change_page_attr() was checking that the address was not mapped by
blocks and was handling highmem, but that's unneeded because the
affected pages can't be in highmem and block mapping verification
is already done by the callers.
Signed-off-by: Christophe Leroy <redacted>
[ruscur: rebase on powerpc/merge with Christophe's new patches]
Signed-off-by: Russell Currey <redacted>
Signed-off-by: Jordan Niethe <redacted>
---
arch/powerpc/mm/pgtable_32.c | 60 ++++++------------------------------
1 file changed, 10 insertions(+), 50 deletions(-)
@@ -198,20 +155,18 @@ void mark_rodata_ro(void)return;}-page=virt_to_page(_stext);numpages=PFN_UP((unsignedlong)_etext)-PFN_DOWN((unsignedlong)_stext);-change_page_attr(page,numpages,PAGE_KERNEL_ROX);+set_memory_attr((unsignedlong)_stext,numpages,PAGE_KERNEL_ROX);/**mark.rodataasreadonly.Use__init_beginratherthan__end_rodata*tocoverNOTESandEXCEPTION_TABLE.*/-page=virt_to_page(__start_rodata);numpages=PFN_UP((unsignedlong)__init_begin)-PFN_DOWN((unsignedlong)__start_rodata);-change_page_attr(page,numpages,PAGE_KERNEL_RO);+set_memory_attr((unsignedlong)__start_rodata,numpages,PAGE_KERNEL_RO);// mark_initmem_nx() should have already run by nowptdump_check_wx();
From: Russell Currey <redacted>
To enable strict module RWX on powerpc, set:
CONFIG_STRICT_MODULE_RWX=y
You should also have CONFIG_STRICT_KERNEL_RWX=y set to have any real
security benefit.
ARCH_HAS_STRICT_MODULE_RWX is set to require ARCH_HAS_STRICT_KERNEL_RWX.
This is due to a quirk in arch/Kconfig and arch/powerpc/Kconfig that
makes STRICT_MODULE_RWX *on by default* in configurations where
STRICT_KERNEL_RWX is *unavailable*.
Since this doesn't make much sense, and module RWX without kernel RWX
doesn't make much sense, having the same dependencies as kernel RWX
works around this problem.
Book3s/32 603 and 604 core processors are not able to write protect
kernel pages so do not set ARCH_HAS_STRICT_MODULE_RWX for Book3s/32.
Reviewed-by: Christophe Leroy <redacted>
Signed-off-by: Russell Currey <redacted>
[jpn: - predicate on !PPC_BOOK3S_604
- make module_alloc() use PAGE_KERNEL protection]
Signed-off-by: Jordan Niethe <redacted>
---
v10: - Predicate on !PPC_BOOK3S_604
- Make module_alloc() use PAGE_KERNEL protection
v11: - Neaten up
v13: Use strict_kernel_rwx_enabled()
v14: Make changes to module_alloc() its own commit
v15: - Force STRICT_KERNEL_RWX if STRICT_MODULE_RWX is selected
- Predicate on !PPC_BOOK3S_32 instead
---
arch/powerpc/Kconfig | 2 ++
1 file changed, 2 insertions(+)
@@ -35,10 +35,7 @@ static int change_page_attr(pte_t *ptep, unsigned long addr, void *data)pte_tpte;spin_lock(&init_mm.page_table_lock);--/* invalidate the PTE so it's safe to modify */-pte=ptep_get_and_clear(&init_mm,addr,ptep);-flush_tlb_kernel_range(addr,addr+PAGE_SIZE);+pte=*ptep;/* modify the PTE bits as desired, then apply */switch(action){
@@ -60,10 +57,7 @@ static int change_page_attr(pte_t *ptep, unsigned long addr, void *data)}set_pte_at(&init_mm,addr,ptep,pte);--/* See ptesync comment in radix__set_pte_at() */-if(radix_enabled())-asmvolatile("ptesync":::"memory");+flush_tlb_kernel_range(addr,addr+PAGE_SIZE);spin_unlock(&init_mm.page_table_lock);return0;---
What I think is happening is that the virtio_console code is running
at the same time we are doing the `module_enable_ro` at the end of
`do_init_module` due to the async nature of the work handler. There is
a window after the TLB flush when the PTE has its permission bits
cleared, so any translations of the module code page attempted during
that window will fault.
I'm ignorant of strict rwx in general so I don't see why we need to
clear the bits before setting them to their final value, but as I
understand it, the set_pte_at + flush_tlb_kernel_range satisfy the ISA
requirement of [ptesync; tlbie; eieio; tlbsync; ptesync;] so it seems
like the patch should work.
Now, I cannot explain why the crash always happens around the code
that does the module's symbols relocation (the NIP in Laurent's trace
is the TOC reload from module_64.c:restore_r2). Maybe because
instructions are already in icache until the first branch into the
stub?
Anyway, this is what Murilo and I found out over our debugging session
in the past couple of days. I hope it helps. =)
@@ -35,10 +35,7 @@ static int change_page_attr(pte_t *ptep, unsigned long addr, void *data)pte_tpte;spin_lock(&init_mm.page_table_lock);--/* invalidate the PTE so it's safe to modify */-pte=ptep_get_and_clear(&init_mm,addr,ptep);-flush_tlb_kernel_range(addr,addr+PAGE_SIZE);+pte=*ptep;/* modify the PTE bits as desired, then apply */switch(action){
@@ -60,10 +57,7 @@ static int change_page_attr(pte_t *ptep, unsigned long addr, void *data)}set_pte_at(&init_mm,addr,ptep,pte);--/* See ptesync comment in radix__set_pte_at() */-if(radix_enabled())-asmvolatile("ptesync":::"memory");+flush_tlb_kernel_range(addr,addr+PAGE_SIZE);spin_unlock(&init_mm.page_table_lock);return0;---
What I think is happening is that the virtio_console code is running
at the same time we are doing the `module_enable_ro` at the end of
`do_init_module` due to the async nature of the work handler. There is
a window after the TLB flush when the PTE has its permission bits
cleared, so any translations of the module code page attempted during
that window will fault.
Thanks for looking at this. I agree that this is the problem.
This avoids the crash (not a proper solution):
I'm ignorant of strict rwx in general so I don't see why we need to
clear the bits before setting them to their final value, but as I
understand it, the set_pte_at + flush_tlb_kernel_range satisfy the ISA
requirement of [ptesync; tlbie; eieio; tlbsync; ptesync;] so it seems
like the patch should work.
I believe it's done like that because ISA 6.10.1.2 Modifying a
Translation Table Entry -
"The sequence is equivalent to deleting the PTE and then adding a new one".
In that sequence, I think it is [set pte to 0; ptesync; tlbie; eieio;
tlbsync; ptesync;]
But it does seem like we need to do something like your patch for
change_page_attr() to work as expected.
Now, I cannot explain why the crash always happens around the code
that does the module's symbols relocation (the NIP in Laurent's trace
is the TOC reload from module_64.c:restore_r2). Maybe because
instructions are already in icache until the first branch into the
stub?
Yeah, mpe thought it might be some cache effect of a branch instruction.
From time to time I did see Oopses like this (not "kernel tried to
execute exec-protected page")
[ 124.986964][ T52] Oops: Kernel access of bad area, sig: 11 [#1]
[ 124.987043][ T52] LE PAGE_SIZE=64K MMU=Radix SMP NR_CPUS=2048 NUMA pSeries
[ 124.987095][ T52] Modules linked in: virtio_console binfmt_misc
virtiofs fuse virtio_net virtio_blk virtio_pci virtio_pci_modern_dev
virtio_ring virtio crc32c_vpmsum [last unloaded: virtio_console]
[ 124.987209][ T52] CPU: 2 PID: 52 Comm: kworker/2:1 Not tainted
5.14.0-rc4 #4
[ 124.987259][ T52] Workqueue: events control_work_handler [virtio_console]
[ 124.987307][ T52] NIP: c008000001a86044 LR: c008000001a82cf8
CTR: c00000000042a6c0
[ 124.987358][ T52] REGS: c00000000b273770 TRAP: 0300 Not tainted
(5.14.0-rc4)
[ 124.987406][ T52] MSR: 800000000280b033
<SF,VEC,VSX,EE,FP,ME,IR,DR,RI,LE> CR: 82002882 XER: 00000004
[ 124.987475][ T52] CFAR: c008000001a82cf4 DAR: c008000001a86058
DSISR: 40000000 IRQMASK: 0
[ 124.987475][ T52] GPR00: c008000001a82ce8 c00000000b273a10
c008000001ab8000 c000000010731320
[ 124.987475][ T52] GPR04: 0000000000000001 0000000000000000
0000000000000000 0000000000000000
[ 124.987475][ T52] GPR08: 0000000000000000 0000000000000000
0000000000000000 c008000001a86038
[ 124.987475][ T52] GPR12: 0000000022002884 c0000001ffffdf00
c000000000169ae8 c0000000037700c0
[ 124.987475][ T52] GPR16: 0000000000000000 0000000000000000
c000000021af0000 c000000003313900
[ 124.987475][ T52] GPR20: 0000000000000001 0000000000000000
0000000000000000 c000000003316780
[ 124.987475][ T52] GPR24: c008000001a90288 0000000000000000
0000000000000000 c000000010731320
[ 124.987475][ T52] GPR28: c000000003316900 0000000000000018
0000000000000068 c00000000379c5a0
[ 124.988028][ T52] NIP [c008000001a86044] fini+0x824/0xa7e0 [virtio_console]
[ 124.988085][ T52] LR [c008000001a82cf8] fill_queue+0xb0/0x230
[virtio_console]
[ 124.988141][ T52] Call Trace:
[ 124.988171][ T52] [c00000000b273a10] [c008000001a82ce8]
fill_queue+0xa0/0x230 [virtio_console] (unreliable)
[ 124.988246][ T52] [c00000000b273aa0] [c008000001a83208]
add_port.isra.0+0x1a0/0x4b0 [virtio_console]
[ 124.988312][ T52] [c00000000b273b70] [c008000001a85474]
control_work_handler+0x46c/0x654 [virtio_console]
[ 124.988403][ T52] [c00000000b273c70] [c00000000015ce60]
process_one_work+0x2a0/0x570
[ 124.988586][ T52] [c00000000b273d10] [c00000000015d1d8]
worker_thread+0xa8/0x660
[ 124.988684][ T52] [c00000000b273da0] [c000000000169c5c] kthread+0x17c/0x190
[ 124.988762][ T52] [c00000000b273e10] [c00000000000cf54]
ret_from_kernel_thread+0x5c/0x64
[ 124.988916][ T52] Instruction dump:
[ 124.988965][ T52] 396be010 f8410018 e98b0020 7d8903a6 4e800420
00000000 73747562 003a0300
[ 124.989152][ T52] c0000000 3d62fffd 396be038 f8410018 <e98b0020>
7d8903a6 4e800420 00000000
[ 124.989298][ T52] ---[ end trace ab9046c024eb3154 ]---
I guess it depends on the timing of which pte is invalidated.
Anyway, this is what Murilo and I found out over our debugging session
in the past couple of days. I hope it helps. =)