kern/94448: if_bridge modifies IP length and offset fields for broadcast packets

Eygene A.Ryabinkin rea-fbsd at rea.mbslab.kiae.ru
Tue Mar 14 15:50:09 UTC 2006


>Number:         94448
>Category:       kern
>Synopsis:       if_bridge modifies IP length and offset fields for broadcast packets
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Mar 14 15:50:07 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Eygene A. Ryabinkin
>Release:        FreeBSD 6.1-PRERELEASE i386
>Organization:
Code Labs
>Environment:
System: FreeBSD XXXX 6.1-PRERELEASE FreeBSD 6.1-PRERELEASE #35: Tue Mar 7 20:15:22 MSK 2006 root at XXXX:/usr/obj/usr/src/sys/XXXX i386


	
>Description:
 if_bridge swaps IP length and header fields in the broadcast packets flowing
through the bridge. This affects only architectures where native byte order
is not the networking one (bid endian). Not all packets are touched: only
packets that are rejected by the firewall (any that installs pfil hooks)
can be modified this way. The bridges with only two interfaces are not
affected: the bug exists, but it will not lead to swapping. Bridges that
do not use firewalling are also unaffected.

 The reason lies in the /sys/net/if_bridge.c, line 2095:
     mc = m_copypacket(m, M_DONTWAIT);
and then the mbuf 'mc' will be passed to the bridge_pfil(), where IP
header fields 'length' and 'offset' will be transformed to the native
host byte order before applying pfil hooks. If any pfil hook will reject
the packet it will free mbuf and NULL'ify the mbuf pointer, but since
this mbuf is just the result of m_copypacket(), the packet's IP
header will be screwed a bit. And the next interface will get the
bad IP header.

 As far as I understand, this error lives in FreeBSD 5.x as well. Though
I do not have any 5.x at hand to test it, judging only by the code.
>How-To-Repeat:
 Set up if_bridge with three or more interfaces and try to send broadcast
packets from one bridge branch. Set up the firewall to reject broadcasts
on some interface. Watch for broadcasts with tcpdump on all bridge
interfaces and you will see that some interfaces will get the bad
packet.
>Fix:
 Replace m_copypacket() with m_dup():
-----
--- if_bridge.c.orig	Tue Mar 14 17:32:02 2006
+++ if_bridge.c	Tue Mar 14 18:05:50 2006
@@ -2092,7 +2092,11 @@
 			mc = m;
 			used = 1;
 		} else {
-			mc = m_copypacket(m, M_DONTWAIT);
+			/*
+			 * Doing the m_dup here, because this mbuf can be
+			 * passed to pfil_hook and modified.
+			 */
+			mc = m_dup(m, M_DONTWAIT);
 			if (mc == NULL) {
 				sc->sc_ifp->if_oerrors++;
 				continue;
-----
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list