summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_fork.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2007-11-05 11:36:16 +0000
committerkib <kib@FreeBSD.org>2007-11-05 11:36:16 +0000
commit9ae733819b7cdf0eef51ba1b18d39feb136a9dbf (patch)
treecccec36134d2cab5ce1eabb67dcaab5981e9beb0 /sys/kern/kern_fork.c
parentf3f033b9b90ea07350fbe7483af3d9636cb31d1d (diff)
downloadFreeBSD-src-9ae733819b7cdf0eef51ba1b18d39feb136a9dbf.zip
FreeBSD-src-9ae733819b7cdf0eef51ba1b18d39feb136a9dbf.tar.gz
Fix for the panic("vm_thread_new: kstack allocation failed") and
silent NULL pointer dereference in the i386 and sparc64 pmap_pinit() when the kmem_alloc_nofault() failed to allocate address space. Both functions now return error instead of panicing or dereferencing NULL. As consequence, vmspace_exec() and vmspace_unshare() returns the errno int. struct vmspace arg was added to vm_forkproc() to avoid dealing with failed allocation when most of the fork1() job is already done. The kernel stack for the thread is now set up in the thread_alloc(), that itself may return NULL. Also, allocation of the first process thread is performed in the fork1() to properly deal with stack allocation failure. proc_linkup() is separated into proc_linkup() called from fork1(), and proc_linkup0(), that is used to set up the kernel process (was known as swapper). In collaboration with: Peter Holm Reviewed by: jhb
Diffstat (limited to 'sys/kern/kern_fork.c')
-rw-r--r--sys/kern/kern_fork.c41
1 files changed, 34 insertions, 7 deletions
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 917de57..ab7ca8b 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -195,6 +195,7 @@ fork1(td, flags, pages, procp)
struct filedesc_to_leader *fdtol;
struct thread *td2;
struct sigacts *newsigacts;
+ struct vmspace *vm2;
int error;
/* Can't copy and clear. */
@@ -218,7 +219,9 @@ fork1(td, flags, pages, procp)
PROC_UNLOCK(p1);
}
- vm_forkproc(td, NULL, NULL, flags);
+ error = vm_forkproc(td, NULL, NULL, NULL, flags);
+ if (error)
+ goto norfproc_fail;
/*
* Close all file descriptors.
@@ -236,6 +239,7 @@ fork1(td, flags, pages, procp)
if (flags & RFFDG)
fdunshare(p1, td);
+norfproc_fail:
if (((p1->p_flag & (P_HADTHREADS|P_SYSTEM)) == P_HADTHREADS) &&
(flags & (RFCFDG | RFFDG))) {
PROC_LOCK(p1);
@@ -243,7 +247,7 @@ fork1(td, flags, pages, procp)
PROC_UNLOCK(p1);
}
*procp = NULL;
- return (0);
+ return (error);
}
/*
@@ -254,6 +258,32 @@ fork1(td, flags, pages, procp)
/* Allocate new proc. */
newproc = uma_zalloc(proc_zone, M_WAITOK);
+ if (TAILQ_EMPTY(&newproc->p_threads)) {
+ td2 = thread_alloc();
+ if (td2 == NULL) {
+ error = ENOMEM;
+ goto fail1;
+ }
+ proc_linkup(newproc, td2);
+ sched_newproc(newproc, td2);
+ } else
+ td2 = FIRST_THREAD_IN_PROC(newproc);
+
+ /* Allocate and switch to an alternate kstack if specified. */
+ if (pages != 0) {
+ if (!vm_thread_new_altkstack(td2, pages)) {
+ error = ENOMEM;
+ goto fail1;
+ }
+ }
+ if ((flags & RFMEM) == 0) {
+ vm2 = vmspace_fork(p1->p_vmspace);
+ if (vm2 == NULL) {
+ error = ENOMEM;
+ goto fail1;
+ }
+ } else
+ vm2 = NULL;
#ifdef MAC
mac_proc_init(newproc);
#endif
@@ -380,7 +410,6 @@ again:
lastpid = trypid;
p2 = newproc;
- td2 = FIRST_THREAD_IN_PROC(newproc);
p2->p_state = PRS_NEW; /* protect against others */
p2->p_pid = trypid;
/*
@@ -456,9 +485,6 @@ again:
* Start by zeroing the section of proc that is zero-initialized,
* then copy the section that is copied directly from the parent.
*/
- /* Allocate and switch to an alternate kstack if specified. */
- if (pages != 0)
- vm_thread_new_altkstack(td2, pages);
PROC_LOCK(p2);
PROC_LOCK(p1);
@@ -630,7 +656,7 @@ again:
* Finish creating the child process. It will return via a different
* execution path later. (ie: directly into user mode)
*/
- vm_forkproc(td, p2, td2, flags);
+ vm_forkproc(td, p2, td2, vm2, flags);
if (flags == (RFFDG | RFPROC)) {
PCPU_INC(cnt.v_forks);
@@ -713,6 +739,7 @@ fail:
#ifdef MAC
mac_proc_destroy(newproc);
#endif
+fail1:
uma_zfree(proc_zone, newproc);
pause("fork", hz / 2);
return (error);
OpenPOWER on IntegriCloud