|
21 | 21 | */ |
22 | 22 |
|
23 | 23 | import cpp |
| 24 | +private import semmle.code.cpp.regex.internal.StdRegex |
24 | 25 |
|
25 | 26 | // --------------------------------------------------------------------------- |
26 | 27 | // Fast-path filter: only consider literals that *look* regex-y |
27 | 28 | // --------------------------------------------------------------------------- |
28 | 29 | /** |
29 | | - * A string literal that is a plausible ReDoS candidate: it contains at least |
30 | | - * one unbounded-repetition quantifier (`+`, `*`, or `{n,}`). |
| 30 | + * Holds if `s` is a plausible ReDoS-candidate string literal value: it |
| 31 | + * contains at least one unbounded-repetition quantifier (`+`, `*`, or |
| 32 | + * `{n,}`). |
31 | 33 | * |
32 | | - * This filter is applied by the flag readers below as an optimisation: |
33 | | - * regexes without such a quantifier are not interesting for the |
34 | | - * polynomial-ReDoS analysis, and skipping them here mirrors the source |
35 | | - * restriction of the dataflow configuration in `RegexFlowConfigs`, |
36 | | - * preserving analysis results exactly. |
37 | | - */ |
38 | | -class ExploitableStringLiteral extends StringLiteral { |
39 | | - ExploitableStringLiteral() { |
40 | | - exists(string s | s = this.getValue() | |
41 | | - s.regexpMatch(".*[+*].*") or |
42 | | - s.regexpMatch(".*\\{[0-9]+,[0-9]*\\}.*") |
43 | | - ) |
44 | | - } |
45 | | -} |
46 | | - |
47 | | -// --------------------------------------------------------------------------- |
48 | | -// std::basic_regex identification |
49 | | -// --------------------------------------------------------------------------- |
50 | | -/** |
51 | | - * A `std::basic_regex` class type (or instantiation thereof, e.g. `std::regex`, |
52 | | - * `std::wregex`). |
53 | | - */ |
54 | | -class StdBasicRegex extends Class { |
55 | | - StdBasicRegex() { |
56 | | - this.hasQualifiedName("std", "basic_regex") |
57 | | - or |
58 | | - this.(ClassTemplateInstantiation).getTemplate().hasQualifiedName("std", "basic_regex") |
59 | | - } |
| 34 | + * This mirrors the source restriction of the dataflow configuration in |
| 35 | + * `RegexFlowConfigs` (whose sources are the `ExploitableStringLiteral`s), |
| 36 | + * so that the flag readers below consider exactly the same set of regexes |
| 37 | + * as the taint-tracking configuration. Inlined here as a syntactic check |
| 38 | + * to keep this module flow-free. |
| 39 | + */ |
| 40 | +private predicate isExploitableStringLiteralValue(StringLiteral s) { |
| 41 | + exists(string v | v = s.getValue() | |
| 42 | + v.regexpMatch(".*[+*].*") or |
| 43 | + v.regexpMatch(".*\\{[0-9]+,[0-9]*\\}.*") |
| 44 | + ) |
60 | 45 | } |
61 | 46 |
|
62 | 47 | // --------------------------------------------------------------------------- |
@@ -124,13 +109,14 @@ private predicate isPatternLiteralOf(StringLiteral regex, Expr patternArg) { |
124 | 109 | * This association is purely syntactic (no dataflow): the pattern literal |
125 | 110 | * must appear inside the constructor/assign call's first argument. |
126 | 111 | * |
127 | | - * Restricted to `ExploitableStringLiteral` to preserve the exact set of |
| 112 | + * Restricted to string literals that look like plausible ReDoS candidates |
| 113 | + * (see `isExploitableStringLiteralValue`) to preserve the exact set of |
128 | 114 | * regexes considered by the flag readers when they were routed through |
129 | | - * the taint-tracking configuration (whose sources were the same |
| 115 | + * the taint-tracking configuration (whose sources are the same |
130 | 116 | * `ExploitableStringLiteral` set). |
131 | 117 | */ |
132 | 118 | private Expr getConstructionFlagArg(StringLiteral regex) { |
133 | | - regex instanceof ExploitableStringLiteral and |
| 119 | + isExploitableStringLiteralValue(regex) and |
134 | 120 | ( |
135 | 121 | // basic_regex(pattern, flags) constructor - both named-variable and |
136 | 122 | // temporary constructions are covered because the search for `regex` |
|
0 commit comments