From d73332cfc965ad50b2fc31fa25a09e5aebbb9b04 Mon Sep 17 00:00:00 2001 From: Jan Vaclav Date: Tue, 7 Apr 2026 12:31:31 +0200 Subject: [PATCH 1/7] policy: fix integer overflow in IPv6 PD subnet calculation The literal `1` is a 32-bit int. When prefix length is less than 33, the shift `(64 - plen)` exceeds 31 bits, causing undefined behavior. Cast to guint64 (same type as `num_subnets`) to perform the shift in 64-bit arithmetic. Found by Coverity (CID: OVERFLOW_BEFORE_WIDEN). Fixes: ec12fcf6bf4f ('policy: delegate IPv6 configuration to ipv6.method=shared connections') Co-Authored-By: Claude Opus 4.6 (cherry picked from commit 4565c9efe4a4866dc0a3394276a20adb2a3bdb90) --- src/core/nm-policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index f7be1a9f87..6685f8c19b 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -253,7 +253,7 @@ ip6_subnet_from_delegation(IP6PrefixDelegation *delegation, NMDevice *device) } /* Check for out-of-prefixes condition */ - num_subnets = 1 << (64 - delegation->prefix.plen); + num_subnets = (guint64) 1 << (64 - delegation->prefix.plen); if (nm_g_hash_table_size(delegation->map_subnet_id_to_ifindex) >= num_subnets) { _LOGD(LOGD_IP6, "ipv6-pd: no more prefixes in %s/%u", From 99028b39a87407f132af5c544f14c9aa8999beb5 Mon Sep 17 00:00:00 2001 From: Jan Vaclav Date: Tue, 7 Apr 2026 12:31:36 +0200 Subject: [PATCH 2/7] device: fix potential null dereference when releasing port find_port_info() can return NULL if the port is not registered. The code dereferenced `info->port_state` before the null check, which would crash. Move the null check before the dereference. Found by Coverity (CID: REVERSE_INULL). Fixes: a8329587c8bd ('device: fix bug when deactivating port connections asynchronously') Co-Authored-By: Claude Opus 4.6 (cherry picked from commit 56099c5e14043b9511cd76bf57bbc6c89c25bdb3) --- src/core/devices/nm-device.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index a0cf1ee6d0..1bebdf1933 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -7149,7 +7149,9 @@ nm_device_controller_release_port(NMDevice *self, info = find_port_info(self, port); - if (info->port_state == PORT_STATE_ATTACHED) + if (!info) + port_state_str = "(not registered)"; + else if (info->port_state == PORT_STATE_ATTACHED) port_state_str = "(attached)"; else if (info->port_state == PORT_STATE_NOT_ATTACHED) port_state_str = "(not attached)"; @@ -7162,7 +7164,7 @@ nm_device_controller_release_port(NMDevice *self, "controller: release one port " NM_HASH_OBFUSCATE_PTR_FMT "/%s %s%s", NM_HASH_OBFUSCATE_PTR(port), nm_device_get_iface(port), - !info ? "(not registered)" : port_state_str, + port_state_str, release_type == RELEASE_PORT_TYPE_CONFIG_FORCE ? " (force-configure)" : (release_type == RELEASE_PORT_TYPE_CONFIG ? " (configure)" : "(no-config)")); From 51027cab73d1700ee2ee8c4ed5f46da88950a32c Mon Sep 17 00:00:00 2001 From: Jan Vaclav Date: Tue, 7 Apr 2026 12:42:26 +0200 Subject: [PATCH 3/7] dns: fix infinite loop in assertion checking search domains The loop condition checked the same pointer twice instead of checking the array element: `ip_data->domains.search && ip_data->domains.search` should be `ip_data->domains.search && ip_data->domains.search[i]`. As written, the loop would never terminate when `search` is non-NULL (only in debug builds with NM_MORE_ASSERTS > 5). Found by Coverity (CID: CONSTANT_EXPRESSION_RESULT). Fixes: b8dab47705dc ('dns: fix handling default routing domains with systemd-resolved') Co-Authored-By: Claude Opus 4.6 (cherry picked from commit 8685ac184517d1852100f27fdc9e3fd1ce1d4154) --- src/core/dns/nm-dns-manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c index ec33c46427..f1a19d0132 100644 --- a/src/core/dns/nm-dns-manager.c +++ b/src/core/dns/nm-dns-manager.c @@ -371,7 +371,7 @@ _ASSERT_dns_config_ip_data(const NMDnsConfigIPData *ip_data) gboolean has_default = FALSE; gsize i; - for (i = 0; ip_data->domains.search && ip_data->domains.search; i++) { + for (i = 0; ip_data->domains.search && ip_data->domains.search[i]; i++) { const char *d = ip_data->domains.search[i]; d = nm_utils_parse_dns_domain(d, NULL); From dbd323ce81f6fa9618f170222ffad1e35fa9e739 Mon Sep 17 00:00:00 2001 From: Jan Vaclav Date: Tue, 7 Apr 2026 12:42:32 +0200 Subject: [PATCH 4/7] nmtui/wireguard: fix peer leak when adding new peer nm_wireguard_peer_new() returns a new peer with refcount 1. nmt_wireguard_peer_editor_new() takes its own copy via g_value_dup_boxed(), so the original peer was never unreffed. Unref the peer after passing it to the editor. Found by Coverity (CID: RESOURCE_LEAK). Fixes: b0f5b1d97a65 ('tui: add WireGuard support to nmtui') Co-Authored-By: Claude Opus 4.6 (cherry picked from commit 00f9a3d862b845246290ae1fbb9e59f0e00f0e06) --- src/nmtui/nmt-wireguard-peer-list.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nmtui/nmt-wireguard-peer-list.c b/src/nmtui/nmt-wireguard-peer-list.c index c6db61a64a..38987a9718 100644 --- a/src/nmtui/nmt-wireguard-peer-list.c +++ b/src/nmtui/nmt-wireguard-peer-list.c @@ -170,6 +170,7 @@ nmt_wireguard_peer_list_add_peer(NmtWireguardPeerList *list) NmtNewtForm *editor; editor = nmt_wireguard_peer_editor_new(priv->setting, peer); + nm_wireguard_peer_unref(peer); if (!editor) return; From 09fa1dc8b4c194410d2b4a4f97517b455a247c58 Mon Sep 17 00:00:00 2001 From: Jan Vaclav Date: Tue, 7 Apr 2026 13:17:16 +0200 Subject: [PATCH 5/7] initrd: fix use-after-free when multiple iBFT entries fail The error variable is declared outside the loop but freed with g_error_free() which does not reset the pointer to NULL. On the next iteration, g_set_error() sees a non-NULL *err (dangling pointer) and error->message dereferences freed memory. Use g_clear_error() instead which also resets the pointer. Found by Coverity (CID: USE_AFTER_FREE). Fixes: ecc074b2f8a6 ('initrd: add command line parser') Co-Authored-By: Claude Opus 4.6 (cherry picked from commit 33871478b7cfdf717eff14de1f2928874d9352e1) --- src/nm-initrd-generator/nmi-cmdline-reader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nm-initrd-generator/nmi-cmdline-reader.c b/src/nm-initrd-generator/nmi-cmdline-reader.c index f9b0fa161b..5d91d15796 100644 --- a/src/nm-initrd-generator/nmi-cmdline-reader.c +++ b/src/nm-initrd-generator/nmi-cmdline-reader.c @@ -409,7 +409,7 @@ reader_read_all_connections_from_fw(Reader *reader, const char *sysfs_dir) if (!nmi_ibft_update_connection_from_nic(connection, nic, &error)) { _LOGW(LOGD_CORE, "Unable to merge iBFT configuration: %s", error->message); - g_error_free(error); + g_clear_error(&error); continue; } From 530a8934f5b5711db2345b0d6900cf4b9aa6514c Mon Sep 17 00:00:00 2001 From: Jan Vaclav Date: Tue, 7 Apr 2026 13:17:23 +0200 Subject: [PATCH 6/7] libnm: fix wrong variable in route attribute validation error message The validation checks 'addr' (the extracted address portion before '/') but the error message prints 'string' (the full input including the prefix). For input like "192.168.1.999/24", the error would show the full string instead of just the invalid address part. Found by Coverity (CID: COPY_PASTE_ERROR). Fixes: 539db43619e4 ('libnm: avoid heap allocation for checking valid routes in nm_ip_route_attribute_validate()') Co-Authored-By: Claude Opus 4.6 (cherry picked from commit 3d4ad7b4ba33a067396acb4a81f78273ada88b9a) --- src/libnm-core-impl/nm-setting-ip-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libnm-core-impl/nm-setting-ip-config.c b/src/libnm-core-impl/nm-setting-ip-config.c index f4ee094ca4..1e9a780de4 100644 --- a/src/libnm-core-impl/nm-setting-ip-config.c +++ b/src/libnm-core-impl/nm-setting-ip-config.c @@ -1401,7 +1401,7 @@ _ip_route_attribute_validate(const char *name, NM_CONNECTION_ERROR_FAILED, family == AF_INET ? _("'%s' is not a valid IPv4 address") : _("'%s' is not a valid IPv6 address"), - string); + addr); return FALSE; } break; From e42c1f6171a56c372860481c4f9d5feb86529480 Mon Sep 17 00:00:00 2001 From: Jan Vaclav Date: Tue, 7 Apr 2026 13:17:30 +0200 Subject: [PATCH 7/7] libnm/tests: fix dead code in WireGuard roundtrip test The inner condition at line 4086 duplicated the outer check for NM_CONNECTION_SERIALIZE_ALL, making the else-if branch for NM_CONNECTION_SERIALIZE_WITH_NON_SECRET unreachable. This meant the non-secret serialization path was never actually tested. Restructure to make both branches reachable. Found by Coverity (CID: DEADCODE). Fixes: 395a78618b6d ('libnm/tests: add tests for creating wireguard connection profiles') Co-Authored-By: Claude Opus 4.6 (cherry picked from commit ca326bd636e642ef0c4916b8a0abaaacf13cd175) --- src/libnm-core-impl/tests/test-setting.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c index f3070c1730..5f2a2ae3ec 100644 --- a/src/libnm-core-impl/tests/test-setting.c +++ b/src/libnm-core-impl/tests/test-setting.c @@ -4082,13 +4082,12 @@ test_roundtrip_conversion(gconstpointer test_data) if (flag == NM_CONNECTION_SERIALIZE_ALL) { s_wg2 = NM_SETTING_WIREGUARD( nm_connection_get_setting(con2, NM_TYPE_SETTING_WIREGUARD)); - - if (flag == NM_CONNECTION_SERIALIZE_ALL) - _rndt_wg_peers_assert_equal(s_wg2, wg_peers, TRUE, TRUE, FALSE); - else if (flag == NM_CONNECTION_SERIALIZE_WITH_NON_SECRET) - _rndt_wg_peers_assert_equal(s_wg2, wg_peers, FALSE, FALSE, TRUE); - else - g_assert_not_reached(); + _rndt_wg_peers_assert_equal(s_wg2, wg_peers, TRUE, TRUE, FALSE); + } else if (flag == NM_CONNECTION_SERIALIZE_WITH_NON_SECRET) { + con2 = _connection_new_from_dbus_strict(con_var, FALSE); + s_wg2 = NM_SETTING_WIREGUARD( + nm_connection_get_setting(con2, NM_TYPE_SETTING_WIREGUARD)); + _rndt_wg_peers_assert_equal(s_wg2, wg_peers, FALSE, FALSE, TRUE); } break; }