This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/qpid-proton.git
commit 329edf8e1e281806f024c9f79ea8f7e86c067c67 Author: Andrew Stitcher <[email protected]> AuthorDate: Thu May 21 16:12:56 2026 -0400 PROTON-1442: Make sure we only respond if we are in a transaction If the peer is misbehaved it could send us a transactioned disposition when we're not in a transaction or it could be for a different transaction. This code was written with the assistance of Cursor. --- cpp/src/messaging_adapter.cpp | 22 +++++++++++++++++++++- cpp/src/transaction_options.cpp | 4 +++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/cpp/src/messaging_adapter.cpp b/cpp/src/messaging_adapter.cpp index e4812d7d3..0e22b142f 100644 --- a/cpp/src/messaging_adapter.cpp +++ b/cpp/src/messaging_adapter.cpp @@ -114,9 +114,14 @@ bool transaction_coordinator_sender(const sender& s) { return txn_context && (txn_context->coordinator == unwrap(s)); } +void transaction_protocol_error(session_context& /*sctx*/, const char* /*message*/) { + // TODO: decide how to handle transactional protocol errors +} + void handle_outgoing_committed_deliveries(messaging_handler& handler, session &s) { auto session = unwrap(s); auto& transaction_context = session_context::get(session).transaction_context_; + assert(transaction_context); for (auto t : transaction_context->provisional_outcomes) { auto disposition = pn_delivery_remote(unwrap(t)); auto trans_disp = pn_transactional_disposition(disposition); @@ -151,6 +156,7 @@ void settle_outgoing_deliveries(session& s) { // scope our transactions to a session, we will settle all outgoing deliveries for the session. auto session = unwrap(s); auto& transaction_context = session_context::get(session).transaction_context_; + assert(transaction_context); auto coordinator = transaction_context->coordinator; for (auto link = pn_link_head(pn_session_connection(session), 0); link; @@ -210,6 +216,7 @@ void handle_transaction_coordinator_outcome(messaging_handler& handler, const tr auto session = t.session(); auto& session_context = session_context::get(unwrap(session)); auto& transaction_context = session_context.transaction_context_; + assert(transaction_context); auto state = transaction_context->state; auto disposition = pn_delivery_remote(unwrap(t)); if (auto *declared_disp = pn_declared_disposition(disposition); declared_disp) { @@ -291,6 +298,20 @@ void handle_transaction_coordinator_outcome(messaging_handler& handler, const tr void handle_transacted_delivery_outcome(messaging_handler& handler, pn_delivery_t* d, tracker& t) { auto& session_context = session_context::get(unwrap(t.session())); auto& transaction_context = session_context.transaction_context_; + if (!transaction_context) { + transaction_protocol_error(session_context, "Received transactional disposition when not in a transaction"); + return; + } + + auto disposition = pn_transactional_disposition(pn_delivery_remote(d)); + if (!disposition) { + transaction_protocol_error(session_context, "Received transactional disposition without transactional state"); + return; + } + if (bin(pn_transactional_disposition_get_id(disposition)) != transaction_context->transaction_id) { + transaction_protocol_error(session_context, "Received transactional disposition with invalid transaction id"); + return; + } // We should hold on to tracker here so that we can call the non transactional handlers if the transaction // commits without error. We can't do this triggered by the the incoming settlement later as it will happen before @@ -304,7 +325,6 @@ void handle_transacted_delivery_outcome(messaging_handler& handler, pn_delivery_ return; } - auto disposition = pn_transactional_disposition(pn_delivery_remote(d)); auto outcome_type = pn_transactional_disposition_get_outcome_type(disposition); switch (outcome_type) { case PN_ACCEPTED: diff --git a/cpp/src/transaction_options.cpp b/cpp/src/transaction_options.cpp index 9258a3d3a..ae7b8ef36 100644 --- a/cpp/src/transaction_options.cpp +++ b/cpp/src/transaction_options.cpp @@ -26,6 +26,8 @@ #include "contexts.hpp" #include "proton_bits.hpp" +#include <assert.h> + namespace proton { namespace { @@ -48,7 +50,7 @@ class transaction_options::impl { void apply(session& s) { auto& session_context = session_context::get(unwrap(s)); auto& transaction_context = session_context.transaction_context_; - + assert(transaction_context); if (auto_modify_on_abort.set) transaction_context->auto_modify_on_abort = auto_modify_on_abort.value; } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
