Skip to content

Commit 823ec0e

Browse files
pimyn-girgisgregkh
authored andcommitted
mm/kfence: randomize the freelist on initialization
commit 870ff19 upstream. Randomize the KFENCE freelist during pool initialization to make allocation patterns less predictable. This is achieved by shuffling the order in which metadata objects are added to the freelist using get_random_u32_below(). Additionally, ensure the error path correctly calculates the address range to be reset if initialization fails, as the address increment logic has been moved to a separate loop. Link: https://lkml.kernel.org/r/20260120161510.3289089-1-pimyn@google.com Fixes: 0ce20dd ("mm: add Kernel Electric-Fence infrastructure") Signed-off-by: Pimyn Girgis <pimyn@google.com> Reviewed-by: Alexander Potapenko <glider@google.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Marco Elver <elver@google.com> Cc: Ernesto Martnez Garca <ernesto.martinezgarcia@tugraz.at> Cc: Greg KH <gregkh@linuxfoundation.org> Cc: Kees Cook <kees@kernel.org> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Pimyn Girgis <pimyn@google.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 3dedeee commit 823ec0e

1 file changed

Lines changed: 19 additions & 4 deletions

File tree

mm/kfence/core.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@ static unsigned long kfence_init_pool(void)
596596
{
597597
unsigned long addr;
598598
struct page *pages;
599-
int i;
599+
int i, rand;
600600

601601
if (!arch_kfence_init_pool())
602602
return (unsigned long)__kfence_pool;
@@ -645,13 +645,27 @@ static unsigned long kfence_init_pool(void)
645645
INIT_LIST_HEAD(&meta->list);
646646
raw_spin_lock_init(&meta->lock);
647647
meta->state = KFENCE_OBJECT_UNUSED;
648-
meta->addr = addr; /* Initialize for validation in metadata_to_pageaddr(). */
649-
list_add_tail(&meta->list, &kfence_freelist);
648+
/* Use addr to randomize the freelist. */
649+
meta->addr = i;
650650

651651
/* Protect the right redzone. */
652-
if (unlikely(!kfence_protect(addr + PAGE_SIZE)))
652+
if (unlikely(!kfence_protect(addr + 2 * i * PAGE_SIZE + PAGE_SIZE)))
653653
goto reset_slab;
654+
}
655+
656+
for (i = CONFIG_KFENCE_NUM_OBJECTS; i > 0; i--) {
657+
rand = get_random_u32_below(i);
658+
swap(kfence_metadata_init[i - 1].addr, kfence_metadata_init[rand].addr);
659+
}
654660

661+
for (i = 0; i < CONFIG_KFENCE_NUM_OBJECTS; i++) {
662+
struct kfence_metadata *meta_1 = &kfence_metadata_init[i];
663+
struct kfence_metadata *meta_2 = &kfence_metadata_init[meta_1->addr];
664+
665+
list_add_tail(&meta_2->list, &kfence_freelist);
666+
}
667+
for (i = 0; i < CONFIG_KFENCE_NUM_OBJECTS; i++) {
668+
kfence_metadata_init[i].addr = addr;
655669
addr += 2 * PAGE_SIZE;
656670
}
657671

@@ -664,6 +678,7 @@ static unsigned long kfence_init_pool(void)
664678
return 0;
665679

666680
reset_slab:
681+
addr += 2 * i * PAGE_SIZE;
667682
for (i = 0; i < KFENCE_POOL_SIZE / PAGE_SIZE; i++) {
668683
struct slab *slab = page_slab(nth_page(pages, i));
669684

0 commit comments

Comments
 (0)