From f90f02bfa2d31f56b25238d750c4746d964aea42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= Date: Tue, 26 Nov 2019 13:52:36 +0100 Subject: [PATCH 1/2] Show check identifiers at multi-check rules Shows OVAL Definition ID and Title when an XCCDF rule uses multi-check='true'. The multi-check is used in rule security_patches_up_to_date in SCAP 1.3 datastreams. It wasn't possible to see which vulnerabilities have been found because all the checks have the same XCCDF rule ID. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1771438 Fixes: #1320 --- src/OVAL/oval_agent.c | 35 ++++++++++---- src/XCCDF_POLICY/public/xccdf_policy.h | 18 ++++++- src/XCCDF_POLICY/xccdf_policy.c | 48 +++++++++++-------- src/XCCDF_POLICY/xccdf_policy_engine.c | 4 +- src/XCCDF_POLICY/xccdf_policy_engine_priv.h | 2 +- src/XCCDF_POLICY/xccdf_policy_model_priv.h | 1 + ...eck_content_ref_without_name_attr.oval.xml | 4 +- .../test_xccdf_check_multi_check2.sh | 6 +++ .../test_xccdf_check_multi_check2.xccdf.xml | 1 + utils/oscap-xccdf.c | 8 ++++ 10 files changed, 92 insertions(+), 35 deletions(-) diff --git a/src/OVAL/oval_agent.c b/src/OVAL/oval_agent.c index a962fe379..986295bf6 100644 --- a/src/OVAL/oval_agent.c +++ b/src/OVAL/oval_agent.c @@ -593,19 +593,34 @@ _oval_agent_list_definitions(void *usr, xccdf_policy_engine_query_t query_type, { __attribute__nonnull__(usr); struct oval_agent_session *sess = (struct oval_agent_session *) usr; - if (query_type != POLICY_ENGINE_QUERY_NAMES_FOR_HREF || (query_data != NULL && strcmp(sess->filename, (const char *) query_data))) + if (query_data != NULL && strcmp(sess->filename, (const char *) query_data)) { return NULL; - struct oval_definition_iterator *iterator = oval_definition_model_get_definitions(sess->def_model); - struct oscap_stringlist *result = oscap_stringlist_new(); - struct oval_definition *oval_def; - - while (oval_definition_iterator_has_more(iterator)) { - oval_def = oval_definition_iterator_next(iterator); - oscap_stringlist_add_string(result, oval_definition_get_id(oval_def)); } + if (query_type == POLICY_ENGINE_QUERY_NAMES_FOR_HREF) { + struct oval_definition_iterator *iterator = oval_definition_model_get_definitions(sess->def_model); + struct oscap_stringlist *result = oscap_stringlist_new(); + + while (oval_definition_iterator_has_more(iterator)) { + struct oval_definition *oval_def = oval_definition_iterator_next(iterator); + oscap_stringlist_add_string(result, oval_definition_get_id(oval_def)); + } + + oval_definition_iterator_free(iterator); + return result; + } else if (query_type == POLICY_ENGINE_QUERY_OVAL_DEFS_FOR_HREF) { + struct oval_definition_iterator *iterator = oval_definition_model_get_definitions(sess->def_model); + struct oscap_list *result = oscap_list_new(); - oval_definition_iterator_free(iterator); - return result; + while (oval_definition_iterator_has_more(iterator)) { + struct oval_definition *oval_def = oval_definition_iterator_next(iterator); + oscap_list_add(result, oval_def); + } + + oval_definition_iterator_free(iterator); + return result; + } else { + return NULL; + } } bool xccdf_policy_model_register_engine_oval(struct xccdf_policy_model * model, struct oval_agent_session * usr) diff --git a/src/SCE/Makefile.am b/src/SCE/Makefile.am index 0c90c6da0..5849cf1a0 100644 --- a/src/SCE/Makefile.am +++ b/src/SCE/Makefile.am @@ -12,7 +12,8 @@ AM_CPPFLAGS = @xml2_CFLAGS@ \ -I$(top_srcdir)/src/source/public \ -I$(top_srcdir)/src/XCCDF_POLICY/public \ -I$(top_srcdir)/src/XCCDF/public \ - -I$(top_srcdir)/src/CPE/public + -I$(top_srcdir)/src/CPE/public \ + -I$(top_srcdir)/src/OVAL/public AM_LDFLAGS = @xml2_LIBS@ diff --git a/src/XCCDF_POLICY/public/xccdf_policy.h b/src/XCCDF_POLICY/public/xccdf_policy.h index aa2525e2b..5e85c476c 100644 --- a/src/XCCDF_POLICY/public/xccdf_policy.h +++ b/src/XCCDF_POLICY/public/xccdf_policy.h @@ -35,6 +35,7 @@ #include #include #include +#include "oval_definitions.h" /** * @struct xccdf_policy_model @@ -69,6 +70,7 @@ struct xccdf_policy_iterator; */ typedef enum { POLICY_ENGINE_QUERY_NAMES_FOR_HREF = 1, /// Considering xccdf:check-content-ref, what are possible @name attributes for given href? + POLICY_ENGINE_QUERY_OVAL_DEFS_FOR_HREF = 2, /// Considering xccdf:check-content-ref, what are OVAL definitions for given href? } xccdf_policy_engine_query_t; /** @@ -80,9 +82,11 @@ typedef enum { * is always user data as registered. Second argument defines the query. Third argument is * dependent on query and defined as follows: * - (const char *)href -- for POLICY_ENGINE_QUERY_NAMES_FOR_HREF + * - (const char *)href -- for POLICY_ENGINE_QUERY_OVAL_DEFS_FOR_HREF * * Expected return type depends also on query as follows: - * - (struct oscap_stringlists *) -- for POLICY_ENGINE_QUERY_NAMES_FOR_HREF + * - (struct oscap_stringlist *) -- for POLICY_ENGINE_QUERY_NAMES_FOR_HREF + * - (struct oscap_list *) -- for POLICY_ENGINE_QUERY_OVAL_DEFS_FOR_HREF * - NULL shall be returned if the function doesn't understand the query. */ typedef void *(*xccdf_policy_engine_query_fn) (void *, xccdf_policy_engine_query_t, void *); @@ -289,6 +293,19 @@ typedef int (*policy_reporter_start)(struct xccdf_rule *, void *); */ bool xccdf_policy_model_register_start_callback(struct xccdf_policy_model * model, policy_reporter_start func, void * usr); +typedef int (*policy_reporter_multicheck)(struct oval_definition*, void *); +/** + * Function to register callback for checking system that will be called + * DURING each rule evaluation if rule sets multi-check="true". + * @param model XCCDF Policy Model + * @param func Callback - pointer to function called by XCCDF Policy system when rule parsed + * @param usr optional parameter for passing user data to callback + * @memberof xccdf_policy_model + * @return true if callback registered successfully, false otherwise + */ +bool xccdf_policy_model_register_multicheck_callback(struct xccdf_policy_model *model, policy_reporter_multicheck func, void *usr); + + /************************************************************/ /** * @name Getters diff --git a/src/XCCDF_POLICY/xccdf_policy.c b/src/XCCDF_POLICY/xccdf_policy.c index b406d7f59..079395c85 100644 --- a/src/XCCDF_POLICY/xccdf_policy.c +++ b/src/XCCDF_POLICY/xccdf_policy.c @@ -378,20 +378,19 @@ xccdf_policy_evaluate_cb(struct xccdf_policy * policy, const char * sysname, con } /** - * Find all posible names for given check-content-ref/@href, considering also the check/@system. - * This is usefull for multi-check="true" feature. - * @return list of names (even empty) if the given href found, NULL otherwise. + * Find all possible names for given check-content-ref/@href, considering also the check/@system. + * This is useful for multi-check="true" feature. + * @return list of OVAL definitions if the given href found, NULL otherwise. */ -static struct oscap_stringlist * -_xccdf_policy_get_namesfor_href(struct xccdf_policy *policy, const char *sysname, const char *href) +static struct oscap_list *_xccdf_policy_get_oval_definitions_for_href(struct xccdf_policy *policy, const char *sysname, const char *href) { struct oscap_iterator *cb_it = _xccdf_policy_get_engines_by_sysname(policy, sysname); - struct oscap_stringlist *result = NULL; + struct oscap_list *result = NULL; while (oscap_iterator_has_more(cb_it) && result == NULL) { struct xccdf_policy_engine *engine = (struct xccdf_policy_engine *) oscap_iterator_next(cb_it); if (engine == NULL) break; - result = xccdf_policy_engine_query(engine, POLICY_ENGINE_QUERY_NAMES_FOR_HREF, (void *) href); + result = xccdf_policy_engine_query(engine, POLICY_ENGINE_QUERY_OVAL_DEFS_FOR_HREF, (void *) href); } oscap_iterator_free(cb_it); return result; @@ -1047,24 +1046,27 @@ _xccdf_policy_rule_evaluate(struct xccdf_policy * policy, const struct xccdf_rul if (content_name == NULL && xccdf_check_get_multicheck(check)) { // parent element is Rule, @multi-check is required - struct oscap_stringlist *names = _xccdf_policy_get_namesfor_href(policy, system_name, href); - if (names != NULL) { + struct oscap_list *oval_definition_list = _xccdf_policy_get_oval_definitions_for_href(policy, system_name, href); + if (oval_definition_list != NULL) { // multi-check is supported by checking-engine - struct oscap_string_iterator *name_it = oscap_stringlist_get_strings(names); - if (!oscap_string_iterator_has_more(name_it)) { + struct oscap_iterator *oval_definition_iterator = oscap_iterator_new(oval_definition_list); + if (!oscap_iterator_has_more(oval_definition_iterator)) { // Super special case when oval file contains no definitions // thus multi-check shall yield zero rule-results. report = _xccdf_policy_report_rule_result(policy, result, rule, check, XCCDF_RESULT_UNKNOWN, "No definitions found for @multi-check."); - oscap_string_iterator_free(name_it); - oscap_stringlist_free(names); + oscap_iterator_free(oval_definition_iterator); + oscap_list_free(oval_definition_list, NULL); xccdf_check_content_ref_iterator_free(content_it); oscap_list_free(bindings, (oscap_destruct_func) xccdf_value_binding_free); return report; } - while (oscap_string_iterator_has_more(name_it)) { - const char *name = oscap_string_iterator_next(name_it); + while (oscap_iterator_has_more(oval_definition_iterator)) { + struct oval_definition *oval_definition = oscap_iterator_next(oval_definition_iterator); + if ((report = xccdf_policy_report_cb(policy, XCCDF_POLICY_OUTCB_MULTICHECK, (void *) oval_definition)) != 0) { + break; + } struct xccdf_check *cloned_check = xccdf_check_clone(check); - xccdf_check_inject_content_ref(cloned_check, content, name); + xccdf_check_inject_content_ref(cloned_check, content, oval_definition_get_id(oval_definition)); int inner_ret = xccdf_policy_check_evaluate(policy, cloned_check); if (inner_ret == -1) { xccdf_check_free(cloned_check); @@ -1073,12 +1075,13 @@ _xccdf_policy_rule_evaluate(struct xccdf_policy * policy, const struct xccdf_rul } if ((report = _xccdf_policy_report_rule_result(policy, result, rule, cloned_check, inner_ret, NULL)) != 0) break; - if (oscap_string_iterator_has_more(name_it)) + if (oscap_iterator_has_more(oval_definition_iterator)) { if ((report = xccdf_policy_report_cb(policy, XCCDF_POLICY_OUTCB_START, (void *) rule)) != 0) break; + } } - oscap_string_iterator_free(name_it); - oscap_stringlist_free(names); + oscap_iterator_free(oval_definition_iterator); + oscap_list_free(oval_definition_list, NULL); xccdf_check_content_ref_iterator_free(content_it); oscap_list_free(bindings, (oscap_destruct_func) xccdf_value_binding_free); xccdf_check_free(check); @@ -1629,6 +1632,13 @@ bool xccdf_policy_model_register_output_callback(struct xccdf_policy_model * mod return oscap_list_add(model->callbacks, reporter); } +bool xccdf_policy_model_register_multicheck_callback(struct xccdf_policy_model *model, policy_reporter_multicheck func, void *usr) +{ + __attribute__nonnull__(model); + struct reporter *reporter = reporter_new(XCCDF_POLICY_OUTCB_MULTICHECK, func, usr); + return oscap_list_add(model->callbacks, reporter); +} + struct xccdf_result * xccdf_policy_get_result_by_id(struct xccdf_policy * policy, const char * id) { struct xccdf_result_iterator * result_it; diff --git a/src/XCCDF_POLICY/xccdf_policy_engine.c b/src/XCCDF_POLICY/xccdf_policy_engine.c index 5e0a2b6b0..3529dd1b6 100644 --- a/src/XCCDF_POLICY/xccdf_policy_engine.c +++ b/src/XCCDF_POLICY/xccdf_policy_engine.c @@ -69,9 +69,9 @@ xccdf_test_result_type_t xccdf_policy_engine_eval(struct xccdf_policy_engine *en return ret; } -struct oscap_stringlist *xccdf_policy_engine_query(struct xccdf_policy_engine *engine, xccdf_policy_engine_query_t query_type, void *query_data) +struct oscap_list *xccdf_policy_engine_query(struct xccdf_policy_engine *engine, xccdf_policy_engine_query_t query_type, void *query_data) { if (engine->query_fn == NULL) return NULL; - return (struct oscap_stringlist *) engine->query_fn(engine->usr, query_type, query_data); + return (struct oscap_list *) engine->query_fn(engine->usr, query_type, query_data); } diff --git a/src/XCCDF_POLICY/xccdf_policy_engine_priv.h b/src/XCCDF_POLICY/xccdf_policy_engine_priv.h index cdcb49613..bcf758b2e 100644 --- a/src/XCCDF_POLICY/xccdf_policy_engine_priv.h +++ b/src/XCCDF_POLICY/xccdf_policy_engine_priv.h @@ -75,7 +75,7 @@ xccdf_test_result_type_t xccdf_policy_engine_eval(struct xccdf_policy_engine *en * @param query_data Additional data for the checking engine query. * @returns list of query results */ -struct oscap_stringlist *xccdf_policy_engine_query(struct xccdf_policy_engine *engine, xccdf_policy_engine_query_t query_type, void *query_data); +struct oscap_list *xccdf_policy_engine_query(struct xccdf_policy_engine *engine, xccdf_policy_engine_query_t query_type, void *query_data); OSCAP_HIDDEN_END; diff --git a/src/XCCDF_POLICY/xccdf_policy_model_priv.h b/src/XCCDF_POLICY/xccdf_policy_model_priv.h index c5223a7b8..8f503ef46 100644 --- a/src/XCCDF_POLICY/xccdf_policy_model_priv.h +++ b/src/XCCDF_POLICY/xccdf_policy_model_priv.h @@ -33,6 +33,7 @@ OSCAP_HIDDEN_START; #define XCCDF_POLICY_OUTCB_START "urn:xccdf:system:callback:start" #define XCCDF_POLICY_OUTCB_END "urn:xccdf:system:callback:output" +#define XCCDF_POLICY_OUTCB_MULTICHECK "urn:xccdf:system:callback:multicheck" /** * Remove checking engines with given system from xccdf_policy_model diff --git a/tests/API/XCCDF/unittests/test_xccdf_check_content_ref_without_name_attr.oval.xml b/tests/API/XCCDF/unittests/test_xccdf_check_content_ref_without_name_attr.oval.xml index 6d4868686..6efdb2f1c 100644 --- a/tests/API/XCCDF/unittests/test_xccdf_check_content_ref_without_name_attr.oval.xml +++ b/tests/API/XCCDF/unittests/test_xccdf_check_content_ref_without_name_attr.oval.xml @@ -17,11 +17,11 @@ - PASSBla. + DEFINITION_1_TITLE_EXPECTED_PASSBla. - FAILBla. + DEFINITION_2_TITLE_EXPECTED_FAILBla. diff --git a/tests/API/XCCDF/unittests/test_xccdf_check_multi_check2.sh b/tests/API/XCCDF/unittests/test_xccdf_check_multi_check2.sh index d5991aa0f..2c45ad0a3 100755 --- a/tests/API/XCCDF/unittests/test_xccdf_check_multi_check2.sh +++ b/tests/API/XCCDF/unittests/test_xccdf_check_multi_check2.sh @@ -17,6 +17,12 @@ echo "Result file = $result" [ -f $stderr ]; [ ! -s $stderr ]; rm $stderr grep '^Result.*pass$' $stdout grep '^Result.*fail$' $stdout +[ $(grep -c '^Rule.*xccdf_moc.elpmaxe.www_rule_1' $stdout) == 2 ] +[ $(grep -c '^Title.*The only rule in this benchmark' $stdout) == 2 ] +grep '^OVAL Definition ID.*oval:moc.elpmaxe.www:def:1$' $stdout +grep '^OVAL Definition Title.*DEFINITION_1_TITLE_EXPECTED_PASS$' $stdout +grep '^OVAL Definition ID.*oval:moc.elpmaxe.www:def:2$' $stdout +grep '^OVAL Definition Title.*DEFINITION_2_TITLE_EXPECTED_FAIL$' $stdout rm $stdout $OSCAP xccdf validate-xml $result diff --git a/tests/API/XCCDF/unittests/test_xccdf_check_multi_check2.xccdf.xml b/tests/API/XCCDF/unittests/test_xccdf_check_multi_check2.xccdf.xml index 44dc4de49..1c87b9d51 100644 --- a/tests/API/XCCDF/unittests/test_xccdf_check_multi_check2.xccdf.xml +++ b/tests/API/XCCDF/unittests/test_xccdf_check_multi_check2.xccdf.xml @@ -3,6 +3,7 @@ incomplete 1.0 + The only rule in this benchmark diff --git a/utils/oscap-xccdf.c b/utils/oscap-xccdf.c index 19ffc0859..59cd7bcf2 100644 --- a/utils/oscap-xccdf.c +++ b/utils/oscap-xccdf.c @@ -392,6 +392,13 @@ static int callback_scr_result_progress(struct xccdf_rule_result *rule_result, v return 0; } +static int callback_scr_multicheck(struct oval_definition *definition, void *arg) +{ + printf("OVAL Definition ID\t%s\n", oval_definition_get_id(definition)); + printf("OVAL Definition Title\t%s\n", oval_definition_get_title(definition)); + return 0; +} + /* * Send XCCDF Rule Results info message to syslog * @@ -434,6 +441,7 @@ static void _register_progress_callback(struct xccdf_session *session, bool prog xccdf_policy_model_register_start_callback(policy_model, callback_scr_rule, (void *) xccdf_session_get_xccdf_policy(session)); xccdf_policy_model_register_output_callback(policy_model, callback_scr_result, NULL); + xccdf_policy_model_register_multicheck_callback(policy_model, callback_scr_multicheck, NULL); } /* xccdf_policy_model_register_output_callback(policy_model, callback_syslog_result, NULL); */ } diff --git a/xsl/xccdf-report-impl.xsl b/xsl/xccdf-report-impl.xsl index cc76a56cc..ba07b0a90 100644 --- a/xsl/xccdf-report-impl.xsl +++ b/xsl/xccdf-report-impl.xsl @@ -346,19 +346,14 @@ Authors: } - - - - - - - - - - - - - + + + + + + + + @@ -371,18 +366,26 @@ Authors: rule-overview-leaf rule-overview-leaf- rule-overview-needs-attention - - - - - - + + + + + + + - + + () + +  waived - + + + + + @@ -394,7 +397,31 @@ Authors: - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -718,179 +745,212 @@ Authors: - - + + + + - - - - -
-
- This allows OpenSCAP JS to search the report rules - - - - - - - - - - - - - -
-
-

- + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - -
Rule ID
Result + + + + + +
+ +
+
Multi-check rule + + yes + no + +
OVAL Definition ID + +
Time
Severity
Identifiers and References + + - - - - -
- - - - - + + - - - - - - - - + + + + + + + + + - - - + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + +
Rule ID
Result - - - - - -
- +
+ + + +
+ This rule has been waived by at . +
+ +
+ + The previous result was   . +
-
Time
Severity
Identifiers and References - - - - -
- - - -
- This rule has been waived by at . -
- -
- - The previous result was   . - -
-
-
Description
-

- - + +

Description
+

+ + + + + +

+
Rationale
+

+ + + + + +

+
Warnings + +
+
+ warning  + -

-
Rationale
-

- - +

+ + +
+ +
+ Evaluation messages +
+
+ + +   + +

                                     
                                     
-                                
-                            

-
Warnings - -
-
- warning  - - - - -
-
+
-
+ + + + + + +
+ + + + + - +
+ - -
- -
- Evaluation messages -
-
- - -   - -

-                                            
-                                            
-                                        
-
-
-
-
- - - - - - -
- - - - - - -
-

-
-
+ + + + + + + + + +
+
+ This allows OpenSCAP JS to search the report rules + + + + + + + + + + + + + +
+
+

+ + + + + +

+
+
+ + + + + + +
+
+
+