diff options
Diffstat (limited to 'meta/recipes-support/re2c/re2c/CVE-2018-21232-3.patch')
-rw-r--r-- | meta/recipes-support/re2c/re2c/CVE-2018-21232-3.patch | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/meta/recipes-support/re2c/re2c/CVE-2018-21232-3.patch b/meta/recipes-support/re2c/re2c/CVE-2018-21232-3.patch new file mode 100644 index 0000000000..f942e21cba --- /dev/null +++ b/meta/recipes-support/re2c/re2c/CVE-2018-21232-3.patch | |||
@@ -0,0 +1,156 @@ | |||
1 | From 4d9c809355b574f2a58eac119f5e076c48e4d1e2 Mon Sep 17 00:00:00 2001 | ||
2 | From: Ulya Trofimovich <skvadrik@gmail.com> | ||
3 | Date: Thu, 23 Apr 2020 22:16:51 +0100 | ||
4 | Subject: [PATCH] Rewrite recursion into iteration (nullable RE). | ||
5 | |||
6 | This is to avoid stack overflow on large RE (especially on instrumented | ||
7 | builds that have larger stack frames, like AddressSanitizer). | ||
8 | |||
9 | Partial fix for #219 "overflow-1.re test fails on system with small stack". | ||
10 | |||
11 | Upstream-Status: Backport: | ||
12 | https://github.com/skvadrik/re2c/commit/4d9c809355b574f2a58eac119f5e076c48e4d1e2 | ||
13 | |||
14 | CVE: CVE-2018-21232 | ||
15 | |||
16 | Signed-off-by: Davide Gardenal <davide.gardenal@huawei.com> | ||
17 | --- | ||
18 | diff --git a/src/re/nullable.cc b/src/re/nullable.cc | ||
19 | --- a/src/re/nullable.cc (revision e58939b34bb4c37cd990f82dc286f21cb405743e) | ||
20 | +++ b/src/re/nullable.cc (date 1647253886226) | ||
21 | @@ -9,43 +9,100 @@ | ||
22 | #include "src/re/tag.h" | ||
23 | |||
24 | namespace re2c { | ||
25 | + namespace { | ||
26 | + | ||
27 | + struct StackItem { | ||
28 | + const RE *re; // current sub-RE | ||
29 | + uint8_t succ; // index of the next sucessor to be visited | ||
30 | + }; | ||
31 | |||
32 | -static bool nullable(const RESpec &spec, const RE *re, bool &trail) | ||
33 | -{ | ||
34 | - if (trail) return true; | ||
35 | + static bool nullable(const RESpec &spec, std::vector<StackItem> &stack, const RE *re0) | ||
36 | + { | ||
37 | + // the "nullable" status of the last sub-RE visited by DFS | ||
38 | + bool null = false; | ||
39 | |||
40 | - switch (re->type) { | ||
41 | - case RE::NIL: return true; | ||
42 | - case RE::SYM: return false; | ||
43 | - case RE::ITER: | ||
44 | - return nullable(spec, re->iter.re, trail); | ||
45 | - case RE::TAG: | ||
46 | - trail |= trailing(spec.tags[re->tag.idx]); | ||
47 | - return true; | ||
48 | - case RE::ALT: | ||
49 | - return nullable(spec, re->alt.re1, trail) | ||
50 | - || nullable(spec, re->alt.re2, trail); | ||
51 | - case RE::CAT: | ||
52 | - return nullable(spec, re->cat.re1, trail) | ||
53 | - && nullable(spec, re->cat.re2, trail); | ||
54 | - } | ||
55 | - return false; /* unreachable */ | ||
56 | -} | ||
57 | + const StackItem i0 = {re0, 0}; | ||
58 | + stack.push_back(i0); | ||
59 | + | ||
60 | + while (!stack.empty()) { | ||
61 | + const StackItem i = stack.back(); | ||
62 | + stack.pop_back(); | ||
63 | + | ||
64 | + const RE *re = i.re; | ||
65 | + if (re->type == RE::NIL) { | ||
66 | + null = true; | ||
67 | + } | ||
68 | + else if (re->type == RE::SYM) { | ||
69 | + null = false; | ||
70 | + } | ||
71 | + else if (re->type == RE::TAG) { | ||
72 | + null = true; | ||
73 | |||
74 | -/* | ||
75 | - * warn about rules that match empty string | ||
76 | - * (including rules with nonempty trailing context) | ||
77 | - * false positives on partially self-shadowed rules like [^]? | ||
78 | - */ | ||
79 | -void warn_nullable(const RESpec &spec, const std::string &cond) | ||
80 | -{ | ||
81 | - const size_t nre = spec.res.size(); | ||
82 | - for (size_t i = 0; i < nre; ++i) { | ||
83 | - bool trail = false; | ||
84 | - if (nullable(spec, spec.res[i], trail)) { | ||
85 | - spec.warn.match_empty_string(spec.rules[i].code->fline, cond); | ||
86 | - } | ||
87 | - } | ||
88 | -} | ||
89 | + // Trailing context is always in top-level concatenation, and sub-RE | ||
90 | + // are visited from left to right. Since we are here, sub-RE to the | ||
91 | + // left of the trailing context is nullable (otherwise we would not | ||
92 | + // recurse into the right sub-RE), therefore the whole RE is nullable. | ||
93 | + if (trailing(spec.tags[re->tag.idx])) { | ||
94 | + //DASSERT(stack.size() == 1 && stack.back().re->type == RE::CAT); | ||
95 | + stack.pop_back(); | ||
96 | + break; | ||
97 | + } | ||
98 | + } | ||
99 | + else if (re->type == RE::ALT) { | ||
100 | + if (i.succ == 0) { | ||
101 | + // recurse into the left sub-RE | ||
102 | + StackItem k = {re, 1}; | ||
103 | + stack.push_back(k); | ||
104 | + StackItem j = {re->alt.re1, 0}; | ||
105 | + stack.push_back(j); | ||
106 | + } | ||
107 | + else if (!null) { | ||
108 | + // if the left sub-RE is nullable, so is alternative, so stop | ||
109 | + // recursion; otherwise recurse into the right sub-RE | ||
110 | + StackItem j = {re->alt.re2, 0}; | ||
111 | + stack.push_back(j); | ||
112 | + } | ||
113 | + } | ||
114 | + else if (re->type == RE::CAT) { | ||
115 | + if (i.succ == 0) { | ||
116 | + // recurse into the left sub-RE | ||
117 | + StackItem k = {re, 1}; | ||
118 | + stack.push_back(k); | ||
119 | + StackItem j = {re->cat.re1, 0}; | ||
120 | + stack.push_back(j); | ||
121 | + } | ||
122 | + else if (null) { | ||
123 | + // if the left sub-RE is not nullable, neither is concatenation, | ||
124 | + // so stop recursion; otherwise recurse into the right sub-RE | ||
125 | + StackItem j = {re->cat.re2, 0}; | ||
126 | + stack.push_back(j); | ||
127 | + } | ||
128 | + } | ||
129 | + else if (re->type == RE::ITER) { | ||
130 | + // iteration is nullable if the sub-RE is nullable | ||
131 | + // (zero repetitions is represented with alternative) | ||
132 | + StackItem j = {re->iter.re, 0}; | ||
133 | + stack.push_back(j); | ||
134 | + } | ||
135 | + } | ||
136 | + | ||
137 | + //DASSERT(stack.empty()); | ||
138 | + return null; | ||
139 | + } | ||
140 | + | ||
141 | + } // anonymous namespace | ||
142 | + | ||
143 | +// Warn about rules that match empty string (including rules with nonempty | ||
144 | +// trailing context). False positives on partially self-shadowed rules like [^]? | ||
145 | + void warn_nullable(const RESpec &spec, const std::string &cond) | ||
146 | + { | ||
147 | + std::vector<StackItem> stack; | ||
148 | + const size_t nre = spec.res.size(); | ||
149 | + for (size_t i = 0; i < nre; ++i) { | ||
150 | + if (nullable(spec, stack, spec.res[i])) { | ||
151 | + spec.warn.match_empty_string(spec.rules[i].code->fline, cond); | ||
152 | + } | ||
153 | + } | ||
154 | + } | ||
155 | |||
156 | } // namespace re2c | ||