From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 9B676413225 for ; Wed, 27 May 2026 13:33:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779888788; cv=none; b=M+7BFvruHEkfhcqisGVwYyHrNgg+IC/f8tB4Nh0NfhFifO21fd6LwXEFnoz2TsXegkTD/WiiQhZ0zyXbhTw5NVm0RnNGm8sV5KImTUR1vnUSzUwnDRlH9so2br/jJz7QXFwWNuMz7QegOQrAv7qFpYBivELsyfvogkebHaaczbg= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779888788; c=relaxed/simple; bh=3ivWgqiUQpM5lpUukOrYmMpxiPpqwEREWe2J1ceJJyQ=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type; b=cPnNxVggsmLPjcvhnPI+NpNqAnsotVWTrS4T+YNQvDfMZtvTtSUrBhunqKT583ifxcpvZsZWUkXzvuVj/tjfigujl2Qfv5fM7tcG32rgK34Wy28SBxiY8cUYtF+Ru7RunJxa5hipRPEa+KlFjTRsJF2AL8lRrSuKLIHD2HnqFUU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=DS09TTNr; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="DS09TTNr" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id ABFD62D97; Wed, 27 May 2026 06:33:00 -0700 (PDT) Received: from [10.164.19.7] (unknown [10.164.19.7]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id B50A13F7D8; Wed, 27 May 2026 06:32:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1779888785; bh=3ivWgqiUQpM5lpUukOrYmMpxiPpqwEREWe2J1ceJJyQ=; h=Date:Subject:To:Cc:References:From:In-Reply-To:From; b=DS09TTNr6G4NjbjAXlLHBx2vUIEabRA7TZV/BDCQgkCNcsiYvXLIIen3LoIszH4I0 I+o57N2wxdUw2rfue4Qw03PT2fcV9LWeRF3FGViXYm0CyHoOnqTkHvkS7PdSPgZKNy V2AHs3nRZMnVjFppu6E4/k3ZV1W8cH28sq13xowo= Message-ID: Date: Wed, 27 May 2026 19:02:55 +0530 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [RFC PATCH 1/3] mm: make persistent huge zero folio read-only To: Xueyuan chen , akpm@linux-foundation.org, linux-mm@kvack.org Cc: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, x86@kernel.org, catalin.marinas@arm.com, will@kernel.org, tglx@kernel.org, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, hpa@zytor.com, david@kernel.org, ljs@kernel.org, ziy@nvidia.com, baolin.wang@linux.alibaba.com, ryan.roberts@arm.com, lance.yang@linux.dev, yang@os.amperecomputing.com, jannh@google.com References: <20260527035607.14919-1-xueyuan.chen21@gmail.com> <20260527035607.14919-2-xueyuan.chen21@gmail.com> Content-Language: en-US From: Dev Jain In-Reply-To: <20260527035607.14919-2-xueyuan.chen21@gmail.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit On 27/05/26 9:26 am, Xueyuan chen wrote: > From: Xueyuan Chen > > The huge zero folio is shared globally, and its contents should never > change after initialization. As Jann Horn pointed out[1], the kernel has > had bugs, including security bugs, where read-only pages were later written > to. If the huge zero folio is read-only in the direct map, such writes > fault instead of silently corrupting shared zero contents. > > For the persistent huge zero folio, set this up once after the folio is > allocated at boot. > > The permission change is best-effort. If the architecture cannot safely > make the direct map read-only, keep using the writable persistent huge zero > folio. > > While at it, mark the huge_zero_folio pointer itself __ro_after_init. > READONLY_HUGE_ZERO_FOLIO depends on PERSISTENT_HUGE_ZERO_FOLIO, so the > pointer is initialized during boot and never replaced. > > This was inspired by Jann Horn's read-only zero page work[1] and follow-up > discussion[2] 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/CAHbLzkrXXe7r3n3jXgDKtwZhRqj=jDx9E6dLOULohnhBguvi9A@mail.gmail.com/ > > Co-developed-by: Lance Yang > Signed-off-by: Lance Yang > Signed-off-by: Xueyuan Chen > --- > include/linux/huge_mm.h | 5 +++++ > mm/Kconfig | 17 +++++++++++++++++ > mm/huge_memory.c | 25 ++++++++++++++++++++++++- > 3 files changed, 46 insertions(+), 1 deletion(-) > > diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h > index edece3e26985..45d1352619d1 100644 > --- a/include/linux/huge_mm.h > +++ b/include/linux/huge_mm.h > @@ -5,6 +5,7 @@ > #include > > #include /* only for vma_is_dax() */ > +#include > #include > > vm_fault_t do_huge_pmd_anonymous_page(struct vm_fault *vmf); > @@ -554,6 +555,10 @@ static inline bool is_huge_zero_pmd(pmd_t pmd) > struct folio *mm_get_huge_zero_folio(struct mm_struct *mm); > void mm_put_huge_zero_folio(struct mm_struct *mm); > > +#ifdef CONFIG_READONLY_HUGE_ZERO_FOLIO > +bool __init arch_make_huge_zero_folio_readonly(struct folio *folio); > +#endif > + > static inline struct folio *get_persistent_huge_zero_folio(void) > { > if (!IS_ENABLED(CONFIG_PERSISTENT_HUGE_ZERO_FOLIO)) > diff --git a/mm/Kconfig b/mm/Kconfig > index 776b67c66e82..f31200816646 100644 > --- a/mm/Kconfig > +++ b/mm/Kconfig > @@ -787,6 +787,23 @@ config PERSISTENT_HUGE_ZERO_FOLIO > Say Y if your system has lots of memory. Say N if you are > memory constrained. > > +config ARCH_HAS_READONLY_HUGE_ZERO_FOLIO > + bool > + > +config READONLY_HUGE_ZERO_FOLIO > + bool "Map the huge zero folio read-only in the direct map" > + depends on PERSISTENT_HUGE_ZERO_FOLIO > + depends on ARCH_HAS_READONLY_HUGE_ZERO_FOLIO > + help > + The persistent huge zero folio is shared globally, and nothing > + should ever change its contents after initialization. > + > + When supported, mark the folio read-only in the direct map so such > + writes trigger a fault instead of silently corrupting the zero contents. > + > + If the permission change is not supported, the kernel keeps using > + the writable persistent huge zero folio. > + > config MM_ID > def_bool n > > diff --git a/mm/huge_memory.c b/mm/huge_memory.c > index bf9b480bb3b0..c568755dd58e 100644 > --- a/mm/huge_memory.c > +++ b/mm/huge_memory.c > @@ -75,7 +75,11 @@ static unsigned long deferred_split_scan(struct shrinker *shrink, > static bool split_underused_thp = true; > > static atomic_t huge_zero_refcount; > +#ifdef CONFIG_READONLY_HUGE_ZERO_FOLIO > +struct folio *huge_zero_folio __ro_after_init; Can we guard this with CONFIG_PERSISTENT_HUGE_ZERO_FOLIO? Since in that case too the pointer is never written after init. > +#else > struct folio *huge_zero_folio __read_mostly; > +#endif > unsigned long huge_zero_pfn __read_mostly = ~0UL; > unsigned long huge_anon_orders_always __read_mostly; > unsigned long huge_anon_orders_madvise __read_mostly; > @@ -305,6 +309,18 @@ static unsigned long shrink_huge_zero_folio_scan(struct shrinker *shrink, > return 0; > } > > +#ifdef CONFIG_READONLY_HUGE_ZERO_FOLIO > +static bool __init make_huge_zero_folio_readonly(void) > +{ > + return arch_make_huge_zero_folio_readonly(READ_ONCE(huge_zero_folio)); I think READ_ONCE is not required since no one is going to change the pointer after allocation? > +} > +#else > +static bool __init make_huge_zero_folio_readonly(void) > +{ > + return false; > +} > +#endif > + > static struct shrinker *huge_zero_folio_shrinker; > > #ifdef CONFIG_SYSFS > @@ -965,8 +981,15 @@ 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; > + } > + > + if (IS_ENABLED(CONFIG_READONLY_HUGE_ZERO_FOLIO) && > + !make_huge_zero_folio_readonly()) > + pr_warn("Making persistent huge zero folio read-only failed\n"); > + > return 0; > } >