2020 year. Quarantine is everywhere. And this article is also about quarantine, but it is of a different kind.
I will talk about quarantine experiments for Linux kernel heap . It is a security mechanism that counteracts use-after-free (UAF) memory in the Linux kernel. I will also summarize the discussion of my patch series on the Linux Kernel Mailing List (LKML).
Memory usage after free in Linux kernel
UAF in the Linux kernel is a very popular type of vulnerability to exploit. There are many public prototypes of nuclear exploits for the UAF:
UAF heap spraying. โ , , , ยซยป. heap spraying UAF Linux , kmalloc()
slab- , :
:
: heap spraying โ , .
2020 , heap spraying UAF Linux. . slab- KASAN SLAB_QUARANTINE
.
, . UAF. SLAB_QUARANTINE
:
SLAB_QUARANTINE
lkdtm_HEAP_SPRAY
. kmem_cache
, 400 000 . , heap spraying UAF:
#define SPRAY_LENGTH 400000 ... addr = kmem_cache_alloc(spray_cache, GFP_KERNEL); ... kmem_cache_free(spray_cache, addr); pr_info("Allocated and freed spray_cache object %p of size %d\n", addr, SPRAY_ITEM_SIZE); ... pr_info("Original heap spraying: allocate %d objects of size %d...\n", SPRAY_LENGTH, SPRAY_ITEM_SIZE); for (i = 0; i < SPRAY_LENGTH; i++) { spray_addrs[i] = kmem_cache_alloc(spray_cache, GFP_KERNEL); ... if (spray_addrs[i] == addr) { pr_info("FAIL: attempt %lu: freed object is reallocated\n", i); break; } } if (i == SPRAY_LENGTH) pr_info("OK: original heap spraying hasn't succeeded\n");
CONFIG_SLAB_QUARANTINE
, :
# echo HEAP_SPRAY > /sys/kernel/debug/provoke-crash/DIRECT lkdtm: Performing direct entry HEAP_SPRAY lkdtm: Allocated and freed spray_cache object 000000002b5b3ad4 of size 333 lkdtm: Original heap spraying: allocate 400000 objects of size 333... lkdtm: FAIL: attempt 0: freed object is reallocated
CONFIG_SLAB_QUARANTINE
, 400 000 :
# echo HEAP_SPRAY > /sys/kernel/debug/provoke-crash/DIRECT lkdtm: Performing direct entry HEAP_SPRAY lkdtm: Allocated and freed spray_cache object 000000009909e777 of size 333 lkdtm: Original heap spraying: allocate 400000 objects of size 333... lkdtm: OK: original heap spraying hasn't succeeded
- , , . , , . .
lkdtm_PUSH_THROUGH_QUARANTINE
. kmem_cache
kmem_cache_alloc()+kmem_cache_free()
400 000 .
addr = kmem_cache_alloc(spray_cache, GFP_KERNEL); ... kmem_cache_free(spray_cache, addr); pr_info("Allocated and freed spray_cache object %p of size %d\n", addr, SPRAY_ITEM_SIZE); pr_info("Push through quarantine: allocate and free %d objects of size %d...\n", SPRAY_LENGTH, SPRAY_ITEM_SIZE); for (i = 0; i < SPRAY_LENGTH; i++) { push_addr = kmem_cache_alloc(spray_cache, GFP_KERNEL); ... kmem_cache_free(spray_cache, push_addr); if (push_addr == addr) { pr_info("Target object is reallocated at attempt %lu\n", i); break; } } if (i == SPRAY_LENGTH) { pr_info("Target object is NOT reallocated in %d attempts\n", SPRAY_LENGTH); }
:
# echo PUSH_THROUGH_QUARANTINE > /sys/kernel/debug/provoke-crash/ lkdtm: Performing direct entry PUSH_THROUGH_QUARANTINE lkdtm: Allocated and freed spray_cache object 000000008fdb15c3 of size 333 lkdtm: Push through quarantine: allocate and free 400000 objects of size 333... lkdtm: Target object is reallocated at attempt 182994 # echo PUSH_THROUGH_QUARANTINE > /sys/kernel/debug/provoke-crash/ lkdtm: Performing direct entry PUSH_THROUGH_QUARANTINE lkdtm: Allocated and freed spray_cache object 000000004e223cbe of size 333 lkdtm: Push through quarantine: allocate and free 400000 objects of size 333... lkdtm: Target object is reallocated at attempt 186830 # echo PUSH_THROUGH_QUARANTINE > /sys/kernel/debug/provoke-crash/ lkdtm: Performing direct entry PUSH_THROUGH_QUARANTINE lkdtm: Allocated and freed spray_cache object 000000007663a058 of size 333 lkdtm: Push through quarantine: allocate and free 400000 objects of size 333... lkdtm: Target object is reallocated at attempt 182010
ยซยป. : . , , , , . :
lkdtm: Target object is reallocated at attempt 107884 lkdtm: Target object is reallocated at attempt 265641 lkdtm: Target object is reallocated at attempt 100030 lkdtm: Target object is NOT reallocated in 400000 attempts lkdtm: Target object is reallocated at attempt 204731 lkdtm: Target object is reallocated at attempt 359333 lkdtm: Target object is reallocated at attempt 289349 lkdtm: Target object is reallocated at attempt 119893 lkdtm: Target object is reallocated at attempt 225202 lkdtm: Target object is reallocated at attempt 87343
: ( ). , , , ( ).
. , : . init_on_free
. CONFIG_SLAB_QUARANTINE
.
: CONFIG_SLAB
init_on_free
, . ( mainline).
, CONFIG_SLAB_QUARANTINE
, , ( mainline). :
quarantine: PUT 508992 to tail batch 123, whole sz 65118872, batch sz 508854 quarantine: whole sz exceed max by 494552, REDUCE head batch 0 by 415392, leave 396304 quarantine: data level in batches: 0 - 77% 1 - 108% 2 - 83% 3 - 21% ... 125 - 75% 126 - 12% 127 - 108% quarantine: whole sz exceed max by 79160, REDUCE head batch 12 by 14160, leave 17608 quarantine: whole sz exceed max by 65000, REDUCE head batch 75 by 218328, leave 195232 quarantine: PUT 508992 to tail batch 124, whole sz 64979984, batch sz 508854 ...
PUT
. REDUCE
, . , , . , REDUCE
.
?
-
iperf
:
:iperf -s -f K
:iperf -c 127.0.0.1 -t 60 -f K
- :
hackbench -s 4000 -l 500 -g 15 -f 25 -P
- :
time make -j2
Linux :
init_on_free=off
init_on_free=on
( )CONFIG_SLAB_QUARANTINE=y
(init_on_free
)
iperf
, :
init_on_free=on
28% ,init_on_free=off
.CONFIG_SLAB_QUARANTINE
2% ,init_on_free=on
.
:
hackbench
5,3%init_on_free=on
init_on_free=off
.hackbench
91,7%CONFIG_SLAB_QUARANTINE
init_on_free=on
. QEMU/KVM 44%, (Intel Core i7-6500U CPU).
:
-
init_on_free=on
1,7% ,init_on_free=off
. -
CONFIG_SLAB_QUARANTINE
1,1% ,init_on_free=on
.
, .
: . . , , , .
LKML CONFIG_SLAB_QUARANTINE
. , . (Kees Cook), , , (Matthew Wilcox), (Daniel Micay), (Christopher Lameter), (Pavel Machek) (Eric W. Biederman).
(Jann Horn) Google Project Zero. , - CONFIG_SLAB_QUARANTINE
UAF Linux.
:
On 06.10.2020 21:37, Jann Horn wrote: > On Tue, Oct 6, 2020 at 7:56 PM Alexander Popov wrote: >> So I think the control over the time of the use-after-free access doesn't help >> attackers, if they don't have an "infinite spray" -- unlimited ability to store >> controlled data in the kernelspace objects of the needed size without freeing them. [...] >> Would you agree? > > But you have a single quarantine (per CPU) for all objects, right? So > for a UAF on slab A, the attacker can just spam allocations and > deallocations on slab B to almost deterministically flush everything > in slab A back to the SLUB freelists? Aaaahh! Nice shot Jann, I see. Another slab cache can be used to flush the randomized quarantine, so eventually the vulnerable object returns into the allocator freelist in its cache, and original heap spraying can be used again. For now I think the idea of a global quarantine for all slab objects is dead.
slab- , , . heap spraying UAF.
Twitch. PUSH_THROUGH_QUARANTINE
. !
LKML . UAF .
Linux, , use-after-free. . , mainline, , , Linux.
, :
Quarantine patch version three Won't appear. No need. Let's exploit use-after-free Like we always did ;) -- a13xp0p0v