diff options
author | anton <anton@cvs.openbsd.org> | 2020-03-04 08:04:49 +0000 |
---|---|---|
committer | anton <anton@cvs.openbsd.org> | 2020-03-04 08:04:49 +0000 |
commit | 445021046b64da989820ca5e75373c6c1afd032f (patch) | |
tree | a5b05243ea0833fda76d395819cfbdd31f8ea3c0 | |
parent | cf0bedb7d9ec8138d14f3bb5fbf3a81f29d19c46 (diff) |
Grab a reference for the shared memory segment before calling uvm_map()
as the same function could end up putting the thread to sleep. Allowing
another thread to free the shared memory segment, which in turns causes
a use-after-free.
With help from and ok millert@ visa@
Reported-by: syzbot+0fc1766671a9461de8a5@syzkaller.appspotmail.com
-rw-r--r-- | sys/kern/sysv_shm.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c index d3ebc0b08f8..96c5abeea75 100644 --- a/sys/kern/sysv_shm.c +++ b/sys/kern/sysv_shm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sysv_shm.c,v 1.75 2019/11/05 08:18:47 mpi Exp $ */ +/* $OpenBSD: sysv_shm.c,v 1.76 2020/03/04 08:04:48 anton Exp $ */ /* $NetBSD: sysv_shm.c,v 1.50 1998/10/21 22:24:29 tron Exp $ */ /* @@ -261,13 +261,25 @@ sys_shmat(struct proc *p, void *v, register_t *retval) return (EINVAL); } else attach_va = 0; + /* + * Since uvm_map() could end up sleeping, grab a reference to prevent + * the segment from being deallocated while sleeping. + */ + shmseg->shm_nattch++; shm_handle = shmseg->shm_internal; uao_reference(shm_handle->shm_object); error = uvm_map(&p->p_vmspace->vm_map, &attach_va, size, shm_handle->shm_object, 0, 0, UVM_MAPFLAG(prot, prot, MAP_INHERIT_SHARE, MADV_RANDOM, flags)); if (error) { - uao_detach(shm_handle->shm_object); + if ((--shmseg->shm_nattch <= 0) && + (shmseg->shm_perm.mode & SHMSEG_REMOVED)) { + shm_deallocate_segment(shmseg); + shm_last_free = IPCID_TO_IX(SCARG(uap, shmid)); + shmsegs[shm_last_free] = NULL; + } else { + uao_detach(shm_handle->shm_object); + } return (error); } @@ -275,7 +287,6 @@ sys_shmat(struct proc *p, void *v, register_t *retval) shmmap_s->shmid = SCARG(uap, shmid); shmseg->shm_lpid = p->p_p->ps_pid; shmseg->shm_atime = time_second; - shmseg->shm_nattch++; *retval = attach_va; return (0); } |