Do not return unlocked/unreferenced lle in arpresolve/nd6_storelladdr -

return lle flags IFF needed.
Do not pass rte to arpresolve - pass is_gateway flag instead.
This commit is contained in:
Alexander V. Chernikov 2014-11-27 23:06:25 +00:00
parent c69aeaad14
commit 74860d4f7c
12 changed files with 72 additions and 59 deletions

View File

@ -103,9 +103,7 @@ arc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
u_int8_t atype, adst; u_int8_t atype, adst;
int loop_copy = 0; int loop_copy = 0;
int isphds; int isphds;
#if defined(INET) || defined(INET6) int is_gw;
struct llentry *lle;
#endif
if (!((ifp->if_flags & IFF_UP) && if (!((ifp->if_flags & IFF_UP) &&
(ifp->if_drv_flags & IFF_DRV_RUNNING))) (ifp->if_drv_flags & IFF_DRV_RUNNING)))
@ -125,8 +123,11 @@ arc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
else if (ifp->if_flags & IFF_NOARP) else if (ifp->if_flags & IFF_NOARP)
adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF; adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF;
else { else {
error = arpresolve(ifp, ro ? ro->ro_rt : NULL, is_gw = 0;
m, dst, &adst, &lle); if (ro != NULL && ro->ro_rt != NULL &&
(ro->ro_rt->rt_flags & RTF_GATEWAY) != 0)
is_gw = 1;
error = arpresolve(ifp, is_gw, m, dst, &adst, NULL);
if (error) if (error)
return (error == EWOULDBLOCK ? 0 : error); return (error == EWOULDBLOCK ? 0 : error);
} }
@ -164,7 +165,7 @@ arc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
#endif #endif
#ifdef INET6 #ifdef INET6
case AF_INET6: case AF_INET6:
error = nd6_storelladdr(ifp, m, dst, (u_char *)&adst, &lle); error = nd6_storelladdr(ifp, m, dst, (u_char *)&adst, NULL);
if (error) if (error)
return (error); return (error);
atype = ARCTYPE_INET6; atype = ARCTYPE_INET6;

View File

@ -154,11 +154,18 @@ ether_output(struct ifnet *ifp, struct mbuf *m,
struct pf_mtag *t; struct pf_mtag *t;
int loop_copy = 1; int loop_copy = 1;
int hlen; /* link layer header length */ int hlen; /* link layer header length */
int is_gw = 0;
uint32_t pflags = 0;
if (ro != NULL) { if (ro != NULL) {
if (!(m->m_flags & (M_BCAST | M_MCAST))) if (!(m->m_flags & (M_BCAST | M_MCAST))) {
lle = ro->ro_lle; lle = ro->ro_lle;
if (lle != NULL)
pflags = lle->la_flags;
}
rt0 = ro->ro_rt; rt0 = ro->ro_rt;
if (rt0 != NULL && (rt0->rt_flags & RTF_GATEWAY) != 0)
is_gw = 1;
} }
#ifdef MAC #ifdef MAC
error = mac_ifnet_check_transmit(ifp, m); error = mac_ifnet_check_transmit(ifp, m);
@ -177,10 +184,10 @@ ether_output(struct ifnet *ifp, struct mbuf *m,
switch (dst->sa_family) { switch (dst->sa_family) {
#ifdef INET #ifdef INET
case AF_INET: case AF_INET:
if (lle != NULL && (lle->la_flags & LLE_VALID)) if (lle != NULL && (pflags & LLE_VALID) != 0)
memcpy(edst, &lle->ll_addr.mac16, sizeof(edst)); memcpy(edst, &lle->ll_addr.mac16, sizeof(edst));
else else
error = arpresolve(ifp, rt0, m, dst, edst, &lle); error = arpresolve(ifp, is_gw, m, dst, edst, &pflags);
if (error) if (error)
return (error == EWOULDBLOCK ? 0 : error); return (error == EWOULDBLOCK ? 0 : error);
type = htons(ETHERTYPE_IP); type = htons(ETHERTYPE_IP);
@ -215,10 +222,11 @@ ether_output(struct ifnet *ifp, struct mbuf *m,
#endif #endif
#ifdef INET6 #ifdef INET6
case AF_INET6: case AF_INET6:
if (lle != NULL && (lle->la_flags & LLE_VALID)) if (lle != NULL && (pflags & LLE_VALID))
memcpy(edst, &lle->ll_addr.mac16, sizeof(edst)); memcpy(edst, &lle->ll_addr.mac16, sizeof(edst));
else else
error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle); error = nd6_storelladdr(ifp, m, dst, (u_char *)edst,
&pflags);
if (error) if (error)
return error; return error;
type = htons(ETHERTYPE_IPV6); type = htons(ETHERTYPE_IPV6);
@ -241,7 +249,7 @@ ether_output(struct ifnet *ifp, struct mbuf *m,
senderr(EAFNOSUPPORT); senderr(EAFNOSUPPORT);
} }
if (lle != NULL && (lle->la_flags & LLE_IFADDR)) { if ((pflags & LLE_IFADDR) != 0) {
update_mbuf_csumflags(m, m); update_mbuf_csumflags(m, m);
return (if_simloop(ifp, m, dst->sa_family, 0)); return (if_simloop(ifp, m, dst->sa_family, 0));
} }

View File

@ -101,9 +101,7 @@ fddi_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
int loop_copy = 0, error = 0, hdrcmplt = 0; int loop_copy = 0, error = 0, hdrcmplt = 0;
u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN]; u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN];
struct fddi_header *fh; struct fddi_header *fh;
#if defined(INET) || defined(INET6) int is_gw;
struct llentry *lle;
#endif
#ifdef MAC #ifdef MAC
error = mac_ifnet_check_transmit(ifp, m); error = mac_ifnet_check_transmit(ifp, m);
@ -121,11 +119,11 @@ fddi_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
switch (dst->sa_family) { switch (dst->sa_family) {
#ifdef INET #ifdef INET
case AF_INET: { case AF_INET: {
struct rtentry *rt0 = NULL; is_gw = 0;
if (ro != NULL && ro->ro_rt != NULL &&
if (ro != NULL) (ro->ro_rt->rt_flags & RTF_GATEWAY) != 0)
rt0 = ro->ro_rt; is_gw = 1;
error = arpresolve(ifp, rt0, m, dst, edst, &lle); error = arpresolve(ifp, is_gw, m, dst, edst, NULL);
if (error) if (error)
return (error == EWOULDBLOCK ? 0 : error); return (error == EWOULDBLOCK ? 0 : error);
type = htons(ETHERTYPE_IP); type = htons(ETHERTYPE_IP);
@ -161,7 +159,7 @@ fddi_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
#endif /* INET */ #endif /* INET */
#ifdef INET6 #ifdef INET6
case AF_INET6: case AF_INET6:
error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle); error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, NULL);
if (error) if (error)
return (error); /* Something bad happened */ return (error); /* Something bad happened */
type = htons(ETHERTYPE_IPV6); type = htons(ETHERTYPE_IPV6);

View File

@ -89,9 +89,7 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
struct mbuf *mtail; struct mbuf *mtail;
int unicast, dgl, foff; int unicast, dgl, foff;
static int next_dgl; static int next_dgl;
#if defined(INET) || defined(INET6) int is_gw;
struct llentry *lle;
#endif
#ifdef MAC #ifdef MAC
error = mac_ifnet_check_transmit(ifp, m); error = mac_ifnet_check_transmit(ifp, m);
@ -140,7 +138,11 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
* doesn't fit into the arp model. * doesn't fit into the arp model.
*/ */
if (unicast) { if (unicast) {
error = arpresolve(ifp, ro ? ro->ro_rt : NULL, m, dst, (u_char *) destfw, &lle); is_gw = 0;
if (ro != NULL && ro->ro_rt != NULL &&
(ro->ro_rt->rt_flags & RTF_GATEWAY) != 0)
is_gw = 1;
error = arpresolve(ifp, is_gw, m, dst, (u_char *) destfw, NULL);
if (error) if (error)
return (error == EWOULDBLOCK ? 0 : error); return (error == EWOULDBLOCK ? 0 : error);
} }
@ -170,7 +172,7 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
case AF_INET6: case AF_INET6:
if (unicast) { if (unicast) {
error = nd6_storelladdr(fc->fc_ifp, m, dst, error = nd6_storelladdr(fc->fc_ifp, m, dst,
(u_char *) destfw, &lle); (u_char *) destfw, NULL);
if (error) if (error)
return (error); return (error);
} }

View File

@ -212,12 +212,13 @@ iso88025_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
struct iso88025_header gen_th; struct iso88025_header gen_th;
struct sockaddr_dl *sdl = NULL; struct sockaddr_dl *sdl = NULL;
struct rtentry *rt0 = NULL; struct rtentry *rt0 = NULL;
#if defined(INET) || defined(INET6) int is_gw = 0;
struct llentry *lle;
#endif
if (ro != NULL) if (ro != NULL) {
rt0 = ro->ro_rt; rt0 = ro->ro_rt;
if (rt0 != NULL && (rt0->rt_flags & RTF_GATEWAY) != 0)
is_gw = 1;
}
#ifdef MAC #ifdef MAC
error = mac_ifnet_check_transmit(ifp, m); error = mac_ifnet_check_transmit(ifp, m);
@ -257,7 +258,7 @@ iso88025_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
switch (dst->sa_family) { switch (dst->sa_family) {
#ifdef INET #ifdef INET
case AF_INET: case AF_INET:
error = arpresolve(ifp, rt0, m, dst, edst, &lle); error = arpresolve(ifp, is_gw, m, dst, edst, NULL);
if (error) if (error)
return (error == EWOULDBLOCK ? 0 : error); return (error == EWOULDBLOCK ? 0 : error);
snap_type = ETHERTYPE_IP; snap_type = ETHERTYPE_IP;
@ -292,7 +293,7 @@ iso88025_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
#endif /* INET */ #endif /* INET */
#ifdef INET6 #ifdef INET6
case AF_INET6: case AF_INET6:
error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle); error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, NULL);
if (error) if (error)
return (error); return (error);
snap_type = ETHERTYPE_IPV6; snap_type = ETHERTYPE_IPV6;

View File

@ -286,19 +286,20 @@ arprequest(struct ifnet *ifp, const struct in_addr *sip,
* Resolve an IP address into an ethernet address. * Resolve an IP address into an ethernet address.
* On input: * On input:
* ifp is the interface we use * ifp is the interface we use
* rt0 is the route to the final destination (possibly useless) * is_gw != if @dst represents gateway to some destination
* m is the mbuf. May be NULL if we don't have a packet. * m is the mbuf. May be NULL if we don't have a packet.
* dst is the next hop, * dst is the next hop,
* desten is where we want the address. * desten is where we want the address.
* flags returns lle entry flags.
* *
* On success, desten is filled in and the function returns 0; * On success, desten and flags are filled in and the function returns 0;
* If the packet must be held pending resolution, we return EWOULDBLOCK * If the packet must be held pending resolution, we return EWOULDBLOCK
* On other errors, we return the corresponding error code. * On other errors, we return the corresponding error code.
* Note that m_freem() handles NULL. * Note that m_freem() handles NULL.
*/ */
int int
arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
const struct sockaddr *dst, u_char *desten, struct llentry **lle) const struct sockaddr *dst, u_char *desten, uint32_t *pflags)
{ {
struct llentry *la = 0; struct llentry *la = 0;
u_int flags = 0; u_int flags = 0;
@ -306,7 +307,9 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m,
struct mbuf *next = NULL; struct mbuf *next = NULL;
int error, renew; int error, renew;
*lle = NULL; if (pflags != NULL)
*pflags = 0;
if (m != NULL) { if (m != NULL) {
if (m->m_flags & M_BCAST) { if (m->m_flags & M_BCAST) {
/* broadcast */ /* broadcast */
@ -354,7 +357,8 @@ retry:
la->la_preempt--; la->la_preempt--;
} }
*lle = la; if (pflags != NULL)
*pflags = la->la_flags;
error = 0; error = 0;
goto done; goto done;
} }
@ -412,8 +416,7 @@ retry:
if (la->la_asked < V_arp_maxtries) if (la->la_asked < V_arp_maxtries)
error = EWOULDBLOCK; /* First request. */ error = EWOULDBLOCK; /* First request. */
else else
error = rt0 != NULL && (rt0->rt_flags & RTF_GATEWAY) ? error = is_gw != 0 ? EHOSTUNREACH : EHOSTDOWN;
EHOSTUNREACH : EHOSTDOWN;
if (renew) { if (renew) {
int canceled; int canceled;

View File

@ -112,11 +112,10 @@ struct sockaddr_inarp {
extern u_char ether_ipmulticast_min[ETHER_ADDR_LEN]; extern u_char ether_ipmulticast_min[ETHER_ADDR_LEN];
extern u_char ether_ipmulticast_max[ETHER_ADDR_LEN]; extern u_char ether_ipmulticast_max[ETHER_ADDR_LEN];
struct llentry;
struct ifaddr; struct ifaddr;
int arpresolve(struct ifnet *ifp, struct rtentry *rt, struct mbuf *m, int arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
const struct sockaddr *dst, u_char *desten, struct llentry **lle); const struct sockaddr *dst, u_char *desten, uint32_t *pflags);
void arprequest(struct ifnet *, const struct in_addr *, void arprequest(struct ifnet *, const struct in_addr *,
const struct in_addr *, u_char *); const struct in_addr *, u_char *);
void arp_ifinit(struct ifnet *, struct ifaddr *); void arp_ifinit(struct ifnet *, struct ifaddr *);

View File

@ -516,15 +516,12 @@ int
toe_l2_resolve(struct toedev *tod, struct ifnet *ifp, struct sockaddr *sa, toe_l2_resolve(struct toedev *tod, struct ifnet *ifp, struct sockaddr *sa,
uint8_t *lladdr, uint16_t *vtag) uint8_t *lladdr, uint16_t *vtag)
{ {
#ifdef INET
struct llentry *lle;
#endif
int rc; int rc;
switch (sa->sa_family) { switch (sa->sa_family) {
#ifdef INET #ifdef INET
case AF_INET: case AF_INET:
rc = arpresolve(ifp, NULL, NULL, sa, lladdr, &lle); rc = arpresolve(ifp, 0, NULL, sa, lladdr, NULL);
break; break;
#endif #endif
#ifdef INET6 #ifdef INET6

View File

@ -2278,11 +2278,12 @@ nd6_rem_ifa_lle(struct in6_ifaddr *ia)
*/ */
int int
nd6_storelladdr(struct ifnet *ifp, struct mbuf *m, nd6_storelladdr(struct ifnet *ifp, struct mbuf *m,
const struct sockaddr *dst, u_char *desten, struct llentry **lle) const struct sockaddr *dst, u_char *desten, uint32_t *pflags)
{ {
struct llentry *ln; struct llentry *ln;
*lle = NULL; if (pflags != NULL)
*pflags = 0;
IF_AFDATA_UNLOCK_ASSERT(ifp); IF_AFDATA_UNLOCK_ASSERT(ifp);
if (m != NULL && m->m_flags & M_MCAST) { if (m != NULL && m->m_flags & M_MCAST) {
int i; int i;
@ -2334,7 +2335,8 @@ nd6_storelladdr(struct ifnet *ifp, struct mbuf *m,
} }
bcopy(&ln->ll_addr, desten, ifp->if_addrlen); bcopy(&ln->ll_addr, desten, ifp->if_addrlen);
*lle = ln; if (pflags != NULL)
*pflags = ln->la_flags;
LLE_RUNLOCK(ln); LLE_RUNLOCK(ln);
/* /*
* A *small* use after free race exists here * A *small* use after free race exists here

View File

@ -418,7 +418,7 @@ int nd6_need_cache(struct ifnet *);
int nd6_add_ifa_lle(struct in6_ifaddr *); int nd6_add_ifa_lle(struct in6_ifaddr *);
void nd6_rem_ifa_lle(struct in6_ifaddr *); void nd6_rem_ifa_lle(struct in6_ifaddr *);
int nd6_storelladdr(struct ifnet *, struct mbuf *, int nd6_storelladdr(struct ifnet *, struct mbuf *,
const struct sockaddr *, u_char *, struct llentry **); const struct sockaddr *, u_char *, uint32_t *);
/* nd6_nbr.c */ /* nd6_nbr.c */
void nd6_na_input(struct mbuf *, int, int); void nd6_na_input(struct mbuf *, int, int);

View File

@ -347,14 +347,12 @@ static int addr_resolve(struct sockaddr *src_in,
struct sockaddr_in6 *sin6; struct sockaddr_in6 *sin6;
struct ifaddr *ifa; struct ifaddr *ifa;
struct ifnet *ifp; struct ifnet *ifp;
#if defined(INET) || defined(INET6)
struct llentry *lle;
#endif
struct rtentry *rte; struct rtentry *rte;
in_port_t port; in_port_t port;
u_char edst[MAX_ADDR_LEN]; u_char edst[MAX_ADDR_LEN];
int multi; int multi;
int bcast; int bcast;
int is_gw = 0;
int error = 0; int error = 0;
/* /*
@ -430,6 +428,8 @@ static int addr_resolve(struct sockaddr *src_in,
RTFREE_LOCKED(rte); RTFREE_LOCKED(rte);
return -EHOSTUNREACH; return -EHOSTUNREACH;
} }
if (rte->rt_flags & RTF_GATEWAY)
is_gw = 1;
/* /*
* If it's not multicast or broadcast and the route doesn't match the * If it's not multicast or broadcast and the route doesn't match the
* requested interface return unreachable. Otherwise fetch the * requested interface return unreachable. Otherwise fetch the
@ -467,12 +467,12 @@ mcast:
switch (dst_in->sa_family) { switch (dst_in->sa_family) {
#ifdef INET #ifdef INET
case AF_INET: case AF_INET:
error = arpresolve(ifp, rte, NULL, dst_in, edst, &lle); error = arpresolve(ifp, is_gw, NULL, dst_in, edst, NULL);
break; break;
#endif #endif
#ifdef INET6 #ifdef INET6
case AF_INET6: case AF_INET6:
error = nd6_storelladdr(ifp, NULL, dst_in, (u_char *)edst, &lle); error = nd6_storelladdr(ifp, NULL, dst_in, (u_char *)edst,NULL);
break; break;
#endif #endif
default: default:

View File

@ -1259,13 +1259,15 @@ ipoib_output(struct ifnet *ifp, struct mbuf *m,
struct llentry *lle = NULL; struct llentry *lle = NULL;
struct rtentry *rt0 = NULL; struct rtentry *rt0 = NULL;
struct ipoib_header *eh; struct ipoib_header *eh;
int error = 0; int error = 0, is_gw = 0;
short type; short type;
if (ro != NULL) { if (ro != NULL) {
if (!(m->m_flags & (M_BCAST | M_MCAST))) if (!(m->m_flags & (M_BCAST | M_MCAST)))
lle = ro->ro_lle; lle = ro->ro_lle;
rt0 = ro->ro_rt; rt0 = ro->ro_rt;
if (rt0 != NULL && (rt0->rt_flags & RTF_GATEWAY) != 0)
is_gw = 1;
} }
#ifdef MAC #ifdef MAC
error = mac_ifnet_check_transmit(ifp, m); error = mac_ifnet_check_transmit(ifp, m);
@ -1292,7 +1294,7 @@ ipoib_output(struct ifnet *ifp, struct mbuf *m,
else if (m->m_flags & M_MCAST) else if (m->m_flags & M_MCAST)
ip_ib_mc_map(((struct sockaddr_in *)dst)->sin_addr.s_addr, ifp->if_broadcastaddr, edst); ip_ib_mc_map(((struct sockaddr_in *)dst)->sin_addr.s_addr, ifp->if_broadcastaddr, edst);
else else
error = arpresolve(ifp, rt0, m, dst, edst, &lle); error = arpresolve(ifp, is_gw, m, dst, edst, NULL);
if (error) if (error)
return (error == EWOULDBLOCK ? 0 : error); return (error == EWOULDBLOCK ? 0 : error);
type = htons(ETHERTYPE_IP); type = htons(ETHERTYPE_IP);
@ -1330,7 +1332,7 @@ ipoib_output(struct ifnet *ifp, struct mbuf *m,
else if (m->m_flags & M_MCAST) else if (m->m_flags & M_MCAST)
ipv6_ib_mc_map(&((struct sockaddr_in6 *)dst)->sin6_addr, ifp->if_broadcastaddr, edst); ipv6_ib_mc_map(&((struct sockaddr_in6 *)dst)->sin6_addr, ifp->if_broadcastaddr, edst);
else else
error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle); error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, NULL);
if (error) if (error)
return error; return error;
type = htons(ETHERTYPE_IPV6); type = htons(ETHERTYPE_IPV6);