diff --git a/SOURCES/openscap-1.2.18-oscap-ssh-sudo.patch b/SOURCES/openscap-1.2.18-oscap-ssh-sudo.patch new file mode 100644 index 0000000..064bbdb --- /dev/null +++ b/SOURCES/openscap-1.2.18-oscap-ssh-sudo.patch @@ -0,0 +1,52 @@ +From f2d9ec9883a344daa67a80ad54e6652185346395 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com> +Date: Fri, 14 Feb 2020 14:57:33 +0100 +Subject: [PATCH] Fixed oscap-ssh failing to retrieve the result files when + executing with --sudo + +Depending on the umask configuration of the target system, "sudo oscap" +may create the result files in temporary directory with 600 permissions, +which makes retrieving the log (as the regular user that ssh'ed to the +system) impossible: + +~~~ +$ oscap-ssh --sudo user@system 22 xccdf eval ... +[...] +oscap exit code: 0 +Copying back requested files... +scp: /tmp/tmp.0kfbPWEy6u/report.html: Permission denied +Failed to copy the HTML report back to local machine! +~~~ + +Scenario to reproduce the failure: set a default umask in /etc/sudoers: + +~~~ +Defaults umask = 0077 +~~~ + +The fix consists in changing the result files' ownership from "root" to +user's back, all while in the single sudo (using two sudo commands +wouldn't be nice since the user may get the password prompt twice, +depending on the sudo's configuration). +--- + utils/oscap-ssh | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/utils/oscap-ssh b/utils/oscap-ssh +index 658cc2ee4..bd2e209c4 100755 +--- a/utils/oscap-ssh ++++ b/utils/oscap-ssh +@@ -280,7 +280,12 @@ echo "Starting the evaluation..." + # changing directory because of --oval-results support. oval results files are + # dumped into PWD, and we can't be sure by the file names - we need controlled + # environment +-ssh_execute_with_command_and_options "cd $REMOTE_TEMP_DIR; $OSCAP_SUDO oscap $(command_array_to_string oscap_args)" "$SSH_TTY_ALLOCATION_OPTION" ++if [ -z "$OSCAP_SUDO" ]; then ++ ssh_execute_with_command_and_options "cd $REMOTE_TEMP_DIR; oscap $(command_array_to_string oscap_args)" "$SSH_TTY_ALLOCATION_OPTION" ++else ++ OSCAP_CMD="oscap $(command_array_to_string oscap_args); rc=\$?; chown \$SUDO_USER $REMOTE_TEMP_DIR/*; exit \$rc" ++ ssh_execute_with_command_and_options "cd $REMOTE_TEMP_DIR; $OSCAP_SUDO sh -c '$OSCAP_CMD'" "$SSH_TTY_ALLOCATION_OPTION" ++fi + OSCAP_EXIT_CODE=$? + echo "oscap exit code: $OSCAP_EXIT_CODE" + diff --git a/SOURCES/openscap-1.3.3-ansible-newlines.patch b/SOURCES/openscap-1.3.3-ansible-newlines.patch new file mode 100644 index 0000000..7e6b509 --- /dev/null +++ b/SOURCES/openscap-1.3.3-ansible-newlines.patch @@ -0,0 +1,156 @@ +diff --git a/src/XCCDF_POLICY/xccdf_policy_remediate.c b/src/XCCDF_POLICY/xccdf_policy_remediate.c +index f59737727..19bb59f2e 100644 +--- a/src/XCCDF_POLICY/xccdf_policy_remediate.c ++++ b/src/XCCDF_POLICY/xccdf_policy_remediate.c +@@ -139,11 +139,10 @@ static int _write_remediation_to_fd_and_free(int output_fd, const char* template + free(text); + return 1; + } +- +- if (_write_text_to_fd(output_fd, "\n") != 0) { +- free(text); +- return 1; +- } ++ } ++ if (_write_text_to_fd(output_fd, "\n") != 0) { ++ free(text); ++ return 1; + } + + if (next_delim != NULL) { +diff --git a/tests/API/XCCDF/unittests/CMakeLists.txt b/tests/API/XCCDF/unittests/CMakeLists.txt +index 2a56d3cdc..05ddea219 100644 +--- a/tests/API/XCCDF/unittests/CMakeLists.txt ++++ b/tests/API/XCCDF/unittests/CMakeLists.txt +@@ -18,6 +18,7 @@ if(PYTHONINTERP_FOUND) + add_oscap_test("all_python.sh") + endif() + ++add_oscap_test("test_ansible_yaml_block_scalar.sh") + add_oscap_test("test_xccdf_shall_pass1.sh") + add_oscap_test("test_xccdf_shall_pass2.sh") + add_oscap_test("test_xccdf_shall_pass3.sh") +diff --git a/tests/API/XCCDF/unittests/test_ansible_yaml_block_scalar.playbook.yml b/tests/API/XCCDF/unittests/test_ansible_yaml_block_scalar.playbook.yml +new file mode 100644 +index 000000000..dd0276739 +--- /dev/null ++++ b/tests/API/XCCDF/unittests/test_ansible_yaml_block_scalar.playbook.yml +@@ -0,0 +1,37 @@ ++--- ++ ++ ++- hosts: all ++ vars: ++ tasks: ++ - name: Make sure contents of /etc/audit/rules.d/10-base-config.rules are as expected ++ copy: ++ dest: /etc/audit/rules.d/10-base-config.rules ++ content: |+ ++ ## First rule - delete all ++ -D ++ ++ ## Increase the buffers to survive stress events. ++ ## Make this bigger for busy systems ++ -b 8192 ++ ++ ## This determine how long to wait in burst of events ++ --backlog_wait_time 60000 ++ ++ ## Set failure mode to syslog ++ -f 1 ++ ++ ++ force: true ++ when: ansible_virtualization_role != "guest" or ansible_virtualization_type != "docker" ++ tags: ++ - audit_basic_configuration ++ - medium_severity ++ - restrict_strategy ++ - low_complexity ++ - low_disruption ++ - no_reboot_needed ++ - CCE-82462-3 ++ - NIST-800-53-AU-2(a) ++ ++ +diff --git a/tests/API/XCCDF/unittests/test_ansible_yaml_block_scalar.sh b/tests/API/XCCDF/unittests/test_ansible_yaml_block_scalar.sh +new file mode 100755 +index 000000000..4ca5b3be5 +--- /dev/null ++++ b/tests/API/XCCDF/unittests/test_ansible_yaml_block_scalar.sh +@@ -0,0 +1,21 @@ ++#!/bin/bash ++. $builddir/tests/test_common.sh ++ ++set -e ++set -o pipefail ++ ++profile="xccdf_moc.elpmaxe.www_profile_standard" ++ ++name=$(basename $0 .sh) ++stderr=$(mktemp -t ${name}.err.XXXXXX) ++playbook=$(mktemp -t ${name}.yml.XXXXXX) ++playbook_without_header=$(mktemp -t ${name}.yml.XXXXXX) ++ ++# Generate an Ansible playbook from a profile in SDS file ++$OSCAP xccdf generate fix --profile $profile --fix-type ansible "$srcdir/$name.xccdf.xml" >$playbook 2>$stderr ++sed '/^#/d' $playbook > $playbook_without_header ++diff -u $playbook_without_header $srcdir/$name.playbook.yml ++[ -f $stderr ]; [ ! -s $stderr ]; rm $stderr ++ ++rm $playbook ++rm $playbook_without_header +diff --git a/tests/API/XCCDF/unittests/test_ansible_yaml_block_scalar.xccdf.xml b/tests/API/XCCDF/unittests/test_ansible_yaml_block_scalar.xccdf.xml +new file mode 100644 +index 000000000..81b2adfd4 +--- /dev/null ++++ b/tests/API/XCCDF/unittests/test_ansible_yaml_block_scalar.xccdf.xml +@@ -0,0 +1,48 @@ ++<?xml version="1.0" encoding="UTF-8"?> ++<Benchmark xmlns="http://checklists.nist.gov/xccdf/1.2" id="xccdf_moc.elpmaxe.www_benchmark_test"> ++ <status>incomplete</status> ++ <title>Security Benchmark</title> ++ <description xml:lang="en-US">A sample benchmark</description> ++ <version>1.0</version> ++ <Profile id="xccdf_moc.elpmaxe.www_profile_standard"> ++ <title xml:lang="en-US">Standard System Security Profile</title> ++ <description xml:lang="en-US">This profile contains rules to ensure standard security baseline of your system.</description> ++ <select idref="xccdf_moc.elpmaxe.www_rule_1" selected="true"/> ++ </Profile> ++ <Rule selected="false" id="xccdf_moc.elpmaxe.www_rule_1"> ++ <title>Passing rule</title> ++ <fix id="ansible_fix_for_passing_rule" system="urn:xccdf:fix:script:ansible">- name: Make sure contents of /etc/audit/rules.d/10-base-config.rules are as expected ++ copy: ++ dest: /etc/audit/rules.d/10-base-config.rules ++ content: |+ ++ ## First rule - delete all ++ -D ++ ++ ## Increase the buffers to survive stress events. ++ ## Make this bigger for busy systems ++ -b 8192 ++ ++ ## This determine how long to wait in burst of events ++ --backlog_wait_time 60000 ++ ++ ## Set failure mode to syslog ++ -f 1 ++ ++ ++ force: true ++ when: ansible_virtualization_role != "guest" or ansible_virtualization_type != "docker" ++ tags: ++ - audit_basic_configuration ++ - medium_severity ++ - restrict_strategy ++ - low_complexity ++ - low_disruption ++ - no_reboot_needed ++ - CCE-82462-3 ++ - NIST-800-53-AU-2(a) ++</fix> ++ <check system="http://oval.mitre.org/XMLSchema/oval-definitions-5"> ++ <check-content-ref href="oval/pass/oval.xml" name="oval:moc.elpmaxe.www:def:1"/> ++ </check> ++ </Rule> ++</Benchmark> diff --git a/SOURCES/openscap-1.3.3-generate-guide-tailoring.patch b/SOURCES/openscap-1.3.3-generate-guide-tailoring.patch new file mode 100644 index 0000000..6c234cd --- /dev/null +++ b/SOURCES/openscap-1.3.3-generate-guide-tailoring.patch @@ -0,0 +1,249 @@ +diff --git a/src/XCCDF/benchmark.c b/src/XCCDF/benchmark.c +index f561736d4..d6560b7c9 100644 +--- a/src/XCCDF/benchmark.c ++++ b/src/XCCDF/benchmark.c +@@ -866,6 +866,19 @@ xccdf_benchmark_find_target_htable(const struct xccdf_benchmark *benchmark, xccd + return XITEM(benchmark)->sub.benchmark.items_dict; + } + ++int xccdf_benchmark_include_tailored_profiles(struct xccdf_benchmark *benchmark) ++{ ++ struct oscap_list *profiles = XITEM(benchmark)->sub.benchmark.profiles; ++ struct oscap_htable_iterator *it = oscap_htable_iterator_new(XITEM(benchmark)->sub.benchmark.profiles_dict); ++ while(oscap_htable_iterator_has_more(it)) { ++ struct xccdf_profile *profile = oscap_htable_iterator_next_value(it); ++ if (xccdf_profile_get_tailoring(profile)) { ++ oscap_list_add(profiles, xccdf_profile_clone(profile)); ++ } ++ } ++ oscap_htable_iterator_free(it); ++ return 0; ++} + + struct xccdf_plain_text *xccdf_plain_text_new(void) + { +diff --git a/src/XCCDF/item.h b/src/XCCDF/item.h +index 35204744f..da76f854d 100644 +--- a/src/XCCDF/item.h ++++ b/src/XCCDF/item.h +@@ -437,6 +437,7 @@ void xccdf_item_dump(struct xccdf_item *item, int depth); + struct xccdf_item* xccdf_item_get_benchmark_internal(struct xccdf_item* item); + bool xccdf_benchmark_parse(struct xccdf_item *benchmark, xmlTextReaderPtr reader); + void xccdf_benchmark_dump(struct xccdf_benchmark *benchmark); ++int xccdf_benchmark_include_tailored_profiles(struct xccdf_benchmark *benchmark); + struct oscap_htable_iterator *xccdf_benchmark_get_cluster_items(struct xccdf_benchmark *benchmark, const char *cluster_id); + bool xccdf_benchmark_register_item(struct xccdf_benchmark *benchmark, struct xccdf_item *item); + bool xccdf_benchmark_unregister_item(struct xccdf_item *item); +diff --git a/src/XCCDF/public/xccdf_session.h b/src/XCCDF/public/xccdf_session.h +index ac96e2036..026432693 100644 +--- a/src/XCCDF/public/xccdf_session.h ++++ b/src/XCCDF/public/xccdf_session.h +@@ -558,6 +558,14 @@ OSCAP_API int xccdf_session_build_policy_from_testresult(struct xccdf_session *s + */ + OSCAP_API int xccdf_session_add_report_from_source(struct xccdf_session *session, struct oscap_source *report_source); + ++/** ++ * Generate HTML guide form a loaded XCCDF session ++ * @param session XCCDF Session ++ * @param outfile path to the output file ++ * @returns zero on success ++ */ ++OSCAP_API int xccdf_session_generate_guide(struct xccdf_session *session, const char *outfile); ++ + /// @} + /// @} + #endif +diff --git a/src/XCCDF/xccdf_session.c b/src/XCCDF/xccdf_session.c +index 1005a030a..d38905f77 100644 +--- a/src/XCCDF/xccdf_session.c ++++ b/src/XCCDF/xccdf_session.c +@@ -1746,3 +1746,44 @@ int xccdf_session_add_report_from_source(struct xccdf_session *session, struct o + session->xccdf.result = result; + return 0; + } ++ ++int xccdf_session_generate_guide(struct xccdf_session *session, const char *outfile) ++{ ++ struct xccdf_policy *policy = xccdf_session_get_xccdf_policy(session); ++ if (policy == NULL) { ++ oscap_seterr(OSCAP_EFAMILY_OSCAP, "Could not get XCCDF policy."); ++ return 1; ++ } ++ struct xccdf_policy_model *model = xccdf_policy_get_model(policy); ++ if (model == NULL) { ++ oscap_seterr(OSCAP_EFAMILY_OSCAP, "Could not get XCCDF policy model."); ++ return 1; ++ } ++ struct xccdf_benchmark *benchmark = xccdf_policy_model_get_benchmark(model); ++ if (benchmark == NULL) { ++ oscap_seterr(OSCAP_EFAMILY_OSCAP, "Could not get XCCDF benchmark."); ++ return 1; ++ } ++ xccdf_benchmark_include_tailored_profiles(benchmark); ++ const char *params[] = { ++ "oscap-version", oscap_get_version(), ++ "benchmark_id", xccdf_benchmark_get_id(benchmark), ++ "profile_id", xccdf_session_get_profile_id(session), ++ NULL ++ }; ++ struct oscap_source *benchmark_source = xccdf_benchmark_export_source(benchmark, NULL); ++ if (benchmark_source == NULL) { ++ oscap_seterr(OSCAP_EFAMILY_OSCAP, ++ "Failed to export source from XCCDF benchmark %s.", ++ xccdf_benchmark_get_id(benchmark)); ++ return 1; ++ } ++ int ret = oscap_source_apply_xslt_path(benchmark_source, ++ "xccdf-guide.xsl", outfile, params, oscap_path_to_xslt()); ++ oscap_source_free(benchmark_source); ++ if (ret < 0) { ++ oscap_seterr(OSCAP_EFAMILY_OSCAP, "Could not apply XSLT."); ++ return 1; ++ } ++ return 0; ++} +\ No newline at end of file +diff --git a/tests/API/XCCDF/tailoring/all.sh b/tests/API/XCCDF/tailoring/all.sh +index dbed97a87..fc2ccd743 100755 +--- a/tests/API/XCCDF/tailoring/all.sh ++++ b/tests/API/XCCDF/tailoring/all.sh +@@ -134,6 +134,21 @@ function test_api_xccdf_tailoring_profile_generate_fix { + rm -f $tailoring_result $fix_result + } + ++function test_api_xccdf_tailoring_profile_generate_guide { ++ local INPUT=$srcdir/$1 ++ local TAILORING=$srcdir/$2 ++ ++ guide=`mktemp` ++ # tailoring profile only with "always fail" rule and generate HTML guide ++ $OSCAP xccdf generate guide --tailoring-file $TAILORING --profile "xccdf_com.example.www_profile_customized" --output $guide $INPUT ++ ++ grep -q "Baseline Testing Profile 1 \[CUSTOMIZED\]" $guide ++ # profile 'customized' selects first rule and deselects the second ++ grep -q "xccdf_com.example.www_rule_first" $guide ++ grep -v "xccdf_com.example.www_rule_second" $guide ++ rm -f $guide ++} ++ + # Testing. + + test_init "test_api_xccdf_tailoring.log" +@@ -154,6 +169,7 @@ test_run "test_api_xccdf_tailoring_autonegotiation" test_api_xccdf_tailoring_aut + test_run "test_api_xccdf_tailoring_simple_include_in_arf" test_api_xccdf_tailoring_simple_include_in_arf simple-xccdf.xml simple-tailoring.xml + test_run "test_api_xccdf_tailoring_profile_include_in_arf" test_api_xccdf_tailoring_profile_include_in_arf baseline.xccdf.xml baseline.tailoring.xml + test_run "test_api_xccdf_tailoring_profile_generate_fix" test_api_xccdf_tailoring_profile_generate_fix baseline.xccdf.xml baseline.tailoring.xml ++test_run "test_api_xccdf_tailoring_profile_generate_guide" test_api_xccdf_tailoring_profile_generate_guide baseline.xccdf.xml baseline.tailoring.xml + + + test_exit +diff --git a/utils/oscap-xccdf.c b/utils/oscap-xccdf.c +index 472a2cc6f..87a0c7ad1 100644 +--- a/utils/oscap-xccdf.c ++++ b/utils/oscap-xccdf.c +@@ -77,6 +77,7 @@ static bool getopt_xccdf(int argc, char **argv, struct oscap_action *action); + static bool getopt_generate(int argc, char **argv, struct oscap_action *action); + static int app_xccdf_xslt(const struct oscap_action *action); + static int app_generate_fix(const struct oscap_action *action); ++static int app_generate_guide(const struct oscap_action *action); + + #define XCCDF_SUBMODULES_NUM 7 + #define XCCDF_GEN_SUBMODULES_NUM 5 /* See actual arrays +@@ -244,12 +245,18 @@ static struct oscap_module XCCDF_GEN_GUIDE = { + .help = GEN_OPTS + "\nGuide Options:\n" + " --output <file> - Write the document into file.\n" +- " --hide-profile-info - Do not output additional information about selected profile.\n" ++ " --hide-profile-info - This option has no effect.\n" + " --benchmark-id <id> - ID of XCCDF Benchmark in some component in the datastream that should be used.\n" ++ " (only applicable for source datastreams)\n" ++ " --xccdf-id <id> - ID of component-ref with XCCDF in the datastream that should be evaluated.\n" ++ " (only applicable for source datastreams)\n" ++ " --tailoring-file <file> - Use given XCCDF Tailoring file.\n" ++ " (only applicable for source datastreams)\n" ++ " --tailoring-id <component-id> - Use given DS component as XCCDF Tailoring file.\n" + " (only applicable for source datastreams)\n", + .opt_parser = getopt_xccdf, +- .user = "xccdf-guide.xsl", +- .func = app_xccdf_xslt ++ .user = NULL, ++ .func = app_generate_guide + }; + + static struct oscap_module XCCDF_GEN_FIX = { +@@ -973,6 +980,50 @@ int app_generate_fix(const struct oscap_action *action) + return ret; + } + ++int app_generate_guide(const struct oscap_action *action) ++{ ++ int ret = OSCAP_ERROR; ++ ++ struct oscap_source *source = oscap_source_new_from_file(action->f_xccdf); ++ struct xccdf_session *session = xccdf_session_new_from_source(source); ++ if (session == NULL) { ++ goto cleanup; ++ } ++ ++ xccdf_session_set_validation(session, action->validate, getenv("OSCAP_FULL_VALIDATION") != NULL); ++ xccdf_session_set_remote_resources(session, action->remote_resources, download_reporting_callback); ++ xccdf_session_set_user_tailoring_file(session, action->tailoring_file); ++ xccdf_session_set_user_tailoring_cid(session, action->tailoring_id); ++ if (xccdf_session_is_sds(session)) { ++ xccdf_session_set_component_id(session, action->f_xccdf_id); ++ xccdf_session_set_benchmark_id(session, action->f_benchmark_id); ++ } ++ xccdf_session_set_loading_flags(session, XCCDF_SESSION_LOAD_XCCDF); ++ ++ if (xccdf_session_load(session) != 0) { ++ goto cleanup; ++ } ++ ++ if (!xccdf_session_set_profile_id(session, action->profile)) { ++ if (action->profile != NULL) { ++ if (xccdf_set_profile_or_report_bad_id(session, action->profile, action->f_xccdf) == OSCAP_ERROR) ++ goto cleanup; ++ } else { ++ fprintf(stderr, "No Policy was found for default profile.\n"); ++ goto cleanup; ++ } ++ } ++ ++ if (xccdf_session_generate_guide(session, action->f_results) == 0) { ++ ret = OSCAP_OK; ++ } ++ ++cleanup: ++ xccdf_session_free(session); ++ oscap_print_error(); ++ return ret; ++} ++ + int app_xccdf_xslt(const struct oscap_action *action) + { + const char *oval_template = action->oval_template; +diff --git a/utils/oscap.8 b/utils/oscap.8 +index 1b05f8c9e..3a50d1df5 100644 +--- a/utils/oscap.8 ++++ b/utils/oscap.8 +@@ -331,10 +331,19 @@ Generate a HTML document containing a security guide from an XCCDF Benchmark. Un + Write the guide to this file instead of standard output. + .TP + \fB\-\-hide-profile-info\fR +-Information on chosen profile (e.g. rules selected by the profile) will be excluded from the document. ++This option has no effect and is kept only for backward compatibility purposes. + .TP + \fB\-\-benchmark-id ID\fR + Selects a component ref from any datastream that references a component with XCCDF Benchmark such that its @id attribute matches given string exactly. ++.TP ++\fB\-\-xccdf-id ID\fR ++Takes component ref with given ID from checklists. This allows to select a particular XCCDF component even in cases where there are 2 XCCDFs in one datastream. If none is given, the first component from the checklists element is used. ++.TP ++\fB\-\-tailoring-file TAILORING_FILE\fR ++Use given file for XCCDF tailoring. Select profile from tailoring file to apply using --profile. If both --tailoring-file and --tailoring-id are specified, --tailoring-file takes priority. ++.TP ++\fB\-\-tailoring-id COMPONENT_REF_ID\fR ++Use tailoring component in input source datastream for XCCDF tailoring. The tailoring component must be specified by its Ref-ID (value of component-ref/@id attribute in input source datastream). Select profile from tailoring component to apply using --profile. If both --tailoring-file and --tailoring-id are specified, --tailoring-file takes priority. + .RE + .TP + .B \fBreport\fR [\fIoptions\fR] xccdf-file diff --git a/SOURCES/openscap-1.3.3-remove-useless-warnings-tests.patch b/SOURCES/openscap-1.3.3-remove-useless-warnings-tests.patch new file mode 100644 index 0000000..97a9420 --- /dev/null +++ b/SOURCES/openscap-1.3.3-remove-useless-warnings-tests.patch @@ -0,0 +1,44 @@ +From b2b00e2316439d6517c8b763f542db637ebcf0b0 Mon Sep 17 00:00:00 2001 +From: Matus Marhefka <mmarhefk@redhat.com> +Date: Tue, 3 Mar 2020 14:12:39 +0100 +Subject: [PATCH] tests/probes/environmentvariable58: add test to cover + 7c78b84dd + +--- + .../test_probes_environmentvariable58.sh | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/tests/probes/environmentvariable58/test_probes_environmentvariable58.sh b/tests/probes/environmentvariable58/test_probes_environmentvariable58.sh +index 786ea528a..7679c3495 100755 +--- a/tests/probes/environmentvariable58/test_probes_environmentvariable58.sh ++++ b/tests/probes/environmentvariable58/test_probes_environmentvariable58.sh +@@ -24,13 +24,16 @@ function test_probes_environmentvariable58 { + local ret_val=0; + local DF="$1.xml" + local RF="$1.results.xml" ++ echo "result file: $RF" ++ local stderr=$(mktemp $1.err.XXXXXX) ++ echo "stderr file: $stderr" + + [ -f $RF ] && rm -f $RF + + bash ${srcdir}/$1.xml.sh > $DF + LINES=$? + +- $OSCAP oval eval --results $RF $DF ++ $OSCAP oval eval --results $RF $DF 2> $stderr + + if [ -f $RF ]; then + verify_results "def" $DF $RF 1 && verify_results "tst" $DF $RF $LINES +@@ -39,6 +42,11 @@ function test_probes_environmentvariable58 { + ret_val=1 + fi + ++ # Test fails if there are any warnings or "Entity has no value" on stderr. ++ echo "Verify that there are no warnings on stderr" ++ grep -Ei "(W:|Entity has no value)" $stderr && ret_val=1 ++ ++ rm $stderr + return $ret_val + } + diff --git a/SOURCES/openscap-1.3.3-remove-useless-warnings.patch b/SOURCES/openscap-1.3.3-remove-useless-warnings.patch new file mode 100644 index 0000000..a9fedfe --- /dev/null +++ b/SOURCES/openscap-1.3.3-remove-useless-warnings.patch @@ -0,0 +1,28 @@ +diff --git a/src/OVAL/probes/public/probe-api.h b/src/OVAL/probes/public/probe-api.h +index 24cf756cb..c1178956f 100644 +--- a/src/OVAL/probes/public/probe-api.h ++++ b/src/OVAL/probes/public/probe-api.h +@@ -488,11 +488,9 @@ OSCAP_API SEXP_t *probe_item_create(oval_subtype_t item_subtype, probe_elmatr_t + SEXP_t *___r; \ + \ + if ((___r = probe_ent_getval(ent)) == NULL) { \ +- dW("Entity has no value!"); \ + invalid_exp \ + } else { \ + if (!SEXP_stringp(___r)) { \ +- dE("Invalid type"); \ + SEXP_free(___r); \ + invalid_exp \ + } \ +@@ -511,11 +509,9 @@ OSCAP_API SEXP_t *probe_item_create(oval_subtype_t item_subtype, probe_elmatr_t + SEXP_t *___r; \ + \ + if ((___r = probe_ent_getval(ent)) == NULL) { \ +- dW("Entity has no value!"); \ + nil_exp; \ + } else { \ + if (!SEXP_numberp(___r)) { \ +- dE("Invalid type"); \ + SEXP_free(___r); \ + invalid_exp; \ + } else { \ diff --git a/SOURCES/openscap-1.3.3-rpmverifyfile-tests.patch b/SOURCES/openscap-1.3.3-rpmverifyfile-tests.patch new file mode 100644 index 0000000..b08183b --- /dev/null +++ b/SOURCES/openscap-1.3.3-rpmverifyfile-tests.patch @@ -0,0 +1,52 @@ +diff --git a/tests/probes/rpm/rpmverifyfile/test_probes_rpmverifyfile.sh b/tests/probes/rpm/rpmverifyfile/test_probes_rpmverifyfile.sh +index cefde6b75..e913a56c4 100755 +--- a/tests/probes/rpm/rpmverifyfile/test_probes_rpmverifyfile.sh ++++ b/tests/probes/rpm/rpmverifyfile/test_probes_rpmverifyfile.sh +@@ -41,7 +41,7 @@ function test_probes_rpmverifyfile { + assert_exists 1 'oval_results/oval_definitions/objects/lin-def:rpmverifyfile_object/lin-def:release' + assert_exists 1 'oval_results/oval_definitions/objects/lin-def:rpmverifyfile_object/lin-def:arch' + assert_exists 1 'oval_results/oval_definitions/objects/lin-def:rpmverifyfile_object/lin-def:filepath' +- assert_exists 1 'oval_results/oval_definitions/objects/lin-def:rpmverifyfile_object/lin-def:filepath[text()="/etc/os-release"]' ++ assert_exists 1 'oval_results/oval_definitions/objects/lin-def:rpmverifyfile_object/lin-def:filepath[text()="/usr/bin/true"]' + sc='oval_results/results/system/oval_system_characteristics/' + sd=$sc'system_data/' + assert_exists 1 $sc'collected_objects/object' +diff --git a/tests/probes/rpm/rpmverifyfile/test_probes_rpmverifyfile.xml b/tests/probes/rpm/rpmverifyfile/test_probes_rpmverifyfile.xml +index ecdecc75c..e3faa2631 100644 +--- a/tests/probes/rpm/rpmverifyfile/test_probes_rpmverifyfile.xml ++++ b/tests/probes/rpm/rpmverifyfile/test_probes_rpmverifyfile.xml +@@ -30,7 +30,7 @@ + <lin-def:version operation="pattern match"/> + <lin-def:release operation="pattern match"/> + <lin-def:arch operation="pattern match"/> +- <lin-def:filepath>/etc/os-release</lin-def:filepath> ++ <lin-def:filepath>/usr/bin/true</lin-def:filepath> + </lin-def:rpmverifyfile_object> + </objects> + +diff --git a/tests/probes/rpm/rpmverifyfile/test_probes_rpmverifyfile_older.sh b/tests/probes/rpm/rpmverifyfile/test_probes_rpmverifyfile_older.sh +index 3cb63eebe..da74e4671 100755 +--- a/tests/probes/rpm/rpmverifyfile/test_probes_rpmverifyfile_older.sh ++++ b/tests/probes/rpm/rpmverifyfile/test_probes_rpmverifyfile_older.sh +@@ -40,7 +40,7 @@ function test_probes_rpmverifyfile { + assert_exists 1 'oval_results/oval_definitions/objects/lin-def:rpmverifyfile_object/lin-def:release' + assert_exists 1 'oval_results/oval_definitions/objects/lin-def:rpmverifyfile_object/lin-def:arch' + assert_exists 1 'oval_results/oval_definitions/objects/lin-def:rpmverifyfile_object/lin-def:filepath' +- assert_exists 1 'oval_results/oval_definitions/objects/lin-def:rpmverifyfile_object/lin-def:filepath[text()="/etc/os-release"]' ++ assert_exists 1 'oval_results/oval_definitions/objects/lin-def:rpmverifyfile_object/lin-def:filepath[text()="/usr/bin/true"]' + sc='oval_results/results/system/oval_system_characteristics/' + sd=$sc'system_data/' + assert_exists 1 $sc'collected_objects/object' +diff --git a/tests/probes/rpm/rpmverifyfile/test_probes_rpmverifyfile_older.xml b/tests/probes/rpm/rpmverifyfile/test_probes_rpmverifyfile_older.xml +index 73f9e76a3..420485146 100644 +--- a/tests/probes/rpm/rpmverifyfile/test_probes_rpmverifyfile_older.xml ++++ b/tests/probes/rpm/rpmverifyfile/test_probes_rpmverifyfile_older.xml +@@ -30,7 +30,7 @@ + <lin-def:version operation="pattern match"/> + <lin-def:release operation="pattern match"/> + <lin-def:arch operation="pattern match"/> +- <lin-def:filepath>/etc/os-release</lin-def:filepath> ++ <lin-def:filepath>/usr/bin/true</lin-def:filepath> + </lin-def:rpmverifyfile_object> + </objects> + diff --git a/SOURCES/openscap-1.3.3-systemdunit-segfault.patch b/SOURCES/openscap-1.3.3-systemdunit-segfault.patch new file mode 100644 index 0000000..4cd36b2 --- /dev/null +++ b/SOURCES/openscap-1.3.3-systemdunit-segfault.patch @@ -0,0 +1,134 @@ +diff --git a/src/OVAL/probes/unix/linux/systemdunitdependency_probe.c b/src/OVAL/probes/unix/linux/systemdunitdependency_probe.c +index 2f194ce07..e2cbdb7d2 100644 +--- a/src/OVAL/probes/unix/linux/systemdunitdependency_probe.c ++++ b/src/OVAL/probes/unix/linux/systemdunitdependency_probe.c +@@ -37,6 +37,8 @@ + #include <string.h> + #include "systemdunitdependency_probe.h" + ++static void get_all_dependencies_by_unit(DBusConnection *conn, const char *unit, SEXP_t *item, struct oscap_htable *visited_units); ++ + static char *get_property_by_unit_path(DBusConnection *conn, const char *unit_path, const char *property) + { + DBusMessage *msg = NULL; +@@ -135,7 +137,38 @@ static bool is_unit_name_a_target(const char *unit) + return strncmp(unit + len - suffix_len, suffix, suffix_len) == 0; + } + +-static void get_all_dependencies_by_unit(DBusConnection *conn, const char *unit, int(*callback)(const char *, void *), void *cbarg, bool include_requires, bool include_wants) ++static int add_unit_dependency(const char *dependency, SEXP_t *item, struct oscap_htable *visited_units) ++{ ++ if (oscap_htable_get(visited_units, dependency) != NULL) { ++ return 1; ++ } ++ oscap_htable_add(visited_units, dependency, (void *) true); ++ SEXP_t *se_dependency = SEXP_string_new(dependency, strlen(dependency)); ++ probe_item_ent_add(item, "dependency", NULL, se_dependency); ++ SEXP_free(se_dependency); ++ return 0; ++} ++ ++static void process_unit_property(const char *property, DBusConnection *conn, const char *path, SEXP_t *item, struct oscap_htable *visited_units) ++{ ++ char *values_s = get_property_by_unit_path(conn, path, property); ++ if (values_s) { ++ char **values = oscap_split(values_s, ", "); ++ for (int i = 0; values[i] != NULL; ++i) { ++ if (oscap_strcmp(values[i], "") == 0) { ++ continue; ++ } ++ ++ if (add_unit_dependency(values[i], item, visited_units) == 0) { ++ get_all_dependencies_by_unit(conn, values[i], item, visited_units); ++ } ++ } ++ free(values); ++ } ++ free(values_s); ++} ++ ++static void get_all_dependencies_by_unit(DBusConnection *conn, const char *unit, SEXP_t *item, struct oscap_htable *visited_units) + { + if (!unit || strcmp(unit, "(null)") == 0) + return; +@@ -146,66 +179,12 @@ static void get_all_dependencies_by_unit(DBusConnection *conn, const char *unit, + + char *path = get_path_by_unit(conn, unit); + +- if (include_requires) { +- char *requires_s = get_property_by_unit_path(conn, path, "Requires"); +- if (requires_s) { +- char **requires = oscap_split(requires_s, ", "); +- for (int i = 0; requires[i] != NULL; ++i) { +- if (oscap_strcmp(requires[i], "") == 0) +- continue; +- +- if (callback(requires[i], cbarg) == 0) { +- get_all_dependencies_by_unit(conn, requires[i], +- callback, cbarg, +- include_requires, include_wants); +- } else { +- free(requires); +- free(requires_s); +- free(path); +- return; +- } +- } +- free(requires); +- } +- free(requires_s); +- } +- +- if (include_wants) { +- char *wants_s = get_property_by_unit_path(conn, path, "Wants"); +- if (wants_s) +- { +- char **wants = oscap_split(wants_s, ", "); +- for (int i = 0; wants[i] != NULL; ++i) { +- if (oscap_strcmp(wants[i], "") == 0) +- continue; +- +- if (callback(wants[i], cbarg) == 0) { +- get_all_dependencies_by_unit(conn, wants[i], +- callback, cbarg, +- include_requires, include_wants); +- } else { +- free(wants); +- free(wants_s); +- free(path); +- return; +- } +- } +- free(wants); +- } +- free(wants_s); +- } ++ process_unit_property("Requires", conn, path, item, visited_units); ++ process_unit_property("Wants", conn, path, item, visited_units); + + free(path); + } + +-static int dependency_callback(const char *dependency, void *cbarg) +-{ +- SEXP_t *item = (SEXP_t *)cbarg; +- SEXP_t *se_dependency = SEXP_string_new(dependency, strlen(dependency)); +- probe_item_ent_add(item, "dependency", NULL, se_dependency); +- return 0; +-} +- + static int unit_callback(const char *unit, void *cbarg) + { + struct unit_callback_vars *vars = (struct unit_callback_vars *)cbarg; +@@ -221,8 +200,9 @@ static int unit_callback(const char *unit, void *cbarg) + "unit", OVAL_DATATYPE_SEXP, se_unit, + NULL); + +- get_all_dependencies_by_unit(vars->dbus_conn, unit, +- dependency_callback, item, true, true); ++ struct oscap_htable *visited_units = oscap_htable_new(); ++ get_all_dependencies_by_unit(vars->dbus_conn, unit, item, visited_units); ++ oscap_htable_free(visited_units, NULL); + + probe_item_collect(vars->ctx, item); + SEXP_free(se_unit); diff --git a/SOURCES/openscap-1.3.3-textfilecontent-crash.patch b/SOURCES/openscap-1.3.3-textfilecontent-crash.patch new file mode 100644 index 0000000..4ee29c6 --- /dev/null +++ b/SOURCES/openscap-1.3.3-textfilecontent-crash.patch @@ -0,0 +1,522 @@ +diff --git a/docs/developer/developer.adoc b/docs/developer/developer.adoc +index 08273e24d..823a1504e 100644 +--- a/docs/developer/developer.adoc ++++ b/docs/developer/developer.adoc +@@ -317,6 +317,8 @@ behaviour. + + * *OSCAP_FULL_VALIDATION=1* - validate all exported documents (slower) + * *SEXP_VALIDATE_DISABLE=1* - do not validate SEXP expressions (faster) ++* *OSCAP_PCRE_EXEC_RECURSION_LIMIT* - override default recursion limit ++ for match in pcre_exec call in textfilecontent(54) probes. + + + +diff --git a/src/OVAL/probes/independent/textfilecontent54_probe.c b/src/OVAL/probes/independent/textfilecontent54_probe.c +index 1c449833f..3053f5d95 100644 +--- a/src/OVAL/probes/independent/textfilecontent54_probe.c ++++ b/src/OVAL/probes/independent/textfilecontent54_probe.c +@@ -52,68 +52,11 @@ + #include <probe/option.h> + #include <oval_fts.h> + #include "common/debug_priv.h" ++#include "common/util.h" + #include "textfilecontent54_probe.h" + + #define FILE_SEPARATOR '/' + +-static int get_substrings(char *str, int *ofs, pcre *re, int want_substrs, char ***substrings) { +- int i, ret, rc; +- int ovector[60], ovector_len = sizeof (ovector) / sizeof (ovector[0]); +- char **substrs; +- +- // todo: max match count check +- +- for (i = 0; i < ovector_len; ++i) +- ovector[i] = -1; +- +-#if defined(OS_SOLARIS) +- rc = pcre_exec(re, NULL, str, strlen(str), *ofs, PCRE_NO_UTF8_CHECK, ovector, ovector_len); +-#else +- rc = pcre_exec(re, NULL, str, strlen(str), *ofs, 0, ovector, ovector_len); +-#endif +- +- if (rc < -1) { +- dE("Function pcre_exec() failed to match a regular expression with return code %d on string '%s'.", rc, str); +- return rc; +- } else if (rc == -1) { +- /* no match */ +- return 0; +- } +- +- *ofs = (*ofs == ovector[1]) ? ovector[1] + 1 : ovector[1]; +- +- if (!want_substrs) { +- /* just report successful match */ +- return 1; +- } +- +- ret = 0; +- if (rc == 0) { +- /* vector too small */ +- // todo: report partial results +- rc = ovector_len / 3; +- } +- +- substrs = malloc(rc * sizeof (char *)); +- for (i = 0; i < rc; ++i) { +- int len; +- char *buf; +- +- if (ovector[2 * i] == -1) +- continue; +- len = ovector[2 * i + 1] - ovector[2 * i]; +- buf = malloc(len + 1); +- memcpy(buf, str + ovector[2 * i], len); +- buf[len] = '\0'; +- substrs[ret] = buf; +- ++ret; +- } +- +- *substrings = substrs; +- +- return ret; +-} +- + static SEXP_t *create_item(const char *path, const char *filename, char *pattern, + int instance, char **substrs, int substr_cnt, oval_schema_version_t over) + { +@@ -260,7 +203,7 @@ static int process_file(const char *prefix, const char *path, const char *file, + want_instance = 0; + + SEXP_free(next_inst); +- substr_cnt = get_substrings(buf, &ofs, pfd->compiled_regex, want_instance, &substrs); ++ substr_cnt = oscap_get_substrings(buf, &ofs, pfd->compiled_regex, want_instance, &substrs); + + if (substr_cnt < 0) { + SEXP_t *msg; +diff --git a/src/OVAL/probes/independent/textfilecontent_probe.c b/src/OVAL/probes/independent/textfilecontent_probe.c +index 9abf8fcc3..988a6471d 100644 +--- a/src/OVAL/probes/independent/textfilecontent_probe.c ++++ b/src/OVAL/probes/independent/textfilecontent_probe.c +@@ -71,63 +71,11 @@ + #include <probe/option.h> + #include <oval_fts.h> + #include "common/debug_priv.h" ++#include "common/util.h" + #include "textfilecontent_probe.h" + + #define FILE_SEPARATOR '/' + +-static int get_substrings(char *str, pcre *re, int want_substrs, char ***substrings) { +- int i, ret, rc; +- int ovector[60], ovector_len = sizeof (ovector) / sizeof (ovector[0]); +- +- // todo: max match count check +- +- for (i = 0; i < ovector_len; ++i) +- ovector[i] = -1; +- +- rc = pcre_exec(re, NULL, str, strlen(str), 0, 0, +- ovector, ovector_len); +- +- if (rc < -1) { +- return -1; +- } else if (rc == -1) { +- /* no match */ +- return 0; +- } else if(!want_substrs) { +- /* just report successful match */ +- return 1; +- } +- +- char **substrs; +- +- ret = 0; +- if (rc == 0) { +- /* vector too small */ +- rc = ovector_len / 3; +- } +- +- substrs = malloc(rc * sizeof (char *)); +- for (i = 0; i < rc; ++i) { +- int len; +- char *buf; +- +- if (ovector[2 * i] == -1) +- continue; +- len = ovector[2 * i + 1] - ovector[2 * i]; +- buf = malloc(len + 1); +- memcpy(buf, str + ovector[2 * i], len); +- buf[len] = '\0'; +- substrs[ret] = buf; +- ++ret; +- } +- /* +- if (ret < rc) +- substrs = realloc(substrs, ret * sizeof (char *)); +- */ +- *substrings = substrs; +- +- return ret; +-} +- + static SEXP_t *create_item(const char *path, const char *filename, char *pattern, + int instance, char **substrs, int substr_cnt, oval_schema_version_t over) + { +@@ -244,9 +192,10 @@ static int process_file(const char *prefix, const char *path, const char *filena + + int cur_inst = 0; + char line[4096]; ++ int ofs = 0; + + while (fgets(line, sizeof(line), fp) != NULL) { +- substr_cnt = get_substrings(line, re, 1, &substrs); ++ substr_cnt = oscap_get_substrings(line, &ofs, re, 1, &substrs); + if (substr_cnt > 0) { + int k; + SEXP_t *item; +diff --git a/src/common/util.c b/src/common/util.c +index 146b7bc39..8f130c50e 100644 +--- a/src/common/util.c ++++ b/src/common/util.c +@@ -30,11 +30,13 @@ + #include <limits.h> + #include <stdarg.h> + #include <math.h> ++#include <pcre.h> + + #include "util.h" + #include "_error.h" + #include "oscap.h" + #include "oscap_helpers.h" ++#include "debug_priv.h" + + #ifdef OS_WINDOWS + #include <stdlib.h> +@@ -45,6 +47,7 @@ + #endif + + #define PATH_SEPARATOR '/' ++#define OSCAP_PCRE_EXEC_RECURSION_LIMIT_DEFAULT 5000 + + int oscap_string_to_enum(const struct oscap_string_map *map, const char *str) + { +@@ -353,6 +356,76 @@ char *oscap_path_join(const char *path1, const char *path2) + return joined_path; + } + ++int oscap_get_substrings(char *str, int *ofs, pcre *re, int want_substrs, char ***substrings) { ++ int i, ret, rc; ++ int ovector[60], ovector_len = sizeof (ovector) / sizeof (ovector[0]); ++ char **substrs; ++ ++ // todo: max match count check ++ ++ for (i = 0; i < ovector_len; ++i) { ++ ovector[i] = -1; ++ } ++ ++ struct pcre_extra extra; ++ extra.match_limit_recursion = OSCAP_PCRE_EXEC_RECURSION_LIMIT_DEFAULT; ++ char *limit_str = getenv("OSCAP_PCRE_EXEC_RECURSION_LIMIT"); ++ if (limit_str != NULL) { ++ unsigned long limit; ++ if (sscanf(limit_str, "%lu", &limit) == 1) { ++ extra.match_limit_recursion = limit; ++ } ++ } ++ extra.flags = PCRE_EXTRA_MATCH_LIMIT_RECURSION; ++#if defined(OS_SOLARIS) ++ rc = pcre_exec(re, &extra, str, strlen(str), *ofs, PCRE_NO_UTF8_CHECK, ovector, ovector_len); ++#else ++ rc = pcre_exec(re, &extra, str, strlen(str), *ofs, 0, ovector, ovector_len); ++#endif ++ ++ if (rc < -1) { ++ dE("Function pcre_exec() failed to match a regular expression with return code %d on string '%s'.", rc, str); ++ return rc; ++ } else if (rc == -1) { ++ /* no match */ ++ return 0; ++ } ++ ++ *ofs = (*ofs == ovector[1]) ? ovector[1] + 1 : ovector[1]; ++ ++ if (!want_substrs) { ++ /* just report successful match */ ++ return 1; ++ } ++ ++ ret = 0; ++ if (rc == 0) { ++ /* vector too small */ ++ // todo: report partial results ++ rc = ovector_len / 3; ++ } ++ ++ substrs = malloc(rc * sizeof (char *)); ++ for (i = 0; i < rc; ++i) { ++ int len; ++ char *buf; ++ ++ if (ovector[2 * i] == -1) { ++ continue; ++ } ++ len = ovector[2 * i + 1] - ovector[2 * i]; ++ buf = malloc(len + 1); ++ memcpy(buf, str + ovector[2 * i], len); ++ buf[len] = '\0'; ++ substrs[ret] = buf; ++ ++ret; ++ } ++ ++ *substrings = substrs; ++ ++ return ret; ++} ++ + #ifdef OS_WINDOWS + char *oscap_windows_wstr_to_str(const wchar_t *wstr) + { +diff --git a/src/common/util.h b/src/common/util.h +index 50a1c746f..2592f3962 100644 +--- a/src/common/util.h ++++ b/src/common/util.h +@@ -31,6 +31,7 @@ + #include "public/oscap.h" + #include <stdarg.h> + #include <string.h> ++#include <pcre.h> + #include "oscap_export.h" + + #ifndef __attribute__nonnull__ +@@ -467,6 +468,19 @@ int oscap_strncasecmp(const char *s1, const char *s2, size_t n); + */ + char *oscap_strerror_r(int errnum, char *buf, size_t buflen); + ++/** ++ * Match a regular expression and return substrings. ++ * Caller is responsible for freeing the returned array. ++ * @param str subject string ++ * @param ofs starting offset in str ++ * @param re compiled regular expression ++ * @param want_substrs if non-zero, substrings will be returned ++ * @param substrings contains returned substrings ++ * @return count of matched substrings, 0 if no match ++ * negative value on failure ++ */ ++int oscap_get_substrings(char *str, int *ofs, pcre *re, int want_substrs, char ***substrings); ++ + #ifdef OS_WINDOWS + /** + * Convert wide character string to a C string (UTF-16 to UTF-8) +diff --git a/tests/probes/textfilecontent54/30-ospp-v42.rules b/tests/probes/textfilecontent54/30-ospp-v42.rules +new file mode 100644 +index 000000000..7ad0c254d +--- /dev/null ++++ b/tests/probes/textfilecontent54/30-ospp-v42.rules +@@ -0,0 +1,113 @@ ++## The purpose of these rules is to meet the requirements for Operating ++## System Protection Profile (OSPP)v4.2. These rules depends on having ++## 10-base-config.rules, 11-loginuid.rules, and 43-module-load.rules installed. ++ ++## Unsuccessful file creation (open with O_CREAT) ++-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-create ++-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-create ++-a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-create ++-a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-create ++-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-create ++-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-create ++-a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-create ++-a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-create ++-a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-create ++-a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-create ++-a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-create ++-a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-create ++ ++## Unsuccessful file modifications (open for write or truncate) ++-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification ++-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification ++-a always,exit -F arch=b32 -S open -F a1&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification ++-a always,exit -F arch=b64 -S open -F a1&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification ++-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification ++-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification ++-a always,exit -F arch=b32 -S open -F a1&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification ++-a always,exit -F arch=b64 -S open -F a1&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification ++-a always,exit -F arch=b32 -S truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification ++-a always,exit -F arch=b64 -S truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification ++-a always,exit -F arch=b32 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification ++-a always,exit -F arch=b64 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification ++ ++## Unsuccessful file access (any other opens) This has to go last. ++-a always,exit -F arch=b32 -S open,creat,truncate,ftruncate,openat,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-access ++-a always,exit -F arch=b64 -S open,creat,truncate,ftruncate,openat,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-access ++-a always,exit -F arch=b32 -S open,creat,truncate,ftruncate,openat,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-access ++-a always,exit -F arch=b64 -S open,creat,truncate,ftruncate,openat,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-access ++ ++## Unsuccessful file delete ++-a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-delete ++-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-delete ++-a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-delete ++-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-delete ++ ++## Unsuccessful permission change ++-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-perm-change ++-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-perm-change ++-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-perm-change ++-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-perm-change ++ ++## Unsuccessful ownership change ++-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-perm-change ++-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-perm-change ++-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-perm-change ++-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-perm-change ++ ++## User add delete modify. This is covered by pam. However, someone could ++## open a file and directly create or modify a user, so we'll watch passwd and ++## shadow for writes ++-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify ++-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify ++-a always,exit -F arch=b32 -S open -F a1&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify ++-a always,exit -F arch=b64 -S open -F a1&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify ++-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify ++-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify ++-a always,exit -F arch=b32 -S open -F a1&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify ++-a always,exit -F arch=b64 -S open -F a1&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify ++ ++## User enable and disable. This is entirely handled by pam. ++ ++## Group add delete modify. This is covered by pam. However, someone could ++## open a file and directly create or modify a user, so we'll watch group and ++## gshadow for writes ++-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&03 -F path=/etc/group -F auid>=1000 -F auid!=unset -F key=group-modify ++-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&03 -F path=/etc/group -F auid>=1000 -F auid!=unset -F key=group-modify ++-a always,exit -F arch=b32 -S open -F a1&03 -F path=/etc/group -F auid>=1000 -F auid!=unset -F key=group-modify ++-a always,exit -F arch=b64 -S open -F a1&03 -F path=/etc/group -F auid>=1000 -F auid!=unset -F key=group-modify ++-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&03 -F path=/etc/gshadow -F auid>=1000 -F auid!=unset -F key=group-modify ++-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&03 -F path=/etc/gshadow -F auid>=1000 -F auid!=unset -F key=group-modify ++-a always,exit -F arch=b32 -S open -F a1&03 -F path=/etc/gshadow -F auid>=1000 -F auid!=unset -F key=group-modify ++-a always,exit -F arch=b64 -S open -F a1&03 -F path=/etc/gshadow -F auid>=1000 -F auid!=unset -F key=group-modify ++ ++## Use of special rights for config changes. This would be use of setuid ++## programs that relate to user accts. This is not all setuid apps because ++## requirements are only for ones that affect system configuration. ++-a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ++-a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ++-a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ++-a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ++-a always,exit -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ++-a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ++-a always,exit -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ++-a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ++-a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ++-a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ++-a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ++ ++## Privilege escalation via su or sudo. This is entirely handled by pam. ++ ++## Audit log access ++-a always,exit -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail ++ ++## Software updates. This is entirely handled by rpm. ++ ++## System start and shutdown. This is entirely handled by systemd ++ ++## Kernel Module loading. This is handled in 43-module-load.rules ++ ++## Application invocation. The requirements list an optional requirement ++## FPT_SRP_EXT.1 Software Restriction Policies. This event is intended to ++## state results from that policy. This would be handled entirely by ++## that daemon. ++ +diff --git a/tests/probes/textfilecontent54/CMakeLists.txt b/tests/probes/textfilecontent54/CMakeLists.txt +index 87c6e215d..48bbde0e6 100644 +--- a/tests/probes/textfilecontent54/CMakeLists.txt ++++ b/tests/probes/textfilecontent54/CMakeLists.txt +@@ -1,4 +1,5 @@ + if(ENABLE_PROBES_INDEPENDENT) + add_oscap_test("all.sh") + add_oscap_test("test_filecontent_non_utf.sh") ++ add_oscap_test("test_recursion_limit.sh") + endif() +diff --git a/tests/probes/textfilecontent54/test_recursion_limit.oval.xml b/tests/probes/textfilecontent54/test_recursion_limit.oval.xml +new file mode 100644 +index 000000000..6f6a5ba14 +--- /dev/null ++++ b/tests/probes/textfilecontent54/test_recursion_limit.oval.xml +@@ -0,0 +1,38 @@ ++<?xml version="1.0"?> ++<oval_definitions xmlns:oval-def="http://oval.mitre.org/XMLSchema/oval-definitions-5" xmlns:oval="http://oval.mitre.org/XMLSchema/oval-common-5" xmlns:ind="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ind-def="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" xmlns:unix-def="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" xmlns:lin-def="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5" xsi:schemaLocation="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix unix-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#independent independent-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#linux linux-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5 oval-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-common-5 oval-common-schema.xsd"> ++ <generator> ++ <oval:schema_version>5.11.1</oval:schema_version> ++ <oval:timestamp>0001-01-01T00:00:00+00:00</oval:timestamp> ++ </generator> ++ ++ <definitions> ++ <definition class="compliance" version="1" id="oval:x:def:1"> ++ <metadata> ++ <title>The regular expression and the provided file should exceed recursion limits within pcre_exec used in the probe and cause a segfault.</title> ++ <description>x</description> ++ <affected family="unix"> ++ <platform>x</platform> ++ </affected> ++ </metadata> ++ <criteria> ++ <criterion test_ref="oval:x:tst:1" comment="always pass"/> ++ </criteria> ++ </definition> ++ </definitions> ++ ++ <tests> ++ <ind:textfilecontent54_test id="oval:x:tst:1" version="1" comment="Match 3 audit rules" check="all"> ++ <ind:object object_ref="oval:x:obj:1"/> ++ </ind:textfilecontent54_test> ++ </tests> ++ ++ <objects> ++ <ind:textfilecontent54_object id="oval:x:obj:1" version="1" comment="Object representing file"> ++ <ind:path>/tmp</ind:path> ++ <ind:filename>30-ospp-v42.rules</ind:filename> ++ <ind:pattern operation="pattern match">-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-create(?:[^.]|\.\s)*-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification(?:[^.]|\.\s)*-a always,exit -F arch=b32 -S open,creat,truncate,ftruncate,openat,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-access</ind:pattern> ++ <ind:instance datatype="int" operation="greater than or equal">1</ind:instance> ++ </ind:textfilecontent54_object> ++ </objects> ++ ++</oval_definitions> +diff --git a/tests/probes/textfilecontent54/test_recursion_limit.sh b/tests/probes/textfilecontent54/test_recursion_limit.sh +new file mode 100755 +index 000000000..2619dafdd +--- /dev/null ++++ b/tests/probes/textfilecontent54/test_recursion_limit.sh +@@ -0,0 +1,31 @@ ++#!/usr/bin/env bash ++ ++set -e -o pipefail ++ ++. $builddir/tests/test_common.sh ++ ++probecheck "textfilecontent54" || exit 255 ++ ++cp $srcdir/30-ospp-v42.rules /tmp ++ ++name=$(basename $0 .sh) ++input=$srcdir/$name.oval.xml ++result=$(mktemp) ++stdout=$(mktemp) ++stderr=$(mktemp) ++ ++$OSCAP oval eval --results $result $input > $stdout 2> $stderr ++ ++grep -q "Function pcre_exec() failed to match a regular expression with return code -21" $stderr ++ ++assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:1" and @result="error"]' ++ ++co='/oval_results/results/system/oval_system_characteristics/collected_objects' ++assert_exists 1 $co'/object[@flag="error"]' ++assert_exists 1 $co'/object/message[@level="error"]' ++assert_exists 1 $co'/object/message[text()="Regular expression pattern match failed in file /tmp/30-ospp-v42.rules with error -21."]' ++ ++rm -f /tmp/30-ospp-v42.rules ++rm -f $result ++rm -f $stdout ++rm -f $stderr diff --git a/SPECS/openscap.spec b/SPECS/openscap.spec index c1e87db..4007e65 100644 --- a/SPECS/openscap.spec +++ b/SPECS/openscap.spec @@ -1,6 +1,6 @@ Name: openscap Version: 1.3.2 -Release: 6%{?dist} +Release: 9%{?dist} Summary: Set of open source libraries enabling integration of the SCAP line of standards Group: System Environment/Libraries License: LGPLv2+ @@ -13,6 +13,14 @@ Patch3: 03-fix-cmake-test-for-libcap-xattr-h.patch Patch4: 04-oscap-podman-detect-ambiguous-targets.patch Patch5: openscap-1.3.2-covscan_ux_fix.patch Patch6: openscap-1.3.3-fix-cmake-findacl.patch +Patch7: openscap-1.3.3-systemdunit-segfault.patch +Patch8: openscap-1.3.3-textfilecontent-crash.patch +Patch9: openscap-1.3.3-ansible-newlines.patch +Patch10: openscap-1.2.18-oscap-ssh-sudo.patch +Patch11: openscap-1.3.3-remove-useless-warnings.patch +Patch12: openscap-1.3.3-remove-useless-warnings-tests.patch +Patch13: openscap-1.3.3-rpmverifyfile-tests.patch +Patch14: openscap-1.3.3-generate-guide-tailoring.patch # END PATCHES FOR 1.3.2 BuildRequires: cmake >= 2.6 BuildRequires: swig libxml2-devel libxslt-devel perl-generators perl-XML-Parser @@ -137,6 +145,14 @@ for developing applications that use %{name}-engine-sce. %patch4 -p1 %patch5 -p1 %patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 mkdir build %build @@ -222,6 +238,19 @@ rm -rf $RPM_BUILD_ROOT %{_bindir}/oscap-run-sce-script %changelog +* Fri Mar 27 2020 Jan Černý <jcerny@redhat.com> - 1.3.2-9 +- Generate HTML guides from tailored profiles (RHBZ#1743835) + +* Wed Mar 18 2020 Jan Černý <jcerny@redhat.com> - 1.3.2-8 +- Fix tests for rpmverifyfileprobe (RHBZ#1814726) + +* Thu Mar 12 2020 Jan Černý <jcerny@redhat.com> - 1.3.2-7 +- Fix segmentation fault in systemdunitdependency_probe (RHBZ#1793050) +- Fix crash in textfilecontent probe (RHBZ#1686467) +- Do not drop empty lines from Ansible remediations (RHBZ#1795563) +- Fix oscap-ssh --sudo (RHBZ#1803116) +- Remove useless warnings (RHBZ#1764139) + * Thu Jan 23 2020 Jan Černý <jcerny@redhat.com> - 1.3.2-6 - Fix FindACL.cmake