Adapt the fix in r341008 to correctly work with EBR.
IFNET_RLOCK_NOSLEEP() is epoch_enter_preempt() in FreeBSD 12+. Holding it in sysctl_rtsock() doesn't protect us from ifnet unlinking, because unlinking occurs with IFNET_WLOCK(), that is rw_wlock+sx_xlock, and it doesn check that concurrent code is running in epoch section. But while we are in epoch section, we should be able to do access to ifnet's fields, even it was unlinked. Thus do not change if_addr and if_hw_addr fields in ifnet_detach_internal() to NULL, since rtsock code can do access to these fields and this is allowed while it is running in epoch section. This should fix the race, when ifnet_detach_internal() unlinks ifnet after we checked it for IFF_DYING in sysctl_dumpentry. Move free(ifp->if_hw_addr) into ifnet_free_internal(). Also remove the NULL check for ifp->if_description, since free(9) can correctly handle NULL pointer. MFC after: 1 week
This commit is contained in:
parent
fc6ebb297b
commit
851073551d
10
sys/net/if.c
10
sys/net/if.c
@ -597,8 +597,6 @@ if_free_internal(struct ifnet *ifp)
|
||||
#ifdef MAC
|
||||
mac_ifnet_destroy(ifp);
|
||||
#endif /* MAC */
|
||||
if (ifp->if_description != NULL)
|
||||
free(ifp->if_description, M_IFDESCR);
|
||||
IF_AFDATA_DESTROY(ifp);
|
||||
IF_ADDR_LOCK_DESTROY(ifp);
|
||||
ifq_delete(&ifp->if_snd);
|
||||
@ -606,6 +604,8 @@ if_free_internal(struct ifnet *ifp)
|
||||
for (int i = 0; i < IFCOUNTERS; i++)
|
||||
counter_u64_free(ifp->if_counters[i]);
|
||||
|
||||
free(ifp->if_description, M_IFDESCR);
|
||||
free(ifp->if_hw_addr, M_IFADDR);
|
||||
free(ifp, M_IFNET);
|
||||
}
|
||||
|
||||
@ -1184,14 +1184,8 @@ if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp)
|
||||
if_dead(ifp);
|
||||
|
||||
/*
|
||||
* Remove link ifaddr pointer and maybe decrement if_index.
|
||||
* Clean up all addresses.
|
||||
*/
|
||||
free(ifp->if_hw_addr, M_IFADDR);
|
||||
ifp->if_hw_addr = NULL;
|
||||
ifp->if_addr = NULL;
|
||||
|
||||
/* We can now free link ifaddr. */
|
||||
IF_ADDR_WLOCK(ifp);
|
||||
if (!CK_STAILQ_EMPTY(&ifp->if_addrhead)) {
|
||||
ifa = CK_STAILQ_FIRST(&ifp->if_addrhead);
|
||||
|
Loading…
Reference in New Issue
Block a user