RIXI fixes.
PATCH 2/2 MIPS: Partially disable RIXI support.
In reply to Ralf BaechleExecution of break instruction, trap instructions, emulation of unaligned loads or floating point instructions - anything that tries to read the instruction's opcode from userspace - needs read access to a page.
RIXI (Read Inhibit / Execute Inhibit) support however allows the creation of pags that are executable but not readable. On such a mapping the attempted load of the opcode by the kernel is going to cause an endless loop of page faults.
The quick workaround for this is to disable the combinations that the kernel currently isn't able to handle which are executable mappings.
--- arch/mips/mm/cache.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
arch/mips/mm/cache.c +4 -4
@@ -160,18 +160,18 @@ static inline void setup_protection_map(void) protection_map[1 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC); protection_map[2 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ); protection_map[3 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC); - protection_map[4 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ); + protection_map[4 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT); protection_map[5 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT); - protection_map[6 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ); + protection_map[6 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT); protection_map[7 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT); protection_map[8 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ); protection_map[9 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC); protection_map[10 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE | _PAGE_NO_READ); protection_map[11 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE); - protection_map[12 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ); + protection_map[12 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT); protection_map[13 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT); - protection_map[14 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE | _PAGE_NO_READ); + protection_map[14 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE); protection_map[15 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE); }else {
Signature · 1 line
2.4.3
PATCH 1/2 MIPS: Handle page faults of executable but unreadable pages correctly.
In reply to Ralf BaechleWithout this we end taking execeptions in an endless loop hanging the thread.
--- arch/mips/mm/fault.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/mips/mm/fault.c +2 -1
@@ -133,7 +133,8 @@ good_area:#endif goto bad_area; } -if (!(vma->vm_flags &VM_READ )) { +if (!(vma->vm_flags &VM_READ ) && +exception_epc (regs) != address) {#if 0 pr_notice("Cpu%d[%s:%d:%0*lx:%ld:%0*lx] RI violation\n", raw_smp_processor_id(),
Signature · 1 line
2.4.3
cover RIXI fixes.
As part of unrelated work I ran into issus with RIXI support which allows the creation of pages that are executable but not readable. Problems arise with instruction emulation on such pages, for example when a load or store instruction is taking an unaligned exception, is an FPU instruction that requires emulation, a trap or break instruction of which the break code needs to bread and more.
A better solution would be to create a temporary mapping using kmap_coherent() but that's more complex so left for a later stage.
These patches have been sitting in a shady git tree for years but seem to work for me. Nevertheless Comments appreciated.
Cheers,
Ralf
Ralf Baechle (2):
MIPS: Handle page faults of executable but unreadable pages correctly.
MIPS: Partially disable RIXI support.
arch/mips/mm/cache.c | 8 ++++---- arch/mips/mm/fault.c | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-)
Signature · 1 line
2.4.3
Re: [PATCH 2/2] MIPS: Partially disable RIXI support.
In reply to Ralf BaechleQuoted 9 lines · Ralf Baechle
Execution of break instruction, trap instructions, emulation of unaligned loads or floating point instructions - anything that tries to read the instruction's opcode from userspace - needs read access to a page.
RIXI (Read Inhibit / Execute Inhibit) support however allows the creation of pags that are executable but not readable. On such a mapping the attempted load of the opcode by the kernel is going to cause an endless loop of page faults.
Quoted 4 lines
The quick workaround for this is to disable the combinations that the kernel currently isn't able to handle which are executable mappings.
Signed-off-by Ralf Baechle <[email protected]>
Cheers
James
Quoted 32 lines
--- arch/mips/mm/cache.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)arch/mips/mm/cache.c +4
-4@@ -160,18 +160,18 @@ static inline void setup_protection_map(void) protection_map[1 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC); protection_map[2 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ); protection_map[3 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC); - protection_map[4 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ); + protection_map[4 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT); protection_map[5 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT); - protection_map[6 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ); + protection_map[6 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT); protection_map[7 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT); protection_map[8 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ); protection_map[9 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC); protection_map[10 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE | _PAGE_NO_READ); protection_map[11 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE); - protection_map[12 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ); + protection_map[12 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT); protection_map[13 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT); - protection_map[14 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE | _PAGE_NO_READ); + protection_map[14 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE); protection_map[15 ] =__pgprot (_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE); }else {
Re: [PATCH 1/2] MIPS: Handle page faults of executable but unreadable pages correctly.
In reply to Ralf BaechleQuoted 2 lines · Ralf Baechle
Without this we end taking execeptions in an endless loop hanging the thread.
A little more explanation would be nice. Under what situations does this occur? Does this mean any VM_EXEC and !VM_READ page can't actually be faulted in without it being treated as an RI violation, or does it only affect when read from kernel emulation code?
Cheers
James
Quoted 21 lines
Signed-off-by Ralf Baechle <[email protected]>--- arch/mips/mm/fault.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)arch/mips/mm/fault.c +2
-1@@ -133,7 +133,8 @@ good_area:#endif goto bad_area; } -if (!(vma->vm_flags &VM_READ )) { +if (!(vma->vm_flags &VM_READ ) && +exception_epc (regs) != address) {#if 0 pr_notice("Cpu%d[%s:%d:%0*lx:%ld:%0*lx] RI violation\n", raw_smp_processor_id(),
Re: [PATCH 1/2] MIPS: Handle page faults of executable but unreadable pages correctly.
Quoted 9 lines · James Hogan
Quoted 2 lines · Ralf Baechle
Without this we end taking execeptions in an endless loop hanging the thread.
A little more explanation would be nice. Under what situations does this occur? Does this mean any
VM_EXECand !VM_READ page can't actually be faulted in without it being treated as an RI violation, or does it only affect when read from kernel emulation code?
Quoted 8 lines
arch/mips/mm/fault.c good_area: · line 140
Quoted 7 lines
arch/mips/mm/fault.c +2
-1-if (!(vma->vm_flags &VM_READ )) { +if (!(vma->vm_flags &VM_READ ) && +exception_epc (regs) != address) {#if 0 pr_notice("Cpu%d[%s:%d:%0*lx:%ld:%0*lx] RI violation\n", raw_smp_processor_id(),
The general idea is the change the code to treat loads of an instruction just like an instruction fetch. Which is achieved by adding the second condition "exception_epc(regs) != address" to the if above. exception_epc(regs) == address means
It would all be easier if Linux was enabling the separate exception codes for read and execution failure but short of that, a test like above must provide if a fault was an attempted instruction fetch or happend fetching data.
Ralf