[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
i386 W^X
- To: misc_(_at_)_cvs_(_dot_)_openbsd_(_dot_)_org
- Subject: i386 W^X
- From: Theo de Raadt <deraadt_(_at_)_cvs_(_dot_)_openbsd_(_dot_)_org>
- Date: Thu, 17 Apr 2003 00:08:20 -0600
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