Skip to content

reject stray AMF0 object-end marker in amf value readers - #3597

Merged
wasphin merged 1 commit into
apache:masterfrom
sahvx655-wq:amf-object-end-marker
Oct 12, 2026
Merged

wasphin merged 1 commit into
apache:masterfrom
sahvx655-wq:amf-object-end-marker

Conversation

@sahvx655-wq

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: N/A

Problem Summary:

While going through the AMF0 readers in amf.cpp after the recent parser hardening there, I noticed the three value readers still handle an object-end marker (0x09) in a value position with CHECK(false): ReadAMFObjectField for protobuf messages, its AMFObject overload, and ReadAMFArrayItem. The marker byte is cut straight off the wire, so any RTMP peer reaches these switches: the message variant through the connect/play/publish command objects (RtmpChunkStream::OnConnect reads the command object via ReadAMFObject at rtmp_protocol.cpp:2385), and the AMFObject/AMFArray variants through onMetaData/onCuePoint data messages and client-side onStatus/_result processing. The root cause is that a stray 0x09 is treated as a programming invariant when it is really just malformed input; AMF0 only defines the marker after an empty field name.

A field name followed by 0x09 logs at FATAL level with a stack trace on every such message, and aborts the process outright when -crash_on_fatal_log is on (CWE-617), dropping every in-flight RPC on the server. Worse, the AMFObject and AMFArray variants then break out of the switch and return true, so with the flag off the malformed document is accepted as if it were valid and the reader carries on misaligned against the field stream.

What is changed and the side effects?

Changed:

The three wire-controlled CHECK(false) sites become LOG(ERROR) plus return false, the same handling as the adjacent unsupported-marker cases in the same switches, so the parse fails and every caller already surfaces that as a protocol error. The fourth occurrence, in the WriteAMFField serialiser, is not driven by network input and is left alone. Same reasoning as the mcpack2pb hardening in #3576.

RtmpTest.amf_rejects_stray_object_end_marker covers all three readers. On master the object and array cases fail (the readers return true) and the FATAL trace fires; with the fix all three inputs are rejected. The full brpc_rtmp_unittest passes.

Side effects:

  • Performance effects: none

  • Breaking backward compatibility: no

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The parser hardening is correct, consistently applied, and covered by focused regression tests.

0 open findings

What changed in this PR

Hardens AMF0 parsing by rejecting stray object-end markers instead of triggering fatal checks or accepting malformed input.

Changes:

  • Return parse failures for object-end markers in value positions.
  • Add regression coverage for protobuf objects, generic objects, and strict arrays.
File Description
src/​brpc/​amf.cpp Replaces three wire-reachable fatal checks with parse errors.
test/​brpc_rtmp_unittest.cpp Tests all three affected reader paths.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@wasphin wasphin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@wasphin
wasphin merged commit f5307aa into apache:master Oct 12, 2026
25 checks passed
wasphin pushed a commit that referenced this pull request Oct 27, 2026
AMF0 defines the type markers 0x00 to 0x11. A larger marker falls out
of the switches in ReadAMFObjectField and ReadAMFArrayItem, and the
readers return true without reading a value. The bytes after the
marker are parsed next, and the document is accepted if they happen
to parse. #3597 fixed the same problem for a stray object-end marker.
Reject the marker, as the unsupported-marker cases in the same
switches do. Switch on the raw byte, so that the new default case
does not depend on converting an undefined marker to AMFMarker. The
"marker=" logs in the object readers now print the byte as a number,
not as a character.

Two more cases in these switches leave bytes unread. The class name of a
typed object can be unreadable, for example when it is longer than a
lowered amf_max_string_size. The readers then only log, and the class
name is parsed as the object's fields. Return false, as the string cases
do. In the protobuf reader, an object value for a field that is not a
message is not read. Its fields are parsed as fields of the outer
object, and its end marker ends the outer object. Skip it, as the reader
does for an unknown field.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants