Skip to content

Commit 4da2378

Browse files
authored
Merge pull request #1493 from jan-cerny/recurse_seg
Prevent crashes when complicated regexes are executed
2 parents 0e79be0 + a822745 commit 4da2378

File tree

9 files changed

+277
-113
lines changed

9 files changed

+277
-113
lines changed

docs/developer/developer.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,8 @@ behaviour.
317317

318318
* *OSCAP_FULL_VALIDATION=1* - validate all exported documents (slower)
319319
* *SEXP_VALIDATE_DISABLE=1* - do not validate SEXP expressions (faster)
320+
* *OSCAP_PCRE_EXEC_RECURSION_LIMIT* - override default recursion limit
321+
for match in pcre_exec call in textfilecontent(54) probes.
320322

321323

322324

src/OVAL/probes/independent/textfilecontent54_probe.c

Lines changed: 2 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -52,68 +52,11 @@
5252
#include <probe/option.h>
5353
#include <oval_fts.h>
5454
#include "common/debug_priv.h"
55+
#include "common/util.h"
5556
#include "textfilecontent54_probe.h"
5657

5758
#define FILE_SEPARATOR '/'
5859

59-
static int get_substrings(char *str, int *ofs, pcre *re, int want_substrs, char ***substrings) {
60-
int i, ret, rc;
61-
int ovector[60], ovector_len = sizeof (ovector) / sizeof (ovector[0]);
62-
char **substrs;
63-
64-
// todo: max match count check
65-
66-
for (i = 0; i < ovector_len; ++i)
67-
ovector[i] = -1;
68-
69-
#if defined(OS_SOLARIS)
70-
rc = pcre_exec(re, NULL, str, strlen(str), *ofs, PCRE_NO_UTF8_CHECK, ovector, ovector_len);
71-
#else
72-
rc = pcre_exec(re, NULL, str, strlen(str), *ofs, 0, ovector, ovector_len);
73-
#endif
74-
75-
if (rc < -1) {
76-
dE("Function pcre_exec() failed to match a regular expression with return code %d on string '%s'.", rc, str);
77-
return rc;
78-
} else if (rc == -1) {
79-
/* no match */
80-
return 0;
81-
}
82-
83-
*ofs = (*ofs == ovector[1]) ? ovector[1] + 1 : ovector[1];
84-
85-
if (!want_substrs) {
86-
/* just report successful match */
87-
return 1;
88-
}
89-
90-
ret = 0;
91-
if (rc == 0) {
92-
/* vector too small */
93-
// todo: report partial results
94-
rc = ovector_len / 3;
95-
}
96-
97-
substrs = malloc(rc * sizeof (char *));
98-
for (i = 0; i < rc; ++i) {
99-
int len;
100-
char *buf;
101-
102-
if (ovector[2 * i] == -1)
103-
continue;
104-
len = ovector[2 * i + 1] - ovector[2 * i];
105-
buf = malloc(len + 1);
106-
memcpy(buf, str + ovector[2 * i], len);
107-
buf[len] = '\0';
108-
substrs[ret] = buf;
109-
++ret;
110-
}
111-
112-
*substrings = substrs;
113-
114-
return ret;
115-
}
116-
11760
static SEXP_t *create_item(const char *path, const char *filename, char *pattern,
11861
int instance, char **substrs, int substr_cnt, oval_schema_version_t over)
11962
{
@@ -260,7 +203,7 @@ static int process_file(const char *prefix, const char *path, const char *file,
260203
want_instance = 0;
261204

262205
SEXP_free(next_inst);
263-
substr_cnt = get_substrings(buf, &ofs, pfd->compiled_regex, want_instance, &substrs);
206+
substr_cnt = oscap_get_substrings(buf, &ofs, pfd->compiled_regex, want_instance, &substrs);
264207

265208
if (substr_cnt < 0) {
266209
SEXP_t *msg;

src/OVAL/probes/independent/textfilecontent_probe.c

Lines changed: 3 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -71,63 +71,11 @@
7171
#include <probe/option.h>
7272
#include <oval_fts.h>
7373
#include "common/debug_priv.h"
74+
#include "common/util.h"
7475
#include "textfilecontent_probe.h"
7576

7677
#define FILE_SEPARATOR '/'
7778

78-
static int get_substrings(char *str, pcre *re, int want_substrs, char ***substrings) {
79-
int i, ret, rc;
80-
int ovector[60], ovector_len = sizeof (ovector) / sizeof (ovector[0]);
81-
82-
// todo: max match count check
83-
84-
for (i = 0; i < ovector_len; ++i)
85-
ovector[i] = -1;
86-
87-
rc = pcre_exec(re, NULL, str, strlen(str), 0, 0,
88-
ovector, ovector_len);
89-
90-
if (rc < -1) {
91-
return -1;
92-
} else if (rc == -1) {
93-
/* no match */
94-
return 0;
95-
} else if(!want_substrs) {
96-
/* just report successful match */
97-
return 1;
98-
}
99-
100-
char **substrs;
101-
102-
ret = 0;
103-
if (rc == 0) {
104-
/* vector too small */
105-
rc = ovector_len / 3;
106-
}
107-
108-
substrs = malloc(rc * sizeof (char *));
109-
for (i = 0; i < rc; ++i) {
110-
int len;
111-
char *buf;
112-
113-
if (ovector[2 * i] == -1)
114-
continue;
115-
len = ovector[2 * i + 1] - ovector[2 * i];
116-
buf = malloc(len + 1);
117-
memcpy(buf, str + ovector[2 * i], len);
118-
buf[len] = '\0';
119-
substrs[ret] = buf;
120-
++ret;
121-
}
122-
/*
123-
if (ret < rc)
124-
substrs = realloc(substrs, ret * sizeof (char *));
125-
*/
126-
*substrings = substrs;
127-
128-
return ret;
129-
}
130-
13179
static SEXP_t *create_item(const char *path, const char *filename, char *pattern,
13280
int instance, char **substrs, int substr_cnt, oval_schema_version_t over)
13381
{
@@ -244,9 +192,10 @@ static int process_file(const char *prefix, const char *path, const char *filena
244192

245193
int cur_inst = 0;
246194
char line[4096];
195+
int ofs = 0;
247196

248197
while (fgets(line, sizeof(line), fp) != NULL) {
249-
substr_cnt = get_substrings(line, re, 1, &substrs);
198+
substr_cnt = oscap_get_substrings(line, &ofs, re, 1, &substrs);
250199
if (substr_cnt > 0) {
251200
int k;
252201
SEXP_t *item;

src/common/util.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@
3030
#include <limits.h>
3131
#include <stdarg.h>
3232
#include <math.h>
33+
#include <pcre.h>
3334

3435
#include "util.h"
3536
#include "_error.h"
3637
#include "oscap.h"
3738
#include "oscap_helpers.h"
39+
#include "debug_priv.h"
3840

3941
#ifdef OS_WINDOWS
4042
#include <stdlib.h>
@@ -45,6 +47,7 @@
4547
#endif
4648

4749
#define PATH_SEPARATOR '/'
50+
#define OSCAP_PCRE_EXEC_RECURSION_LIMIT_DEFAULT 5000
4851

4952
int oscap_string_to_enum(const struct oscap_string_map *map, const char *str)
5053
{
@@ -353,6 +356,76 @@ char *oscap_path_join(const char *path1, const char *path2)
353356
return joined_path;
354357
}
355358

359+
int oscap_get_substrings(char *str, int *ofs, pcre *re, int want_substrs, char ***substrings) {
360+
int i, ret, rc;
361+
int ovector[60], ovector_len = sizeof (ovector) / sizeof (ovector[0]);
362+
char **substrs;
363+
364+
// todo: max match count check
365+
366+
for (i = 0; i < ovector_len; ++i) {
367+
ovector[i] = -1;
368+
}
369+
370+
struct pcre_extra extra;
371+
extra.match_limit_recursion = OSCAP_PCRE_EXEC_RECURSION_LIMIT_DEFAULT;
372+
char *limit_str = getenv("OSCAP_PCRE_EXEC_RECURSION_LIMIT");
373+
if (limit_str != NULL) {
374+
unsigned long limit;
375+
if (sscanf(limit_str, "%lu", &limit) == 1) {
376+
extra.match_limit_recursion = limit;
377+
}
378+
}
379+
extra.flags = PCRE_EXTRA_MATCH_LIMIT_RECURSION;
380+
#if defined(OS_SOLARIS)
381+
rc = pcre_exec(re, &extra, str, strlen(str), *ofs, PCRE_NO_UTF8_CHECK, ovector, ovector_len);
382+
#else
383+
rc = pcre_exec(re, &extra, str, strlen(str), *ofs, 0, ovector, ovector_len);
384+
#endif
385+
386+
if (rc < -1) {
387+
dE("Function pcre_exec() failed to match a regular expression with return code %d on string '%s'.", rc, str);
388+
return rc;
389+
} else if (rc == -1) {
390+
/* no match */
391+
return 0;
392+
}
393+
394+
*ofs = (*ofs == ovector[1]) ? ovector[1] + 1 : ovector[1];
395+
396+
if (!want_substrs) {
397+
/* just report successful match */
398+
return 1;
399+
}
400+
401+
ret = 0;
402+
if (rc == 0) {
403+
/* vector too small */
404+
// todo: report partial results
405+
rc = ovector_len / 3;
406+
}
407+
408+
substrs = malloc(rc * sizeof (char *));
409+
for (i = 0; i < rc; ++i) {
410+
int len;
411+
char *buf;
412+
413+
if (ovector[2 * i] == -1) {
414+
continue;
415+
}
416+
len = ovector[2 * i + 1] - ovector[2 * i];
417+
buf = malloc(len + 1);
418+
memcpy(buf, str + ovector[2 * i], len);
419+
buf[len] = '\0';
420+
substrs[ret] = buf;
421+
++ret;
422+
}
423+
424+
*substrings = substrs;
425+
426+
return ret;
427+
}
428+
356429
#ifdef OS_WINDOWS
357430
char *oscap_windows_wstr_to_str(const wchar_t *wstr)
358431
{

src/common/util.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "public/oscap.h"
3232
#include <stdarg.h>
3333
#include <string.h>
34+
#include <pcre.h>
3435
#include "oscap_export.h"
3536

3637
#ifndef __attribute__nonnull__
@@ -467,6 +468,19 @@ int oscap_strncasecmp(const char *s1, const char *s2, size_t n);
467468
*/
468469
char *oscap_strerror_r(int errnum, char *buf, size_t buflen);
469470

471+
/**
472+
* Match a regular expression and return substrings.
473+
* Caller is responsible for freeing the returned array.
474+
* @param str subject string
475+
* @param ofs starting offset in str
476+
* @param re compiled regular expression
477+
* @param want_substrs if non-zero, substrings will be returned
478+
* @param substrings contains returned substrings
479+
* @return count of matched substrings, 0 if no match
480+
* negative value on failure
481+
*/
482+
int oscap_get_substrings(char *str, int *ofs, pcre *re, int want_substrs, char ***substrings);
483+
470484
#ifdef OS_WINDOWS
471485
/**
472486
* Convert wide character string to a C string (UTF-16 to UTF-8)

0 commit comments

Comments
 (0)