diff options
author | 2015-04-28 20:54:18 +0000 | |
---|---|---|
committer | 2015-04-28 20:54:18 +0000 | |
commit | 05ffb7cef019f60b14cb1c941cb654f894700e2a (patch) | |
tree | 33e8c61026116667aecdc96f38a5748b8c4df21b | |
parent | Don't grab the kernel lock for clock interrupts. The way we use mutexes (diff) | |
download | wireguard-openbsd-05ffb7cef019f60b14cb1c941cb654f894700e2a.tar.xz wireguard-openbsd-05ffb7cef019f60b14cb1c941cb654f894700e2a.zip |
Protect the per-process itimerval structs with a mutex. We update these
from hardclock() which runs without grabbing the kernel lock. This means
that two threads could concurrently update the struct which could lead to
corruption of the value which in turn could stop the timer. It could also
result in getitimer(2) returning a non-normalized value.
With help from guenther@.
ok deraadt@, guenther@
-rw-r--r-- | sys/kern/kern_time.c | 23 |
1 files changed, 13 insertions, 10 deletions
diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index a8808ed1b3b..453790b3682 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_time.c,v 1.89 2014/12/07 02:58:14 deraadt Exp $ */ +/* $OpenBSD: kern_time.c,v 1.90 2015/04/28 20:54:18 kettenis Exp $ */ /* $NetBSD: kern_time.c,v 1.20 1996/02/18 11:57:06 fvdl Exp $ */ /* @@ -460,6 +460,8 @@ sys_adjtime(struct proc *p, void *v, register_t *retval) } +struct mutex itimer_mtx = MUTEX_INITIALIZER(IPL_CLOCK); + /* * Get value of an interval timer. The process virtual and * profiling virtual time timers are kept internally in the @@ -488,7 +490,6 @@ sys_getitimer(struct proc *p, void *v, register_t *retval) syscallarg(struct itimerval *) itv; } */ *uap = v; struct itimerval aitv; - int s; int which; which = SCARG(uap, which); @@ -496,11 +497,12 @@ sys_getitimer(struct proc *p, void *v, register_t *retval) if (which < ITIMER_REAL || which > ITIMER_PROF) return (EINVAL); memset(&aitv, 0, sizeof(aitv)); - s = splclock(); + mtx_enter(&itimer_mtx); aitv.it_interval.tv_sec = p->p_p->ps_timer[which].it_interval.tv_sec; aitv.it_interval.tv_usec = p->p_p->ps_timer[which].it_interval.tv_usec; aitv.it_value.tv_sec = p->p_p->ps_timer[which].it_value.tv_sec; aitv.it_value.tv_usec = p->p_p->ps_timer[which].it_value.tv_usec; + mtx_leave(&itimer_mtx); if (which == ITIMER_REAL) { struct timeval now; @@ -520,7 +522,7 @@ sys_getitimer(struct proc *p, void *v, register_t *retval) &aitv.it_value); } } - splx(s); + return (copyout(&aitv, SCARG(uap, itv), sizeof (struct itimerval))); } @@ -573,12 +575,10 @@ sys_setitimer(struct proc *p, void *v, register_t *retval) } pr->ps_timer[ITIMER_REAL] = aitv; } else { - int s; - itimerround(&aitv.it_interval); - s = splclock(); + mtx_enter(&itimer_mtx); pr->ps_timer[which] = aitv; - splx(s); + mtx_leave(&itimer_mtx); } return (0); @@ -676,7 +676,7 @@ itimerround(struct timeval *tv) int itimerdecr(struct itimerval *itp, int usec) { - + mtx_enter(&itimer_mtx); if (itp->it_value.tv_usec < usec) { if (itp->it_value.tv_sec == 0) { /* expired, and already in next interval */ @@ -688,8 +688,10 @@ itimerdecr(struct itimerval *itp, int usec) } itp->it_value.tv_usec -= usec; usec = 0; - if (timerisset(&itp->it_value)) + if (timerisset(&itp->it_value)) { + mtx_leave(&itimer_mtx); return (1); + } /* expired, exactly at end of interval */ expire: if (timerisset(&itp->it_interval)) { @@ -701,6 +703,7 @@ expire: } } else itp->it_value.tv_usec = 0; /* sec is already 0 */ + mtx_leave(&itimer_mtx); return (0); } |