Skip to content

Commit 8a6db7a

Browse files
gasbytesdanielinux
authored andcommitted
- make payload pointer/length calculations in tcp_recv mask
- correct MTU comment
1 parent b0ee2cc commit 8a6db7a

3 files changed

Lines changed: 51 additions & 4 deletions

File tree

src/test/unit/unit.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,7 @@ Suite *wolf_suite(void)
625625
tcase_add_test(tc_utils, test_tcp_recv_overlapping_ooo_segments_coalesce_on_consume);
626626
tcase_add_test(tc_utils, test_tcp_input_syn_with_sack_option_enables_sack);
627627
tcase_add_test(tc_utils, test_tcp_input_ignores_reserved_bits_in_hlen);
628+
tcase_add_test(tc_utils, test_tcp_recv_ignores_reserved_bits_in_hlen);
628629
tcase_add_test(tc_utils, test_tcp_input_syn_with_sack_option_respects_local_sack_offer);
629630
tcase_add_test(tc_utils, test_tcp_input_iplen_too_big);
630631
tcase_add_test(tc_utils, test_tcp_checksum_valid_passes);

src/test/unit/unit_tests_tcp_flow.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3065,6 +3065,49 @@ START_TEST(test_tcp_recv_queues_payload_and_advances_ack)
30653065
}
30663066
END_TEST
30673067

3068+
START_TEST(test_tcp_recv_ignores_reserved_bits_in_hlen)
3069+
{
3070+
/* RFC 9293 3.1: the low nibble of the Data Offset byte is Rsrvd and MUST
3071+
* be ignored. tcp_recv must therefore base its payload pointer and length
3072+
* on the masked (high-nibble) header length, otherwise a peer that sets
3073+
* reserved bits would have its delivered bytes shifted by 4*Rsrvd octets. */
3074+
struct wolfIP s;
3075+
struct tsocket *ts;
3076+
uint8_t payload[8] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' };
3077+
uint8_t seg_buf[sizeof(struct wolfIP_tcp_seg) + sizeof(payload)];
3078+
struct wolfIP_tcp_seg *seg = (struct wolfIP_tcp_seg *)seg_buf;
3079+
uint32_t seq = 50;
3080+
uint8_t out[sizeof(payload) + 4];
3081+
int ret;
3082+
3083+
wolfIP_init(&s);
3084+
ts = &s.tcpsockets[0];
3085+
memset(ts, 0, sizeof(*ts));
3086+
ts->proto = WI_IPPROTO_TCP;
3087+
ts->S = &s;
3088+
ts->sock.tcp.state = TCP_ESTABLISHED;
3089+
ts->sock.tcp.ack = seq;
3090+
ts->sock.tcp.bytes_in_flight = 1;
3091+
queue_init(&ts->sock.tcp.rxbuf, ts->rxmem, RXBUF_SIZE, seq);
3092+
3093+
memset(seg, 0, sizeof(seg_buf));
3094+
seg->ip.len = ee16(IP_HEADER_LEN + TCP_HEADER_LEN + sizeof(payload));
3095+
/* No options (hdr is the bare 20 bytes), but flip every reserved bit on. */
3096+
seg->hlen = (uint8_t)((TCP_HEADER_LEN << 2) | 0x0F);
3097+
seg->seq = ee32(seq);
3098+
seg->flags = (TCP_FLAG_ACK | TCP_FLAG_PSH);
3099+
memcpy(seg->data, payload, sizeof(payload));
3100+
3101+
tcp_recv(ts, seg);
3102+
3103+
ck_assert_uint_eq(ts->sock.tcp.ack, seq + sizeof(payload));
3104+
memset(out, 0, sizeof(out));
3105+
ret = queue_pop(&ts->sock.tcp.rxbuf, out, sizeof(out));
3106+
ck_assert_int_eq(ret, (int)sizeof(payload));
3107+
ck_assert_mem_eq(out, payload, sizeof(payload));
3108+
}
3109+
END_TEST
3110+
30683111
START_TEST(test_tcp_recv_wrong_state_does_nothing)
30693112
{
30703113
struct wolfIP s;

src/wolfip.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2470,8 +2470,8 @@ static void icmp_try_deliver_tcp_error(struct wolfIP *s,
24702470
next_hop_mtu = ee16(next_hop_mtu);
24712471
/* RFC 879 / RFC 9293 §3.7.1: IPv4 default MSS is 536; ignore
24722472
* any PTB whose next-hop MTU cannot accommodate it. Rejecting
2473-
* (rather than clamping) prevents a spoofed ICMP from dragging
2474-
* a SYN-negotiated peer_mss down to 536. */
2473+
* (rather than clamping) sub-576 MTUs prevents a spoofed ICMP
2474+
* from dragging a SYN-negotiated peer_mss below 536. */
24752475
if (next_hop_mtu >= (IP_HEADER_LEN + TCP_HEADER_LEN + TCP_DEFAULT_MSS)) {
24762476
uint16_t new_mss =
24772477
(uint16_t)(next_hop_mtu - (IP_HEADER_LEN + TCP_HEADER_LEN));
@@ -3615,9 +3615,12 @@ static inline uint32_t tcp_seq_inc(uint32_t seq, uint32_t n)
36153615
/* Add a segment to the rx buffer for the application to consume */
36163616
static void tcp_recv(struct tsocket *t, struct wolfIP_tcp_seg *seg)
36173617
{
3618-
uint32_t seg_len = ee16(seg->ip.len) - (IP_HEADER_LEN + (seg->hlen >> 2));
3618+
/* RFC 9293 3.1: mask the reserved nibble before deriving header length so a
3619+
* peer that sets reserved bits cannot shift our payload pointer/length. */
3620+
uint32_t hdr_len = tcp_data_offset_bytes(seg->hlen);
3621+
uint32_t seg_len = ee16(seg->ip.len) - (IP_HEADER_LEN + hdr_len);
36193622
uint32_t seq = ee32(seg->seq);
3620-
const uint8_t *payload = (uint8_t *)seg->ip.data + (seg->hlen >> 2);
3623+
const uint8_t *payload = (uint8_t *)seg->ip.data + hdr_len;
36213624
if ((t->sock.tcp.state != TCP_ESTABLISHED) &&
36223625
(t->sock.tcp.state != TCP_CLOSE_WAIT) &&
36233626
(t->sock.tcp.state != TCP_FIN_WAIT_1) &&

0 commit comments

Comments
 (0)