From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794590403; b=eFBVoNzSUm2Wx7sfu64iW3Bb2u9JbbO3dwjxWO5MSpvL8thI46Hxjvi52kIdraNmxf6Z F7Ot3Sqfpj90EdV82k6mTxbe0RlTNtOW54C1zfpWrwGdrY0XyOxPm5X6lRvXEXVOm1qd3 K3EcvuMAnbl8u9EYiOhkssH7KIPq6EFrNqfHiWnNhDsuRMoqEkZNbtl1qMEY4VDu7kf/f k7+N4ro8gV8BMSMiEsqRHiFXncl/msEfGU+ubMkPWmfsu5LB1vE0LQYfqVadtrJZ2FGFK 6YFuOmtEcAf4I480eC8bP23apkzdhSl9FFrbBVwNmmPWZCcPP5/9oPtFQd6MS9FPD1Q== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794590403; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:User-Agent:X-stable:X-Patchwork-Hint: MIME-Version:Content-Type:Content-Transfer-Encoding; bh=DyjI6S26vjEXH1HyV3UA03pSPa4Neh1BzIDL6WCjLmc=; b=HyC4pUKaMc40NweU0jGt6Bm005YL/JjqEvJ4t3+7TLPY30hcbqDXjKp8L+WYyFDjpVim DQ1pwVLdgRZaBMFMj/eYO1v1k0dGDfpauj+SFZN+voxnlPJtf2O7McHbQmrONbqZH58sM o4ZuuBR0Y5BCaB6EXAF/Sn42AxzZXQdaKx6x9gNMz6s3/NI9dW0boyc0Rc6zrvodkaohC hMYnD+ctQ5mQvoWgeJ9TqLMwJspd+J7LYYnM6tTJjhDv9wuRoy1wDD9fz/jDL849hq5ob aIz0YHQyH0J60BuHkrOj0u5rwAh69EXebMOdd2AgqXgLu+QqbuYaD5TfHxflvZJf/5A== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=MwgE6ki9; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7662B606B451; Fri, 13 Nov 2026 17:20:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=MwgE6ki9 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1DF351F000C7; Fri, 13 Nov 2026 17:20:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1794590403; bh=DyjI6S26vjEXH1HyV3UA03pSPa4Neh1BzIDL6WCjLmc=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=MwgE6ki9vCZ7Qzx4JsjBnBG0oF5728n3rJ/IDZC/shnykOvhv8SYa5cYPEqhXyA8F y6ZJ+OSdM20EROzNgfUHiE8WLvVnCJdF8KUTA7ZAWmMPKu+9e7cwLds1E4jsMoZwcz azM/OXmIQb1iUuEdoeF3rMePlNQ/1JluI9lIMWOE= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Yafang Shao , Andrew Morton , Zi Yan , "David Hildenbrand (Arm)" , Ying Huang , Matthew Wilcox , Matthew Brost , Joshua Hahn , Byungchul Park , Gregory Price , Alistair Popple , Sasha Levin Subject: [PATCH 6.18 318/686] mm/migrate: snapshot the source nid before the misplaced migration Date: Fri, 13 Nov 2026 10:47:31 -0500 Message-ID: <20261113153831.712001075@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261113153820.902362109@linuxfoundation.org> References: <20261113153820.902362109@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore X-Mailing-List: patches@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 6.18-stable review patch. If anyone has any objections, please let me know. ------------------ From: Yafang Shao [ Upstream commit fe623a81ad9eddf10059b4e44bca0440d9120613 ] A successful migration frees the source folio before the promotion counter update, so the folio_nid() read there operates on a freed folio — which may already have been reallocated. It happens to work today, as Zi explained: : Strictly speaking, it can be seen as a benign UAF. It works, because : 1. folio->flags happens to be the same as page->flags, : 2. folio/page nid is stored in the ->flags and never changed. : : In memdesc world, after a folio is freed, I assume folio->flags would be : zeroed since struct folio is freed and calling folio_nid() on a freed : folio would give a bogus result (yeah, it can be mitigated by not : zeroing node field and each node has its own struct folio pool, but that : makes folio_nid() implementation dependent). and Matthew explained further: : once struct folio is separately allocated, it's a UAF. It could be : recycled to a different NID or maybe the slab containing the folio could : be freed (assuming we're not holding the RCU read lock at this point in : migration, and I don't see why we would be). A separate concern is memory hot-removal. With memory-tiering mode enabled, successful migration can release the source before the promotion-accounting folio_nid() read. If the task is preempted there, an otherwise-free source block can be offlined and removed first. On the x86 path, removal can unmap the source's vmemmap, so the later read can fault. The snapshot avoids that read. Link: https://lore.kernel.org/20261027021721.95781-1-laoar.shao@gmail.com Fixes: e39bb6be9f2b ("NUMA Balancing: add page promotion counter") Signed-off-by: Yafang Shao Signed-off-by: Andrew Morton Suggested-by: Zi Yan Suggested-by: Andrew Morton Acked-by: Zi Yan Acked-by: David Hildenbrand (Arm) Cc: Ying Huang Cc: Matthew Wilcox Cc: Matthew Brost Cc: Joshua Hahn Cc: Byungchul Park Cc: Gregory Price Cc: Alistair Popple Cc: Signed-off-by: Sasha Levin --- mm/migrate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/migrate.c b/mm/migrate.c index 0d2b327368073..2a5846a86baf8 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -2737,6 +2737,7 @@ int migrate_misplaced_folio(struct folio *folio, int node) pg_data_t *pgdat = NODE_DATA(node); int nr_remaining; unsigned int nr_succeeded; + int src_node = folio_nid(folio); LIST_HEAD(migratepages); struct mem_cgroup *memcg = get_mem_cgroup_from_folio(folio); struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); @@ -2751,7 +2752,7 @@ int migrate_misplaced_folio(struct folio *folio, int node) count_vm_numa_events(NUMA_PAGE_MIGRATE, nr_succeeded); count_memcg_events(memcg, NUMA_PAGE_MIGRATE, nr_succeeded); if ((sysctl_numa_balancing_mode & NUMA_BALANCING_MEMORY_TIERING) - && !node_is_toptier(folio_nid(folio)) + && !node_is_toptier(src_node) && node_is_toptier(node)) mod_lruvec_state(lruvec, PGPROMOTE_SUCCESS, nr_succeeded); } -- 2.53.0