summaryrefslogtreecommitdiff
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)
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;