initrd: fix out-of-bounds read when detecting address family in dt_get_ipaddr_property()

The @family argument is an input and output argument.

Initially, the family is set to AF_UNSPEC, in which case the family
gets detected based on the IP address. However, we call
dt_get_ipaddr_property() multiple times to parse the netmask, the
gateway and the IP address.

That means, after the first successfull call, the @family is set to
AF_INET or AF_INET6.

Note that the previous code (in the switch block) would only check that
the family is set to AF_UNSPEC, but it would not check that the @family
matches the expected binary address length @len. Later, we then might call
nm_ip_address_new_binary() with a family and a binary address of
unexpected length.

Also drop the error checking for nm_ip_address_new_binary().
nm_ip_address_new_binary() can only fail if the prefix length is larger
than 32/128. The function has no way to validate the input arguments
beyond that and can thus not fail (short of undefined behavior).
This commit is contained in:
Thomas Haller 2019-09-21 15:27:49 +02:00
parent e7cf22be3e
commit 9618f1bb4b

View file

@ -51,40 +51,24 @@ dt_get_ipaddr_property (const char *base,
const char *prop,
int *family)
{
NMIPAddress *addr;
gs_free char *buf = NULL;
size_t len;
gs_free_error GError *error = NULL;
int f;
if (!dt_get_property (base, dev, prop, &buf, &len))
return NULL;
switch (len) {
case 4:
if (*family == AF_UNSPEC)
*family = AF_INET;
break;
case 16:
if (*family == AF_UNSPEC)
*family = AF_INET6;
break;
default:
break;
}
if (*family == AF_UNSPEC) {
f = nm_utils_addr_family_from_size (len);
if ( f == AF_UNSPEC
|| ( *family != AF_UNSPEC
&& *family != f)) {
_LOGW (LOGD_CORE, "%s: Address %s has unrecognized length (%zd)",
dev, prop, len);
return NULL;
}
addr = nm_ip_address_new_binary (*family, buf, 0, &error);
if (!addr) {
_LOGW (LOGD_CORE, "%s: Address %s is malformed: %s",
dev, prop, error->message);
}
return addr;
*family = f;
return nm_ip_address_new_binary (f, buf, 0, NULL);
}
static char *