Subject: Re: setrlimit(2) strange behaviour under compat_netbsd32
To: NetBSD current <current-users@NetBSD.org>
From: Nicolas Joly <njoly@pasteur.fr>
List: current-users
Date: 11/21/2006 12:17:24
--bg08WKrSYDhXBjb5
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Mon, Nov 20, 2006 at 08:42:53PM +0100, Nicolas Joly wrote:
> 
> I just noticed a strange setrlimit(2) behaviour under compat_netbsd32
> (and compat_linux32) on my -current amd64 workstation ...
> 
> It seems that 32bits programs, running under compat_netbsd32, using
> setrlimit force all other programs to have their maximum data size
> fixed at 3GB, where native 64bits apps used 8GB previously.

I tracked this one to the `netbsd32_adjust_limits()' function (called
when creating a new process under compat_netbsd32), where data and
stack limits are set without checking for shared `p_limit' structure
(p_limit->p_refcnt > 1). This explain the side effect where processes
have their limits changed when a compat_netbsd32 (or compat_linux32)
program is run.

What about the attached patch, that use `dosetrlimit()' to ensure the
needed copy-on-write behaviour for shared structure.

-- 
Nicolas Joly

Biological Software and Databanks.
Institut Pasteur, Paris.

--bg08WKrSYDhXBjb5
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="netbsd-netbsd32limits.diff"

Index: sys/compat/linux32/arch/amd64/linux32_machdep.c
===================================================================
RCS file: /cvsroot/src/sys/compat/linux32/arch/amd64/linux32_machdep.c,v
retrieving revision 1.1
diff -u -r1.1 linux32_machdep.c
--- sys/compat/linux32/arch/amd64/linux32_machdep.c	9 Feb 2006 19:18:57 -0000	1.1
+++ sys/compat/linux32/arch/amd64/linux32_machdep.c	21 Nov 2006 10:17:47 -0000
@@ -290,7 +290,7 @@
 	pmap_ldt_cleanup(p);
 #endif
 
-	netbsd32_adjust_limits(p);
+	netbsd32_adjust_limits(l);
 
 	l->l_md.md_flags &= ~MDP_USEDFPU;
 	pcb->pcb_flags = 0;
@@ -301,11 +301,11 @@
 	pcb->pcb_gs = 0;
 
 
-	l->l_proc->p_flag |= P_32;
+	p->p_flag |= P_32;
 
 	tf = l->l_md.md_regs;
 	tf->tf_rax = 0;
-	tf->tf_rbx = (u_int64_t)l->l_proc->p_psstr & 0xffffffff;
+	tf->tf_rbx = (u_int64_t)p->p_psstr & 0xffffffff;
 	tf->tf_rcx = pack->ep_entry & 0xffffffff;
 	tf->tf_rdx = 0;
 	tf->tf_rsi = 0;
Index: sys/arch/amd64/amd64/netbsd32_machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/amd64/netbsd32_machdep.c,v
retrieving revision 1.28
diff -u -r1.28 netbsd32_machdep.c
--- sys/arch/amd64/amd64/netbsd32_machdep.c	23 Oct 2006 12:11:47 -0000	1.28
+++ sys/arch/amd64/amd64/netbsd32_machdep.c	21 Nov 2006 10:17:47 -0000
@@ -125,7 +125,7 @@
 	pmap_ldt_cleanup(p);
 #endif
 
-	netbsd32_adjust_limits(p);
+	netbsd32_adjust_limits(l);
 
 	l->l_md.md_flags &= ~MDP_USEDFPU;
 	pcb->pcb_flags = 0;
@@ -134,7 +134,7 @@
 	pcb->pcb_savefpu.fp_fxsave.fx_mxcsr_mask = __INITIAL_MXCSR_MASK__;
 
 
-	l->l_proc->p_flag |= P_32;
+	p->p_flag |= P_32;
 
 	tf = l->l_md.md_regs;
 	tf->tf_ds = LSEL(LUDATA32_SEL, SEL_UPL);
Index: sys/arch/sparc64/sparc64/netbsd32_machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/sparc64/netbsd32_machdep.c,v
retrieving revision 1.63
diff -u -r1.63 netbsd32_machdep.c
--- sys/arch/sparc64/sparc64/netbsd32_machdep.c	22 Oct 2006 10:50:44 -0000	1.63
+++ sys/arch/sparc64/sparc64/netbsd32_machdep.c	21 Nov 2006 10:17:47 -0000
@@ -112,7 +112,7 @@
 	/* Mark this as a 32-bit emulation */
 	p->p_flag |= P_32;
 
-	netbsd32_adjust_limits(p);
+	netbsd32_adjust_limits(l);
 
 	/* Setup the ev_out32 hook */
 #if NFIRM_EVENTS > 0
Index: sys/compat/netbsd32/netbsd32.h
===================================================================
RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32.h,v
retrieving revision 1.54
diff -u -r1.54 netbsd32.h
--- sys/compat/netbsd32/netbsd32.h	13 Jul 2006 12:00:25 -0000	1.54
+++ sys/compat/netbsd32/netbsd32.h	21 Nov 2006 10:17:47 -0000
@@ -676,7 +676,7 @@
 void netbsd32_from_stat43 __P((struct stat43 *, struct netbsd32_stat43 *));
 
 vaddr_t netbsd32_vm_default_addr(struct proc *, vaddr_t, vsize_t);
-void netbsd32_adjust_limits(struct proc *);
+void netbsd32_adjust_limits(struct lwp *);
 
 void	netbsd32_si_to_si32(siginfo32_t *, const siginfo_t *);
 void	netbsd32_si32_to_si(siginfo_t *, const siginfo32_t *);
Index: sys/compat/netbsd32/netbsd32_netbsd.c
===================================================================
RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32_netbsd.c,v
retrieving revision 1.112
diff -u -r1.112 netbsd32_netbsd.c
--- sys/compat/netbsd32/netbsd32_netbsd.c	14 Nov 2006 13:34:29 -0000	1.112
+++ sys/compat/netbsd32/netbsd32_netbsd.c	21 Nov 2006 10:17:48 -0000
@@ -2312,23 +2312,26 @@
 }
 
 void
-netbsd32_adjust_limits(struct proc *p)
+netbsd32_adjust_limits(struct lwp *l)
 {
-	rlim_t *valp;
+	struct proc *p = l->l_proc;
+	struct rlimit lim;
 
-	valp = &p->p_rlimit[RLIMIT_DATA].rlim_cur;
-	if (*valp != RLIM_INFINITY && *valp > MAXDSIZ32)
-		*valp = MAXDSIZ32;
-	valp = &p->p_rlimit[RLIMIT_DATA].rlim_max;
-	if (*valp != RLIM_INFINITY && *valp > MAXDSIZ32)
-		*valp = MAXDSIZ32;
-
-	valp = &p->p_rlimit[RLIMIT_STACK].rlim_cur;
-	if (*valp != RLIM_INFINITY && *valp > MAXSSIZ32)
-		*valp = MAXSSIZ32;
-	valp = &p->p_rlimit[RLIMIT_STACK].rlim_max;
-	if (*valp != RLIM_INFINITY && *valp > MAXSSIZ32)
-		*valp = MAXSSIZ32;
+	lim.rlim_cur = p->p_rlimit[RLIMIT_DATA].rlim_cur;
+	if (lim.rlim_cur != RLIM_INFINITY && lim.rlim_cur > MAXDSIZ32)
+		lim.rlim_cur = MAXDSIZ32;
+	lim.rlim_max = p->p_rlimit[RLIMIT_DATA].rlim_max;
+	if (lim.rlim_max != RLIM_INFINITY && lim.rlim_max > MAXDSIZ32)
+		lim.rlim_max = MAXDSIZ32;
+	dosetrlimit(l, p, RLIMIT_DATA, &lim);
+
+	lim.rlim_cur = p->p_rlimit[RLIMIT_STACK].rlim_cur;
+	if (lim.rlim_cur != RLIM_INFINITY && lim.rlim_cur > MAXSSIZ32)
+		lim.rlim_cur = MAXSSIZ32;
+	lim.rlim_max = p->p_rlimit[RLIMIT_STACK].rlim_max;
+	if (lim.rlim_max != RLIM_INFINITY && lim.rlim_max > MAXSSIZ32)
+		lim.rlim_max = MAXSSIZ32;
+	dosetrlimit(l, p, RLIMIT_STACK, &lim);
 }
 
 int

--bg08WKrSYDhXBjb5--