From 866aeaaacc6b74953a2db1f3962c7f80bd8958cb Mon Sep 17 00:00:00 2001 From: Mohit Date: Tue, 20 Oct 2026 19:43:13 +0530 Subject: [PATCH] Evaluate OVAL state with no entities as true According to the OVAL specification, child entities in state elements have minOccurs=0. A state without any entities imposes no conditions; therefore, any collected system item vacuously satisfies it. Previously, eval_item() in oval_resultTest.c would iterate over an empty list of state contents, leaving the results structure empty. It then passed this empty set to ores_get_result_byopr(), which mapped it to OVAL_RESULT_UNKNOWN. This caused a critical false negative with Canonical's Ubuntu OVAL feeds, which define singleton family_states with no child entities. Because the inventory check evaluated to unknown, every Ubuntu Security Notice (USN) extending that inventory definition failed to evaluate to true, reporting zero vulnerabilities and exiting cleanly with code 0. This patch detects when an OVAL state contains no entities and immediately returns OVAL_RESULT_TRUE. Also adds a regression test suite covering entity-less states and Ubuntu applicability check patterns. Fixes #2396 --- src/OVAL/results/oval_resultTest.c | 11 ++ tests/API/OVAL/unittests/CMakeLists.txt | 1 + tests/API/OVAL/unittests/empty_state.xml | 101 +++++++++++++++++++ tests/API/OVAL/unittests/test_empty_state.sh | 28 +++++ 4 files changed, 141 insertions(+) create mode 100644 tests/API/OVAL/unittests/empty_state.xml create mode 100755 tests/API/OVAL/unittests/test_empty_state.sh diff --git a/src/OVAL/results/oval_resultTest.c b/src/OVAL/results/oval_resultTest.c index a937156844..5e9b4e5009 100644 --- a/src/OVAL/results/oval_resultTest.c +++ b/src/OVAL/results/oval_resultTest.c @@ -564,6 +564,17 @@ static oval_result_t eval_item(struct oval_syschar_model *syschar_model, struct ores_clear(&ste_ores); state_contents_itr = oval_state_get_contents(state); + if (!oval_state_content_iterator_has_more(state_contents_itr)) { + /* An OVAL state with no entities imposes no constraints; + * any item satisfies it (evaluates to true). */ + oval_state_content_iterator_free(state_contents_itr); + result = OVAL_RESULT_TRUE; + dI("State '%s' has no entities. Item '%s' satisfies state with result %s.", + oval_state_get_id(state), oval_sysitem_get_id(cur_sysitem), + oval_result_get_text(result)); + return result; + } + while (oval_state_content_iterator_has_more(state_contents_itr)) { struct oval_state_content *content; struct oval_entity *state_entity; diff --git a/tests/API/OVAL/unittests/CMakeLists.txt b/tests/API/OVAL/unittests/CMakeLists.txt index 99052ef739..b09d953fb3 100644 --- a/tests/API/OVAL/unittests/CMakeLists.txt +++ b/tests/API/OVAL/unittests/CMakeLists.txt @@ -10,6 +10,7 @@ add_oscap_test("test_debian_evr_string_missing_epoch.sh") add_oscap_test("test_deprecated_def.sh") add_oscap_test("test_directives.sh") add_oscap_test("test_empty_filename.sh") +add_oscap_test("test_empty_state.sh") add_oscap_test("test_envvar_insensitive_equals.sh") add_oscap_test("test_evr_string_comparison.sh") add_oscap_test("test_evr_string_missing_epoch.sh") diff --git a/tests/API/OVAL/unittests/empty_state.xml b/tests/API/OVAL/unittests/empty_state.xml new file mode 100644 index 0000000000..4e5cd16054 --- /dev/null +++ b/tests/API/OVAL/unittests/empty_state.xml @@ -0,0 +1,101 @@ + + + + 5.11.1 + 2026-10-20T00:00:00+00:00 + + + + + + + Empty state evaluation test + Verify that a state with no entities evaluates to true + + all + + + + + + + + + + + Empty state with OR operator test + Verify that an empty state with operator OR evaluates to true + + all + + + + + + + + + + + Applicability check with empty state + Verify extend_definition using inventory definition with empty state + + all + + + + + + + + + + + + Empty state with non-existent object + Verify that non-existent object still fails check_existence + + all + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /openscap_nonexistent_test_file_path_xyz + + + + + + + + + + + + + + diff --git a/tests/API/OVAL/unittests/test_empty_state.sh b/tests/API/OVAL/unittests/test_empty_state.sh new file mode 100755 index 0000000000..016748117f --- /dev/null +++ b/tests/API/OVAL/unittests/test_empty_state.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +. $builddir/tests/test_common.sh + +result=`mktemp` + +set -e +set -o pipefail + +$OSCAP oval eval --results $result $srcdir/empty_state.xml + +# Definition 1: State with no entities (default AND operator) must evaluate to true +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:1" and @result="true"]' +assert_exists 1 '/oval_results/results/system/tests/test[@test_id="oval:x:tst:1" and @result="true"]' +assert_exists 1 '/oval_results/results/system/tests/test[@test_id="oval:x:tst:1"]/tested_item[@result="true"]' + +# Definition 2: State with no entities and OR operator must evaluate to true +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:2" and @result="true"]' +assert_exists 1 '/oval_results/results/system/tests/test[@test_id="oval:x:tst:2" and @result="true"]' +assert_exists 1 '/oval_results/results/system/tests/test[@test_id="oval:x:tst:2"]/tested_item[@result="true"]' + +# Definition 3: Extended definition applicability check (Ubuntu USN pattern) must evaluate to true +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:3" and @result="true"]' + +# Definition 4: Non-existent item must still evaluate to false even when state has no entities +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:4" and @result="false"]' +assert_exists 1 '/oval_results/results/system/tests/test[@test_id="oval:x:tst:3" and @result="false"]' + +rm $result