NetBSD Problem Report #60377

From www@netbsd.org  Sun Jun 28 06:53:49 2026
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
	 client-signature RSA-PSS (2048 bits) client-digest SHA256)
	(Client CN "mail.netbsd.org", Issuer "R13" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id A71AC1A923A
	for <gnats-bugs@gnats.NetBSD.org>; Sun, 28 Jun 2026 06:53:49 +0000 (UTC)
Message-Id: <20260628065348.43C7A1A923B@mollari.NetBSD.org>
Date: Sun, 28 Jun 2026 06:53:48 +0000 (UTC)
From: kevin.bowling@kev009.com
Reply-To: kevin.bowling@kev009.com
To: gnats-bugs@NetBSD.org
Subject: x86 cpu_uarea_alloc: pmap_update before freeing redzone pages
X-Send-Pr-Version: www-1.0
X-From4GNATS: "kevin.bowling@kev009.com via gnats" <gnats-admin@NetBSD.org>

>Number:         60377
>Category:       kern
>Synopsis:       x86 cpu_uarea_alloc: pmap_update before freeing redzone pages
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Jun 28 06:55:00 +0000 2026
>Last-Modified:  Mon Jun 29 15:55:01 +0000 2026
>Originator:     Kevin Bowling
>Release:        trunk
>Organization:
NetBSD
>Environment:
>Description:
The two pmap_kremove calls had a single trailing pmap_update, leaving
the freed redzone pages reachable through stale TLB entries on remote
CPUs between the uvm_pagefree calls and the eventual shootdown.

Batch both kremoves, then pmap_update, then both frees.

>How-To-Repeat:

>Fix:
diff --git a/sys/arch/x86/x86/vm_machdep.c b/sys/arch/x86/x86/vm_machdep.c
index 7d70835f1b6e..800210175e39 100644
--- a/sys/arch/x86/x86/vm_machdep.c
+++ b/sys/arch/x86/x86/vm_machdep.c
@@ -364,8 +364,8 @@ vunmapbuf(struct buf *bp, vsize_t len)
 void *
 cpu_uarea_alloc(bool system)
 {
-       vaddr_t base, va;
-       paddr_t pa;
+       vaddr_t base, va, va_lo, va_hi;
+       paddr_t pa_lo, pa_hi;
        struct pcb *pcb;

        base = uvm_km_alloc(kernel_map, USPACE + PAGE_SIZE, 0,
@@ -402,23 +402,19 @@ cpu_uarea_alloc(bool system)
                pcb->pcb_savefpu = &pcb->pcb_savefpusmall;
        }

-       /* Page[1] = RedZone */
-       va = base + PAGE_SIZE;
-       if (!pmap_extract(pmap_kernel(), va, &pa)) {
+       va_lo = base + PAGE_SIZE;
+       va_hi = base + USPACE;
+       if (!pmap_extract(pmap_kernel(), va_lo, &pa_lo)) {
                panic("%s: impossible, Page[1] unmapped", __func__);
        }
-       pmap_kremove(va, PAGE_SIZE);
-       uvm_pagefree(PHYS_TO_VM_PAGE(pa));
-
-       /* Page[UPAGES] = RedZone */
-       va = base + USPACE;
-       if (!pmap_extract(pmap_kernel(), va, &pa)) {
+       if (!pmap_extract(pmap_kernel(), va_hi, &pa_hi)) {
                panic("%s: impossible, Page[UPAGES] unmapped", __func__);
        }
-       pmap_kremove(va, PAGE_SIZE);
-       uvm_pagefree(PHYS_TO_VM_PAGE(pa));
-
+       pmap_kremove(va_lo, PAGE_SIZE);
+       pmap_kremove(va_hi, PAGE_SIZE);
        pmap_update(pmap_kernel());
+       uvm_pagefree(PHYS_TO_VM_PAGE(pa_lo));
+       uvm_pagefree(PHYS_TO_VM_PAGE(pa_hi));

        return (void *)base;
 }

>Audit-Trail:
From: Taylor R Campbell <riastradh@NetBSD.org>
To: Kevin Bowling <kevin.bowling@kev009.com>
Cc: gnats-bugs@NetBSD.org, netbsd-bugs@NetBSD.org, skrll@NetBSD.org,
	thorpej@NetBSD.org
Subject: Re: kern/60377: x86 cpu_uarea_alloc: pmap_update before freeing redzone pages
Date: Sun, 28 Jun 2026 18:32:03 +0000

 I'm confused by this one.

 The logic here, condensed and paraphrased, is:

 1. allocate [va1, ..., vaN] and [pa1, ..., paN] with uvm_km_alloc
 2. pmap_kremove the vaN->paN mapping (but keep 1 through N-1)
 3. free paN
 4. pmap_update

 (The purpose is to make vaN a guard page to catch kernel bugs.)

 Note that there is no question about freeing or reusing _virtual_
 addresses -- only about freeing and potentially reusing _physical_
 addresses.

 If I understand correctly, the idea of moving pmap_update earlier is
 to ensure that any loads or stores prior to pmap_kremove won't
 accidentally read or write data in paN _after_ it has been repurposed
 for something else, leaking or corrupting a kernel data structure.

 But I don't see how it could be possible -- barring critical bugs
 elsewhere in the kernel -- for any other CPUs or threads or interrupt
 handlers to load from or store to vaN.  And we certainly don't load
 from or store to vaN in this function.

 So what's the harm in freeing paN before pmap_update?  We've made a
 page table entry that we break, but nobody can possibly be using vaN,
 so the physical page shouldn't be affected by any of this.

From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/60377 CVS commit: src/share/man/man9
Date: Mon, 29 Jun 2026 15:52:17 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Mon Jun 29 15:52:17 UTC 2026

 Modified Files:
 	src/share/man/man9: pmap.9

 Log Message:
 pmap(9): Clarify obligations around pmap_update.

 Note: pmap_kenter_pa does not specify for now, because there is still
 some disagreement over what the rule SHOULD be, and current usage is to
 use pmap_update.

 Prompted by:

 PR kern/60377: x86 cpu_uarea_alloc: pmap_update before freeing
 redzone pages


 To generate a diff of this commit:
 cvs rdiff -u -r1.48 -r1.49 src/share/man/man9/pmap.9

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.51 2026/08/10 02:28:17 riastradh Exp $
$NetBSD: gnats_config.sh,v 1.10 2026/05/13 22:00:09 riastradh Exp $
Copyright © 1994-2026 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.