diff options
author | dillon <dillon@FreeBSD.org> | 2003-01-13 23:04:32 +0000 |
---|---|---|
committer | dillon <dillon@FreeBSD.org> | 2003-01-13 23:04:32 +0000 |
commit | ce710d36cc14755344115d36e5459a39e385e64d (patch) | |
tree | 3c875a6ad9627d4125943a71834883e1b354baa5 | |
parent | e08a8297e2779e8d6e2160c041440e8f3908ece8 (diff) | |
download | FreeBSD-src-ce710d36cc14755344115d36e5459a39e385e64d.zip FreeBSD-src-ce710d36cc14755344115d36e5459a39e385e64d.tar.gz |
It is possible for an active aio to prevent shared memory from being
dereferenced when a process exits due to the vmspace ref-count being
bumped. Change shmexit() and shmexit_myhook() to take a vmspace instead
of a process and call it in vmspace_dofree(). This way if it is missed
in exit1()'s early-resource-free it will still be caught when the zombie is
reaped.
Also fix a potential race in shmexit_myhook() by NULLing out
vmspace->vm_shm prior to calling shm_delete_mapping() and free().
MFC after: 7 days
-rw-r--r-- | sys/kern/kern_exec.c | 3 | ||||
-rw-r--r-- | sys/kern/kern_exit.c | 3 | ||||
-rw-r--r-- | sys/kern/sysv_ipc.c | 7 | ||||
-rw-r--r-- | sys/kern/sysv_shm.c | 32 | ||||
-rw-r--r-- | sys/sys/ipc.h | 3 | ||||
-rw-r--r-- | sys/sys/shm.h | 3 | ||||
-rw-r--r-- | sys/vm/vm_map.c | 8 |
7 files changed, 32 insertions, 27 deletions
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 543bd6a..0ee36ba 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -864,8 +864,7 @@ exec_new_vmspace(imgp, sv) map = &vmspace->vm_map; if (vmspace->vm_refcnt == 1 && vm_map_min(map) == sv->sv_minuser && vm_map_max(map) == sv->sv_maxuser) { - if (vmspace->vm_shm) - shmexit(p); + shmexit(vmspace); vm_page_lock_queues(); pmap_remove_pages(vmspace_pmap(vmspace), vm_map_min(map), vm_map_max(map)); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 8737bed..c34f26f 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -297,8 +297,7 @@ exit1(td, rv) */ ++vm->vm_exitingcnt; if (--vm->vm_refcnt == 0) { - if (vm->vm_shm) - shmexit(p); + shmexit(vm); vm_page_lock_queues(); pmap_remove_pages(vmspace_pmap(vm), vm_map_min(&vm->vm_map), vm_map_max(&vm->vm_map)); diff --git a/sys/kern/sysv_ipc.c b/sys/kern/sysv_ipc.c index fc5fd8f..55d39de 100644 --- a/sys/kern/sysv_ipc.c +++ b/sys/kern/sysv_ipc.c @@ -42,7 +42,7 @@ #include <sys/ucred.h> void (*shmfork_hook)(struct proc *, struct proc *) = NULL; -void (*shmexit_hook)(struct proc *) = NULL; +void (*shmexit_hook)(struct vmspace *) = NULL; /* called from kern_fork.c */ void @@ -57,12 +57,11 @@ shmfork(p1, p2) /* called from kern_exit.c */ void -shmexit(p) - struct proc *p; +shmexit(struct vmspace *vm) { if (shmexit_hook != NULL) - shmexit_hook(p); + shmexit_hook(vm); return; } diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c index 6c9d34a..04c9b2a 100644 --- a/sys/kern/sysv_shm.c +++ b/sys/kern/sysv_shm.c @@ -97,12 +97,12 @@ static void shm_deallocate_segment(struct shmid_ds *); static int shm_find_segment_by_key(key_t); static struct shmid_ds *shm_find_segment_by_shmid(int); static struct shmid_ds *shm_find_segment_by_shmidx(int); -static int shm_delete_mapping(struct proc *p, struct shmmap_state *); +static int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *); static void shmrealloc(void); static void shminit(void); static int sysvshm_modload(struct module *, int, void *); static int shmunload(void); -static void shmexit_myhook(struct proc *p); +static void shmexit_myhook(struct vmspace *vm); static void shmfork_myhook(struct proc *p1, struct proc *p2); static int sysctl_shmsegs(SYSCTL_HANDLER_ARGS); @@ -214,9 +214,7 @@ shm_deallocate_segment(shmseg) } static int -shm_delete_mapping(p, shmmap_s) - struct proc *p; - struct shmmap_state *shmmap_s; +shm_delete_mapping(struct vmspace *vm, struct shmmap_state *shmmap_s) { struct shmid_ds *shmseg; int segnum, result; @@ -227,8 +225,7 @@ shm_delete_mapping(p, shmmap_s) segnum = IPCID_TO_IX(shmmap_s->shmid); shmseg = &shmsegs[segnum]; size = round_page(shmseg->shm_segsz); - result = vm_map_remove(&p->p_vmspace->vm_map, shmmap_s->va, - shmmap_s->va + size); + result = vm_map_remove(&vm->vm_map, shmmap_s->va, shmmap_s->va + size); if (result != KERN_SUCCESS) return (EINVAL); shmmap_s->shmid = -1; @@ -278,7 +275,7 @@ shmdt(td, uap) error = EINVAL; goto done2; } - error = shm_delete_mapping(p, shmmap_s); + error = shm_delete_mapping(p->p_vmspace, shmmap_s); done2: mtx_unlock(&Giant); return (error); @@ -768,20 +765,21 @@ shmfork_myhook(p1, p2) } static void -shmexit_myhook(p) - struct proc *p; +shmexit_myhook(struct vmspace *vm) { - struct shmmap_state *shmmap_s; + struct shmmap_state *base, *shm; int i; GIANT_REQUIRED; - shmmap_s = p->p_vmspace->vm_shm; - for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) - if (shmmap_s->shmid != -1) - shm_delete_mapping(p, shmmap_s); - free(p->p_vmspace->vm_shm, M_SHM); - p->p_vmspace->vm_shm = NULL; + if ((base = vm->vm_shm) != NULL) { + vm->vm_shm = NULL; + for (i = 0, shm = base; i < shminfo.shmseg; i++, shm++) { + if (shm->shmid != -1) + shm_delete_mapping(vm, shm); + } + free(base, M_SHM); + } } static void diff --git a/sys/sys/ipc.h b/sys/sys/ipc.h index e78082a..c79c857 100644 --- a/sys/sys/ipc.h +++ b/sys/sys/ipc.h @@ -115,10 +115,11 @@ struct ipc_perm { struct thread; struct proc; +struct vmspace; int ipcperm(struct thread *, struct ipc_perm *, int); extern void (*shmfork_hook)(struct proc *, struct proc *); -extern void (*shmexit_hook)(struct proc *); +extern void (*shmexit_hook)(struct vmspace *); #else /* ! _KERNEL */ diff --git a/sys/sys/shm.h b/sys/sys/shm.h index b5ce766..6d66384 100644 --- a/sys/sys/shm.h +++ b/sys/sys/shm.h @@ -97,8 +97,9 @@ struct shm_info { struct thread; struct proc; +struct vmspace; -void shmexit(struct proc *); +void shmexit(struct vmspace *); void shmfork(struct proc *, struct proc *); #else /* !_KERNEL */ diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index 97d7c6d..6c53b7f 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -80,6 +80,7 @@ #include <sys/resourcevar.h> #include <sys/sysent.h> #include <sys/stdint.h> +#include <sys/shm.h> #include <vm/vm.h> #include <vm/vm_param.h> @@ -284,6 +285,13 @@ static __inline void vmspace_dofree(struct vmspace *vm) { CTR1(KTR_VM, "vmspace_free: %p", vm); + + /* + * Make sure any SysV shm is freed, it might not have been in + * exit1(). + */ + shmexit(vm); + /* * Lock the map, to wait out all other references to it. * Delete all of the mappings and pages they hold, then call |