Skip to content

[MEDIUM] Prevent infinite loops when skipping indefinite containers - #40

Open
OskarEichler wants to merge 1 commit into
cabo:masterfrom
OskarEichler:codex/skip-indefinite-containers
Open

[MEDIUM] Prevent infinite loops when skipping indefinite containers#40
OskarEichler wants to merge 1 commit into
cabo:masterfrom
OskarEichler:codex/skip-indefinite-containers

Conversation

@OskarEichler

Copy link
Copy Markdown

Summary

CBOR::Unpacker#skip can enter an uninterruptible native loop when the next object is an indefinite-length array, map, or byte string. A four-byte input is enough to hold the Ruby GVL and consume a core until the process is killed.

This change teaches the skip state machine to handle indefinite containers, propagate their completion to enclosing containers, and reject a break marker where a value is still required.

Reproduction

Against 0.5.10.3:

require "cbor"

unpacker = CBOR::Unpacker.new
unpacker.feed("\x9f\x01\xff\x02".b)
unpacker.skip # does not return

The same behavior occurs for an indefinite map (bf 01 02 ff) and indefinite byte string (5f 41 61 ff). Because the loop is inside the native extension while holding the GVL, Timeout.timeout and other Ruby threads cannot recover the process.

The cached break byte was never consumed or reset by the previous skip implementation. It repeatedly decremented a zero indefinite-container count and reread the same marker.

Verification

  • Exact 0.5.10.3 release model: indefinite array, map, byte string, nested containers, and dangling map key all timed out after one second in isolated child processes.
  • Patched model: valid cases advance to the following object; a dangling map key raises CBOR::MalformedFormatError.
  • Focused checks cover definite arrays/maps, tags, bare breaks, wrong indefinite string chunk types, and dangling map keys.
  • Existing suite: 170 examples, 0 failures on Ruby 4.0.6.
  • rake compile, gem build cbor.gemspec, and git diff --check pass.

No tests were changed because this repository asks contributors not to add or modify tests.

Scope and limitations

The vulnerable entry point is the low-level streaming Unpacker#skip API. Normal CBOR.decode does not call it. Impact therefore depends on an application using skip with untrusted CBOR input.

This patch does not change allocation limits or recursion limits elsewhere in the decoder.

Breaking changes

Valid CBOR behavior is unchanged. Malformed bare break markers, wrong indefinite-string chunk types, and indefinite maps ending after a key now raise CBOR::MalformedFormatError instead of hanging or being accepted.

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.

1 participant