Skip to content

UBSan: signed integer overflow in DataReaderImpl::update_sample_lost_status triggered by crafted RTPS DATA sequence number #6366

Description

@TUPYP7180

Is there an already existing issue for this?

  • I have searched the existing issues

Expected behavior

SampleLostStatus.total_count should accumulate monotonically and never wrap or overflow. When the per-event lost-sample count is already capped to INT32_MAX by StatelessReader, the cumulative counter should either saturate at INT32_MAX or use a wider type so that repeated additions remain well-defined.

Current behavior

When a StatelessReader-backed DataReader receives a DATA submessage whose sequence number skips by more than INT32_MAX relative to the previous one, StatelessReader correctly caps lost_samples at INT32_MAX. However, DataReaderImpl::update_sample_lost_status adds this value directly to the int32_t field total_count with no overflow check. If total_count is already greater than zero (from any prior lost-sample event), the addition overflows and UBSan aborts the process:

runtime error: signed integer overflow: 1 + 2147483647 cannot be represented in type 'int'

Without UBSan the counter silently wraps to a large negative value.

Steps to reproduce

Proof of Concept:

The following three RTPS UDP packets, sent in order to a Fast-DDS participant port, reproduce the overflow. The key is that packet 3 carries a writerSN.low of 0x80000004 in little-endian encoding, creating a sequence-number gap large enough to saturate the per-event counter at INT32_MAX.

Packet 1 — establish baseline (SN = 1):

# RTPS header
52 54 50 53  # Magic "RTPS"
02 03        # Protocol version 2.3
01 0F        # Vendor ID (eProsima)
01 02 03 04 05 06 07 08 09 0A 0B 0C  # GUID prefix
# DATA submessage (ID=0x15, flags=0x05: little-endian + data present)
15 05 18 00  # subMsg ID, flags, octetsToNextHeader=24
00 00        # extraFlags
10 00        # octetsToInlineQos = 16
00 00 00 00  # readerEntityId = ENTITYID_UNKNOWN
00 00 00 07  # writerEntityId
00 00 00 00  # writerSN.high = 0
01 00 00 00  # writerSN.low  = 1  (SN = 1)
00 01 00 00  # serialized payload (CDR_BE + padding)

Packet 2 — create one lost sample (SN = 3, gap = 1):

52 54 50 53 02 03 01 0F 01 02 03 04 05 06 07 08 09 0A 0B 0C
15 05 18 00 00 00 10 00 00 00 00 00 00 00 00 07
00 00 00 00 03 00 00 00  # writerSN = 3  →  total_count becomes 1
00 01 00 00

Packet 3 — trigger overflow (SN = 0x80000004, gap ≈ INT32_MAX):

52 54 50 53 02 03 01 0F 01 02 03 04 05 06 07 08 09 0A 0B 0C
15 05 18 00 00 00 10 00 00 00 00 00 00 00 00 07
00 00 00 00 04 00 00 80  # writerSN.low = 0x80000004 (LE)  →  gap saturates at INT32_MAX
00 01 00 00              # total_count = 1 + INT32_MAX  →  UBSan overflow

Fast DDS version/commit

v3.5.0 (tag v3.5.0, branch master)
Fast-CDR v2.3.5

Platform/Architecture

Ubuntu Focal 20.04 amd64

Transport layer

UDPv4

Additional context

No response

XML configuration file

Relevant log output

/home/.../Fast-DDS/src/cpp/fastdds/subscriber/DataReaderImpl.cpp:1577:37:
runtime error: signed integer overflow: 1 + 2147483647 cannot be represented in type 'int'
    #0 eprosima::fastdds::dds::DataReaderImpl::update_sample_lost_status(int)
           DataReaderImpl.cpp:1577
    #1 eprosima::fastdds::dds::DataReaderImpl::InnerDataReaderListener::on_sample_lost(
           eprosima::fastdds::rtps::RTPSReader*, int)
           DataReaderImpl.cpp:1009
    #2 eprosima::fastdds::rtps::StatelessReader::change_received(
           eprosima::fastdds::rtps::CacheChange_t*)
           StatelessReader.cpp:403
    #3 eprosima::fastdds::rtps::StatelessReader::process_data_msg(
           eprosima::fastdds::rtps::CacheChange_t*)
           StatelessReader.cpp:695
    #4 ... MessageReceiver::proc_Submsg_Data(...)  MessageReceiver.cpp:898
    #5 ... MessageReceiver::processCDRMsg(...)     MessageReceiver.cpp:467
    #6 ... ReceiverResource::OnDataReceived(...)   ReceiverResource.cpp:135
    #7 ... UDPChannelResource::perform_listen_operation(...)
    #8 start_thread (pthread)

SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior DataReaderImpl.cpp:1577:37 in

Network traffic capture

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    triageIssue pending classification

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions