Fix a race between kern_setitimer() and realitexpire(), where the
callout is started before kern_setitimer() acquires process mutex, but looses a race and kern_setitimer() gets the process mutex before the callout. Then, assuming that new specified struct itimerval has it_interval zero, but it_value non-zero, the callout, after it starts executing again, clears p->p_realtimer.it_value, but kern_setitimer() already rescheduled the callout. As the result of the race, both p_realtimer is zero, and the callout is rescheduled. Then, in the exit1(), the exit code sees that it_value is zero and does not even try to stop the callout. This allows the struct proc to be reused and eventually the armed callout is re-initialized. The consequence is the corrupted callwheel tailq. Use process mutex to interlock the callout start, which fixes the race. Reported and tested by: pho Reviewed by: jhb MFC after: 2 weeks
This commit is contained in:
parent
9bdf6ccab3
commit
f7e50ea722
@ -498,7 +498,7 @@ proc0_init(void *dummy __unused)
|
||||
strncpy(p->p_comm, "kernel", sizeof (p->p_comm));
|
||||
strncpy(td->td_name, "swapper", sizeof (td->td_name));
|
||||
|
||||
callout_init(&p->p_itcallout, CALLOUT_MPSAFE);
|
||||
callout_init_mtx(&p->p_itcallout, &p->p_mtx, 0);
|
||||
callout_init_mtx(&p->p_limco, &p->p_mtx, 0);
|
||||
callout_init(&td->td_slpcallout, CALLOUT_MPSAFE);
|
||||
|
||||
|
@ -591,7 +591,7 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2,
|
||||
LIST_INIT(&p2->p_children);
|
||||
LIST_INIT(&p2->p_orphans);
|
||||
|
||||
callout_init(&p2->p_itcallout, CALLOUT_MPSAFE);
|
||||
callout_init_mtx(&p2->p_itcallout, &p2->p_mtx, 0);
|
||||
|
||||
/*
|
||||
* If PF_FORK is set, the child process inherits the
|
||||
|
@ -788,13 +788,11 @@ realitexpire(void *arg)
|
||||
struct timeval ctv, ntv;
|
||||
|
||||
p = (struct proc *)arg;
|
||||
PROC_LOCK(p);
|
||||
kern_psignal(p, SIGALRM);
|
||||
if (!timevalisset(&p->p_realtimer.it_interval)) {
|
||||
timevalclear(&p->p_realtimer.it_value);
|
||||
if (p->p_flag & P_WEXIT)
|
||||
wakeup(&p->p_itcallout);
|
||||
PROC_UNLOCK(p);
|
||||
return;
|
||||
}
|
||||
for (;;) {
|
||||
@ -806,7 +804,6 @@ realitexpire(void *arg)
|
||||
timevalsub(&ntv, &ctv);
|
||||
callout_reset(&p->p_itcallout, tvtohz(&ntv) - 1,
|
||||
realitexpire, p);
|
||||
PROC_UNLOCK(p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user