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).

(cherry picked from commit 9618f1bb4b)
This commit is contained in:
Thomas Haller 2019-09-21 15:27:49 +02:00
parent 90c33b798e
commit 4f3e31f7c5

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 *