Attached are (very) simple patches which attempt to address the problem.
I've included -net in the CC to solicit a larger audience.

On Sun, 21 Apr 2002, Bill Fenner wrote:

>
> I think that sdl_data should go back to being a variable-length buffer,
> and the source routing stuff should be reimplemented somewhere else
> (perhaps at the end of the variable-length buffer).
>
> What uses the source-routing fields?
>
>   Bill
>

  Yeah, this is the route I favor, except that it would clearly break
compatibility with 3rd party binary-only drivers.  Personally, I would really
like to see a solution implemented in the RELENG_4 branch.  To that extent,
the attached patches keep the sockaddr_dl at it's current size but allots the
entire 34 bytes needed for token-ring source routing to the sdl_data field
(for a total of 46 bytes).  The token-ring code just embeds it's source
routing information in the sdl_data field now.  I also removed setting the
source routing control field to zero for non-iso88025 sockaddr_dl's since all
of the code which examines the field appears to contingent on the interface
being of the iso88025 persuasion.
  That said, this leaves ample room in the sockaddr_dl structure for interface
name and MAC address in the sockaddr_dl (too much, but the overall size hasn't
changed).  However, token ring interface names are still limited to 6
characters before they risk overflowing the sdl_data field with their source
routing information.  This is no worse than the existing situation wherein a
token ring interface with more than 6 characters would cause the last byte(s)
of the hardware address to get clobbered by the source routing control field.
  One point I am a little leary of is that in in_arpinput() the original code
appears to have made provision for receiving an ISO88025 frame on a non-token
ring interface and trusted the source routing information contained in such a
frame.  First, is this a correct reading of the code?  And second, is this
correct behavior?  If so, I can easily restore it.
  There are 2 sets of attached patches: one for -current and one for -stable
(the one suffixed with a 4).  I've tested these pretty extensively on -stable
but haven't done any testing at all for -current (admittingly, not even a
build); furthermore all testing was just with ethernet...I do not have access
to any token ring hardware.  I would appreciate any feedback regarding the
approach and anyone who can confirm that I haven't horribly borked token ring
source routing.
  If all looks well, then ifconfig (and others?) will have to be updated to
not try and print source routing information unless the interface is token
ring.

  Thanks,

  Kelly
  kbyanc@{posi.net,FreeBSD.org}

  The original message for those subscribed to -net but not -arch:

>From [EMAIL PROTECTED] Tue Apr 30 18:13:51 2002
Date: Sun, 21 Apr 2002 01:48:42 -0700 (PDT)
From: Kelly Yancey <[EMAIL PROTECTED]>
To: [EMAIL PROTECTED]
Subject: Overflowing sockaddr_dl's sdl_data buffer


  While working on a product at work, I discovered that it is trivial to
overflow the sdl_data buffer in sockaddr_dl structures.  In our case,  I
enountered the bug by creating a vlan100 interface.  The sdl_data buffer is
populated with both the interface name and the parent interface's hardware
address; in his case 7 characters for the interface name and 6 more for the
parent's MAC address for a total of 13 characters (sdl_data is only defined
for 12 characters).  As a result, the sdl_rcf field is garbage (actually, the
last octet of the MAC address).  While, I worked around the problem in our
product, I would prefer to see the bug fixed in FreeBSD proper.
  So, I would like to solicit discussion of the proper fix for this bug.
Should sdl_data's length be extended (say 16 characters)?  This would surely
break binary compatibility and only postpones the issue (imagine an interface
with a longer name).  Should bound's checking be added to eliminate the
(supposedly optional) interface name from the sdl_data buffer if there is not
room?  If so, how does one ensure all drivers (including 3rd party)
perform the bounds-checking?  Surely there are other options too.  In any
event, the comment in sys/net/if_dl.h for the sdl_data field needs updating
because since the source routing information was added following the sdl_data
field it is impossible for the sdl_data field to be larger than that defined
by the structure definition.

  Thanks,

  Kelly
  kbyanc@{posi.net,FreeBSD.org}
Index: net/if_dl.h
===================================================================
RCS file: /home/cvs/acs/base/src/sys/net/if_dl.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 if_dl.h
--- net/if_dl.h 22 Mar 2002 04:11:00 -0000      1.1.1.1
+++ net/if_dl.h 30 Apr 2002 20:14:09 -0000
@@ -66,10 +66,8 @@
        u_char  sdl_nlen;       /* interface name length, no trailing 0 reqd. */
        u_char  sdl_alen;       /* link level address length */
        u_char  sdl_slen;       /* link layer selector length */
-       char    sdl_data[12];   /* minimum work area, can be larger;
+       char    sdl_data[46];   /* minimum work area, can be larger;
                                   contains both if name and ll address */
-       u_short sdl_rcf;        /* source routing control */
-       u_short sdl_route[16];  /* source routing information */
 };
 
 #define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen))
Index: net/if_iso88025subr.c
===================================================================
RCS file: /home/cvs/acs/base/src/sys/net/if_iso88025subr.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 if_iso88025subr.c
--- net/if_iso88025subr.c       22 Mar 2002 04:11:00 -0000      1.1.1.1
+++ net/if_iso88025subr.c       30 Apr 2002 21:27:12 -0000
@@ -202,8 +202,8 @@
 
        /* Calculate routing info length based on arp table entry */
        if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway))
-               if (sdl->sdl_rcf != NULL)
-                       rif_len = TR_RCF_RIFLEN(sdl->sdl_rcf);
+               if (SDL_ISO88025(sdl)->trld_rcf != NULL)
+                       rif_len = TR_RCF_RIFLEN(SDL_ISO88025(sdl)->trld_rcf);
 
        /* Generate a generic 802.5 header for the packet */
        gen_th.ac = TR_AC;
@@ -212,8 +212,9 @@
        if (rif_len) {
                gen_th.iso88025_shost[0] |= TR_RII;
                if (rif_len > 2) {
-                       gen_th.rcf = sdl->sdl_rcf;
-                       memcpy(gen_th.rd, sdl->sdl_route, rif_len - 2);
+                       gen_th.rcf = SDL_ISO88025(sdl)->trld_rcf;
+                       memcpy(gen_th.rd, SDL_ISO88025(sdl)->trld_route,
+                              rif_len - 2);
                }
        }
        
Index: net/iso88025.h
===================================================================
RCS file: /home/cvs/acs/base/src/sys/net/iso88025.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 iso88025.h
--- net/iso88025.h      22 Mar 2002 04:11:00 -0000      1.1.1.1
+++ net/iso88025.h      30 Apr 2002 21:27:05 -0000
@@ -102,6 +102,15 @@
        u_char fc;
 };
 
+struct iso88025_sockaddr_dl_data {
+       u_short  trld_rcf;
+       u_short *trld_route[RIF_MAX_LEN];
+};
+
+#define SDL_ISO88025(s)                ((struct iso88025_sockaddr_dl_data *)   \
+                                ((s)->sdl_data + min((s)->sdl_nlen +   \
+                                 (s)->sdl_alen + (s)->sdl_slen, 12)))
+
 /*
  * Structure of a 48-bit iso 802.5 address.
  *  ( We could also add the 16 bit addresses as a union)
Index: netinet/if_ether.c
===================================================================
RCS file: /home/cvs/acs/base/src/sys/netinet/if_ether.c,v
retrieving revision 1.5
diff -u -r1.5 if_ether.c
--- netinet/if_ether.c  29 Mar 2002 20:33:57 -0000      1.5
+++ netinet/if_ether.c  30 Apr 2002 21:27:23 -0000
@@ -529,6 +529,7 @@
        register struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif;
        struct ether_header *eh;
        struct iso88025_header *th = (struct iso88025_header *)0;
+       struct iso88025_sockaddr_dl_data *trld;
        register struct llinfo_arp *la = 0;
        register struct rtentry *rt;
        struct ifaddr *ifa;
@@ -647,7 +648,6 @@
 update:
                (void)memcpy(LLADDR(sdl), ea->arp_sha, sizeof(ea->arp_sha));
                sdl->sdl_alen = sizeof(ea->arp_sha);
-                sdl->sdl_rcf = (u_short)0;
                /*
                 * If we receive an arp from a token-ring station over
                 * a token-ring nic then try to save the source
@@ -655,13 +655,14 @@
                 */
                if (ac->ac_if.if_type == IFT_ISO88025) {
                        th = (struct iso88025_header *)m->m_pkthdr.header;
+                       trld = SDL_ISO88025(sdl);
                        rif_len = TR_RCF_RIFLEN(th->rcf);
                        if ((th->iso88025_shost[0] & TR_RII) &&
                            (rif_len > 2)) {
-                               sdl->sdl_rcf = th->rcf;
-                               sdl->sdl_rcf ^= htons(TR_RCF_DIR);
-                               memcpy(sdl->sdl_route, th->rd, rif_len - 2);
-                               sdl->sdl_rcf &= ~htons(TR_RCF_BCST_MASK);
+                               trld->trld_rcf = th->rcf;
+                               trld->trld_rcf ^= htons(TR_RCF_DIR);
+                               memcpy(trld->trld_route, th->rd, rif_len - 2);
+                               trld->trld_rcf &= ~htons(TR_RCF_BCST_MASK);
                                /*
                                 * Set up source routing information for
                                 * reply packet (XXX)
@@ -675,9 +676,7 @@
                        m->m_data -= 8;
                        m->m_len  += 8;
                        m->m_pkthdr.len += 8;
-                       th->rcf = sdl->sdl_rcf;
-               } else {
-                       sdl->sdl_rcf = (u_short)0;
+                       th->rcf = trld->trld_rcf;
                }
                if (rt->rt_expire)
                        rt->rt_expire = time_second + arpt_keep;
Index: net/if_dl.h
===================================================================
RCS file: /home/ncvs/src/sys/net/if_dl.h,v
retrieving revision 1.11
diff -u -u -r1.11 if_dl.h
--- net/if_dl.h 19 Mar 2002 21:54:16 -0000      1.11
+++ net/if_dl.h 1 May 2002 01:11:42 -0000
@@ -66,10 +66,8 @@
        u_char  sdl_nlen;       /* interface name length, no trailing 0 reqd. */
        u_char  sdl_alen;       /* link level address length */
        u_char  sdl_slen;       /* link layer selector length */
-       char    sdl_data[12];   /* minimum work area, can be larger;
+       char    sdl_data[46];   /* minimum work area, can be larger;
                                   contains both if name and ll address */
-       u_short sdl_rcf;        /* source routing control */
-       u_short sdl_route[16];  /* source routing information */
 };
 
 #define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen))
Index: net/if_iso88025subr.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_iso88025subr.c,v
retrieving revision 1.20
diff -u -u -r1.20 if_iso88025subr.c
--- net/if_iso88025subr.c       14 Dec 2001 19:28:43 -0000      1.20
+++ net/if_iso88025subr.c       1 May 2002 01:11:42 -0000
@@ -253,8 +253,8 @@
 
        /* Calculate routing info length based on arp table entry */
        if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway))
-               if (sdl->sdl_rcf != NULL)
-                       rif_len = TR_RCF_RIFLEN(sdl->sdl_rcf);
+               if (SDL_ISO88025(sdl)->trld_rcf != NULL)
+                       rif_len = TR_RCF_RIFLEN(SDL_ISO88025(sdl)->trld_rcf);
 
        /* Generate a generic 802.5 header for the packet */
        gen_th.ac = TR_AC;
@@ -264,9 +264,10 @@
        if (rif_len) {
                gen_th.iso88025_shost[0] |= TR_RII;
                if (rif_len > 2) {
-                       gen_th.rcf = sdl->sdl_rcf;
+                       gen_th.rcf = SDL_ISO88025(sdl)->trld_rcf;
                        (void)memcpy((caddr_t)gen_th.rd,
-                               (caddr_t)sdl->sdl_route, rif_len - 2);
+                               (caddr_t)SDL_ISO88025(sdl)->trld_route,
+                               rif_len - 2);
                }
        }
        
Index: net/iso88025.h
===================================================================
RCS file: /home/ncvs/src/sys/net/iso88025.h,v
retrieving revision 1.5
diff -u -u -r1.5 iso88025.h
--- net/iso88025.h      18 Mar 2001 05:41:07 -0000      1.5
+++ net/iso88025.h      1 May 2002 01:11:42 -0000
@@ -109,6 +109,15 @@
        u_char fc;
 };
 
+struct iso88025_sockaddr_dl_data {
+       u_short  trld_rcf;
+       u_short *trld_route[RIF_MAX_LEN];
+};
+
+#define SDL_ISO88025(s)                ((struct iso88025_sockaddr_dl_data *)   \
+                                ((s)->sdl_data + min((s)->sdl_nlen +   \
+                                 (s)->sdl_alen + (s)->sdl_slen, 12)))
+
 /*
  * Structure of a 48-bit iso 802.5 address.
  *  ( We could also add the 16 bit addresses as a union)
Index: netinet/if_ether.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/if_ether.c,v
retrieving revision 1.91
diff -u -u -r1.91 if_ether.c
--- netinet/if_ether.c  20 Mar 2002 15:56:36 -0000      1.91
+++ netinet/if_ether.c  1 May 2002 01:11:43 -0000
@@ -571,6 +571,7 @@
        struct ether_header *eh;
        struct arc_header *arh;
        struct iso88025_header *th = (struct iso88025_header *)0;
+       struct iso88025_sockaddr_dl_data *trld;
        register struct llinfo_arp *la = 0;
        register struct rtentry *rt;
        struct ifaddr *ifa;
@@ -697,7 +698,6 @@
                }
                (void)memcpy(LLADDR(sdl), ar_sha(ah),
                    sdl->sdl_alen = ah->ar_hln);
-                sdl->sdl_rcf = (u_short)0;
                /*
                 * If we receive an arp from a token-ring station over
                 * a token-ring nic then try to save the source
@@ -705,13 +705,14 @@
                 */
                if (ifp->if_type == IFT_ISO88025) {
                        th = (struct iso88025_header *)m->m_pkthdr.header;
+                       trld = SDL_ISO88025(sdl);
                        rif_len = TR_RCF_RIFLEN(th->rcf);
                        if ((th->iso88025_shost[0] & TR_RII) &&
                            (rif_len > 2)) {
-                               sdl->sdl_rcf = th->rcf;
-                               sdl->sdl_rcf ^= htons(TR_RCF_DIR);
-                               memcpy(sdl->sdl_route, th->rd, rif_len - 2);
-                               sdl->sdl_rcf &= ~htons(TR_RCF_BCST_MASK);
+                               trld->trld_rcf = th->rcf;
+                               trld->trld_rcf ^= htons(TR_RCF_DIR);
+                               memcpy(trld->trld_route, th->rd, rif_len - 2);
+                               trld->trld_rcf &= ~htons(TR_RCF_BCST_MASK);
                                /*
                                 * Set up source routing information for
                                 * reply packet (XXX)
@@ -725,9 +726,7 @@
                        m->m_data -= 8;
                        m->m_len  += 8;
                        m->m_pkthdr.len += 8;
-                       th->rcf = sdl->sdl_rcf;
-               } else {
-                       sdl->sdl_rcf = (u_short)0;
+                       th->rcf = trld->trld_rcf;
                }
                if (rt->rt_expire)
                        rt->rt_expire = time_second + arpt_keep;

Reply via email to