Date: Wed, 21 Feb 2001 18:59:16 +0200 From: Ruslan Ermilov <ru@FreeBSD.org> To: idobarnea@NewMail.Net, bmilekic@FreeBSD.org Cc: mouss <usebsd@free.fr>, hackers@FreeBSD.org Subject: Re: Bug in creating ICMP error messages in FreeBSD4.2 Message-ID: <20010221185915.A80894@sunbay.com> In-Reply-To: <3a938f82.19b.0@NewMail.Net>; from idobarnea@NewMail.Net on Wed, Feb 21, 2001 at 09:50:58AM %2B0000 References: <3a938f82.19b.0@NewMail.Net>
next in thread | previous in thread | raw e-mail | index | archive | help
[redirected to -net] On Wed, Feb 21, 2001 at 09:50:58AM +0000, idobarnea@NewMail.Net wrote: > >On Mon, Feb 19, 2001 at 08:26:56PM +0100, mouss wrote: > > > At 14:25 19/02/01 +0200, idobarnea@NewMail.Net wrote: > > > > Hi, > > > > I encountered the following problem in the 4.2 version. > > > > In ip_forward, the following lines intend to save the mbuf in > > > > case we want to send ICMP error later: > > > > mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64)); > > > > if (mcopy && (mcopy->m_flags & M_EXT)) > > > > m_copydata(mcopy, 0, sizeof(struct ip), mtod(mcopy, caddr_t)); > > > > > > > > Later on, before sending the ICMP packet we do: > > > > if (mcopy->m_flags & M_EXT) > > > > m_copyback(mcopy, 0, sizeof(struct ip), mtod(mcopy, caddr_t)); > > > > > > > > The problem as I understand it is that the m_copydata and m_copyback, > > > > actually do nothing (It just copies from mcopy to itself). > > > > > > I'm speaking from memory, so don't take this for more than it is:) > > > > > > As far as I understand: > > > m_copym copies the mbuf, but if there is external storage, only > > > pointers are copied. so you get two mbuf chains with a common > > > external storage. > > > m_copydata will copy the external storage. > > > that's why there are both m_copym and m_copydata. so while > > > m_copydata(mcopy, .... (mcopy...)) > > > is surprising, it's not nothing. it copies the data pointed to > > > in mcopy. > > > > > I wrote this code, and the above said is right. > > I understand that this is what you meant it to be. > But look again at m_copydata. > This is the relevant line: > bcopy(mtod(m, caddr_t) + off, cp, count); > If cp is mtod(m, caddr_t) and off is 0, this command has no effect. > > Anyway, even if I am wrong about this, the facts are that if you > take FreeBSD 4.2-RELEASE machine, put net.inet.ip.forwarding to 1, > and then blast the kernel with ip packets with len 256 and with > destination to which it has a direct network route (on its local > lan), but it can't resolve the arp entry the kernel crashes > after a while. You can try this yourself. I can explain some more, > and give exact conf' if anybody wants it. > > Now if you stop with a debugger in icmp_error you see that > oip->ip_len equals 1, then you see the other stuff I talked about, > and then you get a kernel panic. > > After you make the correction I suggested, and do the same thing, > you see that oip->ip_len equals 256 (the right value), and you > never get a kernel panic. > > I'll be glad to here other explanations to this kernel crash. > You are right, the code does nothing, though it was supposed to preserve the byte order of IP header fields in case ip_output() modifies them. The idea was to save the standard IP header in some area in mbuf that is unused for M_EXT mbufs, but obviously mtod() place is wrong, it points to the external data for M_EXT mbuf. Could you please try this patch: Index: ip_input.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_input.c,v retrieving revision 1.130.2.12 diff -u -p -r1.130.2.12 ip_input.c --- ip_input.c 2001/02/01 20:25:09 1.130.2.12 +++ ip_input.c 2001/02/21 16:48:10 @@ -1513,7 +1513,8 @@ ip_forward(m, srcrt) */ mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64)); if (mcopy && (mcopy->m_flags & M_EXT)) - m_copydata(mcopy, 0, sizeof(struct ip), mtod(mcopy, caddr_t)); + m_copydata(mcopy, 0, sizeof(struct ip), + (caddr_t)(&mcopy->m_ext + 1)); #ifdef IPSTEALTH if (!ipstealth) { @@ -1661,7 +1662,8 @@ ip_forward(m, srcrt) return; } if (mcopy->m_flags & M_EXT) - m_copyback(mcopy, 0, sizeof(struct ip), mtod(mcopy, caddr_t)); + m_copyback(mcopy, 0, sizeof(struct ip), + (caddr_t)(&mcopy->m_ext + 1)); icmp_error(mcopy, type, code, dest, destifp); } And if that does not work, this (more clear but slower) one: Index: ip_input.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_input.c,v retrieving revision 1.130.2.13 diff -u -p -r1.130.2.13 ip_input.c --- ip_input.c 2001/02/07 01:03:13 1.130.2.13 +++ ip_input.c 2001/02/21 16:10:35 @@ -1510,9 +1510,17 @@ ip_forward(m, srcrt) * we need to generate an ICMP message to the src. */ mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64)); - if (mcopy && (mcopy->m_flags & M_EXT)) - m_copydata(mcopy, 0, sizeof(struct ip), mtod(mcopy, caddr_t)); + /* + * Make sure the copy is read-write. + */ + if (mcopy && (mcopy->m_flags & M_EXT)) { + struct mbuf *mtemp = mcopy; + + mcopy = m_dup(mtemp, M_DONTWAIT); + m_freem(mtemp); + } + #ifdef IPSTEALTH if (!ipstealth) { #endif @@ -1658,8 +1666,6 @@ ip_forward(m, srcrt) m_freem(mcopy); return; } - if (mcopy->m_flags & M_EXT) - m_copyback(mcopy, 0, sizeof(struct ip), mtod(mcopy, caddr_t)); icmp_error(mcopy, type, code, dest, destifp); } 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-hackers" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010221185915.A80894>