linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Muchun Song <songmuchun@bytedance.com>
To: glider@google.com, elver@google.com, dvyukov@google.com,
	akpm@linux-foundation.org, jannh@google.com, sjpark@amazon.de,
	muchun.song@linux.dev
Cc: kasan-dev@googlegroups.com, linux-mm@kvack.org,
	linux-kernel@vger.kernel.org,
	Muchun Song <songmuchun@bytedance.com>
Subject: [PATCH 5/6] mm: kfence: change kfence pool page layout
Date: Tue, 28 Mar 2023 17:58:06 +0800	[thread overview]
Message-ID: <20230328095807.7014-6-songmuchun@bytedance.com> (raw)
In-Reply-To: <20230328095807.7014-1-songmuchun@bytedance.com>

The original kfence pool layout (Given a layout with 2 objects):

 +------------+------------+------------+------------+------------+------------+
 | guard page | guard page |   object   | guard page |   object   | guard page |
 +------------+------------+------------+------------+------------+------------+
                           |                         |                         |
                           +----kfence_metadata[0]---+----kfence_metadata[1]---+

The comment says "the additional page in the beginning gives us an even
number of pages, which simplifies the mapping of address to metadata index".

However, removing the additional page does not complicate any mapping
calculations. So changing it to the new layout to save a page. And remmove
the KFENCE_ERROR_INVALID test since we cannot test this case easily.

The new kfence pool layout (Given a layout with 2 objects):

 +------------+------------+------------+------------+------------+
 | guard page |   object   | guard page |   object   | guard page |
 +------------+------------+------------+------------+------------+
 |                         |                         |
 +----kfence_metadata[0]---+----kfence_metadata[1]---+

Signed-off-by: Muchun Song <songmuchun@bytedance.com>
---
 include/linux/kfence.h  |  8 ++------
 mm/kfence/core.c        | 40 ++++++++--------------------------------
 mm/kfence/kfence.h      |  2 +-
 mm/kfence/kfence_test.c | 14 --------------
 4 files changed, 11 insertions(+), 53 deletions(-)

diff --git a/include/linux/kfence.h b/include/linux/kfence.h
index 726857a4b680..25b13a892717 100644
--- a/include/linux/kfence.h
+++ b/include/linux/kfence.h
@@ -19,12 +19,8 @@
 
 extern unsigned long kfence_sample_interval;
 
-/*
- * We allocate an even number of pages, as it simplifies calculations to map
- * address to metadata indices; effectively, the very first page serves as an
- * extended guard page, but otherwise has no special purpose.
- */
-#define KFENCE_POOL_SIZE ((CONFIG_KFENCE_NUM_OBJECTS + 1) * 2 * PAGE_SIZE)
+/* The last page serves as an extended guard page. */
+#define KFENCE_POOL_SIZE	((CONFIG_KFENCE_NUM_OBJECTS * 2 + 1) * PAGE_SIZE)
 extern char *__kfence_pool;
 
 DECLARE_STATIC_KEY_FALSE(kfence_allocation_key);
diff --git a/mm/kfence/core.c b/mm/kfence/core.c
index 41befcb3b069..f205b860f460 100644
--- a/mm/kfence/core.c
+++ b/mm/kfence/core.c
@@ -240,24 +240,7 @@ static inline void kfence_unprotect(unsigned long addr)
 
 static inline unsigned long metadata_to_pageaddr(const struct kfence_metadata *meta)
 {
-	unsigned long offset = (meta - kfence_metadata + 1) * PAGE_SIZE * 2;
-	unsigned long pageaddr = (unsigned long)&__kfence_pool[offset];
-
-	/* The checks do not affect performance; only called from slow-paths. */
-
-	/* Only call with a pointer into kfence_metadata. */
-	if (KFENCE_WARN_ON(meta < kfence_metadata ||
-			   meta >= kfence_metadata + CONFIG_KFENCE_NUM_OBJECTS))
-		return 0;
-
-	/*
-	 * This metadata object only ever maps to 1 page; verify that the stored
-	 * address is in the expected range.
-	 */
-	if (KFENCE_WARN_ON(ALIGN_DOWN(meta->addr, PAGE_SIZE) != pageaddr))
-		return 0;
-
-	return pageaddr;
+	return ALIGN_DOWN(meta->addr, PAGE_SIZE);
 }
 
 /*
@@ -535,34 +518,27 @@ static void kfence_init_pool(void)
 	unsigned long addr = (unsigned long)__kfence_pool;
 	int i;
 
-	/*
-	 * Protect the first 2 pages. The first page is mostly unnecessary, and
-	 * merely serves as an extended guard page. However, adding one
-	 * additional page in the beginning gives us an even number of pages,
-	 * which simplifies the mapping of address to metadata index.
-	 */
-	for (i = 0; i < 2; i++, addr += PAGE_SIZE)
-		kfence_protect(addr);
-
 	for (i = 0; i < CONFIG_KFENCE_NUM_OBJECTS; i++, addr += 2 * PAGE_SIZE) {
 		struct kfence_metadata *meta = &kfence_metadata[i];
-		struct slab *slab = page_slab(virt_to_page(addr));
+		struct slab *slab = page_slab(virt_to_page(addr + PAGE_SIZE));
 
 		/* Initialize metadata. */
 		INIT_LIST_HEAD(&meta->list);
 		raw_spin_lock_init(&meta->lock);
 		meta->state = KFENCE_OBJECT_UNUSED;
-		meta->addr = addr; /* Initialize for validation in metadata_to_pageaddr(). */
+		meta->addr = addr + PAGE_SIZE;
 		list_add_tail(&meta->list, &kfence_freelist);
 
-		/* Protect the right redzone. */
-		kfence_protect(addr + PAGE_SIZE);
+		/* Protect the left redzone. */
+		kfence_protect(addr);
 
 		__folio_set_slab(slab_folio(slab));
 #ifdef CONFIG_MEMCG
 		slab->memcg_data = (unsigned long)&meta->objcg | MEMCG_DATA_OBJCGS;
 #endif
 	}
+
+	kfence_protect(addr);
 }
 
 static bool __init kfence_init_pool_early(void)
@@ -1043,7 +1019,7 @@ bool kfence_handle_page_fault(unsigned long addr, bool is_write, struct pt_regs
 
 	atomic_long_inc(&counters[KFENCE_COUNTER_BUGS]);
 
-	if (page_index % 2) {
+	if (page_index % 2 == 0) {
 		/* This is a redzone, report a buffer overflow. */
 		struct kfence_metadata *meta;
 		int distance = 0;
diff --git a/mm/kfence/kfence.h b/mm/kfence/kfence.h
index 600f2e2431d6..249d420100a7 100644
--- a/mm/kfence/kfence.h
+++ b/mm/kfence/kfence.h
@@ -110,7 +110,7 @@ static inline struct kfence_metadata *addr_to_metadata(unsigned long addr)
 	 * __kfence_pool, in which case we would report an "invalid access"
 	 * error.
 	 */
-	index = (addr - (unsigned long)__kfence_pool) / (PAGE_SIZE * 2) - 1;
+	index = (addr - (unsigned long)__kfence_pool) / (PAGE_SIZE * 2);
 	if (index < 0 || index >= CONFIG_KFENCE_NUM_OBJECTS)
 		return NULL;
 
diff --git a/mm/kfence/kfence_test.c b/mm/kfence/kfence_test.c
index b5d66a69200d..d479f9c8afb1 100644
--- a/mm/kfence/kfence_test.c
+++ b/mm/kfence/kfence_test.c
@@ -637,19 +637,6 @@ static void test_gfpzero(struct kunit *test)
 	KUNIT_EXPECT_FALSE(test, report_available());
 }
 
-static void test_invalid_access(struct kunit *test)
-{
-	const struct expect_report expect = {
-		.type = KFENCE_ERROR_INVALID,
-		.fn = test_invalid_access,
-		.addr = &__kfence_pool[10],
-		.is_write = false,
-	};
-
-	READ_ONCE(__kfence_pool[10]);
-	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
-}
-
 /* Test SLAB_TYPESAFE_BY_RCU works. */
 static void test_memcache_typesafe_by_rcu(struct kunit *test)
 {
@@ -787,7 +774,6 @@ static struct kunit_case kfence_test_cases[] = {
 	KUNIT_CASE(test_kmalloc_aligned_oob_write),
 	KUNIT_CASE(test_shrink_memcache),
 	KUNIT_CASE(test_memcache_ctor),
-	KUNIT_CASE(test_invalid_access),
 	KUNIT_CASE(test_gfpzero),
 	KUNIT_CASE(test_memcache_typesafe_by_rcu),
 	KUNIT_CASE(test_krealloc),
-- 
2.11.0



  parent reply	other threads:[~2023-03-28  9:58 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-28  9:58 [PATCH 0/6] Simplify kfence code Muchun Song
2023-03-28  9:58 ` [PATCH 1/6] mm: kfence: simplify kfence pool initialization Muchun Song
2023-03-28 11:55   ` Marco Elver
2023-03-28 12:05     ` Marco Elver
2023-03-28 12:53       ` Muchun Song
2023-03-28  9:58 ` [PATCH 2/6] mm: kfence: check kfence pool size at building time Muchun Song
2023-03-28 10:14   ` Marco Elver
2023-03-28 13:03     ` Muchun Song
2023-03-28  9:58 ` [PATCH 3/6] mm: kfence: make kfence_protect_page() void Muchun Song
2023-03-28 10:32   ` Marco Elver
2023-03-28 13:04     ` Muchun Song
2023-03-28  9:58 ` [PATCH 4/6] mm: kfence: remove useless check for CONFIG_KFENCE_NUM_OBJECTS Muchun Song
2023-04-03  8:59   ` Alexander Potapenko
2023-03-28  9:58 ` Muchun Song [this message]
2023-03-28 12:59   ` [PATCH 5/6] mm: kfence: change kfence pool page layout Marco Elver
2023-03-28 13:32     ` Muchun Song
2023-03-28 14:12       ` Marco Elver
2023-03-28  9:58 ` [PATCH 6/6] mm: kfence: replace ALIGN_DOWN(x, PAGE_SIZE) with PAGE_ALIGN_DOWN(x) Muchun Song
2023-03-28 11:55   ` Marco Elver

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230328095807.7014-6-songmuchun@bytedance.com \
    --to=songmuchun@bytedance.com \
    --cc=akpm@linux-foundation.org \
    --cc=dvyukov@google.com \
    --cc=elver@google.com \
    --cc=glider@google.com \
    --cc=jannh@google.com \
    --cc=kasan-dev@googlegroups.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=muchun.song@linux.dev \
    --cc=sjpark@amazon.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox