From 3c89b36599b547b382b3e10af594296d494bb8bc Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 09:22:59 +0100 Subject: [PATCH 01/50] nvme: Fix loop variable reuse in namespace descriptor iteration The inner loops formatting EUI64 and NGUID hex strings reused the outer loop variable 'i', corrupting the outer iteration over namespace identify descriptors. Descriptors appearing after EUI64 or NGUID could be skipped as a result. Use a separate loop variable 'j' for the inner loops. Co-Authored-By: Claude Opus 4.6 --- src/plugins/nvme/nvme-info.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/plugins/nvme/nvme-info.c b/src/plugins/nvme/nvme-info.c index fb99938c..a52be9c0 100644 --- a/src/plugins/nvme/nvme-info.c +++ b/src/plugins/nvme/nvme-info.c @@ -601,6 +601,7 @@ BDNVMENamespaceInfo *bd_nvme_get_namespace_info (const gchar *device, GError **e struct nvme_ns_id_desc *descs = NULL; guint8 flbas; guint i; + guint j; guint len; BDNVMENamespaceInfo *info; GPtrArray *ptr_array; @@ -685,14 +686,14 @@ BDNVMENamespaceInfo *bd_nvme_get_namespace_info (const gchar *device, GError **e case NVME_NIDT_EUI64: g_free (info->eui64); info->eui64 = g_malloc0 (d->nidl * 2 + 1); - for (i = 0; i < d->nidl; i++) - snprintf (info->eui64 + i * 2, 3, "%02x", d->nid[i]); + for (j = 0; j < d->nidl; j++) + snprintf (info->eui64 + j * 2, 3, "%02x", d->nid[j]); break; case NVME_NIDT_NGUID: g_free (info->nguid); info->nguid = g_malloc0 (d->nidl * 2 + 1); - for (i = 0; i < d->nidl; i++) - snprintf (info->nguid + i * 2, 3, "%02x", d->nid[i]); + for (j = 0; j < d->nidl; j++) + snprintf (info->nguid + j * 2, 3, "%02x", d->nid[j]); break; case NVME_NIDT_UUID: g_free (info->uuid); From 6df1b981f2bcd2798b663ffa73deebf45f7051e5 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 09:24:07 +0100 Subject: [PATCH 02/50] s390: Fix fgetc comparison to use character '1' instead of integer 1 fgetc returns ASCII character values. Comparing to integer 1 (SOH control character) instead of '1' (ASCII 49) means the "already online" check never triggers in both bd_s390_dasd_online and bd_s390_zfcp_online. Co-Authored-By: Claude Opus 4.6 --- src/plugins/s390.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/s390.c b/src/plugins/s390.c index 20a59828..97c05a66 100644 --- a/src/plugins/s390.c +++ b/src/plugins/s390.c @@ -243,7 +243,7 @@ gboolean bd_s390_dasd_online (const gchar *dasd, GError **error) { g_propagate_error (error, l_error); return FALSE; } - if (online == 1) { + if (online == '1') { g_set_error (&l_error, BD_S390_ERROR, BD_S390_ERROR_DEVICE, "DASD device %s is already online.", dasd); fclose (fd); @@ -607,7 +607,7 @@ gboolean bd_s390_zfcp_online (const gchar *devno, const gchar *wwpn, const gchar g_propagate_error (error, l_error); return FALSE; } - if (rc == 1) { + if (rc == '1') { /* otherwise device's status indicates that it's already online, so just close the fd and proceed; we don't return because although 'online' status may be correct, the device may not be completely online and ready From 731c1c8453dd29f85a514a652eecdd7d20f1e2b3 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 09:27:07 +0100 Subject: [PATCH 03/50] lvm: Fix next_arg index in bd_lvm_vdo_pool_convert next_arg was initialized to 4 instead of 8, causing subsequent arguments (-n, -V, etc.) to overwrite the --compression and --deduplication options in the argv array. This silently dropped the user's compression/deduplication settings. Also update the test to pass explicit non-default deduplication=False to verify arguments are correctly forwarded. Co-Authored-By: Claude Opus 4.6 --- src/plugins/lvm/lvm.c | 2 +- tests/_lvm_cases.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugins/lvm/lvm.c b/src/plugins/lvm/lvm.c index 51d5354d..32edeee6 100644 --- a/src/plugins/lvm/lvm.c +++ b/src/plugins/lvm/lvm.c @@ -3078,7 +3078,7 @@ gboolean bd_lvm_vdo_pool_convert (const gchar *vg_name, const gchar *pool_lv, co "--deduplication", deduplication ? "y" : "n", NULL, NULL, NULL, NULL, NULL, NULL}; gboolean success = FALSE; - guint next_arg = 4; + guint next_arg = 8; gchar *size_str = NULL; gchar *lv_spec = NULL; gchar *old_config = NULL; diff --git a/tests/_lvm_cases.py b/tests/_lvm_cases.py index a00d5055..770d37ff 100644 --- a/tests/_lvm_cases.py +++ b/tests/_lvm_cases.py @@ -2134,7 +2134,8 @@ def test_vdo_pool_convert(self): succ = BlockDev.lvm_lvcreate("testVDOVG", "testLV", 7 * 1024**3) self.assertTrue(succ) - succ = BlockDev.lvm_vdo_pool_convert("testVDOVG", "testLV", "vdoLV", 35 * 1024**3) + succ = BlockDev.lvm_vdo_pool_convert("testVDOVG", "testLV", "vdoLV", 35 * 1024**3, + 0, True, False) self.assertTrue(succ) lv_info = BlockDev.lvm_lvinfo("testVDOVG", "vdoLV") @@ -2152,7 +2153,7 @@ def test_vdo_pool_convert(self): vdo_info = BlockDev.lvm_vdo_info("testVDOVG", "testLV") self.assertIsNotNone(vdo_info) self.assertTrue(vdo_info.compression) - self.assertTrue(vdo_info.deduplication) + self.assertFalse(vdo_info.deduplication) self.assertEqual(BlockDev.lvm_get_vdo_write_policy_str(vdo_info.write_policy), "auto") @tag_test(TestTags.SLOW) From b207c65af670332ca07f9d09d494632f7335385d Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 09:35:13 +0100 Subject: [PATCH 04/50] utils: Fix NULL dereference in bd_utils_dbus_service_available When a non-NULL connection was provided, the ListNames D-Bus call was inside the else block and never executed. ret remained NULL, causing g_variant_get_child_value(NULL, 0) to crash. Move the ListNames call outside the else block so it executes regardless of how the connection was obtained. Co-Authored-By: Claude Opus 4.6 --- src/utils/dbus.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/utils/dbus.c b/src/utils/dbus.c index ebaaa8ed..fc68415f 100644 --- a/src/utils/dbus.c +++ b/src/utils/dbus.c @@ -62,14 +62,14 @@ gboolean bd_utils_dbus_service_available (GDBusConnection *connection, GBusType g_prefix_error (error, "Failed to get system bus: "); return FALSE; } + } - ret = g_dbus_connection_call_sync (bus, DBUS_TOP_IFACE, DBUS_TOP_OBJ, DBUS_TOP_IFACE, - "ListNames", NULL, NULL, G_DBUS_CALL_FLAGS_NONE, - -1, NULL, error); - if (!ret) { - g_object_unref (bus); - return FALSE; - } + ret = g_dbus_connection_call_sync (bus, DBUS_TOP_IFACE, DBUS_TOP_OBJ, DBUS_TOP_IFACE, + "ListNames", NULL, NULL, G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (!ret) { + g_object_unref (bus); + return FALSE; } real_ret = g_variant_get_child_value (ret, 0); From 355c0878fbd69a36f957eeb391a945538f42e50d Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 09:46:26 +0100 Subject: [PATCH 05/50] fs: Fix g_free(label) to g_free(*label) in get_uuid_label label is a gchar** parameter. g_free(label) was incorrectly freeing the pointer-to-pointer instead of the allocated string. This leaked the label string and passed an invalid address to g_free. Co-Authored-By: Claude Opus 4.6 --- src/plugins/fs/common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/fs/common.c b/src/plugins/fs/common.c index b6fcbbf5..586484a4 100644 --- a/src/plugins/fs/common.c +++ b/src/plugins/fs/common.c @@ -115,7 +115,8 @@ get_uuid_label (const gchar *device, gchar **uuid, gchar **label, GError **error "Failed to get UUID for the device '%s'", device); blkid_free_probe (probe); synced_close (fd); - g_free (label); + g_free (*label); + *label = NULL; return FALSE; } From dda86073f1dfbb1b65f307a88ee1c445e8428a27 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 09:48:37 +0100 Subject: [PATCH 06/50] core: Fix bd_ensure_init to check all plugins, not just the last The loop checking plugin availability overwrote the 'missing' flag each iteration without short-circuiting. This meant only the last plugin's availability was checked. Add the !missing condition to match the require_plugins branch. Co-Authored-By: Claude Opus 4.6 --- src/lib/blockdev.c.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/blockdev.c.in b/src/lib/blockdev.c.in index b81e802e..16cab30c 100644 --- a/src/lib/blockdev.c.in +++ b/src/lib/blockdev.c.in @@ -496,7 +496,7 @@ gboolean bd_ensure_init (BDPluginSpec **require_plugins, BDUtilsLogFunc log_func missing = !bd_is_plugin_available((*check_plugin)->name); else /* all plugins requested */ - for (plugin=BD_PLUGIN_LVM; plugin != BD_PLUGIN_UNDEF; plugin++) + for (plugin=BD_PLUGIN_LVM; !missing && plugin != BD_PLUGIN_UNDEF; plugin++) missing = !bd_is_plugin_available(plugin); if (!missing) { From f4e0219a85c54d898796865ade1a522c0ce35064 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 09:50:32 +0100 Subject: [PATCH 07/50] core: Restore stub on dlsym failure in generated plugin loaders When dlsym failed for a plugin function, the generated code logged a warning but left the function pointer as NULL, overwriting the stub. Subsequent calls to that API function would segfault instead of returning a graceful GError. Restore the stub function pointer on dlsym failure. Co-Authored-By: Claude Opus 4.6 --- scripts/boilerplate_generator.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/boilerplate_generator.py b/scripts/boilerplate_generator.py index 736e160d..d582cf78 100755 --- a/scripts/boilerplate_generator.py +++ b/scripts/boilerplate_generator.py @@ -219,8 +219,10 @@ def get_loading_func(fn_infos, module_name): # clear any previous error and load the function ret += ' dlerror();\n' ret += ' * (void**) (&_{0.name}) = dlsym(handle, "{0.name}");\n'.format(info) - ret += ' if ((error = dlerror()) != NULL)\n' - ret += ' bd_utils_log_format (BD_UTILS_LOG_WARNING, "failed to load {0.name}: %s", error);\n\n'.format(info) + ret += ' if ((error = dlerror()) != NULL) {\n' + ret += ' bd_utils_log_format (BD_UTILS_LOG_WARNING, "failed to load {0.name}: %s", error);\n'.format(info) + ret += ' _{0.name} = {0.name}_stub;\n'.format(info) + ret += ' }\n\n' ret += ' return handle;\n' ret += '}\n\n' From 4fd7cb0d1db63dc9cd07a76ca1e8187050867ab5 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 09:54:28 +0100 Subject: [PATCH 08/50] fs: Remove mnt_free_fs calls on table-owned fs pointers mnt_table_find_source and mnt_table_find_target return pointers owned by the table. Calling mnt_free_fs on them frees table-owned memory, causing a double-free when mnt_free_table later frees its entries. Co-Authored-By: Claude Opus 4.6 --- src/plugins/fs/mount.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/plugins/fs/mount.c b/src/plugins/fs/mount.c index ef83c22c..7b611a89 100644 --- a/src/plugins/fs/mount.c +++ b/src/plugins/fs/mount.c @@ -832,14 +832,12 @@ gchar* bd_fs_get_mountpoint (const gchar *device, GError **error) { target = mnt_fs_get_target (fs); if (!target) { - mnt_free_fs (fs); mnt_free_table (table); mnt_free_cache (cache); return NULL; } mountpoint = g_strdup (target); - mnt_free_fs (fs); mnt_free_table (table); mnt_free_cache (cache); return mountpoint; @@ -890,13 +888,11 @@ gboolean bd_fs_is_mountpoint (const gchar *path, GError **error) { target = mnt_fs_get_target (fs); if (!target) { - mnt_free_fs (fs); mnt_free_table (table); mnt_free_cache (cache); return FALSE; } - mnt_free_fs (fs); mnt_free_table (table); mnt_free_cache (cache); return TRUE; From 3e53fddfb3353439f08fa8d7c37d5ac35e0ee4c9 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 09:58:21 +0100 Subject: [PATCH 09/50] lvm: Fix FEATURES_WRITECACHE index to distinguish from FEATURES_VDO Both FEATURES_VDO and FEATURES_WRITECACHE were defined as 0, making their bitmasks identical and indistinguishable. Change FEATURES_WRITECACHE to 1 so it maps to the correct index in the features array and produces a distinct bitmask. Co-Authored-By: Claude Opus 4.6 --- src/plugins/lvm/lvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/lvm/lvm.c b/src/plugins/lvm/lvm.c index 32edeee6..76c5717e 100644 --- a/src/plugins/lvm/lvm.c +++ b/src/plugins/lvm/lvm.c @@ -281,7 +281,7 @@ static const UtilDep deps[DEPS_LAST] = { #define FEATURES_VDO 0 #define FEATURES_VDO_MASK (1 << FEATURES_VDO) -#define FEATURES_WRITECACHE 0 +#define FEATURES_WRITECACHE 1 #define FEATURES_WRITECACHE_MASK (1 << FEATURES_WRITECACHE) #define FEATURES_LAST 2 From 59a237de01e48f33bffb19a3a093b722ec28e080 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:03:25 +0100 Subject: [PATCH 10/50] dm: Remove extraneous device argument in bd_dm_create_linear The device is already embedded in the table string passed via --table. Passing it as an additional argv element is not valid dmsetup syntax. Co-Authored-By: Claude Opus 4.6 --- src/plugins/dm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/plugins/dm.c b/src/plugins/dm.c index 51cc1e9c..d764232d 100644 --- a/src/plugins/dm.c +++ b/src/plugins/dm.c @@ -126,7 +126,7 @@ gboolean bd_dm_is_tech_avail (BDDMTech tech, guint64 mode G_GNUC_UNUSED, GError */ gboolean bd_dm_create_linear (const gchar *map_name, const gchar *device, guint64 length, const gchar *uuid, GError **error) { gboolean success = FALSE; - const gchar *argv[9] = {"dmsetup", "create", map_name, "--table", NULL, NULL, NULL, NULL, NULL}; + const gchar *argv[8] = {"dmsetup", "create", map_name, "--table", NULL, NULL, NULL, NULL}; if (!check_deps (&avail_deps, DEPS_DMSETUP_MASK, deps, DEPS_LAST, &deps_check_lock, error)) return FALSE; @@ -137,9 +137,7 @@ gboolean bd_dm_create_linear (const gchar *map_name, const gchar *device, guint6 if (uuid) { argv[5] = "-u"; argv[6] = uuid; - argv[7] = device; - } else - argv[5] = device; + } success = bd_utils_exec_and_report_error (argv, NULL, error); g_free (table); From e7fba91c24d868ff063b771d62d88dcb020f3c6b Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:17:48 +0100 Subject: [PATCH 11/50] crypto: Zero sensitive data before freeing in keyslot context Passphrases and volume keys in BDCryptoKeyslotContext were freed with g_free without zeroing first, leaving sensitive material in freed heap memory. Use explicit_bzero to wipe the buffers before freeing. Co-Authored-By: Claude Opus 4.6 --- src/plugins/crypto.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/crypto.c b/src/plugins/crypto.c index 9e9b09c1..f3852fc4 100644 --- a/src/plugins/crypto.c +++ b/src/plugins/crypto.c @@ -770,14 +770,17 @@ void bd_crypto_keyslot_context_free (BDCryptoKeyslotContext *context) { if (context == NULL) return; - if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) + if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) { + explicit_bzero (context->u.passphrase.pass_data, context->u.passphrase.data_len); g_free (context->u.passphrase.pass_data); - else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) + } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) g_free (context->u.keyfile.keyfile); else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYRING) g_free (context->u.keyring.key_desc); - else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_VOLUME_KEY) + else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_VOLUME_KEY) { + explicit_bzero (context->u.volume_key.volume_key, context->u.volume_key.volume_key_size); g_free (context->u.volume_key.volume_key); + } g_free (context); } From 87f55b15c3fd0687f856c5e1a66713a8e658f1a3 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:18:43 +0100 Subject: [PATCH 12/50] crypto: Fix crypt_device leak in bd_crypto_luks_remove_key When crypt_activate_by_passphrase failed to find the key slot, the function returned without calling crypt_free(cd). Co-Authored-By: Claude Opus 4.6 --- src/plugins/crypto.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/crypto.c b/src/plugins/crypto.c index f3852fc4..04037ef6 100644 --- a/src/plugins/crypto.c +++ b/src/plugins/crypto.c @@ -1645,6 +1645,7 @@ gboolean bd_crypto_luks_remove_key (const gchar *device, BDCryptoKeyslotContext if (ret < 0) { g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_KEY_SLOT, "Failed to determine key slot: %s", strerror_l (-ret, c_locale)); + crypt_free (cd); bd_utils_report_finished (progress_id, l_error->message); g_propagate_error (error, l_error); return FALSE; From 6498154fa15e0c99b9791220d6187d0ee7e2d935 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:21:59 +0100 Subject: [PATCH 13/50] crypto: Fix key_buf leaks on error paths In bd_crypto_luks_add_key and bd_crypto_luks_change_key, key_buf from crypt_keyfile_device_read was leaked when the ncontext validation failed. In bd_crypto_opal_reset_device, key_buf was leaked on the crypt_wipe_hw_opal error path. Add crypt_safe_free(key_buf) to the affected error paths. Co-Authored-By: Claude Opus 4.6 --- src/plugins/crypto.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/plugins/crypto.c b/src/plugins/crypto.c index 04037ef6..59d7337b 100644 --- a/src/plugins/crypto.c +++ b/src/plugins/crypto.c @@ -1546,6 +1546,8 @@ gboolean bd_crypto_luks_add_key (const gchar *device, BDCryptoKeyslotContext *co } else { g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT, "Only 'passphrase' and 'key file' context types are valid for LUKS add key."); + if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) + crypt_safe_free (key_buf); bd_utils_report_finished (progress_id, l_error->message); g_propagate_error (error, l_error); crypt_free (cd); @@ -1757,6 +1759,8 @@ gboolean bd_crypto_luks_change_key (const gchar *device, BDCryptoKeyslotContext } else { g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT, "Only 'passphrase' and 'key file' context types are valid for LUKS change key."); + if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) + crypt_safe_free (key_buf); bd_utils_report_finished (progress_id, l_error->message); g_propagate_error (error, l_error); crypt_free (cd); @@ -4150,6 +4154,9 @@ gboolean bd_crypto_opal_reset_device (const gchar *device, BDCryptoKeyslotContex } ret = crypt_wipe_hw_opal (cd, CRYPT_NO_SEGMENT, key_buf, buf_len, 0); + if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) + crypt_safe_free (key_buf); + if (ret != 0) { g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE, "Failed to wipe LUKS HW-OPAL device: %s", strerror_l (-ret, c_locale)); From e8e32a4a1380ede8047ff8ee9919666a22ac75c6 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:24:04 +0100 Subject: [PATCH 14/50] crypto: Fix strerror_l usage for ioctl error in OPAL support check ioctl returns -1 and sets errno, but the code used strerror_l(-ret) which always evaluates to strerror_l(1) (EPERM) regardless of the actual error. Use errno instead. Co-Authored-By: Claude Opus 4.6 --- src/plugins/crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/crypto.c b/src/plugins/crypto.c index 59d7337b..771a90da 100644 --- a/src/plugins/crypto.c +++ b/src/plugins/crypto.c @@ -3917,7 +3917,7 @@ gboolean bd_crypto_opal_is_supported (const gchar *device, GError **error) { g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE, "Failed to get opal status for the device '%s': %s", device, - strerror_l (-ret, c_locale)); + strerror_l (errno, c_locale)); close (fd); return FALSE; } From 879a4c62759cdb904e0ec315ffae3b23cc1bc353 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:24:42 +0100 Subject: [PATCH 15/50] crypto: Remove stale strerror_l from LUKS label type-check error ret is 0 at this point (from successful crypt_load), so strerror_l(-ret) produced "Success" in the error message. This is a type-check error, not a syscall failure, so the strerror is not appropriate. Co-Authored-By: Claude Opus 4.6 --- src/plugins/crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/crypto.c b/src/plugins/crypto.c index 771a90da..d1fd06dd 100644 --- a/src/plugins/crypto.c +++ b/src/plugins/crypto.c @@ -2260,7 +2260,7 @@ gboolean bd_crypto_luks_set_label (const gchar *device, const gchar *label, cons if (g_strcmp0 (crypt_get_type (cd), CRYPT_LUKS2) != 0) { g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL, - "Label can be set only on LUKS 2 devices: %s", strerror_l (-ret, c_locale)); + "Label can be set only on LUKS 2 devices."); crypt_free (cd); return FALSE; } From 9f2001d5787870d0f201eece396f49e7435b69e5 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:26:15 +0100 Subject: [PATCH 16/50] crypto, part: Call freelocale before clearing c_locale on close Both bd_crypto_close and bd_part_close set c_locale to (locale_t) 0 without calling freelocale first, leaking the locale object on every plugin unload. Co-Authored-By: Claude Opus 4.6 --- src/plugins/crypto.c | 1 + src/plugins/part.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/plugins/crypto.c b/src/plugins/crypto.c index d1fd06dd..a0f41985 100644 --- a/src/plugins/crypto.c +++ b/src/plugins/crypto.c @@ -360,6 +360,7 @@ gboolean bd_crypto_init (void) { * */ void bd_crypto_close (void) { + freelocale (c_locale); c_locale = (locale_t) 0; crypt_set_log_callback (NULL, NULL, NULL); crypt_set_debug_level (CRYPT_DEBUG_NONE); diff --git a/src/plugins/part.c b/src/plugins/part.c index 0b87846e..f727a0b9 100644 --- a/src/plugins/part.c +++ b/src/plugins/part.c @@ -308,6 +308,7 @@ gboolean bd_part_init (void) { * */ void bd_part_close (void) { + freelocale (c_locale); c_locale = (locale_t) 0; } From d326c61c0fb6ac660e83736a29b51c8947c4cfd0 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:27:18 +0100 Subject: [PATCH 17/50] core: Fix GKeyFile leak on config load failure g_key_file_new was called but the config was not freed before returning FALSE when g_key_file_load_from_file failed. Co-Authored-By: Claude Opus 4.6 --- src/lib/blockdev.c.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/blockdev.c.in b/src/lib/blockdev.c.in index 16cab30c..ce505b78 100644 --- a/src/lib/blockdev.c.in +++ b/src/lib/blockdev.c.in @@ -142,8 +142,10 @@ static gboolean process_config_file (const gchar *config_file, GSList **plugins_ gsize n_sonames = 0; config = g_key_file_new (); - if (!g_key_file_load_from_file (config, config_file, G_KEY_FILE_NONE, error)) + if (!g_key_file_load_from_file (config, config_file, G_KEY_FILE_NONE, error)) { + g_key_file_free (config); return FALSE; + } /* get sonames for each plugin (if specified) */ for (i=0; (i < BD_PLUGIN_UNDEF); i++) { From a136489de46b60946d6d1ca50658c19a964eb66c Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:28:22 +0100 Subject: [PATCH 18/50] core: Free so_name strings before clearing on plugin reload On reload, plugins[i].spec.so_name was set to NULL without freeing the g_strdup-ed string from the previous load, leaking memory for each plugin on every reload. Co-Authored-By: Claude Opus 4.6 --- src/lib/blockdev.c.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/blockdev.c.in b/src/lib/blockdev.c.in index ce505b78..d407669b 100644 --- a/src/lib/blockdev.c.in +++ b/src/lib/blockdev.c.in @@ -332,8 +332,10 @@ static gboolean load_plugins (BDPluginSpec **require_plugins, gboolean reload, g unload_plugins (); /* clean all so names and populate back those that are requested or the defaults */ - for (i=0; i < BD_PLUGIN_UNDEF; i++) + for (i=0; i < BD_PLUGIN_UNDEF; i++) { + g_free ((gchar *) plugins[i].spec.so_name); plugins[i].spec.so_name = NULL; + } } if (require_plugins) { From 270aa368d8ccff4f10f9986293bfdce4ccffa25f Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:29:56 +0100 Subject: [PATCH 19/50] lvm: Fix NULL dereference of error parameter in bd_lvm_pvs The error parameter is (out)(optional) but was dereferenced directly with *error without a NULL check. Use a local GError like bd_lvm_vgs does to avoid crashing when the caller passes NULL for error. Co-Authored-By: Claude Opus 4.6 --- src/plugins/lvm/lvm.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/plugins/lvm/lvm.c b/src/plugins/lvm/lvm.c index 76c5717e..4ea2b657 100644 --- a/src/plugins/lvm/lvm.c +++ b/src/plugins/lvm/lvm.c @@ -1157,14 +1157,15 @@ BDLVMPVdata** bd_lvm_pvs (GError **error) { guint num_items; GPtrArray *pvs; BDLVMPVdata *pvdata = NULL; + GError *l_error = NULL; pvs = g_ptr_array_new (); - success = call_lvm_and_capture_output (args, NULL, &output, error); + success = call_lvm_and_capture_output (args, NULL, &output, &l_error); if (!success) { - if (g_error_matches (*error, BD_UTILS_EXEC_ERROR, BD_UTILS_EXEC_ERROR_NOOUT)) { - /* no output => no VGs, not an error */ - g_clear_error (error); + if (g_error_matches (l_error, BD_UTILS_EXEC_ERROR, BD_UTILS_EXEC_ERROR_NOOUT)) { + /* no output => no PVs, not an error */ + g_clear_error (&l_error); /* return an empty list */ g_ptr_array_add (pvs, NULL); return (BDLVMPVdata **) g_ptr_array_free (pvs, FALSE); @@ -1172,6 +1173,7 @@ BDLVMPVdata** bd_lvm_pvs (GError **error) { else { /* the error is already populated from the call */ g_ptr_array_free (pvs, TRUE); + g_propagate_error (error, l_error); return NULL; } } From 22974a3dfbaafc3b8f0a1d2bca3801c26d1454ba Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:31:57 +0100 Subject: [PATCH 20/50] lvm: Fix g_prefix_error called on wrong variable in cache_create g_prefix_error was called on the caller's error instead of &l_error. The subsequent g_propagate_error then overwrote it, losing the prefix message. Co-Authored-By: Claude Opus 4.6 --- src/plugins/lvm/lvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/lvm/lvm.c b/src/plugins/lvm/lvm.c index 4ea2b657..9eeb438a 100644 --- a/src/plugins/lvm/lvm.c +++ b/src/plugins/lvm/lvm.c @@ -2562,7 +2562,7 @@ gboolean bd_lvm_cache_create_cached_lv (const gchar *vg_name, const gchar *lv_na success = bd_lvm_cache_attach (vg_name, lv_name, name, NULL, &l_error); if (!success) { - g_prefix_error (error, "Failed to attach the cache pool '%s' to the data LV: ", name); + g_prefix_error (&l_error, "Failed to attach the cache pool '%s' to the data LV: ", name); g_free (name); bd_utils_report_finished (progress_id, l_error->message); g_propagate_error (error, l_error); From 6744c0474384573718615f51750f16d0da573894 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:32:35 +0100 Subject: [PATCH 21/50] mdraid: Remove g_hash_table_destroy call on NULL table Inside the if (!table) block, table is NULL, so g_hash_table_destroy(table) is incorrect. Co-Authored-By: Claude Opus 4.6 --- src/plugins/mdraid.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/mdraid.c b/src/plugins/mdraid.c index ee3aef1b..60c10701 100644 --- a/src/plugins/mdraid.c +++ b/src/plugins/mdraid.c @@ -1058,7 +1058,6 @@ BDMDExamineData* bd_md_examine (const gchar *device, GError **error) { /* something bad happened or some expected items were missing */ g_set_error (error, BD_MD_ERROR, BD_MD_ERROR_PARSE, "Failed to parse mdexamine metadata"); - g_hash_table_destroy (table); bd_md_examine_data_free (ret); return NULL; } From 26962ac11667d62072a71ffc893f9c4f98c96a74 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:33:44 +0100 Subject: [PATCH 22/50] swap: Fix NULL+1 from strchr in bd_swap_swapstatus strchr returns NULL when '\n' is not found. Adding 1 to NULL produces (char*)1, which passes the while NULL check and causes a segfault on dereference. Check strchr return before incrementing. Co-Authored-By: Claude Opus 4.6 --- src/plugins/swap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/swap.c b/src/plugins/swap.c index e6d1f744..9d6e2a98 100644 --- a/src/plugins/swap.c +++ b/src/plugins/swap.c @@ -424,15 +424,16 @@ gboolean bd_swap_swapstatus (const gchar *device, GError **error) { return TRUE; } - next_line = (strchr (file_content, '\n') + 1); + next_line = strchr (file_content, '\n'); while (next_line && ((gsize)(next_line - file_content) < length)) { + next_line++; if (g_str_has_prefix (next_line, real_device ? real_device : device)) { g_free (real_device); g_free (file_content); return TRUE; } - next_line = (strchr (next_line, '\n') + 1); + next_line = strchr (next_line, '\n'); } g_free (real_device); From 9d5a0caf8a1bb24a45faf4363f94cc0a181ad201 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:34:54 +0100 Subject: [PATCH 23/50] dm, mpath: Fix DM task resource leaks on early returns dm_task_destroy was not called when dm_task_get_names returned NULL or names->dev was 0, leaking the DM task resource. Co-Authored-By: Claude Opus 4.6 --- src/plugins/mpath.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/mpath.c b/src/plugins/mpath.c index dd231bf6..49a1d604 100644 --- a/src/plugins/mpath.c +++ b/src/plugins/mpath.c @@ -333,8 +333,10 @@ gboolean bd_mpath_is_mpath_member (const gchar *device, GError **error) { dm_task_run (task_names); names = dm_task_get_names (task_names); - if (!names || !names->dev) + if (!names || !names->dev) { + dm_task_destroy (task_names); return FALSE; + } /* in case the device is dev_path, we need to resolve it because maps's deps are devices and not their dev_paths */ @@ -431,6 +433,7 @@ gchar** bd_mpath_get_mpath_members (GError **error) { names = dm_task_get_names (task_names); if (!names || !names->dev) { + dm_task_destroy (task_names); bd_utils_report_finished (progress_id, "Completed"); return NULL; } From 99a05ef3c4a157769316746592f420281b812c20 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:40:16 +0100 Subject: [PATCH 24/50] part: Fix type_name leak in get_part_type_guid_and_gpt_flags When fdisk_parttype_get_name succeeded but fdisk_parttype_get_string failed, the already-allocated *type_name was leaked. Co-Authored-By: Claude Opus 4.6 --- src/plugins/part.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/part.c b/src/plugins/part.c index f727a0b9..9da98fad 100644 --- a/src/plugins/part.c +++ b/src/plugins/part.c @@ -477,6 +477,8 @@ static gchar* get_part_type_guid_and_gpt_flags (const gchar *device, int part_nu if (!ptype_string) { g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_FAIL, "Failed to get partition type for partition %d on device '%s'", part_num, device); + g_free (*type_name); + *type_name = NULL; fdisk_unref_partition (pa); close_context (cxt); return NULL; From 7de7a3d6c4443270b995dcc5a5018cfcf2e1b00a Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:44:18 +0100 Subject: [PATCH 25/50] nvme: Fix fd leak on _nvme_alloc failure in controller info The file descriptor from _open_dev was not closed before returning when _nvme_alloc failed. Co-Authored-By: Claude Opus 4.6 --- src/plugins/nvme/nvme-info.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/nvme/nvme-info.c b/src/plugins/nvme/nvme-info.c index a52be9c0..b36a644b 100644 --- a/src/plugins/nvme/nvme-info.c +++ b/src/plugins/nvme/nvme-info.c @@ -479,8 +479,10 @@ BDNVMEControllerInfo * bd_nvme_get_controller_info (const gchar *device, GError return NULL; ctrl_id = _nvme_alloc (sizeof (struct nvme_id_ctrl), error); - if (!ctrl_id) + if (!ctrl_id) { + close (fd); return NULL; + } /* send the NVME_IDENTIFY_CNS_CTRL ioctl */ ret = nvme_identify_ctrl (fd, ctrl_id); if (ret != 0) { From 0bf66fe15b434c5e4142ae956ea8063911525589 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 10:46:48 +0100 Subject: [PATCH 26/50] nvme: Fix out-of-bounds read on empty string in set_host_nqn/id Accessing host_nqn[strlen(host_nqn) - 1] when the string is empty reads at index -1 (underflow to SIZE_MAX), causing an out-of-bounds read. Check for empty string before accessing the last character. Co-Authored-By: Claude Opus 4.6 --- src/plugins/nvme/nvme-fabrics.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/nvme/nvme-fabrics.c b/src/plugins/nvme/nvme-fabrics.c index 4445141e..918481f6 100644 --- a/src/plugins/nvme/nvme-fabrics.c +++ b/src/plugins/nvme/nvme-fabrics.c @@ -684,7 +684,7 @@ gboolean bd_nvme_set_host_nqn (const gchar *host_nqn, GError **error) { return FALSE; } filename = g_build_filename (path, "hostnqn", NULL); - if (host_nqn[strlen (host_nqn) - 1] != '\n') + if (strlen (host_nqn) == 0 || host_nqn[strlen (host_nqn) - 1] != '\n') s = g_strdup_printf ("%s\n", host_nqn); else s = g_strdup (host_nqn); @@ -728,7 +728,7 @@ gboolean bd_nvme_set_host_id (const gchar *host_id, GError **error) { return FALSE; } filename = g_build_filename (path, "hostid", NULL); - if (host_id[strlen (host_id) - 1] != '\n') + if (strlen (host_id) == 0 || host_id[strlen (host_id) - 1] != '\n') s = g_strdup_printf ("%s\n", host_id); else s = g_strdup (host_id); From a37b2ba010526dba2a8d96c473272b3d42ace990 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 11:07:27 +0100 Subject: [PATCH 27/50] utils: Fix GRegex leak in bd_utils_version_cmp error paths The regex was not unreffed when validation of ver_string1 or ver_string2 failed. Co-Authored-By: Claude Opus 4.6 --- src/utils/exec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utils/exec.c b/src/utils/exec.c index e8b3b6ba..7ead7bb1 100644 --- a/src/utils/exec.c +++ b/src/utils/exec.c @@ -677,12 +677,14 @@ gint bd_utils_version_cmp (const gchar *ver_string1, const gchar *ver_string2, G if (!success) { g_set_error (error, BD_UTILS_EXEC_ERROR, BD_UTILS_EXEC_ERROR_INVAL_VER, "Invalid or unsupported version (1) format: %s", ver_string1); + g_regex_unref (regex); return -2; } success = g_regex_match (regex, ver_string2, 0, NULL); if (!success) { g_set_error (error, BD_UTILS_EXEC_ERROR, BD_UTILS_EXEC_ERROR_INVAL_VER, "Invalid or unsupported version (2) format: %s", ver_string2); + g_regex_unref (regex); return -2; } g_regex_unref (regex); From 2d6cce20d4d394bf9cc39f2d0fe74403b8816ce2 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 11:12:09 +0100 Subject: [PATCH 28/50] utils: Fix GIOChannel leak in bd_utils_echo_str_to_file When g_io_channel_new_file succeeded but g_io_channel_write_chars failed, the channel was never unreffed. Split the combined condition so the write failure path can properly unref the channel. Co-Authored-By: Claude Opus 4.6 --- src/utils/exec.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/utils/exec.c b/src/utils/exec.c index 7ead7bb1..89fb2348 100644 --- a/src/utils/exec.c +++ b/src/utils/exec.c @@ -957,10 +957,15 @@ gboolean bd_utils_echo_str_to_file (const gchar *str, const gchar *file_path, GE gsize bytes_written = 0; out_file = g_io_channel_new_file (file_path, "w", error); - if (!out_file || g_io_channel_write_chars (out_file, str, -1, &bytes_written, error) != G_IO_STATUS_NORMAL) { + if (!out_file) { g_prefix_error (error, "Failed to write '%s' to file '%s': ", str, file_path); return FALSE; } + if (g_io_channel_write_chars (out_file, str, -1, &bytes_written, error) != G_IO_STATUS_NORMAL) { + g_prefix_error (error, "Failed to write '%s' to file '%s': ", str, file_path); + g_io_channel_unref (out_file); + return FALSE; + } if (g_io_channel_shutdown (out_file, TRUE, error) != G_IO_STATUS_NORMAL) { g_prefix_error (error, "Failed to flush and close the file '%s': ", file_path); g_io_channel_unref (out_file); From 95e3c6c1aca700feda83fe8a0f6fc9ad8111527b Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 11:17:21 +0100 Subject: [PATCH 29/50] lvm: Add missing vg_exported field to bd_lvm_vgs query Unlike bd_lvm_vginfo, bd_lvm_vgs did not request vg_exported, so the exported field was always FALSE in the returned data. Add the field and update the expected item count from 9 to 10. Co-Authored-By: Claude Opus 4.6 --- src/plugins/lvm/lvm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/lvm/lvm.c b/src/plugins/lvm/lvm.c index 9eeb438a..9d373ed7 100644 --- a/src/plugins/lvm/lvm.c +++ b/src/plugins/lvm/lvm.c @@ -1489,7 +1489,7 @@ BDLVMVGdata* bd_lvm_vginfo (const gchar *vg_name, GError **error) { BDLVMVGdata** bd_lvm_vgs (GError **error) { const gchar *args[9] = {"vgs", "--noheadings", "--nosuffix", "--nameprefixes", "--unquoted", "--units=b", - "-o", "name,uuid,size,free,extent_size,extent_count,free_count,pv_count,vg_tags", + "-o", "name,uuid,size,free,extent_size,extent_count,free_count,pv_count,vg_exported,vg_tags", NULL}; GHashTable *table = NULL; gboolean success = FALSE; @@ -1524,7 +1524,7 @@ BDLVMVGdata** bd_lvm_vgs (GError **error) { for (lines_p = lines; *lines_p; lines_p++) { table = parse_lvm_vars ((*lines_p), &num_items); - if (table && (num_items == 9)) { + if (table && (num_items == 10)) { /* valid line, try to parse and record it */ vgdata = get_vg_data_from_table (table, TRUE); if (vgdata) From af6e9b84bfb3f9b2220260f725f9456db6bb2887 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 11:26:54 +0100 Subject: [PATCH 30/50] mdraid: Handle failed UUID canonicalization in bd_md_detail When bd_md_canonicalize_uuid failed and returned NULL, the error was set but the function continued, potentially overwriting the error with a subsequent mdadm call. Check the return value and propagate the error, matching the pattern used in bd_md_examine. Co-Authored-By: Claude Opus 4.6 --- src/plugins/mdraid.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/plugins/mdraid.c b/src/plugins/mdraid.c index 60c10701..1a1de32d 100644 --- a/src/plugins/mdraid.c +++ b/src/plugins/mdraid.c @@ -1132,6 +1132,12 @@ BDMDDetailData* bd_md_detail (const gchar *raid_spec, GError **error) { orig_uuid = ret->uuid; if (orig_uuid) { ret->uuid = bd_md_canonicalize_uuid (orig_uuid, error); + if (!ret->uuid) { + g_prefix_error (error, "Failed to canonicalize MD UUID '%s': ", orig_uuid); + g_free (orig_uuid); + bd_md_detail_data_free (ret); + return NULL; + } g_free (orig_uuid); } From c01386c9ed5362a8cbb4dbdec5531933fce99aba Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 11:29:08 +0100 Subject: [PATCH 31/50] mpath: Fix string array leak on error in get_map_deps g_free(dep_devs) only freed the array pointer, leaking the already-assigned device name strings. Use g_strfreev to free both the strings and the array. Co-Authored-By: Claude Opus 4.6 --- src/plugins/mpath.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/mpath.c b/src/plugins/mpath.c index 49a1d604..6a62d010 100644 --- a/src/plugins/mpath.c +++ b/src/plugins/mpath.c @@ -286,7 +286,7 @@ static gchar** get_map_deps (const gchar *map_name, guint64 *n_deps, GError **er if (l_error) { g_propagate_prefixed_error (error, l_error, "Failed to resolve '%s' to device name", major_minor); - g_free (dep_devs); + g_strfreev (dep_devs); g_free (major_minor); return NULL; } From eb2e5d5fade93a606cad96c82979a974f9bfc83f Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 11:31:49 +0100 Subject: [PATCH 32/50] crypto: Remove incorrect (nullable) annotation from luks_resume context The context parameter in bd_crypto_luks_resume was annotated as (nullable) but was unconditionally dereferenced, causing a NULL pointer dereference if NULL was passed. Resume requires credentials, so remove the (nullable) annotation. Co-Authored-By: Claude Opus 4.6 --- src/lib/plugin_apis/crypto.api | 2 +- src/plugins/crypto.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/plugin_apis/crypto.api b/src/lib/plugin_apis/crypto.api index adf43ffc..3ebdfde5 100644 --- a/src/lib/plugin_apis/crypto.api +++ b/src/lib/plugin_apis/crypto.api @@ -1058,7 +1058,7 @@ gboolean bd_crypto_luks_suspend (const gchar *luks_device, GError **error); /** * bd_crypto_luks_resume: * @luks_device: LUKS device to resume - * @context: (nullable): key slot context (passphrase/keyfile/token...) for @luks_device + * @context: key slot context (passphrase/keyfile/token...) for @luks_device * @error: (out) (optional): place to store error (if any) * * Supported @context types for this function: passphrase, key file diff --git a/src/plugins/crypto.c b/src/plugins/crypto.c index a0f41985..53583c11 100644 --- a/src/plugins/crypto.c +++ b/src/plugins/crypto.c @@ -1960,7 +1960,7 @@ gboolean bd_crypto_luks_suspend (const gchar *luks_device, GError **error) { /** * bd_crypto_luks_resume: * @luks_device: LUKS device to resume - * @context: (nullable): key slot context (passphrase/keyfile/token...) for @luks_device + * @context: key slot context (passphrase/keyfile/token...) for @luks_device * @error: (out) (optional): place to store error (if any) * * Supported @context types for this function: passphrase, key file From f9375d15ca6c4f1c254720d7adacce3edf1f6767 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 5 Mar 2026 11:35:39 +0100 Subject: [PATCH 33/50] crypto: Call report_finished on wipe success in integrity_format When wipe was TRUE and succeeded, bd_utils_report_finished was never called because it was only in the else branch. Move it after the if/else block so it runs on both paths. Co-Authored-By: Claude Opus 4.6 --- src/plugins/crypto.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/crypto.c b/src/plugins/crypto.c index 53583c11..e65b532a 100644 --- a/src/plugins/crypto.c +++ b/src/plugins/crypto.c @@ -2974,11 +2974,10 @@ gboolean bd_crypto_integrity_format (const gchar *device, const gchar *algorithm ret = crypt_deactivate (cd, tmp_name); if (ret != 0) bd_utils_log_format (BD_UTILS_LOG_ERR, "Failed to deactivate temporary device %s", tmp_name); - - } else - bd_utils_report_finished (progress_id, "Completed"); + } crypt_free (cd); + bd_utils_report_finished (progress_id, "Completed"); return TRUE; } From 1c9696181b5c467a1bcc6af18926daec3d3f54ca Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 10:26:13 +0100 Subject: [PATCH 34/50] lib: Add bounds checking and fix integer width in plugin operations Add bounds validation for the plugin parameter in bd_get_plugin_soname and bd_get_plugin_name to prevent out-of-bounds array access, matching the pattern already used by bd_is_plugin_available. Also validate plugin_name from user-supplied require_plugins in load_plugins. Use (guint64) 1 instead of int literal 1 in required_plugins_mask bit shifts to avoid undefined behavior if the number of plugins exceeds 31. Co-Authored-By: Claude Opus 4.6 --- src/lib/blockdev.c.in | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/lib/blockdev.c.in b/src/lib/blockdev.c.in index d407669b..f8f86ce4 100644 --- a/src/lib/blockdev.c.in +++ b/src/lib/blockdev.c.in @@ -342,7 +342,9 @@ static gboolean load_plugins (BDPluginSpec **require_plugins, gboolean reload, g /* set requested sonames */ for (i=0; *(require_plugins + i); i++) { plugin_name = require_plugins[i]->name; - required_plugins_mask |= (1 << plugin_name); + if (plugin_name >= BD_PLUGIN_UNDEF) + continue; + required_plugins_mask |= ((guint64) 1 << plugin_name); if (require_plugins[i]->so_name) { g_slist_free_full (plugins_sonames[plugin_name], (GDestroyNotify) g_free); plugins_sonames[plugin_name] = NULL; @@ -352,7 +354,7 @@ static gboolean load_plugins (BDPluginSpec **require_plugins, gboolean reload, g /* now remove the defaults for plugins that are not required */ for (i=0; (i < BD_PLUGIN_UNDEF); i++) - if (!(required_plugins_mask & (1 << i))) { + if (!(required_plugins_mask & ((guint64) 1 << i))) { /* plugin not required */ g_slist_free_full (plugins_sonames[i], (GDestroyNotify) g_free); plugins_sonames[i] = NULL; @@ -365,7 +367,7 @@ static gboolean load_plugins (BDPluginSpec **require_plugins, gboolean reload, g for (i=0; (i < BD_PLUGIN_UNDEF); i++) { /* if this plugin was required or all plugins were required, check if it was successfully loaded or not */ - if (!require_plugins || (required_plugins_mask & (1 << i))) { + if (!require_plugins || (required_plugins_mask & ((guint64) 1 << i))) { #if !defined(__s390__) && !defined(__s390x__) if (!require_plugins && (i == BD_PLUGIN_S390)) /* do not check the s390 plugin on different archs unless @@ -761,6 +763,9 @@ gboolean bd_is_plugin_available (BDPlugin plugin) { * %NULL if none is loaded */ gchar* bd_get_plugin_soname (BDPlugin plugin) { + if (plugin >= BD_PLUGIN_UNDEF) + return NULL; + if (plugins[plugin].handle) return g_strdup (plugins[plugin].spec.so_name); @@ -774,5 +779,8 @@ gchar* bd_get_plugin_soname (BDPlugin plugin) { * Returns: (transfer none): name of the plugin */ gchar* bd_get_plugin_name (BDPlugin plugin) { + if (plugin >= BD_PLUGIN_UNDEF) + return NULL; + return plugin_names[plugin]; } From 1fe0d8f8ec06507124c27eb704f6710ddcc14641 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 10:27:21 +0100 Subject: [PATCH 35/50] lvm: Fix sscanf type mismatch with gboolean variable Change 'enabled' from gboolean (gint) to guint to match the %u format specifier used with sscanf in _lvm_devices_enabled. Using %u with a gboolean pointer is a type mismatch since gboolean is typedef'd to gint. Co-Authored-By: Claude Opus 4.6 --- src/plugins/lvm/lvm-common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/lvm/lvm-common.c b/src/plugins/lvm/lvm-common.c index b5ec770b..73ca2bdb 100644 --- a/src/plugins/lvm/lvm-common.c +++ b/src/plugins/lvm/lvm-common.c @@ -620,7 +620,7 @@ static gboolean _lvm_devices_enabled () { gboolean ret = FALSE; GError *loc_error = NULL; gchar *output = NULL; - gboolean enabled = FALSE; + guint enabled = 0; gint scanned = 0; g_autofree gchar *config_arg = NULL; @@ -643,7 +643,7 @@ static gboolean _lvm_devices_enabled () { if (scanned != 1) return FALSE; - return enabled; + return enabled != 0; } else { g_clear_error (&loc_error); g_free (output); @@ -660,7 +660,7 @@ static gboolean _lvm_devices_enabled () { if (scanned != 1) return FALSE; - return enabled; + return enabled != 0; } else { g_clear_error (&loc_error); g_free (output); From 54b305de4b7f2ed246140d5a26ab5d5e9315c983 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 10:31:57 +0100 Subject: [PATCH 36/50] lvm: Use exec_and_report_error in _vgcfgbackup_restore The output captured by bd_utils_exec_and_capture_output was never used, causing a memory leak. Switch to bd_utils_exec_and_report_error which doesn't capture the output at all. Co-Authored-By: Claude Opus 4.6 --- src/plugins/lvm/lvm-common.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/lvm/lvm-common.c b/src/plugins/lvm/lvm-common.c index 73ca2bdb..847d96ba 100644 --- a/src/plugins/lvm/lvm-common.c +++ b/src/plugins/lvm/lvm-common.c @@ -791,7 +791,6 @@ gchar* bd_lvm_config_get (const gchar *section, const gchar *setting, const gcha gboolean _vgcfgbackup_restore (const gchar *command, const gchar *vg_name, const gchar *file, const BDExtraArg **extra, GError **error) { const gchar *args[6] = {"lvm", NULL, NULL, NULL, NULL, NULL}; guint next_arg = 1; - gchar *output = NULL; g_autofree gchar *config_arg = NULL; args[next_arg++] = command; @@ -808,7 +807,7 @@ gboolean _vgcfgbackup_restore (const gchar *command, const gchar *vg_name, const } g_mutex_unlock (&global_config_lock); - return bd_utils_exec_and_capture_output (args, extra, &output, error); + return bd_utils_exec_and_report_error (args, extra, error); } /** From 601c0ebd58ffefc5591db1f845516be0419b7541 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 10:32:59 +0100 Subject: [PATCH 37/50] lvm: Fix PV list length truncation in bd_lvm_lvcreate Change pv_list_len from guint8 to guint so it is not silently truncated at 255 entries. While unlikely in practice, g_strv_length returns guint and the value is used to size the args array allocation. Co-Authored-By: Claude Opus 4.6 --- src/plugins/lvm/lvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/lvm/lvm.c b/src/plugins/lvm/lvm.c index 9d373ed7..f591c68a 100644 --- a/src/plugins/lvm/lvm.c +++ b/src/plugins/lvm/lvm.c @@ -1592,7 +1592,7 @@ gchar* bd_lvm_lvorigin (const gchar *vg_name, const gchar *lv_name, GError **err * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_CREATE */ gboolean bd_lvm_lvcreate (const gchar *vg_name, const gchar *lv_name, guint64 size, const gchar *type, const gchar **pv_list, const BDExtraArg **extra, GError **error) { - guint8 pv_list_len = pv_list ? g_strv_length ((gchar **) pv_list) : 0; + guint pv_list_len = pv_list ? g_strv_length ((gchar **) pv_list) : 0; const gchar **args = g_new0 (const gchar*, pv_list_len + 10); gboolean success = FALSE; guint64 i = 0; From 73be8af728a61a7075c1150e4cca849f0a8f7da0 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 10:37:20 +0100 Subject: [PATCH 38/50] fs: Fix memory leak of intermediate g_autofree value in btrfs_get_info The 'item' variable was declared g_autofree but reassigned to a new g_match_info_fetch_named result without freeing the previous value. Since g_autofree only frees the final value at scope exit, the first allocation was leaked. Replace g_autofree with explicit g_free calls at each reassignment and on every exit path for clarity. Co-Authored-By: Claude Opus 4.6 --- src/plugins/fs/btrfs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/fs/btrfs.c b/src/plugins/fs/btrfs.c index e0290c6e..b9d21bff 100644 --- a/src/plugins/fs/btrfs.c +++ b/src/plugins/fs/btrfs.c @@ -326,7 +326,7 @@ BDFSBtrfsInfo* bd_fs_btrfs_get_info (const gchar *mpoint, GError **error) { GRegex *regex = NULL; GMatchInfo *match_info = NULL; BDFSBtrfsInfo *ret = NULL; - g_autofree gchar *item = NULL; + gchar *item = NULL; guint64 num_devices = 0; guint64 min_size = 0; gint scanned = 0; @@ -368,14 +368,17 @@ BDFSBtrfsInfo* bd_fs_btrfs_get_info (const gchar *mpoint, GError **error) { "Btrfs filesystem mounted on %s spans multiple devices (%"G_GUINT64_FORMAT")." \ "Filesystem plugin is not suitable for multidevice Btrfs volumes, please use " \ "Btrfs plugin instead.", mpoint, num_devices); + g_free (item); g_match_info_free (match_info); g_regex_unref (regex); bd_fs_btrfs_info_free (ret); return NULL; } + g_free (item); item = g_match_info_fetch_named (match_info, "size"); ret->size = g_ascii_strtoull (item, NULL, 0); + g_free (item); g_match_info_free (match_info); g_regex_unref (regex); From 1bead0dda0994ecaab01dc00a8d235de1c0b703d Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 10:45:15 +0100 Subject: [PATCH 39/50] fs: Include colon in ntfsinfo strstr patterns to prevent NULL strchr Include ':' in the strstr search patterns so that the subsequent strchr call for ':' is guaranteed to find a match, preventing a potential NULL pointer dereference. Co-Authored-By: Claude Opus 4.6 --- src/plugins/fs/ntfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/fs/ntfs.c b/src/plugins/fs/ntfs.c index 6bc552ee..abcc0749 100644 --- a/src/plugins/fs/ntfs.c +++ b/src/plugins/fs/ntfs.c @@ -403,7 +403,7 @@ BDFSNtfsInfo* bd_fs_ntfs_get_info (const gchar *device, GError **error) { line_p = lines; /* find the beginning of the (data) section we are interested in */ - while (line_p && *line_p && !strstr (*line_p, "Cluster Size")) + while (line_p && *line_p && !strstr (*line_p, "Cluster Size:")) line_p++; if (!line_p || !(*line_p)) { g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_PARSE, "Failed to parse NTFS file system information"); @@ -417,7 +417,7 @@ BDFSNtfsInfo* bd_fs_ntfs_get_info (const gchar *device, GError **error) { val_start++; cluster_size = g_ascii_strtoull (val_start, NULL, 0); - while (line_p && *line_p && !strstr (*line_p, "Volume Size in Clusters")) + while (line_p && *line_p && !strstr (*line_p, "Volume Size in Clusters:")) line_p++; if (!line_p || !(*line_p)) { g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_PARSE, "Failed to parse NTFS file system information"); @@ -431,7 +431,7 @@ BDFSNtfsInfo* bd_fs_ntfs_get_info (const gchar *device, GError **error) { val_start++; ret->size = g_ascii_strtoull (val_start, NULL, 0) * cluster_size; - while (line_p && *line_p && !strstr (*line_p, "Free Clusters")) + while (line_p && *line_p && !strstr (*line_p, "Free Clusters:")) line_p++; if (!line_p || !(*line_p)) { g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_PARSE, "Failed to parse NTFS file system information"); From fad207cb13c47ab7b63208d3f6fc1adb94e048d4 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 10:46:39 +0100 Subject: [PATCH 40/50] fs: Fix copy-paste error in bd_fs_mount error message The error message incorrectly said "unmount" instead of "mount" for unsupported extra arguments in bd_fs_mount. Co-Authored-By: Claude Opus 4.6 --- src/plugins/fs/mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/fs/mount.c b/src/plugins/fs/mount.c index 7b611a89..b52ed8ab 100644 --- a/src/plugins/fs/mount.c +++ b/src/plugins/fs/mount.c @@ -764,7 +764,7 @@ gboolean bd_fs_mount (const gchar *device, const gchar *mountpoint, const gchar } } else { g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL, - "Unsupported argument for unmount: '%s'", (*extra_p)->opt); + "Unsupported argument for mount: '%s'", (*extra_p)->opt); return FALSE; } } From 42a1e6289f2d4a4d29728f9bb39eeaef040442e1 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 10:47:58 +0100 Subject: [PATCH 41/50] fs: Fix wrong error code when NTFS device is mounted bd_fs_ntfs_get_info used BD_FS_ERROR_NOT_MOUNTED when the device was actually mounted. Use BD_FS_ERROR_FAIL instead since the semantics were inverted. Co-Authored-By: Claude Opus 4.6 --- src/plugins/fs/ntfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/fs/ntfs.c b/src/plugins/fs/ntfs.c index abcc0749..a7b626c7 100644 --- a/src/plugins/fs/ntfs.c +++ b/src/plugins/fs/ntfs.c @@ -372,7 +372,7 @@ BDFSNtfsInfo* bd_fs_ntfs_get_info (const gchar *device, GError **error) { mountpoint = bd_fs_get_mountpoint (device, &l_error); if (mountpoint != NULL) { - g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOT_MOUNTED, + g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL, "Can't get NTFS file system information for '%s': Device is mounted.", device); return NULL; } else { From 48e92cf69945b9652fad562adec88f2deee99498 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 10:48:28 +0100 Subject: [PATCH 42/50] fs: Set error on regex mismatch in btrfs_get_info When the regex failed to match the btrfs filesystem show output, the function returned NULL without setting the error, making it impossible for callers to distinguish between "no info" and "parse error". Co-Authored-By: Claude Opus 4.6 --- src/plugins/fs/btrfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/fs/btrfs.c b/src/plugins/fs/btrfs.c index b9d21bff..fbfe7b84 100644 --- a/src/plugins/fs/btrfs.c +++ b/src/plugins/fs/btrfs.c @@ -351,6 +351,8 @@ BDFSBtrfsInfo* bd_fs_btrfs_get_info (const gchar *mpoint, GError **error) { success = g_regex_match (regex, output, 0, &match_info); if (!success) { + g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_PARSE, + "Failed to parse btrfs filesystem information"); g_regex_unref (regex); g_match_info_free (match_info); return NULL; From 5dab4115b623cda2381c71477d4a6f0606d90347 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 10:49:19 +0100 Subject: [PATCH 43/50] fs: Use g_new0 for BDFSBtrfsInfo allocation in btrfs_get_info Use g_new0 instead of g_new to zero-initialize the struct, consistent with all other info struct allocations in the codebase. This prevents uninitialized fields if new members are added in the future. Co-Authored-By: Claude Opus 4.6 --- src/plugins/fs/btrfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/fs/btrfs.c b/src/plugins/fs/btrfs.c index fbfe7b84..71071809 100644 --- a/src/plugins/fs/btrfs.c +++ b/src/plugins/fs/btrfs.c @@ -358,7 +358,7 @@ BDFSBtrfsInfo* bd_fs_btrfs_get_info (const gchar *mpoint, GError **error) { return NULL; } - ret = g_new (BDFSBtrfsInfo, 1); + ret = g_new0 (BDFSBtrfsInfo, 1); ret->label = g_match_info_fetch_named (match_info, "label"); ret->uuid = g_match_info_fetch_named (match_info, "uuid"); From d57dd8266993f1bfec60c29215313613a231bb83 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 10:50:57 +0100 Subject: [PATCH 44/50] fs: Fix mount cache leak on mnt_table_set_cache failure In both bd_fs_get_mountpoint and bd_fs_is_mountpoint, when mnt_table_set_cache fails, the cache object was not freed before returning. Co-Authored-By: Claude Opus 4.6 --- src/plugins/fs/mount.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/fs/mount.c b/src/plugins/fs/mount.c index b52ed8ab..eaf098a9 100644 --- a/src/plugins/fs/mount.c +++ b/src/plugins/fs/mount.c @@ -811,6 +811,7 @@ gchar* bd_fs_get_mountpoint (const gchar *device, GError **error) { g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL, "Failed to set cache for mount info table."); mnt_free_table (table); + mnt_free_cache (cache); return NULL; } @@ -867,6 +868,7 @@ gboolean bd_fs_is_mountpoint (const gchar *path, GError **error) { g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL, "Failed to set cache for mount info table."); mnt_free_table (table); + mnt_free_cache (cache); return FALSE; } From cef75503c37d75d271f67e03371569c7b062ef0a Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 10:53:06 +0100 Subject: [PATCH 45/50] swap: Fix double report_finished call in swapon/swapoff Both bd_swap_swapon and bd_swap_swapoff called bd_utils_report_finished with the error message on failure, then fell through to call it again with "Completed". Add early return on error paths to prevent the duplicate call. Co-Authored-By: Claude Opus 4.6 --- src/plugins/swap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/swap.c b/src/plugins/swap.c index 9d6e2a98..2ba3d333 100644 --- a/src/plugins/swap.c +++ b/src/plugins/swap.c @@ -347,10 +347,11 @@ gboolean bd_swap_swapon (const gchar *device, gint priority, GError **error) { "Failed to activate swap on %s: %m", device); bd_utils_report_finished (progress_id, l_error->message); g_propagate_error (error, l_error); + return FALSE; } bd_utils_report_finished (progress_id, "Completed"); - return ret == 0; + return TRUE; } /** @@ -378,10 +379,11 @@ gboolean bd_swap_swapoff (const gchar *device, GError **error) { "Failed to deactivate swap on %s: %m", device); bd_utils_report_finished (progress_id, l_error->message); g_propagate_error (error, l_error); + return FALSE; } bd_utils_report_finished (progress_id, "Completed"); - return ret == 0; + return TRUE; } /** From 5ed2016954972107a62f4792a874ca97cd1c377f Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 10:54:20 +0100 Subject: [PATCH 46/50] s390: Fix error message saying "online" in bd_s390_zfcp_offline The error message incorrectly said "Could not set zFCP device online" in the offline function. Co-Authored-By: Claude Opus 4.6 --- src/plugins/s390.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/s390.c b/src/plugins/s390.c index 97c05a66..90a43ac9 100644 --- a/src/plugins/s390.c +++ b/src/plugins/s390.c @@ -1022,7 +1022,7 @@ gboolean bd_s390_zfcp_offline (const gchar *devno, const gchar *wwpn, const gcha g_free (offline); if (!success) { g_set_error (&l_error, BD_S390_ERROR, BD_S390_ERROR_DEVICE, - "Could not set zFCP device %s online", devno); + "Could not set zFCP device %s offline", devno); bd_utils_report_finished (progress_id, l_error->message); g_propagate_error (error, l_error); return FALSE; From 24d9b9f19f4afae89f020363dca8c9d05a999aa9 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 11:00:34 +0100 Subject: [PATCH 47/50] loop: Fix double /dev/ prefix in autoclear progress message The format string had a hardcoded "/dev/" prefix, but the variable already contains the full path including "/dev/" when needed. Co-Authored-By: Claude Opus 4.6 --- src/plugins/loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/loop.c b/src/plugins/loop.c index 037dde84..f17e445b 100644 --- a/src/plugins/loop.c +++ b/src/plugins/loop.c @@ -480,7 +480,7 @@ gboolean bd_loop_set_autoclear (const gchar *loop, gboolean autoclear, GError ** if (!g_str_has_prefix (loop, "/dev/")) dev_loop = g_strdup_printf ("/dev/%s", loop); - msg = g_strdup_printf ("Started setting up the autoclear flag on the /dev/%s device", + msg = g_strdup_printf ("Started setting up the autoclear flag on the %s device", dev_loop ? dev_loop : loop); progress_id = bd_utils_report_started (msg); g_free (msg); From a7f6cb635a93ef9bd959c99167b26593b2fb1e46 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 12:09:35 +0100 Subject: [PATCH 48/50] s390: Fix potential NULL dereference of error in bd_s390_zfcp_online The error parameter is optional but was dereferenced directly via (*error)->message when the WWPN directory was not found. Use a local l_error variable and g_propagate_error, consistent with the rest of the function. Co-Authored-By: Claude Opus 4.6 --- src/plugins/s390.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/s390.c b/src/plugins/s390.c index 90a43ac9..781de405 100644 --- a/src/plugins/s390.c +++ b/src/plugins/s390.c @@ -633,10 +633,11 @@ gboolean bd_s390_zfcp_online (const gchar *devno, const gchar *wwpn, const gchar portdir = g_strdup_printf ("%s/%s/%s", zfcpsysfs, devno, wwpn); pdfd = opendir (portdir); if (!pdfd) { - g_set_error (error, BD_S390_ERROR, BD_S390_ERROR_DEVICE, + g_set_error (&l_error, BD_S390_ERROR, BD_S390_ERROR_DEVICE, "WWPN %s not found for zFCP device %s", wwpn, devno); g_free (portdir); - bd_utils_report_finished (progress_id, (*error)->message); + bd_utils_report_finished (progress_id, l_error->message); + g_propagate_error (error, l_error); return FALSE; } closedir (pdfd); From da5bc5cc258172f68419f0ef542bb2d93807d6cf Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 12:39:03 +0100 Subject: [PATCH 49/50] part: Fix inconsistent progress tracking in set_part_name/set_part_uuid Both bd_part_set_part_name and bd_part_set_part_uuid called bd_utils_report_started but returned without calling bd_utils_report_finished when get_device_context failed. Also used error directly instead of &l_error, inconsistent with the rest of the function. Co-Authored-By: Claude Opus 4.6 --- src/plugins/part.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/plugins/part.c b/src/plugins/part.c index 9da98fad..03a5c856 100644 --- a/src/plugins/part.c +++ b/src/plugins/part.c @@ -1828,9 +1828,11 @@ gboolean bd_part_set_part_name (const gchar *disk, const gchar *part, const gcha progress_id = bd_utils_report_started (msg); g_free (msg); - cxt = get_device_context (disk, FALSE, error); + cxt = get_device_context (disk, FALSE, &l_error); if (!cxt) { /* error is already populated */ + bd_utils_report_finished (progress_id, l_error->message); + g_propagate_error (error, l_error); return FALSE; } @@ -2059,9 +2061,11 @@ gboolean bd_part_set_part_uuid (const gchar *disk, const gchar *part, const gcha progress_id = bd_utils_report_started (msg); g_free (msg); - cxt = get_device_context (disk, FALSE, error); + cxt = get_device_context (disk, FALSE, &l_error); if (!cxt) { /* error is already populated */ + bd_utils_report_finished (progress_id, l_error->message); + g_propagate_error (error, l_error); return FALSE; } From 0176603c6949e83242a9b03315fbf2a0172fba3e Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 6 Mar 2026 13:42:50 +0100 Subject: [PATCH 50/50] s390: Fix multiple memory leaks in bd_s390_zfcp_scsi_offline Several variables allocated each loop iteration were never freed before reassignment: scsidev, scsidel (g_strdup_printf), and fcphbasysfs, fcpwwpnsysfs, fcplunsysfs (getline). Free them at the end of each iteration. The getline-allocated 'line' buffer and the scsifd file handle were also leaked on all error return paths inside the loop. Co-Authored-By: Claude Opus 4.6 --- src/plugins/s390.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/plugins/s390.c b/src/plugins/s390.c index 781de405..15b0644e 100644 --- a/src/plugins/s390.c +++ b/src/plugins/s390.c @@ -797,6 +797,8 @@ gboolean bd_s390_zfcp_scsi_offline (const gchar *devno, const gchar *wwpn, const g_free (hba_path); g_free (fcpsysfs); g_free (scsidev); + fclose (scsifd); + g_free (line); bd_utils_report_finished (progress_id, l_error->message); g_propagate_error (error, l_error); return FALSE; @@ -809,6 +811,8 @@ gboolean bd_s390_zfcp_scsi_offline (const gchar *devno, const gchar *wwpn, const g_free (hba_path); g_free (fcpsysfs); g_free (scsidev); + fclose (scsifd); + g_free (line); bd_utils_report_finished (progress_id, l_error->message); g_propagate_error (error, l_error); return FALSE; @@ -828,6 +832,8 @@ gboolean bd_s390_zfcp_scsi_offline (const gchar *devno, const gchar *wwpn, const g_free (fcphbasysfs); g_free (fcpsysfs); g_free (scsidev); + fclose (scsifd); + g_free (line); bd_utils_report_finished (progress_id, l_error->message); g_propagate_error (error, l_error); return FALSE; @@ -841,6 +847,8 @@ gboolean bd_s390_zfcp_scsi_offline (const gchar *devno, const gchar *wwpn, const g_free (fcpsysfs); g_free (scsidev); fclose (fd); + fclose (scsifd); + g_free (line); bd_utils_report_finished (progress_id, l_error->message); g_propagate_error (error, l_error); return FALSE; @@ -861,6 +869,8 @@ gboolean bd_s390_zfcp_scsi_offline (const gchar *devno, const gchar *wwpn, const g_free (fcphbasysfs); g_free (fcpsysfs); g_free (scsidev); + fclose (scsifd); + g_free (line); bd_utils_report_finished (progress_id, l_error->message); g_propagate_error (error, l_error); return FALSE; @@ -875,6 +885,8 @@ gboolean bd_s390_zfcp_scsi_offline (const gchar *devno, const gchar *wwpn, const g_free (fcphbasysfs); g_free (fcpsysfs); g_free (scsidev); + fclose (scsifd); + g_free (line); bd_utils_report_finished (progress_id, l_error->message); g_propagate_error (error, l_error); return FALSE; @@ -897,6 +909,8 @@ gboolean bd_s390_zfcp_scsi_offline (const gchar *devno, const gchar *wwpn, const g_free (fcpwwpnsysfs); g_free (fcphbasysfs); g_free (scsidev); + fclose (scsifd); + g_free (line); bd_utils_report_finished (progress_id, l_error->message); g_propagate_error (error, l_error); return FALSE; @@ -911,19 +925,28 @@ gboolean bd_s390_zfcp_scsi_offline (const gchar *devno, const gchar *wwpn, const g_free (fcpwwpnsysfs); g_free (fcphbasysfs); g_free (scsidev); + fclose (scsifd); + g_free (line); bd_utils_report_finished (progress_id, l_error->message); g_propagate_error (error, l_error); return FALSE; } fclose (fd); } + + g_free (scsidel); + scsidel = NULL; + g_free (scsidev); + scsidev = NULL; + g_free (fcplunsysfs); + fcplunsysfs = NULL; + g_free (fcpwwpnsysfs); + fcpwwpnsysfs = NULL; + g_free (fcphbasysfs); + fcphbasysfs = NULL; } fclose (scsifd); - g_free (scsidel); - g_free (fcplunsysfs); - g_free (fcpwwpnsysfs); - g_free (fcphbasysfs); - g_free (scsidev); + g_free (line); bd_utils_report_finished (progress_id, "Completed"); return TRUE; }