proactive defense: using read-only memory
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/
[4] http://grsecurity.net/test.php
This feature is specifically "CONFIG_PAX_KERNEXEC".
[5] https://wiki.ubuntu.com/SecurityTeam/Roadmap/KernelHardening#Upstream%20Hardening
Signature · 2 lines
Kees Cook Ubuntu Security Team
Re: [Security] proactive defense: using read-only memory, RO/NX modules
Quoted 6 lines · Kees Cook
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.
Nice! IMHO we need more of that. (If the readonly section gets big enough in practice we could perhaps even mark it large-page in the future. It could serve as an allocator to module code as well - that would probably be a speedup even for modules.)
Quoted 11 lines
[...]
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.
[...]
Quoted 2 lines
The reason the RO/NX patch from Siarhei Liakh is not upstream yet is rather mundane:
it introduced regressions - it caused boot crashes on one of my testboxes.
But there is no fundamental reason why it shouldnt be upstream. We can push it upstream if the crashes are resolved and if it gets an Ack from Rusty or Linus for the module bits.
Siarhei, what's the status of your RO/NX changes?
Thanks,
Ingo
Re: [Security] proactive defense: using read-only memory, RO/NX modules
Quoted 4 lines
Nice! IMHO we need more of that. (If the readonly section gets big enough in practice we could perhaps even mark it large-page in the future. It could serve as an allocator to module code as well - that would probably be a speedup even for modules.)
You ideally want one other thing to go with it. While a non-guest can't support it the marking of pages "permanently and irrevocably" readonly in a guest is something a hypedvisor can happily enforce and provide for the lifetime of the guest.
Alan
Re: [Security] proactive defense: using read-only memory, RO/NX modules
In reply to Ingo MolnarHi,
Quoted 10 lines · Ingo Molnar
Quoted 4 lines · Kees Cook
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.
Nice! IMHO we need more of that. (If the readonly section gets big enough in practice we could perhaps even mark it large-page in the future. It could serve as an allocator to module code as well - that would probably be a speedup even for modules.)
Well, I can try to extract and send what PaX does, but it seems relatively incompatible with the existing system that uses set_kernel_text_rw() and friends.
Quoted 4 lines
Quoted 2 lines
- Modules need to be correctly marked RO/NX. This patch exists[3], but is not in mainline. It needs to be in mainline.
[...]
Quoted 1 line
Quoted 8 lines
Quoted 1 line
The reason the RO/NX patch from Siarhei Liakh is not upstream yet is rather mundane:
it introduced regressions - it caused boot crashes on one of my testboxes.But there is no fundamental reason why it shouldnt be upstream. We can push it upstream if the crashes are resolved and if it gets an Ack from Rusty or Linus for the module bits.
Oh, well, yes, that's a good reason. :) Where was this covered? I'd like to help get it reproduced and ironed out.
-Kees
Signature · 2 lines
Kees Cook Ubuntu Security Team
Re: [Security] proactive defense: using read-only memory, RO/NX modules
Quoted 27 lines · Kees Cook
Hi,
Quoted 10 lines · Ingo Molnar
Quoted 4 lines · Kees Cook
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.
Nice! IMHO we need more of that. (If the readonly section gets big enough in practice we could perhaps even mark it large-page in the future. It could serve as an allocator to module code as well - that would probably be a speedup even for modules.)
Well, I can try to extract and send what PaX does, but it seems relatively incompatible with the existing system that uses
set_kernel_text_rw()and friends.Quoted 9 lines
Quoted 2 lines
- Modules need to be correctly marked RO/NX. This patch exists[3], but is not in mainline. It needs to be in mainline.
[...]
Quoted 2 lines
The reason the RO/NX patch from Siarhei Liakh is not upstream yet is rather mundane:
it introduced regressions - it caused boot crashes on one of my testboxes.
Quoted 6 lines
Quoted 3 lines
But there is no fundamental reason why it shouldnt be upstream. We can push it upstream if the crashes are resolved and if it gets an Ack from Rusty or Linus for the module bits.
Oh, well, yes, that's a good reason. :) Where was this covered? I'd like to help get it reproduced and ironed out.
Matthieu Castet seems to have dusted off those patches and submitted two of them in this mail:
Subject: [RFC] reworked NX protection for kernel data
Matthieu, are you still interested in this topic?
The original, broken patches were these -tip commits:
1e858c081af5: x86, mm: RO/NX protection for loadable kernel modules 18c60ddc9eff: x86, mm: NX protection for kernel data
c226a2feba21: x86, mm: Set first MB as RW+NX
b29d530510d4: x86, mm: Correcting improper large page preservation
I reported one of the crashes in:
Subject: Re: [tip:x86/mm] x86, mm: Set first MB as RW+NX
on lkml.
Thanks,
Ingo
Re: [Security] proactive defense: using read-only memory, RO/NX modules
Hi Ingo,
Quoted 18 lines · Ingo Molnar
Quoted 2 lines · Kees Cook
Oh, well, yes, that's a good reason. :) Where was this covered? I'd like to help get it reproduced and ironed out.
Matthieu Castet seems to have dusted off those patches and submitted two of them in this mail:
Subject: [RFC] reworked NX protection for kernel data
Matthieu, are you still interested in this topic?
The original, broken patches were these -tip commits:
1e858c081af5: x86, mm: RO/NX protection for loadable kernel modules18c60ddc9eff: x86, mm: NX protection for kernel data
c226a2feba21: x86, mm: Set first MB as RW+NX
b29d530510d4: x86, mm: Correcting improper large page preservation
Quoted 5 lines
I reported one of the crashes in:
Subject: Re: [tip:x86/mm] x86, mm: Set first MB as RW+NX
on lkml.
Thanks for looking this up!
Can we get 1e858c081af5 and 18c60ddc9eff back in, and then work forward from there?
-Kees
Signature · 2 lines
Kees Cook Ubuntu Security Team
Re: [Security] proactive defense: using read-only memory, RO/NX modules
Quoted 23 lines · Kees Cook
Hi Ingo,
Quoted 20 lines · Ingo Molnar
Quoted 2 lines · Kees Cook
Oh, well, yes, that's a good reason. :) Where was this covered? I'd like to help get it reproduced and ironed out.
Matthieu Castet seems to have dusted off those patches and submitted two of them in this mail:
Subject: [RFC] reworked NX protection for kernel data
Matthieu, are you still interested in this topic?
The original, broken patches were these -tip commits:
1e858c081af5: x86, mm: RO/NX protection for loadable kernel modules18c60ddc9eff: x86, mm: NX protection for kernel data
c226a2feba21: x86, mm: Set first MB as RW+NX
b29d530510d4: x86, mm: Correcting improper large page preservationI reported one of the crashes in:
Quoted 8 lines
Quoted 3 lines
Subject: Re: [tip:x86/mm] x86, mm: Set first MB as RW+NX
on lkml.
Thanks for looking this up!
Can we get
1e858c081af5and18c60ddc9effback in, and then work forward from there?
Yeah. Please port them to latest -tip:
http://people.redhat.com/mingo/tip.git/README
And give them some testing, and send out the new series. I'll re-report the crash to you for a new kernel, if it still occurs.
(Please also keep Rusty and Linus Cc:-ed for the module bits.)
In hindsight, i think the kernel/module.c bits should be in arch/x86/kernel/module.c
- the new code is full of x86 only names and facilities.
Also, please remove various checkpatch col80 artifacts, such as:
+ if (end_pfn > begin_pfn)
+ set_memory_nx(begin_pfn << PAGE_SHIFT,
+ end_pfn - begin_pfn);
that should be:
+ if (end_pfn > begin_pfn)
+ set_memory_nx(begin_pfn << PAGE_SHIFT, end_pfn - begin_pfn);
Thanks,
Ingo
Re: [Security] proactive defense: using read-only memory, RO/NX modules
In reply to Ingo MolnarHi,
Quoted 18 lines · Ingo Molnar
Quoted 16 lines · Kees Cook
Hi,
Quoted 3 lines · Ingo Molnar
Quoted 1 line · Kees Cook
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.
Nice! IMHO we need more of that. (If the readonly section gets big enough in practice we could perhaps even mark it large-page in the future. It could serve as an allocator to module code as well - that would probably be a speedup even for modules.)
Well, I can try to extract and send what PaX does, but it seems relatively incompatible with the existing system that uses
set_kernel_text_rw()and friends.Quoted 6 lines
Quoted 2 lines
- Modules need to be correctly marked RO/NX. This patch exists[3], but is not in mainline. It needs to be in mainline.
[...]
Quoted 1 line
The reason the RO/NX patch from Siarhei Liakh is not upstream yet is rather mundane: it introduced regressions - it caused boot crashes on one of my testboxes.
Quoted 8 lines
Quoted 2 lines
Quoted 1 line
But there is no fundamental reason why it shouldnt be upstream. We can push it upstream if the crashes are resolved and if it gets an Ack from Rusty or Linus for the module bits.
Oh, well, yes, that's a good reason. :) Where was this covered? I'd like to help get it reproduced and ironed out.
Matthieu Castet seems to have dusted off those patches and submitted two of them in this mail:
Subject: [RFC] reworked NX protection for kernel data
Matthieu, are you still interested in this topic?
Of course, but I was disapointed that my mail got no reply and no testing.
The last version was "[PATCH 2/3 V8] [tip:x86/mm] NX protection for kernel data"
Quoted 8 lines
The original, broken patches were these -tip commits:
1e858c081af5: x86, mm: RO/NX protection for loadable kernel modules18c60ddc9eff: x86, mm: NX protection for kernel data
c226a2feba21: x86, mm: Set first MB as RW+NX
b29d530510d4: x86, mm: Correcting improper large page preservation
Quoted 6 lines
I reported one of the crashes in:
Subject: Re: [tip:x86/mm] x86, mm: Set first MB as RW+NX
on lkml.
My patches should fix the bug.
I merged "NX protection for kernel data" and "Set first MB as RW+NX" :
This patch expands functionality of CONFIG_DEBUG_RODATA to set main
(static) kernel data area as NX.
The following steps are taken to achieve this:
1. Linker script is adjusted so .text always starts and ends on a page bound
2. Linker script is adjusted so .rodata always start and
end on a page boundary
3. NX is set for all pages from _etext through _end in mark_rodata_ro.
4. free_init_pages() sets released memory NX in arch/x86/mm/init.c
5. bios rom is set to x when pcibios is used.
The cause of the crash was because we try to make bios NX. But after some thought,
I made the bios NX only if pcibios isn't used. That should be the case for system supporting NX (X86 or pci mmconfig). This avoid relying on old bios specification.
If you want I can repost things or port it to new kernel.
Matthieu
Re: [Security] proactive defense: using read-only memory, RO/NX modules
Quoted 1 line · matthieu castet
If you want I can repost things or port it to new kernel.
Yes, please post it against latest -tip:
http://people.redhat.com/mingo/tip.git/README
(Please also Cc: everyone who expressed interest in the topic in this thread.)
Thanks,
Ingo
Hi!
Quoted 2 lines
- Modules need to be correctly marked RO/NX. This patch exists[3], but is not in mainline. It needs to be in mainline.
Why not.
Quoted 5 lines
- Pointers to function table also need to be marked read-only after they are set. An example of this is the
security_opstable 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 entiresecurity_opstable lookup somewhere else.
But there are too many of those. You can't block them all...
Quoted 2 lines
- Entry points to
set_kernel_text_rw()and similar need to be blockable. Having these symbols available make kernel memory modification trivial;
What prevents attacker to just inlining those functions in the exploit?
If you want protection domain inside kernel, perhaps you should take ukernel approach?
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Hi Pavel,
Quoted 4 lines · Pavel Machek
Quoted 2 lines
- Modules need to be correctly marked RO/NX. This patch exists[3], but is not in mainline. It needs to be in mainline.
Why not.
That was answered in another thread: basically, it was side-tracked, but has been recently re-proposed.
Quoted 7 lines
Quoted 5 lines
- Pointers to function table also need to be marked read-only after they are set. An example of this is the
security_opstable 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 entiresecurity_opstable lookup somewhere else.But there are too many of those. You can't block them all...
Well, I don't think "too many" is a good reason. And I think it is possible to block them all if we're careful and diligent. Maybe I'm naive; we'll see.
Quoted 5 lines
Quoted 2 lines
- Entry points to
set_kernel_text_rw()and similar need to be blockable. Having these symbols available make kernel memory modification trivial;What prevents attacker to just inlining those functions in the exploit?
The goal is to make it harder for an attacker to create, change, or hide kernel code in memory. If they're able to already execute arbitrary code, then yes, it's doesn't change anything. But the point is to make it harder to get to that point to start with.
Quoted 2 lines
If you want protection domain inside kernel, perhaps you should take ukernel approach?
Someone might want to, but I'm not interested in that. It's not impossible to make the existing kernel more resilient to attack.
-Kees
Signature · 2 lines
Kees Cook Ubuntu Security Team
Hi!
Quoted 11 lines
Quoted 7 lines
Quoted 5 lines
- Pointers to function table also need to be marked read-only after they are set. An example of this is the
security_opstable 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 entiresecurity_opstable lookup somewhere else.But there are too many of those. You can't block them all...
Well, I don't think "too many" is a good reason. And I think it is possible to block them all if we're careful and diligent. Maybe I'm naive;
we'll see.
I believe "too many" is very good reason -- you do not want to uglify the kernel too badly.
It is not like anything that makes attackers life harder is a good thing... for example deleting all the comments would clearly make attacking linux harder, but it is also clearly bad idea.
Quoted 10 lines
Quoted 5 lines
Quoted 2 lines
- Entry points to
set_kernel_text_rw()and similar need to be blockable. Having these symbols available make kernel memory modification trivial;What prevents attacker to just inlining those functions in the exploit?
The goal is to make it harder for an attacker to create, change, or hide kernel code in memory. If they're able to already execute arbitrary code, then yes, it's doesn't change anything. But the point is to make it harder to get to that point to start with.
So... what do you assume attacker _can_ do? What is it you are trying to protect against?
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Quoted 5 lines · Pavel Machek
Quoted 2 lines
- Entry points to
set_kernel_text_rw()and similar need to be blockable. Having these symbols available make kernel memory modification trivial;What prevents attacker to just inlining those functions in the exploit?
Quite often, you are limited on how many bytes of exploit code you can inject. If you have to do the whole thing in (say) 139 bytes, having to inlinine even one function may make the exploit impossible to run.