Linux kernel heap quarantine

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).







image







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- , :







image









:







image









: heap spraying โ€” , .









2020 , heap spraying UAF Linux. . slab-  KASAN  SLAB_QUARANTINE



.







, . UAF.  SLAB_QUARANTINE



:







image









13 LKML .







SLAB_QUARANTINE



 lkdtm



 ( ).







 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



.







?



:







  1.  iperf



    :

    : iperf -s -f K





    : iperf -c 127.0.0.1 -t 60 -f K



  2. :

    hackbench -s 4000 -l 500 -g 15 -f 25 -P



  3. :

    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.







, Twitch, ( ).







:







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
      
      






All Articles