Skip to content

Commit 8147b62

Browse files
committed
DISPATCH-2307: prevent router failure if id is greater than 64 bytes
fixes: - buffer overflow in iterator library - incorrect fanout value for locally destined messages This closes #1478
1 parent 759aa17 commit 8147b62

File tree

10 files changed

+124
-28
lines changed

10 files changed

+124
-28
lines changed

include/qpid/dispatch/iterator.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,12 @@ typedef struct {
139139
* @{
140140
*/
141141

142+
/**
143+
* Clean up any internal state in the iterator library. This must be called at
144+
* shutdown after all iterators have been released.
145+
*/
146+
void qd_iterator_finalize(void);
147+
142148
/**
143149
* Set the area and router names for the local router. These are used to match
144150
* my-area and my-router in address fields. These settings are global and used

include/qpid/dispatch/message.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -547,12 +547,10 @@ void qd_message_set_tag_sent(qd_message_t *msg, bool tag_sent);
547547
/**
548548
* Increase the fanout of the message by 1.
549549
*
550-
* @param in_msg A pointer to the inbound message.
551-
* @param out_msg A pointer to the outbound message or 0 if forwarding to a
552-
* local subscriber.
550+
* @param out_msg A pointer to the message to be sent outbound or to a local
551+
* subscriber.
553552
*/
554-
void qd_message_add_fanout(qd_message_t *in_msg,
555-
qd_message_t *out_msg);
553+
void qd_message_add_fanout(qd_message_t *out_msg);
556554

557555
/**
558556
* Disable the Q2-holdoff for this message.

src/dispatch.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ void qd_dispatch_free(qd_dispatch_t *qd)
379379
qd_python_finalize();
380380
qd_dispatch_set_router_id(qd, NULL);
381381
qd_dispatch_set_router_area(qd, NULL);
382+
qd_iterator_finalize();
382383
free(qd->timestamp_format);
383384
free(qd->metadata);
384385

src/iterator.c

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ typedef enum {
8484

8585

8686
static bool edge_mode = false;
87-
static char *my_area = "";
88-
static char *my_router = "";
87+
static char *my_area = 0;
88+
static char *my_router = 0;
8989

9090
static const char *SEPARATORS = "./";
9191

@@ -156,6 +156,7 @@ static void parse_address_view(qd_iterator_t *iter)
156156
}
157157

158158
if (qd_iterator_prefix(iter, "topo/")) {
159+
assert(my_area && my_router); // ensure qd_iterator_set_address called!
159160
if (qd_iterator_prefix(iter, "all/") || qd_iterator_prefix(iter, my_area)) {
160161
if (qd_iterator_prefix(iter, "all/")) {
161162
iter->prefix = QD_ITER_HASH_PREFIX_TOPOLOGICAL;
@@ -567,19 +568,18 @@ static void qd_iterator_free_hash_segments(qd_iterator_t *iter)
567568

568569
void qd_iterator_set_address(bool _edge_mode, const char *area, const char *router)
569570
{
570-
static char buf[64];
571-
static char *ptr = buf;
572-
size_t area_size = strlen(area);
573-
size_t router_size = strlen(router);
571+
const size_t area_size = strlen(area);
572+
const size_t router_size = strlen(router);
574573

575-
if (area_size + router_size + 1 >= sizeof(buf))
576-
ptr = (char*) malloc(area_size + router_size + 2);
574+
edge_mode = _edge_mode;
577575

578-
sprintf(ptr, "%s/%c%s/", area, '\0', router);
576+
free(my_area);
577+
my_area = qd_malloc(area_size + 2); // include trailing '\'
578+
sprintf(my_area, "%s/", area);
579579

580-
edge_mode = _edge_mode;
581-
my_area = ptr;
582-
my_router = ptr + area_size + 2;
580+
free(my_router);
581+
my_router = qd_malloc(router_size + 2);
582+
sprintf(my_router, "%s/", router);
583583
}
584584

585585

@@ -1143,3 +1143,14 @@ void qd_iterator_get_view_cursor(
11431143
ptr->cursor = iter->view_pointer.cursor;
11441144
ptr->remaining = iter->view_pointer.remaining;
11451145
}
1146+
1147+
1148+
void qd_iterator_finalize(void)
1149+
{
1150+
free(my_area);
1151+
free(my_router);
1152+
1153+
// unit tests need these zeroed
1154+
my_area = 0;
1155+
my_router = 0;
1156+
}

src/message.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,12 +1274,9 @@ void qd_message_set_discard(qd_message_t *msg, bool discard)
12741274

12751275
// update the buffer reference counts for a new outgoing message
12761276
//
1277-
void qd_message_add_fanout(qd_message_t *in_msg,
1278-
qd_message_t *out_msg)
1277+
void qd_message_add_fanout(qd_message_t *out_msg)
12791278
{
1280-
if (!out_msg)
1281-
return;
1282-
1279+
assert(out_msg);
12831280
qd_message_pvt_t *msg = (qd_message_pvt_t *)out_msg;
12841281
msg->is_fanout = true;
12851282

src/router_core/forwarder.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ qdr_delivery_t *qdr_forward_new_delivery_CT(qdr_core_t *core, qdr_delivery_t *in
180180
//
181181
// Add one to the message fanout. This will later be used in the qd_message_send function that sends out messages.
182182
//
183-
qd_message_add_fanout(msg, out_dlv->msg);
183+
qd_message_add_fanout(out_dlv->msg);
184184

185185
//
186186
// Create peer linkage if the outgoing delivery is unsettled. This peer linkage is necessary to deal with dispositions that show up in the future.
@@ -439,7 +439,7 @@ static inline bool qdr_forward_edge_echo_CT(qdr_delivery_t *in_dlv, qdr_link_t *
439439
*/
440440
static void qdr_forward_to_subscriber_CT(qdr_core_t *core, qdr_subscription_t *sub, qdr_delivery_t *in_dlv, qd_message_t *in_msg, bool receive_complete)
441441
{
442-
qd_message_add_fanout(in_msg, 0);
442+
qd_message_add_fanout(in_msg);
443443

444444
//
445445
// Only if the message has been completely received, forward it to the subscription.

tests/c_unittests/helpers.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ class QDRMinimalEnv
305305
qd_log_finalize();
306306
qd_alloc_finalize();
307307
qd_entity_cache_free_entries();
308+
qd_iterator_finalize();
308309
}
309310
};
310311

tests/message_test.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,9 +1167,9 @@ static char *test_check_stream_data_fanout(void *context)
11671167

11681168
// "fan out" the message
11691169
out_msg1 = qd_message_copy(in_msg);
1170-
qd_message_add_fanout(in_msg, out_msg1);
1170+
qd_message_add_fanout(out_msg1);
11711171
out_msg2 = qd_message_copy(in_msg);
1172-
qd_message_add_fanout(in_msg, out_msg2);
1172+
qd_message_add_fanout(out_msg2);
11731173

11741174
// walk the data streams for both messages:
11751175
qd_message_stream_data_t *out_sd1[sd_count] = {0};
@@ -1291,9 +1291,9 @@ static char *test_check_stream_data_footer(void *context)
12911291

12921292
// "fan out" the message
12931293
out_msg1 = qd_message_copy(in_msg);
1294-
qd_message_add_fanout(in_msg, out_msg1);
1294+
qd_message_add_fanout(out_msg1);
12951295
out_msg2 = qd_message_copy(in_msg);
1296-
qd_message_add_fanout(in_msg, out_msg2);
1296+
qd_message_add_fanout(out_msg2);
12971297

12981298
qd_message_stream_data_t *stream_data = 0;
12991299
bool done = false;

tests/run_unit_tests_size.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "qpid/dispatch/alloc.h"
2121
#include "qpid/dispatch/buffer.h"
22+
#include "qpid/dispatch/iterator.h"
2223

2324
void qd_log_initialize(void);
2425
void qd_log_finalize(void);
@@ -52,6 +53,7 @@ int main(int argc, char** argv)
5253

5354
qd_log_finalize();
5455
qd_alloc_finalize();
56+
qd_iterator_finalize();
5557
return result;
5658
}
5759

tests/system_tests_routing_protocol.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,5 +204,85 @@ def run(self):
204204
Container(self).run()
205205

206206

207+
class HugeRouterIdTest(TestCase):
208+
"""
209+
Ensure long router identifiers are advertized properly.
210+
211+
Deploy a mesh of four routers with ids > 64 octets in length.
212+
"""
213+
@classmethod
214+
def setUpClass(cls):
215+
super(HugeRouterIdTest, cls).setUpClass()
216+
217+
def router(name, extra_config):
218+
219+
config = [
220+
('router', {'mode': 'interior', 'id': name}),
221+
('listener', {'port': cls.tester.get_port()})
222+
] + extra_config
223+
224+
config = Qdrouterd.Config(config)
225+
226+
r = cls.tester.qdrouterd(name[:32], config, wait=False)
227+
cls.routers.append(r)
228+
return r
229+
230+
cls.routers = []
231+
232+
ir_port_A = cls.tester.get_port()
233+
ir_port_B = cls.tester.get_port()
234+
ir_port_C = cls.tester.get_port()
235+
ir_port_D = cls.tester.get_port()
236+
237+
name_suffix = "." + "X" * 128
238+
239+
cls.RA_name = 'A' + name_suffix
240+
cls.RA = router(cls.RA_name,
241+
[('listener', {'role': 'inter-router', 'port': ir_port_A}),
242+
('connector', {'role': 'inter-router', 'port': ir_port_B}),
243+
('connector', {'role': 'inter-router', 'port': ir_port_C}),
244+
('connector', {'role': 'inter-router', 'port': ir_port_D})])
245+
246+
cls.RB_name = 'B' + name_suffix
247+
cls.RB = router(cls.RB_name,
248+
[('listener', {'role': 'inter-router', 'port': ir_port_B}),
249+
('connector', {'role': 'inter-router', 'port': ir_port_C}),
250+
('connector', {'role': 'inter-router', 'port': ir_port_D})])
251+
252+
cls.RC_name = 'C' + name_suffix
253+
cls.RC = router(cls.RC_name,
254+
[('listener', {'role': 'inter-router', 'port': ir_port_C}),
255+
('connector', {'role': 'inter-router', 'port': ir_port_D})])
256+
257+
cls.RD_name = 'D' + name_suffix
258+
cls.RD = router(cls.RD_name,
259+
[('listener', {'role': 'inter-router', 'port': ir_port_D})])
260+
261+
cls.RA.wait_ports()
262+
cls.RB.wait_ports()
263+
cls.RC.wait_ports()
264+
cls.RD.wait_ports()
265+
266+
def test_01_wait_for_routers(self):
267+
"""
268+
Wait until all the router in the mesh can see each other
269+
"""
270+
self.RA.wait_router_connected(self.RB_name)
271+
self.RA.wait_router_connected(self.RC_name)
272+
self.RA.wait_router_connected(self.RD_name)
273+
274+
self.RB.wait_router_connected(self.RA_name)
275+
self.RB.wait_router_connected(self.RC_name)
276+
self.RB.wait_router_connected(self.RD_name)
277+
278+
self.RC.wait_router_connected(self.RA_name)
279+
self.RC.wait_router_connected(self.RB_name)
280+
self.RC.wait_router_connected(self.RD_name)
281+
282+
self.RD.wait_router_connected(self.RA_name)
283+
self.RD.wait_router_connected(self.RB_name)
284+
self.RD.wait_router_connected(self.RC_name)
285+
286+
207287
if __name__ == '__main__':
208288
unittest.main(main_module())

0 commit comments

Comments
 (0)