We have discovered (and hopefully fixed) a bug in the token ring module
(net/802/tr.c) in which temporary changes made to the packet (clearing the
RII bit in the source address) were not properly undone before
returning. The bug only affects networks which use token ring source
routing and protocols or applications which use the AF_PACKET socket
interface.
When building a source route cache, the routine tr_add_rif_info clears the
RII bit of the source address and builds a cache entry using the modified
source address. However, the source address is not restored to normal in
several of the possible code paths, with the result being that mangled
packets are passed up to protocols which use the AF_PACKET interface to get
and receive packets. Since the RII bit isn't set but routing info is
present, they are unable to decode the packet and (most likely) discard
it. Programs like TCPDUMP would also receive mangled packets and would not
be able to decode them properly.
The cases in which the wrong thing happens (which turns out to be 99% of
the time) were:
- the second and subsequent times we receive a packet from this address
- if the routing info is exactly two bytes (some bridges insert null
two-byte source routing info)
- if the kmalloc fails
It is the first case that causes the most problems, but given that there
were multiple exit paths from this code, it seemed prudent to not modify
the packet in place, which means we don't have to undo our modifications on
each path through the code.
I've enclosed a diff -u against the version from kernel 2.2.12. We've
tested this patch and it seems to resolve the problem.
[brian@lx tr]$ diff -u /usr/src/linux-2.2.12/net/802/tr.c tr.c
--- /usr/src/linux-2.2.12/net/802/tr.c Mon Sep 27 06:56:32 1999
+++ tr.c Thu Mar 16 16:51:41 2000
@@ -12,8 +12,13 @@
* 22 Jun 98 Paul Norton <[EMAIL PROTECTED]> Rearranged
* tr_header and tr_type_trans to handle passing IPX SNAP and
* 802.2 through the correct layers. Eliminated tr_reformat.
- *
- */
+ * 9 Mar 00 Brian Goetz <[EMAIL PROTECTED]> Fix
+ * tr_add_rif_info; for packets with source-route
+ * information, there were several cases in which the
+ * TR_RII bit would be cleared and not re-set, causing
+ * upstream protocols which use the PF_PACKET interface
+ * to not be able to decode the packet properly.
+ * */
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -328,6 +333,7 @@
unsigned int hash, rii_p = 0;
rif_cache entry;
unsigned long flags;
+ unsigned char saddr[TR_ALEN];
spin_lock_irqsave(&rif_lock, flags);
@@ -336,25 +342,28 @@
* Firstly see if the entry exists
*/
- if(trh->saddr[0] & TR_RII)
+ memcpy(saddr, trh->saddr, TR_ALEN);
+ if(saddr[0] & TR_RII)
{
- trh->saddr[0]&=0x7f;
+ saddr[0] &= ~((unsigned char) TR_RII);
if (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2)
{
rii_p = 1;
}
}
- for(i=0,hash=0;i<TR_ALEN;hash+=trh->saddr[i++]);
+ for(i=0,hash=0; i<TR_ALEN; hash+=saddr[i++]);
hash&=RIF_TABLE_SIZE-1;
- for(entry=rif_table[hash];entry &&
memcmp(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN);entry=entry->next);
+ for(entry=rif_table[hash];
+ entry && memcmp(&(entry->addr[0]), saddr, TR_ALEN);
+ entry=entry->next);
if(entry==NULL)
{
#if TR_SR_DEBUG
printk("adding rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n",
- trh->saddr[0],trh->saddr[1],trh->saddr[2],
- trh->saddr[3],trh->saddr[4],trh->saddr[5],
+ saddr[0], saddr[1], saddr[2],
+ saddr[3], saddr[4], saddr[5],
ntohs(trh->rcf));
#endif
/*
@@ -373,7 +382,7 @@
return;
}
- memcpy(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN);
+ memcpy(&(entry->addr[0]),&(saddr[0]),TR_ALEN);
memcpy(&(entry->iface[0]),dev->name,5);
entry->next=rif_table[hash];
entry->last_used=jiffies;
@@ -384,7 +393,6 @@
entry->rcf = trh->rcf & htons((unsigned
short)~TR_RCF_BROADCAST_MASK);
memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned
short));
entry->local_ring = 0;
- trh->saddr[0]|=TR_RII; /* put the routing indicator back for
tcpdump */
}
else
{
@@ -402,8 +410,8 @@
{
#if TR_SR_DEBUG
printk("updating rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n",
- trh->saddr[0],trh->saddr[1],trh->saddr[2],
- trh->saddr[3],trh->saddr[4],trh->saddr[5],
+ saddr[0], saddr[1], saddr[2],
+ saddr[3], saddr[4], saddr[5],
ntohs(trh->rcf));
#endif
entry->rcf = trh->rcf & htons((unsigned
short)~TR_RCF_BROADCAST_MASK);
--
Brian Goetz
Quiotix Corporation
[EMAIL PROTECTED] Tel: 650-843-1300 Fax: 650-324-8032
http://www.quiotix.com
-
To unsubscribe from this list: send the line "unsubscribe linux-net" in
the body of a message to [EMAIL PROTECTED]