Skip to content

message_impl: reject SOME/IP messages whose length < 8#1041

Open
SoundMatt wants to merge 1 commit into
COVESA:masterfrom
SoundMatt:fix/message-impl-length-underflow
Open

message_impl: reject SOME/IP messages whose length < 8#1041
SoundMatt wants to merge 1 commit into
COVESA:masterfrom
SoundMatt:fix/message-impl-length-underflow

Conversation

@SoundMatt
Copy link
Copy Markdown

Problem

message_impl::deserialize (implementation/message/src/message_impl.cpp:36-44) computes the payload capacity by subtracting the 8-byte trailer size from the wire-encoded length:

bool message_impl::deserialize(deserializer* _from) {
    payload_ = runtime::get()->create_payload();
    bool is_successful = header_.deserialize(_from);
    if (is_successful) {
        payload_->set_capacity(header_.length_ - VSOMEIP_SOMEIP_HEADER_SIZE);
        is_successful = payload_->deserialize(_from);
    }
    return is_successful;
}

header_.length_ is uint32_t and VSOMEIP_SOMEIP_HEADER_SIZE is 8. A peer encoding length < 8 in the SOME/IP wire header wraps the subtraction to a value near 0xFFFFFFF8, which payload_impl::set_capacity passes to std::vector::reserve. That tries to allocate ~4 GB per malformed message.

The subsequent payload_->deserialize correctly refuses the read (because the (wrapped) capacity exceeds the deserializer's remaining bytes), so this isn't memory corruption — but on a 64-bit Linux host with overcommit the giant reserve still allocates a large virtual region per message, and on a 32-bit host or with overcommit off it throws bad_alloc once per message. Either way it's a memory-pressure / DoS primitive against the routing manager from any peer that can put a SOME/IP frame on the routing socket.

Reachable path: routing_manager_client::on_messageSEND_IDsend_command::deserializedeserializer::deserialize_messagemessage_impl::deserialize.

Fix

One-line guard: if header_.length_ < VSOMEIP_SOMEIP_HEADER_SIZE, return false before the subtraction. The SOME/IP spec requires length to cover at least the 8-byte trailer (request_id + protocol version + interface version + message type + return code), so this is the actual minimum value the protocol allows; nothing legitimate is rejected.

Net diff: +12 / −0 (most of which is the explanatory comment).

Notes

This is the second of a small set of audit-found bugs in vsomeip's protocol layer. The first is in flight as #1040 (routing_info_entry bounds checks). I have a couple more I'd like to bring up in separate PRs (one in service_discovery/configuration_option_impl::deserialize, one in deserializer::look_ahead); happy to file them one at a time as this lands.

I haven't been able to run the full test suite locally on macOS yet (boost+CMake setup pending). Pointers on the canonical way to add a malformed-input regression test for this entry would be appreciated and I'd happily follow up with a test commit on this branch.

header_.length_ is wire-controlled and covers the SOME/IP fields
after the length field (the 8-byte trailer: request_id + protocol
version + interface version + message type + return code) plus the
payload. A valid message therefore has length >= 8.

If a peer encodes length < 8, the unsigned subtraction at line 40

    payload_->set_capacity(header_.length_ - VSOMEIP_SOMEIP_HEADER_SIZE);

wraps to a value near 0xFFFFFFF8 and is passed to
payload_impl::set_capacity, which calls std::vector::reserve.
That asks for a ~4 GB allocation per malformed message — pure
memory-pressure DoS. The subsequent payload_->deserialize correctly
rejects the read because the wrapped capacity exceeds remaining_,
so this isn't memory-corruption, but on a 64-bit Linux host with
overcommit the giant reserve still allocates large amounts of
virtual memory.

Reachable via routing_manager_client::on_message → SEND_ID →
send_command::deserialize → deserializer::deserialize_message →
message_impl::deserialize: any peer that can put a SOME/IP frame
on the routing socket can trigger it once per message.

Fix: reject the message before the subtraction when
header_.length_ < VSOMEIP_SOMEIP_HEADER_SIZE.

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
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