This is an automated email from the ASF dual-hosted git repository.
astitcher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton.git
The following commit(s) were added to refs/heads/main by this push:
new 40cb24b PROTON-2535: Parse and generate handle_max in the begin frame
40cb24b is described below
commit 40cb24b5ffee5e2e4d08453329a0e52bf222963d
Author: Andrew Stitcher <[email protected]>
AuthorDate: Fri Mar 18 18:06:27 2022 -0400
PROTON-2535: Parse and generate handle_max in the begin frame
We want to put handle_max into the frame to avoid our peer from sending
a handle that is big enough to seem negative - we use negative handles
for special purposes.
Equally, we should respect any handle_max our peer sends us.
[Bug found by the fuzzer]
---
c/src/core/engine-internal.h | 3 ++
c/src/core/engine.c | 2 ++
c/src/core/transport.c | 33 ++++++++++++++++-----
.../crash/leak-5289430926098432-1 | Bin 0 -> 121 bytes
c/tools/codec-generator/specs.json | 4 +--
5 files changed, 32 insertions(+), 10 deletions(-)
diff --git a/c/src/core/engine-internal.h b/c/src/core/engine-internal.h
index 09ff3ec..7554dd3 100644
--- a/c/src/core/engine-internal.h
+++ b/c/src/core/engine-internal.h
@@ -94,6 +94,8 @@ typedef struct {
pn_sequence_t disp_first;
pn_sequence_t disp_last;
// XXX: stop using negative numbers
+ #define PN_IMPL_HANDLE_MAX 0x7fffffff
+ uint32_t remote_handle_max;
uint16_t local_channel;
uint16_t remote_channel;
bool incoming_init;
@@ -259,6 +261,7 @@ struct pn_session_t {
pn_list_t *freed;
pn_record_t *context;
size_t incoming_capacity;
+ uint32_t local_handle_max;
pn_sequence_t incoming_bytes;
pn_sequence_t outgoing_bytes;
pn_sequence_t incoming_deliveries;
diff --git a/c/src/core/engine.c b/c/src/core/engine.c
index 1aa1992..d16cf65 100644
--- a/c/src/core/engine.c
+++ b/c/src/core/engine.c
@@ -1005,9 +1005,11 @@ pn_session_t *pn_session(pn_connection_t *conn)
ssn->incoming_deliveries = 0;
ssn->outgoing_deliveries = 0;
ssn->outgoing_window = AMQP_MAX_WINDOW_SIZE;
+ ssn->local_handle_max = PN_IMPL_HANDLE_MAX;
// begin transport state
memset(&ssn->state, 0, sizeof(ssn->state));
+ ssn->state.remote_handle_max = UINT32_MAX;
ssn->state.local_channel = (uint16_t)-1;
ssn->state.remote_channel = (uint16_t)-1;
pn_delivery_map_init(&ssn->state.incoming, 0);
diff --git a/c/src/core/transport.c b/c/src/core/transport.c
index e669a06..b05f25a 100644
--- a/c/src/core/transport.c
+++ b/c/src/core/transport.c
@@ -1101,8 +1101,12 @@ int pn_do_begin(pn_transport_t *transport, uint8_t
frame_type, uint16_t channel,
bool reply;
uint16_t remote_channel;
pn_sequence_t next;
+ uint32_t incoming_window;
+ uint32_t outgoing_window;
+ bool handle_max_q;
+ uint32_t handle_max;
- pn_amqp_decode_DqEQHIe(payload, &reply, &remote_channel, &next);
+ pn_amqp_decode_DqEQHIIIQIe(payload, &reply, &remote_channel, &next,
&incoming_window, &outgoing_window, &handle_max_q, &handle_max);
// AMQP 1.0 section 2.7.1 - if the peer doesn't honor our channel_max --
// express our displeasure by closing the connection with a framing error.
@@ -1131,6 +1135,9 @@ int pn_do_begin(pn_transport_t *transport, uint8_t
frame_type, uint16_t channel,
ssn = pn_session(transport->connection);
}
ssn->state.incoming_transfer_count = next;
+ if (handle_max_q) {
+ ssn->state.remote_handle_max = handle_max;
+ }
pni_map_remote_channel(ssn, channel);
PN_SET_REMOTE(ssn->endpoint.state, PN_REMOTE_ACTIVE);
pn_collector_put(transport->connection->collector, PN_OBJECT, ssn,
PN_SESSION_REMOTE_OPEN);
@@ -1242,6 +1249,13 @@ int pn_do_attach(pn_transport_t *transport, uint8_t
frame_type, uint16_t channel
pn_free(rem_props);
return PN_EOS;
}
+ if (handle > ssn->local_handle_max) {
+ pn_do_error(transport, "amqp:connection:framing-error",
+ "remote handle %u is above handle_max %u", handle,
ssn->local_handle_max);
+ if (strheap) free(strheap);
+ pn_free(rem_props);
+ return PN_EOS;
+ }
pn_link_t *link = pni_find_link(ssn, name, is_sender);
if (link && (int32_t)link->state.remote_handle >= 0) {
pn_do_error(transport, "amqp:invalid-field", "link name already attached:
%s", strname);
@@ -1944,12 +1958,13 @@ static int pni_process_ssn_setup(pn_transport_t
*transport, pn_endpoint_t *endpo
}
state->incoming_window = pni_session_incoming_window(ssn);
state->outgoing_window = pni_session_outgoing_window(ssn);
- /* "DL[?HIII]" */
- pn_bytes_t buf = pn_amqp_encode_DLEQHIIIe(transport->frame, BEGIN,
+ /* "DL[?HIIII]" */
+ pn_bytes_t buf = pn_amqp_encode_DLEQHIIIIe(transport->frame, BEGIN,
((int16_t) state->remote_channel >= 0),
state->remote_channel,
state->outgoing_transfer_count,
state->incoming_window,
- state->outgoing_window);
+ state->outgoing_window,
+ ssn->local_handle_max);
pn_framing_send_amqp(transport, state->local_channel, buf);
}
}
@@ -1979,9 +1994,8 @@ static int pni_map_local_handle(pn_link_t *link) {
pn_link_state_t *state = &link->state;
pn_session_state_t *ssn_state = &link->session->state;
int valid;
- // XXX TODO MICK: once changes are made to handle_max, change this hardcoded
value to something reasonable.
- state->local_handle = allocate_alias(ssn_state->local_handles, 65536, &
valid);
- if ( ! valid )
+ state->local_handle = allocate_alias(ssn_state->local_handles,
ssn_state->remote_handle_max, &valid);
+ if ( !valid )
return 0;
pn_hash_put(ssn_state->local_handles, state->local_handle, link);
pn_ep_incref(&link->endpoint);
@@ -1999,7 +2013,10 @@ static int pni_process_link_setup(pn_transport_t
*transport, pn_endpoint_t *endp
if (((int16_t) ssn_state->local_channel >= 0) &&
!(endpoint->state & PN_LOCAL_UNINIT) && state->local_handle ==
(uint32_t) -1)
{
- pni_map_local_handle(link);
+ if (! pni_map_local_handle(link)) {
+ pn_logger_logf(&transport->logger, PN_SUBSYSTEM_AMQP,
PN_LEVEL_WARNING, "unable to find an open available handle within limit of %d",
ssn_state->remote_handle_max );
+ return PN_ERR;
+ }
const pn_distribution_mode_t dist_mode = (pn_distribution_mode_t)
link->source.distribution_mode;
if (link->target.type == PN_COORDINATOR) {
/* "DL[SIoBB?DL[SIsIoC?sCnCC]DL[C]nnI]" */
diff --git a/c/tests/fuzz/fuzz-connection-driver/crash/leak-5289430926098432-1
b/c/tests/fuzz/fuzz-connection-driver/crash/leak-5289430926098432-1
new file mode 100644
index 0000000..04ee2d4
Binary files /dev/null and
b/c/tests/fuzz/fuzz-connection-driver/crash/leak-5289430926098432-1 differ
diff --git a/c/tools/codec-generator/specs.json
b/c/tools/codec-generator/specs.json
index 15bdcdb..2775073 100644
--- a/c/tools/codec-generator/specs.json
+++ b/c/tools/codec-generator/specs.json
@@ -2,7 +2,7 @@
"fill_specs": [
"DLC",
"DL[?DL[sSC]]",
- "DL[?HIII]",
+ "DL[?HIIII]",
"DL[?IIII?I?I?In?o]",
"DL[?o?B?I?o?I]",
"DL[@T[*s]]",
@@ -25,7 +25,7 @@
"D.[.....D..D.[C]...]",
"D.[.....D..DL....]",
"D.[.....D.[.....C.C.CC]]",
- "D.[?HI]",
+ "D.[?HIII?I]",
"D.[?IIII?I?II.o]",
"D.[?S?S?I?HI..CCC]",
"D.[I?Iz.?oo.D?LRooo]",
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]