summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoranton <anton@cvs.openbsd.org>2020-03-04 08:04:49 +0000
committeranton <anton@cvs.openbsd.org>2020-03-04 08:04:49 +0000
commit445021046b64da989820ca5e75373c6c1afd032f (patch)
treea5b05243ea0833fda76d395819cfbdd31f8ea3c0
parentcf0bedb7d9ec8138d14f3bb5fbf3a81f29d19c46 (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.c17
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);
}