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
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
FD_EVENT,
|
||||
FD_GENERAL,
|
||||
FD_DELAY_TIMER,
|
||||
FD_ANNOUNCE_TIMER,
|
||||
FD_SYNC_RX_TIMER,
|
||||
FD_DELAY_TIMER,
|
||||
FD_QUALIFICATION_TIMER,
|
||||
FD_MANNO_TIMER,
|
||||
FD_SYNC_TX_TIMER,
|
||||
@ -35,6 +41,8 @@ enum {
|
||||
N_POLLFD,
|
||||
};
|
||||
|
||||
#define FD_FIRST_TIMER FD_DELAY_TIMER
|
||||
|
||||
struct fdarray {
|
||||
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);
|
||||
|
||||
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. */
|
||||
@ -1590,7 +1590,7 @@ int port_initialize(struct port *p)
|
||||
goto no_tropen;
|
||||
|
||||
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))
|
||||
@ -1628,7 +1628,7 @@ static int port_renew_transport(struct port *p)
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
/* Need to call clock_fda_changed even if transport_open failed in
|
||||
* order to update clock to the now closed descriptors. */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user