infiniband: Widen NET_EPOCH coverage

From static code analysis, some device drivers (cxgbe, mlx4, mthca, and qlnx)
do not enter net epoch before lagg_input_infiniband(). If IPoIB interface is a
member of lagg(4) interface, and after returning from lagg_input_infiniband()
the receiving interface of mbuf is set to lagg(4) interface, then when
concurrently destroying the lagg(4) interface, there is a small window that the
interface gets destroyed and becomes invalid before infiniband_input() re-enter
net epoch, thus leading use-after-free.

Widen NET_EPOCH coverage to prevent use-after-free.

Thanks hselasky@ for testing with mlx5 devices.

Reviewed by:	hselasky
Tested by:	hselasky
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D39275
This commit is contained in:
Zhenlei Huang 2023-04-03 00:51:49 +08:00
parent 3091d980f5
commit 90820ef121
2 changed files with 3 additions and 6 deletions

View File

@ -417,6 +417,7 @@ infiniband_input(struct ifnet *ifp, struct mbuf *m)
int isr;
CURVNET_SET_QUIET(ifp->if_vnet);
NET_EPOCH_ENTER(et);
if ((ifp->if_flags & IFF_UP) == 0) {
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
@ -504,10 +505,9 @@ infiniband_input(struct ifnet *ifp, struct mbuf *m)
mac_ifnet_create_mbuf(ifp, m);
#endif
/* Allow monitor mode to claim this frame, after stats are updated. */
NET_EPOCH_ENTER(et);
netisr_dispatch(isr, m);
NET_EPOCH_EXIT(et);
done:
NET_EPOCH_EXIT(et);
CURVNET_RESTORE();
}

View File

@ -2192,16 +2192,14 @@ lagg_input_ethernet(struct ifnet *ifp, struct mbuf *m)
static struct mbuf *
lagg_input_infiniband(struct ifnet *ifp, struct mbuf *m)
{
struct epoch_tracker et;
struct lagg_port *lp = ifp->if_lagg;
struct lagg_softc *sc = lp->lp_softc;
struct ifnet *scifp = sc->sc_ifp;
NET_EPOCH_ENTER(et);
NET_EPOCH_ASSERT();
if ((scifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
lp->lp_detaching != 0 ||
sc->sc_proto == LAGG_PROTO_NONE) {
NET_EPOCH_EXIT(et);
m_freem(m);
return (NULL);
}
@ -2214,7 +2212,6 @@ lagg_input_infiniband(struct ifnet *ifp, struct mbuf *m)
m = NULL;
}
NET_EPOCH_EXIT(et);
return (m);
}