libnm/ipv4: properly assign address-labels, and report errors from them

Report an error if the data type of the address-labels received via DBus
is not the expected.

Also, fix the assignment of the labels to their corresponding addresses.
As they are matched by array position, if any invalid address was
received, the array of addresses that we generate is shorter than the
array of address-labels. We were not considering this so we were
assigning the address-labels to incorrect addresses. Fix it by moving the
assignment of the labels to _nm_utils_ip4_addresses_from_variant, where
we still have the information of what the original position in the array
the address had.
This commit is contained in:
Íñigo Huguet 2023-11-17 11:23:07 +01:00 committed by Íñigo Huguet
parent e2ac10b97d
commit 87fc6e1a11
3 changed files with 51 additions and 17 deletions

View file

@ -425,32 +425,24 @@ ip4_addresses_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
{
gs_unref_ptrarray GPtrArray *addrs = NULL;
gs_unref_variant GVariant *s_ip4 = NULL;
gs_free const char **labels = NULL;
gs_unref_variant GVariant *labels = NULL;
gs_free char *gateway = NULL;
bool strict = NM_FLAGS_HAS(parse_flags, NM_SETTING_PARSE_FLAGS_STRICT);
guint i;
if (!_nm_setting_use_legacy_property(setting, connection_dict, "addresses", "address-data")) {
*out_is_modified = FALSE;
return TRUE;
}
addrs = _nm_utils_ip4_addresses_from_variant(value, &gateway, strict, error);
if (!addrs)
return FALSE;
s_ip4 = g_variant_lookup_value(connection_dict,
NM_SETTING_IP4_CONFIG_SETTING_NAME,
NM_VARIANT_TYPE_SETTING);
if (g_variant_lookup(s_ip4, "address-labels", "^a&s", &labels)) {
for (i = 0; i < addrs->len && labels[i]; i++) {
if (*labels[i]) {
nm_ip_address_set_attribute(addrs->pdata[i],
NM_IP_ADDRESS_ATTRIBUTE_LABEL,
g_variant_new_string(labels[i]));
}
}
}
labels = g_variant_lookup_value(s_ip4, "address-labels", NULL);
addrs = _nm_utils_ip4_addresses_from_variant(value, labels, &gateway, strict, error);
if (!addrs)
return FALSE;
g_object_set(setting,
NM_SETTING_IP_CONFIG_ADDRESSES,

View file

@ -1446,25 +1446,37 @@ nm_utils_ip4_addresses_to_variant(GPtrArray *addresses, const char *gateway)
GPtrArray *
nm_utils_ip4_addresses_from_variant(GVariant *value, char **out_gateway)
{
return _nm_utils_ip4_addresses_from_variant(value, out_gateway, FALSE, NULL);
return _nm_utils_ip4_addresses_from_variant(value, NULL, out_gateway, FALSE, NULL);
}
/**
* _nm_utils_ip4_addresses_from_variant:
* @value: a #GVariant of type 'aau'
* @labels: (optional) (nullable): a #GVariant of the type 'as'. If not-NULL,
* each element must contain a string with the labels that corresponds to each
* IP address in @value.
* @out_gateway: (out) (optional) (nullable) (transfer full): on return, will
* contain the IP gateway
* @strict: whether to parse in strict mode or best-effort mode
* @error: the error location
*
* Like #nm_utils_ip4_addresses_from_variant, but allows to parse in strict mode. In
* strict mode, parsing is aborted on first error and %NULL is returned.
* strict mode, parsing is aborted on first error and %NULL is returned. It also
* allows to parse the address-labels at the same time than the addresses.
*
* The labels need to be processed at the same time than the addresses, inside
* this function, because if there are invalid addresses they are filtered out,
* and the returned array of addresses contains less elements than the original
* array. If that happens, the caller don't know what label corresponds to what
* address, because they are matched by position in the array. If you are not
* interested in the labels, just set @labels to NULL.
*
* Returns: (transfer full) (element-type NMIPAddress): a newly allocated
* #GPtrArray of #NMIPAddress objects. In strict mode, %NULL is returned on error.
*/
GPtrArray *
_nm_utils_ip4_addresses_from_variant(GVariant *value,
GVariant *labels,
char **out_gateway,
bool strict,
GError **error)
@ -1475,6 +1487,8 @@ _nm_utils_ip4_addresses_from_variant(GVariant *value,
const guint32 *addr_array;
gsize length;
NMIPAddress *addr;
const char *label;
gsize n_labels = 0;
guint i;
addresses = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_address_unref);
@ -1492,6 +1506,21 @@ _nm_utils_ip4_addresses_from_variant(GVariant *value,
return g_steal_pointer(&addresses);
}
if (labels && !g_variant_is_of_type(labels, G_VARIANT_TYPE("as"))) {
if (strict) {
g_set_error_literal(error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("Expected \"address-labels\" of type \"as\""));
return NULL;
}
/* We still can parse the addresses, without the labels */
labels = NULL;
}
if (labels)
n_labels = g_variant_n_children(labels);
g_variant_iter_init(&iter, value);
for (i = 0; g_variant_iter_next(&iter, "@au", &item); i++) {
@ -1525,6 +1554,18 @@ _nm_utils_ip4_addresses_from_variant(GVariant *value,
continue;
}
/* We were accepting address-labels to be shorter than addresses, so
* let's continue doing so and not consider it as an error */
if (labels && i < n_labels) {
g_variant_get_child(labels, i, "&s", &label);
if (label && label[0]) {
nm_ip_address_set_attribute(addr,
NM_IP_ADDRESS_ATTRIBUTE_LABEL,
g_variant_new_string(label));
}
}
g_ptr_array_add(addresses, addr);
if (addr_array[2] && out_gateway && !*out_gateway)
*out_gateway = nm_inet4_ntop_dup(addr_array[2]);

View file

@ -1086,6 +1086,7 @@ char **_nm_utils_ip4_dns_from_variant(GVariant *value, bool strict, GError **err
GPtrArray *_nm_utils_ip4_routes_from_variant(GVariant *value, bool strict, GError **error);
GPtrArray *_nm_utils_ip4_addresses_from_variant(GVariant *value,
GVariant *labels,
char **out_gateway,
bool strict,
GError **error);