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:
Matthew Dillon 2003-01-13 23:04:32 +00:00
parent 1c33791c80
commit 3db161e079
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=109205
7 changed files with 32 additions and 27 deletions

View File

@ -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));

View File

@ -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));

View File

@ -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;
}

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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