From 3f3cceb6b6e0e45a42a2b2fe4a6f2f31f6d766b7 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Mon, 9 Feb 2026 10:05:32 +0100 Subject: [PATCH 1/5] UT to confirm remote_ip not being set in UDP recvfrom --- src/test/unit/unit.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/test/unit/unit.c b/src/test/unit/unit.c index b15825e..fadd275 100644 --- a/src/test/unit/unit.c +++ b/src/test/unit/unit.c @@ -1039,6 +1039,52 @@ START_TEST(test_udp_sendto_and_recvfrom) } END_TEST +START_TEST(test_udp_recvfrom_sets_remote_ip) +{ + struct wolfIP s; + int sd; + struct wolfIP_sockaddr_in sin; + uint8_t payload[4] = {0xAA, 0xBB, 0xCC, 0xDD}; + uint8_t rxbuf[4] = {0}; + struct wolfIP_sockaddr_in from; + socklen_t from_len = sizeof(from); + int ret; + ip4 local_ip = 0x0A000001U; + ip4 remote_ip = 0x0A000002U; + uint16_t local_port = 4001; + uint16_t remote_port = 5001; + struct tsocket *ts; + + wolfIP_init(&s); + mock_link_init(&s); + wolfIP_ipconfig_set(&s, local_ip, 0xFFFFFF00U, 0); + + sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_UDP); + ck_assert_int_gt(sd, 0); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = ee16(local_port); + sin.sin_addr.s_addr = ee32(local_ip); + ret = wolfIP_sock_bind(&s, sd, (struct wolfIP_sockaddr *)&sin, sizeof(sin)); + ck_assert_int_eq(ret, 0); + + ts = &s.udpsockets[SOCKET_UNMARK(sd)]; + ck_assert_uint_eq(ts->remote_ip, 0); + + inject_udp_datagram(&s, TEST_PRIMARY_IF, remote_ip, local_ip, remote_port, local_port, + payload, sizeof(payload)); + + memset(&from, 0, sizeof(from)); + ret = wolfIP_sock_recvfrom(&s, sd, rxbuf, sizeof(rxbuf), 0, + (struct wolfIP_sockaddr *)&from, &from_len); + ck_assert_int_eq(ret, (int)sizeof(payload)); + ck_assert_mem_eq(rxbuf, payload, sizeof(payload)); + ck_assert_uint_eq(from.sin_addr.s_addr, ee32(remote_ip)); + ck_assert_uint_eq(ts->remote_ip, remote_ip); +} +END_TEST + START_TEST(test_sock_error_paths) { struct wolfIP s; @@ -12082,6 +12128,8 @@ Suite *wolf_suite(void) suite_add_tcase(s, tc_proto); tcase_add_test(tc_proto, test_udp_sendto_and_recvfrom); suite_add_tcase(s, tc_proto); + tcase_add_test(tc_proto, test_udp_recvfrom_sets_remote_ip); + suite_add_tcase(s, tc_proto); tcase_add_test(tc_proto, test_dns_query_and_callback_a); suite_add_tcase(s, tc_proto); tcase_add_test(tc_proto, test_dhcp_parse_offer_and_ack); From 51f67b1537df799944d99a54c4f88572eeb2ccc0 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Mon, 9 Feb 2026 10:20:40 +0100 Subject: [PATCH 2/5] Fix: setting ts->remote_ip in wolf_sock_recvfrom() --- src/wolfip.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/wolfip.c b/src/wolfip.c index f9d64a5..2092ea5 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -2647,6 +2647,8 @@ int wolfIP_sock_recvfrom(struct wolfIP *s, int sockfd, void *buf, size_t len, in if (SOCKET_UNMARK(sockfd) >= MAX_UDPSOCKETS) return -WOLFIP_EINVAL; ts = &s->udpsockets[SOCKET_UNMARK(sockfd)]; + if (sin && !addrlen) + return -1; if (sin && *addrlen < sizeof(struct wolfIP_sockaddr_in)) return -1; if (addrlen) *addrlen = sizeof(struct wolfIP_sockaddr_in); @@ -2654,10 +2656,12 @@ int wolfIP_sock_recvfrom(struct wolfIP *s, int sockfd, void *buf, size_t len, in return -WOLFIP_EAGAIN; desc = fifo_peek(&ts->sock.udp.rxbuf); udp = (struct wolfIP_udp_datagram *)(ts->rxmem + desc->pos + sizeof(*desc)); + if (ts->remote_ip == 0) + ts->remote_ip = ee32(udp->ip.src); if (sin) { sin->sin_family = AF_INET; sin->sin_port = ee16(udp->src_port); - sin->sin_addr.s_addr = ee32(ts->remote_ip); + sin->sin_addr.s_addr = udp->ip.src; } seg_len = ee16(udp->len) - UDP_HEADER_LEN; if (seg_len > len) From 19a244b537cae96aa866a528ddb601d4fa6e1e67 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Mon, 9 Feb 2026 10:24:56 +0100 Subject: [PATCH 3/5] wolfIP_sock_recvfrom: added more corner-cases UT --- src/test/unit/unit.c | 127 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/src/test/unit/unit.c b/src/test/unit/unit.c index fadd275..c4ab1ee 100644 --- a/src/test/unit/unit.c +++ b/src/test/unit/unit.c @@ -1085,6 +1085,127 @@ START_TEST(test_udp_recvfrom_sets_remote_ip) } END_TEST +START_TEST(test_udp_recvfrom_null_src_addr_len) +{ + struct wolfIP s; + int sd; + struct wolfIP_sockaddr_in sin; + uint8_t payload[4] = {0x11, 0x22, 0x33, 0x44}; + uint8_t rxbuf[4] = {0}; + int ret; + ip4 local_ip = 0x0A000001U; + ip4 remote_ip = 0x0A000002U; + uint16_t local_port = 4002; + uint16_t remote_port = 5002; + + wolfIP_init(&s); + mock_link_init(&s); + wolfIP_ipconfig_set(&s, local_ip, 0xFFFFFF00U, 0); + + sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_UDP); + ck_assert_int_gt(sd, 0); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = ee16(local_port); + sin.sin_addr.s_addr = ee32(local_ip); + ret = wolfIP_sock_bind(&s, sd, (struct wolfIP_sockaddr *)&sin, sizeof(sin)); + ck_assert_int_eq(ret, 0); + + inject_udp_datagram(&s, TEST_PRIMARY_IF, remote_ip, local_ip, remote_port, local_port, + payload, sizeof(payload)); + + ret = wolfIP_sock_recvfrom(&s, 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 + +START_TEST(test_udp_recvfrom_preserves_remote_ip) +{ + struct wolfIP s; + int sd; + struct wolfIP_sockaddr_in sin; + uint8_t payload[4] = {0x55, 0x66, 0x77, 0x88}; + uint8_t rxbuf[4] = {0}; + struct wolfIP_sockaddr_in from; + socklen_t from_len = sizeof(from); + int ret; + ip4 local_ip = 0x0A000001U; + ip4 remote_ip = 0x0A000002U; + ip4 preset_remote_ip = 0x0A000099U; + uint16_t local_port = 4003; + uint16_t remote_port = 5003; + struct tsocket *ts; + + wolfIP_init(&s); + mock_link_init(&s); + wolfIP_ipconfig_set(&s, local_ip, 0xFFFFFF00U, 0); + + sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_UDP); + ck_assert_int_gt(sd, 0); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = ee16(local_port); + sin.sin_addr.s_addr = ee32(local_ip); + ret = wolfIP_sock_bind(&s, sd, (struct wolfIP_sockaddr *)&sin, sizeof(sin)); + ck_assert_int_eq(ret, 0); + + ts = &s.udpsockets[SOCKET_UNMARK(sd)]; + ts->remote_ip = preset_remote_ip; + + inject_udp_datagram(&s, TEST_PRIMARY_IF, remote_ip, local_ip, remote_port, local_port, + payload, sizeof(payload)); + + memset(&from, 0, sizeof(from)); + ret = wolfIP_sock_recvfrom(&s, sd, rxbuf, sizeof(rxbuf), 0, + (struct wolfIP_sockaddr *)&from, &from_len); + ck_assert_int_eq(ret, (int)sizeof(payload)); + ck_assert_mem_eq(rxbuf, payload, sizeof(payload)); + ck_assert_uint_eq(from.sin_addr.s_addr, ee32(remote_ip)); + ck_assert_uint_eq(ts->remote_ip, preset_remote_ip); +} +END_TEST + +START_TEST(test_udp_recvfrom_null_addrlen) +{ + struct wolfIP s; + int sd; + struct wolfIP_sockaddr_in sin; + uint8_t payload[4] = {0x9A, 0xBC, 0xDE, 0xF0}; + uint8_t rxbuf[4] = {0}; + struct wolfIP_sockaddr_in from; + int ret; + ip4 local_ip = 0x0A000001U; + ip4 remote_ip = 0x0A000002U; + uint16_t local_port = 4004; + uint16_t remote_port = 5004; + + wolfIP_init(&s); + mock_link_init(&s); + wolfIP_ipconfig_set(&s, local_ip, 0xFFFFFF00U, 0); + + sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_UDP); + ck_assert_int_gt(sd, 0); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = ee16(local_port); + sin.sin_addr.s_addr = ee32(local_ip); + ret = wolfIP_sock_bind(&s, sd, (struct wolfIP_sockaddr *)&sin, sizeof(sin)); + ck_assert_int_eq(ret, 0); + + inject_udp_datagram(&s, TEST_PRIMARY_IF, remote_ip, local_ip, remote_port, local_port, + payload, sizeof(payload)); + + memset(&from, 0, sizeof(from)); + ret = wolfIP_sock_recvfrom(&s, sd, rxbuf, sizeof(rxbuf), 0, + (struct wolfIP_sockaddr *)&from, NULL); + ck_assert_int_eq(ret, -1); +} +END_TEST + START_TEST(test_sock_error_paths) { struct wolfIP s; @@ -12130,6 +12251,12 @@ Suite *wolf_suite(void) suite_add_tcase(s, tc_proto); tcase_add_test(tc_proto, test_udp_recvfrom_sets_remote_ip); suite_add_tcase(s, tc_proto); + tcase_add_test(tc_proto, test_udp_recvfrom_null_src_addr_len); + suite_add_tcase(s, tc_proto); + tcase_add_test(tc_proto, test_udp_recvfrom_preserves_remote_ip); + suite_add_tcase(s, tc_proto); + tcase_add_test(tc_proto, test_udp_recvfrom_null_addrlen); + suite_add_tcase(s, tc_proto); tcase_add_test(tc_proto, test_dns_query_and_callback_a); suite_add_tcase(s, tc_proto); tcase_add_test(tc_proto, test_dhcp_parse_offer_and_ack); From 5abd3a8411cb8c43ea05ca24cac78dd2e52994b7 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Mon, 9 Feb 2026 10:54:04 +0100 Subject: [PATCH 4/5] Implemented hardening against spoofed local-ip packets As suggested by copilot --- src/test/unit/unit.c | 47 ++++++++++++++++++++++++++++++++++++++++++++ src/wolfip.c | 7 +++++-- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/test/unit/unit.c b/src/test/unit/unit.c index c4ab1ee..de3431b 100644 --- a/src/test/unit/unit.c +++ b/src/test/unit/unit.c @@ -1206,6 +1206,51 @@ START_TEST(test_udp_recvfrom_null_addrlen) } END_TEST +START_TEST(test_udp_recvfrom_src_equals_local_ip_does_not_persist_remote) +{ + struct wolfIP s; + int sd; + struct wolfIP_sockaddr_in sin; + uint8_t payload[4] = {0x01, 0x02, 0x03, 0x04}; + uint8_t rxbuf[4] = {0}; + struct wolfIP_sockaddr_in from; + socklen_t from_len = sizeof(from); + int ret; + ip4 local_ip = 0x0A000001U; + uint16_t local_port = 4005; + uint16_t remote_port = 5005; + struct tsocket *ts; + + wolfIP_init(&s); + mock_link_init(&s); + wolfIP_ipconfig_set(&s, local_ip, 0xFFFFFF00U, 0); + + sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_UDP); + ck_assert_int_gt(sd, 0); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = ee16(local_port); + sin.sin_addr.s_addr = ee32(local_ip); + ret = wolfIP_sock_bind(&s, sd, (struct wolfIP_sockaddr *)&sin, sizeof(sin)); + ck_assert_int_eq(ret, 0); + + ts = &s.udpsockets[SOCKET_UNMARK(sd)]; + ck_assert_uint_eq(ts->remote_ip, 0); + + inject_udp_datagram(&s, TEST_PRIMARY_IF, local_ip, local_ip, remote_port, local_port, + payload, sizeof(payload)); + + memset(&from, 0, sizeof(from)); + ret = wolfIP_sock_recvfrom(&s, sd, rxbuf, sizeof(rxbuf), 0, + (struct wolfIP_sockaddr *)&from, &from_len); + ck_assert_int_eq(ret, (int)sizeof(payload)); + ck_assert_mem_eq(rxbuf, payload, sizeof(payload)); + ck_assert_uint_eq(from.sin_addr.s_addr, ee32(local_ip)); + ck_assert_uint_eq(ts->remote_ip, 0); +} +END_TEST + START_TEST(test_sock_error_paths) { struct wolfIP s; @@ -12257,6 +12302,8 @@ Suite *wolf_suite(void) suite_add_tcase(s, tc_proto); tcase_add_test(tc_proto, test_udp_recvfrom_null_addrlen); suite_add_tcase(s, tc_proto); + tcase_add_test(tc_proto, test_udp_recvfrom_src_equals_local_ip_does_not_persist_remote); + suite_add_tcase(s, tc_proto); tcase_add_test(tc_proto, test_dns_query_and_callback_a); suite_add_tcase(s, tc_proto); tcase_add_test(tc_proto, test_dhcp_parse_offer_and_ack); diff --git a/src/wolfip.c b/src/wolfip.c index 2092ea5..6a2d73c 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -2656,8 +2656,11 @@ int wolfIP_sock_recvfrom(struct wolfIP *s, int sockfd, void *buf, size_t len, in return -WOLFIP_EAGAIN; desc = fifo_peek(&ts->sock.udp.rxbuf); udp = (struct wolfIP_udp_datagram *)(ts->rxmem + desc->pos + sizeof(*desc)); - if (ts->remote_ip == 0) - ts->remote_ip = ee32(udp->ip.src); + if (ts->remote_ip == 0) { + ip4 src_ip = ee32(udp->ip.src); + if (src_ip != ts->local_ip) + ts->remote_ip = src_ip; + } if (sin) { sin->sin_family = AF_INET; sin->sin_port = ee16(udp->src_port); From a7db6935dd8ae86562e8524429170fce821e4cfd Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Mon, 9 Feb 2026 11:10:51 +0100 Subject: [PATCH 5/5] Addressed copilot comments: - return the remote port in network order - return the correct error code in woldIP_sock_recvfrom() - fixed test cases --- src/test/unit/unit.c | 12 ++++++------ src/wolfip.c | 10 ++++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/test/unit/unit.c b/src/test/unit/unit.c index de3431b..ec4342b 100644 --- a/src/test/unit/unit.c +++ b/src/test/unit/unit.c @@ -1035,7 +1035,7 @@ START_TEST(test_udp_sendto_and_recvfrom) (struct wolfIP_sockaddr *)&from, &from_len); ck_assert_int_eq(ret, (int)sizeof(payload)); ck_assert_mem_eq(rxbuf, payload, sizeof(payload)); - ck_assert_uint_eq(from.sin_port, remote_port); + ck_assert_uint_eq(from.sin_port, ee16(remote_port)); } END_TEST @@ -1202,7 +1202,7 @@ START_TEST(test_udp_recvfrom_null_addrlen) memset(&from, 0, sizeof(from)); ret = wolfIP_sock_recvfrom(&s, sd, rxbuf, sizeof(rxbuf), 0, (struct wolfIP_sockaddr *)&from, NULL); - ck_assert_int_eq(ret, -1); + ck_assert_int_eq(ret, -WOLFIP_EINVAL); } END_TEST @@ -1661,13 +1661,13 @@ START_TEST(test_sock_recvfrom_short_addrlen) ck_assert_int_gt(udp_sd, 0); alen = (socklen_t)1; ck_assert_int_eq(wolfIP_sock_recvfrom(&s, udp_sd, buf, sizeof(buf), 0, - (struct wolfIP_sockaddr *)&sin, &alen), -1); + (struct wolfIP_sockaddr *)&sin, &alen), -WOLFIP_EINVAL); icmp_sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_ICMP); ck_assert_int_gt(icmp_sd, 0); alen = (socklen_t)1; ck_assert_int_eq(wolfIP_sock_recvfrom(&s, icmp_sd, buf, sizeof(buf), 0, - (struct wolfIP_sockaddr *)&sin, &alen), -1); + (struct wolfIP_sockaddr *)&sin, &alen), -WOLFIP_EINVAL); } END_TEST START_TEST(test_dns_query_and_callback_a) @@ -4487,7 +4487,7 @@ START_TEST(test_sock_recvfrom_udp_short_addrlen) ck_assert_int_gt(udp_sd, 0); ck_assert_int_eq(wolfIP_sock_recvfrom(&s, udp_sd, buf, sizeof(buf), 0, - (struct wolfIP_sockaddr *)&sin, &alen), -1); + (struct wolfIP_sockaddr *)&sin, &alen), -WOLFIP_EINVAL); } END_TEST @@ -4506,7 +4506,7 @@ START_TEST(test_sock_recvfrom_icmp_short_addrlen) ck_assert_int_gt(icmp_sd, 0); ck_assert_int_eq(wolfIP_sock_recvfrom(&s, icmp_sd, buf, sizeof(buf), 0, - (struct wolfIP_sockaddr *)&sin, &alen), -1); + (struct wolfIP_sockaddr *)&sin, &alen), -WOLFIP_EINVAL); } END_TEST diff --git a/src/wolfip.c b/src/wolfip.c index 6a2d73c..8b8e8bc 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -2648,9 +2648,9 @@ int wolfIP_sock_recvfrom(struct wolfIP *s, int sockfd, void *buf, size_t len, in return -WOLFIP_EINVAL; ts = &s->udpsockets[SOCKET_UNMARK(sockfd)]; if (sin && !addrlen) - return -1; + return -WOLFIP_EINVAL; if (sin && *addrlen < sizeof(struct wolfIP_sockaddr_in)) - return -1; + return -WOLFIP_EINVAL; if (addrlen) *addrlen = sizeof(struct wolfIP_sockaddr_in); if (fifo_len(&ts->sock.udp.rxbuf) == 0) return -WOLFIP_EAGAIN; @@ -2663,7 +2663,7 @@ int wolfIP_sock_recvfrom(struct wolfIP *s, int sockfd, void *buf, size_t len, in } if (sin) { sin->sin_family = AF_INET; - sin->sin_port = ee16(udp->src_port); + sin->sin_port = udp->src_port; sin->sin_addr.s_addr = udp->ip.src; } seg_len = ee16(udp->len) - UDP_HEADER_LEN; @@ -2677,8 +2677,10 @@ int wolfIP_sock_recvfrom(struct wolfIP *s, int sockfd, void *buf, size_t len, in if (SOCKET_UNMARK(sockfd) >= MAX_ICMPSOCKETS) return -WOLFIP_EINVAL; ts = &s->icmpsockets[SOCKET_UNMARK(sockfd)]; + if (sin && !addrlen) + return -WOLFIP_EINVAL; if (sin && *addrlen < sizeof(struct wolfIP_sockaddr_in)) - return -1; + return -WOLFIP_EINVAL; if (addrlen) *addrlen = sizeof(struct wolfIP_sockaddr_in); desc = fifo_peek(&ts->sock.udp.rxbuf);