KSPP / linux

Linux kernel source tree (Kernel Self Protection Project)
https://kernsec.org/wiki/index.php/Kernel_Self_Protection_Project
Other
81 stars 5 forks source link

Separate slab allocations by type #189

Open kees opened 2 years ago

kees commented 2 years ago

A common UAF involves implicit type confusion by reusing allocations of memory that get allocated to a different struct of a similar size. It would be nice to provide an implicit kmem_cache_create()-like system for each distinct allocation type, but this requires introspection into the type being allocated.

This would also get rid of redundant sizeof(*ptr) arguments. For example:

rc = kmalloc(&var, GFP_KERNEL);

Dynamically sized allocations (flexible array structs) could still be type-separated, but would have a kmalloc-like bucket system.

To avoid needing to rewrite all callers everywhere, it might also be possible to grow a compiler extension to allow for lvalue type introspection, like __builtin_lvalue_type():

#define kmalloc(var, GFP_KERNEL) __kmalloc(var, sizeof(*__builtin_lvalue_type()))

Alternatively, allocations could be separated by caller location, but it's possible this may be too granular. It would be nice to compare performance characteristics.

It's important to address cross-allocator attacks as well. Such a "no virtual address reuse across types" solution has been proposed to cover this part of the problem too.

kees commented 2 years ago

I was just pointed to XNU's own creation of a separate allocator API for types. I'd still prefer avoiding rewriting all the existing kmalloc calls in Linux. :) https://github.com/apple-oss-distributions/xnu/blob/e7776783b89a353188416a9a346c6cdb4928faad/doc/allocators/api-basics.md#user-content-the-typed-allocator https://github.com/apple-oss-distributions/xnu/blob/e7776783b89a353188416a9a346c6cdb4928faad/osfmk/kern/kalloc.h#L608-L641

nickdesaulniers commented 1 year ago

https://security.apple.com/blog/towards-the-next-generation-of-xnu-memory-safety/

nickdesaulniers commented 1 year ago

To avoid needing to rewrite all callers everywhere, it might also be possible to grow a compiler extension to allow for lvalue type introspection, like __builtin_lvalue_type(): I'd still prefer avoiding rewriting all the existing kmalloc calls in Linux. :)

The identifier being assigned to can be referenced in the RHS of an assignment expression:

// type specific slab
void* kmalloc_int(size_t size, int flags);

#define kmalloc2(size, flags, type) _Generic((*type), int: kmalloc_int(size, flags))

int *foo (void) {
    int *bar = kmalloc2(sizeof(*bar), GFP_KERNEL, bar);
    return bar;
}
kees commented 6 months ago

We should be able to use the proposed allocation profiling infrastructure to accomplish per-call-site caches: https://lore.kernel.org/all/202402211449.401382D2AF@keescook/

kees commented 2 weeks ago

RFC: https://lore.kernel.org/lkml/20240809072532.work.266-kees@kernel.org/