Change value of WP bit in cr0 when cr0 is panned

Hadfi Abdel Moumene
3 min readApr 14, 2020

--

In this article , we will talk about WP bit in cr0 and how to change his value when cr0 is panned .

Cr0 register

the cr0 is a control register in x86 , he contains system control flags that control operating mode and states of the processor.

the cr0 register is 32 bits in all 32-bit modes and in 64-bit mode, he is expanded to 64 bits.

WP bit

write protect (WP) is the 16 bit in cr0 register and when he is set (equals to 1) the CPU can’t write to read-only pages when privilege level is 0 (kernel mode) .

Change value of WP bit

[1/3] x86/asm: Pin sensitive CR0 bits

after this patch if you went to change the value of WP bit with this function

static inline void write_cr0(unsigned long x);

you gonna just get a permission error .

because the kernel does not allow you to remove write protection from the cr0 register with this part of code in write_cr0 function.

if (static_branch_likely(&cr_pinning)) {
if (unlikely((val & X86_CR0_WP) != X86_CR0_WP)) {
bits_missing = X86_CR0_WP;
val |= bits_missing;
goto set_register;
}
/* Warn after we've set the missing bits. */
WARN_ONCE(bits_missing, "CR0 WP bit went missing!?\n");
}

so how we can change WP value ?

we know that lkm run in level 0 so we can just write directly to cr0 registry and we don’t need to call write_cr0() function .

i defined this function that gonna replace write_cr0() function

extern unsigned long __force_order ;
static inline void write_forced_cr0(unsigned long value) {
asm volatile("mov %0,%%cr0":"+r"(value),"+m"(__force_order));
}

__force_order is used to force instruction serialization.

the complete code for the lkm :

when i insert this module into the kernel , i get :

we notice the the value of WP bit was changed .

to get the code :

References

--

--

Hadfi Abdel Moumene

linux kernel developer interested in reverse engineering & malware analysis