Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

kasan: ensure poisoning size alignment

A previous changes d99f6a10c161 ("kasan: don't round_up too much")
attempted to simplify the code by adding a round_up(size) call into
kasan_poison(). While this allows to have less round_up() calls around
the code, this results in round_up() being called multiple times.

This patch removes round_up() of size from kasan_poison() and ensures that
all callers round_up() the size explicitly. This patch also adds
WARN_ON() alignment checks for address and size to kasan_poison() and
kasan_unpoison().

Link: https://lkml.kernel.org/r/3ffe8d4a246ae67a8b5e91f65bf98cd7cba9d7b9.1612546384.git.andreyknvl@google.com
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
Reviewed-by: Marco Elver <elver@google.com>
Cc: Alexander Potapenko <glider@google.com>
Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Branislav Rankov <Branislav.Rankov@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Evgenii Stepanov <eugenis@google.com>
Cc: Kevin Brodsky <kevin.brodsky@arm.com>
Cc: Peter Collingbourne <pcc@google.com>
Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Andrey Konovalov and committed by
Linus Torvalds
cde8a7eb d12d9ad8

+48 -31
+6 -3
mm/kasan/common.c
··· 261 261 262 262 void __kasan_poison_object_data(struct kmem_cache *cache, void *object) 263 263 { 264 - kasan_poison(object, cache->object_size, KASAN_KMALLOC_REDZONE); 264 + kasan_poison(object, round_up(cache->object_size, KASAN_GRANULE_SIZE), 265 + KASAN_KMALLOC_REDZONE); 265 266 } 266 267 267 268 /* ··· 349 348 return true; 350 349 } 351 350 352 - kasan_poison(object, cache->object_size, KASAN_KMALLOC_FREE); 351 + kasan_poison(object, round_up(cache->object_size, KASAN_GRANULE_SIZE), 352 + KASAN_KMALLOC_FREE); 353 353 354 354 if ((IS_ENABLED(CONFIG_KASAN_GENERIC) && !quarantine)) 355 355 return false; ··· 492 490 /* Poison the aligned part of the redzone. */ 493 491 redzone_start = round_up((unsigned long)(object + size), 494 492 KASAN_GRANULE_SIZE); 495 - redzone_end = (unsigned long)object + cache->object_size; 493 + redzone_end = round_up((unsigned long)(object + cache->object_size), 494 + KASAN_GRANULE_SIZE); 496 495 kasan_poison((void *)redzone_start, redzone_end - redzone_start, 497 496 KASAN_KMALLOC_REDZONE); 498 497
+20 -13
mm/kasan/kasan.h
··· 330 330 331 331 #ifdef CONFIG_KASAN_HW_TAGS 332 332 333 - static inline void kasan_poison(const void *address, size_t size, u8 value) 333 + static inline void kasan_poison(const void *addr, size_t size, u8 value) 334 334 { 335 - address = kasan_reset_tag(address); 335 + addr = kasan_reset_tag(addr); 336 336 337 337 /* Skip KFENCE memory if called explicitly outside of sl*b. */ 338 - if (is_kfence_address(address)) 338 + if (is_kfence_address(addr)) 339 339 return; 340 340 341 - hw_set_mem_tag_range((void *)address, 342 - round_up(size, KASAN_GRANULE_SIZE), value); 341 + if (WARN_ON((unsigned long)addr & KASAN_GRANULE_MASK)) 342 + return; 343 + if (WARN_ON(size & KASAN_GRANULE_MASK)) 344 + return; 345 + 346 + hw_set_mem_tag_range((void *)addr, size, value); 343 347 } 344 348 345 - static inline void kasan_unpoison(const void *address, size_t size) 349 + static inline void kasan_unpoison(const void *addr, size_t size) 346 350 { 347 - u8 tag = get_tag(address); 351 + u8 tag = get_tag(addr); 348 352 349 - address = kasan_reset_tag(address); 353 + addr = kasan_reset_tag(addr); 350 354 351 355 /* Skip KFENCE memory if called explicitly outside of sl*b. */ 352 - if (is_kfence_address(address)) 356 + if (is_kfence_address(addr)) 353 357 return; 354 358 355 - hw_set_mem_tag_range((void *)address, 356 - round_up(size, KASAN_GRANULE_SIZE), tag); 359 + if (WARN_ON((unsigned long)addr & KASAN_GRANULE_MASK)) 360 + return; 361 + size = round_up(size, KASAN_GRANULE_SIZE); 362 + 363 + hw_set_mem_tag_range((void *)addr, size, tag); 357 364 } 358 365 359 366 static inline bool kasan_byte_accessible(const void *addr) ··· 377 370 /** 378 371 * kasan_poison - mark the memory range as unaccessible 379 372 * @addr - range start address, must be aligned to KASAN_GRANULE_SIZE 380 - * @size - range size 373 + * @size - range size, must be aligned to KASAN_GRANULE_SIZE 381 374 * @value - value that's written to metadata for the range 382 375 * 383 376 * The size gets aligned to KASAN_GRANULE_SIZE before marking the range. ··· 387 380 /** 388 381 * kasan_unpoison - mark the memory range as accessible 389 382 * @addr - range start address, must be aligned to KASAN_GRANULE_SIZE 390 - * @size - range size 383 + * @size - range size, can be unaligned 391 384 * 392 385 * For the tag-based modes, the @size gets aligned to KASAN_GRANULE_SIZE before 393 386 * marking the range.
+22 -15
mm/kasan/shadow.c
··· 69 69 return __memcpy(dest, src, len); 70 70 } 71 71 72 - void kasan_poison(const void *address, size_t size, u8 value) 72 + void kasan_poison(const void *addr, size_t size, u8 value) 73 73 { 74 74 void *shadow_start, *shadow_end; 75 75 ··· 78 78 * some of the callers (e.g. kasan_poison_object_data) pass tagged 79 79 * addresses to this function. 80 80 */ 81 - address = kasan_reset_tag(address); 81 + addr = kasan_reset_tag(addr); 82 82 83 83 /* Skip KFENCE memory if called explicitly outside of sl*b. */ 84 - if (is_kfence_address(address)) 84 + if (is_kfence_address(addr)) 85 85 return; 86 86 87 - size = round_up(size, KASAN_GRANULE_SIZE); 88 - shadow_start = kasan_mem_to_shadow(address); 89 - shadow_end = kasan_mem_to_shadow(address + size); 87 + if (WARN_ON((unsigned long)addr & KASAN_GRANULE_MASK)) 88 + return; 89 + if (WARN_ON(size & KASAN_GRANULE_MASK)) 90 + return; 91 + 92 + shadow_start = kasan_mem_to_shadow(addr); 93 + shadow_end = kasan_mem_to_shadow(addr + size); 90 94 91 95 __memset(shadow_start, value, shadow_end - shadow_start); 92 96 } 93 97 EXPORT_SYMBOL(kasan_poison); 94 98 95 99 #ifdef CONFIG_KASAN_GENERIC 96 - void kasan_poison_last_granule(const void *address, size_t size) 100 + void kasan_poison_last_granule(const void *addr, size_t size) 97 101 { 98 102 if (size & KASAN_GRANULE_MASK) { 99 - u8 *shadow = (u8 *)kasan_mem_to_shadow(address + size); 103 + u8 *shadow = (u8 *)kasan_mem_to_shadow(addr + size); 100 104 *shadow = size & KASAN_GRANULE_MASK; 101 105 } 102 106 } 103 107 #endif 104 108 105 - void kasan_unpoison(const void *address, size_t size) 109 + void kasan_unpoison(const void *addr, size_t size) 106 110 { 107 - u8 tag = get_tag(address); 111 + u8 tag = get_tag(addr); 108 112 109 113 /* 110 114 * Perform shadow offset calculation based on untagged address, as 111 115 * some of the callers (e.g. kasan_unpoison_object_data) pass tagged 112 116 * addresses to this function. 113 117 */ 114 - address = kasan_reset_tag(address); 118 + addr = kasan_reset_tag(addr); 115 119 116 120 /* 117 121 * Skip KFENCE memory if called explicitly outside of sl*b. Also note 118 122 * that calls to ksize(), where size is not a multiple of machine-word 119 123 * size, would otherwise poison the invalid portion of the word. 120 124 */ 121 - if (is_kfence_address(address)) 125 + if (is_kfence_address(addr)) 122 126 return; 123 127 124 - /* Unpoison round_up(size, KASAN_GRANULE_SIZE) bytes. */ 125 - kasan_poison(address, size, tag); 128 + if (WARN_ON((unsigned long)addr & KASAN_GRANULE_MASK)) 129 + return; 130 + 131 + /* Unpoison all granules that cover the object. */ 132 + kasan_poison(addr, round_up(size, KASAN_GRANULE_SIZE), tag); 126 133 127 134 /* Partially poison the last granule for the generic mode. */ 128 135 if (IS_ENABLED(CONFIG_KASAN_GENERIC)) 129 - kasan_poison_last_granule(address, size); 136 + kasan_poison_last_granule(addr, size); 130 137 } 131 138 132 139 #ifdef CONFIG_MEMORY_HOTPLUG