Skip to content

Commit 6792420

Browse files
committed
Addressed two fenrir comments
1 parent 39877a0 commit 6792420

3 files changed

Lines changed: 111 additions & 6 deletions

File tree

src/test/unit/unit.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ Suite *wolf_suite(void)
236236
tcase_add_test(tc_utils, test_multicast_igmp_query_refreshes_report);
237237
tcase_add_test(tc_utils, test_multicast_join_requires_configured_ip);
238238
tcase_add_test(tc_utils, test_multicast_if_pins_egress_interface);
239+
tcase_add_test(tc_utils, test_multicast_loop_does_not_fire_on_blocked_send);
240+
tcase_add_test(tc_utils, test_multicast_recv_rejects_short_frame);
239241
#endif
240242
tcase_add_test(tc_utils, test_tcp_no_rst_for_broadcast_dst);
241243
tcase_add_test(tc_utils, test_tcp_no_rst_for_multicast_dst);

src/test/unit/unit_tests_multicast.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,4 +378,97 @@ START_TEST(test_multicast_if_pins_egress_interface)
378378
}
379379
END_TEST
380380

381+
START_TEST(test_multicast_loop_does_not_fire_on_blocked_send)
382+
{
383+
struct wolfIP s;
384+
int sd;
385+
struct wolfIP_sockaddr_in bind_addr;
386+
struct wolfIP_sockaddr_in dst;
387+
struct wolfIP_ip_mreq mreq;
388+
uint8_t out[8];
389+
int loop = 1;
390+
ip4 group = 0xE9010208U;
391+
const char payload[] = "xy";
392+
393+
wolfIP_init(&s);
394+
mock_link_init(&s);
395+
wolfIP_ipconfig_set(&s, 0x0A000002U, 0xFFFFFF00U, 0);
396+
sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_UDP);
397+
ck_assert_int_gt(sd, 0);
398+
memset(&bind_addr, 0, sizeof(bind_addr));
399+
bind_addr.sin_family = AF_INET;
400+
bind_addr.sin_port = ee16(5003);
401+
ck_assert_int_eq(wolfIP_sock_bind(&s, sd,
402+
(struct wolfIP_sockaddr *)&bind_addr, sizeof(bind_addr)), 0);
403+
404+
multicast_mreq(&mreq, group, IPADDR_ANY);
405+
ck_assert_int_eq(wolfIP_sock_setsockopt(&s, sd, WOLFIP_SOL_IP,
406+
WOLFIP_IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)), 0);
407+
ck_assert_int_eq(wolfIP_sock_setsockopt(&s, sd, WOLFIP_SOL_IP,
408+
WOLFIP_IP_MULTICAST_LOOP, &loop, sizeof(loop)), 0);
409+
410+
/* Block the egress UDP path. With the pre-fix code the mcast_loop
411+
* udp_try_recv() ran before the filter, so the local RX queue got one
412+
* copy per poll even though the frame was never transmitted; with the
413+
* fix, a blocked send must not deliver a loopback copy. */
414+
filter_block_reason = WOLFIP_FILT_SENDING;
415+
wolfIP_filter_set_callback(test_filter_cb_block, NULL);
416+
wolfIP_filter_set_udp_mask(WOLFIP_FILT_MASK(WOLFIP_FILT_SENDING));
417+
418+
memset(&dst, 0, sizeof(dst));
419+
dst.sin_family = AF_INET;
420+
dst.sin_port = ee16(5003);
421+
dst.sin_addr.s_addr = ee32(group);
422+
last_frame_sent_size = 0;
423+
ck_assert_int_eq(wolfIP_sock_sendto(&s, sd, payload, sizeof(payload), 0,
424+
(struct wolfIP_sockaddr *)&dst, sizeof(dst)),
425+
(int)sizeof(payload));
426+
427+
/* Poll twice: with the pre-fix code the descriptor sticks in the txbuf
428+
* and each poll re-loops the datagram, so recvfrom would return it. */
429+
(void)wolfIP_poll(&s, 1);
430+
(void)wolfIP_poll(&s, 2);
431+
ck_assert_uint_eq(last_frame_sent_size, 0U);
432+
ck_assert_int_eq(wolfIP_sock_recvfrom(&s, sd, out, sizeof(out), 0, NULL,
433+
NULL), -WOLFIP_EAGAIN);
434+
435+
/* Clearing the filter lets the next poll send and loop exactly once. */
436+
wolfIP_filter_set_callback(NULL, NULL);
437+
wolfIP_filter_set_udp_mask(0);
438+
(void)wolfIP_poll(&s, 3);
439+
ck_assert_uint_gt(last_frame_sent_size, 0U);
440+
ck_assert_int_eq(wolfIP_sock_recvfrom(&s, sd, out, sizeof(out), 0, NULL,
441+
NULL), (int)sizeof(payload));
442+
/* Only one loopback copy — no leftover. */
443+
ck_assert_int_eq(wolfIP_sock_recvfrom(&s, sd, out, sizeof(out), 0, NULL,
444+
NULL), -WOLFIP_EAGAIN);
445+
}
446+
END_TEST
447+
448+
START_TEST(test_multicast_recv_rejects_short_frame)
449+
{
450+
struct wolfIP s;
451+
uint8_t frame[ETH_HEADER_LEN];
452+
453+
wolfIP_init(&s);
454+
mock_link_init(&s);
455+
wolfIP_ipconfig_set(&s, 0x0A000002U, 0xFFFFFF00U, 0);
456+
457+
/* Build a 14-byte frame (Ethernet header only) with a multicast-looking
458+
* destination MAC and ETH_TYPE_IP. Without the length guard,
459+
* wolfIP_recv_on would read ip->dst at offsets 30-33 — well past the
460+
* end of the buffer. Under ASAN this is a heap-buffer-overflow. */
461+
memset(frame, 0, sizeof(frame));
462+
memcpy(frame + 0, "\x01\x00\x5e\x01\x02\x08", 6);
463+
memcpy(frame + 6, "\x02\x00\x00\x00\x00\x01", 6);
464+
frame[12] = (ETH_TYPE_IP >> 8) & 0xff;
465+
frame[13] = ETH_TYPE_IP & 0xff;
466+
467+
last_frame_sent_size = 0;
468+
wolfIP_recv_ex(&s, TEST_PRIMARY_IF, frame, sizeof(frame));
469+
/* Silently dropped, no response sent. */
470+
ck_assert_uint_eq(last_frame_sent_size, 0U);
471+
}
472+
END_TEST
473+
381474
#endif /* IP_MULTICAST */

src/wolfip.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8423,7 +8423,12 @@ static void wolfIP_recv_on(struct wolfIP *s, unsigned int if_idx, void *buf, uin
84238423
if ((memcmp(eth->dst, ll->mac, 6) != 0) &&
84248424
(memcmp(eth->dst, "\xff\xff\xff\xff\xff\xff", 6) != 0)) {
84258425
#ifdef IP_MULTICAST
8426-
ip4 dst_ip = ee32(ip->dst);
8426+
ip4 dst_ip;
8427+
/* Guard the read of ip->dst (bytes 30-33) against short frames
8428+
* from drivers that don't pad to 60 bytes. */
8429+
if (len < (uint32_t)(ETH_HEADER_LEN + IP_HEADER_LEN))
8430+
return;
8431+
dst_ip = ee32(ip->dst);
84278432
if (!eth_is_ipv4_multicast_mac(eth->dst) ||
84288433
!wolfIP_ip_is_multicast(dst_ip) ||
84298434
(!mcast_is_joined(s, if_idx, dst_ip) &&
@@ -9235,11 +9240,6 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now)
92359240
#endif
92369241
len = desc->len - ETH_HEADER_LEN;
92379242
ip_output_add_header(t, (struct wolfIP_ip_packet *)udp, WI_IPPROTO_UDP, len);
9238-
#ifdef IP_MULTICAST
9239-
if (wolfIP_ip_is_multicast(t->remote_ip) && t->sock.udp.mcast_loop) {
9240-
udp_try_recv(s, tx_if, udp, desc->len);
9241-
}
9242-
#endif
92439243
if (wolfIP_filter_notify_udp(WOLFIP_FILT_SENDING, t->S, tx_if, udp, desc->len) != 0)
92449244
break;
92459245
if (wolfIP_filter_notify_ip(WOLFIP_FILT_SENDING, t->S, tx_if, &udp->ip, desc->len) != 0)
@@ -9273,6 +9273,16 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now)
92739273
break;
92749274
if (send_ret < 0)
92759275
break;
9276+
#ifdef IP_MULTICAST
9277+
/* Loopback only after a successful wire send. Running udp_try_recv
9278+
* before the filter/send path caused repeated local deliveries
9279+
* when a SENDING filter blocked the frame or the driver returned
9280+
* -EAGAIN: the descriptor stays in the txbuf and every subsequent
9281+
* wolfIP_poll() re-enters the loop and re-loops the datagram. */
9282+
if (wolfIP_ip_is_multicast(t->remote_ip) && t->sock.udp.mcast_loop) {
9283+
udp_try_recv(s, tx_if, udp, desc->len);
9284+
}
9285+
#endif
92769286
fifo_pop(&t->sock.udp.txbuf);
92779287
desc = fifo_peek(&t->sock.udp.txbuf);
92789288
}

0 commit comments

Comments
 (0)