From 326fb8f9cfcb3374cbcb520d2701f5ae0ccc4d3b Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 4 Jul 2025 14:28:26 +0200 Subject: [PATCH 01/22] initrd: make parsing of VLANs more robust We are missing some validations when parsing VLANs: a unexpected argument can cause a crash, an assertion, or the connection being dropped without any warning. Make it more robust. --- src/nm-initrd-generator/nmi-cmdline-reader.c | 31 +++++++--- .../tests/test-cmdline-reader.c | 61 +++++++++++++++++++ 2 files changed, 85 insertions(+), 7 deletions(-) diff --git a/src/nm-initrd-generator/nmi-cmdline-reader.c b/src/nm-initrd-generator/nmi-cmdline-reader.c index ba5380afb2..89deddf0a3 100644 --- a/src/nm-initrd-generator/nmi-cmdline-reader.c +++ b/src/nm-initrd-generator/nmi-cmdline-reader.c @@ -1063,27 +1063,44 @@ reader_parse_vlan(Reader *reader, char *argument) const char *vlan; const char *phy; const char *vlanid; + guint64 id; vlan = get_word(&argument, ':'); phy = get_word(&argument, ':'); + if (!vlan) { + _LOGW(LOGD_CORE, "missing VLAN interface name"); + return; + } + + if (!phy) { + _LOGW(LOGD_CORE, "missing VLAN parent"); + return; + } + for (vlanid = vlan + strlen(vlan); vlanid > vlan; vlanid--) { if (!g_ascii_isdigit(*(vlanid - 1))) break; } + if (vlanid[0] == '\0') { + _LOGW(LOGD_CORE, "missing VLAN id in '%s'", vlan); + return; + } + + id = _nm_utils_ascii_str_to_int64(vlanid, 10, 0, 4094, G_MAXUINT); + if (id == G_MAXUINT) { + _LOGW(LOGD_CORE, "invalid VLAN id '%s'", vlanid); + return; + } + connection = reader_get_connection(reader, vlan, NM_SETTING_VLAN_SETTING_NAME, TRUE); s_vlan = nm_connection_get_setting_vlan(connection); - g_object_set(s_vlan, - NM_SETTING_VLAN_PARENT, - phy, - NM_SETTING_VLAN_ID, - (guint) _nm_utils_ascii_str_to_int64(vlanid, 10, 0, G_MAXUINT, G_MAXUINT), - NULL); + g_object_set(s_vlan, NM_SETTING_VLAN_PARENT, phy, NM_SETTING_VLAN_ID, (guint32) id, NULL); if (argument && *argument) - _LOGW(LOGD_CORE, "Ignoring extra: '%s'.", argument); + _LOGW(LOGD_CORE, "ignoring extra VLAN argument '%s'", argument); if (!nm_strv_ptrarray_contains(reader->vlan_parents, phy)) g_ptr_array_add(reader->vlan_parents, g_strdup(phy)); diff --git a/src/nm-initrd-generator/tests/test-cmdline-reader.c b/src/nm-initrd-generator/tests/test-cmdline-reader.c index cd7b1069b6..413f61c655 100644 --- a/src/nm-initrd-generator/tests/test-cmdline-reader.c +++ b/src/nm-initrd-generator/tests/test-cmdline-reader.c @@ -1846,6 +1846,66 @@ test_vlan_over_bond(void) } } +static void +test_vlan_invalid(void) +{ + { + /* Case 1: Missing name */ + const char *const *ARGV0 = NM_MAKE_STRV("vlan="); + gs_unref_hashtable GHashTable *connections = NULL; + + NMTST_EXPECT_NM_WARN("cmdline-reader: missing VLAN interface name"); + connections = _parse_cons(ARGV0); + g_assert_cmpint(g_hash_table_size(connections), ==, 0); + g_test_assert_expected_messages(); + } + + { + /* Case 2: Missing parent */ + const char *const *ARGV0 = NM_MAKE_STRV("vlan=vlan12"); + gs_unref_hashtable GHashTable *connections = NULL; + + NMTST_EXPECT_NM_WARN("cmdline-reader: missing VLAN parent"); + connections = _parse_cons(ARGV0); + g_assert_cmpint(g_hash_table_size(connections), ==, 0); + g_test_assert_expected_messages(); + } + + { + /* Case 3: Interface name without trailing digits should fail, + * not trigger a GLib assertion. */ + const char *const *ARGV0 = NM_MAKE_STRV("vlan=myvlan:eth0"); + gs_unref_hashtable GHashTable *connections = NULL; + + NMTST_EXPECT_NM_WARN("cmdline-reader: missing VLAN id in 'myvlan'"); + connections = _parse_cons(ARGV0); + g_assert_cmpint(g_hash_table_size(connections), ==, 0); + g_test_assert_expected_messages(); + } + + { + /* Case 4: An invalid VLAN id should be rejected */ + const char *const *ARGV0 = NM_MAKE_STRV("vlan=myvlan4095:eth0"); + gs_unref_hashtable GHashTable *connections = NULL; + + NMTST_EXPECT_NM_WARN("cmdline-reader: invalid VLAN id '4095'"); + connections = _parse_cons(ARGV0); + g_assert_cmpint(g_hash_table_size(connections), ==, 0); + g_test_assert_expected_messages(); + } + + { + /* Case 5: Extra arguments */ + const char *const *ARGV0 = NM_MAKE_STRV("vlan=eth0.80:eth0:reorder_hdr=on"); + gs_unref_hashtable GHashTable *connections = NULL; + + NMTST_EXPECT_NM_WARN("cmdline-reader: ignoring extra VLAN argument 'reorder_hdr=on'"); + connections = _parse_cons(ARGV0); + g_assert_cmpint(g_hash_table_size(connections), ==, 2); + g_test_assert_expected_messages(); + } +} + static void test_ibft_ip_dev(void) { @@ -2820,6 +2880,7 @@ main(int argc, char **argv) g_test_add_func("/initrd/cmdline/vlan", test_vlan); g_test_add_func("/initrd/cmdline/vlan/dhcp-on-parent", test_vlan_with_dhcp_on_parent); g_test_add_func("/initrd/cmdline/vlan/over-bond", test_vlan_over_bond); + g_test_add_func("/initrd/cmdline/vlan/invalid", test_vlan_invalid); g_test_add_func("/initrd/cmdline/bridge", test_bridge); g_test_add_func("/initrd/cmdline/bridge/default", test_bridge_default); g_test_add_func("/initrd/cmdline/bridge/ip", test_bridge_ip); From 45ab9d96f1afb086447b4ce3540ed78d721b7ff0 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 4 Jul 2025 14:47:31 +0200 Subject: [PATCH 02/22] platform: use g_strdup() instead of strdup() in ethtool code The string is freed with g_free(), it needs to be allocated with g_strdup(). In practice, the GLib allocator uses malloc() nowadays, but it is better to be consistent. --- src/libnm-platform/nmp-ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libnm-platform/nmp-ethtool.c b/src/libnm-platform/nmp-ethtool.c index ed028f6a1c..28d12ffb1e 100644 --- a/src/libnm-platform/nmp-ethtool.c +++ b/src/libnm-platform/nmp-ethtool.c @@ -153,7 +153,7 @@ ethtool_send_and_recv(struct nl_sock *sock, out: if (nle < 0 && err_msg && *err_msg == NULL) - *err_msg = strdup(nm_strerror(nle)); + *err_msg = g_strdup(nm_strerror(nle)); if (nle >= 0 && cb_result < 0) nle = cb_result; From 253800238eaa062573276db0ea146afc926760a1 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 4 Jul 2025 15:18:27 +0200 Subject: [PATCH 03/22] libnm-core,core: accept uid/gid up to (2^32 - 2) for tun devices Linux UIDs/GIDs are 32-bit unsigned integer, with 4294967295 reserved as undefined. Before: # useradd -u 4294967294 -M testuser useradd warning: testuser's uid -2 outside of the UID_MIN 1000 and UID_MAX 60000 range. # nmcli connection add type tun ifname tun1 owner 4294967294 ipv4.method disabled ipv6.method disabled Error: Failed to add 'tun-tun1' connection: tun.owner: '4294967294': invalid user ID After: # useradd -u 4294967294 -M testuser useradd warning: testuser's uid -2 outside of the UID_MIN 1000 and UID_MAX 60000 range. # nmcli connection add type tun ifname tun1 owner 4294967294 ipv4.method disabled ipv6.method disabled Connection 'tun-tun1' (5da24d19-1723-45d5-8e04-c976f7a251d0) successfully added. # ip -d link show tun1 2421: tun1: mtu 1500 qdisc fq_codel state DOWN mode DEFAULT group default qlen 500 link/none promiscuity 0 allmulti 0 minmtu 68 maxmtu 65535 tun type tun pi off vnet_hdr off persist on user testuser ... ^^^^^^^^^^^^^ Fixes: 1f30147a7a83 ('libnm-core: add NMSettingTun') --- src/core/devices/nm-device-tun.c | 8 +++++--- src/libnm-core-impl/nm-setting-tun.c | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/core/devices/nm-device-tun.c b/src/core/devices/nm-device-tun.c index faab86d0a9..b277c378a2 100644 --- a/src/core/devices/nm-device-tun.c +++ b/src/core/devices/nm-device-tun.c @@ -242,12 +242,14 @@ create_and_realize(NMDevice *device, g_return_val_if_reached(FALSE); } - owner = _nm_utils_ascii_str_to_int64(nm_setting_tun_get_owner(s_tun), 10, 0, G_MAXINT32, -1); + owner = + _nm_utils_ascii_str_to_int64(nm_setting_tun_get_owner(s_tun), 10, 0, G_MAXUINT32 - 1, -1); if (owner != -1) { props.owner_valid = TRUE; props.owner = owner; } - group = _nm_utils_ascii_str_to_int64(nm_setting_tun_get_group(s_tun), 10, 0, G_MAXINT32, -1); + group = + _nm_utils_ascii_str_to_int64(nm_setting_tun_get_group(s_tun), 10, 0, G_MAXUINT32 - 1, -1); if (group != -1) { props.group_valid = TRUE; props.group = group; @@ -278,7 +280,7 @@ _same_og(const char *str, gboolean og_valid, guint32 og_num) { gint64 v; - v = _nm_utils_ascii_str_to_int64(str, 10, 0, G_MAXINT32, -1); + v = _nm_utils_ascii_str_to_int64(str, 10, 0, G_MAXUINT32 - 1, -1); return (!og_valid && (v == (gint64) -1)) || (og_valid && (((guint32) v) == og_num)); } diff --git a/src/libnm-core-impl/nm-setting-tun.c b/src/libnm-core-impl/nm-setting-tun.c index 05460104a4..cac0f10beb 100644 --- a/src/libnm-core-impl/nm-setting-tun.c +++ b/src/libnm-core-impl/nm-setting-tun.c @@ -166,7 +166,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) } if (priv->owner) { - if (_nm_utils_ascii_str_to_int64(priv->owner, 10, 0, G_MAXINT32, -1) == -1) { + if (_nm_utils_ascii_str_to_int64(priv->owner, 10, 0, G_MAXUINT32 - 1, -1) == -1) { g_set_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -178,7 +178,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) } if (priv->group) { - if (_nm_utils_ascii_str_to_int64(priv->group, 10, 0, G_MAXINT32, -1) == -1) { + if (_nm_utils_ascii_str_to_int64(priv->group, 10, 0, G_MAXUINT32 - 1, -1) == -1) { g_set_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, From 55765d29147b48fa2295a547a8aba0556f60cb59 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 4 Jul 2025 16:59:43 +0200 Subject: [PATCH 04/22] ovs: fix logging message Fixes: a259303e1d5a ('ovs: add support for "other_config" settings') --- src/core/devices/ovs/nm-ovsdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index 74fcd80bc8..164bfd3565 100644 --- a/src/core/devices/ovs/nm-ovsdb.c +++ b/src/core/devices/ovs/nm-ovsdb.c @@ -2249,7 +2249,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) ovs_bridge->connection_uuid, ""), (strtmp1 = _strdict_to_string(ovs_bridge->external_ids)), - (strtmp2 = _strdict_to_string(ovs_bridge->external_ids))); + (strtmp2 = _strdict_to_string(ovs_bridge->other_config))); } } else { gs_free char *strtmp1 = NULL; From 62558d50be377f670c85416d2268b55d5ac82c77 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 4 Jul 2025 18:04:56 +0200 Subject: [PATCH 05/22] core: fix constant name for IPv4 method Fix the name for consistency, even if this is harmless because the IPv4 and IPv6 values are the same. --- src/core/devices/nm-device-ethernet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/devices/nm-device-ethernet.c b/src/core/devices/nm-device-ethernet.c index 4034fdaad6..3bc74d80e2 100644 --- a/src/core/devices/nm-device-ethernet.c +++ b/src/core/devices/nm-device-ethernet.c @@ -1894,7 +1894,7 @@ get_ip_method_auto(NMDevice *device, int addr_family) /* We cannot do DHCPv4 on a PPP link, instead we get "auto" IP addresses * by pppd. Return "manual" here, which has the suitable effect to a * (zero) manual addresses in addition. */ - return NM_SETTING_IP6_CONFIG_METHOD_MANUAL; + return NM_SETTING_IP4_CONFIG_METHOD_MANUAL; } return NM_SETTING_IP6_CONFIG_METHOD_AUTO; From 404a3ec8531482e0db8ef39b75ec1ed9d9b04be7 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 4 Jul 2025 18:26:59 +0200 Subject: [PATCH 06/22] core: fix properties update for HSR devices Fixes: 5426bdf4a122 ('HSR: add support to HSR/PRP interface') --- src/core/devices/nm-device-hsr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/devices/nm-device-hsr.c b/src/core/devices/nm-device-hsr.c index 8156fa7796..59454ee341 100644 --- a/src/core/devices/nm-device-hsr.c +++ b/src/core/devices/nm-device-hsr.c @@ -94,8 +94,10 @@ update_properties(NMDevice *device) CHECK_PROPERTY_CHANGED(multicast_spec, PROP_MULTICAST_SPEC); CHECK_PROPERTY_CHANGED(prp, PROP_PRP); - if (!nm_ether_addr_equal(&priv->props.supervision_address, &props->supervision_address)) + if (!nm_ether_addr_equal(&priv->props.supervision_address, &props->supervision_address)) { + priv->props.supervision_address = props->supervision_address; _notify(self, PROP_SUPERVISION_ADDRESS); + } g_object_thaw_notify((GObject *) device); } From 1229fe5abdc907407196fd557fee9e0a31f04c0d Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 4 Jul 2025 18:31:42 +0200 Subject: [PATCH 07/22] bond: fix attribute assignment macro Currently the bug is hidden because the macro is only called with NM_SETTING_BOND_OPTION_ARP_IP_TARGET. Fixes: 45c95e9314cd ('device/bond: rework setting of arp_ip_target bond options') --- src/core/devices/nm-device-bond.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index 0915e9156a..673d236194 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -137,13 +137,13 @@ _set_bond_attr(NMDevice *device, const char *attr, const char *value) return ret; } -#define _set_bond_attr_take(device, attr, value) \ - G_STMT_START \ - { \ - gs_free char *_tmp = (value); \ - \ - _set_bond_attr(device, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, _tmp); \ - } \ +#define _set_bond_attr_take(device, attr, value) \ + G_STMT_START \ + { \ + gs_free char *_tmp = (value); \ + \ + _set_bond_attr(device, attr, _tmp); \ + } \ G_STMT_END #define _set_bond_attr_printf(device, attr, fmt, ...) \ From 20a1d7e8163d00b837b552b7b477a0c631c90f3a Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 4 Jul 2025 18:37:48 +0200 Subject: [PATCH 08/22] vrf: fix wrong logging domain Fixes: 667568d1b2be ('core,libnm: add VRF support') --- src/core/devices/nm-device-vrf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/devices/nm-device-vrf.c b/src/core/devices/nm-device-vrf.c index 7dfd6504a1..6d272a95cc 100644 --- a/src/core/devices/nm-device-vrf.c +++ b/src/core/devices/nm-device-vrf.c @@ -235,7 +235,7 @@ attach_port(NMDevice *device, _LOGI(LOGD_DEVICE, "attached VRF port %s", port_iface); } else - _LOGI(LOGD_BOND, "VRF port %s was attached", port_iface); + _LOGI(LOGD_DEVICE, "VRF port %s was attached", port_iface); return TRUE; } From ce17284c3f71322101f9dcc2272405c533dafc51 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 4 Jul 2025 22:14:32 +0200 Subject: [PATCH 09/22] lldp: fix memchr() argument order The validation of embedded NUL character was skipped due to the wrong order of arguments to memchr(). Fix it. Fixes: 4043f8279003 ('lldp: cleanup converting binary LLDP fields to string') --- src/core/devices/nm-lldp-listener.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/devices/nm-lldp-listener.c b/src/core/devices/nm-lldp-listener.c index e08b379adf..5c90911fc3 100644 --- a/src/core/devices/nm-lldp-listener.c +++ b/src/core/devices/nm-lldp-listener.c @@ -310,7 +310,7 @@ format_string(const guint8 *data, gsize len, gboolean allow_trim, char **out_to_ if (len == 0) return NULL; - if (memchr(data, len, '\0')) + if (memchr(data, '\0', len)) return NULL; return nm_utils_buf_utf8safe_escape(data, From 50a400e16f1a98b2c22ac6dad74102a5da91a04a Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 7 Jul 2025 09:55:14 +0200 Subject: [PATCH 10/22] supplicant: fix wrong check on "EAP" signal arguments The check is inverted. Fixes: b83f07916a54 ('supplicant: large rework of wpa_supplicant handling') --- src/core/supplicant/nm-supplicant-interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/supplicant/nm-supplicant-interface.c b/src/core/supplicant/nm-supplicant-interface.c index d5f56dcde4..514b7c0d39 100644 --- a/src/core/supplicant/nm-supplicant-interface.c +++ b/src/core/supplicant/nm-supplicant-interface.c @@ -3082,7 +3082,7 @@ _signal_handle(NMSupplicantInterface *self, const char *status; const char *parameter; - if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(ss)"))) + if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(ss)"))) return; g_variant_get(parameters, "(&s&s)", &status, ¶meter); From 43f738473cee66744775a829c79720d97099fe93 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 7 Jul 2025 09:56:29 +0200 Subject: [PATCH 11/22] core: remove duplicate include --- src/core/devices/nm-device-ethernet.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/devices/nm-device-ethernet.c b/src/core/devices/nm-device-ethernet.c index 3bc74d80e2..2059ce4279 100644 --- a/src/core/devices/nm-device-ethernet.c +++ b/src/core/devices/nm-device-ethernet.c @@ -14,7 +14,6 @@ #include #include -#include "NetworkManagerUtils.h" #include "NetworkManagerUtils.h" #include "libnm-core-aux-intern/nm-libnm-core-utils.h" #include "libnm-core-intern/nm-core-internal.h" From a9d7abbc5023b51a6e4e8a5e2644fd1a2a20c838 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 7 Jul 2025 09:32:16 +0200 Subject: [PATCH 12/22] dhcp: fix parsing of the search list option The DHCP search list option (119) can use the "message compression" algorithm specified in RFC 1035 section 4.1.4 to reduce the size of the message in presence of subdomains that appear multiple times. When using the compression a label starts with: +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | 1 1| OFFSET | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ where the offset points to a previous domain. Previously, the parsing code was taking the lower 6 bits of the first byte, shifting them left 16 bits, and adding the next byte. Instead, the shift should be of 8 bits. The effect of this bug was that when the offset was greater than 255, it was incorrectly parsed as a number larger than the message size, and the parsing failed. Note that while a single DHCP option can be at most 255 bytes, a DHCP message can contain multiple instances of the same option. The receiver must concatenate all the occurrences according to RFC 3396 and parse the resulting buffer. Fixes: 6adade6f21d5 ('dhcp: add nettools dhcp4 client') --- src/core/dhcp/nm-dhcp-utils.c | 2 +- src/core/dhcp/tests/test-dhcp-utils.c | 70 +++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/core/dhcp/nm-dhcp-utils.c b/src/core/dhcp/nm-dhcp-utils.c index 15293fa389..949d87207f 100644 --- a/src/core/dhcp/nm-dhcp-utils.c +++ b/src/core/dhcp/nm-dhcp-utils.c @@ -1224,7 +1224,7 @@ lease_option_print_domain_name(const uint8_t *cache, } case 0xC0: /* back pointer */ { - size_t offset = (c & 0x3F) << 16; + size_t offset = (c & 0x3F) << 8; /* * The offset is given as two bytes (in big endian), where the diff --git a/src/core/dhcp/tests/test-dhcp-utils.c b/src/core/dhcp/tests/test-dhcp-utils.c index b81523e19b..de1be6538c 100644 --- a/src/core/dhcp/tests/test-dhcp-utils.c +++ b/src/core/dhcp/tests/test-dhcp-utils.c @@ -239,6 +239,76 @@ test_parse_search_list(void) g_assert_cmpint(g_strv_length(domains), ==, 1); g_assert_cmpstr(domains[0], ==, "okay"); g_strfreev(domains); + + /* Test that the message compression works when the offset uses both bytes */ + data = (guint8[]) { + /* clang-format off */ + /* offset 0 */ + 0x3e, + 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a', + 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a', + 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a', + 'a','a','a','a','a','a','a','a','a','a','a','a','a','a', + 0x00, + /* offset 0x40 */ + 0x3e, + 'b','b','b','b','b','b','b','b','b','b','b','b','b','b','b','b', + 'b','b','b','b','b','b','b','b','b','b','b','b','b','b','b','b', + 'b','b','b','b','b','b','b','b','b','b','b','b','b','b','b','b', + 'b','b','b','b','b','b','b','b','b','b','b','b','b','b', + 0x00, + /* offset 0x80 */ + 0x3e, + 'c','c','c','c','c','c','c','c','c','c','c','c','c','c','c','c', + 'c','c','c','c','c','c','c','c','c','c','c','c','c','c','c','c', + 'c','c','c','c','c','c','c','c','c','c','c','c','c','c','c','c', + 'c','c','c','c','c','c','c','c','c','c','c','c','c','c', + 0x00, + /* offset 0xc0 */ + 0x3e, + 'd','d','d','d','d','d','d','d','d','d','d','d','d','d','d','d', + 'd','d','d','d','d','d','d','d','d','d','d','d','d','d','d','d', + 'd','d','d','d','d','d','d','d','d','d','d','d','d','d','d','d', + 'd','d','d','d','d','d','d','d','d','d','d','d','d','d', + 0x00, + /* offset 0x100 */ + 0x3e, + 'e','e','e','e','e','e','e','e','e','e','e','e','e','e','e','e', + 'e','e','e','e','e','e','e','e','e','e','e','e','e','e','e','e', + 'e','e','e','e','e','e','e','e','e','e','e','e','e','e','e','e', + 'e','e','e','e','e','e','e','e','e','e','e','e','e','e', + 0x00, + /* offset 0x140 */ + 0x06, 'f','o','o','b','a','r', 0x03, 'c', 'o', 'm', 0x00, + 0x04, 't', 'e', 's', 't', 0xc1, 0x40, /* back pointer to offset 0x140*/ + /* clang-format on */ + }; + + domains = nm_dhcp_lease_data_parse_search_list(data, + 0x153, + "eth0", + AF_INET, + NM_DHCP_OPTION_DHCP4_DOMAIN_SEARCH_LIST); + g_assert(domains); + g_assert_cmpint(g_strv_length(domains), ==, 7); + g_assert_cmpstr(domains[0], + ==, + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + g_assert_cmpstr(domains[1], + ==, + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); + g_assert_cmpstr(domains[2], + ==, + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"); + g_assert_cmpstr(domains[3], + ==, + "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"); + g_assert_cmpstr(domains[4], + ==, + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"); + g_assert_cmpstr(domains[5], ==, "foobar.com"); + g_assert_cmpstr(domains[6], ==, "test.foobar.com"); + g_strfreev(domains); } static void From d017dc67b42a1060b9e892d4dc14f461711fda23 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 7 Jul 2025 09:58:43 +0200 Subject: [PATCH 13/22] dhcp: fix typo in tcp_keepalive_interval option name Fixes: eed205bff317 ('dhcp/internal: move dhcp options management to shared dhcp codebase') --- src/core/dhcp/nm-dhcp-options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/dhcp/nm-dhcp-options.c b/src/core/dhcp/nm-dhcp-options.c index ce03c60771..30cfd8e68f 100644 --- a/src/core/dhcp/nm-dhcp-options.c +++ b/src/core/dhcp/nm-dhcp-options.c @@ -68,7 +68,7 @@ const NMDhcpOption _nm_dhcp_option_dhcp4_options[] = { REQ(NM_DHCP_OPTION_DHCP4_ARP_CACHE_TIMEOUT, "arp_cache_timeout", FALSE), REQ(NM_DHCP_OPTION_DHCP4_IEEE802_3_ENCAPSULATION, "ieee802_3_encapsulation", FALSE), REQ(NM_DHCP_OPTION_DHCP4_DEFAULT_TCP_TTL, "default_tcp_ttl", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_TCP_KEEPALIVE_INTERVAL, "tcp_keepalive_internal", FALSE), + REQ(NM_DHCP_OPTION_DHCP4_TCP_KEEPALIVE_INTERVAL, "tcp_keepalive_interval", FALSE), REQ(NM_DHCP_OPTION_DHCP4_TCP_KEEPALIVE_GARBAGE, "tcp_keepalive_garbage", FALSE), REQ(NM_DHCP_OPTION_DHCP4_VENDOR_SPECIFIC, "vendor_encapsulated_options", FALSE), REQ(NM_DHCP_OPTION_DHCP4_NETBIOS_NAMESERVER, "netbios_name_servers", FALSE), From 7d23ed9f73abec2d6f5b760e094284d4a239931e Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 7 Jul 2025 09:38:45 +0200 Subject: [PATCH 14/22] platform: rename nm_linux_platform_get_link_fdb_table() Rename nm_linux_platform_get_link_fdb_table() to nm_linux_platform_get_bridge_fdb(). The new name better indicates that the function returns the bridge FDB entries. --- src/core/nm-bond-manager.c | 2 +- src/libnm-platform/nm-linux-platform.c | 2 +- src/libnm-platform/nm-linux-platform.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/nm-bond-manager.c b/src/core/nm-bond-manager.c index 116cb73744..a29ce679d6 100644 --- a/src/core/nm-bond-manager.c +++ b/src/core/nm-bond-manager.c @@ -920,7 +920,7 @@ nm_bond_manager_send_arp(int bond_ifindex, int i; gs_free NMEtherAddr **fdb_addrs = NULL; - fdb_addrs = nm_linux_platform_get_link_fdb_table(platform, ifindexes, 2); + fdb_addrs = nm_linux_platform_get_bridge_fdb(platform, ifindexes, 2); /* we want to send a Reverse ARP (RARP) packet */ data.op = htons(ARP_OP_RARP); diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 2cc50f8f77..f796e53dfb 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -10519,7 +10519,7 @@ parse_fdb_cb(const struct nl_msg *msg, void *arg) } NMEtherAddr ** -nm_linux_platform_get_link_fdb_table(NMPlatform *platform, int *ifindexes, guint ifindexes_len) +nm_linux_platform_get_bridge_fdb(NMPlatform *platform, int *ifindexes, guint ifindexes_len) { int nle; struct nl_sock *sk = NULL; diff --git a/src/libnm-platform/nm-linux-platform.h b/src/libnm-platform/nm-linux-platform.h index 3f591b7f1a..c7f1b17a2b 100644 --- a/src/libnm-platform/nm-linux-platform.h +++ b/src/libnm-platform/nm-linux-platform.h @@ -26,7 +26,7 @@ GType nm_linux_platform_get_type(void); struct _NMDedupMultiIndex; NMEtherAddr ** -nm_linux_platform_get_link_fdb_table(NMPlatform *platform, int *ifindexes, guint ifindexes_len); +nm_linux_platform_get_bridge_fdb(NMPlatform *platform, int *ifindexes, guint ifindexes_len); NMPlatform *nm_linux_platform_new(struct _NMDedupMultiIndex *multi_idx, gboolean log_with_ptr, From 16ef33d38095a9fab694a28deee9059a6510e1df Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 7 Jul 2025 09:43:12 +0200 Subject: [PATCH 15/22] bond-slb: fix memory leak If sendto() fails, the function returns and the remaining entries are not deallocated. Use nm_auto_freev instead to free the array and the pointer it contains. Add a test to check that nm_auto_freev does the right thing on the value returned by nm_linux_platform_get_bridge_fdb(). Fixes: 3f2f922dd943 ('bonding: send ARP announcement on bonding-slb link/carrier down') --- src/core/nm-bond-manager.c | 8 ++-- src/core/platform/tests/test-link.c | 62 +++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/core/nm-bond-manager.c b/src/core/nm-bond-manager.c index a29ce679d6..abaab7d4f3 100644 --- a/src/core/nm-bond-manager.c +++ b/src/core/nm-bond-manager.c @@ -916,9 +916,9 @@ nm_bond_manager_send_arp(int bond_ifindex, if (announce_fdb) { /* if we are announcing the FDB we do a RARP, we don't set the * source/dest IPv4 address */ - int ifindexes[] = {bridge_ifindex, bond_ifindex}; - int i; - gs_free NMEtherAddr **fdb_addrs = NULL; + int ifindexes[] = {bridge_ifindex, bond_ifindex}; + int i; + nm_auto_freev NMEtherAddr **fdb_addrs = NULL; fdb_addrs = nm_linux_platform_get_bridge_fdb(platform, ifindexes, 2); /* we want to send a Reverse ARP (RARP) packet */ @@ -927,10 +927,10 @@ nm_bond_manager_send_arp(int bond_ifindex, i = 0; while (fdb_addrs[i] != NULL) { NMEtherAddr *tmp_hwaddr = fdb_addrs[i]; + memcpy(data.s_hw_addr, tmp_hwaddr, ETH_ALEN); memcpy(data.d_hw_addr, tmp_hwaddr, ETH_ALEN); memcpy(data.s_addr, tmp_hwaddr, ETH_ALEN); - g_free(tmp_hwaddr); if (sendto(sockfd, &data, sizeof(data), 0, (struct sockaddr *) &addr, sizeof(addr)) < 0) return FALSE; i++; diff --git a/src/core/platform/tests/test-link.c b/src/core/platform/tests/test-link.c index 4a08d565a0..54d9dd7fb8 100644 --- a/src/core/platform/tests/test-link.c +++ b/src/core/platform/tests/test-link.c @@ -2725,6 +2725,66 @@ test_link_set_properties(void) /*****************************************************************************/ +static void +test_link_get_bridge_fdb(void) +{ + const NMPlatformLink *link; + nm_auto_freev NMEtherAddr **addrs; + int ifindex[2]; + guint8 expected[][6] = { + {0x00, 0x99, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x99, 0x00, 0x00, 0x00, 0x02}, + {0x00, 0x99, 0x00, 0x00, 0x00, 0x03}, + {0x00, 0x99, 0x00, 0x00, 0x00, 0x05}, + }; + guint i; + guint j; + + ifindex[0] = + nmtstp_link_bridge_add(NULL, -1, "br-test-1", &nm_platform_lnk_bridge_default)->ifindex; + ifindex[1] = + nmtstp_link_bridge_add(NULL, -1, "br-test-2", &nm_platform_lnk_bridge_default)->ifindex; + + link = nmtstp_link_get(NULL, ifindex[0], "br-test-1"); + g_assert(link); + link = nmtstp_link_get(NULL, ifindex[1], "br-test-2"); + g_assert(link); + + nmtstp_run_command_check("bridge fdb add dev br-test-1 00:99:00:00:00:01"); + nmtstp_run_command_check("bridge fdb add dev br-test-1 00:99:00:00:00:02"); + nmtstp_run_command_check("bridge fdb add dev br-test-1 00:99:00:00:00:03"); + nmtstp_run_command_check("bridge fdb add dev br-test-2 00:99:00:00:00:01"); + nmtstp_run_command_check("bridge fdb add dev br-test-2 00:99:00:00:00:05"); + + addrs = nm_linux_platform_get_bridge_fdb(NM_PLATFORM_GET, ifindex, 2); + g_assert(addrs); + + /* Check for expected entries */ + for (i = 0; i < G_N_ELEMENTS(expected); i++) { + gboolean found = FALSE; + + for (j = 0; addrs[j]; j++) { + if (memcmp(addrs[j], expected[i], ETH_ALEN) == 0) { + found = TRUE; + break; + } + } + g_assert(found); + } + + /* No dupes */ + for (i = 0; addrs[i]; i++) { + for (j = i + 1; addrs[j]; j++) { + g_assert_cmpint(memcmp(addrs[i], addrs[j], ETH_ALEN), !=, 0); + } + } + + nmtstp_link_delete(NULL, -1, ifindex[0], "br-test-1", TRUE); + nmtstp_link_delete(NULL, -1, ifindex[1], "br-test-2", TRUE); +} + +/*****************************************************************************/ + static void test_create_many_links_do(guint n_devices) { @@ -4106,6 +4166,8 @@ _nmtstp_setup_tests(void) test_software_detect_add("/link/software/detect/wireguard/1", NM_LINK_TYPE_WIREGUARD, 1); test_software_detect_add("/link/software/detect/wireguard/2", NM_LINK_TYPE_WIREGUARD, 2); + g_test_add_func("/link/get-bridge-fdb", test_link_get_bridge_fdb); + g_test_add_func("/link/software/vlan/set-xgress", test_vlan_set_xgress); g_test_add_func("/link/set-properties", test_link_set_properties); From b58a37acfe5c8ea7bb4ee43c03f591bd4d024ca1 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 7 Jul 2025 10:00:29 +0200 Subject: [PATCH 16/22] core: fix nm_utils_get_nm_gid() Fixes: 31dbcb81fe7a ('core: make nm_utils_get_nm_[ug]id() thread safe') --- src/core/nm-core-utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c index 895a99177d..ebadde3c7b 100644 --- a/src/core/nm-core-utils.c +++ b/src/core/nm-core-utils.c @@ -5417,7 +5417,7 @@ again: if ((g = g_atomic_int_get(&g_static)) == -1) { gid_t g2; - g2 = geteuid(); + g2 = getegid(); g = g2; nm_assert(g == g2); nm_assert(g >= 0); From fa80896ee7c130158844fb209365dbace68db5a4 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 7 Jul 2025 09:49:33 +0200 Subject: [PATCH 17/22] core: fix Wi-Fi data rate tables Fixes: f2b0092b5b23 ('wifi: parse BSS IEs for 80211n and 80211ac data rates') --- src/core/nm-core-utils.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c index ebadde3c7b..d3c2eb21ca 100644 --- a/src/core/nm-core-utils.c +++ b/src/core/nm-core-utils.c @@ -4642,13 +4642,13 @@ get_max_rate_vht_80_ss3(int mcs) case 5: return 702000000; case 6: - return 0; + return 0; /* invalid */ case 7: return 877500000; case 8: - return 105300000; + return 1053000000; case 9: - return 117000000; + return 1170000000; } return 0; } @@ -4732,7 +4732,7 @@ get_max_rate_vht_160_ss3(int mcs) case 8: return 2106000000; case 9: - return 0; + return 0; /* invalid */ } return 0; } From f4f1ecc7eaabc65bfe6d94eb1751c7cdaf9a4c89 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 7 Jul 2025 09:15:01 +0200 Subject: [PATCH 18/22] libnm-core: fix p-key validation for Infiniband connections verify() is setting an error without returning FALSE to make the validation fail. When the parent is set, the device is a Infiniband partition and it must have a p-key != -1. Fixes: d595f7843e31 ('libnm: add libnm/libnm-core (part 1)') --- src/libnm-core-impl/nm-setting-infiniband.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libnm-core-impl/nm-setting-infiniband.c b/src/libnm-core-impl/nm-setting-infiniband.c index 24e5807acb..b70247c1c6 100644 --- a/src/libnm-core-impl/nm-setting-infiniband.c +++ b/src/libnm-core-impl/nm-setting-infiniband.c @@ -212,6 +212,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) NM_CONNECTION_ERROR_INVALID_PROPERTY, _("Must specify a P_Key if specifying parent")); g_prefix_error(error, "%s: ", NM_SETTING_INFINIBAND_PARENT); + return FALSE; } } From 104cafdd44df643fbdbc79f2bff6b3cd039ca4b9 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 7 Jul 2025 09:22:58 +0200 Subject: [PATCH 19/22] libnm-core: fix documentation for NMSettingMatch functions Fixes: 3a8e46f2a59a ('settings: add match for proc cmdline') --- src/libnm-core-impl/nm-setting-match.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libnm-core-impl/nm-setting-match.c b/src/libnm-core-impl/nm-setting-match.c index 255283fc57..dc743b159a 100644 --- a/src/libnm-core-impl/nm-setting-match.c +++ b/src/libnm-core-impl/nm-setting-match.c @@ -309,9 +309,10 @@ nm_setting_match_clear_kernel_command_lines(NMSettingMatch *setting) * @setting: the #NMSettingMatch * @length: (out) (optional): the length of the returned interface names array. * - * Returns all the interface names. + * Returns all the kernel command line arguments. * - * Returns: (transfer none) (array length=length): the configured interface names. + * Returns: (transfer none) (array length=length): the configured kernel command + * line arguments. * * Since: 1.26 **/ @@ -344,7 +345,7 @@ nm_setting_match_get_num_drivers(NMSettingMatch *setting) /** * nm_setting_match_get_driver: * @setting: the #NMSettingMatch - * @idx: index number of the DNS search domain to return + * @idx: index number of the driver to return * * Since 1.46, access at index "len" is allowed and returns NULL. * @@ -443,7 +444,7 @@ nm_setting_match_clear_drivers(NMSettingMatch *setting) /** * nm_setting_match_get_drivers: * @setting: the #NMSettingMatch - * @length: (out) (optional): the length of the returned interface names array. + * @length: (out) (optional): the length of the returned drivers array. * * Returns all the drivers. * From fdb8f07c447b9ce5f4af8ff8662c8b9ce08e52e5 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 7 Jul 2025 09:27:17 +0200 Subject: [PATCH 20/22] libnm-core: validate the ipvlan mode The setting must reject unknown ipvlan modes. Fixes: d238ff487b29 ('ipvlan: add support to IPVLAN interface') --- src/libnm-core-impl/nm-setting-ipvlan.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/libnm-core-impl/nm-setting-ipvlan.c b/src/libnm-core-impl/nm-setting-ipvlan.c index fafa37b6ee..0468e31fd5 100644 --- a/src/libnm-core-impl/nm-setting-ipvlan.c +++ b/src/libnm-core-impl/nm-setting-ipvlan.c @@ -156,6 +156,19 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) } } + if (!NM_IN_SET(priv->mode, + NM_SETTING_IPVLAN_MODE_L2, + NM_SETTING_IPVLAN_MODE_L3, + NM_SETTING_IPVLAN_MODE_L3S)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("unsupported mode %u"), + priv->mode); + g_prefix_error(error, "%s.%s: ", NM_SETTING_IPVLAN_SETTING_NAME, NM_SETTING_IPVLAN_MODE); + return FALSE; + } + if (priv->private_flag && priv->vepa) { g_set_error(error, NM_CONNECTION_ERROR, From b45d5f41dd7948512f33c42e2e501d6ea5ca3110 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 7 Jul 2025 09:31:15 +0200 Subject: [PATCH 21/22] platform: fix harmless typo The function should modify the "ip6_address" member of the union. In practice, it doesn't matter because the ifindex is the first member of both "ip4_address" and "ip6_address". --- src/libnm-platform/nmp-object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c index e11bfb3f5b..56533c99c5 100644 --- a/src/libnm-platform/nmp-object.c +++ b/src/libnm-platform/nmp-object.c @@ -893,7 +893,7 @@ const NMPObject * nmp_object_stackinit_id_ip6_address(NMPObject *obj, int ifindex, const struct in6_addr *address) { _nmp_object_stackinit_from_type(obj, NMP_OBJECT_TYPE_IP6_ADDRESS); - obj->ip4_address.ifindex = ifindex; + obj->ip6_address.ifindex = ifindex; if (address) obj->ip6_address.address = *address; return obj; From eb7917a387741085c888fad6e764e61e77e54016 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 7 Jul 2025 16:53:27 +0200 Subject: [PATCH 22/22] ndisc: fix logic to limit the number of addresses Fixes: c2c8c67d8c45 ('ndisc: rate limit number of accepted RA data to track') --- src/core/ndisc/nm-ndisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ndisc/nm-ndisc.c b/src/core/ndisc/nm-ndisc.c index 3083de009d..1a2bf48072 100644 --- a/src/core/ndisc/nm-ndisc.c +++ b/src/core/ndisc/nm-ndisc.c @@ -1490,7 +1490,7 @@ clean_addresses(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint g_array_set_size(rdata->addresses, j); } - if (_array_set_size_max(rdata->gateways, priv->config.max_addresses)) + if (_array_set_size_max(rdata->addresses, priv->config.max_addresses)) *changed |= NM_NDISC_CONFIG_ADDRESSES; }