Update.
authorUlrich Drepper <drepper@redhat.com>
Thu, 17 Apr 2003 01:08:57 +0000 (01:08 +0000)
committerUlrich Drepper <drepper@redhat.com>
Thu, 17 Apr 2003 01:08:57 +0000 (01:08 +0000)
* sysdeps/unix/sysv/linux/ifaddrs.c (getifaddrs): Check lengths
before copying.  This might leave holes in the list.  Adjust
pointers if necessary.
(netlink_receive): Allocate only one block.
(free_netlink_handle): Adjust appropriately.
(getifaddrs): Lots of cleanups.

ChangeLog
sysdeps/unix/sysv/linux/ifaddrs.c

index 81dfa78..f211511 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2003-04-16  Ulrich Drepper  <drepper@redhat.com>
 
+       * sysdeps/unix/sysv/linux/ifaddrs.c (getifaddrs): Check lengths
+       before copying.  This might leave holes in the list.  Adjust
+       pointers if necessary.
+       (netlink_receive): Allocate only one block.
+       (free_netlink_handle): Adjust appropriately.
+       (getifaddrs): Lots of cleanups.
+
        * string/test-strncpy.c (do_one_test): Mark start and stop as
        possibly unused.
 
index 23a61c5..b310043 100644 (file)
@@ -252,7 +252,8 @@ netlink_open (struct netlink_handle *h)
    Since we get at first all RTM_NEWLINK entries, it can never happen
    that a RTM_NEWADDR index is not known to this map.  */
 static int
-map_newlink (int index, int *map, int max)
+internal_function
+map_newlink (int index, struct ifaddrs_storage *ifas, int *map, int max)
 {
   int i;
 
@@ -261,6 +262,8 @@ map_newlink (int index, int *map, int max)
       if (map[i] == -1)
        {
          map[i] = index;
+         if (i > 0)
+           ifas[i - 1].ifa.ifa_next = &ifas[i].ifa;
          return i;
        }
       else if (map[i] == index)
@@ -389,9 +392,6 @@ getifaddrs (struct ifaddrs **ifap)
   if ((newlink + newaddr) == 0)
     goto exit_free;
 
-  /* Table for mapping kernel index to entry in our list.  */
-  map_newlink_data = alloca (newlink * sizeof (int));
-
   /* Allocate memory for all entries we have and initialize next
      pointer.  */
   ifas = (struct ifaddrs_storage *) calloc (1,
@@ -404,11 +404,10 @@ getifaddrs (struct ifaddrs **ifap)
       goto exit_free;
     }
 
-  for (i = 0; i < newlink + newaddr - 1; i++)
-    {
-      ifas[i].ifa.ifa_next = &ifas[i + 1].ifa;
-      map_newlink_data[i] = -1;
-    }
+  /* Table for mapping kernel index to entry in our list.  */
+  map_newlink_data = alloca (newlink * sizeof (int));
+  memset (map_newlink_data, '\xff', newlink * sizeof (int));
+
   ifa_data_ptr = (char *) &ifas[newlink + newaddr];
   newaddr_idx = 0;             /* Counter for newaddr index.  */
 
@@ -447,7 +446,7 @@ getifaddrs (struct ifaddrs **ifap)
              /* Interfaces are stored in the first "newlink" entries
                 of our list, starting in the order as we got from the
                 kernel.  */
-              ifa_index = map_newlink (ifim->ifi_index - 1,
+              ifa_index = map_newlink (ifim->ifi_index - 1, ifas,
                                       map_newlink_data, newlink);
              ifas[ifa_index].ifa.ifa_flags = ifim->ifi_flags;
 
@@ -459,36 +458,44 @@ getifaddrs (struct ifaddrs **ifap)
                  switch (rta->rta_type)
                    {
                    case IFLA_ADDRESS:
-                     ifas[ifa_index].addr.sl.sll_family = AF_PACKET;
-                     memcpy (ifas[ifa_index].addr.sl.sll_addr,
-                             (char *) rta_data, rta_payload);
-                     ifas[ifa_index].addr.sl.sll_halen = rta_payload;
-                     ifas[ifa_index].addr.sl.sll_ifindex = ifim->ifi_index;
-                     ifas[ifa_index].addr.sl.sll_hatype = ifim->ifi_type;
-
-                     ifas[ifa_index].ifa.ifa_addr = &ifas[ifa_index].addr.sa;
+                     if (rta_payload <= sizeof (ifas[ifa_index].addr))
+                       {
+                         ifas[ifa_index].addr.sl.sll_family = AF_PACKET;
+                         memcpy (ifas[ifa_index].addr.sl.sll_addr,
+                                 (char *) rta_data, rta_payload);
+                         ifas[ifa_index].addr.sl.sll_halen = rta_payload;
+                         ifas[ifa_index].addr.sl.sll_ifindex
+                           = ifim->ifi_index;
+                         ifas[ifa_index].addr.sl.sll_hatype = ifim->ifi_type;
+
+                         ifas[ifa_index].ifa.ifa_addr
+                           = &ifas[ifa_index].addr.sa;
+                       }
                      break;
 
                    case IFLA_BROADCAST:
-                     ifas[ifa_index].broadaddr.sl.sll_family = AF_PACKET;
-                     memcpy (ifas[ifa_index].broadaddr.sl.sll_addr,
-                             (char *) rta_data, rta_payload);
-                     ifas[ifa_index].broadaddr.sl.sll_halen = rta_payload;
-                     ifas[ifa_index].broadaddr.sl.sll_ifindex
-                       = ifim->ifi_index;
-                     ifas[ifa_index].broadaddr.sl.sll_hatype = ifim->ifi_type;
+                     if (rta_payload <= sizeof (ifas[ifa_index].broadaddr))
+                       {
+                         ifas[ifa_index].broadaddr.sl.sll_family = AF_PACKET;
+                         memcpy (ifas[ifa_index].broadaddr.sl.sll_addr,
+                                 (char *) rta_data, rta_payload);
+                         ifas[ifa_index].broadaddr.sl.sll_halen = rta_payload;
+                         ifas[ifa_index].broadaddr.sl.sll_ifindex
+                           = ifim->ifi_index;
+                         ifas[ifa_index].broadaddr.sl.sll_hatype
+                           = ifim->ifi_type;
 
-                     ifas[ifa_index].ifa.ifa_broadaddr
-                       = &ifas[ifa_index].broadaddr.sa;
+                         ifas[ifa_index].ifa.ifa_broadaddr
+                           = &ifas[ifa_index].broadaddr.sa;
+                       }
                      break;
 
                    case IFLA_IFNAME:   /* Name of Interface */
                      if ((rta_payload + 1) <= sizeof (ifas[ifa_index].name))
                        {
                          ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name;
-                         strncpy (ifas[ifa_index].name, rta_data,
-                                  rta_payload);
-                         ifas[ifa_index].name[rta_payload] = '\0';
+                         *(char *) __mempcpy (ifas[ifa_index].name, rta_data,
+                                              rta_payload) = '\0';
                        }
                      break;
 
@@ -521,13 +528,15 @@ getifaddrs (struct ifaddrs **ifap)
              size_t rtasize = IFA_PAYLOAD (nlh);
 
              /* New Addresses are stored in the order we got them from
-                the kernel after interfaces. Theoretically it is possible
+                the kernel after the interfaces. Theoretically it is possible
                 that we have holes in the interface part of the list,
                 but we always have already the interface for this address.  */
              ifa_index = newlink + newaddr_idx;
              ifas[ifa_index].ifa.ifa_flags
-               = ifas[map_newlink (ifam->ifa_index - 1,
+               = ifas[map_newlink (ifam->ifa_index - 1, ifas,
                                    map_newlink_data, newlink)].ifa.ifa_flags;
+             if (ifa_index > 0)
+               ifas[ifa_index - 1].ifa.ifa_next = &ifas[ifa_index].ifa;
              ++newaddr_idx;
 
              while (RTA_OK (rta, rtasize))
@@ -565,21 +574,28 @@ getifaddrs (struct ifaddrs **ifap)
                        switch (ifam->ifa_family)
                          {
                          case AF_INET:
-                           memcpy (&((struct sockaddr_in *) sa)->sin_addr,
-                                   rta_data, rta_payload);
+                           /* Size must match that of an address for IPv4.  */
+                           if (rta_payload == 4)
+                             memcpy (&((struct sockaddr_in *) sa)->sin_addr,
+                                     rta_data, rta_payload);
                            break;
 
                          case AF_INET6:
-                           memcpy (&((struct sockaddr_in6 *) sa)->sin6_addr,
-                                   rta_data, rta_payload);
-                           if (IN6_IS_ADDR_LINKLOCAL (rta_data) ||
-                               IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
-                             ((struct sockaddr_in6 *) sa)->sin6_scope_id =
-                               ifam->ifa_scope;
+                           /* Size must match that of an address for IPv6.  */
+                           if (rta_payload == 16)
+                             {
+                               memcpy (&((struct sockaddr_in6 *) sa)->sin6_addr,
+                                       rta_data, rta_payload);
+                               if (IN6_IS_ADDR_LINKLOCAL (rta_data)
+                                   || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
+                                 ((struct sockaddr_in6 *) sa)->sin6_scope_id
+                                   = ifam->ifa_scope;
+                             }
                            break;
 
                          default:
-                           memcpy (sa->sa_data, rta_data, rta_payload);
+                           if (rta_payload <= sizeof (ifas[ifa_index].addr))
+                             memcpy (sa->sa_data, rta_data, rta_payload);
                            break;
                          }
                      }
@@ -605,22 +621,29 @@ getifaddrs (struct ifaddrs **ifap)
                      switch (ifam->ifa_family)
                        {
                        case AF_INET:
-                         memcpy (&ifas[ifa_index].addr.s4.sin_addr,
+                         /* Size must match that of an address for IPv4.  */
+                         if (rta_payload == 4)
+                           memcpy (&ifas[ifa_index].addr.s4.sin_addr,
                                  rta_data, rta_payload);
                          break;
 
                        case AF_INET6:
-                         memcpy (&ifas[ifa_index].addr.s6.sin6_addr,
-                                 rta_data, rta_payload);
-                         if (IN6_IS_ADDR_LINKLOCAL (rta_data) ||
-                             IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
-                           ifas[ifa_index].addr.s6.sin6_scope_id =
-                             ifam->ifa_scope;
+                         /* Size must match that of an address for IPv6.  */
+                         if (rta_payload == 16)
+                           {
+                             memcpy (&ifas[ifa_index].addr.s6.sin6_addr,
+                                     rta_data, rta_payload);
+                             if (IN6_IS_ADDR_LINKLOCAL (rta_data) ||
+                                 IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
+                               ifas[ifa_index].addr.s6.sin6_scope_id =
+                                 ifam->ifa_scope;
+                           }
                          break;
 
                        default:
-                         memcpy (ifas[ifa_index].addr.sa.sa_data,
-                                 rta_data, rta_payload);
+                         if (rta_payload <= sizeof (ifas[ifa_index].addr))
+                           memcpy (ifas[ifa_index].addr.sa.sa_data,
+                                   rta_data, rta_payload);
                          break;
                        }
                      break;
@@ -639,22 +662,29 @@ getifaddrs (struct ifaddrs **ifap)
                      switch (ifam->ifa_family)
                        {
                        case AF_INET:
-                         memcpy (&ifas[ifa_index].broadaddr.s4.sin_addr,
-                                 rta_data, rta_payload);
+                         /* Size must match that of an address for IPv4.  */
+                         if (rta_payload == 4)
+                           memcpy (&ifas[ifa_index].broadaddr.s4.sin_addr,
+                                   rta_data, rta_payload);
                          break;
 
                        case AF_INET6:
-                         memcpy (&ifas[ifa_index].broadaddr.s6.sin6_addr,
-                                 rta_data, rta_payload);
-                         if (IN6_IS_ADDR_LINKLOCAL (rta_data)
-                             || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
-                           ifas[ifa_index].broadaddr.s6.sin6_scope_id
-                             = ifam->ifa_scope;
+                         /* Size must match that of an address for IPv6.  */
+                         if (rta_payload == 16)
+                           {
+                             memcpy (&ifas[ifa_index].broadaddr.s6.sin6_addr,
+                                     rta_data, rta_payload);
+                             if (IN6_IS_ADDR_LINKLOCAL (rta_data)
+                                 || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
+                               ifas[ifa_index].broadaddr.s6.sin6_scope_id
+                                 = ifam->ifa_scope;
+                           }
                          break;
 
                        default:
-                         memcpy (&ifas[ifa_index].broadaddr.sa.sa_data,
-                                 rta_data, rta_payload);
+                         if (rta_payload <= sizeof (ifas[ifa_index].addr))
+                           memcpy (&ifas[ifa_index].broadaddr.sa.sa_data,
+                                   rta_data, rta_payload);
                          break;
                        }
                      break;
@@ -663,9 +693,8 @@ getifaddrs (struct ifaddrs **ifap)
                      if (rta_payload + 1 <= sizeof (ifas[ifa_index].name))
                        {
                          ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name;
-                         strncpy (ifas[ifa_index].name, rta_data,
-                                  rta_payload);
-                         ifas[ifa_index].name[rta_payload] = '\0';
+                         *(char *) __mempcpy (ifas[ifa_index].name, rta_data,
+                                              rta_payload) = '\0';
                        }
                      else
                        abort ();
@@ -686,7 +715,7 @@ getifaddrs (struct ifaddrs **ifap)
                 address, use the name from the interface entry.  */
              if (ifas[ifa_index].ifa.ifa_name == NULL)
                ifas[ifa_index].ifa.ifa_name
-                 = ifas[map_newlink (ifam->ifa_index - 1,
+                 = ifas[map_newlink (ifam->ifa_index - 1, ifas,
                                      map_newlink_data, newlink)].ifa.ifa_name;
 
              /* Calculate the netmask.  */
@@ -738,6 +767,24 @@ getifaddrs (struct ifaddrs **ifap)
        }
     }
 
+  assert (ifa_data_ptr <= (char *) &ifas[newlink + newaddr] + ifa_data_size);
+
+  if (newaddr_idx > 0)
+    {
+      for (i = 0; i < newlink; ++i)
+       if (map_newlink_data[i] == -1)
+         {
+           /* We have fewer links then we anticipated.  Adjust the
+              forward pointer to the first address entry.  */
+           ifas[i - 1].ifa.ifa_next = &ifas[newlink].ifa;
+         }
+
+      if (i == 0 && newlink > 0)
+       /* No valid link, but we allocated memory.  We have to
+          populate the first entry.  */
+       memmove (ifas, &ifas[newlink], sizeof (struct ifaddrs_storage));
+    }
+
   if (ifap != NULL)
     *ifap = &ifas[0].ifa;