Fedora Account System
Red Hat Associate
Red Hat Customer
AI_ONLY_REPORT package: libmodulemd-2.15.2-7.1.hum1 ------ Summary: Unbounded recursion while parsing attacker-controlled XMD YAML into nested GVariant: denial of service is possible when deeply nested `xmd` YAML is recursively converted into `GVariant` values without recursion-depth or node-count limits, leading to stack exhaustion and excessive parser resource consumption. Requirements to exploit: The attacker must be able to cause an application or tool using `libmodulemd-2.15.2-7.1.hum1` to parse attacker-controlled modulemd YAML containing a deeply nested `xmd` field. This is reachable through public parsing interfaces such as `modulemd_module_index_update_from_string()`, `modulemd_module_index_update_from_stream()`, `modulemd_module_index_update_from_custom()`, or tooling such as `modulemd-validator`. No privileges are required, but environments that only ingest trusted metadata materially reduce exposure. Component affected: `libmodulemd-2.15.2-7.1.hum1`, primarily `modulemd/modulemd-yaml-util.c` (`mmd_parse_xmd()`, `mmd_variant_from_mapping()`, `mmd_variant_from_sequence()`), reached from the `xmd` handling in `modulemd/modulemd-module-stream-v1.c`, `modulemd/modulemd-module-stream-v2.c`, and `modulemd/modulemd-packager-v3.c`. Version affected: `libmodulemd-2.15.2-7.1.hum1` Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Not notified. CVSS: CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - 5.5 (MEDIUM) AV:L - The evidence shows a library/parser issue triggered when a local consumer parses attacker-controlled modulemd YAML; the available materials do not establish a network-facing service in this package. AC:L - A sufficiently deep `xmd` nesting structure is enough to drive the vulnerable recursion. PR:N - No privileges are required to supply malicious metadata to a parser that accepts attacker-controlled input. UI:N - No separate human action is required beyond the normal parsing of the supplied document. S:U - The failure remains within the security scope of the parsing process. C:N - The available evidence does not show confidentiality impact. I:N - The available evidence does not show integrity impact. A:H - The parser can crash, abort, or consume substantial resources, causing a denial of service. Impact: Moderate. Based on the Red Hat severity guidance, the supported impact is availability loss rather than code execution or data exposure. The issue can be serious for consumers that parse untrusted module metadata, but exploitability depends on attacker control over the parsed YAML and is therefore deployment-dependent rather than an easily exploitable remote service case. Embargo: no Reason: The available evidence supports a moderate, availability-only parser denial of service. Exploitation depends on a consumer accepting attacker-controlled modulemd content, and straightforward operational mitigations exist until a code fix is shipped. Acknowledgement: Aisle Research Vulnerability Details: `libmodulemd-2.15.2-7.1.hum1` parses `xmd` content in module stream v1, module stream v2, and packager v3 documents by calling `mmd_parse_xmd()` when the `xmd` key is encountered. `mmd_parse_xmd()` dispatches YAML mappings to `mmd_variant_from_mapping()`, and the conversion helpers recurse again whenever nested mappings or sequences are seen. The available code does not show a recursion-depth limit or a total-node limit in this path. The following excerpt from `modulemd/modulemd-yaml-util.c` shows the recursive descent in `mmd_variant_from_mapping()`: ```c ... case YAML_MAPPING_START_EVENT: value = mmd_variant_from_mapping (parser, &nested_error); if (!value) { g_propagate_error (error, g_steal_pointer (&nested_error)); return NULL; } break; case YAML_SEQUENCE_START_EVENT: value = mmd_variant_from_sequence (parser, &nested_error); if (!value) { g_propagate_error (error, g_steal_pointer (&nested_error)); return NULL; } break; ... ``` `mmd_variant_from_sequence()` contains the same recursive pattern for nested mappings and nested sequences. Because this descent is unbounded, sufficiently deep attacker-controlled `xmd` YAML can exhaust stack space and may also create severe parse-time CPU or memory pressure. The clearest supported outcome is denial of service. The available evidence does not establish confidentiality, integrity, or code execution impact. Steps to reproduce: 1. Build libmodulemd and `modulemd-validator` with sanitizers if available, and set a typical stack limit such as `ulimit -s 8192`. 2. Create a modulemd v2 document with deeply nested `xmd` content, for example: ```yaml document: modulemd version: 2 data: name: demo stream: s version: 1 context: c0 arch: x86_64 summary: s description: d license: { module: [MIT] } xmd: {a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{}}}}}}}}}}}}}}}}}}}} ``` 3. Parse the file with `modulemd-validator <file.yaml>`, or feed the same content to `modulemd_module_index_update_from_string()`. 4. Increase the nesting depth until parsing fails. The expected result is a crash, abort, stack overflow, or severe parse-time resource pressure, depending on the runtime environment and stack limit. 5. A backtrace should show the failure through `mmd_parse_xmd()` into the `mmd_variant_from_mapping()` / `mmd_variant_from_sequence()` recursion chain. Mitigation: Until a fix is available, avoid parsing untrusted modulemd documents containing attacker-controlled `xmd` data. If such input must be accepted, reject unusually deep or large `xmd` structures before handing them to libmodulemd and isolate parsing in a process with strict stack, CPU, and memory limits. If supported by the YAML stack, parser-side depth or alias limits should also be enabled. Proposed Fix: Enforce both a maximum recursion depth and a maximum parsed-node count in the `xmd` conversion path, and return an error when either limit is exceeded. ```diff diff --git a/modulemd/modulemd-yaml-util.c b/modulemd/modulemd-yaml-util.c @@ +#define MMD_XMD_MAX_DEPTH 128 +#define MMD_XMD_MAX_NODES 100000 + +static GVariant *mmd_variant_from_mapping_limited ( + yaml_parser_t *parser, GError **error, guint depth, guint *nodes); +static GVariant *mmd_variant_from_sequence_limited ( + yaml_parser_t *parser, GError **error, guint depth, guint *nodes); @@ -GVariant *mmd_variant_from_mapping (yaml_parser_t *parser, GError **error) +static GVariant *mmd_variant_from_mapping_limited ( + yaml_parser_t *parser, GError **error, guint depth, guint *nodes) { + if (depth > MMD_XMD_MAX_DEPTH || ++(*nodes) > MMD_XMD_MAX_NODES) + MMD_YAML_ERROR_EVENT_EXIT (error, event, "xmd exceeds safety limits"); @@ value = mmd_variant_from_mapping (parser, &nested_error); + value = mmd_variant_from_mapping_limited ( + parser, &nested_error, depth + 1, nodes); @@ value = mmd_variant_from_sequence (parser, &nested_error); + value = mmd_variant_from_sequence_limited ( + parser, &nested_error, depth + 1, nodes); @@ -GVariant *mmd_variant_from_sequence (yaml_parser_t *parser, GError **error) +static GVariant *mmd_variant_from_sequence_limited ( + yaml_parser_t *parser, GError **error, guint depth, guint *nodes) { + if (depth > MMD_XMD_MAX_DEPTH || ++(*nodes) > MMD_XMD_MAX_NODES) + MMD_YAML_ERROR_EVENT_EXIT (error, event, "xmd exceeds safety limits"); @@ value = mmd_variant_from_mapping (parser, &nested_error); + value = mmd_variant_from_mapping_limited ( + parser, &nested_error, depth + 1, nodes); @@ value = mmd_variant_from_sequence (parser, &nested_error); + value = mmd_variant_from_sequence_limited ( + parser, &nested_error, depth + 1, nodes); @@ GVariant *mmd_parse_xmd (yaml_parser_t *parser, GError **error) { + guint nodes = 0; @@ variant = mmd_variant_from_mapping (parser, &nested_error); + variant = mmd_variant_from_mapping_limited ( + parser, &nested_error, 1, &nodes); ``` ------ This report was generated using AI technology. Always review AI-generated content prior to use