From b62069e6a755988438c4ad750a24fe033fb64ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= Date: Tue, 14 Nov 2023 16:42:39 +0100 Subject: [PATCH 01/21] Avoid a cast This cast and rename of the `void *arg` to `struct pfdata *pfd` isn't necessary, we can change the argument type to the actual type, because the function is called only once and therefore always with an argument of the `struct pfdata *` type. --- src/OVAL/probes/independent/textfilecontent54_probe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/OVAL/probes/independent/textfilecontent54_probe.c b/src/OVAL/probes/independent/textfilecontent54_probe.c index 4c6c9a1fa1..f1316fcc5d 100644 --- a/src/OVAL/probes/independent/textfilecontent54_probe.c +++ b/src/OVAL/probes/independent/textfilecontent54_probe.c @@ -118,9 +118,8 @@ struct pfdata { oscap_pcre_t *compiled_regex; }; -static int process_file(const char *prefix, const char *path, const char *file, void *arg, oval_schema_version_t over) +static int process_file(const char *prefix, const char *path, const char *file, struct pfdata *pfd, oval_schema_version_t over) { - struct pfdata *pfd = (struct pfdata *) arg; int ret = 0, path_len, file_len, cur_inst = 0, fd = -1, substr_cnt, buf_size = 0, buf_used = 0, ofs = 0, buf_inc = 4096; char **substrs = NULL; From 1e4b8aecc1cc08c8f5226ed8c8ca8578fadc20a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= Date: Thu, 16 Nov 2023 15:33:36 +0100 Subject: [PATCH 02/21] Add ability to block paths People will be able to tell probes to skip certain paths during content evaluation. They can specify a list of paths by setting the `OSCAP_PROBE_IGNORE_PATHS` environment variable. The paths in this list should be separated by a colon. --- docs/manual/manual.adoc | 1 + .../independent/textfilecontent54_probe.c | 9 +++- src/OVAL/probes/probe-api.c | 48 +++++++++++++++++++ src/OVAL/probes/probe/probe.h | 1 + src/OVAL/probes/probe/worker.c | 18 +++++++ src/OVAL/probes/public/probe-api.h | 8 ++++ src/OVAL/probes/unix/file_probe.c | 8 +++- 7 files changed, 89 insertions(+), 4 deletions(-) diff --git a/docs/manual/manual.adoc b/docs/manual/manual.adoc index ab069a3708..33f9091d49 100644 --- a/docs/manual/manual.adoc +++ b/docs/manual/manual.adoc @@ -1619,6 +1619,7 @@ not considered local by the scanner: * `SOURCE_DATE_EPOCH` - Timestamp in seconds since epoch. This timestamp will be used instead of the current time to populate `timestamp` attributes in SCAP source data streams created by `oscap ds sds-compose` sub-module. This is used for reproducible builds of data streams. * `OSCAP_PROBE_MEMORY_USAGE_RATIO` - maximum memory usage ratio (used/total) for OpenSCAP probes, default: 0.1 * `OSCAP_PROBE_MAX_COLLECTED_ITEMS` - maximal count of collected items by OpenSCAP probe for a single OVAL object evaluation +* `OSCAP_PROBE_IGNORE_PATHS` - Skip given paths during evaluation. If multiple paths should be skipped they need to be separated by a colon. Also, OpenSCAP uses `libcurl` library which also can be configured using environment variables. See https://curl.se/libcurl/c/libcurl-env.html[the list of libcurl environment variables]. diff --git a/src/OVAL/probes/independent/textfilecontent54_probe.c b/src/OVAL/probes/independent/textfilecontent54_probe.c index f1316fcc5d..34199853fa 100644 --- a/src/OVAL/probes/independent/textfilecontent54_probe.c +++ b/src/OVAL/probes/independent/textfilecontent54_probe.c @@ -53,6 +53,8 @@ #include "common/debug_priv.h" #include "common/util.h" #include "common/oscap_pcre.h" +#include "common/list.h" + #include "textfilecontent54_probe.h" #define FILE_SEPARATOR '/' @@ -118,7 +120,7 @@ struct pfdata { oscap_pcre_t *compiled_regex; }; -static int process_file(const char *prefix, const char *path, const char *file, struct pfdata *pfd, oval_schema_version_t over) +static int process_file(const char *prefix, const char *path, const char *file, struct pfdata *pfd, oval_schema_version_t over, struct oscap_list *blocked_paths) { int ret = 0, path_len, file_len, cur_inst = 0, fd = -1, substr_cnt, buf_size = 0, buf_used = 0, ofs = 0, buf_inc = 4096; @@ -143,6 +145,9 @@ static int process_file(const char *prefix, const char *path, const char *file, memcpy(whole_path + path_len, file, file_len + 1); + if (probe_path_is_blocked(whole_path, blocked_paths)) { + goto cleanup; + } /* * If stat() fails, don't report an error and just skip the file. * This is an expected situation, because the fts_*() functions @@ -360,7 +365,7 @@ int textfilecontent54_probe_main(probe_ctx *ctx, void *arg) if (ofts_ent->fts_info == FTS_F || ofts_ent->fts_info == FTS_SL) { // todo: handle return code - process_file(prefix, ofts_ent->path, ofts_ent->file, &pfd, over); + process_file(prefix, ofts_ent->path, ofts_ent->file, &pfd, over, ctx->blocked_paths); } oval_ftsent_free(ofts_ent); } diff --git a/src/OVAL/probes/probe-api.c b/src/OVAL/probes/probe-api.c index 462494cf3b..9a661dbb84 100644 --- a/src/OVAL/probes/probe-api.c +++ b/src/OVAL/probes/probe-api.c @@ -1794,4 +1794,52 @@ SEXP_t *probe_obj_getmask(SEXP_t *obj) SEXP_free(objents); return (mask); } + +static bool path_startswith(const char *path, const char *prefix) +{ + bool res = true; + const char *del = "/"; + char *path_dup = oscap_strdup(path); + char **path_split = oscap_split(path_dup, del); + char *prefix_dup = oscap_strdup(prefix); + char **prefix_split = oscap_split(prefix_dup, del); + int i = 0, j = 0; + while (prefix_split[i] && path_split[j]) { + if (!strcmp(prefix_split[i], "")) { + ++i; + continue; + } + if (!strcmp(path_split[j], "")) { + ++j; + continue; + } + if (strcmp(prefix_split[i], path_split[j])) { + res = false; + break; + } + ++i; + ++j; + } + free(path_dup); + free(path_split); + free(prefix_dup); + free(prefix_split); + return res; +} + +bool probe_path_is_blocked(const char *path, struct oscap_list *blocked_paths) +{ + bool res = false; + struct oscap_iterator *it = oscap_iterator_new(blocked_paths); + while (oscap_iterator_has_more(it)) { + const char *item = oscap_iterator_next(it); + if (path_startswith(path, item)) { + res = true; + break; + } + } + oscap_iterator_free(it); + return res; +} + /// @} diff --git a/src/OVAL/probes/probe/probe.h b/src/OVAL/probes/probe/probe.h index 20244fab27..e7b00ae6ad 100644 --- a/src/OVAL/probes/probe/probe.h +++ b/src/OVAL/probes/probe/probe.h @@ -94,6 +94,7 @@ struct probe_ctx { int offline_mode; double max_mem_ratio; size_t max_collected_items; + struct oscap_list *blocked_paths; }; typedef enum { diff --git a/src/OVAL/probes/probe/worker.c b/src/OVAL/probes/probe/worker.c index 526bbbe78e..c8ef869829 100644 --- a/src/OVAL/probes/probe/worker.c +++ b/src/OVAL/probes/probe/worker.c @@ -972,6 +972,19 @@ static SEXP_t *probe_set_eval(probe_t *probe, SEXP_t *set, size_t depth) return result; } +static void _add_blocked_paths(struct oscap_list *bpaths) +{ + char *envar = getenv("OSCAP_PROBE_IGNORE_PATHS"); + if (envar == NULL) { + return; + } + char **paths = oscap_split(envar, ":"); + for (int i = 0; paths[i]; ++i) { + oscap_list_add(bpaths, strdup(paths[i])); + } + free(paths); +} + /** * Worker thread function. This functions handles the evalution of objects and sets. * @param msg_in SEAP message with the request which contains the object to be evaluated @@ -1083,6 +1096,9 @@ SEXP_t *probe_worker(probe_t *probe, SEAP_msg_t *msg_in, int *ret) } } + pctx.blocked_paths = oscap_list_new(); + _add_blocked_paths(pctx.blocked_paths); + /* simple object */ pctx.icache = probe->icache; pctx.filters = probe_prepare_filters(probe, probe_in); @@ -1142,6 +1158,7 @@ SEXP_t *probe_worker(probe_t *probe, SEAP_msg_t *msg_in, int *ret) SEXP_free(pctx.filters); SEXP_free(probe_in); SEXP_free(mask); + oscap_list_free(pctx.blocked_paths, free); *ret = PROBE_EUNKNOWN; return (NULL); } @@ -1181,6 +1198,7 @@ SEXP_t *probe_worker(probe_t *probe, SEAP_msg_t *msg_in, int *ret) } SEXP_free(pctx.filters); + oscap_list_free(pctx.blocked_paths, free); } SEXP_free(probe_in); diff --git a/src/OVAL/probes/public/probe-api.h b/src/OVAL/probes/public/probe-api.h index c1178956f2..fbce8d27d2 100644 --- a/src/OVAL/probes/public/probe-api.h +++ b/src/OVAL/probes/public/probe-api.h @@ -68,6 +68,7 @@ #include #include "sexp-types.h" #include "oscap_export.h" +#include "list.h" /* * items @@ -538,4 +539,11 @@ OSCAP_API oval_schema_version_t probe_obj_get_platform_schema_version(const SEXP */ OSCAP_API SEXP_t *probe_obj_getmask(SEXP_t *obj); +/** + * Check if the given path matches any of the paths in the blocked paths list + * @param path path to be examined + * @param blocked_paths list of blocked paths + */ +OSCAP_API bool probe_path_is_blocked(const char *path, struct oscap_list *blocked_paths); + /// @} diff --git a/src/OVAL/probes/unix/file_probe.c b/src/OVAL/probes/unix/file_probe.c index 07f86aee4f..f3adfcd661 100644 --- a/src/OVAL/probes/unix/file_probe.c +++ b/src/OVAL/probes/unix/file_probe.c @@ -304,7 +304,7 @@ static SEXP_t *has_extended_acl(const char *path) #endif } -static int file_cb(const char *prefix, const char *p, const char *f, void *ptr, oval_schema_version_t over, struct ID_cache *cache, struct gr_sexps *grs, SEXP_t *gr_lastpath) +static int file_cb(const char *prefix, const char *p, const char *f, void *ptr, oval_schema_version_t over, struct ID_cache *cache, struct gr_sexps *grs, SEXP_t *gr_lastpath, struct oscap_list *blocked_paths) { char path_buffer[PATH_MAX]; SEXP_t *item; @@ -325,6 +325,10 @@ static int file_cb(const char *prefix, const char *p, const char *f, void *ptr, st_path = path_buffer; } + if (probe_path_is_blocked(st_path, blocked_paths)) { + return 0; + } + char *st_path_with_prefix = oscap_path_join(prefix, st_path); if (lstat(st_path_with_prefix, &st) == -1) { dD("lstat failed when processing %s: errno=%u, %s.", st_path, errno, strerror (errno)); @@ -509,7 +513,7 @@ int file_probe_main(probe_ctx *ctx, void *mutex) if ((ofts = oval_fts_open_prefixed(prefix, path, filename, filepath, behaviors, probe_ctx_getresult(ctx))) != NULL) { while ((ofts_ent = oval_fts_read(ofts)) != NULL) { - if (file_cb(prefix, ofts_ent->path, ofts_ent->file, &cbargs, over, cache, grs, &gr_lastpath) != 0) { + if (file_cb(prefix, ofts_ent->path, ofts_ent->file, &cbargs, over, cache, grs, &gr_lastpath, ctx->blocked_paths) != 0) { oval_ftsent_free(ofts_ent); break; } From 63d2a79067a089f64ee384a5cb4bb29d63d0fe7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= Date: Wed, 29 Nov 2023 14:33:51 +0100 Subject: [PATCH 03/21] Add a simple test for the skip paths feature --- tests/API/OVAL/CMakeLists.txt | 1 + tests/API/OVAL/skip_paths/CMakeLists.txt | 1 + tests/API/OVAL/skip_paths/test_skip_paths.sh | 34 ++++++++++ tests/API/OVAL/skip_paths/test_skip_paths.xml | 65 +++++++++++++++++++ 4 files changed, 101 insertions(+) create mode 100644 tests/API/OVAL/skip_paths/CMakeLists.txt create mode 100755 tests/API/OVAL/skip_paths/test_skip_paths.sh create mode 100644 tests/API/OVAL/skip_paths/test_skip_paths.xml diff --git a/tests/API/OVAL/CMakeLists.txt b/tests/API/OVAL/CMakeLists.txt index a653f593f5..5eca0c3ad3 100644 --- a/tests/API/OVAL/CMakeLists.txt +++ b/tests/API/OVAL/CMakeLists.txt @@ -8,5 +8,6 @@ add_oscap_test("test_api_oval.sh") add_subdirectory("glob_to_regex") add_subdirectory("report_variable_values") add_subdirectory("schema_version") +add_subdirectory("skip_paths") add_subdirectory("unittests") add_subdirectory("validate") diff --git a/tests/API/OVAL/skip_paths/CMakeLists.txt b/tests/API/OVAL/skip_paths/CMakeLists.txt new file mode 100644 index 0000000000..c4452fc23c --- /dev/null +++ b/tests/API/OVAL/skip_paths/CMakeLists.txt @@ -0,0 +1 @@ +add_oscap_test("test_skip_paths.sh") diff --git a/tests/API/OVAL/skip_paths/test_skip_paths.sh b/tests/API/OVAL/skip_paths/test_skip_paths.sh new file mode 100755 index 0000000000..02013ce37a --- /dev/null +++ b/tests/API/OVAL/skip_paths/test_skip_paths.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +. $builddir/tests/test_common.sh + +set -e -o pipefail + +result=$(mktemp) +root="/tmp/oscap_test_skip_paths" +mkdir -p "$root/a" +touch "$root/a/x" +mkdir -p "$root/b" +touch "$root/b/y" +mkdir -p "$root/c" +touch "$root/c/z" +# oscap probes will skip directories "b" and "c" +export OSCAP_PROBE_IGNORE_PATHS="$root/b:$root/c" +$OSCAP oval eval --results $result "$srcdir/test_skip_paths.xml" +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:1" and @result="true"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:1" and @flag="complete"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/system_data/unix-sys:file_item' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/system_data/unix-sys:file_item/unix-sys:filepath[text()="/tmp/oscap_test_skip_paths/a/x"]' +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:2" and @result="true"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:2" and @flag="does not exist"]' +assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/unix-sys:file_item/unix-sys:filepath[text()="/tmp/oscap_test_skip_paths/b/y"]' +assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/unix-sys:file_item/unix-sys:filepath[text()="/tmp/oscap_test_skip_paths/c/z"]' +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:3" and @result="true"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:3" and @flag="complete"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:textfilecontent_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/a/x"]' +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:4" and @result="true"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:4" and @flag="does not exist"]' +assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:textfilecontent_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/b/y"]' +assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:textfilecontent_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/c/z"]' +rm -f $result +rm -rf "$root" diff --git a/tests/API/OVAL/skip_paths/test_skip_paths.xml b/tests/API/OVAL/skip_paths/test_skip_paths.xml new file mode 100644 index 0000000000..b679c9bb7b --- /dev/null +++ b/tests/API/OVAL/skip_paths/test_skip_paths.xml @@ -0,0 +1,65 @@ + + + + 5.11.1 + 2009-05-21T11:46:00-04:00 + + + + <description/></metadata> + <criteria operator="AND"> + <criterion test_ref="oval:x:tst:1"/> + </criteria> + </definition> + <definition class="compliance" version="1" id="oval:x:def:2"> + <metadata><title/><description/></metadata> + <criteria operator="AND"> + <criterion test_ref="oval:x:tst:2"/> + </criteria> + </definition> + <definition class="compliance" version="1" id="oval:x:def:3"> + <metadata><title/><description/></metadata> + <criteria operator="AND"> + <criterion test_ref="oval:x:tst:3"/> + </criteria> + </definition> + <definition class="compliance" version="1" id="oval:x:def:4"> + <metadata><title/><description/></metadata> + <criteria operator="AND"> + <criterion test_ref="oval:x:tst:4"/> + </criteria> + </definition> + </definitions> + <tests> + <file_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" check_existence="at_least_one_exists" version="1" id="oval:x:tst:1" check="all" comment="a file"> + <object object_ref="oval:x:obj:1"/> + </file_test> + <file_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" check_existence="none_exist" version="1" id="oval:x:tst:2" check="all" comment="a file"> + <object object_ref="oval:x:obj:2"/> + </file_test> + <textfilecontent54_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" check_existence="at_least_one_exists" version="1" id="oval:x:tst:3" check="all" comment="a file"> + <object object_ref="oval:x:obj:3"/> + </textfilecontent54_test> + <textfilecontent54_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" check_existence="none_exist" version="1" id="oval:x:tst:4" check="all" comment="a file"> + <object object_ref="oval:x:obj:4"/> + </textfilecontent54_test> + </tests> + <objects> + <file_object xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" version="1" id="oval:x:obj:1"> + <filepath>/tmp/oscap_test_skip_paths/a/x</filepath> + </file_object> + <file_object xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" version="1" id="oval:x:obj:2"> + <filepath>/tmp/oscap_test_skip_paths/b/y</filepath> + </file_object> + <textfilecontent54_object xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" version="1" id="oval:x:obj:3"> + <filepath>/tmp/oscap_test_skip_paths/a/x</filepath> + <pattern>^.*$</pattern> + <instance datatype="int" operation="greater than or equal">1</instance> + </textfilecontent54_object> + <textfilecontent54_object xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" version="1" id="oval:x:obj:4"> + <filepath>/tmp/oscap_test_skip_paths/b/y</filepath> + <pattern>^.*$</pattern> + <instance datatype="int" operation="greater than or equal">1</instance> + </textfilecontent54_object> + </objects> +</oval_definitions> From 2b367b6ed6f894e77e5453f85110bc96e512d5bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Mon, 18 Dec 2023 15:16:36 +0100 Subject: [PATCH 04/21] Use blocked paths in filehash58 probe --- src/OVAL/probes/independent/filehash58_probe.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/OVAL/probes/independent/filehash58_probe.c b/src/OVAL/probes/independent/filehash58_probe.c index 55fbbf9b2e..e7facd4b3c 100644 --- a/src/OVAL/probes/independent/filehash58_probe.c +++ b/src/OVAL/probes/independent/filehash58_probe.c @@ -152,6 +152,10 @@ static int filehash58_cb(const char *prefix, const char *p, const char *f, const memcpy (pbuf + plen, f, sizeof (char) * flen); pbuf[plen+flen] = '\0'; + if (probe_path_is_blocked(pbuf, ctx->blocked_paths)) { + return 0; + } + /* * Open the file */ From aa9ffd06caf5a0c65f2e17451e665658f34895bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Mon, 18 Dec 2023 15:16:46 +0100 Subject: [PATCH 05/21] Use blocked paths in filehash probe --- src/OVAL/probes/independent/filehash_probe.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/OVAL/probes/independent/filehash_probe.c b/src/OVAL/probes/independent/filehash_probe.c index 6d8780dc95..014b486abc 100644 --- a/src/OVAL/probes/independent/filehash_probe.c +++ b/src/OVAL/probes/independent/filehash_probe.c @@ -105,6 +105,10 @@ static int filehash_cb (const char *prefix, const char *p, const char *f, probe_ pbuf[plen+flen] = '\0'; include_filepath = oval_schema_version_cmp(over, OVAL_SCHEMA_VERSION(5.6)) >= 0; + if (probe_path_is_blocked(pbuf, ctx->blocked_paths)) { + return 0; + } + /* * Open the file */ From a2201c1b5da40850cb112d471c121bffa5ce7693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Mon, 18 Dec 2023 15:20:24 +0100 Subject: [PATCH 06/21] Use blocked paths in textfilecontent probe --- src/OVAL/probes/independent/textfilecontent_probe.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/OVAL/probes/independent/textfilecontent_probe.c b/src/OVAL/probes/independent/textfilecontent_probe.c index 1f2f9bf2ea..54c9ab1be1 100644 --- a/src/OVAL/probes/independent/textfilecontent_probe.c +++ b/src/OVAL/probes/independent/textfilecontent_probe.c @@ -136,7 +136,7 @@ struct pfdata { probe_ctx *ctx; }; -static int process_file(const char *prefix, const char *path, const char *filename, void *arg, oval_schema_version_t over) +static int process_file(const char *prefix, const char *path, const char *filename, void *arg, oval_schema_version_t over, struct oscap_list *blocked_paths) { struct pfdata *pfd = (struct pfdata *) arg; int ret = 0, path_len, filename_len; @@ -170,6 +170,10 @@ static int process_file(const char *prefix, const char *path, const char *filena } memcpy(whole_path + path_len, filename, filename_len + 1); + if (probe_path_is_blocked(whole_path, blocked_paths)) { + goto cleanup; + } + /* * If stat() fails, don't report an error and just skip the file. * This is an expected situation, because the fts_*() functions @@ -294,7 +298,7 @@ int textfilecontent_probe_main(probe_ctx *ctx, void *arg) if (ofts_ent->fts_info == FTS_F || ofts_ent->fts_info == FTS_SL) { // todo: handle return code - process_file(prefix, ofts_ent->path, ofts_ent->file, &pfd, over); + process_file(prefix, ofts_ent->path, ofts_ent->file, &pfd, over, ctx->blocked_paths); } oval_ftsent_free(ofts_ent); } From 551f972df76d9cf0ca4166a0e135c0cf8a53899d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Mon, 18 Dec 2023 15:23:11 +0100 Subject: [PATCH 07/21] Avoid a cast This cast and rename of the `void *arg` to `struct pfdata *pfd` isn't necessary, we can change the argument type to the actual type, because the function is called only once and therefore always with an argument of the `struct pfdata *` type. --- src/OVAL/probes/independent/xmlfilecontent_probe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/OVAL/probes/independent/xmlfilecontent_probe.c b/src/OVAL/probes/independent/xmlfilecontent_probe.c index da74cb94e8..c2d1892162 100644 --- a/src/OVAL/probes/independent/xmlfilecontent_probe.c +++ b/src/OVAL/probes/independent/xmlfilecontent_probe.c @@ -142,9 +142,8 @@ static xmlDocPtr strip_ns(xmlDocPtr doc) return result; } -static int process_file(const char *prefix, const char *path, const char *filename, void *arg) +static int process_file(const char *prefix, const char *path, const char *filename, struct pfdata *pfd) { - struct pfdata *pfd = (struct pfdata *) arg; int ret = 0, path_len, filename_len; char *whole_path = NULL; xmlDoc *doc = NULL; From e4ea549a91585a4b332b81394c25255e779d3351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Mon, 18 Dec 2023 15:32:53 +0100 Subject: [PATCH 08/21] Use blocked paths in xmlfilecontent probe --- src/OVAL/probes/independent/xmlfilecontent_probe.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/OVAL/probes/independent/xmlfilecontent_probe.c b/src/OVAL/probes/independent/xmlfilecontent_probe.c index c2d1892162..6de5a62e30 100644 --- a/src/OVAL/probes/independent/xmlfilecontent_probe.c +++ b/src/OVAL/probes/independent/xmlfilecontent_probe.c @@ -142,7 +142,7 @@ static xmlDocPtr strip_ns(xmlDocPtr doc) return result; } -static int process_file(const char *prefix, const char *path, const char *filename, struct pfdata *pfd) +static int process_file(const char *prefix, const char *path, const char *filename, struct pfdata *pfd, struct oscap_list *blocked_paths) { int ret = 0, path_len, filename_len; char *whole_path = NULL; @@ -170,6 +170,10 @@ static int process_file(const char *prefix, const char *path, const char *filena memcpy(whole_path + path_len, filename, filename_len + 1); + if (probe_path_is_blocked(whole_path, blocked_paths)) { + goto cleanup; + } + if (prefix == NULL) { doc = xmlParseFile(whole_path); } else { @@ -392,7 +396,7 @@ int xmlfilecontent_probe_main(probe_ctx *ctx, void *arg) if ((ofts = oval_fts_open_prefixed(prefix, path_ent, filename_ent, filepath_ent, behaviors_ent, probe_ctx_getresult(ctx))) != NULL) { while ((ofts_ent = oval_fts_read(ofts)) != NULL) { - process_file(prefix, ofts_ent->path, ofts_ent->file, &pfd); + process_file(prefix, ofts_ent->path, ofts_ent->file, &pfd, ctx->blocked_paths); oval_ftsent_free(ofts_ent); } From 830ea1d9efdfb72f5dc4f5b39dd12f30b95ba266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Mon, 18 Dec 2023 15:36:37 +0100 Subject: [PATCH 09/21] Use blocked paths in yamlfilecontent probe --- src/OVAL/probes/independent/yamlfilecontent_probe.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c index f4698ff4d5..5e9417e789 100644 --- a/src/OVAL/probes/independent/yamlfilecontent_probe.c +++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c @@ -396,6 +396,9 @@ static int process_yaml_file(const char *prefix, const char *path, const char *f yaml_parser_initialize(&parser); char *filepath = oscap_path_join(path, filename); + if (probe_path_is_blocked(filepath, ctx->blocked_paths)) { + goto cleanup; + } char *filepath_with_prefix = oscap_path_join(prefix, filepath); FILE *yaml_file = fopen(filepath_with_prefix, "r"); From 65a40c53db623d39b5e4688ef8d5c8d4ee3c6ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Mon, 18 Dec 2023 15:45:18 +0100 Subject: [PATCH 10/21] Use blocked paths in fileextendedattribute probe --- src/OVAL/probes/unix/fileextendedattribute_probe.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/OVAL/probes/unix/fileextendedattribute_probe.c b/src/OVAL/probes/unix/fileextendedattribute_probe.c index ee853886a8..ba92a150ed 100644 --- a/src/OVAL/probes/unix/fileextendedattribute_probe.c +++ b/src/OVAL/probes/unix/fileextendedattribute_probe.c @@ -77,7 +77,7 @@ struct cbargs { }; #if defined(OS_FREEBSD) -static int file_cb(const char *prefix, const char *p, const char *f, void *ptr, SEXP_t *gr_lastpath) +static int file_cb(const char *prefix, const char *p, const char *f, void *ptr, SEXP_t *gr_lastpath, struct oscap_list *blocked_paths) { char path_buffer[PATH_MAX]; SEXP_t *item; @@ -110,6 +110,10 @@ static int file_cb(const char *prefix, const char *p, const char *f, void *ptr, st_path = path_buffer; } + if (probe_path_is_blocked(st_path, blocked_paths)) { + return 0; + } + char *st_path_with_prefix = oscap_path_join(prefix, st_path); /* update lastpath if needed */ @@ -205,7 +209,7 @@ static int file_cb(const char *prefix, const char *p, const char *f, void *ptr, } #else -static int file_cb(const char *prefix, const char *p, const char *f, void *ptr, SEXP_t *gr_lastpath) +static int file_cb(const char *prefix, const char *p, const char *f, void *ptr, SEXP_t *gr_lastpath, struct oscap_list *blocked_paths) { char path_buffer[PATH_MAX]; SEXP_t *item, xattr_name; @@ -231,6 +235,10 @@ static int file_cb(const char *prefix, const char *p, const char *f, void *ptr, SEXP_init(&xattr_name); + if (probe_path_is_blocked(st_path, blocked_paths)) { + return 0; + } + char *st_path_with_prefix = oscap_path_join(prefix, st_path); do { /* estimate the size of the buffer */ @@ -441,7 +449,7 @@ int fileextendedattribute_probe_main(probe_ctx *ctx, void *mutex) if ((ofts = oval_fts_open_prefixed(prefix, path, filename, filepath, behaviors, probe_ctx_getresult(ctx))) != NULL) { while ((ofts_ent = oval_fts_read(ofts)) != NULL) { - file_cb(prefix, ofts_ent->path, ofts_ent->file, &cbargs, &gr_lastpath); + file_cb(prefix, ofts_ent->path, ofts_ent->file, &cbargs, &gr_lastpath, ctx->blocked_paths); oval_ftsent_free(ofts_ent); } oval_fts_close(ofts); From 160494329dedacab643fa75a8a95ade645ced999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Mon, 18 Dec 2023 15:50:06 +0100 Subject: [PATCH 11/21] Use blocked paths in symlink probe --- src/OVAL/probes/unix/symlink_probe.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/OVAL/probes/unix/symlink_probe.c b/src/OVAL/probes/unix/symlink_probe.c index 1f0b13a06e..b3d5641e90 100644 --- a/src/OVAL/probes/unix/symlink_probe.c +++ b/src/OVAL/probes/unix/symlink_probe.c @@ -58,6 +58,10 @@ static int collect_symlink(SEXP_t *ent, probe_ctx *ctx) if (pathname == NULL) { return PROBE_EINVAL; } + if (probe_path_is_blocked(pathname, ctx->blocked_paths)) { + free(pathname); + return 0; + } if (lstat(pathname, &sb) == -1) { if (errno == ENOENT) { From 129a118bf88b2aaefe959ecb997218f7c20dbad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Mon, 18 Dec 2023 17:27:15 +0100 Subject: [PATCH 12/21] Add sensible comments --- tests/API/OVAL/skip_paths/test_skip_paths.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/API/OVAL/skip_paths/test_skip_paths.xml b/tests/API/OVAL/skip_paths/test_skip_paths.xml index b679c9bb7b..bca1c174b9 100644 --- a/tests/API/OVAL/skip_paths/test_skip_paths.xml +++ b/tests/API/OVAL/skip_paths/test_skip_paths.xml @@ -31,16 +31,16 @@ </definition> </definitions> <tests> - <file_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" check_existence="at_least_one_exists" version="1" id="oval:x:tst:1" check="all" comment="a file"> + <file_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" check_existence="at_least_one_exists" version="1" id="oval:x:tst:1" check="all" comment="read file from directory 'a' - should be read"> <object object_ref="oval:x:obj:1"/> </file_test> - <file_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" check_existence="none_exist" version="1" id="oval:x:tst:2" check="all" comment="a file"> + <file_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" check_existence="none_exist" version="1" id="oval:x:tst:2" check="all" comment="read file from directory 'b' - should be skip"> <object object_ref="oval:x:obj:2"/> </file_test> - <textfilecontent54_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" check_existence="at_least_one_exists" version="1" id="oval:x:tst:3" check="all" comment="a file"> + <textfilecontent54_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" check_existence="at_least_one_exists" version="1" id="oval:x:tst:3" check="all" comment="read file from directory 'a' - should be read"> <object object_ref="oval:x:obj:3"/> </textfilecontent54_test> - <textfilecontent54_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" check_existence="none_exist" version="1" id="oval:x:tst:4" check="all" comment="a file"> + <textfilecontent54_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" check_existence="none_exist" version="1" id="oval:x:tst:4" check="all" comment="read file from directory 'b' - should be skip"> <object object_ref="oval:x:obj:4"/> </textfilecontent54_test> </tests> From a033aef1489c525fe2f7938df0d79dc9552e1dd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Mon, 18 Dec 2023 17:38:57 +0100 Subject: [PATCH 13/21] Extend test_skip_paths Extend test_skip_paths to test the "skip selected paths" feature also in the filehash58 probe. --- tests/API/OVAL/skip_paths/test_skip_paths.sh | 7 +++++ tests/API/OVAL/skip_paths/test_skip_paths.xml | 26 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/tests/API/OVAL/skip_paths/test_skip_paths.sh b/tests/API/OVAL/skip_paths/test_skip_paths.sh index 02013ce37a..7cab277c4b 100755 --- a/tests/API/OVAL/skip_paths/test_skip_paths.sh +++ b/tests/API/OVAL/skip_paths/test_skip_paths.sh @@ -30,5 +30,12 @@ assert_exists 1 '/oval_results/results/system/definitions/definition[@definition assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:4" and @flag="does not exist"]' assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:textfilecontent_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/b/y"]' assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:textfilecontent_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/c/z"]' +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:5" and @result="true"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:5" and @flag="complete"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:filehash58_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/a/x"]' +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:6" and @result="true"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:6" and @flag="does not exist"]' +assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:filehash58_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/b/y"]' +assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:filehash58_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/c/z"]' rm -f $result rm -rf "$root" diff --git a/tests/API/OVAL/skip_paths/test_skip_paths.xml b/tests/API/OVAL/skip_paths/test_skip_paths.xml index bca1c174b9..82609b17e8 100644 --- a/tests/API/OVAL/skip_paths/test_skip_paths.xml +++ b/tests/API/OVAL/skip_paths/test_skip_paths.xml @@ -29,6 +29,18 @@ <criterion test_ref="oval:x:tst:4"/> </criteria> </definition> + <definition class="compliance" version="1" id="oval:x:def:5"> + <metadata><title/><description/></metadata> + <criteria operator="AND"> + <criterion test_ref="oval:x:tst:5"/> + </criteria> + </definition> + <definition class="compliance" version="1" id="oval:x:def:6"> + <metadata><title/><description/></metadata> + <criteria operator="AND"> + <criterion test_ref="oval:x:tst:6"/> + </criteria> + </definition> </definitions> <tests> <file_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" check_existence="at_least_one_exists" version="1" id="oval:x:tst:1" check="all" comment="read file from directory 'a' - should be read"> @@ -43,6 +55,12 @@ <textfilecontent54_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" check_existence="none_exist" version="1" id="oval:x:tst:4" check="all" comment="read file from directory 'b' - should be skip"> <object object_ref="oval:x:obj:4"/> </textfilecontent54_test> + <filehash58_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" check_existence="at_least_one_exists" version="1" id="oval:x:tst:5" check="all" comment="read file from directory 'a' - should be read"> + <object object_ref="oval:x:obj:5"/> + </filehash58_test> + <filehash58_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" check_existence="none_exist" version="1" id="oval:x:tst:6" check="all" comment="read file from directory 'b' - should be skip"> + <object object_ref="oval:x:obj:6"/> + </filehash58_test> </tests> <objects> <file_object xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" version="1" id="oval:x:obj:1"> @@ -61,5 +79,13 @@ <pattern>^.*$</pattern> <instance datatype="int" operation="greater than or equal">1</instance> </textfilecontent54_object> + <filehash58_object xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" version="1" id="oval:x:obj:5"> + <filepath>/tmp/oscap_test_skip_paths/a/x</filepath> + <hash_type>SHA-512</hash_type> + </filehash58_object> + <filehash58_object xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" version="1" id="oval:x:obj:6"> + <filepath>/tmp/oscap_test_skip_paths/b/y</filepath> + <hash_type>SHA-512</hash_type> + </filehash58_object> </objects> </oval_definitions> From c316bc4cc61a3646dec26bcf60884662e9c22c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Mon, 18 Dec 2023 18:10:14 +0100 Subject: [PATCH 14/21] Extend test_skip_paths Extend test_skip_paths to test the "skip selected paths" feature also in the xmlfilecontent probe. --- tests/API/OVAL/skip_paths/test.xml | 3 +++ tests/API/OVAL/skip_paths/test_skip_paths.sh | 10 +++++++ tests/API/OVAL/skip_paths/test_skip_paths.xml | 26 +++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 tests/API/OVAL/skip_paths/test.xml diff --git a/tests/API/OVAL/skip_paths/test.xml b/tests/API/OVAL/skip_paths/test.xml new file mode 100644 index 0000000000..5f63db6fb9 --- /dev/null +++ b/tests/API/OVAL/skip_paths/test.xml @@ -0,0 +1,3 @@ +<parent> + <child>text</child> +</parent> \ No newline at end of file diff --git a/tests/API/OVAL/skip_paths/test_skip_paths.sh b/tests/API/OVAL/skip_paths/test_skip_paths.sh index 7cab277c4b..4b69c9aa33 100755 --- a/tests/API/OVAL/skip_paths/test_skip_paths.sh +++ b/tests/API/OVAL/skip_paths/test_skip_paths.sh @@ -8,10 +8,13 @@ result=$(mktemp) root="/tmp/oscap_test_skip_paths" mkdir -p "$root/a" touch "$root/a/x" +cp "$srcdir/test.xml" "$root/a/" mkdir -p "$root/b" touch "$root/b/y" +cp "$srcdir/test.xml" "$root/b/" mkdir -p "$root/c" touch "$root/c/z" +cp "$srcdir/test.xml" "$root/c/" # oscap probes will skip directories "b" and "c" export OSCAP_PROBE_IGNORE_PATHS="$root/b:$root/c" $OSCAP oval eval --results $result "$srcdir/test_skip_paths.xml" @@ -37,5 +40,12 @@ assert_exists 1 '/oval_results/results/system/definitions/definition[@definition assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:6" and @flag="does not exist"]' assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:filehash58_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/b/y"]' assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:filehash58_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/c/z"]' +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:7" and @result="true"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:7" and @flag="complete"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:xmlfilecontent_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/a/test.xml"]' +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:8" and @result="true"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:8" and @flag="does not exist"]' +assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:xmlfilecontent_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/b/test.xml"]' +assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:xmlfilecontent_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/c/test.xml"]' rm -f $result rm -rf "$root" diff --git a/tests/API/OVAL/skip_paths/test_skip_paths.xml b/tests/API/OVAL/skip_paths/test_skip_paths.xml index 82609b17e8..a03196153b 100644 --- a/tests/API/OVAL/skip_paths/test_skip_paths.xml +++ b/tests/API/OVAL/skip_paths/test_skip_paths.xml @@ -41,6 +41,18 @@ <criterion test_ref="oval:x:tst:6"/> </criteria> </definition> + <definition class="compliance" version="1" id="oval:x:def:7"> + <metadata><title/><description/></metadata> + <criteria operator="AND"> + <criterion test_ref="oval:x:tst:7"/> + </criteria> + </definition> + <definition class="compliance" version="1" id="oval:x:def:8"> + <metadata><title/><description/></metadata> + <criteria operator="AND"> + <criterion test_ref="oval:x:tst:8"/> + </criteria> + </definition> </definitions> <tests> <file_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" check_existence="at_least_one_exists" version="1" id="oval:x:tst:1" check="all" comment="read file from directory 'a' - should be read"> @@ -61,6 +73,12 @@ <filehash58_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" check_existence="none_exist" version="1" id="oval:x:tst:6" check="all" comment="read file from directory 'b' - should be skip"> <object object_ref="oval:x:obj:6"/> </filehash58_test> + <xmlfilecontent_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" check_existence="at_least_one_exists" version="1" id="oval:x:tst:7" check="all" comment="read file from directory 'a' - should be read"> + <object object_ref="oval:x:obj:7"/> + </xmlfilecontent_test> + <xmlfilecontent_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" check_existence="none_exist" version="1" id="oval:x:tst:8" check="all" comment="read file from directory 'b' - should be skip"> + <object object_ref="oval:x:obj:8"/> + </xmlfilecontent_test> </tests> <objects> <file_object xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" version="1" id="oval:x:obj:1"> @@ -87,5 +105,13 @@ <filepath>/tmp/oscap_test_skip_paths/b/y</filepath> <hash_type>SHA-512</hash_type> </filehash58_object> + <xmlfilecontent_object xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" version="1" id="oval:x:obj:7"> + <filepath>/tmp/oscap_test_skip_paths/a/test.xml</filepath> + <xpath>/parent</xpath> + </xmlfilecontent_object> + <xmlfilecontent_object xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" version="1" id="oval:x:obj:8"> + <filepath>/tmp/oscap_test_skip_paths/b/test.xml</filepath> + <xpath>/parent</xpath> + </xmlfilecontent_object> </objects> </oval_definitions> From 592dd6ab3aa4e5dddae030b9353ae114582c42e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Wed, 10 Jan 2024 10:03:18 +0100 Subject: [PATCH 15/21] Add an offline version of the test --- tests/API/OVAL/skip_paths/CMakeLists.txt | 1 + .../skip_paths/test_skip_paths_offline.sh | 56 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100755 tests/API/OVAL/skip_paths/test_skip_paths_offline.sh diff --git a/tests/API/OVAL/skip_paths/CMakeLists.txt b/tests/API/OVAL/skip_paths/CMakeLists.txt index c4452fc23c..7381a1cb59 100644 --- a/tests/API/OVAL/skip_paths/CMakeLists.txt +++ b/tests/API/OVAL/skip_paths/CMakeLists.txt @@ -1 +1,2 @@ add_oscap_test("test_skip_paths.sh") +add_oscap_test("test_skip_paths_offline.sh") diff --git a/tests/API/OVAL/skip_paths/test_skip_paths_offline.sh b/tests/API/OVAL/skip_paths/test_skip_paths_offline.sh new file mode 100755 index 0000000000..393489f193 --- /dev/null +++ b/tests/API/OVAL/skip_paths/test_skip_paths_offline.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +. $builddir/tests/test_common.sh + +set -e -o pipefail + +result=$(mktemp) + +guest="/tmp/guest" +mkdir -p "$guest" +test_data_dir="/tmp/oscap_test_skip_paths" +mkdir -p "$guest/$test_data_dir/a" +touch "$guest/$test_data_dir/a/x" +cp "$srcdir/test.xml" "$guest/$test_data_dir/a/" +mkdir -p "$guest/$test_data_dir/b" +touch "$guest/$test_data_dir/b/y" +cp "$srcdir/test.xml" "$guest/$test_data_dir/b/" +mkdir -p "$guest/$test_data_dir/c" +touch "$guest/$test_data_dir/c/z" +cp "$srcdir/test.xml" "$guest/$test_data_dir/c/" +# oscap probes will skip directories "b" and "c" +export OSCAP_PROBE_IGNORE_PATHS="$test_data_dir/b:$test_data_dir/c" +set_chroot_offline_test_mode "$guest" +$OSCAP oval eval --results $result "$srcdir/test_skip_paths.xml" +unset_chroot_offline_test_mode +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:1" and @result="true"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:1" and @flag="complete"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/system_data/unix-sys:file_item' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/system_data/unix-sys:file_item/unix-sys:filepath[text()="/tmp/oscap_test_skip_paths/a/x"]' +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:2" and @result="true"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:2" and @flag="does not exist"]' +assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/unix-sys:file_item/unix-sys:filepath[text()="/tmp/oscap_test_skip_paths/b/y"]' +assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/unix-sys:file_item/unix-sys:filepath[text()="/tmp/oscap_test_skip_paths/c/z"]' +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:3" and @result="true"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:3" and @flag="complete"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:textfilecontent_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/a/x"]' +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:4" and @result="true"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:4" and @flag="does not exist"]' +assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:textfilecontent_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/b/y"]' +assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:textfilecontent_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/c/z"]' +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:5" and @result="true"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:5" and @flag="complete"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:filehash58_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/a/x"]' +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:6" and @result="true"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:6" and @flag="does not exist"]' +assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:filehash58_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/b/y"]' +assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:filehash58_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/c/z"]' +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:7" and @result="true"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:7" and @flag="complete"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:xmlfilecontent_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/a/test.xml"]' +assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:8" and @result="true"]' +assert_exists 1 '/oval_results/results/system/oval_system_characteristics/collected_objects/object[@id="oval:x:obj:8" and @flag="does not exist"]' +assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:xmlfilecontent_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/b/test.xml"]' +assert_exists 0 '/oval_results/results/system/oval_system_characteristics/system_data/ind-sys:xmlfilecontent_item/ind-sys:filepath[text()="/tmp/oscap_test_skip_paths/c/test.xml"]' +rm -f $result +rm -rf "$guest" From 8cb70c51fd7d85dfc792afb45c44583bef40295c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Wed, 10 Jan 2024 10:04:33 +0100 Subject: [PATCH 16/21] Add a missing newline at EOF --- tests/API/OVAL/skip_paths/test.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/API/OVAL/skip_paths/test.xml b/tests/API/OVAL/skip_paths/test.xml index 5f63db6fb9..cc0d933286 100644 --- a/tests/API/OVAL/skip_paths/test.xml +++ b/tests/API/OVAL/skip_paths/test.xml @@ -1,3 +1,3 @@ <parent> <child>text</child> -</parent> \ No newline at end of file +</parent> From b50e1ba96e1167b40688c9638bf94dfb6ee80ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Wed, 10 Jan 2024 10:13:19 +0100 Subject: [PATCH 17/21] Move a function to utils --- src/OVAL/probes/probe-api.c | 34 +--------------------------------- src/common/util.c | 32 ++++++++++++++++++++++++++++++++ src/common/util.h | 8 ++++++++ 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/OVAL/probes/probe-api.c b/src/OVAL/probes/probe-api.c index 9a661dbb84..d5f0ebeb28 100644 --- a/src/OVAL/probes/probe-api.c +++ b/src/OVAL/probes/probe-api.c @@ -1795,45 +1795,13 @@ SEXP_t *probe_obj_getmask(SEXP_t *obj) return (mask); } -static bool path_startswith(const char *path, const char *prefix) -{ - bool res = true; - const char *del = "/"; - char *path_dup = oscap_strdup(path); - char **path_split = oscap_split(path_dup, del); - char *prefix_dup = oscap_strdup(prefix); - char **prefix_split = oscap_split(prefix_dup, del); - int i = 0, j = 0; - while (prefix_split[i] && path_split[j]) { - if (!strcmp(prefix_split[i], "")) { - ++i; - continue; - } - if (!strcmp(path_split[j], "")) { - ++j; - continue; - } - if (strcmp(prefix_split[i], path_split[j])) { - res = false; - break; - } - ++i; - ++j; - } - free(path_dup); - free(path_split); - free(prefix_dup); - free(prefix_split); - return res; -} - bool probe_path_is_blocked(const char *path, struct oscap_list *blocked_paths) { bool res = false; struct oscap_iterator *it = oscap_iterator_new(blocked_paths); while (oscap_iterator_has_more(it)) { const char *item = oscap_iterator_next(it); - if (path_startswith(path, item)) { + if (oscap_path_startswith(path, item)) { res = true; break; } diff --git a/src/common/util.c b/src/common/util.c index 8bce0d6a03..a8b4a34dda 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -442,3 +442,35 @@ int oscap_open_writable(const char *filename) } return fd; } + +bool oscap_path_startswith(const char *path, const char *prefix) +{ + bool res = true; + const char *del = "/"; + char *path_dup = oscap_strdup(path); + char **path_split = oscap_split(path_dup, del); + char *prefix_dup = oscap_strdup(prefix); + char **prefix_split = oscap_split(prefix_dup, del); + int i = 0, j = 0; + while (prefix_split[i] && path_split[j]) { + if (!strcmp(prefix_split[i], "")) { + ++i; + continue; + } + if (!strcmp(path_split[j], "")) { + ++j; + continue; + } + if (strcmp(prefix_split[i], path_split[j])) { + res = false; + break; + } + ++i; + ++j; + } + free(path_dup); + free(path_split); + free(prefix_dup); + free(prefix_split); + return res; +} diff --git a/src/common/util.h b/src/common/util.h index 0811a7698c..8abe68d479 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -540,4 +540,12 @@ char *oscap_windows_error_message(unsigned long error_code); */ int oscap_open_writable(const char *filename); +/** + * Check if a path starts with the given prefix + * @param path file system path + * @param prefix file system path that will be tested if it's a prefix of the path parameter + * @return true or false + */ +bool oscap_path_startswith(const char *path, const char *prefix); + #endif /* OSCAP_UTIL_H_ */ From faa742a2e23066e04159026199daa5e9b479535e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Wed, 10 Jan 2024 10:15:10 +0100 Subject: [PATCH 18/21] Specify that the paths are absolute --- docs/manual/manual.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/manual.adoc b/docs/manual/manual.adoc index 33f9091d49..0ca6748a6e 100644 --- a/docs/manual/manual.adoc +++ b/docs/manual/manual.adoc @@ -1619,7 +1619,7 @@ not considered local by the scanner: * `SOURCE_DATE_EPOCH` - Timestamp in seconds since epoch. This timestamp will be used instead of the current time to populate `timestamp` attributes in SCAP source data streams created by `oscap ds sds-compose` sub-module. This is used for reproducible builds of data streams. * `OSCAP_PROBE_MEMORY_USAGE_RATIO` - maximum memory usage ratio (used/total) for OpenSCAP probes, default: 0.1 * `OSCAP_PROBE_MAX_COLLECTED_ITEMS` - maximal count of collected items by OpenSCAP probe for a single OVAL object evaluation -* `OSCAP_PROBE_IGNORE_PATHS` - Skip given paths during evaluation. If multiple paths should be skipped they need to be separated by a colon. +* `OSCAP_PROBE_IGNORE_PATHS` - Skip given paths during evaluation. If multiple paths should be skipped they need to be separated by a colon. The paths should be absolute. Also, OpenSCAP uses `libcurl` library which also can be configured using environment variables. See https://curl.se/libcurl/c/libcurl-env.html[the list of libcurl environment variables]. From e9e8558a8c8cb8079a657858f9ff555a3e1d893b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Tue, 16 Jan 2024 14:52:17 +0100 Subject: [PATCH 19/21] Add a simple unit test for oscap_path_startswith --- tests/common/CMakeLists.txt | 3 +++ tests/common/test_oscap_util.c | 38 ++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/tests/common/CMakeLists.txt b/tests/common/CMakeLists.txt index 4beb0323f6..4281500466 100644 --- a/tests/common/CMakeLists.txt +++ b/tests/common/CMakeLists.txt @@ -1,5 +1,8 @@ add_oscap_test_executable(test_oscap_util "test_oscap_util.c" + ${CMAKE_SOURCE_DIR}/src/common/util.c + ${CMAKE_SOURCE_DIR}/src/common/error.c + ${CMAKE_SOURCE_DIR}/src/common/err_queue.c ) add_oscap_test("test_oscap_util.sh") diff --git a/tests/common/test_oscap_util.c b/tests/common/test_oscap_util.c index 22559966bc..88f4497b6a 100644 --- a/tests/common/test_oscap_util.c +++ b/tests/common/test_oscap_util.c @@ -29,8 +29,44 @@ #include <string.h> #include "common/util.h" +int test_oscap_path_startswith(void); int test_oscap_strrm(void); +int test_oscap_path_startswith() +{ + if (!oscap_path_startswith("/", "/")) + return 1; + if (!oscap_path_startswith("/aaa", "/")) + return 2; + if (!oscap_path_startswith("/aaa", "/aaa")) + return 3; + if (!oscap_path_startswith("/aaa/bbb", "/aaa")) + return 4; + if (!oscap_path_startswith("/aaa/bbb/ccc", "/aaa")) + return 5; + if (!oscap_path_startswith("/aaa/bbb/ccc/", "/aaa/")) + return 6; + if (!oscap_path_startswith("/aaa/bbb/ccc", "/aaa/bbb/ccc")) + return 7; + if (!oscap_path_startswith("/aaa/bbb/ccc", "")) + return 8; + if (!oscap_path_startswith("", "")) + return 9; + if (!oscap_path_startswith("", "/")) + return 10; + + if (oscap_path_startswith("/bbb", "/aaa")) + return 101; + if (oscap_path_startswith("/bbb/aaa", "/aaa")) + return 102; + if (oscap_path_startswith("/bbb/aaa/", "/aaa")) + return 103; + if (oscap_path_startswith("/bbb/aaa/", "/aaa/")) + return 104; + + return 0; +} + int test_oscap_strrm() { char str[] = "abcdef12345678def90"; @@ -59,6 +95,8 @@ int main (int argc, char *argv[]) { int retval = 0; + if ((retval = test_oscap_path_startswith()) != 0) + return retval; if ((retval = test_oscap_strrm()) != 0) return retval; From 58e409c38dba74ea2eaab61c3d09d7b1cc66ce44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Tue, 16 Jan 2024 14:54:53 +0100 Subject: [PATCH 20/21] Add a canonical path to the documentation --- docs/manual/manual.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/manual.adoc b/docs/manual/manual.adoc index 0ca6748a6e..2c534d8aa7 100644 --- a/docs/manual/manual.adoc +++ b/docs/manual/manual.adoc @@ -1619,7 +1619,7 @@ not considered local by the scanner: * `SOURCE_DATE_EPOCH` - Timestamp in seconds since epoch. This timestamp will be used instead of the current time to populate `timestamp` attributes in SCAP source data streams created by `oscap ds sds-compose` sub-module. This is used for reproducible builds of data streams. * `OSCAP_PROBE_MEMORY_USAGE_RATIO` - maximum memory usage ratio (used/total) for OpenSCAP probes, default: 0.1 * `OSCAP_PROBE_MAX_COLLECTED_ITEMS` - maximal count of collected items by OpenSCAP probe for a single OVAL object evaluation -* `OSCAP_PROBE_IGNORE_PATHS` - Skip given paths during evaluation. If multiple paths should be skipped they need to be separated by a colon. The paths should be absolute. +* `OSCAP_PROBE_IGNORE_PATHS` - Skip given paths during evaluation. If multiple paths should be skipped they need to be separated by a colon. The paths should be absolute canonical paths. Also, OpenSCAP uses `libcurl` library which also can be configured using environment variables. See https://curl.se/libcurl/c/libcurl-env.html[the list of libcurl environment variables]. From 2d20f338e675209381d588d3c5d0be8ab2e71884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com> Date: Tue, 16 Jan 2024 15:00:04 +0100 Subject: [PATCH 21/21] Add a warning on Windows --- src/OVAL/probes/probe/worker.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/OVAL/probes/probe/worker.c b/src/OVAL/probes/probe/worker.c index c8ef869829..53ebf26639 100644 --- a/src/OVAL/probes/probe/worker.c +++ b/src/OVAL/probes/probe/worker.c @@ -978,11 +978,15 @@ static void _add_blocked_paths(struct oscap_list *bpaths) if (envar == NULL) { return; } +#ifdef OS_WINDOWS + dW("OSCAP_PROBE_IGNORE_PATHS isn't effective on Windows."); +#else char **paths = oscap_split(envar, ":"); for (int i = 0; paths[i]; ++i) { oscap_list_add(bpaths, strdup(paths[i])); } free(paths); +#endif } /**