[197] in bugtraq
Raw Socket Bug: details & patch.
daemon@ATHENA.MIT.EDU (Darren Reed)
Tue Nov 15 05:16:25 1994
From: Darren Reed <avalon@coombs.anu.edu.au>
To: bugtraq@fc.net
Date: Tue, 15 Nov 1994 19:50:27 +1100 (EDT)
Cc: deering@parc.xerox.com, ajit@udel.edu, van@ee.lbl.gov,
Mark.Graff@Corp.Sun.COM
The raw socket bug is highlighted by the ISI (1986) version of ping(1)
but is not peculiar to this program. The problem lies in the networking
code which doesn't bother to check that the length of the IP header is
actually correct (with respect to the mbuf in which it has been placed).
The following is some output from debugging log messages when running
this version of ping:
(these are values inside rip_output)
Nov 15 18:56:44 unix vmunix: m ff663b80 len -30282 m_len 64
Nov 15 18:56:45 unix vmunix: m ff660800 len -30309 m_len 64
Nov 15 18:56:48 unix vmunix: m ff663780 len -29358 m_len 64
Nov 15 18:56:49 unix vmunix: m ff662c80 len -29252 m_len 64
Nov 15 18:56:50 unix vmunix: m ff660780 len -29437 m_len 64
(these were inside a loop in ip_output, just before the fatal m_copy)
Nov 15 18:58:59 unix vmunix: mhlen 20 mnext ff663bfc = 0 mhip ff664fe8
<3>m0 ff663b80 64 m ff664f80 20 h(len) 20 1480 off 1500 ip:off 0 p 200
len 20920 ttl 46panic: m_copy
It would appear to have been introduced with Van Jacobsen's patch to
allow the entire packet header to be supplied. The bug is made possible
by the kernel not checking the packet header sanity further on...
I've included (below) a patch to Van's original patch which provides
the raw socket interface. Van may have a better patch/solution to this...
and if so, it would be nice if it could be put into the multicast .o's
and diffs (yes, I managed to panic my multicast router :-().
cheers,
darren
*** rip_output.van.orig Tue Nov 15 19:14:36 1994
--- rip_output.van Tue Nov 15 19:35:04 1994
***************
*** 43,50 ****
ip->ip_p = proto;
ip->ip_len = sizeof(struct ip) + len;
ip->ip_ttl = MAXTTL;
! } else
ip = mtod(m, struct ip *);
if (rp->rcb_flags & RAW_LADDR) {
sin = (struct sockaddr_in *)&rp->rcb_laddr;
--- 43,61 ----
ip->ip_p = proto;
ip->ip_len = sizeof(struct ip) + len;
ip->ip_ttl = MAXTTL;
! } else {
! int hl;
!
ip = mtod(m, struct ip *);
+ /*
+ * XXX - check ip header supplied to make sure lengths are correct.
+ */
+ if (ip->ip_len != m->m_len)
+ ip->ip_len = m->m_len;
+ hl = ip->ip_hl << 2;
+ if (hl < sizeof(struct ip) || hl > m->m_len)
+ ip->ip_hl = sizeof(struct ip) >> 2;
+ }
if (rp->rcb_flags & RAW_LADDR) {
sin = (struct sockaddr_in *)&rp->rcb_laddr;