← Commit list

717ebe4d0a

David Benjamin
David Benjamin
2026-09-02
SUCCESS Duration: 413s

Subject

vtls: fix Curl_cert_hostcheck when the pattern is not a C string

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/vtls/hostcheck.c+7 -5
@@ -66,6 +66,8 @@ static bool pmatch(const char *hostname, size_t hostlen,
* Only match on "*" being used for the leftmost label, not "a*", "a*b" nor
* "*b".
*
+ * The pattern string does not necessarily need to be NUL-terminated.
+ *
* Return TRUE on a match. FALSE if not.
*
* @unittest: 1397
@@ -84,16 +86,16 @@ static bool hostmatch(const char *hostname,
DEBUGASSERT(hostlen);
/* normalize pattern and hostname by stripping off trailing dots */
- if(hostname[hostlen - 1] == '.')
+ if(hostlen > 0 && hostname[hostlen - 1] == '.')
hostlen--;
- if(pattern[patternlen - 1] == '.')
+ if(patternlen > 0 && pattern[patternlen - 1] == '.')
patternlen--;
- if(strncmp(pattern, "*.", 2))
+ if(patternlen > 2 && strncmp(pattern, "*.", 2))
return pmatch(hostname, hostlen, pattern, patternlen);
/* detect host as IP address or starting with a dot and fail if so */
- else if(Curl_host_is_ipnum(hostname) || (hostname[0] == '.'))
+ else if(Curl_host_is_ipnum(hostname) || (hostlen > 0 && hostname[0] == '.'))
return FALSE;
/* We require at least 2 dots in the pattern to avoid too wide wildcard
@@ -120,7 +122,7 @@ static bool hostmatch(const char *hostname,
bool Curl_cert_hostcheck(const char *match, size_t matchlen,
const char *hostname, size_t hostlen)
{
- if(match && *match && hostname && *hostname)
+ if(matchlen > 0 && hostlen > 0)
return hostmatch(hostname, hostlen, match, matchlen);
return FALSE;
}
tests/unit/unit1397.c+36 -0
@@ -22,6 +22,7 @@
*
***************************************************************************/
#include "unitcheck.h"
+#include "curlx/strdup.h"
#include "vtls/hostcheck.h"
static CURLcode test_unit1397(const char *arg)
@@ -45,6 +46,7 @@ static CURLcode test_unit1397(const char *arg)
{ "", "b", FALSE },
{ "a", "b", FALSE },
{ "aa", "bb", FALSE },
+ { "a", "*", FALSE },
{ "\xff", "\xff", TRUE },
{ "aa.aa.aa", "aa.aa.bb", FALSE },
{ "aa.aa.aa", "aa.aa.aa", TRUE },
@@ -94,6 +96,8 @@ static CURLcode test_unit1397(const char *arg)
int i;
for(i = 0; tests[i].host; i++) {
+ size_t pattern_len;
+ char *pattern;
if(tests[i].match != Curl_cert_hostcheck(tests[i].pattern,
strlen(tests[i].pattern),
tests[i].host,
@@ -107,6 +111,38 @@ static CURLcode test_unit1397(const char *arg)
tests[i].match ? "NOT " : "");
unitfail++;
}
+
+ /* Curl_cert_hostcheck() should not rely on trailing NULs in the pattern.
+ * The underlying TLS library might not make a NUL-terminated copy of the
+ * pattern. Copy it to a new buffer so ASan and valgrind can flag invalid
+ * accesses. */
+ pattern_len = strlen(tests[i].pattern);
+ pattern = pattern_len ? curlx_memdup(tests[i].pattern, pattern_len) : NULL;
+ abort_unless(pattern_len == 0 || pattern, "Out of memory");
+ if(tests[i].match != Curl_cert_hostcheck(pattern,
+ pattern_len,
+ tests[i].host,
+ strlen(tests[i].host))) {
+ curl_mfprintf(stderr,
+ "HOST: %s\n"
+ "PTRN: %s\n"
+ "did %sMATCH\n",
+ tests[i].host,
+ tests[i].pattern,
+ tests[i].match ? "NOT " : "");
+ unitfail++;
+ }
+ curlx_free(pattern);
+ }
+
+ /* Embedded NULs in the pattern should not be misinterpreted. */
+ if(Curl_cert_hostcheck("foo\0bar", 7, "foo", 3)) {
+ curl_mfprintf(stderr, "foo\\0bar incorrectly matched foo\n");
+ unitfail++;
+ }
+ if(Curl_cert_hostcheck("foo\0bar", 7, "foo.bar", 7)) {
+ curl_mfprintf(stderr, "foo\\0bar incorrectly matched foo.bar\n");
+ unitfail++;
}
#endif