diff options
author | Bob Beck <beck@cvs.openbsd.org> | 2012-10-21 19:00:49 +0000 |
---|---|---|
committer | Bob Beck <beck@cvs.openbsd.org> | 2012-10-21 19:00:49 +0000 |
commit | ea9e6de3fdeb45b92517bf22164f081a7cab4775 (patch) | |
tree | 188030413ea931e606b536f0dd07383ee3016e73 /sys/kern/sysv_sem.c | |
parent | 01aa05846272f1859e5882dcbdfa5a0fd6d0ee0a (diff) |
Fix problem reported by Nathan Weeks <weeks@iastate.edu> where a userland
program could induce the kernel to panic by attempting to do a sempo
with nsops > kern.seminfo.semume and the SEM_UNFO flag set.
This fixes it so we return ENOSPC, like the man page says, rather
than panicing.
ok miod@, millert@
Diffstat (limited to 'sys/kern/sysv_sem.c')
-rw-r--r-- | sys/kern/sysv_sem.c | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/sys/kern/sysv_sem.c b/sys/kern/sysv_sem.c index 1a4caada430..2789670ddd7 100644 --- a/sys/kern/sysv_sem.c +++ b/sys/kern/sysv_sem.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sysv_sem.c,v 1.43 2012/04/11 13:29:14 naddy Exp $ */ +/* $OpenBSD: sysv_sem.c,v 1.44 2012/10/21 19:00:48 beck Exp $ */ /* $NetBSD: sysv_sem.c,v 1.26 1996/02/09 19:00:25 christos Exp $ */ /* @@ -594,7 +594,7 @@ sys_semop(struct proc *p, void *v, register_t *retval) do_wakeup = 1; } if (sopptr->sem_flg & SEM_UNDO) - do_undos = 1; + do_undos++; } else if (sopptr->sem_op == 0) { if (semptr->semval > 0) { DPRINTF(("semop: not zero now\n")); @@ -605,14 +605,14 @@ sys_semop(struct proc *p, void *v, register_t *retval) do_wakeup = 1; semptr->semval += sopptr->sem_op; if (sopptr->sem_flg & SEM_UNDO) - do_undos = 1; + do_undos++; } } /* - * Did we get through the entire vector? + * Did we get through the entire vector and can we undo it? */ - if (i >= nsops) + if (i >= nsops && do_undos <= SEMUME) goto done; /* @@ -624,6 +624,14 @@ sys_semop(struct proc *p, void *v, register_t *retval) sops[j].sem_op; /* + * Did we have too many SEM_UNDO's + */ + if (do_undos > SEMUME) { + error = ENOSPC; + goto done2; + } + + /* * If the request that we couldn't satisfy has the * NOWAIT flag set then return with EAGAIN. */ |