diff options
Diffstat (limited to 'meta/recipes-core/busybox/files/CVE-2021-423xx-awk.patch')
-rw-r--r-- | meta/recipes-core/busybox/files/CVE-2021-423xx-awk.patch | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/meta/recipes-core/busybox/files/CVE-2021-423xx-awk.patch b/meta/recipes-core/busybox/files/CVE-2021-423xx-awk.patch new file mode 100644 index 0000000000..7e3d47b88c --- /dev/null +++ b/meta/recipes-core/busybox/files/CVE-2021-423xx-awk.patch | |||
@@ -0,0 +1,215 @@ | |||
1 | From a21708eb8d07b4a6dbc1d3e4ace4c5721515a84c Mon Sep 17 00:00:00 2001 | ||
2 | From: Sana Kazi <Sana.Kazi@kpit.com> | ||
3 | Date: Wed, 8 Dec 2021 12:25:34 +0530 | ||
4 | Subject: [PATCH] busybox: Fix multiple security issues in awk | ||
5 | |||
6 | Description: fix multiple security issues in awk | ||
7 | Origin: backported awk.c from busybox 1.34.1 | ||
8 | |||
9 | CVE: CVE-2021-42378 | ||
10 | CVE: CVE-2021-42379 | ||
11 | CVE: CVE-2021-42380 | ||
12 | CVE: CVE-2021-42381 | ||
13 | CVE: CVE-2021-42382 | ||
14 | CVE: CVE-2021-42384 | ||
15 | CVE: CVE-2021-42385 | ||
16 | CVE: CVE-2021-42386 | ||
17 | |||
18 | Upstream-Status: Backport [https://launchpad.net/ubuntu/+archive/primary/+sourcefiles/busybox/1:1.30.1-6ubuntu3.1/busybox_1.30.1-6ubuntu3.1.debian.tar.xz] | ||
19 | |||
20 | Comment: Refreshed first hunk and removed few hunks as they are already present in source. | ||
21 | |||
22 | Signed-off-by: Sana Kazi <Sana.Kazi@kpit.com> | ||
23 | Signed-off-by: Ranjitsinh Rathod <Ranjitsinh.Rathod@kpit.com> | ||
24 | |||
25 | --- | ||
26 | editors/awk.c | 80 ++++++++++++++++++++++++++++++++++++++------------- | ||
27 | 1 file changed, 60 insertions(+), 20 deletions(-) | ||
28 | |||
29 | diff --git a/editors/awk.c b/editors/awk.c | ||
30 | index d25508e..4e4f282 100644 | ||
31 | --- a/editors/awk.c | ||
32 | +++ b/editors/awk.c | ||
33 | @@ -272,7 +272,8 @@ typedef struct tsplitter_s { | ||
34 | /* if previous token class is CONCAT1 and next is CONCAT2, concatenation */ | ||
35 | /* operator is inserted between them */ | ||
36 | #define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \ | ||
37 | - | TC_STRING | TC_NUMBER | TC_UOPPOST) | ||
38 | + | TC_STRING | TC_NUMBER | TC_UOPPOST \ | ||
39 | + | TC_LENGTH) | ||
40 | #define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE) | ||
41 | |||
42 | #define OF_RES1 0x010000 | ||
43 | @@ -404,7 +405,7 @@ static const char tokenlist[] ALIGN1 = | ||
44 | |||
45 | #define OC_B OC_BUILTIN | ||
46 | |||
47 | -static const uint32_t tokeninfo[] = { | ||
48 | +static const uint32_t tokeninfo[] ALIGN4 = { | ||
49 | 0, | ||
50 | 0, | ||
51 | OC_REGEXP, | ||
52 | @@ -1070,8 +1071,10 @@ static uint32_t next_token(uint32_t expected) | ||
53 | const uint32_t *ti; | ||
54 | |||
55 | if (t_rollback) { | ||
56 | + debug_printf_parse("%s: using rolled-back token\n", __func__); | ||
57 | t_rollback = FALSE; | ||
58 | } else if (concat_inserted) { | ||
59 | + debug_printf_parse("%s: using concat-inserted token\n", __func__); | ||
60 | concat_inserted = FALSE; | ||
61 | t_tclass = save_tclass; | ||
62 | t_info = save_info; | ||
63 | @@ -1200,7 +1203,11 @@ static uint32_t next_token(uint32_t expected) | ||
64 | goto readnext; | ||
65 | |||
66 | /* insert concatenation operator when needed */ | ||
67 | - if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) { | ||
68 | + debug_printf_parse("%s: %x %x %x concat_inserted?\n", __func__, | ||
69 | + (ltclass & TC_CONCAT1), (tc & TC_CONCAT2), (expected & TC_BINOP)); | ||
70 | + if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP) | ||
71 | + && !(ltclass == TC_LENGTH && tc == TC_SEQSTART) /* but not for "length(..." */ | ||
72 | + ) { | ||
73 | concat_inserted = TRUE; | ||
74 | save_tclass = tc; | ||
75 | save_info = t_info; | ||
76 | @@ -1208,6 +1215,7 @@ static uint32_t next_token(uint32_t expected) | ||
77 | t_info = OC_CONCAT | SS | P(35); | ||
78 | } | ||
79 | |||
80 | + debug_printf_parse("%s: t_tclass=tc=%x\n", __func__, t_tclass); | ||
81 | t_tclass = tc; | ||
82 | } | ||
83 | ltclass = t_tclass; | ||
84 | @@ -1218,6 +1226,7 @@ static uint32_t next_token(uint32_t expected) | ||
85 | EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN); | ||
86 | } | ||
87 | |||
88 | + debug_printf_parse("%s: returning, ltclass:%x t_double:%f\n", __func__, ltclass, t_double); | ||
89 | return ltclass; | ||
90 | #undef concat_inserted | ||
91 | #undef save_tclass | ||
92 | @@ -1282,7 +1291,7 @@ static node *parse_expr(uint32_t iexp) | ||
93 | glptr = NULL; | ||
94 | |||
95 | } else if (tc & (TC_BINOP | TC_UOPPOST)) { | ||
96 | - debug_printf_parse("%s: TC_BINOP | TC_UOPPOST\n", __func__); | ||
97 | + debug_printf_parse("%s: TC_BINOP | TC_UOPPOST tc:%x\n", __func__, tc); | ||
98 | /* for binary and postfix-unary operators, jump back over | ||
99 | * previous operators with higher priority */ | ||
100 | vn = cn; | ||
101 | @@ -1350,8 +1359,10 @@ static node *parse_expr(uint32_t iexp) | ||
102 | v = cn->l.v = xzalloc(sizeof(var)); | ||
103 | if (tc & TC_NUMBER) | ||
104 | setvar_i(v, t_double); | ||
105 | - else | ||
106 | + else { | ||
107 | setvar_s(v, t_string); | ||
108 | + xtc &= ~TC_UOPPOST; /* "str"++ is not allowed */ | ||
109 | + } | ||
110 | break; | ||
111 | |||
112 | case TC_REGEXP: | ||
113 | @@ -1387,7 +1398,12 @@ static node *parse_expr(uint32_t iexp) | ||
114 | |||
115 | case TC_LENGTH: | ||
116 | debug_printf_parse("%s: TC_LENGTH\n", __func__); | ||
117 | - next_token(TC_SEQSTART | TC_OPTERM | TC_GRPTERM); | ||
118 | + next_token(TC_SEQSTART /* length(...) */ | ||
119 | + | TC_OPTERM /* length; (or newline)*/ | ||
120 | + | TC_GRPTERM /* length } */ | ||
121 | + | TC_BINOPX /* length <op> NUM */ | ||
122 | + | TC_COMMA /* print length, 1 */ | ||
123 | + ); | ||
124 | rollback_token(); | ||
125 | if (t_tclass & TC_SEQSTART) { | ||
126 | /* It was a "(" token. Handle just like TC_BUILTIN */ | ||
127 | @@ -1747,12 +1763,34 @@ static void fsrealloc(int size) | ||
128 | nfields = size; | ||
129 | } | ||
130 | |||
131 | +static int regexec1_nonempty(const regex_t *preg, const char *s, regmatch_t pmatch[]) | ||
132 | +{ | ||
133 | + int r = regexec(preg, s, 1, pmatch, 0); | ||
134 | + if (r == 0 && pmatch[0].rm_eo == 0) { | ||
135 | + /* For example, happens when FS can match | ||
136 | + * an empty string (awk -F ' *'). Logically, | ||
137 | + * this should split into one-char fields. | ||
138 | + * However, gawk 5.0.1 searches for first | ||
139 | + * _non-empty_ separator string match: | ||
140 | + */ | ||
141 | + size_t ofs = 0; | ||
142 | + do { | ||
143 | + ofs++; | ||
144 | + if (!s[ofs]) | ||
145 | + return REG_NOMATCH; | ||
146 | + regexec(preg, s + ofs, 1, pmatch, 0); | ||
147 | + } while (pmatch[0].rm_eo == 0); | ||
148 | + pmatch[0].rm_so += ofs; | ||
149 | + pmatch[0].rm_eo += ofs; | ||
150 | + } | ||
151 | + return r; | ||
152 | +} | ||
153 | + | ||
154 | static int awk_split(const char *s, node *spl, char **slist) | ||
155 | { | ||
156 | - int l, n; | ||
157 | + int n; | ||
158 | char c[4]; | ||
159 | char *s1; | ||
160 | - regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough... | ||
161 | |||
162 | /* in worst case, each char would be a separate field */ | ||
163 | *slist = s1 = xzalloc(strlen(s) * 2 + 3); | ||
164 | @@ -1769,29 +1807,31 @@ static int awk_split(const char *s, node *spl, char **slist) | ||
165 | return n; /* "": zero fields */ | ||
166 | n++; /* at least one field will be there */ | ||
167 | do { | ||
168 | + int l; | ||
169 | + regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough... | ||
170 | + | ||
171 | l = strcspn(s, c+2); /* len till next NUL or \n */ | ||
172 | - if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0 | ||
173 | + if (regexec1_nonempty(icase ? spl->r.ire : spl->l.re, s, pmatch) == 0 | ||
174 | && pmatch[0].rm_so <= l | ||
175 | ) { | ||
176 | + /* if (pmatch[0].rm_eo == 0) ... - impossible */ | ||
177 | l = pmatch[0].rm_so; | ||
178 | - if (pmatch[0].rm_eo == 0) { | ||
179 | - l++; | ||
180 | - pmatch[0].rm_eo++; | ||
181 | - } | ||
182 | n++; /* we saw yet another delimiter */ | ||
183 | } else { | ||
184 | pmatch[0].rm_eo = l; | ||
185 | if (s[l]) | ||
186 | pmatch[0].rm_eo++; | ||
187 | } | ||
188 | - memcpy(s1, s, l); | ||
189 | - /* make sure we remove *all* of the separator chars */ | ||
190 | - do { | ||
191 | - s1[l] = '\0'; | ||
192 | - } while (++l < pmatch[0].rm_eo); | ||
193 | - nextword(&s1); | ||
194 | + s1 = mempcpy(s1, s, l); | ||
195 | + *s1++ = '\0'; | ||
196 | s += pmatch[0].rm_eo; | ||
197 | } while (*s); | ||
198 | + | ||
199 | + /* echo a-- | awk -F-- '{ print NF, length($NF), $NF }' | ||
200 | + * should print "2 0 ": | ||
201 | + */ | ||
202 | + *s1 = '\0'; | ||
203 | + | ||
204 | return n; | ||
205 | } | ||
206 | if (c[0] == '\0') { /* null split */ | ||
207 | @@ -1995,7 +2035,7 @@ static int ptest(node *pattern) | ||
208 | static int awk_getline(rstream *rsm, var *v) | ||
209 | { | ||
210 | char *b; | ||
211 | - regmatch_t pmatch[2]; | ||
212 | + regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough... | ||
213 | int size, a, p, pp = 0; | ||
214 | int fd, so, eo, r, rp; | ||
215 | char c, *m, *s; | ||