Date: Thu, 19 Jul 2001 13:54:23 +0300 From: Ruslan Ermilov <ru@FreeBSD.org> To: Bruce Evans <bde@zeta.org.au>, Kris Kennaway <kris@obsecurity.org> Cc: "Daniel C. Sobral" <dcs@FreeBSD.org>, Bill Fenner <fenner@FreeBSD.org>, net@FreeBSD.org Subject: Re: cvs commit: src/sys/netinet ip_output.c Message-ID: <20010719135423.G69276@sunbay.com> In-Reply-To: <Pine.BSF.4.21.0107191733360.778-100000@besplex.bde.org>; from bde@zeta.org.au on Thu, Jul 19, 2001 at 05:46:38PM %2B1000 References: <200107190710.f6J7AVl44738@freefall.freebsd.org> <20010719011806.A28830@xor.obsecurity.org> <200107190710.f6J7AVl44738@freefall.freebsd.org> <Pine.BSF.4.21.0107191733360.778-100000@besplex.bde.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, Jul 19, 2001 at 05:46:38PM +1000, Bruce Evans wrote: > > Modified files: > > sys/netinet ip_output.c > > Log: > > Backout non-functional changes from revision 1.128. > > > > Not objected to by: dcs > > This reduces the bugs in rev.1.128 to style bugs on every line, and: > > ./@/netinet/ip_output.c: In function `ip_output': > ./@/netinet/ip_output.c:127: warning: `ifp' might be used uninitialized in this function > ./@/netinet/ip_output.c:132: warning: `ia' might be used uninitialized in this function > ./@/netinet/ip_output.c:133: warning: `isbroadcast' might be used uninitialized in this function > > The warning is because the variables were initialized only in each arm of an > if-else clause, and the commit adds an elseif which doesn't do anything. > Are you going to fix this too? I don't really understand this. > You are attacking the wrong person here. Daniel did the actual commit. In fact, warnings about `ifp' and `isbroadcast' were mostly harmless. gcc(1) just can't realize that these variables are either unused or really get initialized in the code path that is affected by the following conditional (let's call it "multicast destination" block), due to (probably) using goto's: if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { ... } This block then jumps to either `sendit' or `done' labels. `ifp' is properly initialized within the block, and `isbroadcast' wasn't used below in `sendit' and `done'. The warning for `ifp' is easily fixable. Another story is with `ia'. `ia' is used later to update per-address statistics counters: : /* Record statistics for this interface address. */ : if (!(flags & IP_FORWARDING)) { : ia->ia_ifa.if_opackets++; : ia->ia_ifa.if_obytes += m->m_pkthdr.len; : } (And yet in one place below, for "fragmentation" case.) The following patch: 1) Fixes the `ifp' warning. 2) Doesn't fix the `isbroadcast' (harmless) warning. ??? 3) Tries to fix the `ia' warning, but: What happens if the interface in question (imo->imo_multicast_ifp) doesn't have any INET addresses bound to it? IFP_TO_IA(ifp, ia) will set `ia' to 0, and the statistics code will later panic. It's unclear to me at all whether this should be allowed (multicasting over an interface with no addresses), and if yes, then the statistics code should be modified to check whether `ia' is zero or not (I've put this in the patch). But there's still race possible in the "multicast destination" block, when it initializes the unspecified (INADDR_ANY) source address of a datagram using the address of an interface. NetBSD (see below) should panic here. Index: ip_output.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_output.c,v retrieving revision 1.130 diff -u -p -r1.130 ip_output.c --- ip_output.c 2001/07/19 07:10:30 1.130 +++ ip_output.c 2001/07/19 10:49:09 @@ -253,14 +253,13 @@ ip_output(m0, opt, ro, flags, imo) ip->ip_ttl = 1; isbroadcast = in_broadcast(dst->sin_addr, ifp); } else if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) && - (imo != NULL) && - (imo->imo_multicast_ifp != NULL)) { + imo != NULL && imo->imo_multicast_ifp != NULL) { /* - * bypass the normal routing lookup for - * multicast packets if the interface is - * specified + * Bypass the normal routing lookup for multicast + * packets if the interface is specified. */ - /* No Operation */ + ifp = imo->imo_multicast_ifp; + IFP_TO_IA(ifp, ia); } else { /* * If this is the case, we probably don't want to allocate @@ -303,8 +302,6 @@ ip_output(m0, opt, ro, flags, imo) */ if (imo != NULL) { ip->ip_ttl = imo->imo_multicast_ttl; - if (imo->imo_multicast_ifp != NULL) - ifp = imo->imo_multicast_ifp; if (imo->imo_multicast_vif != -1) ip->ip_src.s_addr = ip_mcast_src(imo->imo_multicast_vif); @@ -325,13 +322,9 @@ ip_output(m0, opt, ro, flags, imo) * of outgoing interface. */ if (ip->ip_src.s_addr == INADDR_ANY) { - register struct in_ifaddr *ia1; - - TAILQ_FOREACH(ia1, &in_ifaddrhead, ia_link) - if (ia1->ia_ifp == ifp) { - ip->ip_src = IA_SIN(ia1)->sin_addr; - break; - } + /* XXX: interface may have no addresses. */ + if (ia != NULL) + ip->ip_src = IA_SIN(ia)->sin_addr; } IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm); @@ -824,7 +817,7 @@ pass: } /* Record statistics for this interface address. */ - if (!(flags & IP_FORWARDING)) { + if (!(flags & IP_FORWARDING) && ia) { ia->ia_ifa.if_opackets++; ia->ia_ifa.if_obytes += m->m_pkthdr.len; } @@ -964,7 +957,7 @@ sendorfree: /* clean ipsec history once it goes out of the node */ ipsec_delaux(m); #endif - if (error == 0) { + if (error == 0 && ia) { /* Record statistics for this interface address. */ ia->ia_ifa.if_opackets++; ia->ia_ifa.if_obytes += m->m_pkthdr.len; Finally, I have looked at NetBSD code, and they seem to: 1) look the route to the destination, as we did it before. 2) check that `ia' is non-zero in the per-address statistics code. 3) not check that `ia' is non-zero in the "multicast destination" block, in the following code snippet: : /* : * See if the caller provided any multicast options : */ : if (imo != NULL) { : ip->ip_ttl = imo->imo_multicast_ttl; : if (imo->imo_multicast_ifp != NULL) { : ifp = imo->imo_multicast_ifp; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ : mtu = ifp->if_mtu; : } : } else : ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL; [...] : /* : * If source address not specified yet, use an address : * of outgoing interface. : */ : if (in_nullhost(ip->ip_src)) { : struct in_ifaddr *ia; : IFP_TO_IA(ifp, ia); : ip->ip_src = ia->ia_addr.sin_addr; : } There's a race in the last two lines if `ifp' doesn't have addresses bound. Sorry, I'm not too familiar with the multicast code, so probably some MCAST geeks like Bill Fenner could speak up? :-) Cheers, -- Ruslan Ermilov Oracle Developer/DBA, ru@sunbay.com Sunbay Software AG, ru@FreeBSD.org FreeBSD committer, +380.652.512.251 Simferopol, Ukraine http://www.FreeBSD.org The Power To Serve http://www.oracle.com Enabling The Information Age To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-net" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010719135423.G69276>