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.
|
* Copyright (c) 1998,2002 The NetBSD Foundation, Inc.
|
||||||
@ -45,12 +45,18 @@
|
|||||||
* stored in the emuldata field of the proc
|
* stored in the emuldata field of the proc
|
||||||
* structure.
|
* structure.
|
||||||
*/
|
*/
|
||||||
|
struct linux_emuldata_shared {
|
||||||
|
caddr_t p_break; /* Processes' idea of break */
|
||||||
|
int refs;
|
||||||
|
};
|
||||||
|
|
||||||
struct linux_emuldata {
|
struct linux_emuldata {
|
||||||
#if notyet
|
#if notyet
|
||||||
sigset_t ps_siginfo; /* Which signals have a RT handler */
|
sigset_t ps_siginfo; /* Which signals have a RT handler */
|
||||||
#endif
|
#endif
|
||||||
int debugreg[8]; /* GDB information for ptrace - for use, */
|
int debugreg[8]; /* GDB information for ptrace - for use, */
|
||||||
/* see ../arch/i386/linux_ptrace.c */
|
/* see ../arch/i386/linux_ptrace.c */
|
||||||
caddr_t p_break; /* Processes' idea of break */
|
struct linux_emuldata_shared *s;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* !_COMMON_LINUX_EMULDATA_H */
|
#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.
|
* Copyright (c) 1994, 1995, 1998, 2000 The NetBSD Foundation, Inc.
|
||||||
@ -38,7 +38,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#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/param.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
@ -75,9 +75,9 @@ extern const char * const linux_syscallnames[];
|
|||||||
extern char linux_sigcode[], linux_esigcode[];
|
extern char linux_sigcode[], linux_esigcode[];
|
||||||
|
|
||||||
static void linux_e_proc_exec __P((struct proc *, struct exec_package *));
|
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_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
|
* Execve(2). Just check the alternate emulation path, and pass it on
|
||||||
@ -147,25 +147,54 @@ const struct emul emul_linux = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
linux_e_proc_init(p, vmspace)
|
linux_e_proc_init(p, parent, forkflags)
|
||||||
struct proc *p;
|
struct proc *p, *parent;
|
||||||
struct vmspace *vmspace;
|
int forkflags;
|
||||||
{
|
{
|
||||||
if (!p->p_emuldata) {
|
struct linux_emuldata *e = p->p_emuldata;
|
||||||
|
struct linux_emuldata_shared *s;
|
||||||
|
|
||||||
|
if (!e) {
|
||||||
/* allocate new Linux emuldata */
|
/* allocate new Linux emuldata */
|
||||||
MALLOC(p->p_emuldata, void *, sizeof(struct linux_emuldata),
|
MALLOC(e, void *, sizeof(struct linux_emuldata),
|
||||||
M_EMULDATA, M_WAITOK);
|
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));
|
memset(e, '\0', sizeof(struct linux_emuldata));
|
||||||
|
|
||||||
/* Set the process idea of the break to the real value */
|
if (forkflags & CLONE_VM) {
|
||||||
((struct linux_emuldata*)(p->p_emuldata))->p_break =
|
struct linux_emuldata *e2 = parent->p_emuldata;
|
||||||
vmspace->vm_daddr + ctob(vmspace->vm_dsize);
|
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,
|
* process. We can reuse the old emuldata - if it's not null,
|
||||||
* the executed process is of same emulation as original forked one.
|
* 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;
|
struct exec_package *epp;
|
||||||
{
|
{
|
||||||
/* exec, use our vmspace */
|
/* 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)
|
linux_e_proc_exit(p)
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
{
|
{
|
||||||
|
struct linux_emuldata *e = p->p_emuldata;
|
||||||
|
|
||||||
/* free Linux emuldata and set the pointer to null */
|
/* 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;
|
p->p_emuldata = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,16 +228,16 @@ linux_e_proc_exit(p)
|
|||||||
* Emulation fork hook.
|
* Emulation fork hook.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
linux_e_proc_fork(p, parent)
|
linux_e_proc_fork(p, parent, forkflags)
|
||||||
struct proc *p, *parent;
|
struct proc *p, *parent;
|
||||||
|
int forkflags;
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* It could be desirable to copy some stuff from parent's
|
* The new process might share some vmspace-related stuff
|
||||||
* emuldata. We don't need anything like that for now.
|
* with parent, depending on fork flags (CLONE_VM et.al).
|
||||||
* So just allocate new emuldata for the new process.
|
* Force allocation of new base emuldata, and share the
|
||||||
|
* VM-related parts only if necessary.
|
||||||
*/
|
*/
|
||||||
p->p_emuldata = NULL;
|
p->p_emuldata = NULL;
|
||||||
|
linux_e_proc_init(p, parent, forkflags);
|
||||||
/* fork, use parent's vmspace (our vmspace may not be setup yet) */
|
|
||||||
linux_e_proc_init(p, parent->p_vmspace);
|
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* Copyright (c) 1995, 1998, 1999 The NetBSD Foundation, Inc.
|
||||||
@ -64,7 +64,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#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/param.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
@ -283,9 +283,9 @@ linux_sys_brk(l, v, retval)
|
|||||||
SCARG(&oba, nsize) = nbrk;
|
SCARG(&oba, nsize) = nbrk;
|
||||||
|
|
||||||
if ((caddr_t) nbrk > vm->vm_daddr && sys_obreak(l, &oba, retval) == 0)
|
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
|
else
|
||||||
nbrk = ed->p_break;
|
nbrk = ed->s->p_break;
|
||||||
|
|
||||||
retval[0] = (register_t)nbrk;
|
retval[0] = (register_t)nbrk;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user