On Thu, Oct 29, 2020 at 2:17 PM Marco Elver <elver@xxxxxxxxxx> wrote: > Inserts KFENCE hooks into the SLUB allocator. > > To pass the originally requested size to KFENCE, add an argument > 'orig_size' to slab_alloc*(). The additional argument is required to > preserve the requested original size for kmalloc() allocations, which > uses size classes (e.g. an allocation of 272 bytes will return an object > of size 512). Therefore, kmem_cache::size does not represent the > kmalloc-caller's requested size, and we must introduce the argument > 'orig_size' to propagate the originally requested size to KFENCE. > > Without the originally requested size, we would not be able to detect > out-of-bounds accesses for objects placed at the end of a KFENCE object > page if that object is not equal to the kmalloc-size class it was > bucketed into. > > When KFENCE is disabled, there is no additional overhead, since > slab_alloc*() functions are __always_inline. > > Reviewed-by: Dmitry Vyukov <dvyukov@xxxxxxxxxx> > Co-developed-by: Marco Elver <elver@xxxxxxxxxx> > Signed-off-by: Marco Elver <elver@xxxxxxxxxx> > Signed-off-by: Alexander Potapenko <glider@xxxxxxxxxx> Reviewed-by: Jann Horn <jannh@xxxxxxxxxx> if you fix one nit: [...] > diff --git a/mm/slub.c b/mm/slub.c [...] > @@ -2658,7 +2664,8 @@ static inline void *get_freelist(struct kmem_cache *s, struct page *page) > * already disabled (which is the case for bulk allocation). > */ > static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, > - unsigned long addr, struct kmem_cache_cpu *c) > + unsigned long addr, struct kmem_cache_cpu *c, > + size_t orig_size) orig_size is added as a new argument, but never used. (And if you remove this argument, __slab_alloc will also not be using its orig_size argument anymore.) > { > void *freelist; > struct page *page; > @@ -2763,7 +2770,8 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, > * cpu changes by refetching the per cpu area pointer. > */ > static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, > - unsigned long addr, struct kmem_cache_cpu *c) > + unsigned long addr, struct kmem_cache_cpu *c, > + size_t orig_size) > { > void *p; > unsigned long flags; > @@ -2778,7 +2786,7 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, > c = this_cpu_ptr(s->cpu_slab); > #endif > > - p = ___slab_alloc(s, gfpflags, node, addr, c); > + p = ___slab_alloc(s, gfpflags, node, addr, c, orig_size); > local_irq_restore(flags); > return p; > }