* 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.
This commit is contained in:
Ulrich Drepper 2003-04-17 01:08:57 +00:00
parent 5bdd77cb60
commit 31dfab9e17
2 changed files with 117 additions and 63 deletions

View File

@ -1,5 +1,12 @@
2003-04-16 Ulrich Drepper <drepper@redhat.com> 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 * string/test-strncpy.c (do_one_test): Mark start and stop as
possibly unused. possibly unused.

View File

@ -252,7 +252,8 @@ netlink_open (struct netlink_handle *h)
Since we get at first all RTM_NEWLINK entries, it can never happen Since we get at first all RTM_NEWLINK entries, it can never happen
that a RTM_NEWADDR index is not known to this map. */ that a RTM_NEWADDR index is not known to this map. */
static int 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; int i;
@ -261,6 +262,8 @@ map_newlink (int index, int *map, int max)
if (map[i] == -1) if (map[i] == -1)
{ {
map[i] = index; map[i] = index;
if (i > 0)
ifas[i - 1].ifa.ifa_next = &ifas[i].ifa;
return i; return i;
} }
else if (map[i] == index) else if (map[i] == index)
@ -389,9 +392,6 @@ getifaddrs (struct ifaddrs **ifap)
if ((newlink + newaddr) == 0) if ((newlink + newaddr) == 0)
goto exit_free; 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 /* Allocate memory for all entries we have and initialize next
pointer. */ pointer. */
ifas = (struct ifaddrs_storage *) calloc (1, ifas = (struct ifaddrs_storage *) calloc (1,
@ -404,11 +404,10 @@ getifaddrs (struct ifaddrs **ifap)
goto exit_free; goto exit_free;
} }
for (i = 0; i < newlink + newaddr - 1; i++) /* Table for mapping kernel index to entry in our list. */
{ map_newlink_data = alloca (newlink * sizeof (int));
ifas[i].ifa.ifa_next = &ifas[i + 1].ifa; memset (map_newlink_data, '\xff', newlink * sizeof (int));
map_newlink_data[i] = -1;
}
ifa_data_ptr = (char *) &ifas[newlink + newaddr]; ifa_data_ptr = (char *) &ifas[newlink + newaddr];
newaddr_idx = 0; /* Counter for newaddr index. */ newaddr_idx = 0; /* Counter for newaddr index. */
@ -447,7 +446,7 @@ getifaddrs (struct ifaddrs **ifap)
/* Interfaces are stored in the first "newlink" entries /* Interfaces are stored in the first "newlink" entries
of our list, starting in the order as we got from the of our list, starting in the order as we got from the
kernel. */ kernel. */
ifa_index = map_newlink (ifim->ifi_index - 1, ifa_index = map_newlink (ifim->ifi_index - 1, ifas,
map_newlink_data, newlink); map_newlink_data, newlink);
ifas[ifa_index].ifa.ifa_flags = ifim->ifi_flags; ifas[ifa_index].ifa.ifa_flags = ifim->ifi_flags;
@ -459,36 +458,44 @@ getifaddrs (struct ifaddrs **ifap)
switch (rta->rta_type) switch (rta->rta_type)
{ {
case IFLA_ADDRESS: case IFLA_ADDRESS:
if (rta_payload <= sizeof (ifas[ifa_index].addr))
{
ifas[ifa_index].addr.sl.sll_family = AF_PACKET; ifas[ifa_index].addr.sl.sll_family = AF_PACKET;
memcpy (ifas[ifa_index].addr.sl.sll_addr, memcpy (ifas[ifa_index].addr.sl.sll_addr,
(char *) rta_data, rta_payload); (char *) rta_data, rta_payload);
ifas[ifa_index].addr.sl.sll_halen = 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_ifindex
= ifim->ifi_index;
ifas[ifa_index].addr.sl.sll_hatype = ifim->ifi_type; ifas[ifa_index].addr.sl.sll_hatype = ifim->ifi_type;
ifas[ifa_index].ifa.ifa_addr = &ifas[ifa_index].addr.sa; ifas[ifa_index].ifa.ifa_addr
= &ifas[ifa_index].addr.sa;
}
break; break;
case IFLA_BROADCAST: case IFLA_BROADCAST:
if (rta_payload <= sizeof (ifas[ifa_index].broadaddr))
{
ifas[ifa_index].broadaddr.sl.sll_family = AF_PACKET; ifas[ifa_index].broadaddr.sl.sll_family = AF_PACKET;
memcpy (ifas[ifa_index].broadaddr.sl.sll_addr, memcpy (ifas[ifa_index].broadaddr.sl.sll_addr,
(char *) rta_data, rta_payload); (char *) rta_data, rta_payload);
ifas[ifa_index].broadaddr.sl.sll_halen = rta_payload; ifas[ifa_index].broadaddr.sl.sll_halen = rta_payload;
ifas[ifa_index].broadaddr.sl.sll_ifindex ifas[ifa_index].broadaddr.sl.sll_ifindex
= ifim->ifi_index; = ifim->ifi_index;
ifas[ifa_index].broadaddr.sl.sll_hatype = ifim->ifi_type; ifas[ifa_index].broadaddr.sl.sll_hatype
= ifim->ifi_type;
ifas[ifa_index].ifa.ifa_broadaddr ifas[ifa_index].ifa.ifa_broadaddr
= &ifas[ifa_index].broadaddr.sa; = &ifas[ifa_index].broadaddr.sa;
}
break; break;
case IFLA_IFNAME: /* Name of Interface */ case IFLA_IFNAME: /* Name of Interface */
if ((rta_payload + 1) <= sizeof (ifas[ifa_index].name)) if ((rta_payload + 1) <= sizeof (ifas[ifa_index].name))
{ {
ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name; ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name;
strncpy (ifas[ifa_index].name, rta_data, *(char *) __mempcpy (ifas[ifa_index].name, rta_data,
rta_payload); rta_payload) = '\0';
ifas[ifa_index].name[rta_payload] = '\0';
} }
break; break;
@ -521,13 +528,15 @@ getifaddrs (struct ifaddrs **ifap)
size_t rtasize = IFA_PAYLOAD (nlh); size_t rtasize = IFA_PAYLOAD (nlh);
/* New Addresses are stored in the order we got them from /* 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, that we have holes in the interface part of the list,
but we always have already the interface for this address. */ but we always have already the interface for this address. */
ifa_index = newlink + newaddr_idx; ifa_index = newlink + newaddr_idx;
ifas[ifa_index].ifa.ifa_flags 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; map_newlink_data, newlink)].ifa.ifa_flags;
if (ifa_index > 0)
ifas[ifa_index - 1].ifa.ifa_next = &ifas[ifa_index].ifa;
++newaddr_idx; ++newaddr_idx;
while (RTA_OK (rta, rtasize)) while (RTA_OK (rta, rtasize))
@ -565,20 +574,27 @@ getifaddrs (struct ifaddrs **ifap)
switch (ifam->ifa_family) switch (ifam->ifa_family)
{ {
case AF_INET: case AF_INET:
/* Size must match that of an address for IPv4. */
if (rta_payload == 4)
memcpy (&((struct sockaddr_in *) sa)->sin_addr, memcpy (&((struct sockaddr_in *) sa)->sin_addr,
rta_data, rta_payload); rta_data, rta_payload);
break; break;
case AF_INET6: case AF_INET6:
/* Size must match that of an address for IPv6. */
if (rta_payload == 16)
{
memcpy (&((struct sockaddr_in6 *) sa)->sin6_addr, memcpy (&((struct sockaddr_in6 *) sa)->sin6_addr,
rta_data, rta_payload); rta_data, rta_payload);
if (IN6_IS_ADDR_LINKLOCAL (rta_data) || if (IN6_IS_ADDR_LINKLOCAL (rta_data)
IN6_IS_ADDR_MC_LINKLOCAL (rta_data)) || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
((struct sockaddr_in6 *) sa)->sin6_scope_id = ((struct sockaddr_in6 *) sa)->sin6_scope_id
ifam->ifa_scope; = ifam->ifa_scope;
}
break; break;
default: default:
if (rta_payload <= sizeof (ifas[ifa_index].addr))
memcpy (sa->sa_data, rta_data, rta_payload); memcpy (sa->sa_data, rta_data, rta_payload);
break; break;
} }
@ -605,20 +621,27 @@ getifaddrs (struct ifaddrs **ifap)
switch (ifam->ifa_family) switch (ifam->ifa_family)
{ {
case AF_INET: case AF_INET:
/* Size must match that of an address for IPv4. */
if (rta_payload == 4)
memcpy (&ifas[ifa_index].addr.s4.sin_addr, memcpy (&ifas[ifa_index].addr.s4.sin_addr,
rta_data, rta_payload); rta_data, rta_payload);
break; break;
case AF_INET6: case AF_INET6:
/* Size must match that of an address for IPv6. */
if (rta_payload == 16)
{
memcpy (&ifas[ifa_index].addr.s6.sin6_addr, memcpy (&ifas[ifa_index].addr.s6.sin6_addr,
rta_data, rta_payload); rta_data, rta_payload);
if (IN6_IS_ADDR_LINKLOCAL (rta_data) || if (IN6_IS_ADDR_LINKLOCAL (rta_data) ||
IN6_IS_ADDR_MC_LINKLOCAL (rta_data)) IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
ifas[ifa_index].addr.s6.sin6_scope_id = ifas[ifa_index].addr.s6.sin6_scope_id =
ifam->ifa_scope; ifam->ifa_scope;
}
break; break;
default: default:
if (rta_payload <= sizeof (ifas[ifa_index].addr))
memcpy (ifas[ifa_index].addr.sa.sa_data, memcpy (ifas[ifa_index].addr.sa.sa_data,
rta_data, rta_payload); rta_data, rta_payload);
break; break;
@ -639,20 +662,27 @@ getifaddrs (struct ifaddrs **ifap)
switch (ifam->ifa_family) switch (ifam->ifa_family)
{ {
case AF_INET: case AF_INET:
/* Size must match that of an address for IPv4. */
if (rta_payload == 4)
memcpy (&ifas[ifa_index].broadaddr.s4.sin_addr, memcpy (&ifas[ifa_index].broadaddr.s4.sin_addr,
rta_data, rta_payload); rta_data, rta_payload);
break; break;
case AF_INET6: case AF_INET6:
/* Size must match that of an address for IPv6. */
if (rta_payload == 16)
{
memcpy (&ifas[ifa_index].broadaddr.s6.sin6_addr, memcpy (&ifas[ifa_index].broadaddr.s6.sin6_addr,
rta_data, rta_payload); rta_data, rta_payload);
if (IN6_IS_ADDR_LINKLOCAL (rta_data) if (IN6_IS_ADDR_LINKLOCAL (rta_data)
|| IN6_IS_ADDR_MC_LINKLOCAL (rta_data)) || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
ifas[ifa_index].broadaddr.s6.sin6_scope_id ifas[ifa_index].broadaddr.s6.sin6_scope_id
= ifam->ifa_scope; = ifam->ifa_scope;
}
break; break;
default: default:
if (rta_payload <= sizeof (ifas[ifa_index].addr))
memcpy (&ifas[ifa_index].broadaddr.sa.sa_data, memcpy (&ifas[ifa_index].broadaddr.sa.sa_data,
rta_data, rta_payload); rta_data, rta_payload);
break; break;
@ -663,9 +693,8 @@ getifaddrs (struct ifaddrs **ifap)
if (rta_payload + 1 <= sizeof (ifas[ifa_index].name)) if (rta_payload + 1 <= sizeof (ifas[ifa_index].name))
{ {
ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name; ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name;
strncpy (ifas[ifa_index].name, rta_data, *(char *) __mempcpy (ifas[ifa_index].name, rta_data,
rta_payload); rta_payload) = '\0';
ifas[ifa_index].name[rta_payload] = '\0';
} }
else else
abort (); abort ();
@ -686,7 +715,7 @@ getifaddrs (struct ifaddrs **ifap)
address, use the name from the interface entry. */ address, use the name from the interface entry. */
if (ifas[ifa_index].ifa.ifa_name == NULL) if (ifas[ifa_index].ifa.ifa_name == NULL)
ifas[ifa_index].ifa.ifa_name 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; map_newlink_data, newlink)].ifa.ifa_name;
/* Calculate the netmask. */ /* 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) if (ifap != NULL)
*ifap = &ifas[0].ifa; *ifap = &ifas[0].ifa;