summary refs log tree commit diff
path: root/sysdeps/unix/sysv/linux/ifaddrs.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2003-04-17 01:08:57 +0000
committerUlrich Drepper <drepper@redhat.com>2003-04-17 01:08:57 +0000
commit31dfab9e1775a673b18858af13794c50477ac76a (patch)
tree2836894ac62398d8f6679d67cc8d9aa440d0a3c4 /sysdeps/unix/sysv/linux/ifaddrs.c
parent5bdd77cb60126cbf6c96ac0d39eb49e6e45d759c (diff)
downloadglibc-31dfab9e1775a673b18858af13794c50477ac76a.tar.gz
glibc-31dfab9e1775a673b18858af13794c50477ac76a.tar.xz
glibc-31dfab9e1775a673b18858af13794c50477ac76a.zip
Update.
	* 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.
Diffstat (limited to 'sysdeps/unix/sysv/linux/ifaddrs.c')
-rw-r--r--sysdeps/unix/sysv/linux/ifaddrs.c175
1 files changed, 111 insertions, 64 deletions
diff --git a/sysdeps/unix/sysv/linux/ifaddrs.c b/sysdeps/unix/sysv/linux/ifaddrs.c
index 23a61c5662..b310043b6a 100644
--- a/sysdeps/unix/sysv/linux/ifaddrs.c
+++ b/sysdeps/unix/sysv/linux/ifaddrs.c
@@ -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;