summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authoranton <anton@cvs.openbsd.org>2019-10-28 19:57:51 +0000
committeranton <anton@cvs.openbsd.org>2019-10-28 19:57:51 +0000
commit6f10cca1004f36904d8042e94adcfd10786c737d (patch)
tree94ada5f5589ecf567b4c43a260f41ed7af259e5f /sys
parentb2796020899590813fae8656955a5e19b0eb85b6 (diff)
Copy in the user-supplied buffer in shmctl(2) before looking up the
shared memory segment. Otherwise, if copyin ends up sleeping it allows another thread to remove the same segment leading to a use-after-free. Feedback from kettenis@ and ok guenther@ Reported-by: syzbot+0de42c2e600a6dd3091d@syzkaller.appspotmail.com
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/sysv_shm.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c
index 1fcaff75b9f..c64112f8f72 100644
--- a/sys/kern/sysv_shm.c
+++ b/sys/kern/sysv_shm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sysv_shm.c,v 1.71 2019/01/25 00:19:26 millert Exp $ */
+/* $OpenBSD: sysv_shm.c,v 1.72 2019/10/28 19:57:50 anton Exp $ */
/* $NetBSD: sysv_shm.c,v 1.50 1998/10/21 22:24:29 tron Exp $ */
/*
@@ -302,6 +302,12 @@ shmctl1(struct proc *p, int shmid, int cmd, caddr_t buf,
struct shmid_ds inbuf, *shmseg;
int error;
+ if (cmd == IPC_SET) {
+ error = ds_copyin(buf, &inbuf, sizeof(inbuf));
+ if (error)
+ return (error);
+ }
+
shmseg = shm_find_segment_by_shmid(shmid);
if (shmseg == NULL)
return (EINVAL);
@@ -316,9 +322,6 @@ shmctl1(struct proc *p, int shmid, int cmd, caddr_t buf,
case IPC_SET:
if ((error = ipcperm(cred, &shmseg->shm_perm, IPC_M)) != 0)
return (error);
- error = ds_copyin(buf, &inbuf, sizeof(inbuf));
- if (error)
- return (error);
shmseg->shm_perm.uid = inbuf.shm_perm.uid;
shmseg->shm_perm.gid = inbuf.shm_perm.gid;
shmseg->shm_perm.mode =