Dmytro Shteflyuk created THRIFT-6139:
----------------------------------------
Summary: Ruby CompactProtocol writers should reject out-of-range
integers
Key: THRIFT-6139
URL: https://issues.apache.org/jira/browse/THRIFT-6139
Project: Thrift
Issue Type: Bug
Components: Ruby - Library
Reporter: Dmytro Shteflyuk
Assignee: Dmytro Shteflyuk
h3. Problem
Ruby's CompactProtocol writers do not consistently enforce the widths declared
by the Thrift type system. The pure-Ruby implementation can encode integers
outside the signed i8, i16, i32, and i64 ranges, while the native extension may
narrow the same values during decoding. Related protocol values such as field
identifiers, message sequence identifiers, and collection sizes also reach the
wire without consistent bounds checking.
This means the same encoded bytes can produce different values depending on
whether {{thrift_native}} is loaded.
h3. Client impact
A client can supply a value that does not fit its declared Thrift type and
receive no error while serializing it. The value may then change when decoded,
and native and pure-Ruby clients can disagree about the result. Applications
therefore receive delayed and environment-dependent behavior instead of an
immediate error at the invalid write.
h3. Reproduction
Run the following as {{repro.rb}} from {{lib/rb}}:
{code:ruby}
require "thrift"
transport = Thrift::MemoryBufferTransport.new
protocol = Thrift::CompactProtocol.new(transport)
protocol.write_i16(32_768)
wire = transport.read(transport.available)
transport.reset_buffer(wire)
decoded = Thrift::CompactProtocol.new(transport).read_i16
puts "native=#{protocol.native?}"
puts "wire=#{wire.bytes.inspect}"
puts "decoded=#{decoded}"
{code}
Build the native extension, then run both implementations:
{code:bash}
bundle exec rake build_ext
ruby -Ilib -Iext repro.rb
ruby -Ilib repro.rb
{code}
Testing on master commit {{a9663bc6661a5dd1d99d629e1f269c1907592a1a}} produces:
{code}
native=true
wire=[128, 128, 4]
decoded=-32768
native=false
wire=[128, 128, 4]
decoded=32768
{code}
Both implementations accept {{32768}} even though it is outside the signed i16
range, and they disagree when decoding the resulting bytes.
h3. Expected behavior
CompactProtocol should reject integers outside their declared signed widths
before writing any bytes or changing protocol state. Field identifiers should
be limited to signed i16, message sequence identifiers to signed i32, and
collection or binary sizes to the non-negative signed i32 range. Native and
pure-Ruby implementations should behave consistently, while valid values should
retain their existing wire encoding.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)