Blame SOURCES/openscap-1.3.3-textfilecontent-crash.patch

0b628f
diff --git a/docs/developer/developer.adoc b/docs/developer/developer.adoc
0b628f
index 08273e24d..823a1504e 100644
0b628f
--- a/docs/developer/developer.adoc
0b628f
+++ b/docs/developer/developer.adoc
0b628f
@@ -317,6 +317,8 @@ behaviour.
0b628f
 
0b628f
 * *OSCAP_FULL_VALIDATION=1* - validate all exported documents (slower)
0b628f
 * *SEXP_VALIDATE_DISABLE=1* - do not validate SEXP expressions (faster)
0b628f
+* *OSCAP_PCRE_EXEC_RECURSION_LIMIT* - override default recursion limit
0b628f
+  for match in pcre_exec call in textfilecontent(54) probes.
0b628f
 
0b628f
 
0b628f
 
0b628f
diff --git a/src/OVAL/probes/independent/textfilecontent54_probe.c b/src/OVAL/probes/independent/textfilecontent54_probe.c
0b628f
index 1c449833f..3053f5d95 100644
0b628f
--- a/src/OVAL/probes/independent/textfilecontent54_probe.c
0b628f
+++ b/src/OVAL/probes/independent/textfilecontent54_probe.c
0b628f
@@ -52,68 +52,11 @@
0b628f
 #include <probe/option.h>
0b628f
 #include <oval_fts.h>
0b628f
 #include "common/debug_priv.h"
0b628f
+#include "common/util.h"
0b628f
 #include "textfilecontent54_probe.h"
0b628f
 
0b628f
 #define FILE_SEPARATOR '/'
0b628f
 
0b628f
-static int get_substrings(char *str, int *ofs, pcre *re, int want_substrs, char ***substrings) {
0b628f
-	int i, ret, rc;
0b628f
-	int ovector[60], ovector_len = sizeof (ovector) / sizeof (ovector[0]);
0b628f
-	char **substrs;
0b628f
-
0b628f
-	// todo: max match count check
0b628f
-
0b628f
-	for (i = 0; i < ovector_len; ++i)
0b628f
-		ovector[i] = -1;
0b628f
-
0b628f
-#if defined(OS_SOLARIS)
0b628f
-	rc = pcre_exec(re, NULL, str, strlen(str), *ofs, PCRE_NO_UTF8_CHECK, ovector, ovector_len);
0b628f
-#else
0b628f
-	rc = pcre_exec(re, NULL, str, strlen(str), *ofs, 0, ovector, ovector_len);
0b628f
-#endif
0b628f
-
0b628f
-	if (rc < -1) {
0b628f
-		dE("Function pcre_exec() failed to match a regular expression with return code %d on string '%s'.", rc, str);
0b628f
-		return rc;
0b628f
-	} else if (rc == -1) {
0b628f
-		/* no match */
0b628f
-		return 0;
0b628f
-	}
0b628f
-
0b628f
-	*ofs = (*ofs == ovector[1]) ? ovector[1] + 1 : ovector[1];
0b628f
-
0b628f
-	if (!want_substrs) {
0b628f
-		/* just report successful match */
0b628f
-		return 1;
0b628f
-	}
0b628f
-
0b628f
-	ret = 0;
0b628f
-	if (rc == 0) {
0b628f
-		/* vector too small */
0b628f
-		// todo: report partial results
0b628f
-		rc = ovector_len / 3;
0b628f
-	}
0b628f
-
0b628f
-	substrs = malloc(rc * sizeof (char *));
0b628f
-	for (i = 0; i < rc; ++i) {
0b628f
-		int len;
0b628f
-		char *buf;
0b628f
-
0b628f
-		if (ovector[2 * i] == -1)
0b628f
-			continue;
0b628f
-		len = ovector[2 * i + 1] - ovector[2 * i];
0b628f
-		buf = malloc(len + 1);
0b628f
-		memcpy(buf, str + ovector[2 * i], len);
0b628f
-		buf[len] = '\0';
0b628f
-		substrs[ret] = buf;
0b628f
-		++ret;
0b628f
-	}
0b628f
-
0b628f
-	*substrings = substrs;
0b628f
-
0b628f
-	return ret;
0b628f
-}
0b628f
-
0b628f
 static SEXP_t *create_item(const char *path, const char *filename, char *pattern,
0b628f
 			   int instance, char **substrs, int substr_cnt, oval_schema_version_t over)
0b628f
 {
0b628f
@@ -260,7 +203,7 @@ static int process_file(const char *prefix, const char *path, const char *file,
0b628f
 			want_instance = 0;
0b628f
 
0b628f
 		SEXP_free(next_inst);
0b628f
-		substr_cnt = get_substrings(buf, &ofs, pfd->compiled_regex, want_instance, &substrs);
0b628f
+		substr_cnt = oscap_get_substrings(buf, &ofs, pfd->compiled_regex, want_instance, &substrs);
0b628f
 
0b628f
 		if (substr_cnt < 0) {
0b628f
 			SEXP_t *msg;
0b628f
diff --git a/src/OVAL/probes/independent/textfilecontent_probe.c b/src/OVAL/probes/independent/textfilecontent_probe.c
0b628f
index 9abf8fcc3..988a6471d 100644
0b628f
--- a/src/OVAL/probes/independent/textfilecontent_probe.c
0b628f
+++ b/src/OVAL/probes/independent/textfilecontent_probe.c
0b628f
@@ -71,63 +71,11 @@
0b628f
 #include <probe/option.h>
0b628f
 #include <oval_fts.h>
0b628f
 #include "common/debug_priv.h"
0b628f
+#include "common/util.h"
0b628f
 #include "textfilecontent_probe.h"
0b628f
 
0b628f
 #define FILE_SEPARATOR '/'
0b628f
 
0b628f
-static int get_substrings(char *str, pcre *re, int want_substrs, char ***substrings) {
0b628f
-	int i, ret, rc;
0b628f
-	int ovector[60], ovector_len = sizeof (ovector) / sizeof (ovector[0]);
0b628f
-
0b628f
-	// todo: max match count check
0b628f
-
0b628f
-	for (i = 0; i < ovector_len; ++i)
0b628f
-		ovector[i] = -1;
0b628f
-
0b628f
-	rc = pcre_exec(re, NULL, str, strlen(str), 0, 0,
0b628f
-		       ovector, ovector_len);
0b628f
-
0b628f
-	if (rc < -1) {
0b628f
-		return -1;
0b628f
-	} else if (rc == -1) {
0b628f
-		/* no match */
0b628f
-		return 0;
0b628f
-	} else if(!want_substrs) {
0b628f
-		/* just report successful match */
0b628f
-		return 1;
0b628f
-	}
0b628f
-
0b628f
-	char **substrs;
0b628f
-
0b628f
-	ret = 0;
0b628f
-	if (rc == 0) {
0b628f
-		/* vector too small */
0b628f
-		rc = ovector_len / 3;
0b628f
-	}
0b628f
-
0b628f
-	substrs = malloc(rc * sizeof (char *));
0b628f
-	for (i = 0; i < rc; ++i) {
0b628f
-		int len;
0b628f
-		char *buf;
0b628f
-
0b628f
-		if (ovector[2 * i] == -1)
0b628f
-			continue;
0b628f
-		len = ovector[2 * i + 1] - ovector[2 * i];
0b628f
-		buf = malloc(len + 1);
0b628f
-		memcpy(buf, str + ovector[2 * i], len);
0b628f
-		buf[len] = '\0';
0b628f
-		substrs[ret] = buf;
0b628f
-		++ret;
0b628f
-	}
0b628f
-	/*
0b628f
-	  if (ret < rc)
0b628f
-	  substrs = realloc(substrs, ret * sizeof (char *));
0b628f
-	*/
0b628f
-	*substrings = substrs;
0b628f
-
0b628f
-	return ret;
0b628f
-}
0b628f
-
0b628f
 static SEXP_t *create_item(const char *path, const char *filename, char *pattern,
0b628f
 			   int instance, char **substrs, int substr_cnt, oval_schema_version_t over)
0b628f
 {
0b628f
@@ -244,9 +192,10 @@ static int process_file(const char *prefix, const char *path, const char *filena
0b628f
 
0b628f
 	int cur_inst = 0;
0b628f
 	char line[4096];
0b628f
+	int ofs = 0;
0b628f
 
0b628f
 	while (fgets(line, sizeof(line), fp) != NULL) {
0b628f
-		substr_cnt = get_substrings(line, re, 1, &substrs);
0b628f
+		substr_cnt = oscap_get_substrings(line, &ofs, re, 1, &substrs);
0b628f
 		if (substr_cnt > 0) {
0b628f
 			int k;
0b628f
 			SEXP_t *item;
0b628f
diff --git a/src/common/util.c b/src/common/util.c
0b628f
index 146b7bc39..8f130c50e 100644
0b628f
--- a/src/common/util.c
0b628f
+++ b/src/common/util.c
0b628f
@@ -30,11 +30,13 @@
0b628f
 #include <limits.h>
0b628f
 #include <stdarg.h>
0b628f
 #include <math.h>
0b628f
+#include <pcre.h>
0b628f
 
0b628f
 #include "util.h"
0b628f
 #include "_error.h"
0b628f
 #include "oscap.h"
0b628f
 #include "oscap_helpers.h"
0b628f
+#include "debug_priv.h"
0b628f
 
0b628f
 #ifdef OS_WINDOWS
0b628f
 #include <stdlib.h>
0b628f
@@ -45,6 +47,7 @@
0b628f
 #endif
0b628f
 
0b628f
 #define PATH_SEPARATOR '/'
0b628f
+#define OSCAP_PCRE_EXEC_RECURSION_LIMIT_DEFAULT 5000
0b628f
 
0b628f
 int oscap_string_to_enum(const struct oscap_string_map *map, const char *str)
0b628f
 {
0b628f
@@ -353,6 +356,76 @@ char *oscap_path_join(const char *path1, const char *path2)
0b628f
 	return joined_path;
0b628f
 }
0b628f
 
0b628f
+int oscap_get_substrings(char *str, int *ofs, pcre *re, int want_substrs, char ***substrings) {
0b628f
+	int i, ret, rc;
0b628f
+	int ovector[60], ovector_len = sizeof (ovector) / sizeof (ovector[0]);
0b628f
+	char **substrs;
0b628f
+
0b628f
+	// todo: max match count check
0b628f
+
0b628f
+	for (i = 0; i < ovector_len; ++i) {
0b628f
+		ovector[i] = -1;
0b628f
+	}
0b628f
+
0b628f
+	struct pcre_extra extra;
0b628f
+	extra.match_limit_recursion = OSCAP_PCRE_EXEC_RECURSION_LIMIT_DEFAULT;
0b628f
+	char *limit_str = getenv("OSCAP_PCRE_EXEC_RECURSION_LIMIT");
0b628f
+	if (limit_str != NULL) {
0b628f
+		unsigned long limit;
0b628f
+		if (sscanf(limit_str, "%lu", &limit) == 1) {
0b628f
+			extra.match_limit_recursion = limit;
0b628f
+		}
0b628f
+	}
0b628f
+	extra.flags = PCRE_EXTRA_MATCH_LIMIT_RECURSION;
0b628f
+#if defined(OS_SOLARIS)
0b628f
+	rc = pcre_exec(re, &extra, str, strlen(str), *ofs, PCRE_NO_UTF8_CHECK, ovector, ovector_len);
0b628f
+#else
0b628f
+	rc = pcre_exec(re, &extra, str, strlen(str), *ofs, 0, ovector, ovector_len);
0b628f
+#endif
0b628f
+
0b628f
+	if (rc < -1) {
0b628f
+		dE("Function pcre_exec() failed to match a regular expression with return code %d on string '%s'.", rc, str);
0b628f
+		return rc;
0b628f
+	} else if (rc == -1) {
0b628f
+		/* no match */
0b628f
+		return 0;
0b628f
+	}
0b628f
+
0b628f
+	*ofs = (*ofs == ovector[1]) ? ovector[1] + 1 : ovector[1];
0b628f
+
0b628f
+	if (!want_substrs) {
0b628f
+		/* just report successful match */
0b628f
+		return 1;
0b628f
+	}
0b628f
+
0b628f
+	ret = 0;
0b628f
+	if (rc == 0) {
0b628f
+		/* vector too small */
0b628f
+		// todo: report partial results
0b628f
+		rc = ovector_len / 3;
0b628f
+	}
0b628f
+
0b628f
+	substrs = malloc(rc * sizeof (char *));
0b628f
+	for (i = 0; i < rc; ++i) {
0b628f
+		int len;
0b628f
+		char *buf;
0b628f
+
0b628f
+		if (ovector[2 * i] == -1) {
0b628f
+			continue;
0b628f
+		}
0b628f
+		len = ovector[2 * i + 1] - ovector[2 * i];
0b628f
+		buf = malloc(len + 1);
0b628f
+		memcpy(buf, str + ovector[2 * i], len);
0b628f
+		buf[len] = '\0';
0b628f
+		substrs[ret] = buf;
0b628f
+		++ret;
0b628f
+	}
0b628f
+
0b628f
+	*substrings = substrs;
0b628f
+
0b628f
+	return ret;
0b628f
+}
0b628f
+
0b628f
 #ifdef OS_WINDOWS
0b628f
 char *oscap_windows_wstr_to_str(const wchar_t *wstr)
0b628f
 {
0b628f
diff --git a/src/common/util.h b/src/common/util.h
0b628f
index 50a1c746f..2592f3962 100644
0b628f
--- a/src/common/util.h
0b628f
+++ b/src/common/util.h
0b628f
@@ -31,6 +31,7 @@
0b628f
 #include "public/oscap.h"
0b628f
 #include <stdarg.h>
0b628f
 #include <string.h>
0b628f
+#include <pcre.h>
0b628f
 #include "oscap_export.h"
0b628f
 
0b628f
 #ifndef __attribute__nonnull__
0b628f
@@ -467,6 +468,19 @@ int oscap_strncasecmp(const char *s1, const char *s2, size_t n);
0b628f
  */
0b628f
 char *oscap_strerror_r(int errnum, char *buf, size_t buflen);
0b628f
 
0b628f
+/**
0b628f
+ * Match a regular expression and return substrings.
0b628f
+ * Caller is responsible for freeing the returned array.
0b628f
+ * @param str subject string
0b628f
+ * @param ofs starting offset in str
0b628f
+ * @param re compiled regular expression
0b628f
+ * @param want_substrs if non-zero, substrings will be returned
0b628f
+ * @param substrings contains returned substrings
0b628f
+ * @return count of matched substrings, 0 if no match
0b628f
+ * negative value on failure
0b628f
+ */
0b628f
+int oscap_get_substrings(char *str, int *ofs, pcre *re, int want_substrs, char ***substrings);
0b628f
+
0b628f
 #ifdef OS_WINDOWS
0b628f
 /**
0b628f
  * Convert wide character string to a C string (UTF-16 to UTF-8)
0b628f
diff --git a/tests/probes/textfilecontent54/30-ospp-v42.rules b/tests/probes/textfilecontent54/30-ospp-v42.rules
0b628f
new file mode 100644
0b628f
index 000000000..7ad0c254d
0b628f
--- /dev/null
0b628f
+++ b/tests/probes/textfilecontent54/30-ospp-v42.rules
0b628f
@@ -0,0 +1,113 @@
0b628f
+## The purpose of these rules is to meet the requirements for Operating
0b628f
+## System Protection Profile (OSPP)v4.2. These rules depends on having
0b628f
+## 10-base-config.rules, 11-loginuid.rules, and 43-module-load.rules installed.
0b628f
+
0b628f
+## Unsuccessful file creation (open with O_CREAT)
0b628f
+-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
0b628f
+-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
0b628f
+-a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-create
0b628f
+-a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-create
0b628f
+-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
0b628f
+-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
0b628f
+-a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-create
0b628f
+-a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-create
0b628f
+-a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-create
0b628f
+-a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-create
0b628f
+-a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-create
0b628f
+-a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-create
0b628f
+
0b628f
+## Unsuccessful file modifications (open for write or truncate)
0b628f
+-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
0b628f
+-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
0b628f
+-a always,exit -F arch=b32 -S open -F a1&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification
0b628f
+-a always,exit -F arch=b64 -S open -F a1&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification
0b628f
+-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
0b628f
+-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
0b628f
+-a always,exit -F arch=b32 -S open -F a1&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification
0b628f
+-a always,exit -F arch=b64 -S open -F a1&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification
0b628f
+-a always,exit -F arch=b32 -S truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification
0b628f
+-a always,exit -F arch=b64 -S truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification
0b628f
+-a always,exit -F arch=b32 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification
0b628f
+-a always,exit -F arch=b64 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-modification
0b628f
+
0b628f
+## Unsuccessful file access (any other opens) This has to go last.
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+
0b628f
+## Unsuccessful file delete
0b628f
+-a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-delete
0b628f
+-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-delete
0b628f
+-a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-delete
0b628f
+-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccesful-delete
0b628f
+
0b628f
+## Unsuccessful permission change
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+
0b628f
+## Unsuccessful ownership change
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+
0b628f
+## User add delete modify. This is covered by pam. However, someone could
0b628f
+## open a file and directly create or modify a user, so we'll watch passwd and
0b628f
+## shadow for writes
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+
0b628f
+## User enable and disable. This is entirely handled by pam.
0b628f
+
0b628f
+## Group add delete modify. This is covered by pam. However, someone could
0b628f
+## open a file and directly create or modify a user, so we'll watch group and
0b628f
+## gshadow for writes
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+-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
0b628f
+
0b628f
+## Use of special rights for config changes. This would be use of setuid
0b628f
+## programs that relate to user accts. This is not all setuid apps because
0b628f
+## requirements are only for ones that affect system configuration.
0b628f
+-a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
0b628f
+-a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
0b628f
+-a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
0b628f
+-a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
0b628f
+-a always,exit -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
0b628f
+-a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
0b628f
+-a always,exit -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
0b628f
+-a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
0b628f
+-a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
0b628f
+-a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
0b628f
+-a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
0b628f
+
0b628f
+## Privilege escalation via su or sudo. This is entirely handled by pam.
0b628f
+
0b628f
+## Audit log access
0b628f
+-a always,exit -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail
0b628f
+
0b628f
+## Software updates. This is entirely handled by rpm.
0b628f
+
0b628f
+## System start and shutdown. This is entirely handled by systemd
0b628f
+
0b628f
+## Kernel Module loading. This is handled in 43-module-load.rules
0b628f
+
0b628f
+## Application invocation. The requirements list an optional requirement
0b628f
+## FPT_SRP_EXT.1 Software Restriction Policies. This event is intended to
0b628f
+## state results from that policy. This would be handled entirely by
0b628f
+## that daemon.
0b628f
+
0b628f
diff --git a/tests/probes/textfilecontent54/CMakeLists.txt b/tests/probes/textfilecontent54/CMakeLists.txt
0b628f
index 87c6e215d..48bbde0e6 100644
0b628f
--- a/tests/probes/textfilecontent54/CMakeLists.txt
0b628f
+++ b/tests/probes/textfilecontent54/CMakeLists.txt
0b628f
@@ -1,4 +1,5 @@
0b628f
 if(ENABLE_PROBES_INDEPENDENT)
0b628f
 	add_oscap_test("all.sh")
0b628f
 	add_oscap_test("test_filecontent_non_utf.sh")
0b628f
+	add_oscap_test("test_recursion_limit.sh")
0b628f
 endif()
0b628f
diff --git a/tests/probes/textfilecontent54/test_recursion_limit.oval.xml b/tests/probes/textfilecontent54/test_recursion_limit.oval.xml
0b628f
new file mode 100644
0b628f
index 000000000..6f6a5ba14
0b628f
--- /dev/null
0b628f
+++ b/tests/probes/textfilecontent54/test_recursion_limit.oval.xml
0b628f
@@ -0,0 +1,38 @@
0b628f
+
0b628f
+<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">
0b628f
+  <generator>
0b628f
+    <oval:schema_version>5.11.1</oval:schema_version>
0b628f
+    <oval:timestamp>0001-01-01T00:00:00+00:00</oval:timestamp>
0b628f
+  </generator>
0b628f
+
0b628f
+  <definitions>
0b628f
+    <definition class="compliance" version="1" id="oval:x:def:1">
0b628f
+      <metadata>
0b628f
+        <title>The regular expression and the provided file should exceed recursion limits within pcre_exec used in the probe and cause a segfault.</title>
0b628f
+        <description>x</description>
0b628f
+        <affected family="unix">
0b628f
+          <platform>x</platform>
0b628f
+        </affected>
0b628f
+      </metadata>
0b628f
+      <criteria>
0b628f
+        <criterion test_ref="oval:x:tst:1" comment="always pass"/>
0b628f
+      </criteria>
0b628f
+    </definition>
0b628f
+  </definitions>
0b628f
+
0b628f
+  <tests>
0b628f
+    <ind:textfilecontent54_test id="oval:x:tst:1" version="1" comment="Match 3 audit rules"  check="all">
0b628f
+      <ind:object object_ref="oval:x:obj:1"/>
0b628f
+    </ind:textfilecontent54_test>
0b628f
+  </tests>
0b628f
+
0b628f
+  <objects>
0b628f
+    <ind:textfilecontent54_object id="oval:x:obj:1" version="1" comment="Object representing file">
0b628f
+      <ind:path>/tmp</ind:path>
0b628f
+      <ind:filename>30-ospp-v42.rules</ind:filename>
0b628f
+      <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>
0b628f
+      <ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
0b628f
+    </ind:textfilecontent54_object>
0b628f
+  </objects>
0b628f
+
0b628f
+</oval_definitions>
0b628f
diff --git a/tests/probes/textfilecontent54/test_recursion_limit.sh b/tests/probes/textfilecontent54/test_recursion_limit.sh
0b628f
new file mode 100755
0b628f
index 000000000..2619dafdd
0b628f
--- /dev/null
0b628f
+++ b/tests/probes/textfilecontent54/test_recursion_limit.sh
0b628f
@@ -0,0 +1,31 @@
0b628f
+#!/usr/bin/env bash
0b628f
+
0b628f
+set -e -o pipefail
0b628f
+
0b628f
+. $builddir/tests/test_common.sh
0b628f
+
0b628f
+probecheck "textfilecontent54" || exit 255
0b628f
+
0b628f
+cp $srcdir/30-ospp-v42.rules /tmp
0b628f
+
0b628f
+name=$(basename $0 .sh)
0b628f
+input=$srcdir/$name.oval.xml
0b628f
+result=$(mktemp)
0b628f
+stdout=$(mktemp)
0b628f
+stderr=$(mktemp)
0b628f
+
0b628f
+$OSCAP oval eval --results $result $input > $stdout 2> $stderr
0b628f
+
0b628f
+grep -q "Function pcre_exec() failed to match a regular expression with return code -21" $stderr
0b628f
+
0b628f
+assert_exists 1 '/oval_results/results/system/definitions/definition[@definition_id="oval:x:def:1" and @result="error"]'
0b628f
+
0b628f
+co='/oval_results/results/system/oval_system_characteristics/collected_objects'
0b628f
+assert_exists 1 $co'/object[@flag="error"]'
0b628f
+assert_exists 1 $co'/object/message[@level="error"]'
0b628f
+assert_exists 1 $co'/object/message[text()="Regular expression pattern match failed in file /tmp/30-ospp-v42.rules with error -21."]'
0b628f
+
0b628f
+rm -f /tmp/30-ospp-v42.rules
0b628f
+rm -f $result
0b628f
+rm -f $stdout
0b628f
+rm -f $stderr