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 0ec4d39707285d12608e6597671747c541ba245d Author: Andrew Stitcher <[email protected]> AuthorDate: Mon Aug 24 21:43:15 2026 -0400 PROTON-2970: Validate the SASL state before handling a frame Each SASL body handler checked that the frame was one its role could receive - but not that it was one it was expecting at this point in the protocol exchange. Check the state of the exchange as well. A server takes an init only once it has posted its mechanisms, and a response only once it has posted a challenge. A client takes a mechanisms frame only before it has posted anything, and a challenge or an outcome only once it has posted an init or a response. Anything else is PN_ERR, as a frame arriving at the wrong role already was. The state tested is desired_state rather than last_state. A pipelining peer can legitimately send its next frame before we have actually written our own, so last_state can still be lagging behind the frame we have already committed to sending. Assisted-By: Claude Opus 5 <[email protected]> --- c/src/sasl/sasl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/c/src/sasl/sasl.c b/c/src/sasl/sasl.c index 3e639de58..d757c8adc 100644 --- a/c/src/sasl/sasl.c +++ b/c/src/sasl/sasl.c @@ -904,6 +904,10 @@ int pn_do_init(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, // We should only receive this if we are a sasl server if (sasl->client) return PN_ERR; + // Check the protocol state using desired_state not last_state: a pipelining peer can + // legitimately send its next frame before we've actually written out our own, so + // last_state can still be lagging behind the frame we've already committed to sending. + if (sasl->desired_state != SASL_POSTED_MECHANISMS) return PN_ERR; pn_bytes_t mech; pn_bytes_t recv; @@ -936,6 +940,7 @@ int pn_do_mechanisms(pn_transport_t *transport, uint8_t frame_type, uint16_t cha // We should only receive this if we are a sasl client if (!sasl->client) return PN_ERR; + if (sasl->desired_state != SASL_NONE) return PN_ERR; pn_string_t *mechs = pn_string(""); @@ -1004,6 +1009,7 @@ int pn_do_challenge(pn_transport_t *transport, uint8_t frame_type, uint16_t chan // We should only receive this if we are a sasl client if (!sasl->client) return PN_ERR; + if (sasl->desired_state != SASL_POSTED_INIT && sasl->desired_state != SASL_POSTED_RESPONSE) return PN_ERR; pn_bytes_t recv; @@ -1025,6 +1031,7 @@ int pn_do_response(pn_transport_t *transport, uint8_t frame_type, uint16_t chann // We should only receive this if we are a sasl server if (sasl->client) return PN_ERR; + if (sasl->desired_state != SASL_POSTED_CHALLENGE) return PN_ERR; pn_bytes_t recv; @@ -1046,6 +1053,7 @@ int pn_do_outcome(pn_transport_t *transport, uint8_t frame_type, uint16_t channe // We should only receive this if we are a sasl client if (!sasl->client) return PN_ERR; + if (sasl->desired_state != SASL_POSTED_INIT && sasl->desired_state != SASL_POSTED_RESPONSE) return PN_ERR; uint8_t outcome; pn_bytes_t recv; --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
