[BUG]: Heap Out-of-Bounds Read in SOME/IP E2E Profile 07 (P07) Checker
- Dominant language
- C++
- Stars
- 1.4k
- Forks
- 826
- PR merge metrics
- No merged PRs in 30d
Description
### vSomeip Version
7bcc1e06f16a774e70931ed641f475fbba9c8c64
### Boost Version
1.9.0
### Environment
Ubuntu 24.04
### Describe the bug
## Summary
`vsomeip_v3::e2e::profile07::profile_07_checker` validates only the message's **total** length (`min_data_length_`/`max_data_length_`) and never checks that `offset_ + bytes_read <= buffer.size()`. As a result, a short SOME/IP NOTIFICATION UDP datagram can trigger a heap **out-of-bounds read** and crash any service using E2E Profile 07.
## Root Cause
`profile_07_checker::check()` reads up to `offset_ + 19` but never verifies that `buffer.size() >= offset_ + 20`. Instead, it validates only the message's **total** length (`min_data_length_`/`max_data_length_`), which is independent of `offset_` and cannot prevent out-of-bounds reads.
```cpp
// implementation/e2e_protection/src/e2e/profile/profile07/checker.cpp
void profile_07_checker::check(const e2e_buffer& _buffer, instance_t _instance,
e2e::profile_interface::check_status_t& _generic_check_status) {
std::scoped_lock lock(check_mutex_);
_generic_check_status = e2e::profile_interface::generic_check_status::E2E_ERROR;
if (verify_input(_buffer)) { // (1)
uint32_t its_received_length;
if (read_32(_buffer, its_received_length, PROFILE_07_SIZE_OFFSET)) { // offset_+8..11
uint32_t its_received_counter;
if (read_32(_buffer, its_received_counter, PROFILE_07_COUNTER_OFFSET)) { // offset_+12..15
uint32_t its_received_data_id;
if (read_32(_buffer, its_received_data_id, PROFILE_07_DATAID_OFFSET)) { // offset_+16..19
uint64_t its_received_crc;
if (read_64(_buffer, its_received_crc, PROFILE_07_CRC_OFFSET)) { // offset_+0..7
...
```
```cpp
// (1) verify_input() -- only checks total buffer size, unrelated to offset_
bool profile_07_checker::verify_input(const e2e_buffer& _buffer) const {
auto its_length = _buffer.size();
return (its_length >= config_.min_data_length_ && its_length <= config_.max_data_length_);
}
```
```cpp
// read_32 / read_64 -- no bounds check before indexing
bool profile_07_checker::read_32(const e2e_buffer& _buffer, uint32_t& _data, size_t _index) const {
_data = bithelper::read_uint32_be(&_buffer[config_.offset_ + _index]); // OOB if offset_+_index+4 > buffer.size()
return true;
}
bool profile_07_checker::read_64(const e2e_buffer& _buffer, uint64_t& _data, size_t _index) const {
_data = bithelper::read_uint64_be(&_buffer[config_.offset_ + _index]); // OOB if offset_+_index+8 > buffer.size()
return true;
}
```
```cpp
// implementation/e2e_protection/include/e2e/profile/profile07/profile_07.hpp
const uint8_t PROFILE_07_SIZE_OFFSET = 8;
const uint8_t PROFILE_07_COUNTER_OFFSET = 12;
const uint8_t PROFILE_07_DATAID_OFFSET = 16;
const uint8_t PROFILE_07_CRC_OFFSET = 0;
```
Reachability from the network (`implementation/routing/src/routing_manager_impl.cpp`):
```cpp
// routing_manager_impl::on_message(...)
...
if (e2e_provider_->is_checked({its_service, its_method})) {
auto its_base = e2e_provider_->get_protection_base(its_service, its_method);
e2e_buffer its_buffer(_data + its_base, _data + _size);
e2e_provider_->check({its_service, its_method}, its_buffer, its_instance, its_generic_check_status); // -> profile_07_checker::check()
}
```
### Reproduction Steps
**Reproduction**: a standard Release build of vsomeip, attacking the real,
unmodified `examples/notify-sample` binary with a JSON config that adds Profile 07 protection to
its existing event:
```jsonc
{
"applications": [ { "name": "notify-sample", "id": "0x1343" } ],
"services": [ { "service": "0x1234", "instance": "0x5678", "unreliable": "30509" } ],
"e2e": { "e2e_enabled": "true", "protected": [
{ "service_id": "0x1234", "event_id": "0x8778", "variant": "checker", "profile": "P07",
"data_id": "0x1", "crc_offset": "1600000", "min_data_length": "0", "max_data_length": "4194304",
"max_delta_counter": "4294967295" }
]},
"routing": "notify-sample"
}
```
Attack packet — an 18-byte UDP datagram (16-byte SOME/IP header + 2-byte payload) targeting `notify-sample`'s real service/event IDs (`0x1234`/`0x8778`):
### Expected behaviour
_No response_
### Logs and Screenshots
```
=================================================================
==6191==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x5020000004b8 at pc 0x75a842aee6c9 bp 0x7ffdd97dd650 sp 0x7ffdd97dd640
READ of size 4 at 0x5020000004b8 thread T0
#0 0x75a842aee6c8 in memcpy /usr/include/x86_64-linux-gnu/bits/string_fortified.h:29
#1 0x75a842aee6c8 in vsomeip_v3::bithelper::read_uint32_be(unsigned char const*) /root/vsomeip-src/implementation/e2e_protection/src/e2e/profile/profile07/../../../../../utility/include/bithelper.hpp:80
#2 0x75a842aee6c8 in vsomeip_v3::e2e::profile07::profile_07_checker::read_32(std::vector > const&, unsigned int&, unsigned long) const /root/vsomeip-src/implementation/e2e_protection/src/e2e/profile/profile07/checker.cpp:86
#3 0x75a842aefae4 in vsomeip_v3::e2e::profile07::profile_07_checker::check(std::vector > const&, unsigned short, unsigned char&) /root/vsomeip-src/implementation/e2e_protection/src/e2e/profile/profile07/checker.cpp:28
#4 0x75a842abfff5 in vsomeip_v3::e2e::e2e_provider_impl::check(std::pair, std::vector > const&, unsigned short, unsigned char&) /root/vsomeip-src/implementation/e2e_protection/src/e2e/profile/e2e_provider_impl.cpp:125
#5 0x75a843f014ca in vsomeip_v3::routing_manager_impl::on_message(unsigned char const*, unsigned int, vsomeip_v3::boardnet_endpoint*, boost::asio::ip::address const&, unsigned short, bool) /root/vsomeip-src/implementation/routing/src/routing_manager_impl.cpp:1165
#6 0x75a843cc18e6 in vsomeip_v3::udp_server_endpoint_impl::on_message_received_unlocked(boost::system::error_code const&, unsigned long, bool, boost::asio::ip::basic_endpoint const&, std::vector > const&) /root/vsomeip-src/implementation/endpoints/src/udp_server_endpoint_impl.cpp:719
#7 0x75a843cc503d in vsomeip_v3::udp_server_endpoint_impl::on_unicast_received(boost::system::error_code const&, unsigned long, std::vector > const&) /root/vsomeip-src/implementation/endpoints/src/udp_server_endpoint_impl.cpp:571
#8 0x75a843cc599e in operator() /root/vsomeip-src/implementation/endpoints/src/udp_server_endpoint_impl.cpp:295
#9 0x75a84397f239 in std::function::operator()(boost::system::error_code const&, unsigned long) const /usr/include/c++/13/bits/std_function.h:591
#10 0x75a84397f239 in boost::asio::detail::binder2, boost::system::error_code, unsigned long>::operator()() /usr/include/boost/asio/detail/bind_handler.hpp:289
#11 0x75a84397f239 in void boost::asio::asio_handler_invoke, boost::system::error_code, unsigned long> >(boost::asio::detail::binder2, boost::system::error_code, unsigned long>&, ...) /usr/include/boost/asio/handler_invoke_hook.hpp:88
#12 0x75a84397f239 in void boost_asio_handler_invoke_helpers::invoke, boost::system::error_code, unsigned long>, std::function >(boost::asio::detail::binder2, boost::system::error_code, unsigned long>&, std::function&) /usr/include/boost/asio/detail/handler_invoke_helpers.hpp:54
#13 0x75a84397f239 in void boost::asio::detail::handler_work, boost::asio::any_io_executor, void>::complete, boost::system::error_code, unsigned long> >(boost::asio::detail::binder2, boost::system::error_code, unsigned long>&, std::function&) /usr/include/boost/asio/detail/handler_work.hpp:524
#14 0x75a84397f239 in void boost::asio::detail::handler_work, boost::asio::any_io_executor, void>::complete, boost::system::error_code, unsigned long> >(boost::asio::detail::binder2, boost::system::error_code, unsigned long>&, std::function&) /usr/include/boost/asio/detail/handler_work.hpp:517
#15 0x75a84397f239 in boost::asio::detail::reactive_socket_recvfrom_op, std::function, boost::asio::any_io_executor>::do_complete(void*, boost::asio::detail::scheduler_operation*, boost::system::error_code const&, unsigned long) /usr/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp:157
#16 0x75a84393eb85 in boost::asio::detail::scheduler_operation::complete(void*, boost::system::error_code const&, unsigned long) /usr/include/boost/asio/detail/scheduler_operation.hpp:40
#17 0x75a84393eb85 in boost::asio::detail::scheduler::do_run_one(boost::asio::detail::conditionally_enabled_mutex::scoped_lock&, boost::asio::detail::scheduler_thread_info&, boost::system::error_code const&) /usr/include/boost/asio/detail/impl/scheduler.ipp:493
#18 0x75a84401f8dc in boost::asio::detail::scheduler::run(boost::system::error_code&) /usr/include/boost/asio/detail/impl/scheduler.ipp:210
#19 0x75a8440735da in boost::asio::io_context::run() /usr/include/boost/asio/impl/io_context.ipp:64
#20 0x75a8440735da in vsomeip_v3::application_impl::start() /root/vsomeip-src/implementation/runtime/src/application_impl.cpp:438
#21 0x5b00a1870cad in service_sample::start() /root/vsomeip-src/examples/notify-sample.cpp:60
#22 0x5b00a1870cad in main /root/vsomeip-src/examples/notify-sample.cpp:247
#23 0x75a8432741c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
#24 0x75a84327428a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
#25 0x5b00a1870fa4 in _start (/root/build-asan/examples/notify-sample+0x3fa4) (BuildId: 41eb245d3c52a1e1b6fb1cc6895e16c6828db377)
0x5020000004ba is located 0 bytes after 10-byte region [0x5020000004b0,0x5020000004ba)
allocated by thread T0 here:
#0 0x75a84449b548 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:95
#1 0x75a843f0130c in std::__new_allocator::allocate(unsigned long, void const*) /usr/include/c++/13/bits/new_allocator.h:151
#2 0x75a843f0130c in std::allocator::allocate(unsigned long) /usr/include/c++/13/bits/allocator.h:198
#3 0x75a843f0130c in std::allocator_traits >::allocate(std::allocator&, unsigned long) /usr/include/c++/13/bits/alloc_traits.h:482
#4 0x75a843f0130c in std::_Vector_base >::_M_allocate(unsigned long) /usr/include/c++/13/bits/stl_vector.h:381
#5 0x75a843f0130c in std::_Vector_base >::_M_allocate(unsigned long) /usr/include/c++/13/bits/stl_vector.h:378
#6 0x75a843f0130c in void std::vector >::_M_range_initialize(unsigned char const*, unsigned char const*, std::forward_iterator_tag) /usr/include/c++/13/bits/stl_vector.h:1692
#7 0x75a843f0130c in std::vector >::vector(unsigned char const*, unsigned char const*, std::allocator const&) /usr/include/c++/13/bits/stl_vector.h:711
#8 0x75a843f0130c in vsomeip_v3::routing_manager_impl::on_message(unsigned char const*, unsigned int, vsomeip_v3::boardnet_endpoint*, boost::asio::ip::address const&, unsigned short, bool) /root/vsomeip-src/implementation/routing/src/routing_manager_impl.cpp:1164
#9 0x75a843cc18e6 in vsomeip_v3::udp_server_endpoint_impl::on_message_received_unlocked(boost::system::error_code const&, unsigned long, bool, boost::asio::ip::basic_endpoint const&, std::vector > const&) /root/vsomeip-src/implementation/endpoints/src/udp_server_endpoint_impl.cpp:719
#10 0x75a843cc503d in vsomeip_v3::udp_server_endpoint_impl::on_unicast_received(boost::system::error_code const&, unsigned long, std::vector > const&) /root/vsomeip-src/implementation/endpoints/src/udp_server_endpoint_impl.cpp:571
#11 0x75a843cc599e in operator() /root/vsomeip-src/implementation/endpoints/src/udp_server_endpoint_impl.cpp:295
#12 0x75a84397f239 in std::function::operator()(boost::system::error_code const&, unsigned long) const /usr/include/c++/13/bits/std_function.h:591
#13 0x75a84397f239 in boost::asio::detail::binder2, boost::system::error_code, unsigned long>::operator()() /usr/include/boost/asio/detail/bind_handler.hpp:289
#14 0x75a84397f239 in void boost::asio::asio_handler_invoke, boost::system::error_code, unsigned long> >(boost::asio::detail::binder2, boost::system::error_code, unsigned long>&, ...) /usr/include/boost/asio/handler_invoke_hook.hpp:88
#15 0x75a84397f239 in void boost_asio_handler_invoke_helpers::invoke, boost::system::error_code, unsigned long>, std::function >(boost::asio::detail::binder2, boost::system::error_code, unsigned long>&, std::function&) /usr/include/boost/asio/detail/handler_invoke_helpers.hpp:54
#16 0x75a84397f239 in void boost::asio::detail::handler_work, boost::asio::any_io_executor, void>::complete, boost::system::error_code, unsigned long> >(boost::asio::detail::binder2, boost::system::error_code, unsigned long>&, std::function&) /usr/include/boost/asio/detail/handler_work.hpp:524
#17 0x75a84397f239 in void boost::asio::detail::handler_work, boost::asio::any_io_executor, void>::complete, boost::system::error_code, unsigned long> >(boost::asio::detail::binder2, boost::system::error_code, unsigned long>&, std::function&) /usr/include/boost/asio/detail/handler_work.hpp:517
#18 0x75a84397f239 in boost::asio::detail::reactive_socket_recvfrom_op, std::function, boost::asio::any_io_executor>::do_complete(void*, boost::asio::detail::scheduler_operation*, boost::system::error_code const&, unsigned long) /usr/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp:157
#19 0x75a84393eb85 in boost::asio::detail::scheduler_operation::complete(void*, boost::system::error_code const&, unsigned long) /usr/include/boost/asio/detail/scheduler_operation.hpp:40
#20 0x75a84393eb85 in boost::asio::detail::scheduler::do_run_one(boost::asio::detail::conditionally_enabled_mutex::scoped_lock&, boost::asio::detail::scheduler_thread_info&, boost::system::error_code const&) /usr/include/boost/asio/detail/impl/scheduler.ipp:493
#21 0x75a84401f8dc in boost::asio::detail::scheduler::run(boost::system::error_code&) /usr/include/boost/asio/detail/impl/scheduler.ipp:210
#22 0x75a8440735da in boost::asio::io_context::run() /usr/include/boost/asio/impl/io_context.ipp:64
#23 0x75a8440735da in vsomeip_v3::application_impl::start() /root/vsomeip-src/implementation/runtime/src/application_impl.cpp:438
#24 0x5b00a1870cad in service_sample::start() /root/vsomeip-src/examples/notify-sample.cpp:60
#25 0x5b00a1870cad in main /root/vsomeip-src/examples/notify-sample.cpp:247
#26 0x75a8432741c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
#27 0x75a84327428a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
#28 0x5b00a1870fa4 in _start (/root/build-asan/examples/notify-sample+0x3fa4) (BuildId: 41eb245d3c52a1e1b6fb1cc6895e16c6828db377)
SUMMARY: AddressSanitizer: heap-buffer-overflow /usr/include/x86_64-linux-gnu/bits/string_fortified.h:29 in memcpy
Shadow bytes around the buggy address:
0x502000000200: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
0x502000000280: fa fa 00 07 fa fa fd fa fa fa 00 00 fa fa 00 00
0x502000000300: fa fa 00 00 fa fa fd fd fa fa 00 00 fa fa fd fd
0x502000000380: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
0x502000000400: fa fa 00 00 fa fa 00 00 fa fa fd fd fa fa fd fd
=>0x502000000480: fa fa fd fd fa fa 00[02]fa fa fa fa fa fa fa fa
0x502000000500: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000000580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000000600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000000680: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000000700: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==6191==ABORTING
```
Contributor guide
Research direction
Start with implementation/e2e_protection/src/e2e/profile/profile07/checker.cpp and the offsets in implementation/e2e_protection/include/e2e/profile/profile07/profile_07.hpp; then trace the call from routing_manager_impl::on_message. Reproduce with the notify-sample configuration and short UDP packet under AddressSanitizer. Done means malformed short Profile 07 datagrams are rejected without an out-of-bounds read or crash.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- networking, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 58/100