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