From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wm1-f74.google.com (mail-wm1-f74.google.com [209.85.128.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EF30D39281B for ; Fri, 17 Jul 2026 13:40:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.74 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784295636; cv=none; b=N676reBavDte+CrjzxyFITnxGv3nQ28kjr2sFNlT+mFs0t9c7ZvxVTk0igz8TNc5SMXSJKSyAFzMYNiXTETmFBVKlN9cutDXdS7NpuPBvCz3rM9Qd7CB3lfdEWyjRNJk+MBLafG8Y5kyBf3VvGQ4xHpzJnqRhAnG1rBDCFaPSXw= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784295636; c=relaxed/simple; bh=/r6uAtf+Zx81tRtQzBtFpxy2LO0b0Yq0RnPgXTUud1s=; h=Date:Mime-Version:Message-ID:Subject:From:To:Cc:Content-Type; b=AjwsKBUNFwk4OtzfKBjly8vtAXaoo0u1V2kbiZPgviyYk16CW/8/Qh9XriWpzmp/AyoqXBWh3InWFu7dVnBVkZ3v7Iam34TwDOM6cA9RT4J5pMmfFFMPmWVttd22Tr0aTuHKdX+QYVnkhgC1iPGB5IEhtc5QnBOrUkA8pSXhA6E= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--mclapinski.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=UknOBzjb; arc=none smtp.client-ip=209.85.128.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--mclapinski.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="UknOBzjb" Received: by mail-wm1-f74.google.com with SMTP id 5b1f17b1804b1-493c20d0468so53594365e9.1 for ; Fri, 17 Jul 2026 06:40:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1784295633; x=1784900433; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:mime-version:date:from :to:cc:subject:date:message-id:reply-to:content-type; bh=qJ3lF392ZnaDQ7ksH9U+tbRYSBGb3EW5QpOiJ+U17/M=; b=UknOBzjb5S3XQo+GpbCPCYrcgNC8rOkmQrkWapVmN01f88h7HDlAcleO+sRdimwnUU I7WjMV43CfpiH0Z9xX/VTif5esqmEaArcTVh+9RN/pjkBkCeF+x8i6FMGv8KAe71k0Sj BA2ficFOz2sLD8QjvEsnMe1Rm79SDXscHIjSpfhiWKsw3TGEsL9w7xtdCi5qCPrqJxqk tgm16N81zkHPiyHqJ9o0EkN/7GmZg0Mf6zvbsa9p/2u/En1oC1O8aK7KsmWjrKVlDvuj DVmvhPzg9dX8gHGg5HXuYJ/l0h4SJc+eHv+IzmW6VKI78jPBRJVQDzTeQ6zW42JMQMhx F4dw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784295633; x=1784900433; h=content-type:cc:to:from:subject:message-id:mime-version:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=qJ3lF392ZnaDQ7ksH9U+tbRYSBGb3EW5QpOiJ+U17/M=; b=c5fX77O2COkCJTzeeYu27s08vkJxe4fmmuQt8EsaPssza70TvuaPcB7lctVdUwHYn1 VMGaHzR2WAwf/bbJ6hUSMnjlNKpXSgTXDgOKbCB+N09MkB3FaJuL/AII1wXgajD0OBL+ pfF3hyxMbqCyMLxuA0amL50pwfuyNlKHpsMSMvPjL+3+73hRLc4mInBbFtGtTAMTcsKm KRowBmK83fF/4rFDOn8ODDyyteWrW40sEkIQCVLmJ0MgElw5vdzVoI8/XI20xFFH/r0j BKl63x896rGZPJRIyW1NFvC2Jf2qBtJM8HNs8B/NfPcACdvzKGdH1Y+xeZwzLAsr925Y gR1w== X-Forwarded-Encrypted: i=1; AHgh+Rq3h8ym5lkX0HQeeNfrucvC4QNeXEhqis7u69JvRw8qqcXomJnkKzmlUxExFn6L8gYDW9zKHMmU6Uu4fIE=@vger.kernel.org X-Gm-Message-State: AOJu0YywjAg9NRnZM2ORpMSW3zDcnDNYne/i8meHhvHe14aEocN8UPto 3Vncd6h7ierpp2Y1urXGIpQPBXNT37ioZ1RD6oE1N8CS3qY+GShmaMytFUkuErTSuLxFRjtBTaZ fDpkDG6Wq3AAIJFzH+6akVw== X-Received: from wrvx6.prod.google.com ([2002:a5d:54c6:0:b0:47f:4443:1db4]) (user=mclapinski job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:1382:b0:495:3f48:5df2 with SMTP id 5b1f17b1804b1-4954a40bcf6mr31154885e9.29.1784295632744; Fri, 17 Jul 2026 06:40:32 -0700 (PDT) Date: Fri, 17 Jul 2026 15:40:28 +0200 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 X-Mailer: git-send-email 2.55.0.229.g6434b31f56-goog Message-ID: <20260717134028.2880508-1-mclapinski@google.com> Subject: [PATCH v2] kho: align kho_scratch to MAX_ORDER_NR_PAGES pages From: Michal Clapinski To: Mike Rapoport , Pasha Tatashin , Pratyush Yadav , Alexander Graf , Evangelos Petrongonas , kexec@lists.infradead.org Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org, Michal Clapinski Content-Type: text/plain; charset="UTF-8" While booting with KHO, the following crash was observed: BUG: unable to handle page fault for address: ff19164fffff8328 RIP: 0010:__free_one_page+0x1a1/0x6b0 Call Trace: [] free_one_page+0xaf/0x240 [] deferred_free_pages+0xa8/0xd0 [] deferred_init_memmap_chunk+0x10f/0x1b0 [] padata_mt_helper+0x65/0xa0 [] process_scheduled_works+0x202/0x410 [] worker_thread+0x1f9/0x2d0 [] kthread+0x27d/0x2f0 [] ? __pfx_worker_thread+0x10/0x10 [] ? __pfx_kthread+0x10/0x10 [] ret_from_fork+0x145/0x280 [] ? __pfx_kthread+0x10/0x10 [] ret_from_fork_asm+0x1a/0x30 deferred_init_memmap_chunk() interleaves initialization of struct pages with freeing them. This works fine without KHO because free regions will never be neighbors. However, with KHO, free memory will be split into (free && scratch) and (free && !scratch), which can be neighbors. KHO scratch is aligned to CMA_MIN_ALIGNMENT_PAGES pages but buddy looks at the neighborhood of MAX_ORDER_NR_PAGES pages. These values are configurable but CMA_MIN_ALIGNMENT_PAGES is always less or equal to MAX_ORDER_NR_PAGES. In the crashing configuration they were set as follows: CMA_MIN_ALIGNMENT_PAGES = 1 << 9 MAX_ORDER_NR_PAGES = 1 << 10 So while freeing one chunk, buddy accessed uninitialized struct pages from another chunk, tried to merge the blocks and crashed. To fix this, let's just align KHO scratch to MAX_ORDER_NR_PAGES pages. Fixes: c6073743d0c7 ("kho: make preserved pages compatible with deferred struct page init") Signed-off-by: Michal Clapinski --- Unfortunately, this is very hard to catch, so I don't have a good reproducer. But I run the code with the fix through extensive testing and it seems fine. I think I've never caught it before because enabling HUGETLB is what causes CMA_MIN_ALIGNMENT_PAGES to be 1 << 9, instead of 1 << 10. If this passes review, please cherry-pick it to 7.2 so we don't release a broken kernel. --- kernel/liveupdate/kexec_handover.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c index 4834a809985a..175c08a6e41e 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -38,6 +38,16 @@ #include "../kexec_internal.h" #include "kexec_handover_internal.h" +/* + * This is the minimal alignment required by deferred struct page init. + * deferred_init_memmap_chunk frees memory to the buddy allocator, which looks + * at the neighboring pages (up to MAX_PAGE_ORDER) to merge them. + * If KHO scratch is not aligned to that value, buddy can access uninitialized + * struct pages, which can cause a crash. + */ +#define SCRATCH_ALIGNMENT_BYTES (PAGE_SIZE * MAX_ORDER_NR_PAGES) +static_assert(SCRATCH_ALIGNMENT_BYTES >= CMA_MIN_ALIGNMENT_BYTES); + /* The magic token for preserved pages */ #define KHO_PAGE_MAGIC 0x4b484f50U /* ASCII for 'KHOP' */ @@ -640,8 +650,8 @@ static void __init scratch_size_update(void) * Scratch areas are released as MIGRATE_CMA. Round them up to the right * size. */ - scratch_size_lowmem = round_up(scratch_size_lowmem, CMA_MIN_ALIGNMENT_BYTES); - scratch_size_global = round_up(scratch_size_global, CMA_MIN_ALIGNMENT_BYTES); + scratch_size_lowmem = round_up(scratch_size_lowmem, SCRATCH_ALIGNMENT_BYTES); + scratch_size_global = round_up(scratch_size_global, SCRATCH_ALIGNMENT_BYTES); } static phys_addr_t __init scratch_size_node(int nid) @@ -656,7 +666,7 @@ static phys_addr_t __init scratch_size_node(int nid) size = scratch_size_pernode; } - return round_up(size, CMA_MIN_ALIGNMENT_BYTES); + return round_up(size, SCRATCH_ALIGNMENT_BYTES); } /** @@ -692,7 +702,7 @@ static void __init kho_reserve_scratch(void) * next kernel */ size = scratch_size_lowmem; - addr = memblock_phys_alloc_range(size, CMA_MIN_ALIGNMENT_BYTES, 0, + addr = memblock_phys_alloc_range(size, SCRATCH_ALIGNMENT_BYTES, 0, ARCH_LOW_ADDRESS_LIMIT); if (!addr) { pr_err("Failed to reserve lowmem scratch buffer\n"); @@ -705,7 +715,7 @@ static void __init kho_reserve_scratch(void) /* reserve large contiguous area for allocations without nid */ size = scratch_size_global; - addr = memblock_phys_alloc(size, CMA_MIN_ALIGNMENT_BYTES); + addr = memblock_phys_alloc(size, SCRATCH_ALIGNMENT_BYTES); if (!addr) { pr_err("Failed to reserve global scratch buffer\n"); goto err_free_scratch_areas; @@ -721,7 +731,7 @@ static void __init kho_reserve_scratch(void) */ for_each_node_state(nid, N_MEMORY) { size = scratch_size_node(nid); - addr = memblock_alloc_range_nid(size, CMA_MIN_ALIGNMENT_BYTES, + addr = memblock_alloc_range_nid(size, SCRATCH_ALIGNMENT_BYTES, 0, MEMBLOCK_ALLOC_ACCESSIBLE, nid, true); if (!addr) { -- 2.55.0.229.g6434b31f56-goog