diff options
author | rwatson <rwatson@FreeBSD.org> | 2009-06-22 10:23:54 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2009-06-22 10:23:54 +0000 |
commit | 5daa0c14237b29afdd8225eba0c34cc0c8238ca3 (patch) | |
tree | 8b6fd873a14e459bd3341eef4e3b417559fcfec3 /sys/netatalk/ddp_output.c | |
parent | 1a759a35f242325e2263831a412a94a6e90ca317 (diff) | |
download | FreeBSD-src-5daa0c14237b29afdd8225eba0c34cc0c8238ca3.zip FreeBSD-src-5daa0c14237b29afdd8225eba0c34cc0c8238ca3.tar.gz |
Add a global rwlock, at_ifaddr_rw, to protect the global netatalk
address lists, at_ifaddr_list. Acquire the lock, and use ifaddr
refcounts where necessary, to close most known address-related
races in netatalk.
Annotate one potential race in at_control() where we acquire an
ifaddr reference, drop the global lock, and scrub the address from
the ifnet before re-acquiring the global lock, which could allow
for a writer-writer race.
MFC after: 3 weeks
Diffstat (limited to 'sys/netatalk/ddp_output.c')
-rw-r--r-- | sys/netatalk/ddp_output.c | 10 |
1 files changed, 9 insertions, 1 deletions
diff --git a/sys/netatalk/ddp_output.c b/sys/netatalk/ddp_output.c index 6fa75ce..a820f24 100644 --- a/sys/netatalk/ddp_output.c +++ b/sys/netatalk/ddp_output.c @@ -142,12 +142,16 @@ ddp_route(struct mbuf *m, struct route *ro) if ((ro->ro_rt != NULL) && (ro->ro_rt->rt_ifa) && (ifp = ro->ro_rt->rt_ifa->ifa_ifp)) { net = ntohs(satosat(ro->ro_rt->rt_gateway)->sat_addr.s_net); + AT_IFADDR_RLOCK(); for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) { if (((net == 0) || (aa->aa_ifp == ifp)) && net >= ntohs(aa->aa_firstnet) && net <= ntohs(aa->aa_lastnet)) break; } + if (aa != NULL) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); } else { m_freem(m); #ifdef NETATALK_DEBUG @@ -199,6 +203,7 @@ ddp_route(struct mbuf *m, struct route *ro) if (!(aa->aa_flags & AFA_PHASE2)) { MGET(m0, M_DONTWAIT, MT_DATA); if (m0 == NULL) { + ifa_free(&aa->aa_ifa); m_freem(m); printf("ddp_route: no buffers\n"); return (ENOBUFS); @@ -231,8 +236,11 @@ ddp_route(struct mbuf *m, struct route *ro) if ((satosat(&aa->aa_addr)->sat_addr.s_net == satosat(&ro->ro_dst)->sat_addr.s_net) && (satosat(&aa->aa_addr)->sat_addr.s_node == - satosat(&ro->ro_dst)->sat_addr.s_node)) + satosat(&ro->ro_dst)->sat_addr.s_node)) { + ifa_free(&aa->aa_ifa); return (if_simloop(ifp, m, gate.sat_family, 0)); + } + ifa_free(&aa->aa_ifa); /* XXX */ return ((*ifp->if_output)(ifp, m, (struct sockaddr *)&gate, NULL)); |