From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pl1-f174.google.com (mail-pl1-f174.google.com [209.85.214.174]) (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 A1AB03B19D5 for ; Mon, 10 Aug 2026 09:45:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.174 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786355124; cv=none; b=QUuM7IOevV0ehpzfGyqRwlPOhSaYlOyEv39uGVtAGFHUmFcOu8A9HYPzHl+zcYPcBFPhaY2Ubx9X2VNX3BNheMgAajAii/FUPyo+ERhvkbU9lmPSOsLgJLwju0uJcMO3Xi42Vsm/OTEAajW/v/EPJHLnBCsOIJ0Tp10CpuiSoLM= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786355124; c=relaxed/simple; bh=V8cN7PW00Vo2LeM2gs8vrM3r/U3rRLNF0k0eC8Vf7xo=; h=Date:From:To:Cc:Subject:Message-ID:MIME-Version:Content-Type: Content-Disposition; b=sLOskn4W2J5ol+kiTYAeYTQK+OY/O1HAuih0Qtii0bIqZP9GhLUdBdk45IUZ3K2e4jti1wgev18DQe7EEa+dYnTC+6je1A0V3q3fyQw5dcbzys3vlkpzfaYeLli15HL89xHEwzq5cxMAC9wKM0LRvmCsfjzbGH9iDtUCB7dbFYY= ARC-Authentication-Results:i=1; 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=H361FhSv; arc=none smtp.client-ip=209.85.214.174 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="H361FhSv" Received: by mail-pl1-f174.google.com with SMTP id d9443c01a7336-2caf228a910so12066325ad.2 for ; Mon, 10 Aug 2026 02:45:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786355122; x=1786959922; darn=vger.kernel.org; h=content-disposition:content-type:mime-version:message-id:subject:cc :to:from:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=dNGakf2M6oPelBo3WH3aqKoEk48xxZj317kKXaenRIw=; b=H361FhSvAMBqYjQn2DovUHosksEO4pnTed6WcZQfnHxZ/7DbxXmqUEwC1qjm3xY/Ke /mqioFTt6qcyKZs56uO8Fb+PcacqVRAFrEtujHdyfFzpEOHFHlXHTYGSAJhXi+FVuszB ucDBxA5OQW6ew+q/TNqGNE4PLcW93Qt8c/aeFGPoB6c1sYU4IHJBslnj7bCXsYn8YGcQ xN8++mPFEO6kL+h5NU+UIe5SjB0kAmLpM4Dqjl3HNkO45C3Z3eDQP3jOj63bIiLf+aVu J8F8srXB208wlyOieNMFsHn11cG+V0mSPTlSLwBCKf+f/y8nZInjGO2TTfiqEois0xTT +w6g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786355122; x=1786959922; h=content-disposition:content-type:mime-version:message-id:subject:cc :to:from:date:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=dNGakf2M6oPelBo3WH3aqKoEk48xxZj317kKXaenRIw=; b=XASAJNctxNQxuXzD9HFL8p3b+EoHPXo65KRFL4Gav+ozSrr3DbKYAOaZOhO0JK1n2X V+yIz6FnZy6RV/tmJqXJNmSGzJoyiHe68IvSWKAsXqe3CL3eYYSudePCLdSBNFKhFxxd DsgGNrSaflS9TwKf3w/vLGTGCnF5hw2Yeyx0tzs8c8bQy6vKBNL3UcnqjhjPjVK4+uNd Ed8pMWUcZCmui6MF7l55SyYDGu6E02xSNmbOnHU9qjemCeYbGigaHF6ixRv+leihn5vJ jY6IsJm6+VwpmUp8o0L+cicBv/LUiyyG0BEUOptCpjOYTUJUQSqIhvEeiWSKhnzPh479 McNg== X-Forwarded-Encrypted: i=1; AHgh+Rr5mUw4NrDyAIHmpvfgjQgW64XVxghzmMhFRj3Oq49FW6pj/++NIeNGCShLdj+JtL78z/11jTNejM9yeVE=@vger.kernel.org X-Gm-Message-State: AOJu0YwvmSa9+hHJQxf9M8ZLw2T3Zoh9VqPTT7s+5eECLNpeMlFqbV9X Ixn0A6gay0cDSbkhrOCUA7iYmWjtQ4OztZ+DGR2TAa9vMNtJm/f9Wz/6 X-Gm-Gg: AR+sD10YEt6cCttzGkW5aTDw6VZmrpggcPcJhToQKTTgpsOHbS3lkY62ZPcx0MkJz1B C7xh1zWY3HFBR30iSbwKS4kFJkRmFYfqEyLfrGr364xooRX7aMXrT5kVcvpdHHCwY7G7Px1mW43 90HnsYnSTywDell/FraxF2xsUuRxRszhadt0ND8i9OYHKnA2x8/bIDItCbk3hlrqa/1qQjQydgP OAjiEa6vLXWnKzbqAsu3sI/b2EN6TMt2HRkxe+0zGJcwtue4Bq9DGx6YI+YJ8lw1go9s7Zn9X/n 9/plh3c/gMg4gYcjJqRVTZs9vANW/C8ONNxehGptxp1pyr1rD6r1LyN3wqzJtYXIk9mVpc5tu0N HPRm90XX/mwZA79WgoE0z9FbEKUia0SBVFNzfNpOVAZs8EjbjwGepn8ZVKuxl3wmAj6lT+P5aKx i8cLX5og5szHAZLBXq3iRljtuPl/7rDgGxtarDI/KA5uZ/9V1/xaJh/CsKkoSfFmftgtgZJogYh FfUY5cv X-Received: by 2002:a17:902:fda5:b0:2cf:82e6:a5 with SMTP id d9443c01a7336-2d2a8d3b8d6mr245246815ad.13.1786355121841; Mon, 10 Aug 2026 02:45:21 -0700 (PDT) Received: from v4bel ([58.123.110.97]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2d14da67e21sm31904325ad.37.2026.08.10.02.45.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 10 Aug 2026 02:45:21 -0700 (PDT) Date: Mon, 10 Aug 2026 18:45:17 +0900 From: Hyunwoo Kim To: akpm@linux-foundation.org, david@kernel.org, ljs@kernel.org, liam@infradead.org, vbabka@kernel.org, rppt@kernel.org, surenb@google.com, mhocko@suse.com Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org, imv4bel@gmail.com Subject: [PATCH] mm/pagewalk: fix stale walk->action escaping walk_pmd_range() Message-ID: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline walk_pmd_range() resets walk->action in only one place in its loop body, and that place is after the pmd_none() branch. For a walker with no ->install_pte, that branch continues to the next entry without passing the reset. So if ->pmd_entry() sets ACTION_AGAIN and returns 0, and the PMD has become none by the time the loop restarts at the again label, the reset is skipped. If the remaining entries are all none too, the loop returns 0 with ACTION_AGAIN still set. The ACTION_AGAIN that walk_pte_range() sets when pte_offset_map_lock() fails escapes the same way. Nothing looked at that value after walk_pmd_range() returned until commit 3b89863c3fa4 ("mm/pagewalk: fix race between concurrent split and refault") turned that into a problem. It added both the PUD check that sets ACTION_AGAIN before the loop is entered and the test in walk_pud_range() that picks the value up right after walk_pmd_range() returns and walks [addr, pud_addr_end(addr, end)) again. That is fine for the PUD check, since none of walk_pmd_range()'s own callbacks have run at that point, but a value that escaped as described above arrives after those callbacks have already covered the range. For mincore(2) this becomes an out-of-bounds write. ->pmd_entry() and ->pte_hole() advance the walk->private cursor by one byte per page, the buffer is a single page from __get_free_page(), and mincore(2) asks for at most PAGE_SIZE entries at a time, so there is no room to spare. Walking the range a second time pushes the cursor past the end of the buffer, and it does so again every time the race is hit. Reproducing this needs no privileges: run mincore(2) over a 16 MiB anonymous mapping marked MADV_NOHUGEPAGE while another thread repeatedly faults in a PMD-aligned 2 MiB range inside it and then drops it with madvise(MADV_DONTNEED). Move the reset to the first statement of the loop body. walk_pud_range() has the same shape and gets the same change; walk_p4d_range() never looks at walk->action, so that hunk keeps the two functions in sync rather than fixing a second bug. Fixes: 3b89863c3fa4 ("mm/pagewalk: fix race between concurrent split and refault") Cc: stable@vger.kernel.org Signed-off-by: Hyunwoo Kim --- mm/pagewalk.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mm/pagewalk.c b/mm/pagewalk.c index 5d87c632a25507..d3bfece3193366 100644 --- a/mm/pagewalk.c +++ b/mm/pagewalk.c @@ -126,6 +126,7 @@ static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end, pmd = pmd_offset(pud, addr); do { again: + walk->action = ACTION_SUBTREE; next = pmd_addr_end(addr, end); if (pmd_none(*pmd)) { if (has_install) @@ -138,8 +139,6 @@ static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end, continue; } - walk->action = ACTION_SUBTREE; - /* * This implies that each ->pmd_entry() handler * needs to know about pmd_trans_huge() pmds @@ -196,6 +195,7 @@ static int walk_pud_range(p4d_t *p4d, unsigned long addr, unsigned long end, pud = pud_offset(p4d, addr); do { again: + walk->action = ACTION_SUBTREE; next = pud_addr_end(addr, end); if (pud_none(*pud)) { if (has_install) @@ -208,8 +208,6 @@ static int walk_pud_range(p4d_t *p4d, unsigned long addr, unsigned long end, continue; } - walk->action = ACTION_SUBTREE; - if (ops->pud_entry) err = ops->pud_entry(pud, addr, next, walk); if (err) -- 2.43.0