From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pg1-f177.google.com (mail-pg1-f177.google.com [209.85.215.177]) (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 A2371386552 for ; Mon, 27 Jul 2026 14:35:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.177 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785162917; cv=none; b=HqIa6YB2ux2A2WLcbV9TbXJYUZ+MRqiSa+axUKJ5sxNAnWnriSut2gOhoF+Q50rs1Z/nPGeF6m6sHm5gM/MymLavMu/aWByUY+EDpoOOnre1L9Pz4Jqe9XL7/lL121uoU6JTYSPEQ21b8hdB6XYRL4R16TpLq/Tg52oZm94Tkj0= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785162917; c=relaxed/simple; bh=BkhvyAl41lLtYiFI8zJ9qADiaAA2a0URAAzIw0G5FzI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=o3Vl4hvX8ymQCWbXSONn4fGp0i9Yb1DWU38uTciqugtiPZjqdMWocn64bOCd4X1e9B85ixNCDQefSRGGNg98Qd9jht6i0b+ytN/QRmDJdiEPSqjCCE7idgz/eprs95g7lr9GTXOsSj8iPRHlSo/mu7LOqtvUjf9icbeQ1Ki2vAg= 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=hm7Jaftw; arc=none smtp.client-ip=209.85.215.177 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="hm7Jaftw" Received: by mail-pg1-f177.google.com with SMTP id 41be03b00d2f7-ca132e9c54aso231572a12.3 for ; Mon, 27 Jul 2026 07:35:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785162915; x=1785767715; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=NM59zTITSAnSgD8fALdagpl6xYMLVePtK5I+sk28JTE=; b=hm7JaftwtEdANXVl3FX8fPrWioDAEns/3e1UrU57OuaEB13oPbp0YBtM1MOozP5K8k fHUDjdw/D8luaPlC2yJgs8hyMnkN/NN3uuSwQmeU5VtLkYX1doTGaOWM0BaGMEUv1ypf 9lnkFeU/H+5qjLH29eyK0xqfhdxVTO271fgH8hYxkd3ggpen9osv5GqafLVMjATDn7Uy Lo7vpd80h+GjSloJJ0/IfWNT8YwYJiMCEz6haxaaCc6f6JCQWEMFS5NRlAYrynqZBQDc P7HKZgmKBEQBDTtEPDSpmitNloUrVBNh9Ykv3J7OBzrMn+3f9W45YpLj5nfLXSxbWAN1 5VAg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785162915; x=1785767715; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=NM59zTITSAnSgD8fALdagpl6xYMLVePtK5I+sk28JTE=; b=BCeKE+5/tGfWqZgBkl5xpkwsPekwQP5gtUS9/7WybShk+BGJFUVZXCDndYuBcUIunn EzqAII0lHOD1djNVJ+NHlaIzYRRfbo17xxXt06lSXEAPjJUWyCzmCTuuW0fTGT5/LBC8 4j7BPOW1Kn2y8WcM/v1w3nht/6c0gB1zf1JMOTR4Do8mrOVUAKRDBkhC+6E+ijOcqaOh 5w8qcQ052iMiK1J36HpNHZPBeDMu+QueqdcENh+TvLwHyAHduev/4nQOPVZ08K/mvPyf VoxwacrMXAliFxwh25wd3NB+8hLtGDgtcnEFyNvbyd6VSn+ODhtSEEiLXrJf0mK8UELq H/lg== X-Gm-Message-State: AOJu0YysrRS4miz/GzaKPVacUqu+dtlJeqFibJyQU6squ1I50BAeRVfS DO/YO7mmgzMNBRq9N2CQV14uFmMsq6fpqSuJGE4ywzpDw1F8pdLPTddu X-Gm-Gg: AR+sD10ihAUHxTDT3I2RAJ3Tj6/uvVwJoOEsv4Oip2AT0OVFZYyRD6qQkebCGegBuKz oYXtRNDxTVGuRNx+HZnoIVT+OwRhKbzp11LvVL0w+WGkq4TDcsozgLyxVAvld4Yt85WABVFYLBB uJ5luB4TcoLDMVTOP9B/B1FWjx4V5DHN4NEEUUp4JRw/8M2f0Sj82Uw0znZaL+H4C1AzXm6WXfs csMEWb9ei6GZ+XXRLwZ9G7JLs3f1ooek3leheU3jH6wfzOLCqUht1cl2lbd/fVjzrVpNSHr4ngj PDT/DSSMs79u7LqgWeHDt82Ioj86FMr9bKjONuxNUtK+HORx2RJFNLgNiBAKLZFNUwjz/KO+0le GyXLgt8iMAJvOver6US9+JCErqZX4zvYrOnasMqxuEFCTbJ8T1uxOgUOfAv51Z1Y+KvuoYhLIvC IuiWhL4uucwSanny1hnPZUAQMkOccVVFNFuautc8h3fBL1TJr8x8vfXDVqwF6f2q1k5LOrfG6nQ gM= X-Received: by 2002:a17:902:f710:b0:2ca:d344:7743 with SMTP id d9443c01a7336-2d00baddaddmr3424865ad.7.1785162914572; Mon, 27 Jul 2026 07:35:14 -0700 (PDT) Received: from debian.lan ([141.11.42.65]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2cfde7d5297sm36877485ad.56.2026.07.27.07.35.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 27 Jul 2026 07:35:14 -0700 (PDT) From: Xueyuan Chen To: linux-mm@kvack.org, akpm@linux-foundation.org, david@kernel.org, ljs@kernel.org Cc: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, catalin.marinas@arm.com, will@kernel.org, tglx@kernel.org, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org, hpa@zytor.com, luto@kernel.org, peterz@infradead.org, lance.yang@linux.dev, usama.arif@linux.dev, jannh@google.com, yang@os.amperecomputing.com, rppt@kernel.org, ziy@nvidia.com, baolin.wang@linux.alibaba.com, liam@infradead.org, npache@redhat.com, ryan.roberts@arm.com, dev.jain@arm.com, baohua@kernel.org Subject: [PATCH v5 1/3] mm: make persistent huge zero folio read-only Date: Mon, 27 Jul 2026 22:34:24 +0800 Message-ID: <20260727143426.1077133-2-xueyuan.chen21@gmail.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260727143426.1077133-1-xueyuan.chen21@gmail.com> References: <20260727143426.1077133-1-xueyuan.chen21@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit The persistent huge zero folio is shared globally and should stay zero after initialization. As Jann Horn pointed out[1], kernel bugs have ended up writing to pages that were meant to be read-only, including in security-sensitive cases. Making the persistent huge zero folio read-only in the direct map turns such writes into faults instead of silent zero-page corruption. Add set_direct_map_ro_noflush() so mm code can make a direct-map range read-only. Use an address-based signature to match ongoing direct-map helper work[2], where existing page-based helpers may move the same way. The helper is direct-map specific and leaves TLB invalidation to its caller. Architectures without direct-map permission support keep existing behavior through the generic stub. The folio is allocated and zeroed through the writable direct map before thp_shrinker_init() changes its permissions. thp_shrinker_init() is called from hugepage_init(), which is registered as a subsys_initcall and runs after SMP initialization. Stale writable kernel TLB entries may therefore exist. Flush the direct-map range immediately after the page-table update so they cannot bypass the read-only mapping. Treat the direct-map permission change as best-effort. Architectures that do not implement the helper keep the existing behavior via the generic stub. Inspired by Jann Horn's read-only zero page work[1] and follow-up discussion[3] with Yang Shi. [1] https://lore.kernel.org/linux-mm/20260508-ro-zeropage-v1-1-9808abc20b49@google.com/ [2] https://lore.kernel.org/linux-mm/0e5b23a6-4895-454a-9dfa-6dc21adc2991@kernel.org/ [3] https://lore.kernel.org/linux-mm/CAHbLzkrXXe7r3n3jXgDKtwZhRqj=jDx9E6dLOULohnhBguvi9A@mail.gmail.com/ Suggested-by: David Hildenbrand Suggested-by: Usama Arif Co-developed-by: Lance Yang Signed-off-by: Lance Yang Signed-off-by: Xueyuan Chen --- include/linux/set_memory.h | 29 +++++++++++++++++++++++++++++ mm/huge_memory.c | 16 +++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/include/linux/set_memory.h b/include/linux/set_memory.h index 3030d9245f5a..e83ced6a3827 100644 --- a/include/linux/set_memory.h +++ b/include/linux/set_memory.h @@ -40,6 +40,24 @@ static inline int set_direct_map_valid_noflush(struct page *page, return 0; } +/** + * set_direct_map_ro_noflush - make a direct-map range read-only + * @addr: start address in the direct map + * @nr_pages: number of pages starting at @addr + * + * Make the direct-map range starting at @addr read-only without invalidating + * TLBs. Callers must either ensure that no stale writable translations can + * be used, or treat the permission change as a best-effort hardening step. + * + * Return: 0 on success or when direct-map permission changes are unsupported, + * or a negative errno on failure. + */ +static inline int set_direct_map_ro_noflush(const void *addr, + unsigned long nr_pages) +{ + return 0; +} + static inline bool kernel_page_present(struct page *page) { return true; @@ -56,6 +74,17 @@ static inline bool can_set_direct_map(void) } #define can_set_direct_map can_set_direct_map #endif + +#ifndef set_direct_map_ro_noflush +/* See the comment above the generic fallback for the _noflush contract. */ +static inline int set_direct_map_ro_noflush(const void *addr, + unsigned long nr_pages) +{ + return 0; +} + +#define set_direct_map_ro_noflush set_direct_map_ro_noflush +#endif #endif /* CONFIG_ARCH_HAS_SET_DIRECT_MAP */ #ifdef CONFIG_X86_64 diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 970e077019b7..4425ae5560cb 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -40,8 +40,10 @@ #include #include #include +#include #include +#include #include "internal.h" #include "swap.h" @@ -932,6 +934,8 @@ static int __init thp_shrinker_init(void) shrinker_register(deferred_split_shrinker); if (IS_ENABLED(CONFIG_PERSISTENT_HUGE_ZERO_FOLIO)) { + unsigned long addr; + /* * Bump the reference of the huge_zero_folio and do not * initialize the shrinker. @@ -940,8 +944,18 @@ static int __init thp_shrinker_init(void) * that get_huge_zero_folio() will most likely not fail as * thp_shrinker_init() is invoked early on during boot. */ - if (!get_huge_zero_folio()) + if (!get_huge_zero_folio()) { pr_warn("Allocating persistent huge zero folio failed\n"); + return 0; + } + + addr = (unsigned long)folio_address(huge_zero_folio); + /* + * The folio was zeroed through the writable direct map. Flush + * after the page-table update to invalidate stale translations. + */ + set_direct_map_ro_noflush((void *)addr, HPAGE_PMD_NR); + flush_tlb_kernel_range(addr, addr + HPAGE_PMD_SIZE); return 0; } -- 2.47.3