Fix crash in hybrid E2E mode.
Richard Hill reported an occasional NULL pointer deference in
port_delay_request() when in hybrid mode.
if (p->hybrid_e2e) {
struct ptp_message *dst = TAILQ_FIRST(&p->best->messages);
msg->address = dst->address;
...
}
The code assumes that the p->best->messages list can't be empty
because:
The function, port_delay_request(), is called only when
FD_DELAY_TIMER expires. That timer is only set by the function,
port_set_delay_tmo(), which is called:
1. from process_delay_resp(), but only when state is UNCALIBRATED
or SLAVE.
2. from port_e2e_transition(), but only when state is UNCALIBRATED
or SLAVE.
Looking at handle_state_decision_event(), a port can only enter
UNCALIBRATED or SLAVE when it has a valid foreign master record,
ie p->best->messages is not null.
A port also only clears p->best->messages when it leaves
UNCALIBRATED or SLAVE, at which point the FD_DELAY_TIMER is also
cleared.
*However* the p->best->messages list *can* be empty if the
FD_ANNOUNCE_TIMER and the FD_DELAY_TIMER expire at the same time. In
this case, the poll() call indicates events on both file descriptors.
The announce timeout is handled like this:
case FD_ANNOUNCE_TIMER:
case FD_SYNC_RX_TIMER:
if (p->best)
fc_clear(p->best);
So then the port_delay_request() call de-references the null
TAILQ_FIRST message pointer.
This patch fixes the issue by re-ordering the timer file descriptors
within the polling list.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
Reported-by: Richard Hill <plonta@gmx.de>
This commit is contained in:
parent
cacf272d1c
commit
a8b66ce7f2
10
fd.h
10
fd.h
@ -22,12 +22,18 @@
|
|||||||
|
|
||||||
#define N_TIMER_FDS 6
|
#define N_TIMER_FDS 6
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The order matters here. The DELAY timer must appear before the
|
||||||
|
* ANNOUNCE and SYNC_RX timers in order to correctly handle the case
|
||||||
|
* when the DELAY timer and one of the other two expire during the
|
||||||
|
* same call to poll().
|
||||||
|
*/
|
||||||
enum {
|
enum {
|
||||||
FD_EVENT,
|
FD_EVENT,
|
||||||
FD_GENERAL,
|
FD_GENERAL,
|
||||||
|
FD_DELAY_TIMER,
|
||||||
FD_ANNOUNCE_TIMER,
|
FD_ANNOUNCE_TIMER,
|
||||||
FD_SYNC_RX_TIMER,
|
FD_SYNC_RX_TIMER,
|
||||||
FD_DELAY_TIMER,
|
|
||||||
FD_QUALIFICATION_TIMER,
|
FD_QUALIFICATION_TIMER,
|
||||||
FD_MANNO_TIMER,
|
FD_MANNO_TIMER,
|
||||||
FD_SYNC_TX_TIMER,
|
FD_SYNC_TX_TIMER,
|
||||||
@ -35,6 +41,8 @@ enum {
|
|||||||
N_POLLFD,
|
N_POLLFD,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define FD_FIRST_TIMER FD_DELAY_TIMER
|
||||||
|
|
||||||
struct fdarray {
|
struct fdarray {
|
||||||
int fd[N_POLLFD];
|
int fd[N_POLLFD];
|
||||||
};
|
};
|
||||||
|
|||||||
6
port.c
6
port.c
@ -1545,7 +1545,7 @@ void port_disable(struct port *p)
|
|||||||
transport_close(p->trp, &p->fda);
|
transport_close(p->trp, &p->fda);
|
||||||
|
|
||||||
for (i = 0; i < N_TIMER_FDS; i++) {
|
for (i = 0; i < N_TIMER_FDS; i++) {
|
||||||
close(p->fda.fd[FD_ANNOUNCE_TIMER + i]);
|
close(p->fda.fd[FD_FIRST_TIMER + i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep rtnl socket to get link status info. */
|
/* Keep rtnl socket to get link status info. */
|
||||||
@ -1590,7 +1590,7 @@ int port_initialize(struct port *p)
|
|||||||
goto no_tropen;
|
goto no_tropen;
|
||||||
|
|
||||||
for (i = 0; i < N_TIMER_FDS; i++) {
|
for (i = 0; i < N_TIMER_FDS; i++) {
|
||||||
p->fda.fd[FD_ANNOUNCE_TIMER + i] = fd[i];
|
p->fda.fd[FD_FIRST_TIMER + i] = fd[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port_set_announce_tmo(p))
|
if (port_set_announce_tmo(p))
|
||||||
@ -1628,7 +1628,7 @@ static int port_renew_transport(struct port *p)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
transport_close(p->trp, &p->fda);
|
transport_close(p->trp, &p->fda);
|
||||||
port_clear_fda(p, FD_ANNOUNCE_TIMER);
|
port_clear_fda(p, FD_FIRST_TIMER);
|
||||||
res = transport_open(p->trp, p->iface, &p->fda, p->timestamping);
|
res = transport_open(p->trp, p->iface, &p->fda, p->timestamping);
|
||||||
/* Need to call clock_fda_changed even if transport_open failed in
|
/* Need to call clock_fda_changed even if transport_open failed in
|
||||||
* order to update clock to the now closed descriptors. */
|
* order to update clock to the now closed descriptors. */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user