diff options
author | qingli <qingli@FreeBSD.org> | 2009-10-20 17:55:42 +0000 |
---|---|---|
committer | qingli <qingli@FreeBSD.org> | 2009-10-20 17:55:42 +0000 |
commit | eeb330ad1e5dc0d19dff4214fc5a6380ddd50173 (patch) | |
tree | 3c74fa53e334bf6ed6b290654dc39a2ae2673371 /sys/netinet | |
parent | 8bb7f5309bf62bb21a6bc77ddbe7f2c67f8d8f0d (diff) | |
download | FreeBSD-src-eeb330ad1e5dc0d19dff4214fc5a6380ddd50173.zip FreeBSD-src-eeb330ad1e5dc0d19dff4214fc5a6380ddd50173.tar.gz |
In the ARP callout timer expiration function, the current time_second
is compared against the entry expiration time value (that was set based
on time_second) to check if the current time is larger than the set
expiration time. Due to the +/- timer granularity value, the comparison
returns false, causing the alternative code to be executed. The
alternative code path freed the memory without removing that entry
from the table list, causing a use-after-free bug.
Reviewed by: discussed with kmacy
MFC after: immediately
Verified by: rnoland, yongari
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/if_ether.c | 18 |
1 files changed, 9 insertions, 9 deletions
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index 45cee89..4737b13 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -175,18 +175,18 @@ arptimer(void *arg) CURVNET_SET(ifp->if_vnet); IF_AFDATA_LOCK(ifp); LLE_WLOCK(lle); - if (((lle->la_flags & LLE_DELETED) || - (time_second >= lle->la_expire)) && - (!callout_pending(&lle->la_timer) && + if ((!callout_pending(&lle->la_timer) && callout_active(&lle->la_timer))) { (void) llentry_free(lle); ARPSTAT_INC(timeouts); - } else { - /* - * Still valid, just drop our reference - */ - LLE_FREE_LOCKED(lle); + } +#ifdef DIAGNOSTICS + else { + struct sockaddr *l3addr = L3_ADDR(lle); + log(LOG_INFO, "arptimer issue: %p, IPv4 address: \"%s\"\n", lle, + inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr)); } +#endif IF_AFDATA_UNLOCK(ifp); CURVNET_RESTORE(); } @@ -377,7 +377,7 @@ retry: if (renew) { LLE_ADDREF(la); - la->la_expire = time_second; + la->la_expire = time_second + V_arpt_down; callout_reset(&la->la_timer, hz * V_arpt_down, arptimer, la); la->la_asked++; LLE_WUNLOCK(la); |