diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/damon/paddr.c | 7 | ||||
-rw-r--r-- | mm/kasan/Makefile | 9 | ||||
-rw-r--r-- | mm/kasan/kasan.h | 4 | ||||
-rw-r--r-- | mm/kasan/kasan_test.c | 29 | ||||
-rw-r--r-- | mm/kasan/shadow.c | 16 | ||||
-rw-r--r-- | mm/memory-failure.c | 8 | ||||
-rw-r--r-- | mm/mmap.c | 2 | ||||
-rw-r--r-- | mm/rmap.c | 2 |
8 files changed, 65 insertions, 12 deletions
diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c index 607bb69e526c..6c655d9b5639 100644 --- a/mm/damon/paddr.c +++ b/mm/damon/paddr.c @@ -250,12 +250,11 @@ static unsigned long damon_pa_pageout(struct damon_region *r, struct damos *s) folio_put(folio); continue; } - if (folio_test_unevictable(folio)) { + if (folio_test_unevictable(folio)) folio_putback_lru(folio); - } else { + else list_add(&folio->lru, &folio_list); - folio_put(folio); - } + folio_put(folio); } applied = reclaim_pages(&folio_list); cond_resched(); diff --git a/mm/kasan/Makefile b/mm/kasan/Makefile index d4837bff3b60..7634dd2a6128 100644 --- a/mm/kasan/Makefile +++ b/mm/kasan/Makefile @@ -35,7 +35,14 @@ CFLAGS_shadow.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_hw_tags.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_sw_tags.o := $(CC_FLAGS_KASAN_RUNTIME) -CFLAGS_KASAN_TEST := $(CFLAGS_KASAN) -fno-builtin $(call cc-disable-warning, vla) +CFLAGS_KASAN_TEST := $(CFLAGS_KASAN) $(call cc-disable-warning, vla) +ifndef CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX +# If compiler instruments memintrinsics by prefixing them with __asan/__hwasan, +# we need to treat them normally (as builtins), otherwise the compiler won't +# recognize them as instrumentable. If it doesn't instrument them, we need to +# pass -fno-builtin, so the compiler doesn't inline them. +CFLAGS_KASAN_TEST += -fno-builtin +endif CFLAGS_kasan_test.o := $(CFLAGS_KASAN_TEST) CFLAGS_kasan_test_module.o := $(CFLAGS_KASAN_TEST) diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index 9377b0789edc..a61eeee3095a 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -666,4 +666,8 @@ void __hwasan_storeN_noabort(unsigned long addr, size_t size); void __hwasan_tag_memory(unsigned long addr, u8 tag, unsigned long size); +void *__hwasan_memset(void *addr, int c, size_t len); +void *__hwasan_memmove(void *dest, const void *src, size_t len); +void *__hwasan_memcpy(void *dest, const void *src, size_t len); + #endif /* __MM_KASAN_KASAN_H */ diff --git a/mm/kasan/kasan_test.c b/mm/kasan/kasan_test.c index 74cd80c12b25..627eaf1ee1db 100644 --- a/mm/kasan/kasan_test.c +++ b/mm/kasan/kasan_test.c @@ -165,6 +165,15 @@ static void kasan_test_exit(struct kunit *test) kunit_skip((test), "Test requires " #config "=n"); \ } while (0) +#define KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test) do { \ + if (IS_ENABLED(CONFIG_KASAN_HW_TAGS)) \ + break; /* No compiler instrumentation. */ \ + if (IS_ENABLED(CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX)) \ + break; /* Should always be instrumented! */ \ + if (IS_ENABLED(CONFIG_GENERIC_ENTRY)) \ + kunit_skip((test), "Test requires checked mem*()"); \ +} while (0) + static void kmalloc_oob_right(struct kunit *test) { char *ptr; @@ -454,6 +463,8 @@ static void kmalloc_oob_16(struct kunit *test) u64 words[2]; } *ptr1, *ptr2; + KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test); + /* This test is specifically crafted for the generic mode. */ KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_GENERIC); @@ -476,6 +487,8 @@ static void kmalloc_uaf_16(struct kunit *test) u64 words[2]; } *ptr1, *ptr2; + KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test); + ptr1 = kmalloc(sizeof(*ptr1), GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr1); @@ -498,6 +511,8 @@ static void kmalloc_oob_memset_2(struct kunit *test) char *ptr; size_t size = 128 - KASAN_GRANULE_SIZE; + KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test); + ptr = kmalloc(size, GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr); @@ -511,6 +526,8 @@ static void kmalloc_oob_memset_4(struct kunit *test) char *ptr; size_t size = 128 - KASAN_GRANULE_SIZE; + KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test); + ptr = kmalloc(size, GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr); @@ -524,6 +541,8 @@ static void kmalloc_oob_memset_8(struct kunit *test) char *ptr; size_t size = 128 - KASAN_GRANULE_SIZE; + KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test); + ptr = kmalloc(size, GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr); @@ -537,6 +556,8 @@ static void kmalloc_oob_memset_16(struct kunit *test) char *ptr; size_t size = 128 - KASAN_GRANULE_SIZE; + KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test); + ptr = kmalloc(size, GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr); @@ -550,6 +571,8 @@ static void kmalloc_oob_in_memset(struct kunit *test) char *ptr; size_t size = 128 - KASAN_GRANULE_SIZE; + KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test); + ptr = kmalloc(size, GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr); @@ -566,6 +589,8 @@ static void kmalloc_memmove_negative_size(struct kunit *test) size_t size = 64; size_t invalid_size = -2; + KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test); + /* * Hardware tag-based mode doesn't check memmove for negative size. * As a result, this test introduces a side-effect memory corruption, @@ -590,6 +615,8 @@ static void kmalloc_memmove_invalid_size(struct kunit *test) size_t size = 64; size_t invalid_size = size; + KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test); + ptr = kmalloc(size, GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr); @@ -618,6 +645,8 @@ static void kmalloc_uaf_memset(struct kunit *test) char *ptr; size_t size = 33; + KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test); + /* * Only generic KASAN uses quarantine, which is required to avoid a * kernel memory corruption this test causes. diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c index 3703983a8e55..c8b86f3273b5 100644 --- a/mm/kasan/shadow.c +++ b/mm/kasan/shadow.c @@ -38,11 +38,14 @@ bool __kasan_check_write(const volatile void *p, unsigned int size) } EXPORT_SYMBOL(__kasan_check_write); -#ifndef CONFIG_GENERIC_ENTRY +#if !defined(CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX) && !defined(CONFIG_GENERIC_ENTRY) /* * CONFIG_GENERIC_ENTRY relies on compiler emitted mem*() calls to not be * instrumented. KASAN enabled toolchains should emit __asan_mem*() functions * for the sites they want to instrument. + * + * If we have a compiler that can instrument meminstrinsics, never override + * these, so that non-instrumented files can safely consider them as builtins. */ #undef memset void *memset(void *addr, int c, size_t len) @@ -107,6 +110,17 @@ void *__asan_memcpy(void *dest, const void *src, size_t len) } EXPORT_SYMBOL(__asan_memcpy); +#ifdef CONFIG_KASAN_SW_TAGS +void *__hwasan_memset(void *addr, int c, size_t len) __alias(__asan_memset); +EXPORT_SYMBOL(__hwasan_memset); +#ifdef __HAVE_ARCH_MEMMOVE +void *__hwasan_memmove(void *dest, const void *src, size_t len) __alias(__asan_memmove); +EXPORT_SYMBOL(__hwasan_memmove); +#endif +void *__hwasan_memcpy(void *dest, const void *src, size_t len) __alias(__asan_memcpy); +EXPORT_SYMBOL(__hwasan_memcpy); +#endif + void kasan_poison(const void *addr, size_t size, u8 value, bool init) { void *shadow_start, *shadow_end; diff --git a/mm/memory-failure.c b/mm/memory-failure.c index a1ede7bdce95..fae9baf3be16 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1069,7 +1069,7 @@ static int me_pagecache_dirty(struct page_state *ps, struct page *p) * cache and swap cache(ie. page is freshly swapped in). So it could be * referenced concurrently by 2 types of PTEs: * normal PTEs and swap PTEs. We try to handle them consistently by calling - * try_to_unmap(TTU_IGNORE_HWPOISON) to convert the normal PTEs to swap PTEs, + * try_to_unmap(!TTU_HWPOISON) to convert the normal PTEs to swap PTEs, * and then * - clear dirty bit to prevent IO * - remove from LRU @@ -1486,7 +1486,7 @@ static bool hwpoison_user_mappings(struct page *p, unsigned long pfn, int flags, struct page *hpage) { struct folio *folio = page_folio(hpage); - enum ttu_flags ttu = TTU_IGNORE_MLOCK | TTU_SYNC; + enum ttu_flags ttu = TTU_IGNORE_MLOCK | TTU_SYNC | TTU_HWPOISON; struct address_space *mapping; LIST_HEAD(tokill); bool unmap_success; @@ -1516,7 +1516,7 @@ static bool hwpoison_user_mappings(struct page *p, unsigned long pfn, if (PageSwapCache(p)) { pr_err("%#lx: keeping poisoned page in swap cache\n", pfn); - ttu |= TTU_IGNORE_HWPOISON; + ttu &= ~TTU_HWPOISON; } /* @@ -1531,7 +1531,7 @@ static bool hwpoison_user_mappings(struct page *p, unsigned long pfn, if (page_mkclean(hpage)) { SetPageDirty(hpage); } else { - ttu |= TTU_IGNORE_HWPOISON; + ttu &= ~TTU_HWPOISON; pr_info("%#lx: corrupted page was clean: dropped without side effects\n", pfn); } diff --git a/mm/mmap.c b/mm/mmap.c index 20f21f0949dd..740b54be3ed4 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -973,7 +973,7 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm, vma_end = addr; adjust = mid; adj_next = -(vma->vm_end - addr); - err = dup_anon_vma(res, adjust); + err = dup_anon_vma(adjust, prev); } else { vma = next; /* case 3 */ vma_start = addr; diff --git a/mm/rmap.c b/mm/rmap.c index 15ae24585fc4..8632e02661ac 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -1602,7 +1602,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma, /* Update high watermark before we lower rss */ update_hiwater_rss(mm); - if (PageHWPoison(subpage) && !(flags & TTU_IGNORE_HWPOISON)) { + if (PageHWPoison(subpage) && (flags & TTU_HWPOISON)) { pteval = swp_entry_to_pte(make_hwpoison_entry(subpage)); if (folio_test_hugetlb(folio)) { hugetlb_count_sub(folio_nr_pages(folio), mm); |