[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

i386 W^X



for the record, i386 W^X works as follows:

we want to be able to ensure that no X page is ever W, or any W page
is ever X.  unless the application requests it, of course...

we have already modified the machine-independent code to try to
generate executables where this is true.  that required modifying
(fixing) gcc for the trampolines, placing the system signal trampoline
differently, putting GOT and PLT in their own ELF segments, moving
more stuff into .rodata, etc.  a whole slog of changes.  so the
machine independent kernel believes that an X bit exists per-page on
the cpu.

however, on some architectures it does not.  like the vax, m68k, i386,
or powerpc.

on the i386, we have a way of saying "code below this line can be
executed, above this it cannot be executed".  this is called the "code
segment limit".

our problem is we want to ensure that no W page can be X.  so we
turned the problem upside down: we ensure that all X pages are below
that line, and all W pages are above that line.

with a.out and static executables, you have this.


			stack


		...

			main bss	rw
			main bss	rw
			main data	rw
			main data	rw
			--- we can place the line here
			main code    	rx		
			main code	rx
			main code	rx
	00000000	unmapped


with dynamic executables this does not work


			stack


		...

			libc data	rw
			libc data	rw
			libc data	rw
			libc code	rx
			libc code	rx
			libc code	rx
			libc code	rx
			gap
			ld.so data	rw
			ld.so data	rw
			ld.so code	rx
			ld.so code	rx
			gap
			main bss	rw
			main bss	rw
			main data	rw
			main data	rw
			main code    	rx
			main code	rx
			main code	rx
	00000000	unmapped

there is no place to put the line, because any place you would put the line,
you have writable memory.

so how did we solve this?  in each executable (program, ld.so, or shared
library) we put a virtual 1GB gap.

			stack


		...

			libc data	rw
			libc data	rw
			libc data	rw
			gap
			ld.so data	rw
			ld.so data	rw
			gap
			main bss	rw
			main bss	rw
			main data	rw
			main data	rw
	40000000	unmapped
			--- we can place the line here
			...

			libc code	rx
			libc code	rx
			libc code	rx
			libc code	rx
			gap
			ld.so code	rx
			ld.so code	rx
			gap
			gap
			main code    	rx
			main code	rx
			main code	rx
	00000000	unmapped

this is how the problem is solved.  now, the i386 in 3.3-current has no
pages that are both writeble and executable.

we are going to do the same trick with the powerpc, which has 16 "zones"
seperated by 15 "lines"



Visit your host, monkey.org