• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1From 97fe40da79ac0d28d13a68f2c8181d18b8ff0ef8 Mon Sep 17 00:00:00 2001
2From: s00423892 <shichenchen@huawei.com>
3Date: Fri, 19 May 2023 18:02:52 +0800
4Subject: [PATCH] [Backport]curl:fix CVE-2023-28321
5
6Conflict:The hostmatch function does not have the hostlen and patternlen parameters.
7However, the two parameters are the lengths of the existing input parameters host and pattern,
8which can be generated.
9Reference:https://github.com/curl/curl/commit/199f2d440d8659b42
10
11Signed-off-by: shichenchen shichenchen@huawei.com
12---
13 lib/hostcheck.c | 104 +++++++++++++++++++++++++-----------------------
14 1 file changed, 55 insertions(+), 49 deletions(-)
15
16diff --git a/lib/hostcheck.c b/lib/hostcheck.c
17index cf267a7..e055958 100644
18--- a/lib/hostcheck.c
19+++ b/lib/hostcheck.c
20@@ -33,6 +33,7 @@
21 #ifdef HAVE_NETINET_IN6_H
22 #include <netinet/in6.h>
23 #endif
24+#include "curl_memrchr.h"
25
26 #include "hostcheck.h"
27 #include "strcase.h"
28@@ -42,13 +43,23 @@
29 /* The last #include file should be: */
30 #include "memdebug.h"
31
32+/* check the two input strings with given length, but do not
33+   assume they end in nul-bytes */
34+static bool pmatch(const char *hostname, size_t hostlen,
35+                   const char *pattern, size_t patternlen)
36+{
37+  if(hostlen != patternlen)
38+    return FALSE;
39+  return strncasecompare(hostname, pattern, hostlen);
40+}
41+
42 /*
43  * Match a hostname against a wildcard pattern.
44  * E.g.
45  *  "foo.host.com" matches "*.host.com".
46  *
47  * We use the matching rule described in RFC6125, section 6.4.3.
48- * https://tools.ietf.org/html/rfc6125#section-6.4.3
49+ * https://datatracker.ietf.org/doc/html/rfc6125#section-6.4.3
50  *
51  * In addition: ignore trailing dots in the host names and wildcards, so that
52  * the names are used normalized. This is what the browsers do.
53@@ -58,65 +69,58 @@
54  * apparent distinction between a name and an IP. We need to detect the use of
55  * an IP address and not wildcard match on such names.
56  *
57- * NOTE: hostmatch() gets called with copied buffers so that it can modify the
58- * contents at will.
59+ * Only match on "*" being used for the leftmost label, not "a*", "a*b" nor
60+ * "*b".
61+ *
62+ * Return TRUE on a match. FALSE if not.
63+ *
64+ * @unittest: 1397
65  */
66
67-static int hostmatch(char *hostname, char *pattern)
68+static bool hostmatch(const char *hostname,
69+                      size_t hostlen,
70+                      const char *pattern,
71+                      size_t patternlen)
72 {
73-  const char *pattern_label_end, *pattern_wildcard, *hostname_label_end;
74-  int wildcard_enabled;
75-  size_t prefixlen, suffixlen;
76+  const char *pattern_label_end;
77+
78+  DEBUGASSERT(pattern);
79+  DEBUGASSERT(patternlen);
80+  DEBUGASSERT(hostname);
81+  DEBUGASSERT(hostlen);
82
83   /* normalize pattern and hostname by stripping off trailing dots */
84-  size_t len = strlen(hostname);
85-  if(hostname[len-1]=='.')
86-    hostname[len-1] = 0;
87-  len = strlen(pattern);
88-  if(pattern[len-1]=='.')
89-    pattern[len-1] = 0;
90-
91-  pattern_wildcard = strchr(pattern, '*');
92-  if(!pattern_wildcard)
93-    return strcasecompare(pattern, hostname) ?
94-      CURL_HOST_MATCH : CURL_HOST_NOMATCH;
95+  if(hostname[hostlen-1]=='.')
96+    hostlen--;
97+  if(pattern[patternlen-1]=='.')
98+    patternlen--;
99+
100+  if(strncmp(pattern, "*.", 2))
101+    return pmatch(hostname, hostlen, pattern, patternlen);
102
103   /* detect IP address as hostname and fail the match if so */
104-  if(Curl_host_is_ipnum(hostname))
105-    return CURL_HOST_NOMATCH;
106+  else if(Curl_host_is_ipnum(hostname))
107+    return FALSE;
108
109-  /* We require at least 2 dots in pattern to avoid too wide wildcard
110+  /* We require at least 2 dots in the pattern to avoid too wide wildcard
111      match. */
112-  wildcard_enabled = 1;
113-  pattern_label_end = strchr(pattern, '.');
114-  if(!pattern_label_end || strchr(pattern_label_end + 1, '.') == NULL ||
115-     pattern_wildcard > pattern_label_end ||
116-     strncasecompare(pattern, "xn--", 4)) {
117-    wildcard_enabled = 0;
118+  pattern_label_end = memchr(pattern, '.', patternlen);
119+  if(!pattern_label_end ||
120+     (memrchr(pattern, '.', patternlen) == pattern_label_end))
121+    return pmatch(hostname, hostlen, pattern, patternlen);
122+  else {
123+    const char *hostname_label_end = memchr(hostname, '.', hostlen);
124+    if(hostname_label_end) {
125+      size_t skiphost = hostname_label_end - hostname;
126+      size_t skiplen = pattern_label_end - pattern;
127+      return pmatch(hostname_label_end, hostlen - skiphost,
128+                    pattern_label_end, patternlen - skiplen);
129+    }
130   }
131-  if(!wildcard_enabled)
132-    return strcasecompare(pattern, hostname) ?
133-      CURL_HOST_MATCH : CURL_HOST_NOMATCH;
134-
135-  hostname_label_end = strchr(hostname, '.');
136-  if(!hostname_label_end ||
137-     !strcasecompare(pattern_label_end, hostname_label_end))
138-    return CURL_HOST_NOMATCH;
139-
140-  /* The wildcard must match at least one character, so the left-most
141-     label of the hostname is at least as large as the left-most label
142-     of the pattern. */
143-  if(hostname_label_end - hostname < pattern_label_end - pattern)
144-    return CURL_HOST_NOMATCH;
145-
146-  prefixlen = pattern_wildcard - pattern;
147-  suffixlen = pattern_label_end - (pattern_wildcard + 1);
148-  return strncasecompare(pattern, hostname, prefixlen) &&
149-    strncasecompare(pattern_wildcard + 1, hostname_label_end - suffixlen,
150-                    suffixlen) ?
151-    CURL_HOST_MATCH : CURL_HOST_NOMATCH;
152+  return FALSE;
153 }
154
155+
156 int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
157 {
158   int res = 0;
159@@ -128,7 +132,9 @@ int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
160     if(matchp) {
161       char *hostp = strdup(hostname);
162       if(hostp) {
163-        if(hostmatch(hostp, matchp) == CURL_HOST_MATCH)
164+        size_t hostlen = strlen(hostp);
165+        size_t matchlen = strlen(matchp);
166+        if(hostmatch(hostp, hostlen, matchp, matchlen) == TRUE)
167           res = 1;
168         free(hostp);
169       }
170--
1712.27.0
172
173