summaryrefslogtreecommitdiffstats
path: root/sys/net/rtsock.c
diff options
context:
space:
mode:
authorrstone <rstone@FreeBSD.org>2016-11-26 01:16:33 +0000
committerrstone <rstone@FreeBSD.org>2016-11-26 01:16:33 +0000
commit6622d4d3a9bcae4eefea44361d8b9d96d81a3073 (patch)
treeda698adb2876c15c8b1327cc25496ac0bd1ad0ed /sys/net/rtsock.c
parenta860155e70250266ffaffb42af7f2e421f330d8a (diff)
downloadFreeBSD-src-6622d4d3a9bcae4eefea44361d8b9d96d81a3073.zip
FreeBSD-src-6622d4d3a9bcae4eefea44361d8b9d96d81a3073.tar.gz
MFC r308580:
Don't read if_counters with if_addr_lock held Calling into an ifnet implementation with the if_addr_lock already held can cause a LOR and potentially a deadlock, as ifnet implementations typically can take the if_addr_lock after their own locks during configuration. Refactor a sysctl handler that was violating this to read if_counter data in a temporary buffer before the if_addr_lock is taken, and then copying the data in its final location later, when the if_addr_lock is held. PR: 194109 Reported by: Jean-Sebastien Pedron MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D8498 Reviewed by: sbruno
Diffstat (limited to 'sys/net/rtsock.c')
-rw-r--r--sys/net/rtsock.c21
1 files changed, 13 insertions, 8 deletions
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index 1ffb997..5f14287 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -1566,8 +1566,8 @@ sysctl_dumpentry(struct radix_node *rn, void *vw)
}
static int
-sysctl_iflist_ifml(struct ifnet *ifp, struct rt_addrinfo *info,
- struct walkarg *w, int len)
+sysctl_iflist_ifml(struct ifnet *ifp, const struct if_data *src_ifd,
+ struct rt_addrinfo *info, struct walkarg *w, int len)
{
struct if_msghdrl *ifm;
struct if_data *ifd;
@@ -1598,14 +1598,14 @@ sysctl_iflist_ifml(struct ifnet *ifp, struct rt_addrinfo *info,
ifd = &ifm->ifm_data;
}
- if_data_copy(ifp, ifd);
+ memcpy(ifd, src_ifd, sizeof(*ifd));
return (SYSCTL_OUT(w->w_req, (caddr_t)ifm, len));
}
static int
-sysctl_iflist_ifm(struct ifnet *ifp, struct rt_addrinfo *info,
- struct walkarg *w, int len)
+sysctl_iflist_ifm(struct ifnet *ifp, const struct if_data *src_ifd,
+ struct rt_addrinfo *info, struct walkarg *w, int len)
{
struct if_msghdr *ifm;
struct if_data *ifd;
@@ -1630,7 +1630,7 @@ sysctl_iflist_ifm(struct ifnet *ifp, struct rt_addrinfo *info,
ifd = &ifm->ifm_data;
}
- if_data_copy(ifp, ifd);
+ memcpy(ifd, src_ifd, sizeof(*ifd));
return (SYSCTL_OUT(w->w_req, (caddr_t)ifm, len));
}
@@ -1705,15 +1705,18 @@ sysctl_iflist(int af, struct walkarg *w)
{
struct ifnet *ifp;
struct ifaddr *ifa;
+ struct if_data ifd;
struct rt_addrinfo info;
int len, error = 0;
struct sockaddr_storage ss;
bzero((caddr_t)&info, sizeof(info));
+ bzero(&ifd, sizeof(ifd));
IFNET_RLOCK_NOSLEEP();
TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
if (w->w_arg && w->w_arg != ifp->if_index)
continue;
+ if_data_copy(ifp, &ifd);
IF_ADDR_RLOCK(ifp);
ifa = ifp->if_addr;
info.rti_info[RTAX_IFP] = ifa->ifa_addr;
@@ -1723,9 +1726,11 @@ sysctl_iflist(int af, struct walkarg *w)
info.rti_info[RTAX_IFP] = NULL;
if (w->w_req && w->w_tmem) {
if (w->w_op == NET_RT_IFLISTL)
- error = sysctl_iflist_ifml(ifp, &info, w, len);
+ error = sysctl_iflist_ifml(ifp, &ifd, &info, w,
+ len);
else
- error = sysctl_iflist_ifm(ifp, &info, w, len);
+ error = sysctl_iflist_ifm(ifp, &ifd, &info, w,
+ len);
if (error)
goto done;
}
OpenPOWER on IntegriCloud