Reduce minimal time intervals of setitimer(2) from 1/HZ to 1/(16*HZ) by
using callout_reset_sbt() instead of callout_reset(). We can't remove lower limit completely in this case because of significant processing overhead, caused by unability to use direct callout execution due to using process mutex in callout handler for sending SEGALRM signal. With support of periodic events that would allow unprivileged user to abuse the system. Reviewed by: davide
This commit is contained in:
parent
0e7919f704
commit
b5ea3779da
@ -691,7 +691,7 @@ kern_getitimer(struct thread *td, u_int which, struct itimerval *aitv)
|
||||
*aitv = p->p_realtimer;
|
||||
PROC_UNLOCK(p);
|
||||
if (timevalisset(&aitv->it_value)) {
|
||||
getmicrouptime(&ctv);
|
||||
microuptime(&ctv);
|
||||
if (timevalcmp(&aitv->it_value, &ctv, <))
|
||||
timevalclear(&aitv->it_value);
|
||||
else
|
||||
@ -736,28 +736,33 @@ kern_setitimer(struct thread *td, u_int which, struct itimerval *aitv,
|
||||
{
|
||||
struct proc *p = td->td_proc;
|
||||
struct timeval ctv;
|
||||
sbintime_t sbt, pr;
|
||||
|
||||
if (aitv == NULL)
|
||||
return (kern_getitimer(td, which, oitv));
|
||||
|
||||
if (which > ITIMER_PROF)
|
||||
return (EINVAL);
|
||||
if (itimerfix(&aitv->it_value))
|
||||
if (itimerfix(&aitv->it_value) ||
|
||||
aitv->it_value.tv_sec > INT32_MAX / 2)
|
||||
return (EINVAL);
|
||||
if (!timevalisset(&aitv->it_value))
|
||||
timevalclear(&aitv->it_interval);
|
||||
else if (itimerfix(&aitv->it_interval))
|
||||
else if (itimerfix(&aitv->it_interval) ||
|
||||
aitv->it_interval.tv_sec > INT32_MAX / 2)
|
||||
return (EINVAL);
|
||||
|
||||
if (which == ITIMER_REAL) {
|
||||
PROC_LOCK(p);
|
||||
if (timevalisset(&p->p_realtimer.it_value))
|
||||
callout_stop(&p->p_itcallout);
|
||||
getmicrouptime(&ctv);
|
||||
microuptime(&ctv);
|
||||
if (timevalisset(&aitv->it_value)) {
|
||||
callout_reset(&p->p_itcallout, tvtohz(&aitv->it_value),
|
||||
realitexpire, p);
|
||||
pr = tvtosbt(aitv->it_value) >> tc_precexp;
|
||||
timevaladd(&aitv->it_value, &ctv);
|
||||
sbt = tvtosbt(aitv->it_value);
|
||||
callout_reset_sbt(&p->p_itcallout, sbt, pr,
|
||||
realitexpire, p, C_ABSOLUTE);
|
||||
}
|
||||
*oitv = p->p_realtimer;
|
||||
p->p_realtimer = *aitv;
|
||||
@ -793,7 +798,8 @@ void
|
||||
realitexpire(void *arg)
|
||||
{
|
||||
struct proc *p;
|
||||
struct timeval ctv, ntv;
|
||||
struct timeval ctv;
|
||||
sbintime_t isbt;
|
||||
|
||||
p = (struct proc *)arg;
|
||||
kern_psignal(p, SIGALRM);
|
||||
@ -803,19 +809,17 @@ realitexpire(void *arg)
|
||||
wakeup(&p->p_itcallout);
|
||||
return;
|
||||
}
|
||||
for (;;) {
|
||||
isbt = tvtosbt(p->p_realtimer.it_interval);
|
||||
if (isbt >= sbt_timethreshold)
|
||||
getmicrouptime(&ctv);
|
||||
else
|
||||
microuptime(&ctv);
|
||||
do {
|
||||
timevaladd(&p->p_realtimer.it_value,
|
||||
&p->p_realtimer.it_interval);
|
||||
getmicrouptime(&ctv);
|
||||
if (timevalcmp(&p->p_realtimer.it_value, &ctv, >)) {
|
||||
ntv = p->p_realtimer.it_value;
|
||||
timevalsub(&ntv, &ctv);
|
||||
callout_reset(&p->p_itcallout, tvtohz(&ntv) - 1,
|
||||
realitexpire, p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
} while (timevalcmp(&p->p_realtimer.it_value, &ctv, <=));
|
||||
callout_reset_sbt(&p->p_itcallout, tvtosbt(p->p_realtimer.it_value),
|
||||
isbt >> tc_precexp, realitexpire, p, C_ABSOLUTE);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -830,8 +834,9 @@ itimerfix(struct timeval *tv)
|
||||
|
||||
if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000)
|
||||
return (EINVAL);
|
||||
if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
|
||||
tv->tv_usec = tick;
|
||||
if (tv->tv_sec == 0 && tv->tv_usec != 0 &&
|
||||
tv->tv_usec < (u_int)tick / 16)
|
||||
tv->tv_usec = (u_int)tick / 16;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user