Fix an overflow that can cause spuriously short epoll timeouts.

Lease times and arp timeouts are all calculated using long long,
but epoll takes its timeout argument as an int.  Guard against
timeouts > INT_MAX but < UINT_MAX wrapping and causing spuriously
short timeouts when converted to a signed int.

This problem has been observed in the wild.  Thanks to thypon
for a detailed strace that pointed me towards this issue.
This commit is contained in:
Nicholas J. Kain 2015-05-27 12:58:42 -04:00
parent ba875d4b2e
commit abb1b54bfe

View File

@ -394,19 +394,22 @@ static void do_ndhc_work(void)
} }
int prev_timeout = timeout; int prev_timeout = timeout;
long long tt;
arp_wake_ts = arp_get_wake_ts(); arp_wake_ts = arp_get_wake_ts();
if (arp_wake_ts < 0 && cs.dhcp_wake_ts < 0) { if (arp_wake_ts < 0 && cs.dhcp_wake_ts < 0) {
timeout = -1; timeout = -1;
continue; continue;
} else if (arp_wake_ts < 0) { } else if (arp_wake_ts < 0) {
timeout = cs.dhcp_wake_ts - nowts; tt = cs.dhcp_wake_ts - nowts;
} else if (cs.dhcp_wake_ts < 0) { } else if (cs.dhcp_wake_ts < 0) {
timeout = arp_wake_ts - nowts; tt = arp_wake_ts - nowts;
} else { } else {
timeout = (arp_wake_ts < cs.dhcp_wake_ts ? tt = (arp_wake_ts < cs.dhcp_wake_ts ?
arp_wake_ts : cs.dhcp_wake_ts) - nowts; arp_wake_ts : cs.dhcp_wake_ts) - nowts;
} }
if (tt > INT_MAX) tt = INT_MAX;
timeout = tt;
if (timeout < 0) if (timeout < 0)
timeout = 0; timeout = 0;