[Security] proactive defense: using read-only memory

From: Kees Cook
Date: Sun Nov 07 2010 - 14:35:27 EST


Hi,

While Dan Rosenberg is working to make things harder to locate potential
targets in the kernel through fixing kernel address leaks[1], I'd like
to approach a related proactive security measure: enforcing read-only
memory for things that would make good targets.

The proposal is simple: as much of the kernel should be read-only as
possible, most especially function pointers and other execution control
points, which are the easiest target to exploit when an arbitrary kernel
memory write becomes available[2] to an attacker. There has been past work
to "const"ify function pointer tables, and this should continue. However,
there are a few things that need further attention:

- Modules need to be correctly marked RO/NX. This patch exists[3], but is
not in mainline. It needs to be in mainline.

- Pointers to function table also need to be marked read-only after
they are set. An example of this is the security_ops table pointer. It
gets set once at boot, and never changes again. These need to be handled
so it isn't possible to just trivially reaim the entire security_ops
table lookup somewhere else.

- Architectures besides just x86 need to be considered.

- Entry points to set_kernel_text_rw() and similar need to be blockable.
Having these symbols available make kernel memory modification trivial;
there needs to be a way to disable these features for people that want
to harden their kernel further (though it obviously breaks things like
ftrace, ksplice, etc, but that should be the admin's choice).

The PaX solution[4] to most of this is to rearrange the loader and memory
sections of the kernel to make use of .rodata fully. For function table
pointers (and other critical things like GDT) that are less commonly
changed, PaX uses a simple approach of just disabling write-protection
when changing variables. For example:

pax_open_kernel();
security_ops = &default_security_ops;
pax_close_kernel();

And pax_(open|close)_kernel() are _inline_ functions so that
return-oriented-programming attacks cannot leave the system with
write-protection disabled:

static inline unsigned long native_pax_open_kernel(void)
{
unsigned long cr0;

preempt_disable();
barrier();
cr0 = read_cr0() ^ X86_CR0_WP;
BUG_ON(unlikely(cr0 & X86_CR0_WP));
write_cr0(cr0);
return cr0 ^ X86_CR0_WP;
}

And finally, we'll need to go through and address the remaining missing
"const" needs. My intention is to try to get through all these kinds of
changes, but it is going to need the help and understanding of many
subsystem maintainers. Hardening the kernel against manipulation is a win
for everyone. I'd like to try to move this forward, but I'd really
appreciate getting help with it; this will only be successful if people are
on board with it.

Thanks,

-Kees

P.S. If anyone would like to help us try to get more pieces of PaX and
grsecurity into mainline, please choose a thing you'd like to drive
forward, sign up[5] for it, and get to working on it.


[1] http://marc.info/?l=linux-netdev&m=128907432600565&w=2
http://marc.info/?t=128907683400002&r=1&w=2

[2] proactive security assumes there will be future kernel security
vulnerabilities and seeks to harden the system against exploitation.
For evidence of the steady stream of vulnerabilities, see:
http://lwn.net/Articles/410606/

[3] http://git.kernel.org/?p=linux/kernel/git/x86/linux-2.6-tip.git;a=commitdiff;h=65187d24fa3ef60f691f847c792e8eaca7e19251

[4] http://grsecurity.net/test.php
This feature is specifically "CONFIG_PAX_KERNEXEC".

[5] https://wiki.ubuntu.com/SecurityTeam/Roadmap/KernelHardening#Upstream%20Hardening

--
Kees Cook
Ubuntu Security Team
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/