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
This commit is contained in:
parent
1c33791c80
commit
3db161e079
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user