Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6202a32
F-5009: reject path traversal and absolute paths in TFTP RRQ/WRQ file…
danielinux Jun 4, 2026
227c30e
F-5481: put the ACK-triggering segment in the first SACK block
danielinux Jun 4, 2026
1ed5dc9
F-4946: guard DNS lookups against clobbering in-flight query state
danielinux Jun 4, 2026
62bdc9f
F-5070: enforce raw socket bound_local_ip and if_idx on receive
danielinux Jun 4, 2026
ae1f904
F-5696: deregister httpd callback on the lingering socket in fail_close
danielinux Jun 4, 2026
ebd7109
F-4501: drop filter-blocked packet-socket TX frames instead of resending
danielinux Jun 4, 2026
7b9e310
F-5011: deliver 802.1Q-tagged frames to parent-bound AF_PACKET sockets
danielinux Jun 4, 2026
16e20df
F-5697: never forward a packet whose source is one of our own IPs
danielinux Jun 4, 2026
b9e84e3
F-5784: strip IP options before ESP unwrap so IHL>5 ESP packets are h…
danielinux Jun 4, 2026
435a976
F-5484: document that raw sockets intentionally tap before source-rou…
danielinux Jun 4, 2026
1aa3587
F-4948: purge ARP state for a VLAN slot on delete to stop cross-VLAN …
danielinux Jun 4, 2026
129d267
F-5698: re-randomize the DHCP xid for each renewal cycle
danielinux Jun 4, 2026
71e81b8
F-5482: reject a DHCPACK that lacks the mandatory lease-time option
danielinux Jun 4, 2026
0c050fa
F-5485: null-check the public DHCP helper APIs
danielinux Jun 4, 2026
5d62a3e
F-5733: validate ECHO_REPLY destination IP before delivering to ICMP …
danielinux Jun 4, 2026
9d05b09
F-5069: defer UDP/ICMP bind src_port commit until the filter approves
danielinux Jun 4, 2026
57e8aff
F-5495: reject a NULL receive buffer in wolfIP_sock_recvfrom
danielinux Jun 4, 2026
eae67c1
F-5479: validate TCP connect local binding before mutating socket state
danielinux Jun 4, 2026
99cbd86
F-5904: validate IGMP query TTL and destination in igmp_input
danielinux Jun 4, 2026
58f791b
F-5490: make iphdr_set_checksum clear the csum field before computing
danielinux Jun 4, 2026
6e1f584
F-4949: coalesce overlapping OOO segments instead of consuming a slot…
danielinux Jun 4, 2026
bf2c625
F-5488: reject overlong TCP Timestamp options instead of accepting them
danielinux Jun 4, 2026
24d86d5
tftp: reject Windows drive specifiers and NTFS ADS in filename safety…
danielinux Jun 4, 2026
f2644e5
ci: tolerate gcov -block lines in autocov so gcovr 7.0 does not abort
danielinux Jun 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/wolfip-autocov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:

- name: Generate coverage JSON
run: |
gcovr -r . --exclude "src/test/unit/unit.c" --json -o build/coverage/coverage.json
gcovr -r . --exclude "src/test/unit/unit.c" --gcov-ignore-parse-errors=all --json -o build/coverage/coverage.json

- name: Enforce 100% function coverage for src/wolfip.c
run: |
Expand Down
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ cov: unit $(COV_UNIT)
@mkdir -p build/coverage
@gcovr -r . --exclude "src/test/unit/.*" \
--gcov-ignore-errors=no_working_dir_found \
--gcov-ignore-parse-errors=all \
--merge-mode-functions=merge-use-line-min \
--html-details -o build/coverage/index.html
@$(OPEN_CMD) build/coverage/index.html
Expand All @@ -576,6 +577,7 @@ autocov: unit $(COV_UNIT)
@mkdir -p build/coverage
@gcovr -r . --exclude "src/test/unit/.*" \
--gcov-ignore-errors=no_working_dir_found \
--gcov-ignore-parse-errors=all \
--merge-mode-functions=merge-use-line-min \
--html-details -o build/coverage/index.html

Expand All @@ -587,6 +589,7 @@ autocov-multicast: unit-multicast $(COV_MCAST_UNIT)
@mkdir -p build/coverage
@gcovr -r . --exclude "src/test/unit/.*" \
--gcov-ignore-errors=no_working_dir_found \
--gcov-ignore-parse-errors=all \
--merge-mode-functions=merge-use-line-min \
--html-details -o build/coverage/multicast.html

Expand All @@ -598,6 +601,7 @@ cov-multicast: unit-multicast $(COV_MCAST_UNIT)
@mkdir -p build/coverage
@gcovr -r . --exclude "src/test/unit/.*" \
--gcov-ignore-errors=no_working_dir_found \
--gcov-ignore-parse-errors=all \
--merge-mode-functions=merge-use-line-min \
--html-details -o build/coverage/multicast.html
@$(OPEN_CMD) build/coverage/multicast.html
Expand All @@ -620,6 +624,7 @@ cov-vlan: unit-vlan $(COV_VLAN_UNIT)
@mkdir -p build/coverage
@gcovr -r . --exclude "src/test/unit/.*" \
--gcov-ignore-errors=no_working_dir_found \
--gcov-ignore-parse-errors=all \
--merge-mode-functions=merge-use-line-min \
--html-details -o build/coverage/vlan.html
@$(OPEN_CMD) build/coverage/vlan.html
Expand All @@ -632,6 +637,7 @@ autocov-vlan: unit-vlan $(COV_VLAN_UNIT)
@mkdir -p build/coverage
@gcovr -r . --exclude "src/test/unit/.*" \
--gcov-ignore-errors=no_working_dir_found \
--gcov-ignore-parse-errors=all \
--merge-mode-functions=merge-use-line-min \
--html-details -o build/coverage/vlan.html

Expand Down
7 changes: 7 additions & 0 deletions src/http/httpd.c
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,13 @@ static void http_recv_cb(int sd, uint16_t event, void *arg) {
hc->ssl = NULL;
}
wolfIP_sock_close(hc->httpd->ipstack, sd);
/* wolfIP_sock_close on an ESTABLISHED socket only starts the active close
* (FIN_WAIT_1) and returns -EAGAIN; the socket lingers, still carrying this
* callback and its arg. Once we zero client_sd the slot is reused by the
* next accept, so the lingering socket's callback_arg would dangle onto a
* different live connection's state. Deregister it here so a late segment
* on the half-closed socket can no longer fire http_recv_cb. */
wolfIP_register_callback(hc->httpd->ipstack, sd, NULL, NULL);
hc->client_sd = 0;
}

Expand Down
23 changes: 23 additions & 0 deletions src/test/unit/unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ Suite *wolf_suite(void)
tcase_add_test(tc_utils, test_sock_recvfrom_short_addrlen);
tcase_add_test(tc_utils, test_sock_recvfrom_udp_short_addrlen);
tcase_add_test(tc_utils, test_sock_recvfrom_icmp_short_addrlen);
tcase_add_test(tc_utils, test_sock_recvfrom_null_buf_rejected);
tcase_add_test(tc_utils, test_sock_recvfrom_udp_fifo_alignment);
tcase_add_test(tc_utils, test_sock_recvfrom_tcp_close_wait_sets_readable);
tcase_add_test(tc_utils, test_sock_recvfrom_udp_readable_stays_when_queue_nonempty);
Expand Down Expand Up @@ -272,6 +273,7 @@ Suite *wolf_suite(void)
tcase_add_test(tc_utils, test_multicast_udp_send_mac_ttl_loop_and_options);
tcase_add_test(tc_utils, test_multicast_igmp_query_refreshes_report);
tcase_add_test(tc_utils, test_multicast_igmp_query_bad_checksum_dropped);
tcase_add_test(tc_utils, test_multicast_igmp_query_spoofed_dropped);
tcase_add_test(tc_utils, test_multicast_join_requires_configured_ip);
tcase_add_test(tc_utils, test_multicast_if_pins_egress_interface);
tcase_add_test(tc_utils, test_multicast_loop_does_not_fire_on_blocked_send);
Expand Down Expand Up @@ -434,6 +436,7 @@ Suite *wolf_suite(void)
tcase_add_test(tc_utils, test_udp_try_recv_full_fifo_drop_does_not_set_readable_or_send_icmp);
tcase_add_test(tc_utils, test_dns_callback_bad_flags);
tcase_add_test(tc_utils, test_dns_callback_truncated_response_aborts_query);
tcase_add_test(tc_utils, test_dns_inflight_query_state_not_clobbered_by_second_call);
tcase_add_test(tc_utils, test_regression_dns_callback_high_bit_octet_ip_no_ub);
tcase_add_test(tc_utils, test_dns_callback_bad_name);
tcase_add_test(tc_utils, test_dns_callback_short_header_ignored);
Expand Down Expand Up @@ -644,8 +647,10 @@ Suite *wolf_suite(void)
tcase_add_test(tc_utils, test_tcp_merge_sack_blocks_wrap_order);
tcase_add_test(tc_utils, test_tcp_recv_tracks_holes_and_sack_blocks);
tcase_add_test(tc_utils, test_tcp_rebuild_rx_sack_right_edge_wraps);
tcase_add_test(tc_utils, test_tcp_rebuild_rx_sack_triggering_block_first);
tcase_add_test(tc_utils, test_tcp_consume_ooo_wrap_trim_and_promote);
tcase_add_test(tc_utils, test_tcp_consume_ooo_wrap_drop_fully_acked);
tcase_add_test(tc_utils, test_tcp_store_ooo_overlap_does_not_exhaust_cache);
tcase_add_test(tc_utils, test_tcp_ack_sack_early_retransmit_before_three_dupack);
tcase_add_test(tc_utils, test_tcp_input_listen_syn_without_sack_disables_sack);
tcase_add_test(tc_utils, test_tcp_input_listen_syn_arms_control_rto);
Expand Down Expand Up @@ -773,6 +778,7 @@ Suite *wolf_suite(void)
tcase_add_test(tc_proto, test_icmp_try_recv_mismatch_remote_ip);
tcase_add_test(tc_proto, test_icmp_try_recv_full_fifo_does_not_signal_readable);
tcase_add_test(tc_proto, test_raw_socket_recv_captures_ip_header);
tcase_add_test(tc_proto, test_raw_socket_recv_honors_bound_local_ip_and_if);
tcase_add_test(tc_proto, test_raw_socket_send_hdrincl_respected);
tcase_add_test(tc_proto, test_raw_socket_send_builds_ip_header);
tcase_add_test(tc_proto, test_regression_raw_socket_send_ip_id_network_byte_order);
Expand All @@ -785,6 +791,9 @@ Suite *wolf_suite(void)
tcase_add_test(tc_proto, test_getsockopt_unsupported_option_returns_einval);
tcase_add_test(tc_proto, test_packet_socket_recv_frame);
tcase_add_test(tc_proto, test_packet_socket_send_frame);
#if WOLFIP_PACKET_SOCKETS
tcase_add_test(tc_proto, test_packet_socket_tx_filter_block_does_not_resend);
#endif
tcase_add_test(tc_proto, test_packet_socket_sendto_wrong_family_returns_einval);
tcase_add_test(tc_proto, test_packet_socket_setsockopt_rejected);
tcase_add_test(tc_proto, test_packet_socket_getsockopt_rejected);
Expand Down Expand Up @@ -844,6 +853,7 @@ Suite *wolf_suite(void)
tcase_add_test(tc_proto, test_sock_connect_selects_local_ip_multi_if);
tcase_add_test(tc_proto, test_icmp_socket_send_recv);
tcase_add_test(tc_proto, test_icmp_input_echo_reply_queues);
tcase_add_test(tc_proto, test_icmp_input_echo_reply_wrong_dst_dropped);
tcase_add_test(tc_proto, test_icmp_input_echo_request_reply_sent);
tcase_add_test(tc_proto, test_icmp_input_echo_reply_sets_df);
tcase_add_test(tc_proto, test_icmp_input_echo_request_bad_checksum_dropped);
Expand Down Expand Up @@ -918,6 +928,7 @@ Suite *wolf_suite(void)

tcase_add_test(tc_utils, test_transport_checksum);
tcase_add_test(tc_utils, test_iphdr_set_checksum);
tcase_add_test(tc_utils, test_iphdr_set_checksum_idempotent_with_stale_csum);
tcase_add_test(tc_utils, test_eth_output_add_header);
tcase_add_test(tc_utils, test_eth_output_add_header_invalid_if);
tcase_add_test(tc_utils, test_ip_output_add_header);
Expand Down Expand Up @@ -965,6 +976,8 @@ Suite *wolf_suite(void)
tcase_add_test(tc_core, test_sock_bind_icmp_basic_and_rebind);
tcase_add_test(tc_core, test_sock_bind_icmp_wrong_family);
tcase_add_test(tc_core, test_sock_bind_filter_block_rolls_back);
tcase_add_test(tc_core, test_udp_bind_src_port_deferred_until_filter_approves);
tcase_add_test(tc_core, test_icmp_bind_src_port_deferred_until_filter_approves);
tcase_add_test(tc_core, test_sendto_arg_validation);
tcase_add_test(tc_core, test_sendto_udp_short_addrlen_and_zero_dest);
tcase_add_test(tc_core, test_sendto_udp_auto_assigns_src_port);
Expand Down Expand Up @@ -1174,6 +1187,7 @@ Suite *wolf_suite(void)
tcase_add_test(tc_core, test_tcp_parse_options_nop_advances);
tcase_add_test(tc_core, test_tcp_parse_options_zero_olen_breaks);
tcase_add_test(tc_core, test_tcp_parse_options_timestamp_parsed);
tcase_add_test(tc_core, test_tcp_parse_options_timestamp_overlong_ignored);
tcase_add_test(tc_core, test_tcp_parse_options_mss_zero_ignored);
tcase_add_test(tc_core, test_tcp_parse_options_sack_permitted_parsed);
tcase_add_test(tc_core, test_tcp_input_syn_rcvd_rst_bad_seq_ignored);
Expand Down Expand Up @@ -1336,13 +1350,17 @@ Suite *wolf_suite(void)
tcase_add_test(tc_core, test_dhcp_timer_cb_bound_lease_not_expired_starts_renew);
tcase_add_test(tc_core, test_dhcp_timer_cb_default_state_noop);
tcase_add_test(tc_core, test_dhcp_timer_cb_null_arg_noop);
tcase_add_test(tc_core, test_dhcp_renew_rerandomizes_xid_rejecting_stale_ack);
tcase_add_test(tc_core, test_dhcp_parse_ack_without_lease_time_rejected);
tcase_add_test(tc_core, test_dhcp_public_apis_null_stack_safe);
/* --- unit_tests_ip_arp_recv.c (34 tests) --- */
tcase_add_test(tc_core, test_ip_recv_limited_broadcast_dst_is_local);
tcase_add_test(tc_core, test_ip_recv_directed_broadcast_dst_is_local);
tcase_add_test(tc_core, test_ip_recv_ipaddr_any_dst_is_local);
tcase_add_test(tc_core, test_ip_recv_forward_arp_hit_sends_immediately);
tcase_add_test(tc_core, test_ip_recv_forward_unconfigured_iface_skipped);
tcase_add_test(tc_core, test_ip_recv_forward_link_local_src_rpf_drop);
tcase_add_test(tc_core, test_ip_recv_forward_self_ip_src_dropped);
tcase_add_test(tc_core, test_ip_recv_options_nop_delivered);
tcase_add_test(tc_core, test_ip_recv_options_rr_stripped_and_delivered);
tcase_add_test(tc_core, test_ip_recv_options_bad_length_aborts_parse);
Expand Down Expand Up @@ -1523,6 +1541,11 @@ Suite *wolf_suite(void)
tcase_add_test(tc_proto, test_vlan_rx_dei_bit_accepted);
tcase_add_test(tc_proto, test_vlan_rx_tagged_arp_processed);
tcase_add_test(tc_proto, test_vlan_mtu_inherited);
tcase_add_test(tc_proto, test_vlan_delete_purges_arp_neighbor_cache);
#if WOLFIP_PACKET_SOCKETS
tcase_add_test(tc_proto, test_vlan_packet_socket_parent_and_sub_delivery);
tcase_add_test(tc_proto, test_vlan_packet_socket_wildcard_gets_tagged_once);
#endif
#endif /* WOLFIP_VLAN */

suite_add_tcase(s, tc_core);
Expand Down
62 changes: 62 additions & 0 deletions src/test/unit/unit_esp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1388,6 +1388,67 @@ START_TEST(test_ip_recv_esp_transport_unwrap_failure_drops_packet)
}
END_TEST

/* F-5784: an ESP packet whose outer IPv4 header carries options (IHL>5) must
* still be unwrapped and delivered. ip_recv used to dispatch ESP before the
* IP option-strip, so esp_transport_unwrap read the SPI from the option bytes,
* the SA lookup failed, and every IHL>5 ESP packet was silently dropped. */
START_TEST(test_ip_recv_esp_transport_with_ip_options_delivers_payload)
{
static uint8_t buf[LINK_MTU + 256];
struct wolfIP s;
struct wolfIP_ip_packet *ip = (struct wolfIP_ip_packet *)buf;
struct wolfIP_sockaddr_in sin;
uint8_t payload[] = { 'o', 'p', 't', '!' };
uint8_t rxbuf[sizeof(payload)] = {0};
uint32_t frame_len;
uint16_t ip_len;
uint32_t esp_payload_len;
uint8_t *opt;
int udp_sd;
int ret;

wolfIP_init(&s);
esp_setup();
esp_add_cbc_test_sas();
wolfIP_ipconfig_set(&s, atoip4(T_DST), 0xFFFFFF00U, 0);

udp_sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_UDP);
ck_assert_int_gt(udp_sd, 0);

memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = ee16(1234);
sin.sin_addr.s_addr = ee32(atoip4(T_DST));
ck_assert_int_eq(wolfIP_sock_bind(&s, udp_sd, (struct wolfIP_sockaddr *)&sin, sizeof(sin)), 0);

frame_len = build_udp_ip_packet(buf, sizeof(buf), atoip4(T_SRC), atoip4(T_DST),
4321, 1234, payload, sizeof(payload));
ip_len = (uint16_t)(frame_len - ETH_HEADER_LEN);

ret = esp_transport_wrap(ip, &ip_len);
ck_assert_int_eq(ret, 0);
frame_len = (uint32_t)ip_len + ETH_HEADER_LEN;

/* Splice a 4-byte Router-Alert option into the outer IP header so it
* becomes IHL=6, shifting the ESP header off its default offset. */
esp_payload_len = frame_len - (ETH_HEADER_LEN + IP_HEADER_LEN);
opt = buf + ETH_HEADER_LEN + IP_HEADER_LEN;
memmove(opt + 4U, opt, esp_payload_len);
opt[0] = 0x94U; opt[1] = 0x04U; opt[2] = 0x00U; opt[3] = 0x00U;
ip->ver_ihl = 0x46U;
ip->len = ee16((uint16_t)(ee16(ip->len) + 4U));
ip->csum = 0;
iphdr_set_checksum(ip);
frame_len += 4U;

ip_recv(&s, 0, ip, frame_len);

ret = wolfIP_sock_recvfrom(&s, udp_sd, rxbuf, sizeof(rxbuf), 0, NULL, NULL);
ck_assert_int_eq(ret, (int)sizeof(payload));
ck_assert_mem_eq(rxbuf, payload, sizeof(payload));
}
END_TEST

/* Mock send that captures the last frame sent.
* Used by tests that exercise the full TX path (tcp_send_empty_immediate). */
static uint8_t esp_test_last_frame[LINK_MTU];
Expand Down Expand Up @@ -1756,6 +1817,7 @@ static Suite *esp_suite(void)
tc = tcase_create("ip_recv");
tcase_add_test(tc, test_ip_recv_esp_transport_delivers_udp_payload);
tcase_add_test(tc, test_ip_recv_esp_transport_unwrap_failure_drops_packet);
tcase_add_test(tc, test_ip_recv_esp_transport_with_ip_options_delivers_payload);
suite_add_tcase(s, tc);

/* No-SA outbound path */
Expand Down
7 changes: 7 additions & 0 deletions src/test/unit/unit_shared.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ static uint16_t socket_cb_last_events;
static int timer_cb_calls;
static uint32_t dns_lookup_ip;
static int dns_lookup_calls;
static int dns_lookup_evil_calls;

struct tcp_seg_buf {
struct wolfIP_tcp_seg seg;
Expand Down Expand Up @@ -302,6 +303,12 @@ static void test_dns_lookup_cb(uint32_t ip)
dns_lookup_calls++;
}

static void test_dns_lookup_evil_cb(uint32_t ip)
{
(void)ip;
dns_lookup_evil_calls++;
}

static void test_dns_ptr_cb(const char *name)
{
(void)name;
Expand Down
8 changes: 8 additions & 0 deletions src/test/unit/unit_tests_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -1957,6 +1957,14 @@ START_TEST(test_sock_connect_tcp_bound_local_ip_no_match)
sin.sin_addr.s_addr = ee32(0x0A000002U);

ck_assert_int_eq(wolfIP_sock_connect(&s, tcp_sd, (struct wolfIP_sockaddr *)&sin, sizeof(sin)), -WOLFIP_EINVAL);
/* F-5479: a rejected connect must leave the socket CLOSED, not wedged in
* SYN_SENT. Otherwise the next connect returns a stuck EAGAIN for a SYN
* that was never queued. */
ck_assert_int_eq(ts->sock.tcp.state, TCP_CLOSED);
/* Retrying must re-validate (EINVAL again), not report a phantom in-flight
* SYN. */
ck_assert_int_eq(wolfIP_sock_connect(&s, tcp_sd, (struct wolfIP_sockaddr *)&sin, sizeof(sin)), -WOLFIP_EINVAL);
ck_assert_int_eq(ts->sock.tcp.state, TCP_CLOSED);
}
END_TEST

Expand Down
94 changes: 94 additions & 0 deletions src/test/unit/unit_tests_branches.c
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,100 @@ START_TEST(test_sock_bind_filter_block_rolls_back)
}
END_TEST

/* F-5069: the bind callback must not see a committed src_port. If src_port is
* written before WOLFIP_FILT_BINDING runs, a callback that re-enters the stack
* (wolfIP_poll) would have an ingress datagram delivered to the socket while
* the bind is still being vetted (and even if it is rejected). Capture the
* socket's src_port as visible during the callback to prove it is deferred. */
static struct wolfIP *bind_toctou_stack;
static unsigned int bind_toctou_idx;
static int bind_toctou_is_icmp;
static uint16_t bind_toctou_port_during_cb;
static int bind_toctou_capture_cb(void *arg, const struct wolfIP_filter_event *event)
{
(void)arg;
if (event && event->reason == WOLFIP_FILT_BINDING && bind_toctou_stack) {
bind_toctou_port_during_cb = bind_toctou_is_icmp ?
bind_toctou_stack->icmpsockets[bind_toctou_idx].src_port :
bind_toctou_stack->udpsockets[bind_toctou_idx].src_port;
}
return 1; /* reject the bind */
}

START_TEST(test_udp_bind_src_port_deferred_until_filter_approves)
{
struct wolfIP s;
int udp_sd;
struct tsocket *ts;
struct wolfIP_sockaddr_in sin;

wolfIP_init(&s);
mock_link_init(&s);
wolfIP_ipconfig_set(&s, 0x0A000001U, 0xFFFFFF00U, 0);
udp_sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_UDP);
ck_assert_int_gt(udp_sd, 0);
ts = &s.udpsockets[SOCKET_UNMARK(udp_sd)];

bind_toctou_stack = &s;
bind_toctou_idx = SOCKET_UNMARK(udp_sd);
bind_toctou_is_icmp = 0;
bind_toctou_port_during_cb = 0xFFFF;
wolfIP_filter_set_callback(bind_toctou_capture_cb, NULL);
wolfIP_filter_set_mask(WOLFIP_FILT_MASK(WOLFIP_FILT_BINDING));

memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = ee16(4444);
sin.sin_addr.s_addr = ee32(0x0A000001U);
ck_assert_int_eq(wolfIP_sock_bind(&s, udp_sd,
(struct wolfIP_sockaddr *)&sin, sizeof(sin)), -1);

wolfIP_filter_set_callback(NULL, NULL);
wolfIP_filter_set_mask(0);

/* The port was not committed (matchable) while the filter was deciding. */
ck_assert_uint_eq(bind_toctou_port_during_cb, 0);
/* A rejected bind leaves the socket unbound. */
ck_assert_uint_eq(ts->src_port, 0);
}
END_TEST

START_TEST(test_icmp_bind_src_port_deferred_until_filter_approves)
{
struct wolfIP s;
int icmp_sd;
struct tsocket *ts;
struct wolfIP_sockaddr_in sin;

wolfIP_init(&s);
mock_link_init(&s);
wolfIP_ipconfig_set(&s, 0x0A000001U, 0xFFFFFF00U, 0);
icmp_sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_ICMP);
ck_assert_int_gt(icmp_sd, 0);
ts = &s.icmpsockets[SOCKET_UNMARK(icmp_sd)];

bind_toctou_stack = &s;
bind_toctou_idx = SOCKET_UNMARK(icmp_sd);
bind_toctou_is_icmp = 1;
bind_toctou_port_during_cb = 0xFFFF;
wolfIP_filter_set_callback(bind_toctou_capture_cb, NULL);
wolfIP_filter_set_mask(WOLFIP_FILT_MASK(WOLFIP_FILT_BINDING));

memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = ee16(0x4321); /* ICMP echo id */
sin.sin_addr.s_addr = ee32(0x0A000001U);
ck_assert_int_eq(wolfIP_sock_bind(&s, icmp_sd,
(struct wolfIP_sockaddr *)&sin, sizeof(sin)), -1);

wolfIP_filter_set_callback(NULL, NULL);
wolfIP_filter_set_mask(0);

ck_assert_uint_eq(bind_toctou_port_during_cb, 0);
ck_assert_uint_eq(ts->src_port, 0);
}
END_TEST

/* ---- wolfIP_sock_sendto extras ---- */

START_TEST(test_sendto_arg_validation)
Expand Down
Loading
Loading