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=1794585667; b=AOe1Guef0jzy6rqCLZwXerbCfvLZPen9nXqES+GFFdvneQ15xMgSTDHHOi/YjMlXk1UY wLqEAeRS49YCecMxtOJ1kg4/SH+ZZfEqpy5BKsZKh7E7YxoGfOXG6LVaY4z/4vc/Dps3a W9Nt9d2l/oWdIM42ODypql5gRytgA/O1+V0bj4OP6NER7Po256P3uilb3SrD83bxJNRGI kq7CHuDZXzZX+onUFj/0Tj6Ny78F2BbJY1fNthl2U2uIV73J8xBFSVyPDR8Cer6e60RTD +/JTFamDf5UEc9PC0ECLcJjpGiBrG4anJYL5MEYP0trfi21kvFNjouu8hX6Aks8Uq7A== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794585667; 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=7+zarlz1DZMRhQdjRnH5p1sQZgkQxkFNeHUIa5S55PU=; b=FIyGgyWYpvkjdDEq7yymqtQQAnMR+TsegKbuohhrzLt4xfFEMwR+VOLvORxLF4dcxF4c LSTAD8xCcEkcmfOZo3tNg9uH4idSbkA7sdG58qs6e423YJT2QCOf6yZRvCWvOgJKalgr7 /WuWMeM0wRNJLCsmUPCzEcOFxSl7i3cRMHXjrG+7DzeqncSFYLtrdRgXjWszhnhRSWyHX TWxuatcP5fdOlJPMdu5k9dBvtabYvLa6M7sd1B2KCUtMmCIvaKl0uCdFbO+KgaU9+dM7K Yzi25un8i7MzKlUNseoOnu6t6MUaIXoUs5Y8yKfNnjgwWDkU6NJ0YRA1VpQR3JutXHA== 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=s3gjAKaW; 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 055B5606B2F8; Fri, 13 Nov 2026 16:01:07 +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=s3gjAKaW Received: by smtp.kernel.org (Postfix) with ESMTPSA id A978D1F000C4; Fri, 13 Nov 2026 16:01:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1794585666; bh=7+zarlz1DZMRhQdjRnH5p1sQZgkQxkFNeHUIa5S55PU=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=s3gjAKaWeGKl42/Aqc3dbgBpMtvXyU9JprLQtotLGsNl4GUgF5eC5lJt8zE3Uasd0 fEVRz8M0ptDI79K2xV9OeDFVd/TSt3uKvtB4aJVLhcF9LUsUhqRoOoQxAdR+RhAr5I G5RxDPhnoYT0w3WTbZNXhYM0ow3+LTs1Inf0GVo0= 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 7.3 238/507] mm/migrate: snapshot the source nid before the misplaced migration Date: Fri, 13 Nov 2026 10:49:02 -0500 Message-ID: <20261113153802.678114792@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261113153753.358973689@linuxfoundation.org> References: <20261113153753.358973689@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 7.3-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 296f39a73d492..ee78577177d65 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -2757,6 +2757,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); @@ -2771,7 +2772,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