Skip to content

Reject negative data length in ExchangeCodec decode - #16448

Open
L1nq0 wants to merge 1 commit into
apache:3.3from
L1nq0:16447-negative-frame-length
Open

Reject negative data length in ExchangeCodec decode#16448
L1nq0 wants to merge 1 commit into
apache:3.3from
L1nq0:16447-negative-frame-length

Conversation

@L1nq0

@L1nq0 L1nq0 commented Sep 5, 2026

Copy link
Copy Markdown

What is the purpose of the change?

Closes #16447

A frame header that declares a negative data length is not a valid frame, and no additional input can make it one. On the 3.3 branch such a header passes every check in ExchangeCodec.decode: finishRespWhenOverPayload only compares against the payload upper bound, and the completeness check readable < len + 16 holds for every negative len. The negative value then reaches the ChannelBufferInputStream constructor, which rejects it with an IllegalArgumentException that escapes decode.

Stack trace from a 16-byte frame with data length ffffffff:

java.lang.IllegalArgumentException: length: -1
    at org.apache.dubbo.remoting.buffer.ChannelBufferInputStream.<init>(ChannelBufferInputStream.java:37)
    at org.apache.dubbo.remoting.exchange.codec.ExchangeCodec.decode(ExchangeCodec.java:134)
    at org.apache.dubbo.remoting.exchange.codec.ExchangeCodec.decode(ExchangeCodec.java:92)

What this PR does

decode now checks the sign of len right after Bytes.bytes2int(header, 12) and rejects a negative value with an IOException, so an invalid header is handled as a decode-level protocol error at the point the length is read instead of surfacing as an unexpected exception from a stream constructor. On the netty4 transport the connection-level behavior is unchanged: the exception is caught by InternalDecoder, logged, and the connection is closed.

NEED_MORE_INPUT is deliberately not used here. It is only correct when more input can complete the frame, and a negative length can never be completed.

The same guard is added to DeprecatedExchangeCodec in test sources: CodecAdapterTest re-runs the ExchangeCodecTest suite through the old Codec interface, so the copy needs the same behavior to keep the two paths aligned.

Testing

A new test, test_Decode_Negative_Data_Length, feeds the exact 16-byte reproducer from the issue (magic dabb, flag c2, requestId all ff, data length ffffffff) and asserts that decode rejects it with an IOException. Without the fix this test fails with the stack above.

The full dubbo-remoting-api module suite (385 tests) and the dubbo-remoting-netty4 module pass locally.

Checklist

  • Make sure there is a GitHub_issue field for the change.
  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  • Write necessary unit-test to verify your logic correction. If the new feature or significant change is committed, please remember to add sample in dubbo samples project.
  • Make sure gitHub actions can pass. Why the workflow is failing and how to fix it?

A negative data length can never become a valid frame, so returning
NEED_MORE_INPUT would leave the channel waiting forever. Throw an
IOException where the length is read instead.

Same change in the deprecated Codec-path copy, which CodecAdapterTest
runs through the old interface.
@codecov-commenter

codecov-commenter commented Sep 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 60.93%. Comparing base (dab47b7) to head (cde9f6c).

Additional details and impacted files
@@             Coverage Diff              @@
##                3.3   #16448      +/-   ##
============================================
+ Coverage     60.91%   60.93%   +0.01%     
- Complexity       15    11767   +11752     
============================================
  Files          1953     1953              
  Lines         89271    89273       +2     
  Branches      13473    13474       +1     
============================================
+ Hits          54383    54402      +19     
+ Misses        29309    29290      -19     
- Partials       5579     5581       +2     
Flag Coverage Δ
integration-tests-java21 32.08% <0.00%> (-0.06%) ⬇️
integration-tests-java8 32.21% <0.00%> (+<0.01%) ⬆️
samples-tests-java21 32.16% <0.00%> (+<0.01%) ⬆️
samples-tests-java8 29.75% <0.00%> (-0.09%) ⬇️
unit-tests-java11 59.15% <100.00%> (-0.01%) ⬇️
unit-tests-java17 58.64% <100.00%> (-0.02%) ⬇️
unit-tests-java21 58.67% <100.00%> (+0.02%) ⬆️
unit-tests-java25 58.61% <100.00%> (+<0.01%) ⬆️
unit-tests-java8 59.19% <100.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

[Bug] Negative frame data length causes IllegalArgumentException in ExchangeCodec

2 participants