From d3763a5707eaf8e5ae21af0f0f22338b1441e075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= Date: Wed, 5 Aug 2026 11:59:01 +0200 Subject: [PATCH] Fix iterating over checksums in modulemd_module_stream_v2_emit_rpm_map() There was a copy-and-paste mistake in an inner loop in modulemd_module_stream_v2_emit_rpm_map() function. As a result when serializing a module index into a YAML string where a number of hash types was different from a number of hashes of a particular type in "rpm-map" modulemd-v2 YAML element, not all hashes would be serialized or an invalid memory would be read. E.g. an attempt to serialize this document: document: modulemd version: 2 data: [...] artifacts: rpm-map: sha256: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: name: bar epoch: 0 version: 0 release: 0 arch: x86_64 nevra: bar-0:0-0.x86_64 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: name: foo epoch: 0 version: 0 release: 0 arch: x86_64 nevra: foo-0:0-0.x86_64 sha512: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: name: bar epoch: 0 version: 0 release: 0 arch: x86_64 nevra: bar-0:0-0.x86_64 would provoke valgrind like this: Use of uninitialised value of size 8 at 0x48624E6: strlen (vg_replace_strmem.c:506) by 0x48D9027: mmd_emitter_scalar (modulemd-yaml-util.c:293) by 0x48C75DE: modulemd_module_stream_v2_emit_rpm_map (modulemd-module-stream-v2.c:3271) by 0x48C857A: modulemd_module_stream_v2_emit_yaml (modulemd-module-stream-v2.c:3211) by 0x48B1437: dump_streams (modulemd-module-index.c:498) by 0x48B1437: modulemd_module_index_dump_to_emitter (modulemd-module-index.c:562) by 0x48B169C: modulemd_module_index_dump_to_string (modulemd-module-index.c:936) by 0x401222: main (in /tmp/a.out) This patch fixes an upper bound condition of the inner loop. It also adds a test. This flaw was intruduced with b5abf3bbedd211a403122fccfec192581e2bbe8f commit ("Add rpm-map to ModuleStreamV2") and first released in 2.2.0 version. Acknowledgement: Aisle Research Resolves: CVE-2026-92824 --- .../modulemd-module-stream-v2-private.h | 18 ++++ modulemd/modulemd-module-stream-v2.c | 7 +- modulemd/tests/test-modulemd-modulestream.c | 93 +++++++++++++++++++ 3 files changed, 112 insertions(+), 6 deletions(-) diff --git a/modulemd/include/private/modulemd-module-stream-v2-private.h b/modulemd/include/private/modulemd-module-stream-v2-private.h index eaff4ec4..5ddde16a 100644 --- a/modulemd/include/private/modulemd-module-stream-v2-private.h +++ b/modulemd/include/private/modulemd-module-stream-v2-private.h @@ -111,6 +111,24 @@ modulemd_module_stream_v2_parse_yaml (ModulemdSubdocumentInfo *subdoc, gboolean only_packager, GError **error); +/** + * modulemd_module_stream_v2_emit_rpm_map: + * @self: (in) This #ModulemdModuleStreamV2 object. + * @emitter: (inout): A libyaml emitter object positioned where the "rpm-map" + * element of #ModulemdModuleStreamV2 belongs in the YAML document. + * @error: (out): A #GError that will return the reason why the emission + * failed. + * + * Return: TRUE if the "rpm-map" YAML element was successfully serialized. + * Otherwise, FALSE and sets @error appropriately. + * + * Since: 2.2.0 + */ +gboolean +modulemd_module_stream_v2_emit_rpm_map (ModulemdModuleStreamV2 *self, + yaml_emitter_t *emitter, + GError **error); + /** * modulemd_module_stream_v2_emit_yaml: * @self: This #ModulemdModuleStreamV2 object. diff --git a/modulemd/modulemd-module-stream-v2.c b/modulemd/modulemd-module-stream-v2.c index 5afa4352..78de41ff 100644 --- a/modulemd/modulemd-module-stream-v2.c +++ b/modulemd/modulemd-module-stream-v2.c @@ -3060,11 +3060,6 @@ modulemd_module_stream_v2_parse_rpm_map_digest ( } -gboolean -modulemd_module_stream_v2_emit_rpm_map (ModulemdModuleStreamV2 *self, - yaml_emitter_t *emitter, - GError **error); - gboolean modulemd_module_stream_v2_emit_yaml (ModulemdModuleStreamV2 *self, yaml_emitter_t *emitter, @@ -3265,7 +3260,7 @@ modulemd_module_stream_v2_emit_rpm_map (ModulemdModuleStreamV2 *self, checksums = modulemd_ordered_str_keys (digest_table, modulemd_strcmp_sort); - for (guint j = 0; j < digests->len; j++) + for (guint j = 0; j < checksums->len; j++) { checksum = g_ptr_array_index (checksums, j); EMIT_SCALAR (emitter, error, checksum); diff --git a/modulemd/tests/test-modulemd-modulestream.c b/modulemd/tests/test-modulemd-modulestream.c index 1835472a..a80b6f19 100644 --- a/modulemd/tests/test-modulemd-modulestream.c +++ b/modulemd/tests/test-modulemd-modulestream.c @@ -3105,6 +3105,96 @@ module_stream_v2_test_rpm_map (void) } +/* Use a number of hash types different from a number of hashes to exhibit + * loop nesting in modulemd_module_stream_v2_emit_rpm_map(). */ +static void +module_stream_v2_test_rpm_map_serialize (void) +{ + g_autoptr (ModulemdModuleStreamV2) stream = NULL; + g_autoptr (ModulemdRpmMapEntry) entry = NULL; + MMD_INIT_YAML_EMITTER (emitter); + MMD_INIT_YAML_STRING (&emitter, yaml_string); + g_autoptr (GError) error = NULL; + + /* Build a stream document with non-trivial "rpm-map" entries. */ + stream = modulemd_module_stream_v2_new ("test", "a"); + g_assert_nonnull (stream); + + entry = modulemd_rpm_map_entry_new ("bar", 0, "0", "0", "x86_64"); + g_assert_nonnull (entry); + modulemd_module_stream_v2_set_rpm_artifact_map_entry ( + stream, + entry, + "sha256", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + g_clear_object (&entry); + + entry = modulemd_rpm_map_entry_new ("foo", 0, "0", "0", "x86_64"); + g_assert_nonnull (entry); + modulemd_module_stream_v2_set_rpm_artifact_map_entry ( + stream, + entry, + "sha256", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); + g_clear_object (&entry); + + entry = modulemd_rpm_map_entry_new ("bar", 0, "0", "0", "x86_64"); + g_assert_nonnull (entry); + modulemd_module_stream_v2_set_rpm_artifact_map_entry ( + stream, + entry, + "sha512", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); + g_clear_object (&entry); + + /* Serialize the "rpm-map" entry */ + g_assert_true (mmd_emitter_start_stream (&emitter, &error)); + g_assert_true (mmd_emitter_start_document (&emitter, &error)); + g_assert_true ( + mmd_emitter_start_mapping (&emitter, YAML_BLOCK_MAPPING_STYLE, &error)); + g_assert_true ( + modulemd_module_stream_v2_emit_rpm_map (stream, &emitter, &error)); + g_assert_no_error (error); + g_assert_true (mmd_emitter_end_mapping (&emitter, &error)); + g_assert_true (mmd_emitter_end_document (&emitter, &error)); + g_assert_true (mmd_emitter_end_stream (&emitter, &error)); + + /* Check that it was serialized correctly */ + g_assert_cmpstr ( + yaml_string->str, + ==, + "---\n" + "rpm-map:\n" + " sha256:\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:\n" + " name: bar\n" + " epoch: 0\n" + " version: \"0\"\n" + " release: \"0\"\n" + " arch: x86_64\n" + " nevra: bar-0:0-0.x86_64\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb:\n" + " name: foo\n" + " epoch: 0\n" + " version: \"0\"\n" + " release: \"0\"\n" + " arch: x86_64\n" + " nevra: foo-0:0-0.x86_64\n" + " sha512:\n" + " " + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb:\n" + " name: bar\n" + " epoch: 0\n" + " version: \"0\"\n" + " release: \"0\"\n" + " arch: x86_64\n" + " nevra: bar-0:0-0.x86_64\n" + "...\n"); +} + + static void module_stream_test_unicode_desc (void) { @@ -3639,6 +3729,9 @@ main (int argc, char *argv[]) g_test_add_func ("/modulemd/v2/modulestream/v2/rpm_map", module_stream_v2_test_rpm_map); + g_test_add_func ("/modulemd/v2/modulestream/v2/rpm_map_serialize", + module_stream_v2_test_rpm_map_serialize); + g_test_add_func ("/modulemd/v2/modulestream/v1/community", module_stream_v1_test_community);