~bigbes/tarantool

tarantool-protobuf

1712192b2ee7256d0e4ddd85052a16373280a163 — Eugene Blikh 3 months ago 50ed9b6
wire: bounds-check skip_field for I32/I64/LEN truncation

skip_field advanced pos by a fixed or length-prefixed amount with no
check against #buf, so a truncated unknown field was silently consumed:
the outer decode loop's `while pos <= len` exited without raising,
making the parser accept payloads it should have rejected.

Validates that the new position never exceeds #buf+1 for WIRE_I64,
WIRE_I32, and both WIRE_LEN fast and slow paths. WIRE_VARINT already
errored correctly via decode_varint's per-byte check.

Drops 15 entries from test/conformance/known_failures.txt
(PrematureEofBeforeUnknownValue.*, PrematureEofInsideUnknownValue.*,
PrematureEofInDelimitedDataForUnknownValue.*).
2 files changed, 14 insertions(+), 19 deletions(-)

M runtime/pb/wire.lua
M test/conformance/known_failures.txt
M runtime/pb/wire.lua => runtime/pb/wire.lua +14 -4
@@ 446,15 446,25 @@ local function skip_field(buf, pos, wire_type)
        local _, npos = decode_varint(buf, pos)
        return npos
    elseif wire_type == M.WIRE_I64 then
        return pos + 8
        local np = pos + 8
        if np > #buf + 1 then error("truncated I64 at offset " .. pos, 0) end
        return np
    elseif wire_type == M.WIRE_LEN then
        local b = buf:byte(pos)
        if b == nil then error("truncated varint at offset " .. pos, 0) end
        if b < 0x80 then return pos + 1 + b end
        if b < 0x80 then
            local np = pos + 1 + b
            if np > #buf + 1 then error("truncated LEN at offset " .. pos, 0) end
            return np
        end
        local len, npos = decode_varint(buf, pos)
        return npos + tonumber(len)
        local np = npos + tonumber(len)
        if np > #buf + 1 then error("truncated LEN at offset " .. pos, 0) end
        return np
    elseif wire_type == M.WIRE_I32 then
        return pos + 4
        local np = pos + 4
        if np > #buf + 1 then error("truncated I32 at offset " .. pos, 0) end
        return np
    end
    error("unknown wire type " .. tostring(wire_type), 0)
end

M test/conformance/known_failures.txt => test/conformance/known_failures.txt +0 -15
@@ 54,21 54,6 @@ Required.Proto3.ProtobufInput.BadTag_OverlongVarint
Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_0
Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_1
Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_3
Required.Proto3.ProtobufInput.PrematureEofBeforeUnknownValue.DOUBLE
Required.Proto3.ProtobufInput.PrematureEofBeforeUnknownValue.FIXED32
Required.Proto3.ProtobufInput.PrematureEofBeforeUnknownValue.FIXED64
Required.Proto3.ProtobufInput.PrematureEofBeforeUnknownValue.FLOAT
Required.Proto3.ProtobufInput.PrematureEofBeforeUnknownValue.SFIXED32
Required.Proto3.ProtobufInput.PrematureEofBeforeUnknownValue.SFIXED64
Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForUnknownValue.BYTES
Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForUnknownValue.MESSAGE
Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForUnknownValue.STRING
Required.Proto3.ProtobufInput.PrematureEofInsideUnknownValue.DOUBLE
Required.Proto3.ProtobufInput.PrematureEofInsideUnknownValue.FIXED32
Required.Proto3.ProtobufInput.PrematureEofInsideUnknownValue.FIXED64
Required.Proto3.ProtobufInput.PrematureEofInsideUnknownValue.FLOAT
Required.Proto3.ProtobufInput.PrematureEofInsideUnknownValue.SFIXED32
Required.Proto3.ProtobufInput.PrematureEofInsideUnknownValue.SFIXED64
Required.Proto3.ProtobufInput.RepeatedScalarMessageMerge.ProtobufOutput
Required.Proto3.ProtobufInput.ValidDataOneof.MESSAGE.Merge.ProtobufOutput
Required.Proto3.TimestampProtoNegativeNanos.JsonOutput