Avoid string_view underflow in ParseCodeMetadataAnnotation#2761
Conversation
| (@custom "x"))) | ||
| (;; STDERR ;;; | ||
| out/test/parse/bad-code-metadata-annotation.txt:6:5: error: unexpected annotation: custom | ||
| (@custom "x"))) |
There was a problem hiding this comment.
Should this be an error, or something we just skip over in ParseCodeMetadataAnnotation?
There was a problem hiding this comment.
Switched it to skip. Peek already discards every annotation it does not recognise; the only reason a non-metadata.code one lands here is the cur.text() == "custom" branch admitting custom for module-scope custom sections. So erroring would single out custom while (@foo ...) and the rest get dropped silently, and the binary reader already skips unknown custom sections too. Skipping keeps it consistent. It now eats the annotation’s balanced parens and carries on, and a real metadata.code annotation in the same body is still emitted. Reworked the test into a dump that shows both.
|
(Nit: Please start the PR titles with a capital letter). |
ParseInstrList hands every (@...) annotation in an instruction list to ParseCodeMetadataAnnotation, which strips the "metadata.code." prefix unconditionally. Peek admits a bare (@Custom ...), only meaningful at module scope, into the stream, so it reaches the strip with 6-byte text; remove_prefix(14) then underflows the string_view length and the stored name is read off the heap when the binary writer hashes it. Every other unrecognised annotation in an instruction list is already discarded by Peek, so skip a non-metadata.code annotation here too instead of misparsing it.
f0137d2 to
61b94ff
Compare
|
Title capitalised, thanks. Also flipped the handling from a parse error to skipping the annotation per the inline note. |
| WABT_TRACE(ParseCodeMetadataAnnotation); | ||
| Token tk = Consume(); | ||
| std::string_view name = tk.text(); | ||
| if (name.find("metadata.code.") != 0) { |
There was a problem hiding this comment.
Do we not require C++20 so don't have str.starts_with
There was a problem hiding this comment.
Right, we're on C++17 here (CMAKE_CXX_STANDARD 17 in CMakeLists), so no starts_with. Went with find(...) != 0 to match the existing prefix check in Peek at wast-parser.cc:598, which tests the same string the same way.
ASAN,
wat2wasm --enable-annotationson a(@custom ...)sat inside a function body:ParseCodeMetadataAnnotationstrips themetadata.code.prefix withremove_prefix(14)and assumes it is always there.ParseInstrListhands it every(@...)annotation in an instruction list, andPeekadmits the bare(@custom ...)token because that spelling is meaningful at module scope. On the 6-bytecustomtextremove_prefix(14)underflows the view length to ~2^64 and walks the data pointer past the token. TheCodeMetadataExprthen keeps a name whose pointer and size are both rubbish. Nothing trips until the binary writer hashes that name as a map key, which is where ASAN fires.The binary reader already guards the matching strip with
find("metadata.code.") == 0in binary-reader.cc; the parser never got it. Reject annotations without the prefix.Repro:
Turned up fuzzing wat2wasm with annotations enabled.