Blob Blame History Raw
From a7a0c4a3f528594bb3181174b6986e9c50a684b4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com>
Date: Mon, 30 Aug 2021 15:44:37 +0200
Subject: [PATCH 1/3] Lower memory limits and improve their checking

This patch attempts to mitigate problems caused by a large amount of
collected objects such as rhbz#1932833.

Specifically, these changes are made:
- Lower the threshold so that the amount of used memory is checked when
  only 1000 items are collected for the given OVAL object. That's
  because 32768 items (the original value) is already a large amount which
  occupies a lot of memory during further processing.
- Lower the memory usage ratio limit for the probe to 10 %. We have
  found experimentally that giving the probe 15 % or more will cause the
  oscap process to be killed when processing the collected data and
  generating results.
- In the calling function probe_item_collect, distinguish between return
  codes which means different behavior when there is insufficient memory
  than when the memory consumption can't be checked.
- Improve the warning message to show greater details about memory
  consumption to the user.
- Remove the check for the absolute amount of remaining free memory. As
  we can see on the example of rhbz#1932833, on systems with large
  amount of memory the remaining memory of 512 MB isn't enough memory for
  openscap to process the collected data. At the same time, if we lowered
  the usage ratio, we don't need this anymore.
- Remove useless message "spt:" from the verbose log because it's
  produced many times and pollutes the log extremely.
---
 src/OVAL/probes/probe/icache.c | 23 +++++++++++------------
 src/common/memusage.c          |  2 --
 2 files changed, 11 insertions(+), 14 deletions(-)

diff --git a/src/OVAL/probes/probe/icache.c b/src/OVAL/probes/probe/icache.c
index 7e16daa334..af7b528372 100644
--- a/src/OVAL/probes/probe/icache.c
+++ b/src/OVAL/probes/probe/icache.c
@@ -487,9 +487,8 @@ int probe_icache_nop(probe_icache_t *cache)
         return (0);
 }
 
-#define PROBE_RESULT_MEMCHECK_CTRESHOLD  32768  /* item count */
-#define PROBE_RESULT_MEMCHECK_MINFREEMEM 512    /* MiB */
-#define PROBE_RESULT_MEMCHECK_MAXRATIO   0.8   /* max. memory usage ratio - used/total */
+#define PROBE_RESULT_MEMCHECK_CTRESHOLD  1000  /* item count */
+#define PROBE_RESULT_MEMCHECK_MAXRATIO   0.1   /* max. memory usage ratio - used/total */
 
 /**
  * Returns 0 if the memory constraints are not reached. Otherwise, 1 is returned.
@@ -511,18 +510,12 @@ static int probe_cobj_memcheck(size_t item_cnt)
 		c_ratio = (double)mu_proc.mu_rss/(double)(mu_sys.mu_total);
 
 		if (c_ratio > PROBE_RESULT_MEMCHECK_MAXRATIO) {
-			dW("Memory usage ratio limit reached! limit=%f, current=%f",
-			   PROBE_RESULT_MEMCHECK_MAXRATIO, c_ratio);
+			dW("Memory usage ratio limit reached! limit=%f, current=%f, used=%ld MB, free=%ld MB, total=%ld MB, count of items=%ld",
+			   PROBE_RESULT_MEMCHECK_MAXRATIO, c_ratio, mu_proc.mu_rss / 1024, mu_sys.mu_realfree / 1024, mu_sys.mu_total / 1024, item_cnt);
 			errno = ENOMEM;
 			return (1);
 		}
 
-		if ((mu_sys.mu_realfree / 1024) < PROBE_RESULT_MEMCHECK_MINFREEMEM) {
-			dW("Minimum free memory limit reached! limit=%zu, current=%zu",
-			   PROBE_RESULT_MEMCHECK_MINFREEMEM, mu_sys.mu_realfree / 1024);
-			errno = ENOMEM;
-			return (1);
-		}
 	}
 
 	return (0);
@@ -547,6 +540,7 @@ int probe_item_collect(struct probe_ctx *ctx, SEXP_t *item)
 {
 	SEXP_t *cobj_content;
 	size_t  cobj_itemcnt;
+	int memcheck_ret;
 
 	if (ctx == NULL || ctx->probe_out == NULL || item == NULL) {
 		return -1;
@@ -556,7 +550,12 @@ int probe_item_collect(struct probe_ctx *ctx, SEXP_t *item)
 	cobj_itemcnt = SEXP_list_length(cobj_content);
 	SEXP_free(cobj_content);
 
-	if (probe_cobj_memcheck(cobj_itemcnt) != 0) {
+	memcheck_ret = probe_cobj_memcheck(cobj_itemcnt);
+	if (memcheck_ret == -1) {
+		dE("Failed to check available memory");
+		return -1;
+	}
+	if (memcheck_ret == 1) {
 
 		/*
 		 * Don't set the message again if the collected object is
diff --git a/src/common/memusage.c b/src/common/memusage.c
index fc6909e6fb..c6755f21f1 100644
--- a/src/common/memusage.c
+++ b/src/common/memusage.c
@@ -137,8 +137,6 @@ static int read_status(const char *source, void *base, struct stat_parser *spt,
 			sp = oscap_bfind(spt, spt_size, sizeof(struct stat_parser),
 			                 linebuf, (int(*)(void *, void *))&cmpkey);
 
-			dD("spt: %s", linebuf);
-
 			if (sp == NULL) {
 				/* drop end of unread line */
 				while (strchr(strval, '\n') == NULL) {

From ded3d58cd62259b217a9ab35030827ac3cb8dd45 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com>
Date: Tue, 7 Sep 2021 13:52:50 +0200
Subject: [PATCH 2/3] Allow to set memory ratio by environment variable

If the probe memory usage ratio limit will be too small or too big
in some situation, the user will be able to modify the limit easily
by setting the environment variable OSCAP_PROBE_MEMORY_USAGE_RATIO
to a different value. This can also help users when debugging memory
problems.
---
 docs/manual/manual.adoc        |  1 +
 src/OVAL/probes/probe/icache.c |  9 ++++-----
 src/OVAL/probes/probe/probe.h  |  1 +
 src/OVAL/probes/probe/worker.c | 12 ++++++++++++
 4 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/docs/manual/manual.adoc b/docs/manual/manual.adoc
index 90e2cc2c63..825844bc71 100644
--- a/docs/manual/manual.adoc
+++ b/docs/manual/manual.adoc
@@ -1613,6 +1613,7 @@ not considered local by the scanner:
 * `OSCAP_PROBE_ROOT` - Path to a directory which contains mounted filesystem to be evaluated. Used for offline scanning.
 * `SEXP_VALIDATE_DISABLE` - If set, `oscap` will not validate SEXP expressions during its execution.
 * `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
 
 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/probe/icache.c b/src/OVAL/probes/probe/icache.c
index af7b528372..a397d35ec2 100644
--- a/src/OVAL/probes/probe/icache.c
+++ b/src/OVAL/probes/probe/icache.c
@@ -488,13 +488,12 @@ int probe_icache_nop(probe_icache_t *cache)
 }
 
 #define PROBE_RESULT_MEMCHECK_CTRESHOLD  1000  /* item count */
-#define PROBE_RESULT_MEMCHECK_MAXRATIO   0.1   /* max. memory usage ratio - used/total */
 
 /**
  * Returns 0 if the memory constraints are not reached. Otherwise, 1 is returned.
  * In case of an error, -1 is returned.
  */
-static int probe_cobj_memcheck(size_t item_cnt)
+static int probe_cobj_memcheck(size_t item_cnt, double max_ratio)
 {
 	if (item_cnt > PROBE_RESULT_MEMCHECK_CTRESHOLD) {
 		struct proc_memusage mu_proc;
@@ -509,9 +508,9 @@ static int probe_cobj_memcheck(size_t item_cnt)
 
 		c_ratio = (double)mu_proc.mu_rss/(double)(mu_sys.mu_total);
 
-		if (c_ratio > PROBE_RESULT_MEMCHECK_MAXRATIO) {
+		if (c_ratio > max_ratio) {
 			dW("Memory usage ratio limit reached! limit=%f, current=%f, used=%ld MB, free=%ld MB, total=%ld MB, count of items=%ld",
-			   PROBE_RESULT_MEMCHECK_MAXRATIO, c_ratio, mu_proc.mu_rss / 1024, mu_sys.mu_realfree / 1024, mu_sys.mu_total / 1024, item_cnt);
+			max_ratio, c_ratio, mu_proc.mu_rss / 1024, mu_sys.mu_realfree / 1024, mu_sys.mu_total / 1024, item_cnt);
 			errno = ENOMEM;
 			return (1);
 		}
@@ -550,7 +549,7 @@ int probe_item_collect(struct probe_ctx *ctx, SEXP_t *item)
 	cobj_itemcnt = SEXP_list_length(cobj_content);
 	SEXP_free(cobj_content);
 
-	memcheck_ret = probe_cobj_memcheck(cobj_itemcnt);
+	memcheck_ret = probe_cobj_memcheck(cobj_itemcnt, ctx->max_mem_ratio);
 	if (memcheck_ret == -1) {
 		dE("Failed to check available memory");
 		return -1;
diff --git a/src/OVAL/probes/probe/probe.h b/src/OVAL/probes/probe/probe.h
index 1c7a3b1b00..d3a488c4d5 100644
--- a/src/OVAL/probes/probe/probe.h
+++ b/src/OVAL/probes/probe/probe.h
@@ -83,6 +83,7 @@ struct probe_ctx {
         SEXP_t         *filters;   /**< object filters (OVAL 5.8 and higher) */
         probe_icache_t *icache;    /**< item cache */
 	int offline_mode;
+	double max_mem_ratio;
 };
 
 typedef enum {
diff --git a/src/OVAL/probes/probe/worker.c b/src/OVAL/probes/probe/worker.c
index 94fe5c2037..3ef489b40d 100644
--- a/src/OVAL/probes/probe/worker.c
+++ b/src/OVAL/probes/probe/worker.c
@@ -52,6 +52,10 @@ extern int chroot(const char *);
 #include "probe-table.h"
 #include "probe.h"
 
+/* default max. memory usage ratio - used/total */
+/* can be overridden by environment variable OSCAP_PROBE_MEMORY_USAGE_RATIO */
+#define OSCAP_PROBE_MEMORY_USAGE_RATIO_DEFAULT 0.1
+
 extern bool  OSCAP_GSYM(varref_handling);
 extern void *OSCAP_GSYM(probe_arg);
 
@@ -1064,6 +1068,14 @@ SEXP_t *probe_worker(probe_t *probe, SEAP_msg_t *msg_in, int *ret)
 
 		pctx.offline_mode = probe->selected_offline_mode;
 
+		pctx.max_mem_ratio = OSCAP_PROBE_MEMORY_USAGE_RATIO_DEFAULT;
+		char *max_ratio_str = getenv("OSCAP_PROBE_MEMORY_USAGE_RATIO");
+		if (max_ratio_str != NULL) {
+			double max_ratio = strtod(max_ratio_str, NULL);
+			if (max_ratio != 0)
+				pctx.max_mem_ratio = max_ratio;
+		}
+
 		/* simple object */
                 pctx.icache  = probe->icache;
 		pctx.filters = probe_prepare_filters(probe, probe_in);

From 0f5cf5b09f469920616a2037d0f9c81cf0868a58 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com>
Date: Wed, 15 Sep 2021 14:41:30 +0200
Subject: [PATCH 3/3] Update src/OVAL/probes/probe/worker.c

Co-authored-by: Evgeny Kolesnikov <evgenyz@gmail.com>
---
 src/OVAL/probes/probe/worker.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/OVAL/probes/probe/worker.c b/src/OVAL/probes/probe/worker.c
index 3ef489b40d..1183ed06bf 100644
--- a/src/OVAL/probes/probe/worker.c
+++ b/src/OVAL/probes/probe/worker.c
@@ -1072,7 +1072,7 @@ SEXP_t *probe_worker(probe_t *probe, SEAP_msg_t *msg_in, int *ret)
 		char *max_ratio_str = getenv("OSCAP_PROBE_MEMORY_USAGE_RATIO");
 		if (max_ratio_str != NULL) {
 			double max_ratio = strtod(max_ratio_str, NULL);
-			if (max_ratio != 0)
+			if (max_ratio > 0)
 				pctx.max_mem_ratio = max_ratio;
 		}