diff options
| author | Hauke Mehrtens | 2026-05-03 21:56:57 +0000 |
|---|---|---|
| committer | Hauke Mehrtens | 2026-05-15 00:13:28 +0000 |
| commit | 1781b6dec414a4e284aacf09a544d58fac374289 (patch) | |
| tree | 1f5f5469e9609fd35a6dd5a9bdc013733c5e5655 | |
| parent | 05317bf30a9432aaeac1a20300f605d9cf43c64f (diff) | |
| download | uhttpd-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.c | 4 | ||||
| -rw-r--r-- | utils.c | 8 |
2 files changed, 7 insertions, 5 deletions
@@ -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")) @@ -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; |