kernel: fix alarm postnote race

when alarmkproc is commited to send the alarm note to the process,
the process might have exited already, or worse, being reused for
another process. pexit() zeros p->alarm at the beginning, but the
kalarmproc() might read p->alarm before pexit() zeroed it, decide
to send the note, then get preempted and pexit() releases the proc.
once kalarmproc() is resumed, the proc might be already something
different and we send the note to the wrong thing.

we now check p->alarm under the debug qlock. that way, pexit()
cannot make progress while we test the condition.

remove the error label arround postnote(). postnote does not raise
error.
This commit is contained in:
cinap_lenrek 2014-01-01 05:14:38 +01:00
parent 0feb6e06af
commit f481ac716d

View file

@ -11,7 +11,7 @@ void
alarmkproc(void*) alarmkproc(void*)
{ {
Proc *rp; Proc *rp;
ulong now; ulong now, when;
while(waserror()) while(waserror())
; ;
@ -19,20 +19,20 @@ alarmkproc(void*)
for(;;){ for(;;){
now = MACHP(0)->ticks; now = MACHP(0)->ticks;
qlock(&alarms); qlock(&alarms);
while((rp = alarms.head) && (long)(now - rp->alarm) >= 0){ for(rp = alarms.head; rp != nil; rp = rp->palarm){
if(rp->alarm != 0L){ if((when = rp->alarm) == 0)
if(canqlock(&rp->debug)){ continue;
if(!waserror()){ if((long)(now - when) < 0)
postnote(rp, 0, "alarm", NUser); break;
poperror(); if(!canqlock(&rp->debug))
} break;
qunlock(&rp->debug); if(rp->alarm != 0){
rp->alarm = 0L; postnote(rp, 0, "alarm", NUser);
}else rp->alarm = 0;
break;
} }
alarms.head = rp->palarm; qunlock(&rp->debug);
} }
alarms.head = rp;
qunlock(&alarms); qunlock(&alarms);
sleep(&alarmr, return0, 0); sleep(&alarmr, return0, 0);
@ -46,13 +46,15 @@ void
checkalarms(void) checkalarms(void)
{ {
Proc *p; Proc *p;
ulong now; ulong now, when;
p = alarms.head; p = alarms.head;
now = MACHP(0)->ticks; if(p != nil){
now = MACHP(0)->ticks;
if(p != nil && (long)(now - p->alarm) >= 0) when = p->alarm;
wakeup(&alarmr); if(when == 0 || (long)(now - when) >= 0)
wakeup(&alarmr);
}
} }
ulong ulong
@ -61,10 +63,9 @@ procalarm(ulong time)
Proc **l, *f; Proc **l, *f;
ulong when, old; ulong when, old;
if(up->alarm) old = up->alarm;
old = tk2ms(up->alarm - MACHP(0)->ticks); if(old)
else old = tk2ms(old - MACHP(0)->ticks);
old = 0;
if(time == 0) { if(time == 0) {
up->alarm = 0; up->alarm = 0;
return old; return old;