summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHauke Mehrtens2026-05-03 21:56:57 +0000
committerHauke Mehrtens2026-05-15 00:13:28 +0000
commit1781b6dec414a4e284aacf09a544d58fac374289 (patch)
tree1f5f5469e9609fd35a6dd5a9bdc013733c5e5655
parent05317bf30a9432aaeac1a20300f605d9cf43c64f (diff)
downloaduhttpd-1781b6dec414a4e284aacf09a544d58fac374289.tar.gz
utils, client: cast char to unsigned before passing to ctype functions
The is*() and tolower()/toupper() functions accept an int argument that must be either EOF or representable as unsigned char. Passing a plain char with the high bit set produces a sign-extended negative int on platforms where char is signed (the default on x86), which is undefined behavior per C99 / POSIX. Real-world libc implementations typically resolve the negative index against an internal lookup table and may return surprising results or read out of bounds. Inputs reach these functions from URL bytes, header values, and the gap between a header name and its value, all of which can legitimately contain bytes >= 0x80 (UTF-8 paths, latin-1 percent-decoded values, etc.). Cast through unsigned char at every call site so the value is in the range [0, UCHAR_MAX] regardless of the platform's char signedness. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
-rw-r--r--client.c4
-rw-r--r--utils.c8
2 files changed, 7 insertions, 5 deletions
diff --git a/client.c b/client.c
index 2926965..69bb7e1 100644
--- a/client.c
+++ b/client.c
@@ -380,8 +380,8 @@ static void client_parse_header(struct client *cl, char *data)
}
for (name = data; *name; name++)
- if (isupper(*name))
- *name = tolower(*name);
+ if (isupper((unsigned char)*name))
+ *name = tolower((unsigned char)*name);
if (!strcmp(data, "expect")) {
if (!strcasecmp(val, "100-continue"))
diff --git a/utils.c b/utils.c
index e10d1dc..28af993 100644
--- a/utils.c
+++ b/utils.c
@@ -119,7 +119,9 @@ int uh_urldecode(char *buf, int blen, const char *src, int slen)
continue;
}
- if (i + 2 >= slen || !isxdigit(src[i + 1]) || !isxdigit(src[i + 2]))
+ if (i + 2 >= slen ||
+ !isxdigit((unsigned char)src[i + 1]) ||
+ !isxdigit((unsigned char)src[i + 2]))
return -2;
buf[len++] = (char)(16 * hex(src[i+1]) + hex(src[i+2]));
@@ -141,7 +143,7 @@ int uh_urlencode(char *buf, int blen, const char *src, int slen)
for (i = 0; (i < slen) && (len < blen); i++)
{
- if( isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') ||
+ if( isalnum((unsigned char)src[i]) || (src[i] == '-') || (src[i] == '_') ||
(src[i] == '.') || (src[i] == '~') )
{
buf[len++] = src[i];
@@ -231,7 +233,7 @@ char *uh_split_header(char *str)
*val = 0;
val++;
- while (isspace(*val))
+ while (isspace((unsigned char)*val))
val++;
return val;