I'm not sure if I'm asking the question right, but I'm wondering if it's possible for a C or ASM program to write at the virtual adress 0x0 ?
I know the kernel don't allow write/read at virtual 0x0, but I'm wondering if there's some strange way to do this. Using maybe a flag for ld or gcc that I don't know about ?
The settings are as follow :
- Computer running Linux on x86-64
- Can use root if necessary
Three steps are needed to do this:
Configure the system to permit mapping memory at address zero. This is done by setting the
vm.mmap_min_addrsysctl to 0:If you are using Wine on the system, there's a chance this sysctl is already configured as it is needed for Wine to be able to execute 16 bit code.
An alterative to
vm.mmap_min_addr=0is to run your process withCAP_SYS_RAWIO, such as by running as root likesudo strace ./a.out. (stracelets you see the system calls it makes, so you can seemmapreturn a successful0rather than(void*)-1)Establish a mapping at address 0. To let the kernel have you write data to address 0, you need to map some memory there. This is easily done by calling
mmapto map some memory there or by arranging for your binary to load a segment there.For an
mmapexample, see allocating address zero on Linux with mmap failsDereference a pointer to address 0. This can be done with C code like
*(int *)0 = 42.This happens to compile to the asm we want with GCC or clang with optimization disabled1.
Footnote 1:
0is a null pointer constant in C, and dereferencing it is undefined behaviour. With optimization disabled, GCC and clang just compile to asm that stores to that address (Godbolt) , but clang warns indirection of non-volatile null pointer will be deleted, not trap, consider using__builtin_trap()or qualifying pointer with 'volatile'. That is indeed what happens with optimization enabled. GCC-O2or higher still emits a store instruction, but on x86-64 follows it with aud2illegal instruction trap.volatile int *volatile zero_ptr = 0;*zero_ptr = 42;works in GCC and clang to hide the UB from the compiler: Godbolt. (Making the pointer object itselfvolatilehides the fact that it's a null pointer. Making it a pointer tovolatile intworks around a GCC bug(?) where it optimizes away the actual store, perhaps assuming that it can't be pointing to anything with a lifetime that outlasts this function.)