NetBSD Problem Report #60664

From www@netbsd.org  Fri Aug 28 23:48:24 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 "YR2" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id 2997F1A923B
	for <gnats-bugs@gnats.NetBSD.org>; Fri, 28 Aug 2026 23:48:24 +0000 (UTC)
Message-Id: <20260828234822.C65211A923C@mollari.NetBSD.org>
Date: Fri, 28 Aug 2026 23:48:22 +0000 (UTC)
From: kaloz@dune.hu
Reply-To: kaloz@dune.hu
To: gnats-bugs@NetBSD.org
Subject: mips: rdhwr emulation corrupts v0 on nested TLB miss, random userland SIGSEGV
X-Send-Pr-Version: www-1.0
X-From4GNATS: "kaloz@dune.hu via gnats" <gnats-admin@NetBSD.org>

>Number:         60664
>Category:       port-mips
>Synopsis:       mips: rdhwr emulation corrupts v0 on nested TLB miss, random userland SIGSEGV
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    port-mips-maintainer
>State:          closed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Aug 28 23:50:01 +0000 2026
>Closed-Date:    Sun Oct 11 05:30:49 +0000 2026
>Last-Modified:  Sun Oct 11 05:30:49 +0000 2026
>Originator:     Imre Kaloz
>Release:        NetBSD 11.0 (also -current)
>Organization:
>Environment:
NetBSD indigo 11.0 NetBSD 11.0 (GENERIC32_IP2x) #0: Thu Jul 30 15:23:12 UTC 2026
mkrepro@mkrepro.NetBSD.org:/usr/src/sys/arch/sgimips/compile/GENERIC32_IP2x sgimips

>Description:
On CPUs without RDHWR every TLS access traps into MIPSX(user_reserved_insn), which re-reads the trapping instruction from user space with a plain inline load while EXL is still set.  If that read takes a TLB miss (the entry can be evicted by a refill for the mapped kernel stack moments earlier), the exception dispatch, which only looks at KSU, treats it as a fresh trap from userland and clobbers the v0 save slot the routine is still using. The emulation then returns the trap's own exception PC to the program as its TLS pointer, and the process later crashes at some unrelated address. From the outside it looks like random memory corruption, took a while to pin down.
>How-To-Repeat:
Run a few concurrent loops of dynamically linked commands (while :; do /bin/ls >/dev/null; done) next to a memory hog bigger than RAM, so paging keeps the TLB busy. I get a SIGSEGV rate of about 1 in 7.
>Fix:
Check the page with TLBP before the inline read and fall back to the existing protected slow path if it is not mapped.

Signed-off-by: Imre Kaloz <kaloz@dune.hu>

--- a/sys/arch/mips/mips/mipsX_subr.S
+++ b/sys/arch/mips/mips/mipsX_subr.S
@@ -1320,11 +1320,43 @@ NESTED_NOPROFILE(MIPSX(user_reserved_insn), CALLFRAME_SIZ, ra)
 	 nop

 	/*
-	 * Get exception PC and fetch the instruction.  We know we can do
-	 * this since the instruction actually got read.
+	 * Get exception PC and fetch the instruction.
+	 *
+	 * Probe the page with TLBP first, and take the slow path if the
+	 * entry isn't there.  A nested miss on the inline read below would
+	 * otherwise land in user_gen_exception and clobber this routine's
+	 * own v0, since the exception PC isn't saved again while EXL is set.
 	 */
 	_MFC0	v0, MIPS_COP_0_EXC_PC
 	MFC0_HAZARD
+
+	/* Need v1 and a0 too */
+	REG_S	v1, CALLFRAME_SIZ+TF_REG_V1(k0)
+	REG_S	a0, CALLFRAME_SIZ+TF_REG_A0(k0)
+	_MFC0	v1, MIPS_COP_0_TLB_HI		# save current ASID
+	MFC0_HAZARD
+	andi	a0, v1, MIPS3_PG_ASID
+	move	AT, v0
+#ifdef MIPSNNR2
+	_INS	AT, a0, 0, V_MIPS3_PG_HVPN
+#else
+	_SRA	AT, V_MIPS3_PG_HVPN		# clear bottom bits of VA
+	_SLL	AT, V_MIPS3_PG_HVPN		# clear bottom bits of VA
+	or	AT, AT, a0
+#endif
+	_MTC0	AT, MIPS_COP_0_TLB_HI		# look for the vaddr & ASID
+	COP0_SYNC
+	tlbp					# probe the entry in question
+	COP0_SYNC
+	mfc0	AT, MIPS_COP_0_TLB_INDEX	# see what we got
+	MFC0_HAZARD
+	_MTC0	v1, MIPS_COP_0_TLB_HI		# restore ASID
+	COP0_SYNC
+	/* Restore v1 and a0 for either outcome */
+	REG_L	v1, CALLFRAME_SIZ+TF_REG_V1(k0)
+	bltz	AT, MIPSX(user_gen_exception_common) # index < 0 => !found
+	 REG_L	a0, CALLFRAME_SIZ+TF_REG_A0(k0)
+
 	INT_L	AT, 0(v0)

 	/*

>Release-Note:

>Audit-Trail:
From: Nick Hudson <nick.hudson@gmx.co.uk>
To: gnats-bugs@netbsd.org,
 port-mips-maintainer@netbsd.org,
 gnats-admin@netbsd.org,
 netbsd-bugs@netbsd.org
Cc: 
Subject: Re: port-mips/60664: mips: rdhwr emulation corrupts v0 on nested TLB
 miss, random userland SIGSEGV
Date: Tue, 22 Sep 2026 18:58:42 +0100

 --Apple-Mail=_1E0D089D-F651-40AE-98A7-C6C6B197948D
 Content-Transfer-Encoding: quoted-printable
 Content-Type: text/plain;
 	charset=us-ascii

 Thanks for the PR.

 I changed the patch a little to improve register usage in both the fast =
 and slow paths.



 --Apple-Mail=_1E0D089D-F651-40AE-98A7-C6C6B197948D
 Content-Disposition: attachment;
 	filename=mipsX_subr.S.diff
 Content-Type: application/octet-stream;
 	x-unix-mode=0644;
 	name="mipsX_subr.S.diff"
 Content-Transfer-Encoding: quoted-printable

 Index: sys/arch/mips/mips/mipsX_subr.S
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 RCS file: /cvsroot/src/sys/arch/mips/mips/mipsX_subr.S,v
 retrieving revision 1.118
 diff -u -p -r1.118 mipsX_subr.S
 =2D-- sys/arch/mips/mips/mipsX_subr.S	27 Jun 2026 07:44:56 -0000	1.118
 +++ sys/arch/mips/mips/mipsX_subr.S	22 Sep 2026 15:52:31 -0000
 @@ -1320,32 +1320,63 @@ NESTED_NOPROFILE(MIPSX(user_reserved_ins
  	 nop
 =20
  	/*
 -	 * Get exception PC and fetch the instruction.  We know we can do
 -	 * this since the instruction actually got read.
 +	 * Get exception PC and fetch the instruction.
 +	 *
 +	 * Probe the page with TLBP first, and take the slow path if the
 +	 * entry isn't there.  A nested miss on the inline read below would
 +	 * otherwise land in user_gen_exception and clobber this routine's
 +	 * own v0, since the exception PC isn't saved again while EXL is set.
  	 */
  	_MFC0	v0, MIPS_COP_0_EXC_PC
  	MFC0_HAZARD
 +
 +	/* Need v1 and a0 too */
 +	REG_S	v1, CALLFRAME_SIZ+TF_REG_V1(k0)
 +	REG_S	a0, CALLFRAME_SIZ+TF_REG_A0(k0)
 +
 +	_MFC0	v1, MIPS_COP_0_TLB_HI		# grab current ASID
 +	MFC0_HAZARD
 +	andi	a0, v1, MIPS3_PG_ASID
 +	move	AT, v0
 +#ifdef MIPSNNR2
 +	_INS	AT, a0, 0, V_MIPS3_PG_HVPN
 +#else
 +	_SRA	AT, V_MIPS3_PG_HVPN		# clear bottom bits of VA
 +	_SLL	AT, V_MIPS3_PG_HVPN		# clear bottom bits of VA
 +	or	AT, AT, a0
 +#endif
 +	_MTC0	AT, MIPS_COP_0_TLB_HI		# look for the vaddr & ASID
 +	COP0_SYNC
 +	tlbp					# probe the entry in question
 +	COP0_SYNC
 +	mfc0	AT, MIPS_COP_0_TLB_INDEX	# see what we got
 +	MFC0_HAZARD
 +	_MTC0	v1, MIPS_COP_0_TLB_HI		# restore HI
 +	COP0_SYNC
 +	bltz	AT, MIPSX(user_gen_exception_common2) # index < 0 =3D> !found
 +	 nop
 +
 +	// Load instruction
  	INT_L	AT, 0(v0)
 =20
  	/*
  	 * Was this rdhwr $3,$29?
  	 */
 -	lui	v0, %hi(0x7c03e83b)	# 0x7c03e83b =3D> rdhwr $3,$29
 -	addiu	v0, %lo(0x7c03e83b)	#        or ... rdhwr v1,ulr
 -	bne	AT, v0, MIPSX(user_gen_exception_common)
 +	lui	v1, %hi(0x7c03e83b)	# 0x7c03e83b =3D> rdhwr $3,$29
 +	addiu	v1, %lo(0x7c03e83b)	#        or ... rdhwr v1,ulr
 +	bne	AT, v1, MIPSX(user_gen_exception_common2)
  	 nop
 =20
  	/*
  	 * Advance the PC (don't want to restart at the rdhwr).
  	 */
 -	_MFC0	v0, MIPS_COP_0_EXC_PC
 -	MFC0_HAZARD
  	PTR_ADDIU v0, 4
  	_MTC0	v0, MIPS_COP_0_EXC_PC
  	COP0_SYNC
 =20
  	PTR_L	v1, L_PRIVATE(k1)		# rdhwr $3,$29 updates v1
 =20
 +	REG_L	a0, CALLFRAME_SIZ+TF_REG_A0(k0) # restore reg
  	REG_L	AT, CALLFRAME_SIZ+TF_REG_AST(k0)# restore reg
  	REG_L	v0, CALLFRAME_SIZ+TF_REG_V0(k0) # restore reg
  	eret
 @@ -1374,34 +1405,35 @@ NESTED_NOPROFILE(MIPSX(user_gen_exceptio
  	REG_S	v0, CALLFRAME_SIZ+TF_REG_V0(k0)
  MIPSX(user_gen_exception_common):
  	REG_S	v1, CALLFRAME_SIZ+TF_REG_V1(k0)
 -	mflo	v0
  	REG_S	a0, CALLFRAME_SIZ+TF_REG_A0(k0)
 +MIPSX(user_gen_exception_common2):
  	REG_S	a1, CALLFRAME_SIZ+TF_REG_A1(k0)
 +	mflo	v0
  	REG_S	a2, CALLFRAME_SIZ+TF_REG_A2(k0)
  	REG_S	a3, CALLFRAME_SIZ+TF_REG_A3(k0)
 -	mfhi	v1
  	REG_S	t0, CALLFRAME_SIZ+TF_REG_T0(k0)
  	REG_S	t1, CALLFRAME_SIZ+TF_REG_T1(k0)
 +	mfhi	v1
  	REG_S	t2, CALLFRAME_SIZ+TF_REG_T2(k0)
  	REG_S	t3, CALLFRAME_SIZ+TF_REG_T3(k0)
 -	mfc0	a0, MIPS_COP_0_STATUS		# 1st arg is STATUS
  	REG_S	ta0, CALLFRAME_SIZ+TF_REG_TA0(k0)
  	REG_S	ta1, CALLFRAME_SIZ+TF_REG_TA1(k0)
 +	mfc0	a0, MIPS_COP_0_STATUS		# 1st arg is STATUS
  	REG_S	ta2, CALLFRAME_SIZ+TF_REG_TA2(k0)
  	REG_S	ta3, CALLFRAME_SIZ+TF_REG_TA3(k0)
 -	mfc0	a1, MIPS_COP_0_CAUSE		# 2nd arg is CAUSE
  	REG_S	s0, CALLFRAME_SIZ+TF_REG_S0(k0)
  	REG_S	s1, CALLFRAME_SIZ+TF_REG_S1(k0)
 +	mfc0	a1, MIPS_COP_0_CAUSE		# 2nd arg is CAUSE
  	REG_S	s2, CALLFRAME_SIZ+TF_REG_S2(k0)
  	REG_S	s3, CALLFRAME_SIZ+TF_REG_S3(k0)
 -	_MFC0	a2, MIPS_COP_0_BAD_VADDR	# 3rd arg is fault address
  	REG_S	s4, CALLFRAME_SIZ+TF_REG_S4(k0)
  	REG_S	s5, CALLFRAME_SIZ+TF_REG_S5(k0)
 +	_MFC0	a2, MIPS_COP_0_BAD_VADDR	# 3rd arg is fault address
  	REG_S	s6, CALLFRAME_SIZ+TF_REG_S6(k0)
  	REG_S	s7, CALLFRAME_SIZ+TF_REG_S7(k0)
 -	_MFC0	a3, MIPS_COP_0_EXC_PC		# 4th arg is exception PC
  	REG_S	t8, CALLFRAME_SIZ+TF_REG_T8(k0)	# will be MIPS_CURLWP
  	REG_S	t9, CALLFRAME_SIZ+TF_REG_T9(k0)
 +	_MFC0	a3, MIPS_COP_0_EXC_PC		# 4th arg is exception PC
  	REG_S	v0, CALLFRAME_SIZ+TF_REG_MULLO(k0)
  	REG_S	v1, CALLFRAME_SIZ+TF_REG_MULHI(k0)
  	REG_S	gp, CALLFRAME_SIZ+TF_REG_GP(k0)

 --Apple-Mail=_1E0D089D-F651-40AE-98A7-C6C6B197948D--

From: "Nick Hudson" <skrll@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/60664 CVS commit: src/sys/arch/mips/mips
Date: Fri, 25 Sep 2026 16:30:31 +0000

 Module Name:	src
 Committed By:	skrll
 Date:		Fri Sep 25 16:30:31 UTC 2026

 Modified Files:
 	src/sys/arch/mips/mips: mipsX_subr.S

 Log Message:
 mips: fix rdhwr emulation wrt TLB misses on loading the faulting instruction.

 Use tlbp to probe the TLB for an entry for the page containing the
 instruction to emulate, and fail to slow path if it doesn't exist.

 A TLB miss (nested exception) on the instruction load would otherwise
 land in user_gen_exception and clobber this routine's v0, since the
 exception PC isn't saved again while EXL is set.

 PR/60664 mips: rdhwr emulation corrupts v0 on nested TLB miss...

 This patch is based on the diff included in the PR, but updated by me
 to improve register save / restore in both the fast and slow paths.

 The mf* instructions in user_gen_exception_common are shuffled down
 to maintain the same number of stores (4) between each mf* in
 user_gen_exception_common and user_gen_exception_common2

 The symptoms that this change fixes match those described in

 port-evbmips/59236: Multiple segfaults in erlite3 boot


 To generate a diff of this commit:
 cvs rdiff -u -r1.118 -r1.119 src/sys/arch/mips/mips/mipsX_subr.S

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

From: "Nick Hudson" <skrll@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/60664 CVS commit: src/sys/arch/mips/mips
Date: Mon, 28 Sep 2026 10:53:42 +0000

 Module Name:	src
 Committed By:	skrll
 Date:		Mon Sep 28 10:53:41 UTC 2026

 Modified Files:
 	src/sys/arch/mips/mips: mipsX_subr.S

 Log Message:
 mips: remove the OCTEON workaround for PR/59236 as fixed by PR/60664

 The rdhwr emulation bug observed in PR/59236 was fixed by the patch in
 PR/60664 so the workaround applied for PR/59236 can be safely removed.


 To generate a diff of this commit:
 cvs rdiff -u -r1.119 -r1.120 src/sys/arch/mips/mips/mipsX_subr.S

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

State-Changed-From-To: open->pending-pullups
State-Changed-By: skrll@NetBSD.org
State-Changed-When: Mon, 28 Sep 2026 12:05:13 +0000
State-Changed-Why:
[pullup-11 #500] PR/60664 mips: rdhwr emulation corrupts v0 on nested TLB miss...
[pullup-10 #1347] PR/60664 mips: rdhwr emulation corrupts v0 on nested TLB miss...


From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/60664 CVS commit: [netbsd-11] src/sys/arch/mips/mips
Date: Fri, 2 Oct 2026 10:27:03 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Fri Oct  2 10:27:02 UTC 2026

 Modified Files:
 	src/sys/arch/mips/mips [netbsd-11]: mipsX_subr.S

 Log Message:
 Pull up following revision(s) (requested by skrll in ticket #500):

 	sys/arch/mips/mips/mipsX_subr.S: revision 1.120
 	sys/arch/mips/mips/mipsX_subr.S: revision 1.119

 mips: fix rdhwr emulation wrt TLB misses on loading the faulting instruction.

 Use tlbp to probe the TLB for an entry for the page containing the
 instruction to emulate, and fail to slow path if it doesn't exist.

 A TLB miss (nested exception) on the instruction load would otherwise
 land in user_gen_exception and clobber this routine's v0, since the
 exception PC isn't saved again while EXL is set.

 PR/60664 mips: rdhwr emulation corrupts v0 on nested TLB miss...

 This patch is based on the diff included in the PR, but updated by me
 to improve register save / restore in both the fast and slow paths.

 The mf* instructions in user_gen_exception_common are shuffled down
 to maintain the same number of stores (4) between each mf* in
 user_gen_exception_common and user_gen_exception_common2

 The symptoms that this change fixes match those described in
 port-evbmips/59236: Multiple segfaults in erlite3 boot
 mips: remove the OCTEON workaround for PR/59236 as fixed by PR/60664

 The rdhwr emulation bug observed in PR/59236 was fixed by the patch in
 PR/60664 so the workaround applied for PR/59236 can be safely removed.


 To generate a diff of this commit:
 cvs rdiff -u -r1.116 -r1.116.2.1 src/sys/arch/mips/mips/mipsX_subr.S

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

From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/60664 CVS commit: [netbsd-10] src/sys/arch/mips/mips
Date: Fri, 2 Oct 2026 10:29:34 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Fri Oct  2 10:29:34 UTC 2026

 Modified Files:
 	src/sys/arch/mips/mips [netbsd-10]: mipsX_subr.S

 Log Message:
 Pull up following revision(s) (requested by skrll in ticket #1347):

 	sys/arch/mips/mips/mipsX_subr.S: revision 1.119

 mips: fix rdhwr emulation wrt TLB misses on loading the faulting instruction.

 Use tlbp to probe the TLB for an entry for the page containing the
 instruction to emulate, and fail to slow path if it doesn't exist.

 A TLB miss (nested exception) on the instruction load would otherwise
 land in user_gen_exception and clobber this routine's v0, since the
 exception PC isn't saved again while EXL is set.

 PR/60664 mips: rdhwr emulation corrupts v0 on nested TLB miss...

 This patch is based on the diff included in the PR, but updated by me
 to improve register save / restore in both the fast and slow paths.

 The mf* instructions in user_gen_exception_common are shuffled down
 to maintain the same number of stores (4) between each mf* in
 user_gen_exception_common and user_gen_exception_common2

 The symptoms that this change fixes match those described in
 port-evbmips/59236: Multiple segfaults in erlite3 boot


 To generate a diff of this commit:
 cvs rdiff -u -r1.115 -r1.115.4.1 src/sys/arch/mips/mips/mipsX_subr.S

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

State-Changed-From-To: pending-pullups->feedback
State-Changed-By: skrll@NetBSD.org
State-Changed-When: Fri, 02 Oct 2026 17:05:58 +0000
State-Changed-Why:
ok to close?


From: Imre Kaloz <kaloz@dune.hu>
To: "gnats-bugs@NetBSD.org" <gnats-bugs@NetBSD.org>
Cc: 
Subject: Re: port-mips/60664: mips: rdhwr emulation corrupts v0 on nested TLB
 miss, random userland SIGSEGV
Date: Sat, 10 Oct 2026 17:55:39 +0000

 Hi Nick,=0A=
 =0A=
 Yes, OK to close from my side, thanks for picking it up and for the=0A=
 pullups.=0A=
 =0A=
 I re-tested with the GENERIC32_IP2x kernels from the 20261009 HEAD and=0A=
 20261008 netbsd-11 daily builds, on an 11.0 userland.=0A=
 =0A=
 Each run is 400 invocations of expr, sed, date and sysctl from a single-use=
 r=0A=
 shell, counting SIGSEGVs:=0A=
 =0A=
                         11.0        HEAD      netbsd-11=0A=
 IP20 (R4400)    43/400   0/400      0/400=0A=
 IP24 (R5000)    52/400   0/400      0/400=0A=
 =0A=
 =0A=
 Imre=

State-Changed-From-To: feedback->closed
State-Changed-By: skrll@NetBSD.org
State-Changed-When: Sun, 11 Oct 2026 05:30:49 +0000
State-Changed-Why:
confirmed fixed.


>Unformatted:

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.