Skip to content

In security mode, when the authentication fails, the change for the handshake request is not released. #5934

@Barry-Xu-2018

Description

@Barry-Xu-2018

Is there an already existing issue for this?

  • I have searched the existing issues

Expected behavior

While the authentication of the remote participant fails, the change for sending the request is released.

Current behavior

While the authentication of the remote participant fails, the change for sending the request isn't released.

Steps to reproduce

This issue was discovered in an environment using DDS-Router and Humble. Since the version of FastDDS used in Humble is no longer maintained, I compared code with the latest code of FastDDS and I think the problem likely still exists.
So, I’ll describe the scenario in which the issue occurs.

  1. SPDP find a new remote participant.
  2. In SecurityManager::on_process_handshake(), the authentication status of remote participant is AUTHENTICATION_REQUEST_NOT_SEND. FastDDS will prepare a handshake request message and send it.
    if (participant_stateless_message_writer_history_->add_change(change))
    {
    handshake_message_send = true;
    expected_sequence_number = message.message_identity().sequence_number();
    remote_participant_info->change_sequence_number_ = change->sequenceNumber;
    remote_participant_info->handshake_requests_sent_++;
    }

    And this change will be hold.
  3. At this time, the remote participant is removed.
  4. FastDDS will attempt to resend the Handshake Request until it reaches the maximum number of handshake requests (max_handshake_requests).
    Refer to
    void SecurityManager::resend_handshake_message_token(
    const GUID_t& remote_participant_key) const
    {
    auto sentry = is_security_manager_initialized();
    if (!sentry)
    {
    return;
    }
    shared_lock<shared_mutex> _(mutex_);
    auto dp_it = discovered_participants_.find(remote_participant_key);
    if (dp_it != discovered_participants_.end())
    {
    SecurityManager::DiscoveredParticipantInfo::AuthUniquePtr remote_participant_info = dp_it->second->get_auth();
    if (remote_participant_info)
    {
    if (remote_participant_info->handshake_requests_sent_ >= auth_handshake_props_.max_handshake_requests_)
    {
    if (remote_participant_info->auth_status_ != AUTHENTICATION_FAILED)
    {
    SecurityException exception;
    remote_participant_info->event_->cancel_timer();
    remote_participant_info->auth_status_ = AUTHENTICATION_FAILED;
    on_validation_failed(dp_it->second->participant_data(), exception);
    }
    }
    else
    {
    if (remote_participant_info->change_sequence_number_ != SequenceNumber_t::unknown())
    {
    CacheChange_t* p_change = participant_stateless_message_writer_history_->remove_change_and_reuse(
    remote_participant_info->change_sequence_number_);
    remote_participant_info->change_sequence_number_ = SequenceNumber_t::unknown();
    if (p_change != nullptr)
    {
    EPROSIMA_LOG_INFO(SECURITY, "Authentication handshake resent to participant " <<
    remote_participant_key);
    if (participant_stateless_message_writer_history_->add_change(p_change))
    {
    remote_participant_info->change_sequence_number_ = p_change->sequenceNumber;
    remote_participant_info->handshake_requests_sent_++;
    }
    //TODO (Ricardo) What to do if not added?
    }
    }
    if (remote_participant_info->auth_status_ == AUTHENTICATION_WAITING_REPLY)
    {
    // Avoid DoS attack by exponentially increasing event interval
    auto time_ms = remote_participant_info->event_->getIntervalMilliSec();
    remote_participant_info->event_->update_interval_millisec(
    time_ms * auth_handshake_props_.handshake_resend_period_gain_);
    remote_participant_info->event_->restart_timer();
    }
    }
    dp_it->second->set_auth(remote_participant_info);
    }
    }
    }
  5. When the max_handshake_requests is reached, the following code will be executed.
    if (remote_participant_info->handshake_requests_sent_ >= auth_handshake_props_.max_handshake_requests_)
    {
    if (remote_participant_info->auth_status_ != AUTHENTICATION_FAILED)
    {
    SecurityException exception;
    remote_participant_info->event_->cancel_timer();
    remote_participant_info->auth_status_ = AUTHENTICATION_FAILED;
    on_validation_failed(dp_it->second->participant_data(), exception);
    }
    }

But the change for request isn't released.
The fix refers to #5935

Fast DDS version/commit

v3.3.0

Platform/Architecture

Other. Please specify in Additional context section.

Transport layer

Default configuration, UDPv4 & SHM

Additional context

Platform: Ubuntu 24.04 (x86_64)

XML configuration file

Relevant log output

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