Web: restricted HTTP header lookup to the header section, and fixed an out-of-bounds read - #398
Web: restricted HTTP header lookup to the header section, and fixed an out-of-bounds read#398COOOkies4U wants to merge 2 commits into
Conversation
|
Hi @COOOkies4U. Thank you for this contribution! Before we can accept it, you need to sign the Eclipse Contributor Agreement (ECA). The purpose of the ECA is to provide a written record that you have agreed to provide your code and documentation contributions under the licenses used by the Eclipse ThreadX project. It also makes it clear that you are promising that what you are contributing to Eclipse is code you wrote, and you have the necessary rights to contribute it to our projects. And finally, it documents a commitment from you that your open source contributions will be permanently on the public record. Signing the ECA requires an Eclipse Foundation account if you do not already have one. You can create one for free at https://accounts.eclipse.org. Be sure to use the same email address when you register for the account that you intend to use on Git commit records. Also, please add your GitHub ID to your Eclipse account. This enables synchronisation between Eclipse-owned infrastructure and GitHub. Here is the link to sign the ECA: |
c70289e to
99fb969
Compare
_nx_web_http_server_field_value_get() searched the whole request packet for header fields. Per RFC 7230 header parsing must stop at the first CRLFCRLF: the message body is opaque and must never be interpreted as header fields. Because the scan ran past that terminator, a field name appearing in the body was reported as a header field, so a request declaring Content-Length whose body contained "Transfer-Encoding: chunked" made _nx_web_http_server_chunked_check() see chunked encoding. Bound the scan to the header section and track whether the field was found in an explicit flag. The flag matters: the absent-field outcome used to be inferred from the scan pointer having run past the end of the packet, so bounding the scan without it left that outcome undetectable and the value was copied from a fixed offset inside the body instead. The whole field name must lie inside the header, so a name is not matched across the boundary. A packet with no header terminator carries no body, so all of it is scanned. Reported and first patched by Jannes Wegner in issue eclipse-threadx#397; the implementation was reworked during review, and a regression test was added covering the reported request, a body beginning with the field name, an absent field whose body holds a CRLF, a packet with no terminator, and a header field competing with a body decoy. Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
The whitespace skip in _nx_web_http_server_field_value_get() read the character before testing the bound, so a header value made up entirely of spaces running to the last byte of the packet data caused one read at nx_packet_append_ptr. The check inside the loop body then returned NX_WEB_HTTP_NOT_FOUND, so the outcome was correct but the read had already happened. Test the bound in the loop condition instead. Running off the end is still caught immediately afterwards by the CRLF bound check, so the returned status is unchanged; only the read is removed. Confirmed with AddressSanitizer against an exact-size buffer: heap-buffer-overflow READ of size 1 before, clean after, NX_WEB_HTTP_NOT_FOUND in both cases. This defect predates the header boundary fix in the preceding commit and is independent of it, so it is kept separate to remain cherry-pickable on its own. Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Thanks @COOOkies4U — the report in #397 is correct and was the hard part of this. Header parsing must stop at the first CRLFCRLF, I have reworked the implementation and pushed it to this branch, and I want to explain why rather than just replace your diff — the reason the first version did not hold is genuinely non-obvious, and it is worth having on the record. Why the first patch did not take effectThis function has no "field not found" flag. It infers absence from the scan pointer having run off the end of the packet: the loop exits on A I built a harness from the real code — the parser, Case 1 is the request from your issue, and it still returned SUCCESS. Because the read offset is fixed, the string Three further consequences came from the same root cause:
None of this is obvious from reading the function, which is why I would rather write it down than leave you to infer it from a rewritten diff. What is on the branch nowTwo commits, and the PR title has been widened to match.
The fix tracks the outcome in an explicit It also carries a regression test, I checked that the test actually discriminates rather than assuming it does: two cases fail on unpatched
Built and run across all three web configurations — One practical noteThe branch history was rewritten, so if you have it checked out locally a plain Thanks again for the report. The diagnosis was accurate and clearly written, and it found something that had been in the Web add-on since its first public commit. If you spot the same pattern elsewhere in the add-ons, please do open issues the same way. |
|
If you are fine with the current state of the PR, I will merge it into dev. This would ship in our Q3 2026 release in September. |
|
Thanks, @fdesbiens, for the detailed review of my pull request. I agree with your changes and the current state of the PR. |
Bugfix for Issue #397