NetBSD Problem Report #59252

From www@netbsd.org  Sat Apr  5 11:13:28 2025
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 "mail.NetBSD.org CA" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id CC79B1A923E
	for <gnats-bugs@gnats.NetBSD.org>; Sat,  5 Apr 2025 11:13:28 +0000 (UTC)
Message-Id: <20250405111327.3165F1A9241@mollari.NetBSD.org>
Date: Sat,  5 Apr 2025 11:13:27 +0000 (UTC)
From: campbell+netbsd@mumble.net
Reply-To: campbell+netbsd@mumble.net
To: gnats-bugs@NetBSD.org
Subject: tests/rump/rumpkern/t_sp:sigsafe: out of memory
X-Send-Pr-Version: www-1.0

>Number:         59252
>Category:       misc
>Synopsis:       tests/rump/rumpkern/t_sp:sigsafe: out of memory
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    misc-bug-people
>State:          needs-pullups
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Apr 05 11:15:00 +0000 2025
>Closed-Date:    
>Last-Modified:  Sun Apr 06 03:17:32 +0000 2025
>Originator:     Taylor R Campbell
>Release:        current
>Organization:
The rump t_sp Foundaleak
>Environment:
>Description:
The `sigsafe' test in tests/rump/rumpkern/t_sp has been intermittently failing for a long time.  I put in various diagnostic measures (e.g., PR bin/58112: daemonized rump conceals output on crash) to no avail, until I noticed this:

Pre-test stderr:
[1]   Killed                  ${Atf_Check} "${@}"
rump.halt: init failed: Connection refused
t_sp: ERROR: The test case cleanup returned a non-ok exit code, but this is not allowed

https://releng.netbsd.org/b5reports/i386/2025/2025.04.04.21.52.19/test.html#rump_rumpkern_t_sp_sigsafe

On review of the test logs, I see that a sampling of t_sp:sigsafe failures all show the uvm oom killer:

    sigsafe: [ 7629.0398811] UVM: pid 25563.25563 (h_sigcli), uid 0 killed: out of swap
[ 7629.0427354] UVM: pid 17924.17924 (sh), uid 0 killed: out of swap
[ 7629.0526265] UVM: pid 17976.26594 (rump_server), uid 0 killed: out of swap
[ 7629.0526265] UVM: pid 27133.27133 (atf-check), uid 0 killed: out of swap
[5.689429s] Failed: atf-check failed; see the output of the test for details

https://releng.netbsd.org/b5reports/i386/2025/2025.04.04.21.52.19/test.log

    sigsafe: [ 7541.7773590] UVM: pid 2566.14124 (rump_server), uid 0 killed: out of swap
[5.739012s] Failed: atf-check failed; see the output of the test for details

https://releng.netbsd.org/b5reports/i386/2025/2025.04.04.20.40.58/test.log

    sigsafe: [ 7636.1123173] UVM: pid 29410.16674 (rump_server), uid 0 killed: out of swap
[ 7636.1123173] UVM: pid 26178.26178 (sh), uid 0 killed: out of swap
[5.838166s] Failed: atf-check failed; see the output of the test for details

https://releng.netbsd.org/b5reports/i386/2025/2025.04.01.16.35.46/test.log
>How-To-Repeat:
On a low-memory machine:

atf-run /usr/tests/rump/rumpkern/t_sp:sigsafe | atf-report
>Fix:
Yes, please!

>Release-Note:

>Audit-Trail:
From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/59252 CVS commit: src/sys/rump/librump/rumpkern
Date: Sun, 6 Apr 2025 01:13:55 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Sun Apr  6 01:13:55 UTC 2025

 Modified Files:
 	src/sys/rump/librump/rumpkern: lwproc.c

 Log Message:
 rump: Nix leaked struct lwp on every rump_server syscall.

 This leak was introduced by lwproc.c rev. 1.51 back in 2020, when the
 kmem_zalloc(sizeof(*l), KM_SLEEP) was factored out of callers and
 into lwproc_makelwp:

 -static void
 -lwproc_makelwp(struct proc *p, struct lwp *l, bool doswitch, bool procmake)
 +static struct lwp *
 +lwproc_makelwp(struct proc *p, bool doswitch, bool procmake)
  {
 +	struct lwp *l = kmem_zalloc(sizeof(*l), KM_SLEEP);
 ...
 @@ -435,8 +431,12 @@ rump_lwproc_newlwp(pid_t pid)
  		kmem_free(l, sizeof(*l));
  		return EBUSY;
  	}
 +	mutex_exit(p->p_lock);
  	mutex_exit(&proc_lock);
 -	lwproc_makelwp(p, l, true, false);
 +
 +	/* XXX what holds proc? */
 +
 +	lwproc_makelwp(p, true, false);

 Unfortunately, the kmem_zalloc in rump_lwproc_newlwp was not deleted.
 So it just leaked.

 And this routine is called on _every_ syscall handled by rump_server
 (via struct rumpuser_hyperup::hyp_lwproc_newlwp):

     674 static void
     675 serv_handlesyscall(struct spclient *spc, struct rsp_hdr *rhdr, uint8_t *data)
     676 {
     677 	register_t retval[2] = {0, 0};
     678 	int rv, sysnum;
     679
     680 	sysnum = (int)rhdr->rsp_sysnum;
     681 	DPRINTF(("rump_sp: handling syscall %d from client %d\n",
     682 	    sysnum, spc->spc_pid));
     683
  => 684 	if (__predict_false((rv = lwproc_newlwp(spc->spc_pid)) != 0)) {
     685 		retval[0] = -1;
     686 		send_syscall_resp(spc, rhdr->rsp_reqno, rv, retval);
     687 		return;
     688 	}
     689 	spc->spc_syscallreq = rhdr->rsp_reqno;
     690 	rv = rumpsyscall(sysnum, data, retval);

 https://nxr.netbsd.org/xref/src/lib/librumpuser/rumpuser_sp.c?r=1.77#684

 So this leak would grow fairly quickly in processes issuing rump
 syscalls to rump_servers, which t_sp:sigsafe's helper h_sigcli does
 as fast as it can in a loop for 5sec -- which is just long enough for
 the i386 releng testbed with about 128 MB of RAM to run out of memory
 in roughly half of the test runs, but not long enough on my laptop
 with 64 GB of RAM to ever reproduce the problem.

 Found by:

 (a) running the test for 20sec rather than 5sec to amplify the leak;
 (b) counting bytes allocated by return addresses of rumpuser_malloc;
 (c) chasing that to rump_hypermalloc (culprit) vs uvm_km_alloc;
 (d) chasing that to pgctor, uvm_map, uvm_km_kmem_alloc (culprit),
     vmapbuf;
 (e) then to pool_page_alloc, then to pool_allocator_alloc, then to
     pool_grow, then to pool_get, then to pool_cache_get, then to
     kmem_zalloc;
 (f) finally to the call to kmem_zalloc in rump_lwproc_newlwp, which
     at last yielded to my stare.

 This instrumentation was extremely ad hoc -- I just created a table
 of 4096 entries for each routine, and populated by linear scan with
 atomics:

 struct {
 	void *volatile ra;
 	volatile unsigned long n;
 } pool_cache_get_bytes;

 void *
 kmem_zalloc(size_t size, km_flags_t flags)
 {
 	...
 	void *const ra = __builtin_return_address(0);
 	size_t i;
 	for (i = 0; i < __arraycount(kmem_zalloc_bytes); i++) {
 		if (pool_cache_get_bytes[i].ra == ra ||
 		    (pool_cache_get_bytes[i].ra == NULL &&
 			atomic_cas_ptr(&pool_cache_get_bytes[i].ra, NULL,
 			    ra) == NULL)) {
 			atomic_add_long(&pool_cache_get_bytes[i].n, size);
 			break;
 		}
 	}
 	...
 }

 Would be nice to systematize this.  Would also be nice to bring back
 malloc tags for accounting purposes so you don't need to match up the
 kmem_zalloc return addresses with the kmem_free return addresses to
 find leaks -- I got lucky here because there were very few return
 addresses to piece through.

 PR misc/59252: tests/rump/rumpkern/t_sp:sigsafe: out of memory


 To generate a diff of this commit:
 cvs rdiff -u -r1.58 -r1.59 src/sys/rump/librump/rumpkern/lwproc.c

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

From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/59252 CVS commit: src/sys/rump/librump/rumpkern
Date: Sun, 6 Apr 2025 01:58:23 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Sun Apr  6 01:58:23 UTC 2025

 Modified Files:
 	src/sys/rump/librump/rumpkern: intr.c

 Log Message:
 rump: Set up the softint CPU bouncer only once, not once per CPU.

 This is used for softint_schedule_cpu to schedule softints on other
 CPUs.  There is one global lock, and one global condition variable,
 and really there only needs to be one thread to handle the requests.
 Without this change, we reinitialize the lock and condition variable,
 leaking them (and possibly leave some threads confused if they are
 currently taking the lock or waiting on the condition variable as
 they get reinitialized).

 Leak found by lsan while investigating:

 PR misc/59252: tests/rump/rumpkern/t_sp:sigsafe: out of memory


 To generate a diff of this commit:
 cvs rdiff -u -r1.56 -r1.57 src/sys/rump/librump/rumpkern/intr.c

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

State-Changed-From-To: open->needs-pullups
State-Changed-By: riastradh@NetBSD.org
State-Changed-When: Sun, 06 Apr 2025 03:17:32 +0000
State-Changed-Why:
fixed in HEAD, needs pullup-9 and pullup-10


>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.