From: Ethan Graham Introduce a new helper function, kasan_poison_range(), to encapsulate the logic for poisoning an arbitrary memory range of a given size, and expose it publically in . This is a preparatory change for the upcoming KFuzzTest patches, which requires the ability to poison the inter-region padding in its input buffers. No functional change to any other subsystem is intended by this commit. Signed-off-by: Ethan Graham --- include/linux/kasan.h | 16 ++++++++++++++++ mm/kasan/shadow.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 890011071f2b..09baeb6c9f4d 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -102,6 +102,21 @@ static inline bool kasan_has_integrated_init(void) } #ifdef CONFIG_KASAN + +/** + * kasan_poison_range - poison the memory range [start, start + size) + * + * The exact behavior is subject to alignment with KASAN_GRANULE_SIZE, defined + * in . + * + * - If @start is unaligned, the initial partial granule at the beginning + * of the range is only poisoned if CONFIG_KASAN_GENERIC is enabled. + * - The poisoning of the range only extends up to the last full granule before + * the end of the range. Any remaining bytes in a final partial granule are + * ignored. + */ +void kasan_poison_range(const void *start, size_t size); + void __kasan_unpoison_range(const void *addr, size_t size); static __always_inline void kasan_unpoison_range(const void *addr, size_t size) { @@ -402,6 +417,7 @@ static __always_inline bool kasan_check_byte(const void *addr) #else /* CONFIG_KASAN */ +static inline void kasan_poison_range(const void *start, size_t size) {} static inline void kasan_unpoison_range(const void *address, size_t size) {} static inline void kasan_poison_pages(struct page *page, unsigned int order, bool init) {} diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c index d2c70cd2afb1..a1b6bfb35f07 100644 --- a/mm/kasan/shadow.c +++ b/mm/kasan/shadow.c @@ -147,6 +147,37 @@ void kasan_poison(const void *addr, size_t size, u8 value, bool init) } EXPORT_SYMBOL_GPL(kasan_poison); +void kasan_poison_range(const void *start, size_t size) +{ + void *end = (char *)start + size; + uintptr_t start_addr = (uintptr_t)start; + uintptr_t head_granule_start; + uintptr_t poison_body_start; + uintptr_t poison_body_end; + size_t head_prefix_size; + uintptr_t end_addr; + + end_addr = ALIGN_DOWN((uintptr_t)end, KASAN_GRANULE_SIZE); + if (start_addr >= end_addr) + return; + + head_granule_start = ALIGN_DOWN(start_addr, KASAN_GRANULE_SIZE); + head_prefix_size = start_addr - head_granule_start; + + if (IS_ENABLED(CONFIG_KASAN_GENERIC) && head_prefix_size > 0) + kasan_poison_last_granule((void *)head_granule_start, + head_prefix_size); + + poison_body_start = ALIGN(start_addr, KASAN_GRANULE_SIZE); + poison_body_end = ALIGN_DOWN(end_addr, KASAN_GRANULE_SIZE); + + if (poison_body_start < poison_body_end) + kasan_poison((void *)poison_body_start, + poison_body_end - poison_body_start, + KASAN_SLAB_REDZONE, false); +} +EXPORT_SYMBOL(kasan_poison_range); + #ifdef CONFIG_KASAN_GENERIC void kasan_poison_last_granule(const void *addr, size_t size) { -- 2.51.0.rc0.205.g4a044479a3-goog