View Full Version : Linux Kernel memory page protection? (ARM architecture)

February 8th, 2011, 03:54
Kernel fault Oops 80d occurred when I loaded a kernel module to write 4 bytes to kernel code that can be found from /proc/kallsyms.

However, root user using /dev/kmem with mmap can write to the same location and value with no problem.

Is it because the mapped kernel address c0xxxxxx have write protection? So if mmap to another location will have a different access right descriptor?

How may I adjust the access right descriptor for the kernel memory within a kernel module?

What's interesting is that I can do this without any problem in another kernel(same 2.6.29) that is very similar(same machine) but for older device.

The partial panic log:
<1>[ 761.930450] Unable to handle kernel paging request at virtual address c0******
<1>[ 761.939392] pgd = d005c000
<1>[ 761.942230] [c0******] *pgd=80e0840e(bad)
<4>[ 761.947845] Internal error: Oops: 80d [#1] PREEMPT
<4>[ 762.008178] Flags: NzCv IRQs on FIQs off Mode SVC_32 ISA ARM Segment user

The PC was at a STR R1, [R3] where R3 is the virtual address c0******.

fsr = 80d

800 is write?

if (fsr & (1 << 11)) /* write? */
mask = VM_WRITE;

d is section permission fault?

fault.c:fsr_info[] (entry 13)
{ do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault" },
const struct fsr_info *inf = fsr_info + (fsr & 15) + ((fsr & (1 << 10)) >> 6);
if (!inf->fn(addr, fsr, regs))
It shows that the fsr can be used to lookup the fsr_info table. So value d refers to the sect fault handler...

Ahha, found the suspect in arch/arm/mm/mmu.c. Some read only kernel memory section is being created for the executable area.

So now the question become:
How to alter what mmu.c has done on the page prot setting in the kernel module way?

After some trial and error when using codes inside probe_kernel_write(...), it has been proven that using set_fs(KERNEL_DS), which will change the curr_limit to something, could prevent the section access permission check being taken.

Practically, this is to first saving the current value from get_fs()....then set_fs(KERNEL_DS), after the job is done(writing to kernel text), set_fs(old_fs) to avoid any side effect.

This solution is the simplest form I believe, no pte/pmd need to be modified.

February 11th, 2011, 03:55