From 89b57fcf01d895a82a24b97548116e924bca5efc Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Mon, 5 Nov 2007 11:36:16 +0000 Subject: 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 --- sys/kern/kern_fork.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'sys/kern/kern_fork.c') diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 917de57ca742..ab7ca8b41206 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); -- cgit v1.2.3