linux processes sharing VM space (via clone() call) must also
share same 'break' value used for brk()/sbrk(), otherwise application SIGSEGVs quickly once different threads try to adjust data segment size this fixes linux Mozilla crashes with SuSE 9.1 libraries, and possibly other linux applications using real threads
This commit is contained in:
parent
a37fba2a04
commit
a714ac8294
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: linux_emuldata.h,v 1.5 2003/06/23 17:29:25 erh Exp $ */
|
||||
/* $NetBSD: linux_emuldata.h,v 1.6 2004/08/08 09:40:50 jdolecek Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998,2002 The NetBSD Foundation, Inc.
|
||||
@ -45,12 +45,18 @@
|
||||
* stored in the emuldata field of the proc
|
||||
* structure.
|
||||
*/
|
||||
struct linux_emuldata_shared {
|
||||
caddr_t p_break; /* Processes' idea of break */
|
||||
int refs;
|
||||
};
|
||||
|
||||
struct linux_emuldata {
|
||||
#if notyet
|
||||
sigset_t ps_siginfo; /* Which signals have a RT handler */
|
||||
#endif
|
||||
int debugreg[8]; /* GDB information for ptrace - for use, */
|
||||
/* see ../arch/i386/linux_ptrace.c */
|
||||
caddr_t p_break; /* Processes' idea of break */
|
||||
struct linux_emuldata_shared *s;
|
||||
};
|
||||
|
||||
#endif /* !_COMMON_LINUX_EMULDATA_H */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: linux_exec.c,v 1.70 2003/12/20 19:01:30 fvdl Exp $ */
|
||||
/* $NetBSD: linux_exec.c,v 1.71 2004/08/08 09:40:50 jdolecek Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1994, 1995, 1998, 2000 The NetBSD Foundation, Inc.
|
||||
@ -38,7 +38,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.70 2003/12/20 19:01:30 fvdl Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.71 2004/08/08 09:40:50 jdolecek Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -75,9 +75,9 @@ extern const char * const linux_syscallnames[];
|
||||
extern char linux_sigcode[], linux_esigcode[];
|
||||
|
||||
static void linux_e_proc_exec __P((struct proc *, struct exec_package *));
|
||||
static void linux_e_proc_fork __P((struct proc *, struct proc *));
|
||||
static void linux_e_proc_fork __P((struct proc *, struct proc *, int));
|
||||
static void linux_e_proc_exit __P((struct proc *));
|
||||
static void linux_e_proc_init __P((struct proc *, struct vmspace *));
|
||||
static void linux_e_proc_init __P((struct proc *, struct proc *, int));
|
||||
|
||||
/*
|
||||
* Execve(2). Just check the alternate emulation path, and pass it on
|
||||
@ -147,25 +147,54 @@ const struct emul emul_linux = {
|
||||
};
|
||||
|
||||
static void
|
||||
linux_e_proc_init(p, vmspace)
|
||||
struct proc *p;
|
||||
struct vmspace *vmspace;
|
||||
linux_e_proc_init(p, parent, forkflags)
|
||||
struct proc *p, *parent;
|
||||
int forkflags;
|
||||
{
|
||||
if (!p->p_emuldata) {
|
||||
struct linux_emuldata *e = p->p_emuldata;
|
||||
struct linux_emuldata_shared *s;
|
||||
|
||||
if (!e) {
|
||||
/* allocate new Linux emuldata */
|
||||
MALLOC(p->p_emuldata, void *, sizeof(struct linux_emuldata),
|
||||
MALLOC(e, void *, sizeof(struct linux_emuldata),
|
||||
M_EMULDATA, M_WAITOK);
|
||||
} else {
|
||||
e->s->refs++;
|
||||
if (e->s->refs == 0)
|
||||
FREE(e->s, M_EMULDATA);
|
||||
}
|
||||
|
||||
memset(p->p_emuldata, '\0', sizeof(struct linux_emuldata));
|
||||
|
||||
/* Set the process idea of the break to the real value */
|
||||
((struct linux_emuldata*)(p->p_emuldata))->p_break =
|
||||
vmspace->vm_daddr + ctob(vmspace->vm_dsize);
|
||||
memset(e, '\0', sizeof(struct linux_emuldata));
|
||||
|
||||
if (forkflags & CLONE_VM) {
|
||||
struct linux_emuldata *e2 = parent->p_emuldata;
|
||||
s = e2->s;
|
||||
s->refs++;
|
||||
} else {
|
||||
struct vmspace *vm;
|
||||
|
||||
MALLOC(s, void *, sizeof(struct linux_emuldata_shared),
|
||||
M_EMULDATA, M_WAITOK);
|
||||
s->refs = 1;
|
||||
|
||||
/*
|
||||
* Set the process idea of the break to the real value.
|
||||
* For fork, we use parent's vmspace since our's
|
||||
* is not setup at the time of this call and is going
|
||||
* to be copy of parent's anyway. For exec, just
|
||||
* use our own vmspace.
|
||||
*/
|
||||
vm = (parent) ? parent->p_vmspace : p->p_vmspace;
|
||||
s->p_break = vm->vm_daddr + ctob(vm->vm_dsize);
|
||||
|
||||
}
|
||||
|
||||
e->s = s;
|
||||
p->p_emuldata = e;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate per-process structures. Called when executing Linux
|
||||
* Allocate new per-process structures. Called when executing Linux
|
||||
* process. We can reuse the old emuldata - if it's not null,
|
||||
* the executed process is of same emulation as original forked one.
|
||||
*/
|
||||
@ -175,7 +204,7 @@ linux_e_proc_exec(p, epp)
|
||||
struct exec_package *epp;
|
||||
{
|
||||
/* exec, use our vmspace */
|
||||
linux_e_proc_init(p, p->p_vmspace);
|
||||
linux_e_proc_init(p, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -185,8 +214,13 @@ static void
|
||||
linux_e_proc_exit(p)
|
||||
struct proc *p;
|
||||
{
|
||||
struct linux_emuldata *e = p->p_emuldata;
|
||||
|
||||
/* free Linux emuldata and set the pointer to null */
|
||||
FREE(p->p_emuldata, M_EMULDATA);
|
||||
e->s->refs--;
|
||||
if (e->s->refs == 0)
|
||||
FREE(e->s, M_EMULDATA);
|
||||
FREE(e, M_EMULDATA);
|
||||
p->p_emuldata = NULL;
|
||||
}
|
||||
|
||||
@ -194,16 +228,16 @@ linux_e_proc_exit(p)
|
||||
* Emulation fork hook.
|
||||
*/
|
||||
static void
|
||||
linux_e_proc_fork(p, parent)
|
||||
linux_e_proc_fork(p, parent, forkflags)
|
||||
struct proc *p, *parent;
|
||||
int forkflags;
|
||||
{
|
||||
/*
|
||||
* It could be desirable to copy some stuff from parent's
|
||||
* emuldata. We don't need anything like that for now.
|
||||
* So just allocate new emuldata for the new process.
|
||||
* The new process might share some vmspace-related stuff
|
||||
* with parent, depending on fork flags (CLONE_VM et.al).
|
||||
* Force allocation of new base emuldata, and share the
|
||||
* VM-related parts only if necessary.
|
||||
*/
|
||||
p->p_emuldata = NULL;
|
||||
|
||||
/* fork, use parent's vmspace (our vmspace may not be setup yet) */
|
||||
linux_e_proc_init(p, parent->p_vmspace);
|
||||
linux_e_proc_init(p, parent, forkflags);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: linux_misc.c,v 1.126 2004/08/01 22:44:10 jdolecek Exp $ */
|
||||
/* $NetBSD: linux_misc.c,v 1.127 2004/08/08 09:40:50 jdolecek Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1995, 1998, 1999 The NetBSD Foundation, Inc.
|
||||
@ -64,7 +64,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: linux_misc.c,v 1.126 2004/08/01 22:44:10 jdolecek Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: linux_misc.c,v 1.127 2004/08/08 09:40:50 jdolecek Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -283,9 +283,9 @@ linux_sys_brk(l, v, retval)
|
||||
SCARG(&oba, nsize) = nbrk;
|
||||
|
||||
if ((caddr_t) nbrk > vm->vm_daddr && sys_obreak(l, &oba, retval) == 0)
|
||||
ed->p_break = (char*)nbrk;
|
||||
ed->s->p_break = (char*)nbrk;
|
||||
else
|
||||
nbrk = ed->p_break;
|
||||
nbrk = ed->s->p_break;
|
||||
|
||||
retval[0] = (register_t)nbrk;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user