Date: Sat, 19 Aug 2000 15:56:22 +1000 (Australia/NSW) From: Darren Reed <avalon@coombs.anu.edu.au> To: luigi@info.iet.unipi.it (Luigi Rizzo) Cc: freebsd-security@freefall.freebsd.org Subject: Re: [avalon@COOMBS.ANU.EDU.AU: Ip packet filtering with bridging on Message-ID: <200008190556.PAA16336@cairo.anu.edu.au> In-Reply-To: <200008182048.WAA09758@info.iet.unipi.it> from "Luigi Rizzo" at Aug 18, 2000 10:48:05 PM
next in thread | previous in thread | raw e-mail | index | archive | help
In some mail from Luigi Rizzo, sie said: > > I was informed by a few people of a thread on alleged problems with > ipfw+bridging, so i think i should say a few things on the subject. > > Darren was complaining that net/bridge.c was missing some sanity > checks on packets before passing them to ip_fw_chk(). I looked at > his proposed fix on -security archives (i am not subscribed to the > list, this is why i did not react). > > I am not sure which version of FreeBSD Darren refers to -- the What's in -current. > missing checks were there when i committed the code to 3.x and 4.x > -- only thing, they are|were located in /sys/netinet/ip_fw.c, > function ip_fw_chk() near this section of code: [...] Huh ? Can you point to *exact* versions of the relevant files ? I'm looking at /sys/net/bridge.c (1.23) and I see: if (ntohs(eh->ether_type) != ETHERTYPE_IP) goto forward ; /* not an IP packet, ipfw is not appropriate */ /* * In this section, canfree=1 means m is the same as *m0. * canfree==0 means m is a copy. We need to make a copy here * (to be destroyed on exit from the firewall section) because * the firewall itself might destroy the packet. * (This is not very smart... i should really change ipfw to * leave the pkt alive!) */ if (canfree == 0 ) { /* * Need to make a copy (and for good measure, make sure that * the header is contiguous). The original is still in *m0 */ int needed = min(MHLEN, max_protohdr) ; needed = min(needed, (*m0)->m_len ) ; m = m_copypacket( (*m0), M_DONTWAIT); if (m == NULL) { printf("-- bdg: m_copypacket failed.\n") ; return ENOBUFS ; } if (m->m_len < needed && (m = m_pullup(m, needed)) == NULL) { printf("-- bdg: pullup failed.\n") ; return ENOBUFS ; } } Which is *NOT* sufficient. Version 1.138 of ip_fw.c does not have "ETHERTYPE_IP" anywhere in it. Version 1.131.2.1 (FreeBSD 4.0) has this in ip_fw.c: case ETHERTYPE_IP : if ((*m)->m_len<sizeof(struct ether_header) + sizeof(struct ip)) goto non_ip ; ip = (struct ip *)(eh + 1 ); if (ip->ip_v != IPVERSION) goto non_ip ; hlen = ip->ip_hl << 2; if (hlen < sizeof(struct ip)) /* minimum header length */ goto non_ip ; if ((*m)->m_len < 14 + hlen + 14) { printf("-- m_len %d, need more...\n", (*m)->m_len); goto non_ip ; } offset = (ip->ip_off & IP_OFFMASK); break ; default : non_ip: ip = NULL ; break ; } Which almost does the right thing. It will cause some packets to be dropped when they shouldn't (what is "14 + hlen + 14" ?). Having looked at other ipfw code, it would *appear* this is a cheap way of saying "sizeof(struct ether_header) + hlen + some_magic_bytes", where some_magic_bytes is hopefully enough to get all the important TCP fields. Furthermore, ip_len is never checked ... it's unclear if this poses a threat to icmp_error()/tcp_respond(). Luckily the "state" code for ipfw has not reached a level of sophistication where it examines the ICMP payload as does IP Filter. Darren To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-security" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200008190556.PAA16336>