* [kernel-hardening] On techniques for preventing commit_creds() user-space abuse
@ 2015-11-25 23:14 Salva Peiró
2015-11-26 7:43 ` comex
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Salva Peiró @ 2015-11-25 23:14 UTC (permalink / raw)
To: kernel-hardening
[-- Attachment #1.1: Type: text/plain, Size: 3708 bytes --]
A complete version of the technique can be found at
http://speirofr.appspot.com/category/techniques/
# Analysis
Given the typical path for kernel exploitation is the
`commit_creds(prepare_kernel_cred(0))` being called from user space as
detailed in [References].
Why is not a check placed in commit_creds() that checks the return address
of the call to ensure the call is a legit one coming from kernel space?.
This blocks direct calls to commit_creds from user space,
however, it remains vulnerable to alternative exploit routes.
The alternatives to bypass this protection are:
- *Indirect jump*
An attacker can perform an indirect jump to a kernel location that does
the commit_creds() for him, but it complicates the task of the
attacker. To prevent indirect calls check the rest of the stack trace.
- *Direct override*
Another route to bypass would be to figure out the location of the
process creds in memory, and perform the change directly in memory,
but AFAIK SMAP and its ARM equivalent would deter this route.
Therefore, I started implementing some exploits for testing it,
and implemented the `commit_cred` protection checks technique to
check if it is viable for preventing the commit_creds abuse.
The [Implementation] provides a patch that implements the discussed
approach.
The [Evaluation] provides the tests performed showing it effectively
blocks commit_creds abuse from user space.
# Threat Model
The steps involved in commit_creds() exploits:
- Prepare user code to get root:
user_addr = commit_creds(prepare_creds(0))
- Override kernel code with:
kernel_struct.fptr = user_addr (1st vuln point SMAP)
- Trigger a syscall that calls kernel_struct.fptr
- Invoke syscall from user
- Results in kernel_struct.fptr() being called
Calls user-space code from kernel code
(2nd vuln point this point we're already toasted SMEP)
Then call commit_creds (kernel_code) from user
At this point the can detect commit_creds called from user
(3rd vuln: fix check return address)
# Implementation
The patch implementing the commit_creds() abuse prevention:
From: Salva Peiró <speirofr AT gmail.com>
Date: Wed, 25 Nov 2015 14:03:50 +0100
Subject: [PATCH] cred: Prevent commit_creds() user-space abuse
Signed-off-by: Salva Peiró <speirofr AT gmail.com>
---
kernel/cred.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/kernel/cred.c b/kernel/cred.c
index 71179a0..7191db3 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -428,6 +428,13 @@ int commit_creds(struct cred *new)
atomic_read(&new->usage),
read_cred_subscribers(new));
+ /* block attempts to use commit_creds from user space */
+ if (__builtin_return_address(0) < PAGE_OFFSET) {
+ printk(KERN_ERR "CRED: BUG commit_creds called from user space\n");
+ WARN_ON(1);
+ return -1;
+ }
+
# Evaluation
The `dmesg(1)` output below shows the prevention of an exploit attempt
using [References] where commit_creds is being called from user-space.
[ 1979.132453] exploit[8549]: segfault at 0 ip 08048719 sp bf8ff430 error 6
in exploit[8048000+1000]
[ 1981.658186] BUG: commit_creds called from user space
[ 1981.658201] ------------[ cut here ]------------
[ 1981.658207] WARNING: CPU: 0 PID: 8552 at kernel/cred.c:436
commit_creds+0x1e5/0x210()
[ 1981.658209] Modules linked in: nullderef(O) nls_utf8 isofs udf crc_itu_
# References
- Much ado about NULL: Exploiting a kernel NULL dereference, by Nelson
Elhage
https://blogs.oracle.com/ksplice/entry/much_ado_about_null_exploiting1.
--
Salva Peiró @ https://speirofr.appspot.com
[-- Attachment #1.2: Type: text/html, Size: 5447 bytes --]
[-- Attachment #2: 0001-cred-Prevent-commit_creds-user-space-abuse.patch --]
[-- Type: text/x-patch, Size: 1010 bytes --]
From a961324af1f5b5484efa60f5cf7072de5cbda69d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Salva=20Peir=C3=B3?= <speirofr@gmail.com>
Date: Wed, 25 Nov 2015 14:03:50 +0100
Subject: [PATCH] cred: Prevent commit_creds() user-space abuse
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Salva Peiró <speirofr@gmail.com>
---
kernel/cred.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/kernel/cred.c b/kernel/cred.c
index 71179a0..7191db3 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -428,6 +428,13 @@ int commit_creds(struct cred *new)
atomic_read(&new->usage),
read_cred_subscribers(new));
+ /* block attempts to use commit_creds from user space */
+ if (__builtin_return_address(0) < PAGE_OFFSET) {
+ printk(KERN_ERR "CRED: BUG commit_creds called from user-space\n");
+ WARN_ON(1);
+ return -1;
+ }
+
BUG_ON(task->cred != old);
#ifdef CONFIG_DEBUG_CREDENTIALS
BUG_ON(read_cred_subscribers(old) < 2);
--
2.1.4
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [kernel-hardening] On techniques for preventing commit_creds() user-space abuse
2015-11-25 23:14 [kernel-hardening] On techniques for preventing commit_creds() user-space abuse Salva Peiró
@ 2015-11-26 7:43 ` comex
2015-11-26 15:32 ` Salva Peiró
2015-11-26 8:27 ` Yves-Alexis Perez
2015-11-26 11:03 ` Yann Droneaud
2 siblings, 1 reply; 5+ messages in thread
From: comex @ 2015-11-26 7:43 UTC (permalink / raw)
To: kernel-hardening
On Wed, Nov 25, 2015 at 6:14 PM, Salva Peiró <speirofr@gmail.com> wrote:
> - *Indirect jump*
> An attacker can perform an indirect jump to a kernel location that does
> the commit_creds() for him, but it complicates the task of the
> attacker. To prevent indirect calls check the rest of the stack trace.
The added complication of indirection is minimal, and checking the
frame pointer/return address chain on the stack would be far from
sufficient to prevent it: even if you had full control flow integrity
on returns (see e.g. RAP), if the attacker was already executing
arbitrary code, they could overwrite the whole stack to simulate a
call stack that would normally be allowed to call commit_creds and
won't crash on return, e.g. setuid returning to userland.
> - *Direct override*
> Another route to bypass would be to figure out the location of the
> process creds in memory, and perform the change directly in memory,
> but AFAIK SMAP and its ARM equivalent would deter this route.
SMEP (not SMAP) already makes it impossible to directly execute code
from userspace mapped addresses. SMAP prevents accessing those
addresses, but has no effect on kernel mapped addresses such as the
data structures containing credentials.
In general there's not much point trying to defend against an attacker
who is already running arbitrary code in kernel mode. Even executing
a ROP chain, once the attacker gets past any initial hurdles such as
stack pivoting, is pretty much game over (the possibility of it being
complicated to find gadgets with unusual instruction sequences, find a
large number of gadgets, or use a long chain of them /might/ make some
additional measures valuable, but not very - e.g. [1]); true code
execution generally makes working around any 'harassment' measures
trivial.
[1] http://vulnfactory.org/blog/2011/09/21/defeating-windows-8-rop-mitigation/
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [kernel-hardening] On techniques for preventing commit_creds() user-space abuse
2015-11-26 7:43 ` comex
@ 2015-11-26 15:32 ` Salva Peiró
0 siblings, 0 replies; 5+ messages in thread
From: Salva Peiró @ 2015-11-26 15:32 UTC (permalink / raw)
To: kernel-hardening
[-- Attachment #1: Type: text/plain, Size: 2271 bytes --]
On Thu, Nov 26, 2015 at 8:43 AM, comex <comexk@gmail.com> wrote:
> On Wed, Nov 25, 2015 at 6:14 PM, Salva Peiró <speirofr@gmail.com> wrote:
> > - *Indirect jump*
> > An attacker can perform an indirect jump to a kernel location that does
> > the commit_creds() for him, but it complicates the task of the
> > attacker. To prevent indirect calls check the rest of the stack trace.
>
> The added complication of indirection is minimal, and checking the
> frame pointer/return address chain on the stack would be far from
> sufficient to prevent it: even if you had full control flow integrity
> on returns (see e.g. RAP), if the attacker was already executing
> arbitrary code, they could overwrite the whole stack to simulate a
> call stack that would normally be allowed to call commit_creds and
> won't crash on return, e.g. setuid returning to userland.
>
> > - *Direct override*
> > Another route to bypass would be to figure out the location of the
> > process creds in memory, and perform the change directly in memory,
> > but AFAIK SMAP and its ARM equivalent would deter this route.
>
> SMEP (not SMAP) already makes it impossible to directly execute code
> from userspace mapped addresses. SMAP prevents accessing those
> addresses, but has no effect on kernel mapped addresses such as the
> data structures containing credentials.
>
> In general there's not much point trying to defend against an attacker
> who is already running arbitrary code in kernel mode. Even executing
> a ROP chain, once the attacker gets past any initial hurdles such as
> stack pivoting, is pretty much game over (the possibility of it being
> complicated to find gadgets with unusual instruction sequences, find a
> large number of gadgets, or use a long chain of them /might/ make some
> additional measures valuable, but not very - e.g. [1]); true code
> execution generally makes working around any 'harassment' measures
> trivial.
>
> [1]
> http://vulnfactory.org/blog/2011/09/21/defeating-windows-8-rop-mitigation/
>
Thanks for explaining the flaws I was wondering why it wasn't done.
Implementing such a thing is pointless, since by the time the attacker
is executing code he can already bypass the protections as shown in [1].
[-- Attachment #2: Type: text/html, Size: 3105 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [kernel-hardening] On techniques for preventing commit_creds() user-space abuse
2015-11-25 23:14 [kernel-hardening] On techniques for preventing commit_creds() user-space abuse Salva Peiró
2015-11-26 7:43 ` comex
@ 2015-11-26 8:27 ` Yves-Alexis Perez
2015-11-26 11:03 ` Yann Droneaud
2 siblings, 0 replies; 5+ messages in thread
From: Yves-Alexis Perez @ 2015-11-26 8:27 UTC (permalink / raw)
To: kernel-hardening
[-- Attachment #1: Type: text/plain, Size: 909 bytes --]
On jeu., 2015-11-26 at 00:14 +0100, Salva Peiró wrote:
> Given the typical path for kernel exploitation is the
> `commit_creds(prepare_kernel_cred(0))` being called from user space as
> detailed in [References].
> Why is not a check placed in commit_creds() that checks the return address
> of the call to ensure the call is a legit one coming from kernel space?.
I have the feeling that commit_creds(prepare_creds(0)) is just a quick way for
white hats / good guys to demonstrate a vulnerability by showing an exploit
leading to privilege escalation (or rooting Android devices).
As already said elsewere, we don't have much data on the exploitation
techniques used by real bad guys, but I somehow assume that if you have ring 0
access, the first things you do is disable existing protections and insert
kernel code in order to have free hands on userspace.
Regards,
--
Yves-Alexis
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [kernel-hardening] On techniques for preventing commit_creds() user-space abuse
2015-11-25 23:14 [kernel-hardening] On techniques for preventing commit_creds() user-space abuse Salva Peiró
2015-11-26 7:43 ` comex
2015-11-26 8:27 ` Yves-Alexis Perez
@ 2015-11-26 11:03 ` Yann Droneaud
2 siblings, 0 replies; 5+ messages in thread
From: Yann Droneaud @ 2015-11-26 11:03 UTC (permalink / raw)
To: kernel-hardening
Hi,
Le jeudi 26 novembre 2015 à 00:14 +0100, Salva Peiró a écrit :
> A complete version of the technique can be found at
> http://speirofr.appspot.com/category/techniques/
>
> # Analysis
>
> Given the typical path for kernel exploitation is the
> `commit_creds(prepare_kernel_cred(0))` being called from user space
> as detailed in [References].
> Why is not a check placed in commit_creds() that checks the return
> address of the call to ensure the call is a legit one coming from
> kernel space?.
>
> This blocks direct calls to commit_creds from user space,
> however, it remains vulnerable to alternative exploit routes.
> The alternatives to bypass this protection are:
>
> - *Indirect jump*
> An attacker can perform an indirect jump to a kernel location that
> does the commit_creds() for him, but it complicates the task of the
> attacker. To prevent indirect calls check the rest of the stack
> trace.
>
> - *Direct override*
> Another route to bypass would be to figure out the location of the
> process creds in memory, and perform the change directly in memory,
> but AFAIK SMAP and its ARM equivalent would deter this route.
>
> Therefore, I started implementing some exploits for testing it,
> and implemented the `commit_cred` protection checks technique to
> check if it is viable for preventing the commit_creds abuse.
>
> The [Implementation] provides a patch that implements the discussed
> approach.
> The [Evaluation] provides the tests performed showing it effectively
> blocks commit_creds abuse from user space.
>
> # Threat Model
>
> The steps involved in commit_creds() exploits:
>
> - Prepare user code to get root:
> user_addr = commit_creds(prepare_creds(0))
>
> - Override kernel code with:
> kernel_struct.fptr = user_addr (1st vuln point SMAP)
>
> - Trigger a syscall that calls kernel_struct.fptr
> - Invoke syscall from user
> - Results in kernel_struct.fptr() being called
> Calls user-space code from kernel code
> (2nd vuln point this point we're already toasted SMEP)
> Then call commit_creds (kernel_code) from user
> At this point the can detect commit_creds called from
> user
> (3rd vuln: fix check return address)
>
> # Implementation
>
> The patch implementing the commit_creds() abuse prevention:
>
> From: Salva Peiró <speirofr AT gmail.com>
> Date: Wed, 25 Nov 2015 14:03:50 +0100
> Subject: [PATCH] cred: Prevent commit_creds() user-space abuse
>
Please add some explanation in your commit message.
> Signed-off-by: Salva Peiró <speirofr AT gmail.com>
>
> ---
> kernel/cred.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/kernel/cred.c b/kernel/cred.c
> index 71179a0..7191db3 100644
> --- a/kernel/cred.c
> +++ b/kernel/cred.c
> @@ -428,6 +428,13 @@ int commit_creds(struct cred *new)
> atomic_read(&new->usage),
> read_cred_subscribers(new));
>
> + /* block attempts to use commit_creds from user space */
> + if (__builtin_return_address(0) < PAGE_OFFSET) {
> + printk(KERN_ERR "CRED: BUG commit_creds called from
> user space\n");
> + WARN_ON(1);
> + return -1;
> + }
> +
>
What about
#define call_ok() !access_ok(__builtin_return_address(0), VERIFY_READ)
if (WARN(!call_ok(),
"%s called from user space\n", __function__))
return -1;
If __builtin_return_address() is reliable enough, that trick can be
easily added on many sensitive functions.
If such kind of prologue can be injected by compiler in functions
marked with a dedicated attribute, I think that could be a nice thing
to have before PAX's UDEREF and KERNEXEC are made available, as the
latter should better
Regards.
--
Yann Droneaud
OPTEYA
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2015-11-26 15:32 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-25 23:14 [kernel-hardening] On techniques for preventing commit_creds() user-space abuse Salva Peiró
2015-11-26 7:43 ` comex
2015-11-26 15:32 ` Salva Peiró
2015-11-26 8:27 ` Yves-Alexis Perez
2015-11-26 11:03 ` Yann Droneaud
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.