Fix possible panic during ifnet detach in rtsock.
The panic can happen, when some application does dump of routing table using sysctl interface. To prevent this, set IFF_DYING flag in if_detach_internal() function, when ifnet under lock is removed from the chain. In sysctl_rtsock() take IFNET_RLOCK_NOSLEEP() to prevent ifnet detach during routes enumeration. In case, if some interface was detached in the time before we take the lock, add the check, that ifnet is not DYING. This prevents access to memory that could be freed after ifnet is unlinked. PR: 227720, 230498, 233306 Reviewed by: bz, eugen MFC after: 1 week Sponsored by: Yandex LLC Differential Revision: https://reviews.freebsd.org/D18338
This commit is contained in:
parent
a9b758a791
commit
4e66e79020
@ -1068,6 +1068,8 @@ if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp)
|
||||
CK_STAILQ_FOREACH(iter, &V_ifnet, if_link)
|
||||
if (iter == ifp) {
|
||||
CK_STAILQ_REMOVE(&V_ifnet, ifp, ifnet, if_link);
|
||||
if (!vmove)
|
||||
ifp->if_flags |= IFF_DYING;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
@ -1559,6 +1559,8 @@ sysctl_dumpentry(struct radix_node *rn, void *vw)
|
||||
struct rt_addrinfo info;
|
||||
struct sockaddr_storage ss;
|
||||
|
||||
IFNET_RLOCK_NOSLEEP_ASSERT();
|
||||
|
||||
if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
|
||||
return 0;
|
||||
if ((rt->rt_flags & RTF_HOST) == 0
|
||||
@ -1571,7 +1573,7 @@ sysctl_dumpentry(struct radix_node *rn, void *vw)
|
||||
info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(rt_key(rt),
|
||||
rt_mask(rt), &ss);
|
||||
info.rti_info[RTAX_GENMASK] = 0;
|
||||
if (rt->rt_ifp) {
|
||||
if (rt->rt_ifp && !(rt->rt_ifp->if_flags & IFF_DYING)) {
|
||||
info.rti_info[RTAX_IFP] = rt->rt_ifp->if_addr->ifa_addr;
|
||||
info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
|
||||
if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
|
||||
@ -1934,8 +1936,10 @@ sysctl_rtsock(SYSCTL_HANDLER_ARGS)
|
||||
rnh = rt_tables_get_rnh(fib, i);
|
||||
if (rnh != NULL) {
|
||||
RIB_RLOCK(rnh);
|
||||
IFNET_RLOCK_NOSLEEP();
|
||||
error = rnh->rnh_walktree(&rnh->head,
|
||||
sysctl_dumpentry, &w);
|
||||
IFNET_RUNLOCK_NOSLEEP();
|
||||
RIB_RUNLOCK(rnh);
|
||||
} else if (af != 0)
|
||||
error = EAFNOSUPPORT;
|
||||
|
Loading…
Reference in New Issue
Block a user