From 3f5477dd35de312556258c25b1a8e9c4adb6677e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= Date: Tue, 8 Sep 2026 14:10:15 +0200 Subject: [PATCH 1/2] Introduce a recursion limit for YAML documents A modulemd document with "xmd" element having 2^16 nested single-character mapping elements, occupying 327860 bytes, causes modulemd-validator to exhaust all heap memory (tens of gigabytes) when duplicating subdocuments in modulemd_yaml_parse_document_type_internal(). This patch adds a "recursion_limit" build-time option defining a maximal depth of acceptable YAML documents. Default is 64. The only recursive structure in the modulemd documents is "xmd" which has unspecified content. Thus this patch adds tests exhibiting modulemd_yaml_parse_document_type() on an acceptable document and on an oversized document. modulemd_yaml_parse_document_type() is common to all public parsing functions and calls the affected modulemd_yaml_parse_document_type_internal() function. This flaw was confirmed in current 2.15.3 version and back to 1.4.0 version. Earlier versions might be affected as well. Acknowledgement: Aisle Research Resolves: CVE-2026-92822 --- meson.build | 1 + meson_options.txt | 3 + modulemd/meson.build | 3 + modulemd/modulemd-yaml-util.c | 10 +- modulemd/tests/test-modulemd-limits.c | 141 ++++++++++++++++++++++++++ 5 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 modulemd/tests/test-modulemd-limits.c diff --git a/meson.build b/meson.build index df6e5ae1..813a8592 100644 --- a/meson.build +++ b/meson.build @@ -228,5 +228,6 @@ summary({'Custom Python': get_option('python_name'), 'Python 3 Support': get_option('with_py3'), 'Skip Introspection': get_option('skip_introspection'), 'Accept overflowed buildorder': get_option('accept_overflowed_buildorder'), + 'Recursion limit': get_option('recursion_limit'), 'Test Installed Library': get_option('test_installed_lib'), }, section: 'Build Configuration') diff --git a/meson_options.txt b/meson_options.txt index c347afa0..1c668231 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -23,6 +23,9 @@ option('libmagic', type : 'feature', value : 'auto', option('python_name', type : 'string', description : 'The name of the Python 3 interpreter to use for generating Python bindings and running tests. If left blank, it defaults to the version of Python 3 being used to run meson.') +option('recursion_limit', type : 'integer', min : 16, value : 64, + description : 'Maximal depth of accepted recusive structures, like mappings in YAML documents.') + option('rpmio', type : 'feature', value : 'enabled', description : 'Use the rpmio library to automatically decompress gzip, bzip2 and xz YAML streams.') diff --git a/modulemd/meson.build b/modulemd/meson.build index e41bcc52..0b87913d 100644 --- a/modulemd/meson.build +++ b/modulemd/meson.build @@ -16,6 +16,7 @@ skip_introspection = get_option('skip_introspection') verbose_tests = get_option('verbose_tests') accept_overflowed_buildorder = get_option('accept_overflowed_buildorder') clang_simple_version_script = find_program ('clang_simple_version.sh') +recursion_limit = get_option('recursion_limit') # -- Library -- # @@ -147,6 +148,7 @@ cdata.set('HAVE_EXTEND_AND_STEAL', has_extend_and_steal) cdata.set('HAVE_G_SPAWN_CHECK_WAIT_STATUS', has_g_spawn_check_wait_status) cdata.set('HAVE_G_TEST_SUBPROCESS_DEFAULT', has_g_test_subprocess_default) cdata.set('HAVE_OVERFLOWED_BUILDORDER', accept_overflowed_buildorder) +cdata.set('LIBMODULEMD_RECURSION_LIMIT', recursion_limit) configure_file( output : 'config.h', configuration : cdata @@ -355,6 +357,7 @@ c_tests = { 'defaults' : [ 'tests/test-modulemd-defaults.c' ], 'defaultsv1' : [ 'tests/test-modulemd-defaults-v1.c' ], 'dependencies' : [ 'tests/test-modulemd-dependencies.c' ], +'limits' : [ 'tests/test-modulemd-limits.c' ], 'module' : [ 'tests/test-modulemd-module.c' ], 'module_index' : [ 'tests/test-modulemd-moduleindex.c' ], 'module_index_merger' : [ 'tests/test-modulemd-merger.c' ], diff --git a/modulemd/modulemd-yaml-util.c b/modulemd/modulemd-yaml-util.c index be5fb566..4c5490d4 100644 --- a/modulemd/modulemd-yaml-util.c +++ b/modulemd/modulemd-yaml-util.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -1085,7 +1086,14 @@ modulemd_yaml_parse_document_type_internal ( { return FALSE; } - depth++; + if (depth == INT_MAX || ++depth > LIBMODULEMD_RECURSION_LIMIT) + { + MMD_YAML_ERROR_EVENT_EXIT_BOOL ( + error, + event, + "YAML document depth limit %d exceeded.", + LIBMODULEMD_RECURSION_LIMIT); + } break; case YAML_SCALAR_EVENT: diff --git a/modulemd/tests/test-modulemd-limits.c b/modulemd/tests/test-modulemd-limits.c new file mode 100644 index 00000000..fc01d82c --- /dev/null +++ b/modulemd/tests/test-modulemd-limits.c @@ -0,0 +1,141 @@ +/* + * This file is part of libmodulemd + * Copyright (C) 2018-2020 Red Hat, Inc. + * + * Fedora-License-Identifier: MIT + * SPDX-2.0-License-Identifier: MIT + * SPDX-3.0-License-Identifier: MIT + * + * This program is free software. + * For more information on the license, see COPYING. + * For more information on free software, see . + */ + +#include +#include +#include + +#include "config.h" +#include "modulemd-subdocument-info.h" +#include "private/modulemd-subdocument-info-private.h" +#include "private/modulemd-yaml.h" + +/* Return a modulemd-stream-v2 document with an xmd tree of @depth depth. + * I.e. the total depth of the YAML document will be @depth + 2. */ +static GString * +build_modulemd_stream_v2_document (int depth) +{ + g_autoptr (GString) string = g_string_new (NULL); + g_string_append (string, + "document: modulemd\n" + "version: 2\n" + "data:\n" + " name: demo\n" + " stream: s\n" + " version: 1\n" + " context: c0\n" + " arch: x86_64\n" + " summary: s\n" + " description: d\n" + " license: { module: [MIT] }\n" + " xmd: {\n"); + g_string_append (string, " "); + for (int i = 1; i < depth; i++) + g_string_append (string, "a: {"); + for (int i = 1; i < depth; i++) + g_string_append (string, "}"); + g_string_append (string, "\n }\n"); + + return g_steal_pointer (&string); +} + + +static void +module_limits_test_parse_document_type_exact (void) +{ + g_autoptr (GString) yaml_string = NULL; + MMD_INIT_YAML_EVENT (event); + MMD_INIT_YAML_PARSER (parser); + int yaml_ret; + g_autoptr (ModulemdSubdocumentInfo) subdoc = NULL; + + /* Build a document with a depth matching, i.e. fitting, the recursion limit. */ + yaml_string = + build_modulemd_stream_v2_document (LIBMODULEMD_RECURSION_LIMIT - 2); + + /* Advance the parser to the first document element */ + yaml_parser_set_input_string ( + &parser, (const unsigned char *)yaml_string->str, yaml_string->len); + /* The first event must be the stream start */ + yaml_ret = yaml_parser_parse (&parser, &event); + g_assert_true (yaml_ret); + g_assert_cmpint (event.type, ==, YAML_STREAM_START_EVENT); + yaml_event_delete (&event); + /* The second event must be the document start */ + yaml_ret = yaml_parser_parse (&parser, &event); + g_assert_true (yaml_ret); + g_assert_cmpint (event.type, ==, YAML_DOCUMENT_START_EVENT); + yaml_event_delete (&event); + + /* Parse it and exhibit the recursion limit */ + subdoc = modulemd_yaml_parse_document_type (&parser); + g_assert_nonnull (subdoc); + g_assert_null (modulemd_subdocument_info_get_gerror (subdoc)); + g_assert_cmpint (modulemd_subdocument_info_get_doctype (subdoc), + ==, + MODULEMD_YAML_DOC_MODULESTREAM); + g_assert_cmpint (modulemd_subdocument_info_get_mdversion (subdoc), ==, 2); + g_assert_nonnull (modulemd_subdocument_info_get_yaml (subdoc)); +} + + +static void +module_limits_test_parse_document_type_oversized (void) +{ + g_autoptr (GString) yaml_string = NULL; + MMD_INIT_YAML_EVENT (event); + MMD_INIT_YAML_PARSER (parser); + int yaml_ret; + g_autoptr (ModulemdSubdocumentInfo) subdoc = NULL; + const GError *error = NULL; + + /* Build a document with a depth exceeding the recursion limit. */ + yaml_string = + build_modulemd_stream_v2_document (LIBMODULEMD_RECURSION_LIMIT - 2 + 1); + + /* Advance the parser to the first document element */ + yaml_parser_set_input_string ( + &parser, (const unsigned char *)yaml_string->str, yaml_string->len); + /* The first event must be the stream start */ + yaml_ret = yaml_parser_parse (&parser, &event); + g_assert_true (yaml_ret); + g_assert_cmpint (event.type, ==, YAML_STREAM_START_EVENT); + yaml_event_delete (&event); + /* The second event must be the document start */ + yaml_ret = yaml_parser_parse (&parser, &event); + g_assert_true (yaml_ret); + g_assert_cmpint (event.type, ==, YAML_DOCUMENT_START_EVENT); + yaml_event_delete (&event); + + /* Parse it and exhibit the recursion limit */ + subdoc = modulemd_yaml_parse_document_type (&parser); + g_assert_nonnull (subdoc); + error = modulemd_subdocument_info_get_gerror (subdoc); + g_assert_error (error, MODULEMD_YAML_ERROR, MMD_YAML_ERROR_PARSE); +} + + +int +main (int argc, char *argv[]) +{ + setlocale (LC_ALL, ""); + g_test_init (&argc, &argv, NULL); + g_test_bug_base ("https://bugzilla.redhat.com/show_bug.cgi?id="); + + g_test_add_func ("/modulemd/v2/limits/parse_document_type/exact", + module_limits_test_parse_document_type_exact); + g_test_add_func ("/modulemd/v2/limits/parse_document_type/oversized", + module_limits_test_parse_document_type_oversized); + + return g_test_run (); +} From a9db6f9819ac8abf5b7238443c69aaa1711168e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= Date: Fri, 11 Sep 2026 14:21:27 +0200 Subject: [PATCH 2/2] Apply a recursion limit to mmd_parse_xmd() This patch is not needed per se because all code paths leading to mmd_parse_xmd() get the YAML XMD tree from a subdocument obtained with modulemd_yaml_parse_document_type() which is already protected by the recursion limit. We apply this patch as a hardening for possible future code paths. As a side effect, this patch fixes propagating errors from mmd_variant_from_mapping() in mmd_parse_xmd(). Acknowledgement: Aisle Research Resolves: CVE-2026-92822 --- modulemd/include/private/modulemd-yaml.h | 6 +- modulemd/modulemd-yaml-util.c | 62 +++++++- modulemd/tests/test-modulemd-limits.c | 178 +++++++++++++++++++++++ 3 files changed, 237 insertions(+), 9 deletions(-) diff --git a/modulemd/include/private/modulemd-yaml.h b/modulemd/include/private/modulemd-yaml.h index 105063b6..10cd31b5 100644 --- a/modulemd/include/private/modulemd-yaml.h +++ b/modulemd/include/private/modulemd-yaml.h @@ -913,6 +913,7 @@ mmd_variant_from_scalar (const gchar *scalar); /** * mmd_variant_from_mapping: * @parser: (inout): A YAML parser positioned just after a `MAPPING_START` + * @depth: Current YAML depth in the XMD document * @error: (out): A #GError that will return the reason for failing to parse. * * Returns: (transfer full): A new, floating #GVariant representing a hash @@ -921,12 +922,13 @@ mmd_variant_from_scalar (const gchar *scalar); * Since: 2.0 */ GVariant * -mmd_variant_from_mapping (yaml_parser_t *parser, GError **error); +mmd_variant_from_mapping (yaml_parser_t *parser, int depth, GError **error); /** * mmd_variant_from_sequence: * @parser: (inout): A YAML parser positioned just after a `SEQUENCE_START` + * @depth: Current YAML depth in the XMD document * @error: (out): A #GError that will return the reason for failing to parse. * * Returns: (transfer full): A new, floating #GVariant representing a list of @@ -935,7 +937,7 @@ mmd_variant_from_mapping (yaml_parser_t *parser, GError **error); * Since: 2.0 */ GVariant * -mmd_variant_from_sequence (yaml_parser_t *parser, GError **error); +mmd_variant_from_sequence (yaml_parser_t *parser, int depth, GError **error); /** diff --git a/modulemd/modulemd-yaml-util.c b/modulemd/modulemd-yaml-util.c index 4c5490d4..47d0bda6 100644 --- a/modulemd/modulemd-yaml-util.c +++ b/modulemd/modulemd-yaml-util.c @@ -1496,7 +1496,7 @@ mmd_variant_from_scalar (const gchar *scalar) GVariant * -mmd_variant_from_mapping (yaml_parser_t *parser, GError **error) +mmd_variant_from_mapping (yaml_parser_t *parser, int depth, GError **error) { MODULEMD_INIT_TRACE (); gboolean done = FALSE; @@ -1540,7 +1540,16 @@ mmd_variant_from_mapping (yaml_parser_t *parser, GError **error) break; case YAML_MAPPING_START_EVENT: - value = mmd_variant_from_mapping (parser, &nested_error); + if (depth == INT_MAX || depth + 1 > LIBMODULEMD_RECURSION_LIMIT) + { + MMD_YAML_ERROR_EVENT_EXIT ( + error, + event, + "XMD YAML document depth limit %d exceeded.", + LIBMODULEMD_RECURSION_LIMIT); + } + value = + mmd_variant_from_mapping (parser, depth + 1, &nested_error); if (!value) { g_propagate_error (error, g_steal_pointer (&nested_error)); @@ -1549,7 +1558,16 @@ mmd_variant_from_mapping (yaml_parser_t *parser, GError **error) break; case YAML_SEQUENCE_START_EVENT: - value = mmd_variant_from_sequence (parser, &nested_error); + if (depth == INT_MAX || depth + 1 > LIBMODULEMD_RECURSION_LIMIT) + { + MMD_YAML_ERROR_EVENT_EXIT ( + error, + event, + "XMD YAML document depth limit %d exceeded.", + LIBMODULEMD_RECURSION_LIMIT); + } + value = + mmd_variant_from_sequence (parser, depth + 1, &nested_error); if (!value) { g_propagate_error (error, g_steal_pointer (&nested_error)); @@ -1590,7 +1608,7 @@ mmd_variant_from_mapping (yaml_parser_t *parser, GError **error) GVariant * -mmd_variant_from_sequence (yaml_parser_t *parser, GError **error) +mmd_variant_from_sequence (yaml_parser_t *parser, int depth, GError **error) { MODULEMD_INIT_TRACE (); gboolean done = FALSE; @@ -1625,7 +1643,15 @@ mmd_variant_from_sequence (yaml_parser_t *parser, GError **error) break; case YAML_MAPPING_START_EVENT: - value = mmd_variant_from_mapping (parser, &nested_error); + if (depth == INT_MAX || depth + 1 > LIBMODULEMD_RECURSION_LIMIT) + { + MMD_YAML_ERROR_EVENT_EXIT ( + error, + event, + "XMD YAML document depth limit %d exceeded.", + LIBMODULEMD_RECURSION_LIMIT); + } + value = mmd_variant_from_mapping (parser, depth + 1, &nested_error); if (!value) { g_propagate_error (error, g_steal_pointer (&nested_error)); @@ -1634,7 +1660,15 @@ mmd_variant_from_sequence (yaml_parser_t *parser, GError **error) break; case YAML_SEQUENCE_START_EVENT: - value = mmd_variant_from_sequence (parser, &nested_error); + if (depth == INT_MAX || depth + 1 > LIBMODULEMD_RECURSION_LIMIT) + { + MMD_YAML_ERROR_EVENT_EXIT ( + error, + event, + "XMD YAML document depth limit %d exceeded.", + LIBMODULEMD_RECURSION_LIMIT); + } + value = mmd_variant_from_sequence (parser, depth + 1, &nested_error); if (!value) { g_propagate_error (error, g_steal_pointer (&nested_error)); @@ -1685,6 +1719,7 @@ mmd_parse_xmd (yaml_parser_t *parser, GError **error) MMD_INIT_YAML_EVENT (event); GVariant *variant = NULL; g_autoptr (GError) nested_error = NULL; + int depth = 0; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); @@ -1702,7 +1737,20 @@ mmd_parse_xmd (yaml_parser_t *parser, GError **error) break; case YAML_MAPPING_START_EVENT: - variant = mmd_variant_from_mapping (parser, &nested_error); + if (depth == INT_MAX || depth + 1 > LIBMODULEMD_RECURSION_LIMIT) + { + MMD_YAML_ERROR_EVENT_EXIT ( + error, + event, + "XMD YAML document depth limit %d exceeded.", + LIBMODULEMD_RECURSION_LIMIT); + } + variant = mmd_variant_from_mapping (parser, depth + 1, &nested_error); + if (!variant) + { + g_propagate_error (error, g_steal_pointer (&nested_error)); + return NULL; + } break; default: diff --git a/modulemd/tests/test-modulemd-limits.c b/modulemd/tests/test-modulemd-limits.c index fc01d82c..56c0c671 100644 --- a/modulemd/tests/test-modulemd-limits.c +++ b/modulemd/tests/test-modulemd-limits.c @@ -125,6 +125,174 @@ module_limits_test_parse_document_type_oversized (void) } +/* Return an XMD YAML document with a mapping of @depth depth. */ +static GString * +build_xmd_mapping_document (int depth) +{ + g_autoptr (GString) string = g_string_new (NULL); + for (int i = 1; i < depth; i++) + g_string_append (string, "a: {"); + for (int i = 1; i < depth; i++) + g_string_append (string, "}"); + g_string_append (string, "\n"); + + return g_steal_pointer (&string); +} + + +static void +module_limits_test_mmd_parse_xmd_mapping_exact (void) +{ + g_autoptr (GString) yaml_string = NULL; + MMD_INIT_YAML_EVENT (event); + MMD_INIT_YAML_PARSER (parser); + int yaml_ret; + g_autoptr (GVariant) xmd = NULL; + g_autoptr (GError) error = NULL; + + /* Build a document with a depth matching, i.e. fitting, the recursion limit. */ + yaml_string = build_xmd_mapping_document (LIBMODULEMD_RECURSION_LIMIT); + + /* Advance the parser to the first document element */ + yaml_parser_set_input_string ( + &parser, (const unsigned char *)yaml_string->str, yaml_string->len); + /* The first event must be the stream start */ + yaml_ret = yaml_parser_parse (&parser, &event); + g_assert_true (yaml_ret); + g_assert_cmpint (event.type, ==, YAML_STREAM_START_EVENT); + yaml_event_delete (&event); + /* The second event must be the document start */ + yaml_ret = yaml_parser_parse (&parser, &event); + g_assert_true (yaml_ret); + g_assert_cmpint (event.type, ==, YAML_DOCUMENT_START_EVENT); + yaml_event_delete (&event); + + /* Parse it and exhibit the recursion limit */ + xmd = mmd_parse_xmd (&parser, &error); + g_assert_nonnull (xmd); + g_assert_null (error); +} + + +static void +module_limits_test_mmd_parse_xmd_mapping_oversized (void) +{ + g_autoptr (GString) yaml_string = NULL; + MMD_INIT_YAML_EVENT (event); + MMD_INIT_YAML_PARSER (parser); + int yaml_ret; + g_autoptr (GVariant) xmd = NULL; + g_autoptr (GError) error = NULL; + + /* Build a document with a depth exceeding the recursion limit. */ + yaml_string = build_xmd_mapping_document (LIBMODULEMD_RECURSION_LIMIT + 1); + + /* Advance the parser to the first document element */ + yaml_parser_set_input_string ( + &parser, (const unsigned char *)yaml_string->str, yaml_string->len); + /* The first event must be the stream start */ + yaml_ret = yaml_parser_parse (&parser, &event); + g_assert_true (yaml_ret); + g_assert_cmpint (event.type, ==, YAML_STREAM_START_EVENT); + yaml_event_delete (&event); + /* The second event must be the document start */ + yaml_ret = yaml_parser_parse (&parser, &event); + g_assert_true (yaml_ret); + g_assert_cmpint (event.type, ==, YAML_DOCUMENT_START_EVENT); + yaml_event_delete (&event); + + /* Parse it and exhibit the recursion limit */ + xmd = mmd_parse_xmd (&parser, &error); + g_assert_null (xmd); + g_assert_error (error, MODULEMD_YAML_ERROR, MMD_YAML_ERROR_PARSE); +} + + +/* Return an XMD YAML document with a recursive sequence of @depth depth. */ +static GString * +build_xmd_sequence_document (int depth) +{ + g_autoptr (GString) string = g_string_new (NULL); + /* mmd_parse_xmd() requires the top-level element to be a mapping. */ + g_string_append (string, "a: "); + for (int i = 1; i < depth; i++) + g_string_append (string, "["); + for (int i = 1; i < depth; i++) + g_string_append (string, "]"); + g_string_append (string, "\n"); + + return g_steal_pointer (&string); +} + + +static void +module_limits_test_mmd_parse_xmd_sequence_exact (void) +{ + g_autoptr (GString) yaml_string = NULL; + MMD_INIT_YAML_EVENT (event); + MMD_INIT_YAML_PARSER (parser); + int yaml_ret; + g_autoptr (GVariant) xmd = NULL; + g_autoptr (GError) error = NULL; + + /* Build a document with a depth matching, i.e. fitting, the recursion limit. */ + yaml_string = build_xmd_sequence_document (LIBMODULEMD_RECURSION_LIMIT); + + /* Advance the parser to the first document element */ + yaml_parser_set_input_string ( + &parser, (const unsigned char *)yaml_string->str, yaml_string->len); + /* The first event must be the stream start */ + yaml_ret = yaml_parser_parse (&parser, &event); + g_assert_true (yaml_ret); + g_assert_cmpint (event.type, ==, YAML_STREAM_START_EVENT); + yaml_event_delete (&event); + /* The second event must be the document start */ + yaml_ret = yaml_parser_parse (&parser, &event); + g_assert_true (yaml_ret); + g_assert_cmpint (event.type, ==, YAML_DOCUMENT_START_EVENT); + yaml_event_delete (&event); + + /* Parse it and exhibit the recursion limit */ + xmd = mmd_parse_xmd (&parser, &error); + g_assert_nonnull (xmd); + g_assert_null (error); +} + + +static void +module_limits_test_mmd_parse_xmd_sequence_oversized (void) +{ + g_autoptr (GString) yaml_string = NULL; + MMD_INIT_YAML_EVENT (event); + MMD_INIT_YAML_PARSER (parser); + int yaml_ret; + g_autoptr (GVariant) xmd = NULL; + g_autoptr (GError) error = NULL; + + /* Build a document with a depth matching, i.e. fitting, the recursion limit. */ + yaml_string = build_xmd_sequence_document (LIBMODULEMD_RECURSION_LIMIT + 1); + + /* Advance the parser to the first document element */ + yaml_parser_set_input_string ( + &parser, (const unsigned char *)yaml_string->str, yaml_string->len); + /* The first event must be the stream start */ + yaml_ret = yaml_parser_parse (&parser, &event); + g_assert_true (yaml_ret); + g_assert_cmpint (event.type, ==, YAML_STREAM_START_EVENT); + yaml_event_delete (&event); + /* The second event must be the document start */ + yaml_ret = yaml_parser_parse (&parser, &event); + g_assert_true (yaml_ret); + g_assert_cmpint (event.type, ==, YAML_DOCUMENT_START_EVENT); + yaml_event_delete (&event); + + /* Parse it and exhibit the recursion limit */ + xmd = mmd_parse_xmd (&parser, &error); + g_assert_null (xmd); + g_assert_error (error, MODULEMD_YAML_ERROR, MMD_YAML_ERROR_PARSE); +} + + int main (int argc, char *argv[]) { @@ -137,5 +305,15 @@ main (int argc, char *argv[]) g_test_add_func ("/modulemd/v2/limits/parse_document_type/oversized", module_limits_test_parse_document_type_oversized); + g_test_add_func ("/modulemd/v2/limits/mmd_parse_xmd/mapping/exact", + module_limits_test_mmd_parse_xmd_mapping_exact); + g_test_add_func ("/modulemd/v2/limits/mmd_parse_xmd/mapping/oversized", + module_limits_test_mmd_parse_xmd_mapping_oversized); + + g_test_add_func ("/modulemd/v2/limits/mmd_parse_xmd/sequence/exact", + module_limits_test_mmd_parse_xmd_sequence_exact); + g_test_add_func ("/modulemd/v2/limits/mmd_parse_xmd/sequence/oversized", + module_limits_test_mmd_parse_xmd_sequence_oversized); + return g_test_run (); }