diff --git a/lib/bson/binary.rb b/lib/bson/binary.rb index e3fc78c27..74d84ffc8 100644 --- a/lib/bson/binary.rb +++ b/lib/bson/binary.rb @@ -306,7 +306,20 @@ def self.from_bson(buffer, **_options) type = type_byte end - length = buffer.get_int32 if type == :old + if type == :old + inner_length = buffer.get_int32 + unless inner_length == length - 4 + raise Error::BSONDecodeError, + "BSON binary subtype 0x02 length mismatch: outer=#{length}, inner=#{inner_length}" + end + length = inner_length + end + + if length.negative? + raise Error::BSONDecodeError, + "BSON binary length is negative: #{length}" + end + data = buffer.get_bytes(length) new(data, type) end diff --git a/spec/bson/binary_spec.rb b/spec/bson/binary_spec.rb index ded26f87d..15d5da05a 100644 --- a/spec/bson/binary_spec.rb +++ b/spec/bson/binary_spec.rb @@ -204,6 +204,58 @@ /BSON data contains unsupported binary subtype 0x10/) end end + + context 'when subtype 0x02 inner length is too long' do + let(:bson) do + ([6].pack('l<') + 2.chr + [3].pack('l<') + 'xxx').force_encoding('BINARY') + end + + it 'raises BSONDecodeError' do + expect { obj }.to raise_error( + BSON::Error::BSONDecodeError, + /length mismatch.*outer=6.*inner=3/ + ) + end + end + + context 'when subtype 0x02 inner length is too short' do + let(:bson) do + ([6].pack('l<') + 2.chr + [1].pack('l<') + 'xxx').force_encoding('BINARY') + end + + it 'raises BSONDecodeError' do + expect { obj }.to raise_error( + BSON::Error::BSONDecodeError, + /length mismatch.*outer=6.*inner=1/ + ) + end + end + + context 'when subtype 0x02 inner length is negative' do + let(:bson) do + ([6].pack('l<') + 2.chr + [-1].pack('l<') + 'xx').force_encoding('BINARY') + end + + it 'raises BSONDecodeError' do + expect { obj }.to raise_error( + BSON::Error::BSONDecodeError, + /length mismatch.*outer=6.*inner=-1/ + ) + end + end + + context 'when non-old subtype outer length is negative' do + let(:bson) do + ([-1].pack('l<') + 0.chr).force_encoding('BINARY') + end + + it 'raises BSONDecodeError' do + expect { obj }.to raise_error( + BSON::Error::BSONDecodeError, + /length is negative.*-1/ + ) + end + end end describe "#to_bson/#from_bson" do