Skip to content

Commit 2d55246

Browse files
xairyakpm00
authored andcommitted
slub, kasan: improve interaction of KASAN and slub_debug poisoning
When both KASAN and slub_debug are enabled, when a free object is being prepared in setup_object, slub_debug poisons the object data before KASAN initializes its per-object metadata. Right now, in setup_object, KASAN only initializes the alloc metadata, which is always stored outside of the object. slub_debug is aware of this and it skips poisoning and checking that memory area. However, with the following patch in this series, KASAN also starts initializing its free medata in setup_object. As this metadata might be stored within the object, this initialization might overwrite the slub_debug poisoning. This leads to slub_debug reports. Thus, skip checking slub_debug poisoning of the object data area that overlaps with the in-object KASAN free metadata. Also make slub_debug poisoning of tail kmalloc redzones more precise when KASAN is enabled: slub_debug can still poison and check the tail kmalloc allocation area that comes after the KASAN free metadata. Link: https://lkml.kernel.org/r/20231122231202.121277-1-andrey.konovalov@linux.dev Signed-off-by: Andrey Konovalov <andreyknvl@google.com> Tested-by: Hyeonggon Yoo <42.hyeyoo@gmail.com> Cc: Alexander Potapenko <glider@google.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Evgenii Stepanov <eugenis@google.com> Cc: Feng Tang <feng.tang@intel.com> Cc: Marco Elver <elver@google.com> Cc: Oscar Salvador <osalvador@suse.de> Cc: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent f816938 commit 2d55246

File tree

1 file changed

+26
-15
lines changed

1 file changed

+26
-15
lines changed

mm/slub.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -870,20 +870,20 @@ static inline void set_orig_size(struct kmem_cache *s,
870870
void *object, unsigned int orig_size)
871871
{
872872
void *p = kasan_reset_tag(object);
873+
unsigned int kasan_meta_size;
873874

874875
if (!slub_debug_orig_size(s))
875876
return;
876877

877-
#ifdef CONFIG_KASAN_GENERIC
878878
/*
879-
* KASAN could save its free meta data in object's data area at
880-
* offset 0, if the size is larger than 'orig_size', it will
881-
* overlap the data redzone in [orig_size+1, object_size], and
882-
* the check should be skipped.
879+
* KASAN can save its free meta data inside of the object at offset 0.
880+
* If this meta data size is larger than 'orig_size', it will overlap
881+
* the data redzone in [orig_size+1, object_size]. Thus, we adjust
882+
* 'orig_size' to be as at least as big as KASAN's meta data.
883883
*/
884-
if (kasan_metadata_size(s, true) > orig_size)
885-
orig_size = s->object_size;
886-
#endif
884+
kasan_meta_size = kasan_metadata_size(s, true);
885+
if (kasan_meta_size > orig_size)
886+
orig_size = kasan_meta_size;
887887

888888
p += get_info_end(s);
889889
p += sizeof(struct track) * 2;
@@ -1192,7 +1192,7 @@ static int check_object(struct kmem_cache *s, struct slab *slab,
11921192
{
11931193
u8 *p = object;
11941194
u8 *endobject = object + s->object_size;
1195-
unsigned int orig_size;
1195+
unsigned int orig_size, kasan_meta_size;
11961196

11971197
if (s->flags & SLAB_RED_ZONE) {
11981198
if (!check_bytes_and_report(s, slab, object, "Left Redzone",
@@ -1222,12 +1222,23 @@ static int check_object(struct kmem_cache *s, struct slab *slab,
12221222
}
12231223

12241224
if (s->flags & SLAB_POISON) {
1225-
if (val != SLUB_RED_ACTIVE && (s->flags & __OBJECT_POISON) &&
1226-
(!check_bytes_and_report(s, slab, p, "Poison", p,
1227-
POISON_FREE, s->object_size - 1) ||
1228-
!check_bytes_and_report(s, slab, p, "End Poison",
1229-
p + s->object_size - 1, POISON_END, 1)))
1230-
return 0;
1225+
if (val != SLUB_RED_ACTIVE && (s->flags & __OBJECT_POISON)) {
1226+
/*
1227+
* KASAN can save its free meta data inside of the
1228+
* object at offset 0. Thus, skip checking the part of
1229+
* the redzone that overlaps with the meta data.
1230+
*/
1231+
kasan_meta_size = kasan_metadata_size(s, true);
1232+
if (kasan_meta_size < s->object_size - 1 &&
1233+
!check_bytes_and_report(s, slab, p, "Poison",
1234+
p + kasan_meta_size, POISON_FREE,
1235+
s->object_size - kasan_meta_size - 1))
1236+
return 0;
1237+
if (kasan_meta_size < s->object_size &&
1238+
!check_bytes_and_report(s, slab, p, "End Poison",
1239+
p + s->object_size - 1, POISON_END, 1))
1240+
return 0;
1241+
}
12311242
/*
12321243
* check_pad_bytes cleans up on its own.
12331244
*/

0 commit comments

Comments
 (0)