client: perform strict chunk size parsing#4
Conversation
cf071f4 to
3b723c4
Compare
|
Consider the case in which the chunk size is just |
|
Also, chunk-extensions do have a grammar that it may be worth considering enforcing. |
Since we're not consuming any body data when serving file requests, forcibly shut down keep-alive connections after requests indicating either a content-length or a chunked transfer encoding in order to avoid interpreting request body data as subsequent HTTP request. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Commit 15346de ("client: Always close connection with request body in case of error") added logic to close keep alive connections on HTTP errors due to unconsumed request body data. However, since the check happens after emitting the standard HTTP headers, uhttpd might incorrectly reply with a `Connection: keep-alive` even if it is going to close the connection. Move the check before the emitting of the response headers in order to ensure that we're sending the correct `Connection: close` line. Fixes: 15346de ("client: Always close connection with request body in case of error") Signed-off-by: Jo-Philipp Wich <jo@mein.io>
The function `uh_header_error()` will tear down the connection after sending the HTTP reply message, so update the `connection_close` flag accordingly to avoid incorrectly emitting a `Connection: keep-alive` header. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
3b723c4 to
3c0fcf1
Compare
Introduce infrastructure and logic to perform less lenient parsing of HTTP request headers, chunk size headers and content-length values. We can not rely on `strtoul()` to parse hexadecimal chunk sizes or content length values as it accepts a wider range of inputs than what is allowed by the HTTP spec. Decode the chunk sizes and length values manually and fix skipping chunk extension headers while we're at it. Also ensure that there's no trailing garbage after the size and that we bail out on overflows. Also rework the parsing of request header lines, to reject malformed header lines or illegal header names. Fixes: openwrt#3 Fixes: openwrt#5 Signed-off-by: Jo-Philipp Wich <jo@mein.io>
3c0fcf1 to
3c8b991
Compare
|
This line in This can also be problematic if the proxy allows trailing data after the chunk contents (for example, see this bug in pound). Might be worth incorporating into this change. |
|
According to this research published here by @JeppW, this fixes a legitimate security vulnerability in this library: Would the openwrt team be willing to assist with CVE vulnerability assignment? That can be done by opening a GitHub security advisory here and inviting the relevant parties: https://github.com/openwrt/uhttpd/security |
Addresses the eight issues raised in the PR review of 2f53907. - Route every ".gz" candidate through canonpath() plus the docroot containment check, so with -S (no_symlinks) a symlinked .gz can no longer escape the docroot (#1), and a gz-only layout still resolves when realpath() of the absent plain file fails (openwrt#4). uh_stat_gzip now canonicalizes the candidate itself and hands back the .gz-stripped logical path, replacing the hand-rolled snprintf+stat at serve time and taking a const char * (openwrt#8). - Never let a .gz fallback reach CGI/interpreter dispatch: a matched script handler on a gzip result returns a clean 404 instead of exec'ing a nonexistent plain file (openwrt#3). - Accumulate Accept-Encoding across repeated header lines with |= (openwrt#5) and treat "*" as accepting gzip, with an explicit gzip token (incl. gzip;q=0) taking precedence over "*" (openwrt#6). - Emit Vary: Accept-Encoding on the plain 200 response whenever a .gz sibling exists, so shared caches keep the variants apart (openwrt#7). Fix the test harness: status()/bodylen() were missing the shift that hdr() has, so curl received two URLs and every assertion silently failed; the suite never actually passed. Add coverage for -S symlink rejection, gz-only under -S, script-path fallout, multi-header and wildcard Accept-Encoding, and Vary on plain responses (21 -> 34 cases). Refs: openwrt#28 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Introduce infrastructure and logic to perform less lenient parsing of HTTP request headers, chunk size headers and content-length values.
We can not rely on
strtoul()to parse hexadecimal chunk sizes or content length values as it accepts a wider range of inputs than what is allowed by the HTTP spec.Decode the chunk sizes and length values manually and fix skipping chunk extension headers while we're at it. Also ensure that there's no trailing garbage after the size and that we bail out on overflows.
Also rework the parsing of request header lines, to reject malformed header lines or illegal header names.
Fixes: #3
Fixes: #5
The function
uh_header_error()will tear down the connection after sending the HTTP reply message, so update theconnection_closeflag accordingly to avoid incorrectly emitting aConnection: keep-aliveheader.Commit 15346de ("client: Always close connection with request body in case of error") added logic to close keep alive connections on HTTP errors due to unconsumed request body data.
However, since the check happens after emitting the standard HTTP headers, uhttpd might incorrectly reply with a
Connection: keep-aliveeven if it is going to close the connection.Move the check before the emitting of the response headers in order to ensure that we're sending the correct
Connection: closeline.Fixes: 15346de ("client: Always close connection with request body in case of error")
Since we're not consuming any body data when serving file requests, forcibly shut down keep-alive connections after requests indicating either a content-length or a chunked transfer encoding in order to avoid interpreting request body data as subsequent HTTP request.