Hi Andrey, On Wed, Sep 21, 2022 at 03:20:58AM +0800, Andrey Konovalov wrote: > On Tue, Sep 13, 2022 at 8:54 AM Feng Tang <feng.tang@xxxxxxxxx> wrote: > > > > When kasan is enabled for slab/slub, it may save kasan' free_meta > > data in the former part of slab object data area in slab object's > > free path, which works fine. > > > > There is ongoing effort to extend slub's debug function which will > > redzone the latter part of kmalloc object area, and when both of > > the debug are enabled, there is possible conflict, especially when > > the kmalloc object has small size, as caught by 0Day bot [1] > > > > For better information for slab/slub, add free_meta's data size > > into 'struct kasan_cache', so that its users can take right action > > to avoid data conflict. > > > > [1]. https://lore.kernel.org/lkml/YuYm3dWwpZwH58Hu@xsang-OptiPlex-9020/ > > Reported-by: kernel test robot <oliver.sang@xxxxxxxxx> > > Signed-off-by: Feng Tang <feng.tang@xxxxxxxxx> > > Acked-by: Dmitry Vyukov <dvyukov@xxxxxxxxxx> > > --- > > include/linux/kasan.h | 2 ++ > > mm/kasan/common.c | 2 ++ > > 2 files changed, 4 insertions(+) > > > > diff --git a/include/linux/kasan.h b/include/linux/kasan.h > > index b092277bf48d..49af9513e8ed 100644 > > --- a/include/linux/kasan.h > > +++ b/include/linux/kasan.h > > @@ -100,6 +100,8 @@ static inline bool kasan_has_integrated_init(void) > > struct kasan_cache { > > int alloc_meta_offset; > > int free_meta_offset; > > + /* size of free_meta data saved in object's data area */ > > + int free_meta_size; > > bool is_kmalloc; > > }; > > > > diff --git a/mm/kasan/common.c b/mm/kasan/common.c > > index 69f583855c8b..0cb867e92524 100644 > > --- a/mm/kasan/common.c > > +++ b/mm/kasan/common.c > > @@ -201,6 +201,8 @@ void __kasan_cache_create(struct kmem_cache *cache, unsigned int *size, > > cache->kasan_info.free_meta_offset = KASAN_NO_FREE_META; > > *size = ok_size; > > } > > + } else { > > + cache->kasan_info.free_meta_size = sizeof(struct kasan_free_meta); > > Hi Feng, > > I just realized that we already have a function that exposes a similar > functionality: kasan_metadata_size. However, this function returns the > size of metadata that is stored in the redzone. > > I think, instead of adding free_meta_size, a better approach would be to: > > 1. Rename kasan_metadata_size to kasan_metadata_size_in_redzone (or > something like that). > 2. Add kasan_metadata_size_in_object with appropriate implementation > and use that in your patches. > > This allows avoiding exposing KASAN-internal details such as what kind > of fields the kasan_cache struct has to the common code. Agree, it's better not touch the internal fields in slub code. How about the following patch, it merge the 2 functions with one flag indicating in meta data or object. (I'm fine with 2 separate functions) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index b092277bf48d..0ad05a34e708 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -150,11 +150,12 @@ static __always_inline void kasan_cache_create_kmalloc(struct kmem_cache *cache) __kasan_cache_create_kmalloc(cache); } -size_t __kasan_metadata_size(struct kmem_cache *cache); -static __always_inline size_t kasan_metadata_size(struct kmem_cache *cache) +size_t __kasan_meta_size(struct kmem_cache *cache, bool in_slab_object); +static __always_inline size_t kasan_meta_size(struct kmem_cache *cache, + bool in_slab_object) { if (kasan_enabled()) - return __kasan_metadata_size(cache); + return __kasan_meta_size(cache, in_slab_object); return 0; } diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 69f583855c8b..2a8710461ebb 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -218,14 +218,21 @@ void __kasan_cache_create_kmalloc(struct kmem_cache *cache) cache->kasan_info.is_kmalloc = true; } -size_t __kasan_metadata_size(struct kmem_cache *cache) +size_t __kasan_meta_size(struct kmem_cache *cache, bool in_slab_object) { if (!kasan_stack_collection_enabled()) return 0; - return (cache->kasan_info.alloc_meta_offset ? - sizeof(struct kasan_alloc_meta) : 0) + - (cache->kasan_info.free_meta_offset ? - sizeof(struct kasan_free_meta) : 0); + + if (in_slab_object) + return (cache->kasan_info.alloc_meta_offset == 0 ? + sizeof(struct kasan_alloc_meta) : 0) + + (cache->kasan_info.free_meta_offset ? + sizeof(struct kasan_free_meta) : 0); + else + return (cache->kasan_info.alloc_meta_offset == 0 ? + sizeof(struct kasan_alloc_meta) : 0) + + (cache->kasan_info.free_meta_offset ? + sizeof(struct kasan_free_meta) : 0); } struct kasan_alloc_meta *kasan_get_alloc_meta(struct kmem_cache *cache, > Sorry for nor realizing this straight away. > > (Note that there's an upcoming patch that fixes a bug in > kasan_metadata_size' implementation [1].) Thanks for the note, will check this when making the formal patch. - Feng > Thanks! > > [1] https://lore.kernel.org/linux-mm/c7b316d30d90e5947eb8280f4dc78856a49298cf.1662411799.git.andreyknvl@xxxxxxxxxx/