]> git.pld-linux.org Git - packages/libuv.git/blame - CVE-2021-22918.patch
upstream fix for CVE-2021-22918; rel 2
[packages/libuv.git] / CVE-2021-22918.patch
CommitLineData
52b5b29e
JP
1From b7466e31e4bee160d82a68fca11b1f61d46debae Mon Sep 17 00:00:00 2001
2From: Ben Noordhuis <info@bnoordhuis.nl>
3Date: Fri, 21 May 2021 11:23:36 +0200
4Subject: [PATCH] idna: fix OOB read in punycode decoder
5
6libuv was vulnerable to out-of-bounds reads in the uv__idna_toascii()
7function which is used to convert strings to ASCII. This is called by
8the DNS resolution function and can lead to information disclosures or
9crashes.
10
11Reported by Eric Sesterhenn in collaboration with Cure53 and ExpressVPN.
12
13Reported-By: Eric Sesterhenn <eric.sesterhenn@x41-dsec.de>
14Fixes: https://github.com/libuv/libuv/issues/3147
15PR-URL: https://github.com/libuv/libuv-private/pull/1
16Refs: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22918
17Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
18Reviewed-By: Richard Lau <riclau@uk.ibm.com>
19---
20 src/idna.c | 49 +++++++++++++++++++++++++++++++++++-------------
21 test/test-idna.c | 19 +++++++++++++++++++
22 test/test-list.h | 2 ++
23 3 files changed, 57 insertions(+), 13 deletions(-)
24
25diff --git a/src/idna.c b/src/idna.c
26index 13ffac6be8..b44cb16a1e 100644
27--- a/src/idna.c
28+++ b/src/idna.c
29@@ -19,6 +19,7 @@
30
31 #include "uv.h"
32 #include "idna.h"
33+#include <assert.h>
34 #include <string.h>
35
36 static unsigned uv__utf8_decode1_slow(const char** p,
37@@ -32,7 +33,7 @@ static unsigned uv__utf8_decode1_slow(const char** p,
38 if (a > 0xF7)
39 return -1;
40
41- switch (*p - pe) {
42+ switch (pe - *p) {
43 default:
44 if (a > 0xEF) {
45 min = 0x10000;
46@@ -62,6 +63,8 @@ static unsigned uv__utf8_decode1_slow(const char** p,
47 a = 0;
48 break;
49 }
50+ /* Fall through. */
51+ case 0:
52 return -1; /* Invalid continuation byte. */
53 }
54
55@@ -88,6 +91,8 @@ static unsigned uv__utf8_decode1_slow(const char** p,
56 unsigned uv__utf8_decode1(const char** p, const char* pe) {
57 unsigned a;
58
59+ assert(*p < pe);
60+
61 a = (unsigned char) *(*p)++;
62
63 if (a < 128)
64@@ -96,9 +101,6 @@ unsigned uv__utf8_decode1(const char** p, const char* pe) {
65 return uv__utf8_decode1_slow(p, pe, a);
66 }
67
68-#define foreach_codepoint(c, p, pe) \
69- for (; (void) (*p <= pe && (c = uv__utf8_decode1(p, pe))), *p <= pe;)
70-
71 static int uv__idna_toascii_label(const char* s, const char* se,
72 char** d, char* de) {
73 static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
74@@ -121,15 +123,22 @@ static int uv__idna_toascii_label(const char* s, const char* se,
75 ss = s;
76 todo = 0;
77
78- foreach_codepoint(c, &s, se) {
79+ /* Note: after this loop we've visited all UTF-8 characters and know
80+ * they're legal so we no longer need to check for decode errors.
81+ */
82+ while (s < se) {
83+ c = uv__utf8_decode1(&s, se);
84+
85+ if (c == -1u)
86+ return UV_EINVAL;
87+
88 if (c < 128)
89 h++;
90- else if (c == (unsigned) -1)
91- return UV_EINVAL;
92 else
93 todo++;
94 }
95
96+ /* Only write "xn--" when there are non-ASCII characters. */
97 if (todo > 0) {
98 if (*d < de) *(*d)++ = 'x';
99 if (*d < de) *(*d)++ = 'n';
100@@ -137,9 +146,13 @@ static int uv__idna_toascii_label(const char* s, const char* se,
101 if (*d < de) *(*d)++ = '-';
102 }
103
104+ /* Write ASCII characters. */
105 x = 0;
106 s = ss;
107- foreach_codepoint(c, &s, se) {
108+ while (s < se) {
109+ c = uv__utf8_decode1(&s, se);
110+ assert(c != -1u);
111+
112 if (c > 127)
113 continue;
114
115@@ -166,10 +179,15 @@ static int uv__idna_toascii_label(const char* s, const char* se,
116 while (todo > 0) {
117 m = -1;
118 s = ss;
119- foreach_codepoint(c, &s, se)
120+
121+ while (s < se) {
122+ c = uv__utf8_decode1(&s, se);
123+ assert(c != -1u);
124+
125 if (c >= n)
126 if (c < m)
127 m = c;
128+ }
129
130 x = m - n;
131 y = h + 1;
132@@ -181,7 +199,10 @@ static int uv__idna_toascii_label(const char* s, const char* se,
133 n = m;
134
135 s = ss;
136- foreach_codepoint(c, &s, se) {
137+ while (s < se) {
138+ c = uv__utf8_decode1(&s, se);
139+ assert(c != -1u);
140+
141 if (c < n)
142 if (++delta == 0)
143 return UV_E2BIG; /* Overflow. */
144@@ -245,8 +266,6 @@ static int uv__idna_toascii_label(const char* s, const char* se,
145 return 0;
146 }
147
148-#undef foreach_codepoint
149-
150 long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
151 const char* si;
152 const char* st;
153@@ -256,10 +275,14 @@ long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
154
155 ds = d;
156
157- for (si = s; si < se; /* empty */) {
158+ si = s;
159+ while (si < se) {
160 st = si;
161 c = uv__utf8_decode1(&si, se);
162
163+ if (c == -1u)
164+ return UV_EINVAL;
165+
166 if (c != '.')
167 if (c != 0x3002) /* 。 */
168 if (c != 0xFF0E) /* . */
169diff --git a/test/test-idna.c b/test/test-idna.c
170index b76853cb99..f4fad9653d 100644
171--- a/test/test-idna.c
172+++ b/test/test-idna.c
173@@ -96,6 +96,25 @@ TEST_IMPL(utf8_decode1) {
174 return 0;
175 }
176
177+TEST_IMPL(utf8_decode1_overrun) {
178+ const char* p;
179+ char b[1];
180+
181+ /* Single byte. */
182+ p = b;
183+ b[0] = 0x7F;
184+ ASSERT_EQ(0x7F, uv__utf8_decode1(&p, b + 1));
185+ ASSERT_EQ(p, b + 1);
186+
187+ /* Multi-byte. */
188+ p = b;
189+ b[0] = 0xC0;
190+ ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + 1));
191+ ASSERT_EQ(p, b + 1);
192+
193+ return 0;
194+}
195+
196 /* Doesn't work on z/OS because that platform uses EBCDIC, not ASCII. */
197 #ifndef __MVS__
198
199diff --git a/test/test-list.h b/test/test-list.h
200index c3c6002ea3..424eea07fa 100644
201--- a/test/test-list.h
202+++ b/test/test-list.h
203@@ -528,6 +528,7 @@ TEST_DECLARE (fork_threadpool_queue_work_simple)
204
205 TEST_DECLARE (idna_toascii)
206 TEST_DECLARE (utf8_decode1)
207+TEST_DECLARE (utf8_decode1_overrun)
208 TEST_DECLARE (uname)
209
210 TEST_DECLARE (metrics_idle_time)
211@@ -1124,6 +1125,7 @@ TASK_LIST_START
212 #endif
213
214 TEST_ENTRY (utf8_decode1)
215+ TEST_ENTRY (utf8_decode1_overrun)
216 TEST_ENTRY (uname)
217
218 /* Doesn't work on z/OS because that platform uses EBCDIC, not ASCII. */
This page took 0.115885 seconds and 4 git commands to generate.