From nobody Mon Feb 9 19:40:57 2026 Received: from mail-ot1-f50.google.com (mail-ot1-f50.google.com [209.85.210.50]) (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 0819E2C0260 for ; Fri, 30 Jan 2026 13:49:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=209.85.210.50 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769780956; cv=pass; b=aJL4LqgJiT6rSuB/01jM2m90XZfegCY8/wBHubx2Ly/yh8KcPekV3Es1w8fjo8FTK0l3T7PC91XP/SZpVawScYX1iePQKGaEBBFeUirHTBQKYbfSfgorUYOR5/SqeRLbm/cXIPE71o7B7lbLBp1wm1M+gt11RwOwB1LVeAgLdL0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769780956; c=relaxed/simple; bh=z2LjBGZVXRPB/+5JtvZQ5TNsN2oZiVR/etnhnHUiKts=; h=MIME-Version:From:Date:Message-ID:Subject:To:Cc:Content-Type; b=ErpBmbctcWmi6B+NLLLehIiZg6rh5X7agJBrryg1TmSGTgpryqyULCZjHGR0ue1+3gxhZntznjzPYCBTTuzvbr6sVljh/WUFOubj716S2RynB6+V9ow2R8bgAYegN74sFiBElgyXxiuTzNXpCFNEEnkepm8Gr1nrkVwkxPXEL9g= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=nnIDXVBs; arc=pass smtp.client-ip=209.85.210.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="nnIDXVBs" Received: by mail-ot1-f50.google.com with SMTP id 46e09a7af769-7cfd65ea639so1340908a34.0 for ; Fri, 30 Jan 2026 05:49:14 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1769780954; cv=none; d=google.com; s=arc-20240605; b=CWrQQk311ioi8/Mp9JoikeK5b9pKbDZuex7LAeHg4AnWOnZKUNesdL0hIEhT/Tu4pK dwPkemRSw6aDa7X1DonwDbWPtbHlpGka7gU58B7uZblNDNrYZ2UfobfMNUiDa6t2XzTe zrrUC24RIXjqhCkeUD1cyifx8g8aBxihWfwUTvKMPVR/6wElErN0f0Bit0Aq9XIPsyde pgaAtz1mFiyutogUMs7KKGpYvTGwWLvc2M1FuKvqKqMSVPcA0LHO0vfIErmu/1vpopyc Tkjv9dRgoSx1hrFULHs5nCdeVg532L8l17/OQs9ZodZSrRkJd02ovJU5VaIT9CfNXeI/ WUMw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:mime-version:dkim-signature; bh=Xt8oCbrH9okAjKUrPiZSoeA6LFAs2r1CjMNwP+aJ+Pw=; fh=HJeANdDJIy7phYX+a7ajN7K/k8lfJMJkp6GjmALtRUM=; b=lWvcqM0Ojtgd/aYbq7hCy9Mq79wMZzu18AjctrNw//orrUMUI2hrmXatR6z5biJppA nQwgwvWJREVjulMQ1d/0gjjcow/L30JF2IgTHvogVHJwpT/nIt9Fl0Q09CrJcJcczjQE ts6QEIt2cnisNQne3wVwVZV+8ci/HeX/783FrGd0G9mrLDafpRAMbYWGH0WSXgx/C3JO LSMcXlX4GUgmaRWGgFX04+OZlXJUk9N8Upm8a4EjVJpk+9dHGmrki7FEL1YuWGuhSn7E ZEdsXWO6yGO5t+QBDg391fok2YKvIb63dpmSPjv/Bt17PymChnbYUEpbhLbetSDoVDVF DeiA==; darn=vger.kernel.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1769780954; x=1770385754; darn=vger.kernel.org; h=cc:to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=Xt8oCbrH9okAjKUrPiZSoeA6LFAs2r1CjMNwP+aJ+Pw=; b=nnIDXVBsQimlFeZc6FjGxv3qn/5vdtWALbSRT/2oMDyMpmpmF4Nsw9qSkS/Vy9k2tM G3clw1DiWOCmkNe17h0JgjjZ63sntieuZkv3R9+T3/zrzEonLtgTyNupMnv6VS/3FoLZ lVXz7P24OPz4ht6haTDI3dE8nAKjxXJv3h4g3Ha9Imuk/MdLRV9T206gKc3bG0iaL6zv a01zABiYnJeHDfrELFpVQ4zXEawS/3czIsruM3ZqB3bDcAuXAEUHm9EZuGNI2om55Wuh R7M4F7/jFucKjqx0Y68LTf01rP+5t9emfycv32bjjsOKOo19AkFw8J/4aaOUPGHrIA1e +M1g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769780954; x=1770385754; h=cc:to:subject:message-id:date:from:mime-version:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Xt8oCbrH9okAjKUrPiZSoeA6LFAs2r1CjMNwP+aJ+Pw=; b=Pdrd0dQv3A54WA0SnCehkFo6q8dnTrOHAAIkPEtMgsYKDt1RyJevVWvC4OSOVqehit j3abdbCZ+DgUHhZEBBbZ5lxdmrlePfriNMTWSqck3/6YSzx6foqtrMOix1UEhS6o/43S kEs2IdyYgPOF30ANH/ZKWIF4IUpdQsCK3hQnR9FVuzwHSRrSxlRFvzw74B9DdaUax340 vmWG4x2De8MR15OhMLxWvhO1+wUe/PioNOR1NKIM6OhtsJh8UeXLvztNIZgvrRGE2O6M Fr4VVkhI+trwbcF89pydBIeQVJpnG8y5vexekpNjg3/PluKuQCyiBj6SiMd6opKXar7a o+dA== X-Forwarded-Encrypted: i=1; AJvYcCUhyZuDEc3AiIRTT6cHXA0gJmmlHlfJa1G3ZBENsJjgTdZ1pk9BVhNqONsSGMq/3+25cyGr6CsFFU0Wbes=@vger.kernel.org X-Gm-Message-State: AOJu0YwAz27Vjpwbdtp7rEnxCahXfbqkH/RI5Y3VHrnvr5ZGxEbK97rw IKjDxJ9vkmneJvg6djLFmAGzYdh5A23C1+54UYuTXIYe04WvqQasrkR0/I0RHXeK+rJfzuZ9uVh LIivTTCTkfAEEO5PMoGAWRICAJA2B4No= X-Gm-Gg: AZuq6aKl/U/6QIvRUUTPrPRwaAnFULg+bOHfbfI4JLwJ3ZWASJ90OM4Bgg7YJ3QjMOh 8dWh4jXK3zi46ntqJqLGPXm/iTb1OGnUoaBT9dJVZtFA352pglDi0AwHn81copx7SgAT/nyDk7+ hyLLLJd3NOUCe2xn4rS0A+s1TJUMGiRSEexVL0fX6ADI0wpgv+ul2e8JPwYMB/fT2m5xVNff6C8 K9zlJfMi/NBK30uXdeZR8XfVr8zOXVL0VjSQK/DWbQYgs0Fu8QN35drGAuw8QdaoqKlPJ1SAA== X-Received: by 2002:a05:6830:6517:b0:7c7:471:55ff with SMTP id 46e09a7af769-7d1a52ccbc5mr2041628a34.10.1769780953663; Fri, 30 Jan 2026 05:49:13 -0800 (PST) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Mikhail Gavrilov Date: Fri, 30 Jan 2026 18:49:00 +0500 X-Gm-Features: AZwV_QiAk9It0ObCVuiEkeuO_Q6itWeKLvxgAKgEWxUFdAWF4LnAoAqeZfwVzVg Message-ID: Subject: [RFC PATCH] mm/page_alloc: fix use-after-free in swap due to stale page data after split_page() To: Linux Memory Management List , Linux List Kernel Mailing Cc: Andrew Morton , Vlastimil Babka , chrisl@kernel.org, kasong@tencent.com, Hugh Dickins Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Hi, I've been debugging a use-after-free bug in the swap subsystem that manifes= ts as a crash in free_swap_count_continuations() during swapoff on zram device= s. =3D=3D Problem =3D=3D KASAN reports wild-memory-access at address 0xdead000000000100 (LIST_POISON= 1): Oops: general protection fault, probably for non-canonical address 0xfbd59c0000000020 KASAN: maybe wild-memory-access in range [0xdead000000000100-0xdead000000000107] RIP: 0010:__do_sys_swapoff+0x1151/0x1860 RBP: dead0000000000f8 R13: dead000000000100 The crash occurs when free_swap_count_continuations() iterates over a list_head containing LIST_POISON values from a previous list_del(). =3D=3D Root Cause =3D=3D The swap subsystem uses vmalloc_to_page() to get struct page pointers for the swap_map array, then uses page->private and page->lru for swap count continuation lists. When vmalloc allocates high-order pages without __GFP_COMP and splits them via split_page(), the resulting pages may contain stale data: 1. post_alloc_hook() only clears page->private for the head page (page[0]) 2. split_page() only calls set_page_refcounted() for tail pages 3. Tail pages retain whatever was in page->private and page->lru from previous use - including LIST_POISON values from prior list_del() calls In add_swap_count_continuation() (mm/swapfile.c): if (!page_private(head)) { INIT_LIST_HEAD(&head->lru); set_page_private(head, SWP_CONTINUED); } If head is a vmalloc tail page with stale non-zero page->private, the INIT_LIST_HEAD is skipped, leaving page->lru with poison values. When free_swap_count_continuations() later iterates this list, it crashes. The comment at line 3862 says "Page allocation does not initialize the page's lru field, but it does always reset its private field" - this assumption is incorrect for vmalloc pages obtained via split_page(). =3D=3D Proposed Fix =3D=3D Initialize page->private and page->lru for all pages in split_page(). This matches the documented expectation in mm/vmalloc.c: "High-order allocations must be able to be treated as independent small pages by callers... Some drivers do their own refcounting on vmalloc_to_page() pages, some use page->mapping, page->lru, etc." --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -3122,6 +3122,16 @@ void split_page(struct page *page, unsigned int orde= r) VM_BUG_ON_PAGE(PageCompound(page), page); VM_BUG_ON_PAGE(!page_count(page), page); + /* + * Split pages may contain stale data from previous use. Initialize + * page->private and page->lru which may have LIST_POISON values. + */ + INIT_LIST_HEAD(&page->lru); + for (i =3D 1; i < (1 << order); i++) { + set_page_private(page + i, 0); + INIT_LIST_HEAD(&page[i].lru); + } + for (i =3D 1; i < (1 << order); i++) set_page_refcounted(page + i); split_page_owner(page, order, 0); =3D=3D Testing =3D=3D Reproduced with a stress test cycling swapon/swapoff on 8GB zram under memory pressure: - Without patch: crash within ~50 iterations - With patch: 1154+ iterations, no crash The bug was originally discovered on Fedora 44 with kernel 6.19.0-rc7 during normal system shutdown after extended use. =3D=3D Questions =3D=3D 1. Is split_page() the right place for this fix, or should the swap code be more defensive about uninitialized vmalloc pages? 2. Should prep_new_page()/post_alloc_hook() initialize all pages in high-order allocations, not just the head? 3. Are there other fields besides page->private and page->lru that callers of split_page() might expect to be initialized? Thoughts? --=20 Best Regards, Mike Gavrilov.