fix(esp_netif): stop L2TAP IREC walk on non-advancing records

This commit is contained in:
Ondrej Kosta
2026-09-18 14:10:48 +02:00
parent 09e2786ddf
commit 76ad6810e9
2 changed files with 35 additions and 2 deletions
@@ -1008,6 +1008,28 @@ TEST_CASE("esp32 l2tap - time stamping", "[ethernet]")
TEST_ASSERT_EQUAL(exp_n, n);
TEST_ASSERT_EQUAL(exp_sequence_id, ((test_eth_ptp_msg_t *)in_buffer)->ptp_msg.ptp_hdr.sequence_id);
ESP_LOGI(TAG, "Verify read IREC walk terminates when truncated record overlays a 0/0 timestamp");
ts_info->type = L2TAP_IREC_TIME_STAMP;
ts_info->len = L2TAP_IREC_LEN(sizeof(struct timespec));
test_ptp_msg.ptp_msg.ptp_hdr.sequence_id++;
exp_sequence_id++;
ptp_msg_ext_buff.buff = &test_ptp_msg;
ptp_msg_ext_buff.buff_len = sizeof(test_ptp_msg);
n = write(eth_tap_fd, &ptp_msg_ext_buff, 0);
TEST_ASSERT_EQUAL(sizeof(test_ptp_msg), n);
// 0/0 is an invalid timestamp. Reusing this IREC buffer with a truncated len makes
// L2TAP_IREC_NEXT land on tv_nsec==0 (a zero-length pseudo-header) and must not hang.
struct timespec *stale_ts = (struct timespec *)ts_info->data;
stale_ts->tv_sec = 0;
stale_ts->tv_nsec = 0;
ts_info->type = 0xFF;
ts_info->len = L2TAP_IREC_LEN(1);
ptp_msg_ext_buff.buff = in_buffer;
ptp_msg_ext_buff.buff_len = IN_BUFFER_SIZE;
n = read(eth_tap_fd, &ptp_msg_ext_buff, 0);
exp_n = sizeof(test_ptp_msg) < 60 ? 60 : sizeof(test_ptp_msg);
TEST_ASSERT_EQUAL(exp_n, n);
TEST_ASSERT_EQUAL(exp_sequence_id, ((test_eth_ptp_msg_t *)in_buffer)->ptp_msg.ptp_hdr.sequence_id);
ESP_LOGI(TAG, "Verify response to invalid record len for read (first we need write correctly)");
ts_info->type = L2TAP_IREC_TIME_STAMP;
+13 -2
View File
@@ -183,11 +183,22 @@ static esp_err_t pop_rx_queue(l2tap_context_t *l2tap_socket, void *buff, size_t
if (l2tap_socket->flags & L2TAP_FLAG_TS) {
// find the record allocated for the time stamp info
l2tap_irec_hdr_t *info_rec = L2TAP_IREC_FIRST(ext_buff);
while(info_rec != NULL) {
while (info_rec != NULL) {
/* rec->len is the NEXT stride. A truncated/invalid record (or leftover
* payload interpreted as a header) can have len < header size, */
if (info_rec->len < sizeof(l2tap_irec_hdr_t)) {
info_rec = NULL;
break;
}
if (info_rec->type == L2TAP_IREC_TIME_STAMP) {
break;
}
info_rec = L2TAP_IREC_NEXT(ext_buff, info_rec);
l2tap_irec_hdr_t *info_rec_next = L2TAP_IREC_NEXT(ext_buff, info_rec);
if (info_rec_next == NULL || (uint8_t *)info_rec_next <= (uint8_t *)info_rec) {
info_rec = NULL;
break;
}
info_rec = info_rec_next;
}
if (info_rec != NULL) {
// check if there is enough space to store TS