port: Avoid calling freed servo after switching PHC.

In port_synchronize(), when the clock returned SERVO_UNLOCKED and
port_dispatch() triggered a switch of the PHC, the variable "s" would
point to a servo which was already freed and the following call of
servo_offset_threshold() would read invalid memory.

Don't save the servo before dispatching the port.

Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
Fixes: 3f5f5653d7 ("port: Add interval update mechanism.")
master
Miroslav Lichvar 2019-09-26 15:54:31 +02:00 committed by Richard Cochran
parent f9e84e69bf
commit e20d8228f9
1 changed files with 2 additions and 4 deletions

6
port.c
View File

@ -1137,7 +1137,6 @@ static void port_synchronize(struct port *p,
{ {
enum servo_state state, last_state; enum servo_state state, last_state;
tmv_t t1, t1c, t2, c1, c2; tmv_t t1, t1c, t2, c1, c2;
struct servo *s;
port_set_sync_rx_tmo(p); port_set_sync_rx_tmo(p);
@ -1147,13 +1146,12 @@ static void port_synchronize(struct port *p,
c2 = correction_to_tmv(correction2); c2 = correction_to_tmv(correction2);
t1c = tmv_add(t1, tmv_add(c1, c2)); t1c = tmv_add(t1, tmv_add(c1, c2));
s = clock_servo(p->clock);
last_state = clock_servo_state(p->clock); last_state = clock_servo_state(p->clock);
state = clock_synchronize(p->clock, t2, t1c); state = clock_synchronize(p->clock, t2, t1c);
switch (state) { switch (state) {
case SERVO_UNLOCKED: case SERVO_UNLOCKED:
port_dispatch(p, EV_SYNCHRONIZATION_FAULT, 0); port_dispatch(p, EV_SYNCHRONIZATION_FAULT, 0);
if (servo_offset_threshold(s) != 0 && if (servo_offset_threshold(clock_servo(p->clock)) != 0 &&
sync_interval != p->initialLogSyncInterval) { sync_interval != p->initialLogSyncInterval) {
p->logPdelayReqInterval = p->logMinPdelayReqInterval; p->logPdelayReqInterval = p->logMinPdelayReqInterval;
p->logSyncInterval = p->initialLogSyncInterval; p->logSyncInterval = p->initialLogSyncInterval;
@ -1186,7 +1184,7 @@ static void port_synchronize(struct port *p,
* The most likely reason for this to happen is the * The most likely reason for this to happen is the
* master daemon re-initialized due to some fault. * master daemon re-initialized due to some fault.
*/ */
servo_reset(s); servo_reset(clock_servo(p->clock));
port_dispatch(p, EV_SYNCHRONIZATION_FAULT, 0); port_dispatch(p, EV_SYNCHRONIZATION_FAULT, 0);
} }
break; break;