Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Wed, 24 Feb 2016 09:22:29 -0800
From: Kees Cook <keescook@...omium.org>
To: Laura Abbott <labbott@...hat.com>
Cc: Laura Abbott <labbott@...oraproject.org>, 
	Greg Kroah-Hartman <gregkh@...uxfoundation.org>, Arnd Bergmann <arnd@...db.de>, 
	"kernel-hardening@...ts.openwall.com" <kernel-hardening@...ts.openwall.com>, LKML <linux-kernel@...r.kernel.org>
Subject: Re: [PATCHv2] lkdtm: Add READ_AFTER_FREE test

I did 3 defconfig builds as a benchmark, just to get ballpark numbers...

On Tue, Feb 23, 2016 at 1:25 PM, Kees Cook <keescook@...omium.org> wrote:
> Okay, it looks like the combinations to test are:
>
> default:
> DEBUG_PAGEALLOC=n
> PAGE_POISONING=n

Run times: 412.57 414.19 417.27
Mean: 414.68
Std Dev: 1.95

READ_AFTER_FREE fails:
[   83.521712] lkdtm: Performing direct entry READ_AFTER_FREE
[   83.521851] lkdtm: Value in memory before free: 12345678
[   83.521861] lkdtm: Attempting to read from freed memory
[   83.521864] lkdtm: Successfully read value: 12345678

WRITE_AFTER_FREE accidentally(?) gets detected (due to
CONFIG_SLUB_DEBUG=y default) but does not kill process:
[  120.544198] lkdtm: Performing direct entry WRITE_AFTER_FREE
[  120.544874] =============================================================================
[  120.545028] BUG kmalloc-1024 (Not tainted): Freepointer corrupt

READ_BUDDY_AFTER_FREE fails:
[  120.711466] lkdtm: Performing direct entry READ_BUDDY_AFTER_FREE
[  120.711472] lkdtm: Value in memory before free: 12345678
[  120.711473] lkdtm: Attempting to read from freed memory
[  120.711475] lkdtm: Successfully read value: 12345678

WRITE_BUDDY_AFTER_FREE fails:
[  120.714371] lkdtm: Performing direct entry WRITE_BUDDY_AFTER_FREE
[  120.714374] lkdtm: Writing to the buddy page before free
[  120.714377] lkdtm: Writing to the buddy page after free
[  120.714378] lkdtm: Wrote to free page successfully

So, other than what SLUB_DEBUG caught (which I think is probably an
accident, as we can change the test to avoid SLUB_DEBUG detection),
this is as-expected: use-after-free was not detected.

> heavy-duty:
> DEBUG_PAGEALLOC=y (ARCH_SUPPORTS_DEBUG_PAGEALLOC=y)
> debug_pagealloc=on

Run times: 486.82 464.90 469.34
Mean: 473.69
Std Dev: 9.46

Kind of a giant std-dev, but regardless, DEBUG_PAGEALLOC appears to
introduce a 14% perf overhead.

READ_AFTER_FREE fails, as before.
WRITE_AFTER_FREE accidentally gets detected, as before.

READ_BUDDY_AFTER_FREE detected:
[ 1760.522979] lkdtm: Performing direct entry READ_BUDDY_AFTER_FREE
[ 1760.522985] lkdtm: Value in memory before free: 12345678
[ 1760.523013] BUG: unable to handle kernel paging request at ffff88007994b000

WRITE_BUDDY_AFTER_FREE detected:
[ 1938.050091] lkdtm: Performing direct entry WRITE_BUDDY_AFTER_FREE
[ 1938.051475] lkdtm: Writing to the buddy page before free
[ 1938.056455] lkdtm: Writing to the buddy page after free
[ 1938.058543] BUG: unable to handle kernel paging request at ffff880079b38000

I was expecting DEBUG_PAGEALLOC to detect the read/write after free cases too.

> random poison only:
> DEBUG_PAGEALLOC=n
> PAGE_POISONING=y
> PAGE_POISONING_NO_SANITY=y
> PAGE_POISONING_ZERO=n
> page_poison=on

Run times: 428.96 424.76 426.12
Mean: 426.61
Std Dev: 1.75

This is under 3% perf overhead, with similar std-dev.

READ_AFTER_FREE fails, as before.
WRITE_AFTER_FREE accidentally gets detected, as before.

READ_BUDDY_AFTER_FREE detected:
[ 1448.167650] lkdtm: Performing direct entry READ_BUDDY_AFTER_FREE
[ 1448.167654] lkdtm: Value in memory before free: 12345678
[ 1448.167656] lkdtm: Attempting to read from freed memory
[ 1448.167677] general protection fault: 0000 [#1] SMP

WRITE_BUDDY_AFTER_FREE fails:
[ 1448.206587] lkdtm: Performing direct entry WRITE_BUDDY_AFTER_FREE
[ 1448.207550] lkdtm: Writing to the buddy page before free
[ 1448.208327] lkdtm: Writing to the buddy page after free
[ 1448.209088] lkdtm: Wrote to free page successfully

I wasn't expecting the GP with NO_SANITY=y. I was expecting to read
back random data?

> zero poison only:
> DEBUG_PAGEALLOC=n
> PAGE_POISONING=y
> PAGE_POISONING_NO_SANITY=y
> PAGE_POISONING_ZERO=y
> page_poison=on

This breaks my test system (as mentioned in other thread).

> random poison with sanity:
> DEBUG_PAGEALLOC=n
> PAGE_POISONING=y
> PAGE_POISONING_NO_SANITY=n
> PAGE_POISONING_ZERO=n
> page_poison=on

Run times: 432.72 434.41 429.19
Mean: 432.11
Std Dev: 2.18

Just over 4% perf overhead to no checks, and only 1.5% more overhead
compared to no sanity.

READ_AFTER_FREE fails, as before, but I thought it should be detected
with the sanity checking?
WRITE_AFTER_FREE accidentally gets detected, as before.

READ_BUDDY_AFTER_FREE detects:
[   46.720158] lkdtm: Performing direct entry READ_BUDDY_AFTER_FREE
[   46.720163] lkdtm: Value in memory before free: 12345678
[   46.720164] lkdtm: Attempting to read from freed memory
[   46.720169] general protection fault: 0000 [#1] SMP

WRITE_BUDDY_AFTER_FREE detects, but does not kill process:
[   46.756109] lkdtm: Performing direct entry WRITE_BUDDY_AFTER_FREE
[   46.756975] lkdtm: Writing to the buddy page before free
[   46.757764] lkdtm: Writing to the buddy page after free
[   46.758514] lkdtm: Wrote to free page successfully
[   46.759244] pagealloc: memory corruption

While WRITE_BUDDY_AFTER_FREE is detected, it doesn't kill the process
(similar to the WRITE_AFTER_FREE detection). We should change this
(maybe optionally) to drop processes that are triggering issues like
this.

> zero poison with sanity:
> DEBUG_PAGEALLOC=n
> PAGE_POISONING=y
> PAGE_POISONING_NO_SANITY=n
> PAGE_POISONING_ZERO=y
> page_poison=on

Again, couldn't test.

Looks like good progress to me. :)

-Kees

-- 
Kees Cook
Chrome OS & Brillo Security

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.