From b8dcde269fb97a021b44b2c54a823a50f3d8982c Mon Sep 17 00:00:00 2001 From: Evgeny Kolesnikov Date: Wed, 15 Jul 2020 14:46:06 +0200 Subject: [PATCH 1/8] OVAL: Fix evaluation of field entries in records Add proper evaluation implementation for operation, var_check and var_ref attributes in the field entry of a record. --- src/OVAL/results/oval_cmp.c | 6 ---- src/OVAL/results/oval_cmp_impl.h | 10 ------- src/OVAL/results/oval_resultTest.c | 44 +++++++++++++++++++----------- 3 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/OVAL/results/oval_cmp.c b/src/OVAL/results/oval_cmp.c index 39e1f59e5..585332223 100644 --- a/src/OVAL/results/oval_cmp.c +++ b/src/OVAL/results/oval_cmp.c @@ -161,9 +161,3 @@ oval_result_t oval_str_cmp_str(char *state_data, oval_datatype_t state_data_type oscap_seterr(OSCAP_EFAMILY_OVAL, "Invalid OVAL data type: %d.", state_data_type); return OVAL_RESULT_ERROR; } - -oval_result_t oval_ent_cmp_str(char *state_data, oval_datatype_t state_data_type, struct oval_sysent *sysent, oval_operation_t operation) -{ - const char *sys_data = oval_sysent_get_value(sysent); - return oval_str_cmp_str(state_data, state_data_type, sys_data, operation); -} diff --git a/src/OVAL/results/oval_cmp_impl.h b/src/OVAL/results/oval_cmp_impl.h index 4e38810f5..01014763b 100644 --- a/src/OVAL/results/oval_cmp_impl.h +++ b/src/OVAL/results/oval_cmp_impl.h @@ -29,16 +29,6 @@ #include "oval_system_characteristics.h" -/** - * Compare state entity (or variable/value) to sysent object collected from system. - * This function does not support @datatype="record". - * @param state_value Value defined within state/entity/value or variable/value - * @param sysent Value collected from system - * @operation Comparison type operation - * @returns OVAL Result of comparison - */ -oval_result_t oval_ent_cmp_str(char *state_data, oval_datatype_t state_data_type, struct oval_sysent *sysent, oval_operation_t operation); - /** * Compare state entity (or variable/value) to data collected from system. * This function does not support @datatype="record". diff --git a/src/OVAL/results/oval_resultTest.c b/src/OVAL/results/oval_resultTest.c index b52b845ac..38477cb3b 100644 --- a/src/OVAL/results/oval_resultTest.c +++ b/src/OVAL/results/oval_resultTest.c @@ -381,17 +381,11 @@ oval_result_t ores_get_result_byopr(struct oresults *ores, oval_operator_t op) return result; } -static inline oval_result_t _evaluate_sysent_with_variable(struct oval_syschar_model *syschar_model, struct oval_entity *state_entity, struct oval_sysent *item_entity, oval_operation_t state_entity_operation, struct oval_state_content *content) +static inline oval_result_t _evaluate_sysent_with_variable(struct oval_syschar_model *syschar_model, struct oval_variable *state_entity_var, const char *sys_data, oval_operation_t state_entity_operation, oval_check_t var_check) { oval_syschar_collection_flag_t flag; oval_result_t ent_val_res; - struct oval_variable *state_entity_var; - if ((state_entity_var = oval_entity_get_variable(state_entity)) == NULL) { - oscap_seterr(OSCAP_EFAMILY_OVAL, "OVAL internal error: found NULL variable"); - return -1; - } - if (0 != oval_syschar_model_compute_variable(syschar_model, state_entity_var)) { return -1; } @@ -420,16 +414,15 @@ static inline oval_result_t _evaluate_sysent_with_variable(struct oval_syschar_m } oval_datatype_t state_entity_val_datatype = oval_value_get_datatype(var_val); - var_val_res = oval_ent_cmp_str(state_entity_val_text, state_entity_val_datatype, item_entity, state_entity_operation); + var_val_res = oval_str_cmp_str(state_entity_val_text, state_entity_val_datatype, sys_data, state_entity_operation); if (var_val_res == OVAL_RESULT_ERROR) { dE("Error occured when comparing a variable '%s' value '%s' with collected item entity = '%s'", - oval_variable_get_id(state_entity_var), state_entity_val_text, oval_sysent_get_value(item_entity)); + oval_variable_get_id(state_entity_var), state_entity_val_text, sys_data); } ores_add_res(&var_ores, var_val_res); } oval_value_iterator_free(val_itr); - oval_check_t var_check = oval_state_content_get_var_check(content); ent_val_res = ores_get_result_bychk(&var_ores, var_check); } break; case SYSCHAR_FLAG_ERROR: @@ -450,6 +443,9 @@ struct record_field_instance { char *value; oval_datatype_t data_type; oval_check_t ent_check; + oval_operation_t operation; + struct oval_variable *var; + oval_check_t var_check; }; static struct record_field_instance _oval_record_field_iterator_next_instance(struct oval_record_field_iterator *iterator) @@ -461,11 +457,14 @@ static struct record_field_instance _oval_record_field_iterator_next_instance(st instance.data_type = oval_record_field_get_datatype(rf); if (oval_record_field_get_type(rf) == OVAL_RECORD_FIELD_STATE) { instance.ent_check = oval_record_field_get_ent_check(rf); + instance.operation = oval_record_field_get_operation(rf); } + instance.var = oval_record_field_get_variable(rf); + instance.var_check = oval_record_field_get_var_check(rf); return instance; } -static oval_result_t _evaluate_sysent_record(struct oval_state_content *state_content, struct oval_sysent *item_entity) +static oval_result_t _evaluate_sysent_record(struct oval_syschar_model *syschar_model, struct oval_state_content *state_content, struct oval_sysent *item_entity) { struct oresults record_ores; ores_clear(&record_ores); @@ -485,7 +484,12 @@ static oval_result_t _evaluate_sysent_record(struct oval_state_content *state_co struct record_field_instance item_rf = _oval_record_field_iterator_next_instance(item_it); if (strcmp(state_rf.name, item_rf.name) == 0) { field_found = true; - oval_result_t fields_comparison_result = oval_str_cmp_str(state_rf.value, state_rf.data_type, item_rf.value, OVAL_OPERATION_EQUALS); + oval_result_t fields_comparison_result; + if (state_rf.var != NULL) { + fields_comparison_result = _evaluate_sysent_with_variable(syschar_model, state_rf.var, item_rf.value, state_rf.operation, state_rf.var_check); + } else { + fields_comparison_result = oval_str_cmp_str(state_rf.value, state_rf.data_type, item_rf.value, state_rf.operation); + } ores_add_res(&field_ores, fields_comparison_result); } } @@ -510,10 +514,17 @@ static inline oval_result_t _evaluate_sysent(struct oval_syschar_model *syschar_ if (oval_sysent_get_status(item_entity) == SYSCHAR_STATUS_DOES_NOT_EXIST) { return OVAL_RESULT_FALSE; } else if (oval_entity_get_varref_type(state_entity) == OVAL_ENTITY_VARREF_ATTRIBUTE) { + struct oval_variable *state_entity_var; + if ((state_entity_var = oval_entity_get_variable(state_entity)) == NULL) { + oscap_seterr(OSCAP_EFAMILY_OVAL, "OVAL internal error: found NULL variable"); + return -1; + } + const char *sys_data = oval_sysent_get_value(item_entity); + oval_check_t var_check = oval_state_content_get_var_check(content); return _evaluate_sysent_with_variable(syschar_model, - state_entity, item_entity, - state_entity_operation, content); + state_entity_var, sys_data, + state_entity_operation, var_check); } else { struct oval_value *state_entity_val; char *state_entity_val_text; @@ -525,7 +536,7 @@ static inline oval_result_t _evaluate_sysent(struct oval_syschar_model *syschar_ dE("The only allowed operation for comparing record types is 'equals'."); return OVAL_RESULT_ERROR; } - return _evaluate_sysent_record(content, item_entity); + return _evaluate_sysent_record(syschar_model, content, item_entity); } else { if ((state_entity_val = oval_entity_get_value(state_entity)) == NULL) { oscap_seterr(OSCAP_EFAMILY_OVAL, "OVAL internal error: found NULL entity value"); @@ -537,7 +548,8 @@ static inline oval_result_t _evaluate_sysent(struct oval_syschar_model *syschar_ } state_entity_val_datatype = oval_value_get_datatype(state_entity_val); - return oval_ent_cmp_str(state_entity_val_text, state_entity_val_datatype, item_entity, state_entity_operation); + const char *sys_data = oval_sysent_get_value(item_entity); + return oval_str_cmp_str(state_entity_val_text, state_entity_val_datatype, sys_data, state_entity_operation); } } } From 21d52f1eb56951be976674f318ecfd5359f282c6 Mon Sep 17 00:00:00 2001 From: Evgeny Kolesnikov Date: Thu, 25 Jun 2020 23:31:11 +0200 Subject: [PATCH 2/8] probes/yamlfilecontent: Bump yaml-filter, extend the schema and probe to be able to work with a set of values in maps This introduces YAML Path selection ($.blah['key1','key2']) syntax and enriches yamlfilecontent test and schema with EntityStateRecordType and EntityItemRecordType result elements for collecting and checking complex objects in YAML/JSON documents. This change also depend on removal of the 'only lower case' restriction from the name attribute of the field element (EntityXxxFieldType). --- .../5.11.3/independent-definitions-schema.xsd | 19 ++- ...ependent-system-characteristics-schema.xsd | 13 +- .../oval/5.11.3/oval-definitions-schema.xsd | 14 +- .../oval-system-characteristics-schema.xsd | 7 +- .../independent/yamlfilecontent_probe.c | 155 ++++++++++++------ .../yamlfilecontent/openshift-logging.yaml | 28 ++++ .../test_probes_yamlfilecontent_array.xml | 8 +- .../test_probes_yamlfilecontent_key.sh | 2 +- .../test_probes_yamlfilecontent_key.xml | 70 +++++++- ...st_probes_yamlfilecontent_offline_mode.xml | 12 +- .../test_probes_yamlfilecontent_types.sh | 40 ++--- yaml-filter | 2 +- 12 files changed, 261 insertions(+), 109 deletions(-) diff --git a/schemas/oval/5.11.3/independent-definitions-schema.xsd b/schemas/oval/5.11.3/independent-definitions-schema.xsd index 53e67e187..0f202abf6 100644 --- a/schemas/oval/5.11.3/independent-definitions-schema.xsd +++ b/schemas/oval/5.11.3/independent-definitions-schema.xsd @@ -2115,7 +2115,7 @@ - Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list of zero or more scalar values which will be accessible in OVAL via instances of the value_of entity. Any results from evaluating the YAML Path expression other than a list of scalar values (e.g., a hash or list of lists) is considered an error. The intention is that the scalar values be drawn from instances of a single, uniquely named element. However, an OVAL interpreter is not required to verify this, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. + Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list or a map (part of a map) of zero or more scalar values which will be accessible in OVAL via instances of the result entity. Any results from evaluating the YAML Path expression other than a list of scalar values (or a map with scalar values) at the bottom level (e.g. list of lists, list of maps, map with maps or lists) is considered an error, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. @@ -2158,13 +2158,24 @@ - Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list of zero or more text values which will be accessible in OVAL via instances of the value_of entity. Any results from evaluating the YAML Path expression other than a list of text strings (e.g., a nodes set) is considered an error. The intention is that the text values be drawn from instances of a single, uniquely named element or attribute. However, an OVAL interpreter is not required to verify this, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. + Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list or a map (part of a map) of zero or more scalar values which will be accessible in OVAL via instances of the result entity. Any results from evaluating the YAML Path expression other than a list of scalar values (or a map with scalar values) at the bottom level (e.g. list of lists, list of maps, map with maps or lists) is considered an error, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. - + - The value_of element checks the value(s) of the text node(s) or attribute(s) found. + The value entity specifies how to test objects in the value set of the specified YAML Path. To define tests for a signle scalar value or a list of scalar values, set name attribute of the field child element to an empty string (''). The check is entirely controlled by operator attributes of the field element. + + + + - datatype attribute for the value entity of a yamlfile_state must be 'record' + + + + + + + diff --git a/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd b/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd index 19c6a240e..b2934d4c6 100644 --- a/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd +++ b/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd @@ -606,12 +606,19 @@ - Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list of zero or more scalar values which will be accessible in OVAL via instances of the value_of entity. Any results from evaluating the YAML Path expression other than a list of scalar values (e.g., a hash or list of lists) is considered an error. The intention is that the scalar values be drawn from instances of a single, uniquely named element. However, an OVAL interpreter is not required to verify this, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. + Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list or a map (part of a map) of zero or more scalar values which will be accessible in OVAL via instances of the result entity. Any results from evaluating the YAML Path expression other than a list of scalar values (or a map with scalar values) at the bottom level (e.g. list of lists, list of maps, map with maps or lists) is considered an error, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. - + - The value_of element checks the value(s) of the text node(s) or attribute(s) found. How this is used is entirely controlled by operator attributes. + The value entity holds the target(s) of the specified YAML Path. If YAML Path target is a signle scalar value or a list of scalar values, the field child element's name would be empty (''). The check is entirely controlled by operator attributes of the field element. + + + + - datatype attribute for the value entity of a yamlfile_item must be 'record' + + + diff --git a/schemas/oval/5.11.3/oval-definitions-schema.xsd b/schemas/oval/5.11.3/oval-definitions-schema.xsd index f43abd318..a57b889cf 100644 --- a/schemas/oval/5.11.3/oval-definitions-schema.xsd +++ b/schemas/oval/5.11.3/oval-definitions-schema.xsd @@ -1553,13 +1553,8 @@ - A string restricted to disallow upper case characters. + A string. - - - - - @@ -1824,13 +1819,8 @@ - A string restricted to disallow upper case characters. + A string. - - - - - diff --git a/schemas/oval/5.11.3/oval-system-characteristics-schema.xsd b/schemas/oval/5.11.3/oval-system-characteristics-schema.xsd index 30962f330..543b2db71 100644 --- a/schemas/oval/5.11.3/oval-system-characteristics-schema.xsd +++ b/schemas/oval/5.11.3/oval-system-characteristics-schema.xsd @@ -574,13 +574,8 @@ - A string restricted to disallow upper case characters. + A string. - - - - - diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c index 66d08ad22..f7c7d08cb 100644 --- a/src/OVAL/probes/independent/yamlfilecontent_probe.c +++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c @@ -73,7 +73,7 @@ static SEXP_t *yaml_scalar_event_to_sexp(yaml_event_t *event) char *tag = (char *) event->data.scalar.tag; char *value = (char *) event->data.scalar.value; - /* nodes lacking an explicit tag are given a non-specific tag: + /* Nodes lacking an explicit tag are given a non-specific tag: * “!” for non-plain scalars, and “?” for all other nodes */ if (tag == NULL) { @@ -139,30 +139,30 @@ static SEXP_t *yaml_scalar_event_to_sexp(yaml_event_t *event) return SEXP_string_new(value, strlen(value)); } +#define result_error(fmt, args...) \ +do { \ + SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, fmt, args); \ + probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); \ + SEXP_free(msg); \ + probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); \ + ret = -1; \ +} while (0) + static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, struct oscap_list *values, probe_ctx *ctx) { int ret = 0; FILE *yaml_file = fopen(filepath, "r"); if (yaml_file == NULL) { - SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, - "Unable to open file '%s': %s", filepath, strerror(errno)); - probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); - SEXP_free(msg); - probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); - return -1; + result_error("Unable to open file '%s': %s", filepath, strerror(errno)); + return ret; } yaml_path_t *yaml_path = yaml_path_create(); if (yaml_path_parse(yaml_path, (char *) yaml_path_cstr)) { - SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, - "Invalid YAML path '%s' (%s)\n", yaml_path_cstr, - yaml_path_error_get(yaml_path)->message); - probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); - SEXP_free(msg); - probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); + result_error("Invalid YAML path '%s': %s", yaml_path_cstr, yaml_path_error_get(yaml_path)->message); yaml_path_destroy(yaml_path); fclose(yaml_file); - return -1; + return ret; }; yaml_parser_t parser; @@ -172,71 +172,94 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str yaml_event_t event; yaml_event_type_t event_type; bool sequence = false; + bool mapping = false; + int index = 0; + char *key = strdup(""); + + struct oscap_htable *record = NULL; do { if (!yaml_parser_parse(&parser, &event)) { - SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, - "YAML parser error: yaml_parse_parse returned 0: %s", - parser.problem); - probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); - SEXP_free(msg); - probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); - ret = -1; + result_error("YAML parser error: %s", parser.problem); goto cleanup; } - - event_type = event.type; if (!yaml_path_filter_event(yaml_path, &parser, &event, YAML_PATH_FILTER_RETURN_ALL)) { goto next; } + + event_type = event.type; + if (sequence) { if (event_type == YAML_SEQUENCE_END_EVENT) { sequence = false; - } else if (event_type != YAML_SCALAR_EVENT) { - SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, - "YAML path '%s' contains non-scalar in a sequence.", - yaml_path_cstr); - probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); - SEXP_free(msg); - probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); - ret = -1; + } else if (event_type == YAML_SEQUENCE_START_EVENT) { + result_error("YAML path '%s' points to a multi-dimensional structure", yaml_path_cstr); goto cleanup; } } else { if (event_type == YAML_SEQUENCE_START_EVENT) { sequence = true; } - if (event_type == YAML_MAPPING_START_EVENT) { - SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, - "YAML path '%s' matches a mapping.", - yaml_path_cstr); - probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); - SEXP_free(msg); - probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); - ret = -1; + } + + if (mapping) { + if (event_type == YAML_MAPPING_END_EVENT) { + mapping = false; + oscap_list_add(values, record); + record = NULL; + } else if (event_type == YAML_MAPPING_START_EVENT) { + result_error("YAML path '%s' points to a multi-dimensional structure", yaml_path_cstr); goto cleanup; } + } else { + if (event_type == YAML_MAPPING_START_EVENT) { + if (record) { + result_error("YAML path '%s' points to a multi-dimensional structure", yaml_path_cstr); + goto cleanup; + } + mapping = true; + sequence = false; + index = 0; + record = oscap_htable_new(); + } } + if (event_type == YAML_SCALAR_EVENT) { + if (mapping) { + if (!sequence) { + if (index++ % 2 == 0) { + free(key); + key = strdup((const char *) event.data.scalar.value); + goto next; + } + } + } + SEXP_t *sexp = yaml_scalar_event_to_sexp(&event); if (sexp == NULL) { - SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, - "Can't convert '%s %s' to SEXP", event.data.scalar.tag, - event.data.scalar.value); - probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); - SEXP_free(msg); - probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); - ret = -1; + result_error("Can't convert '%s %s' to SEXP", event.data.scalar.tag, event.data.scalar.value); goto cleanup; } - oscap_list_add(values, sexp); + + if (!record) + record = oscap_htable_new(); + struct oscap_list *field = oscap_htable_get(record, key); + if (!field) { + field = oscap_list_new(); + oscap_htable_add(record, key, field); + } + + oscap_list_add(field, sexp); } next: yaml_event_delete(&event); } while (event_type != YAML_STREAM_END_EVENT); cleanup: + if (record) + oscap_list_add(values, record); + free(key); yaml_parser_delete(&parser); yaml_path_destroy(yaml_path); fclose(yaml_file); @@ -244,6 +267,16 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str return ret; } +static void record_free(struct oscap_list *items) +{ + oscap_list_free(items, (oscap_destruct_func) SEXP_free); +} + +static void values_free(struct oscap_htable *record) +{ + oscap_htable_free(record, (oscap_destruct_func) record_free); +} + static int process_yaml_file(const char *prefix, const char *path, const char *filename, const char *yamlpath, probe_ctx *ctx) { int ret = 0; @@ -265,21 +298,37 @@ static int process_yaml_file(const char *prefix, const char *path, const char *f "path", OVAL_DATATYPE_STRING, path, "filename", OVAL_DATATYPE_STRING, filename, "yamlpath", OVAL_DATATYPE_STRING, yamlpath, - /* - "windows_view", - */ + // TODO: Implement "windows_view", NULL ); while (oscap_iterator_has_more(values_it)) { - SEXP_t *value_sexp = oscap_iterator_next(values_it); - probe_item_ent_add(item, "value_of", NULL, value_sexp); + SEXP_t *result_ent = probe_ent_creat1("value", NULL, NULL); + probe_ent_setdatatype(result_ent, OVAL_DATATYPE_RECORD); + struct oscap_htable *record = oscap_iterator_next(values_it); + struct oscap_htable_iterator *record_it = oscap_htable_iterator_new(record); + while(oscap_htable_iterator_has_more(record_it)) { + const struct oscap_htable_item *record_item = oscap_htable_iterator_next(record_it); + struct oscap_iterator *item_value_it = oscap_iterator_new(record_item->value); + SEXP_t se_tmp_mem; + SEXP_t *key = SEXP_string_new_r(&se_tmp_mem, record_item->key, strlen(record_item->key)); + while(oscap_iterator_has_more(item_value_it)) { + SEXP_t *value_sexp = oscap_iterator_next(item_value_it); + SEXP_t *field = probe_ent_creat1("field", NULL, value_sexp); + probe_item_attr_add(field, "name", key); + SEXP_list_add(result_ent, field); + } + oscap_iterator_free(item_value_it); + SEXP_free_r(&se_tmp_mem); + } + oscap_htable_iterator_free(record_it); + SEXP_list_add(item, result_ent); } probe_item_collect(ctx, item); } oscap_iterator_free(values_it); cleanup: - oscap_list_free(values, (oscap_destruct_func) SEXP_free); + oscap_list_free(values, (oscap_destruct_func) values_free); free(filepath_with_prefix); free(filepath); return ret; diff --git a/tests/probes/yamlfilecontent/openshift-logging.yaml b/tests/probes/yamlfilecontent/openshift-logging.yaml index a89e70942..fb6a9d8b6 100644 --- a/tests/probes/yamlfilecontent/openshift-logging.yaml +++ b/tests/probes/yamlfilecontent/openshift-logging.yaml @@ -38,3 +38,31 @@ spec: inputSource: logs.audit outputRefs: - secureforward-offcluster +status: + conditions: + - lastTransitionTime: "2020-06-08T04:54:58Z" + reason: AsExpected + status: "False" + type: Degraded + - lastTransitionTime: "2020-06-08T06:34:00Z" + reason: AsExpected + status: "False" + type: Progressing + - lastTransitionTime: "2020-06-08T04:51:08Z" + reason: AsExpected + status: "True" + type: Available + - lastTransitionTime: "2020-06-08T04:45:45Z" + reason: AsExpected + status: "True" + type: Upgradeable + extension: null + relatedObjects: + - group: operator.openshift.io + name: cluster + resource: openshiftapiservers + versions: + - name: operator + version: 4.5.0-0.nightly-2020-06-04-214605 + - name: openshift-apiserver + version: 4.5.0-0.nightly-2020-06-04-214605 diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml index 768b0b4a3..9a4227fb8 100644 --- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml +++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml @@ -76,11 +76,15 @@ - secureforward-offcluster + + secureforward-offcluster + - + + + diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh index 300c1b496..b25ad99f9 100755 --- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh +++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh @@ -19,7 +19,7 @@ function test_probes_yamlfilecontent_key { $OSCAP oval eval --results $RF $DF if [ -f $RF ]; then - verify_results "def" $DF $RF 3 && verify_results "tst" $DF $RF 4 + verify_results "def" $DF $RF 5 && verify_results "tst" $DF $RF 6 ret_val=$? else ret_val=1 diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml index f055bb648..fc3ee939e 100644 --- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml +++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml @@ -21,7 +21,7 @@ - + @@ -41,6 +41,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -55,7 +75,7 @@ - + @@ -63,6 +83,16 @@ + + + + + + + + + + @@ -91,16 +121,48 @@ .doesnt.exist + + /tmp + openshift-logging.yaml + .status.conditions[:]['status','type'] + + + + /tmp + openshift-logging.yaml + .status.conditions[:] + + - LogForwarding + + LogForwarding + - openshift-logging + + openshift-logging + + + + + + True + Upgradeable + + + + + + True + AsExpected + Upgradeable + ^\d+-\d+-.*Z$ + diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_offline_mode.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_offline_mode.xml index 675f528e8..5c7cf5b28 100644 --- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_offline_mode.xml +++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_offline_mode.xml @@ -85,15 +85,21 @@ - instance + + instance + - outstance + + outstance + - instance + + instance + diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh index 97bb33dfd..8b0614fc6 100755 --- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh +++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh @@ -24,49 +24,49 @@ function test_probes_yamlfilecontent_types { sd='/oval_results/results/system/oval_system_characteristics/system_data' - assert_exists 8 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="boolean"]' - assert_exists 4 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="boolean" and text()="true"]' - assert_exists 4 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="boolean" and text()="false"]' + assert_exists 8 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="boolean"]' + assert_exists 4 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="boolean" and text()="true"]' + assert_exists 4 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="boolean" and text()="false"]' - assert_exists 5 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="int"]' + assert_exists 5 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int"]' # int_10: 42 - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="int" and text()="42"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="42"]' # int_10_neg: -17 - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="int" and text()="-17"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="-17"]' # int_8: 0o33 - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="int" and text()="27"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="27"]' # int_16: 0xFF - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="int" and text()="255"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="255"]' # int_cast: !!int "369" - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="int" and text()="369"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="369"]' - assert_exists 7 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float"]' + assert_exists 7 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float"]' # float: 7.4 - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float" and text()="7.400000"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="7.400000"]' # float_neg: -0.3 - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float" and text()="-0.300000"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="-0.300000"]' # float_exp: +12e03 - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float" and text()="12000.000000"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="12000.000000"]' # float_exp_neg: -43e-4 - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float" and text()="-0.004300"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="-0.004300"]' # float: .inf - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float" and text()="inf"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="inf"]' # float: .NAN - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float" and text()="nan"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="nan"]' # float_cast: !!float "978.65" - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float" and text()="978.650000"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="978.650000"]' # string_true - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype!="boolean" and text()="true"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype!="boolean" and text()="true"]' # string_number - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype!="int" and text()="81"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype!="int" and text()="81"]' # bool_error_cast, int_error_cast, float_error_cast co='/oval_results/results/system/oval_system_characteristics/collected_objects' assert_exists 3 $co'/object[@flag="error"]' assert_exists 3 $co'/object[@flag="error"]/message' - rm -f $result + #rm -f $result rm -f $YAML_FILE } From 4f129b7142360ff4adb06aa49ee050ccf335fa8e Mon Sep 17 00:00:00 2001 From: Evgeny Kolesnikov Date: Fri, 31 Jul 2020 08:37:25 +0200 Subject: [PATCH 3/8] OVAL: Fix record field evaluation --- src/OVAL/oval_recordField.c | 20 ++++++++++---------- src/OVAL/results/oval_resultTest.c | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/OVAL/oval_recordField.c b/src/OVAL/oval_recordField.c index a0c8a6a54..dd765097d 100644 --- a/src/OVAL/oval_recordField.c +++ b/src/OVAL/oval_recordField.c @@ -208,7 +208,7 @@ void oval_record_field_set_mask(struct oval_record_field *rf, int mask) void oval_record_field_set_operation(struct oval_record_field *rf, oval_operation_t operation) { if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) { - dE("Wrong record field type: %d.", rf->record_field_type); + dE("Wrong record field type (set operation): %d.", rf->record_field_type); return; } @@ -218,7 +218,7 @@ void oval_record_field_set_operation(struct oval_record_field *rf, oval_operatio void oval_record_field_set_variable(struct oval_record_field *rf, struct oval_variable *var) { if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) { - dE("Wrong record field type: %d.", rf->record_field_type); + dE("Wrong record field type (set variable): %d.", rf->record_field_type); return; } @@ -228,7 +228,7 @@ void oval_record_field_set_variable(struct oval_record_field *rf, struct oval_va void oval_record_field_set_var_check(struct oval_record_field *rf, oval_check_t var_check) { if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) { - dE("Wrong record field type: %d.", rf->record_field_type); + dE("Wrong record field type (set var_check): %d.", rf->record_field_type); return; } @@ -238,7 +238,7 @@ void oval_record_field_set_var_check(struct oval_record_field *rf, oval_check_t void oval_record_field_set_ent_check(struct oval_record_field *rf, oval_check_t ent_check) { if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) { - dE("Wrong record field type: %d.", rf->record_field_type); + dE("Wrong record field type (set ent_check): %d.", rf->record_field_type); return; } @@ -248,7 +248,7 @@ void oval_record_field_set_ent_check(struct oval_record_field *rf, oval_check_t void oval_record_field_set_status(struct oval_record_field *rf, oval_syschar_status_t status) { if (rf->record_field_type != OVAL_RECORD_FIELD_ITEM) { - dE("Wrong record field type: %d.", rf->record_field_type); + dE("Wrong record field type (set status): %d.", rf->record_field_type); return; } @@ -283,7 +283,7 @@ int oval_record_field_get_mask(struct oval_record_field *rf) oval_operation_t oval_record_field_get_operation(struct oval_record_field *rf) { if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) { - dE("Wrong record field type: %d.", rf->record_field_type); + dE("Wrong record field type (get operation): %d.", rf->record_field_type); return OVAL_OPERATION_UNKNOWN; } @@ -293,7 +293,7 @@ oval_operation_t oval_record_field_get_operation(struct oval_record_field *rf) struct oval_variable *oval_record_field_get_variable(struct oval_record_field *rf) { if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) { - dE("Wrong record field type: %d.", rf->record_field_type); + dE("Wrong record field type (get variable): %d.", rf->record_field_type); return NULL; } @@ -303,7 +303,7 @@ struct oval_variable *oval_record_field_get_variable(struct oval_record_field *r oval_check_t oval_record_field_get_var_check(struct oval_record_field *rf) { if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) { - dE("Wrong record field type: %d.", rf->record_field_type); + dE("Wrong record field type (get var_check): %d.", rf->record_field_type); return OVAL_CHECK_UNKNOWN; } @@ -313,7 +313,7 @@ oval_check_t oval_record_field_get_var_check(struct oval_record_field *rf) oval_check_t oval_record_field_get_ent_check(struct oval_record_field *rf) { if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) { - dE("Wrong record field type: %d.", rf->record_field_type); + dE("Wrong record field type (get ent_check): %d.", rf->record_field_type); return OVAL_CHECK_UNKNOWN; } @@ -323,7 +323,7 @@ oval_check_t oval_record_field_get_ent_check(struct oval_record_field *rf) oval_syschar_status_t oval_record_field_get_status(struct oval_record_field *rf) { if (rf->record_field_type != OVAL_RECORD_FIELD_ITEM) { - dE("Wrong record field type: %d.", rf->record_field_type); + dE("Wrong record field type (get status): %d.", rf->record_field_type); return SYSCHAR_STATUS_UNKNOWN; } diff --git a/src/OVAL/results/oval_resultTest.c b/src/OVAL/results/oval_resultTest.c index 38477cb3b..00e161481 100644 --- a/src/OVAL/results/oval_resultTest.c +++ b/src/OVAL/results/oval_resultTest.c @@ -458,9 +458,9 @@ static struct record_field_instance _oval_record_field_iterator_next_instance(st if (oval_record_field_get_type(rf) == OVAL_RECORD_FIELD_STATE) { instance.ent_check = oval_record_field_get_ent_check(rf); instance.operation = oval_record_field_get_operation(rf); + instance.var = oval_record_field_get_variable(rf); + instance.var_check = oval_record_field_get_var_check(rf); } - instance.var = oval_record_field_get_variable(rf); - instance.var_check = oval_record_field_get_var_check(rf); return instance; } From 277548a18c4d7312df4e19da5cff38dfff56fd45 Mon Sep 17 00:00:00 2001 From: Evgeny Kolesnikov Date: Fri, 31 Jul 2020 08:38:10 +0200 Subject: [PATCH 4/8] probes/yamlfilecontent: Avoid collecting empty records --- .../independent/yamlfilecontent_probe.c | 7 ++++++- .../test_probes_yamlfilecontent_key.sh | 2 +- .../test_probes_yamlfilecontent_key.xml | 20 +++++++++++++++++++ .../test_probes_yamlfilecontent_types.sh | 2 -- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c index f7c7d08cb..8e276dc3c 100644 --- a/src/OVAL/probes/independent/yamlfilecontent_probe.c +++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c @@ -206,7 +206,12 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str if (mapping) { if (event_type == YAML_MAPPING_END_EVENT) { mapping = false; - oscap_list_add(values, record); + if (record->itemcount > 0) { + oscap_list_add(values, record); + } else { + // Do not collect empty records + oscap_htable_free0(record); + } record = NULL; } else if (event_type == YAML_MAPPING_START_EVENT) { result_error("YAML path '%s' points to a multi-dimensional structure", yaml_path_cstr); diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh index b25ad99f9..fc1e0ae7e 100755 --- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh +++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh @@ -19,7 +19,7 @@ function test_probes_yamlfilecontent_key { $OSCAP oval eval --results $RF $DF if [ -f $RF ]; then - verify_results "def" $DF $RF 5 && verify_results "tst" $DF $RF 6 + verify_results "def" $DF $RF 6 && verify_results "tst" $DF $RF 7 ret_val=$? else ret_val=1 diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml index fc3ee939e..bb40d89be 100644 --- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml +++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml @@ -61,6 +61,16 @@ + + + + + + + + + + @@ -93,6 +103,10 @@ + + + + @@ -133,6 +147,12 @@ .status.conditions[:] + + /tmp + openshift-logging.yaml + .status.conditions[:]['nonexistent','dummy'] + + diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh index 8b0614fc6..83910ed38 100755 --- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh +++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh @@ -66,9 +66,7 @@ function test_probes_yamlfilecontent_types { assert_exists 3 $co'/object[@flag="error"]' assert_exists 3 $co'/object[@flag="error"]/message' - #rm -f $result rm -f $YAML_FILE - } test_probes_yamlfilecontent_types From 8d64db6203c02d3326c9e3336464bb2333d8f9f4 Mon Sep 17 00:00:00 2001 From: Evgeny Kolesnikov Date: Wed, 23 Sep 2020 13:34:59 +0200 Subject: [PATCH 5/8] Revert changes in base OVAL schema And adjust probe implementation and tests for the workaround (lowercase and escape capital letters in field names with ^, use # instead of empty field names for scalars). --- .../5.11.3/independent-definitions-schema.xsd | 8 ++-- ...ependent-system-characteristics-schema.xsd | 4 +- .../oval/5.11.3/oval-definitions-schema.xsd | 14 +++++- .../oval-system-characteristics-schema.xsd | 7 ++- .../independent/yamlfilecontent_probe.c | 43 ++++++++++++++++--- .../test_probes_yamlfilecontent_array.xml | 4 +- .../test_probes_yamlfilecontent_key.xml | 23 ++++++++-- ...st_probes_yamlfilecontent_offline_mode.xml | 6 +-- .../test_probes_yamlfilecontent_types.sh | 38 ++++++++-------- 9 files changed, 106 insertions(+), 41 deletions(-) diff --git a/schemas/oval/5.11.3/independent-definitions-schema.xsd b/schemas/oval/5.11.3/independent-definitions-schema.xsd index 0f202abf6..4168b45bf 100644 --- a/schemas/oval/5.11.3/independent-definitions-schema.xsd +++ b/schemas/oval/5.11.3/independent-definitions-schema.xsd @@ -2115,7 +2115,7 @@ - Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list or a map (part of a map) of zero or more scalar values which will be accessible in OVAL via instances of the result entity. Any results from evaluating the YAML Path expression other than a list of scalar values (or a map with scalar values) at the bottom level (e.g. list of lists, list of maps, map with maps or lists) is considered an error, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. + Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a sequence or a map (part of a map) of scalar values which will be accessible in OVAL via instances of the value entity. Any results from evaluating the YAML Path expression other than a sequence (or a map) of scalar values (e.g. sequence of sequences, sequence of maps, map of maps etc.) are considered as incorrect, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. @@ -2158,12 +2158,12 @@ - Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list or a map (part of a map) of zero or more scalar values which will be accessible in OVAL via instances of the result entity. Any results from evaluating the YAML Path expression other than a list of scalar values (or a map with scalar values) at the bottom level (e.g. list of lists, list of maps, map with maps or lists) is considered an error, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. + Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. Note that "equals" is the only valid operator for the yamlpath entity. - The value entity specifies how to test objects in the value set of the specified YAML Path. To define tests for a signle scalar value or a list of scalar values, set name attribute of the field child element to an empty string (''). The check is entirely controlled by operator attributes of the field element. + The value entity specifies how to test objects in the value set of the specified YAML Path. To define tests for a signle scalar value or a list of scalar values (where there is no key to associate), set the name attribute of the field element to '#'. Due to the limitation of the record type field names could not contain uppercase letters, they will be converted to the lowercase and escaped using the '^' symbol (the '^' symbol would be escaped as well). For example 'myCamelCase^Key' would be collected as 'my^camel^case^^^key'. The check is entirely controlled by operator attributes of the field element. @@ -2172,7 +2172,7 @@ - + diff --git a/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd b/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd index b2934d4c6..9c108297b 100644 --- a/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd +++ b/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd @@ -606,12 +606,12 @@ - Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list or a map (part of a map) of zero or more scalar values which will be accessible in OVAL via instances of the result entity. Any results from evaluating the YAML Path expression other than a list of scalar values (or a map with scalar values) at the bottom level (e.g. list of lists, list of maps, map with maps or lists) is considered an error, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. + Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. Note that "equals" is the only valid operator for the yamlpath entity. - The value entity holds the target(s) of the specified YAML Path. If YAML Path target is a signle scalar value or a list of scalar values, the field child element's name would be empty (''). The check is entirely controlled by operator attributes of the field element. + The value entity holds the target(s) of the specified YAML Path. To define tests for a signle scalar value or a list of scalar values (where there is no key to associate), set the name attribute of the field element to '#'. Due to the limitation of the record type field names could not contain uppercase letters, they will be converted to the lowercase and escaped using the '^' symbol (the '^' symbol would be escaped as well). For example 'myCamelCase^Key' would be collected as 'my^camel^case^^^key'. The check is entirely controlled by operator attributes of the field element. diff --git a/schemas/oval/5.11.3/oval-definitions-schema.xsd b/schemas/oval/5.11.3/oval-definitions-schema.xsd index a57b889cf..f43abd318 100644 --- a/schemas/oval/5.11.3/oval-definitions-schema.xsd +++ b/schemas/oval/5.11.3/oval-definitions-schema.xsd @@ -1553,8 +1553,13 @@ - A string. + A string restricted to disallow upper case characters. + + + + + @@ -1819,8 +1824,13 @@ - A string. + A string restricted to disallow upper case characters. + + + + + diff --git a/schemas/oval/5.11.3/oval-system-characteristics-schema.xsd b/schemas/oval/5.11.3/oval-system-characteristics-schema.xsd index 543b2db71..30962f330 100644 --- a/schemas/oval/5.11.3/oval-system-characteristics-schema.xsd +++ b/schemas/oval/5.11.3/oval-system-characteristics-schema.xsd @@ -574,8 +574,13 @@ - A string. + A string restricted to disallow upper case characters. + + + + + diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c index 8e276dc3c..641709bb9 100644 --- a/src/OVAL/probes/independent/yamlfilecontent_probe.c +++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c @@ -148,6 +148,39 @@ do { \ ret = -1; \ } while (0) +static char *escape_key(char *key) +{ + if (key == NULL) + return NULL; + + size_t cap_letters = 0; + size_t key_len = strlen(key); + for (size_t i = 0; i < key_len; i++) + if ((key[i] >= 'A' && key[i] <= 'Z') || key[i] == '^') + cap_letters++; + + if (cap_letters == 0) + return key; + + char *new_key = realloc(key, key_len + 1 + cap_letters); + if (new_key == NULL) + return key; + new_key[key_len + cap_letters] = '\0'; + + for (ssize_t i = key_len; i >= 0; i--) { + if ((new_key[i] >= 'A' && new_key[i] <= 'Z') || new_key[i] == '^') { + if (new_key[i] != '^') + new_key[i] += 32; + memmove(new_key + i + cap_letters, new_key + i, key_len - i); + new_key[i + cap_letters - 1] = '^'; + cap_letters--; + key_len = i; + } + } + + return new_key; +} + static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, struct oscap_list *values, probe_ctx *ctx) { int ret = 0; @@ -174,7 +207,7 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str bool sequence = false; bool mapping = false; int index = 0; - char *key = strdup(""); + char *key = strdup("#"); struct oscap_htable *record = NULL; @@ -194,7 +227,7 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str if (event_type == YAML_SEQUENCE_END_EVENT) { sequence = false; } else if (event_type == YAML_SEQUENCE_START_EVENT) { - result_error("YAML path '%s' points to a multi-dimensional structure", yaml_path_cstr); + result_error("YAML path '%s' points to a multi-dimensional structure (sequence containing another sequence)", yaml_path_cstr); goto cleanup; } } else { @@ -214,13 +247,13 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str } record = NULL; } else if (event_type == YAML_MAPPING_START_EVENT) { - result_error("YAML path '%s' points to a multi-dimensional structure", yaml_path_cstr); + result_error("YAML path '%s' points to a multi-dimensional structure (map containing another map)", yaml_path_cstr); goto cleanup; } } else { if (event_type == YAML_MAPPING_START_EVENT) { if (record) { - result_error("YAML path '%s' points to a multi-dimensional structure", yaml_path_cstr); + result_error("YAML path '%s' points to an invalid structure (map containing another map)", yaml_path_cstr); goto cleanup; } mapping = true; @@ -235,7 +268,7 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str if (!sequence) { if (index++ % 2 == 0) { free(key); - key = strdup((const char *) event.data.scalar.value); + key = escape_key(strdup((const char *) event.data.scalar.value)); goto next; } } diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml index 9a4227fb8..9fd92492e 100644 --- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml +++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml @@ -77,13 +77,13 @@ - secureforward-offcluster + secureforward-offcluster - + diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml index bb40d89be..05757d0c8 100644 --- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml +++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml @@ -71,6 +71,15 @@ + + + + + + + + + @@ -107,6 +116,9 @@ + + + @@ -153,19 +165,24 @@ .status.conditions[:]['nonexistent','dummy'] + + /tmp + openshift-logging.yaml + .spec.outputs + - LogForwarding + LogForwarding - openshift-logging + openshift-logging @@ -181,7 +198,7 @@ True AsExpected Upgradeable - ^\d+-\d+-.*Z$ + ^\d+-\d+-.*Z$ diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_offline_mode.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_offline_mode.xml index 5c7cf5b28..35a646688 100644 --- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_offline_mode.xml +++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_offline_mode.xml @@ -86,19 +86,19 @@ - instance + instance - outstance + outstance - instance + instance diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh index 83910ed38..4f110f6eb 100755 --- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh +++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh @@ -24,42 +24,42 @@ function test_probes_yamlfilecontent_types { sd='/oval_results/results/system/oval_system_characteristics/system_data' - assert_exists 8 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="boolean"]' - assert_exists 4 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="boolean" and text()="true"]' - assert_exists 4 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="boolean" and text()="false"]' + assert_exists 8 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="boolean"]' + assert_exists 4 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="boolean" and text()="true"]' + assert_exists 4 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="boolean" and text()="false"]' - assert_exists 5 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int"]' + assert_exists 5 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="int"]' # int_10: 42 - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="42"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="int" and text()="42"]' # int_10_neg: -17 - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="-17"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="int" and text()="-17"]' # int_8: 0o33 - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="27"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="int" and text()="27"]' # int_16: 0xFF - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="255"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="int" and text()="255"]' # int_cast: !!int "369" - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="369"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="int" and text()="369"]' - assert_exists 7 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float"]' + assert_exists 7 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="float"]' # float: 7.4 - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="7.400000"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="float" and text()="7.400000"]' # float_neg: -0.3 - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="-0.300000"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="float" and text()="-0.300000"]' # float_exp: +12e03 - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="12000.000000"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="float" and text()="12000.000000"]' # float_exp_neg: -43e-4 - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="-0.004300"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="float" and text()="-0.004300"]' # float: .inf - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="inf"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="float" and text()="inf"]' # float: .NAN - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="nan"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="float" and text()="nan"]' # float_cast: !!float "978.65" - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="978.650000"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="float" and text()="978.650000"]' # string_true - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype!="boolean" and text()="true"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype!="boolean" and text()="true"]' # string_number - assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype!="int" and text()="81"]' + assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype!="int" and text()="81"]' # bool_error_cast, int_error_cast, float_error_cast co='/oval_results/results/system/oval_system_characteristics/collected_objects' From 5f9b9b6686e9d1b05094cdda8d5d1339ed4e8547 Mon Sep 17 00:00:00 2001 From: Evgeny Kolesnikov Date: Thu, 24 Sep 2020 11:21:02 +0200 Subject: [PATCH 6/8] Bump yaml-filter --- src/OVAL/probes/independent/yamlfilecontent_probe.c | 3 +-- .../yamlfilecontent/test_probes_yamlfilecontent_array.xml | 2 +- yaml-filter | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c index 641709bb9..b57956765 100644 --- a/src/OVAL/probes/independent/yamlfilecontent_probe.c +++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c @@ -216,8 +216,7 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str result_error("YAML parser error: %s", parser.problem); goto cleanup; } - if (!yaml_path_filter_event(yaml_path, &parser, &event, - YAML_PATH_FILTER_RETURN_ALL)) { + if (yaml_path_filter_event(yaml_path, &parser, &event) == YAML_PATH_FILTER_RESULT_OUT) { goto next; } diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml index 9fd92492e..c05c5fbb9 100644 --- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml +++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml @@ -62,7 +62,7 @@ /tmp openshift-logging.yaml - .spec.outputs[0:2].name + .spec.outputs[:].name From 183e3517365890d0e704460fdb6e99672c469d22 Mon Sep 17 00:00:00 2001 From: Evgeny Kolesnikov Date: Tue, 29 Sep 2020 10:42:22 +0200 Subject: [PATCH 7/8] Update schemas --- .../5.11.3/independent-definitions-schema.xsd | 2 +- ...dependent-system-characteristics-schema.xsd | 2 +- .../probes/independent/yamlfilecontent_probe.c | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/schemas/oval/5.11.3/independent-definitions-schema.xsd b/schemas/oval/5.11.3/independent-definitions-schema.xsd index 4168b45bf..d9a891d23 100644 --- a/schemas/oval/5.11.3/independent-definitions-schema.xsd +++ b/schemas/oval/5.11.3/independent-definitions-schema.xsd @@ -2163,7 +2163,7 @@ - The value entity specifies how to test objects in the value set of the specified YAML Path. To define tests for a signle scalar value or a list of scalar values (where there is no key to associate), set the name attribute of the field element to '#'. Due to the limitation of the record type field names could not contain uppercase letters, they will be converted to the lowercase and escaped using the '^' symbol (the '^' symbol would be escaped as well). For example 'myCamelCase^Key' would be collected as 'my^camel^case^^^key'. The check is entirely controlled by operator attributes of the field element. + The value entity specifies how to test objects in the value set of the specified YAML Path. To define tests for a single scalar value or a list of scalar values (where there is no key to associate), set the name attribute of the field element to '#'. Due to the limitation of the record type field names could not contain uppercase letters, they should be converted to the lowercase and escaped using the '^' symbol (the '^' symbol should be escaped as well). For example, to check a value associated with 'myCamelCase^Key' set the name attribute of the field to 'my^camel^case^^^key'. The check is entirely controlled by operator attributes of the field element. diff --git a/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd b/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd index 9c108297b..c2a2aab50 100644 --- a/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd +++ b/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd @@ -611,7 +611,7 @@ - The value entity holds the target(s) of the specified YAML Path. To define tests for a signle scalar value or a list of scalar values (where there is no key to associate), set the name attribute of the field element to '#'. Due to the limitation of the record type field names could not contain uppercase letters, they will be converted to the lowercase and escaped using the '^' symbol (the '^' symbol would be escaped as well). For example 'myCamelCase^Key' would be collected as 'my^camel^case^^^key'. The check is entirely controlled by operator attributes of the field element. + The value entity holds the target(s) of the specified YAML Path. A single scalar value or a list of scalar values (where there is no key to associate) would have the name attribute of the field element set to '#'. Due to the limitation of the record type field names could not contain uppercase letters, they will be converted to the lowercase and escaped using the '^' symbol (the '^' symbol would be escaped as well). For example 'myCamelCase^Key' would be collected as 'my^camel^case^^^key'. diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c index b57956765..72e5638ae 100644 --- a/src/OVAL/probes/independent/yamlfilecontent_probe.c +++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c @@ -139,15 +139,6 @@ static SEXP_t *yaml_scalar_event_to_sexp(yaml_event_t *event) return SEXP_string_new(value, strlen(value)); } -#define result_error(fmt, args...) \ -do { \ - SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, fmt, args); \ - probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); \ - SEXP_free(msg); \ - probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); \ - ret = -1; \ -} while (0) - static char *escape_key(char *key) { if (key == NULL) @@ -181,6 +172,15 @@ static char *escape_key(char *key) return new_key; } +#define result_error(fmt, args...) \ +do { \ + SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, fmt, args); \ + probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); \ + SEXP_free(msg); \ + probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); \ + ret = -1; \ +} while (0) + static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, struct oscap_list *values, probe_ctx *ctx) { int ret = 0; From 227cce0560574d3f2efd75e884152f1fb1a7c619 Mon Sep 17 00:00:00 2001 From: Evgeny Kolesnikov Date: Tue, 29 Sep 2020 15:31:41 +0200 Subject: [PATCH 8/8] probes/yamlfilecontent: Add missed SEXP_free --- src/OVAL/probes/independent/yamlfilecontent_probe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c index 72e5638ae..6f18abf83 100644 --- a/src/OVAL/probes/independent/yamlfilecontent_probe.c +++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c @@ -359,6 +359,7 @@ static int process_yaml_file(const char *prefix, const char *path, const char *f } oscap_htable_iterator_free(record_it); SEXP_list_add(item, result_ent); + SEXP_free(result_ent); } probe_item_collect(ctx, item); }