You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Part of #239. sys::server, sys::listener, net::http::server and util::http were written for a loopback harness, and several of them say so.
jhttpd is a decision to face a port anyone can reach, and that is a different
threat model rather than a bigger one.
This is the audit issue. It is deliberately separate from #237
(authentication) and #238 (rate limiting), which are features; this is about
the code that already exists.
Starting from something, not nothing
Worth recording, so an audit does not re-derive it:
Every response field is checked against the grammar on the way out, so a
handler cannot inject a CR or LF and turn one response into two.
basic_tlsbuf::start() refuses to upgrade a stream with buffered
plaintext, which is CVE-2011-0411 and was reachable through Imap4::upgrade.
Three timeouts bound a slow-loris, and max_connections bounds descriptors.
Two things a short look already found
Both are small; they are here because finding them took five minutes, which
suggests what an actual audit would turn up.
The number of header fields is unbounded.max_head caps the head at 8192
octets and nothing caps the field count, so a request can carry several
hundred fields within that budget. fields looks up linearly and the server
does several lookups per request, so cost is quadratic in the field count --
bounded by 8KB, so this is a sharp edge rather than a hole, but it is the shape
of one.
400 bodies reflect client input.decide_framing throws messages built
from the offending value:
throw error("Content-Length is not a number: \"" + v + "\"");
and serve_request_async puts e.what() straight into the response body. It
goes out as text/plain, so this is not XSS as it stands -- but it is
unsanitised client data echoed back, and the reasoning that makes it safe is
the Content-Type, which nothing enforces or documents.
The surface
util/http.cc -- the grammar-driven parsers, chunk decoding, the caps,
and integer handling in Content-Length and range arithmetic.
net/http_server.cc -- routing, the conditional and range logic, error
paths, and what those error paths disclose.
sys/async_*.cc, sys/sslstream.hh -- buffer arithmetic, and the TLS
configuration tls_context actually applies (protocol versions, ciphers,
renegotiation) which has never been reviewed.
sys/reactor.cc -- table growth under many connections.
What "audit level" should mean here
Fuzzing the parsers.util::http's head and body readers, the ABNF
grammar entry points, and the chunk decoder take attacker-controlled bytes
and are the right shape for libFuzzer or afl. This is the highest-value item
on the list and nothing here has ever been fuzzed.
ASan and UBSan across the suite, not only TSan -- which has been run and
found the cancel_token race, so the precedent exists.
A pass for unbounded growth: buffered responses have no cap the way
requests have max_body; jserve's relay queue grows if a client is slow but
not gone.
Integer overflow in range and length arithmetic, which mixes long long, size_t and std::streamoff.
A written threat model, so the next person knows what is defended against
and what is not -- which is what "not hardened for a public port" was doing
informally.
What it should not become
A checklist ticked once. The value is in the fuzzing harness and the sanitiser
runs, because those keep working after the audit is over; a document that was
true in September is not a defence.
Part of #239.
sys::server,sys::listener,net::http::serverandutil::httpwere written for a loopback harness, and several of them say so.jhttpd is a decision to face a port anyone can reach, and that is a different
threat model rather than a bigger one.
This is the audit issue. It is deliberately separate from #237
(authentication) and #238 (rate limiting), which are features; this is about
the code that already exists.
Starting from something, not nothing
Worth recording, so an audit does not re-derive it:
util::http::decide_framingrefuses both smuggling primitives --Content-LengthwithTransfer-Encoding, and twoContent-Lengths thatdisagree -- and any framing error closes the connection rather than looking
for the next request in a stream it has said it cannot parse (net: keep-alive on the async server, and the three latent sys defects only a reused connection could reach #217).
path_ofrefuses%2Fand%5Cbefore routing, and decodespercent-escapes, so a capture can never contain a path separator (net: route patterns with captures and prefixes, and the 405 that only a router can tell from a 404 #223).
files()decides containment withrealpath, not by inspecting thepath -- a string check for
..catches the traversal and serves the symlink,which is demonstrated by a break in
net_http_files_test(net: serve a directory, and refuse everything outside it by resolving the path rather than inspecting it #225).handler cannot inject a CR or LF and turn one response into two.
basic_tlsbuf::start()refuses to upgrade a stream with bufferedplaintext, which is CVE-2011-0411 and was reachable through
Imap4::upgrade.max_connectionsbounds descriptors.Two things a short look already found
Both are small; they are here because finding them took five minutes, which
suggests what an actual audit would turn up.
The number of header fields is unbounded.
max_headcaps the head at 8192octets and nothing caps the field count, so a request can carry several
hundred fields within that budget.
fieldslooks up linearly and the serverdoes several lookups per request, so cost is quadratic in the field count --
bounded by 8KB, so this is a sharp edge rather than a hole, but it is the shape
of one.
400 bodies reflect client input.
decide_framingthrows messages builtfrom the offending value:
and
serve_request_asyncputse.what()straight into the response body. Itgoes out as
text/plain, so this is not XSS as it stands -- but it isunsanitised client data echoed back, and the reasoning that makes it safe is
the
Content-Type, which nothing enforces or documents.The surface
util/http.cc-- the grammar-driven parsers, chunk decoding, the caps,and integer handling in
Content-Lengthand range arithmetic.net/http_server.cc-- routing, the conditional and range logic, errorpaths, and what those error paths disclose.
sys/server.cc,sys/listener.cc-- accept, admission control,descriptor ownership, the teardown paths that net: keep-alive on the async server, and the three latent sys defects only a reused connection could reach #217 already found a data race
in.
sys/async_*.cc,sys/sslstream.hh-- buffer arithmetic, and the TLSconfiguration
tls_contextactually applies (protocol versions, ciphers,renegotiation) which has never been reviewed.
sys/reactor.cc-- table growth under many connections.What "audit level" should mean here
util::http's head and body readers, the ABNFgrammar entry points, and the chunk decoder take attacker-controlled bytes
and are the right shape for libFuzzer or afl. This is the highest-value item
on the list and nothing here has ever been fuzzed.
found the
cancel_tokenrace, so the precedent exists.requests have
max_body; jserve's relay queue grows if a client is slow butnot gone.
long long,size_tandstd::streamoff.and what is not -- which is what "not hardened for a public port" was doing
informally.
What it should not become
A checklist ticked once. The value is in the fuzzing harness and the sanitiser
runs, because those keep working after the audit is over; a document that was
true in September is not a defence.