diff options
author | anton <anton@cvs.openbsd.org> | 2019-10-28 19:57:51 +0000 |
---|---|---|
committer | anton <anton@cvs.openbsd.org> | 2019-10-28 19:57:51 +0000 |
commit | 6f10cca1004f36904d8042e94adcfd10786c737d (patch) | |
tree | 94ada5f5589ecf567b4c43a260f41ed7af259e5f /sys | |
parent | b2796020899590813fae8656955a5e19b0eb85b6 (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.c | 11 |
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 = |