Browse Source

etcp: fix OOB/DoS in packet parsing and ping path

- FILLER: drop (uint16_t) truncation in fill_len bound (OOB pointer)
- ACK: require len >= ETCP_ACK_BASE_SIZE (8); wrap-aware clamp of till
  to next_tx_id + 16MB cumulative-ACK iteration limit (DoS)
- ping: bound len before sc_encrypt (stack overflow), ulen bound,
  allocate ETCP_DGRAM + PACKET_DATA_SIZE (heap overflow)

Signed-off-by: uTun <dev@utun>
proxy
evgeny 2 weeks ago
parent
commit
8bfb456161
  1. 10
      src/transport_layer/etcp.c
  2. 1
      src/transport_layer/etcp.h
  3. 11
      src/transport_layer/etcp_connections.c

10
src/transport_layer/etcp.c

@ -1546,9 +1546,10 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
// Process sections as per protocol.txt
switch (type) {
case ETCP_SECTION_ACK: {
if (len < 2) { len = 0; break; }
if (len < ETCP_ACK_BASE_SIZE) { len = 0; break; }
int elm_cnt=data[1];
uint32_t till=data[2] | (data[3]<<8) | (data[4]<<16) | (data[5]<<24);
if ((int32_t)(till - etcp->next_tx_id) > 0) till = etcp->next_tx_id; // wrap-aware: пир не мог подтвердить больше, чем мы отправили
uint16_t rx_dup_count_16 = data[6] | (data[7]<<8);
uint16_t old_tx_dup_16 = etcp->tx_dup_count & 0xFFFF;
int16_t diff = (int16_t)(rx_dup_count_16 - old_tx_dup_16);
@ -1567,7 +1568,10 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
uint16_t dts=data[-ack_section_len+14+i*8] | (data[-ack_section_len+15+i*8]<<8);
etcp_ack_recv(etcp, seq, ts, dts);
}
while ((int32_t)(etcp->rx_ack_till-till)<0) { etcp->rx_ack_till++; etcp_ack_recv(etcp, etcp->rx_ack_till, -1, -1); }// подтверждаем всё по till
uint32_t ack_gap = 0;
while ((int32_t)(etcp->rx_ack_till-till)<0 && ack_gap < ETCP_ACK_GAP_MAX_PACKETS) {
etcp->rx_ack_till++; etcp_ack_recv(etcp, etcp->rx_ack_till, -1, -1); ack_gap++;
}// подтверждаем всё по till
break;
}
case ETCP_SECTION_TIMESTAMP: {
@ -1794,7 +1798,7 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
case ETCP_SECTION_FILLER: {
if (len < FILLER_HDR_SIZE) { len = 0; break; }
uint16_t fill_len = data[1] | (data[2] << 8);
if ((uint16_t)(fill_len + FILLER_HDR_SIZE) > len) { len = 0; break; }
if (fill_len > len - FILLER_HDR_SIZE) { len = 0; break; }
data += FILLER_HDR_SIZE + fill_len; len -= FILLER_HDR_SIZE + fill_len;
break;
}

1
src/transport_layer/etcp.h

@ -61,6 +61,7 @@ uint16_t get_current_timestamp(void);
#define INFLIGHT_INITIAL_HASH_SIZE 1024
#define MAX_INFLIGHT_SIZE 16384 // максимальное число элементов в inflight приёмной очереди (для предотвращения атак)
#define ETCP_ACK_GAP_MAX_PACKETS 8192 // предел кумулятивного ACK за приём: 8192 × PACKET_DATA_SIZE(2048) = 16 MB (защита от DoS)
#define ASM_BUF_MAX_SIZE (64 * 1024) // максимальный размер буфера сборки фрагментов
// в этот список пакет добавляется когда перемещается из input_queue в input_send_q, при этом к пакету добавляется struct INFLIGHT_PACKET из inflight_pool.

11
src/transport_layer/etcp_connections.c

@ -1366,11 +1366,11 @@ static int etcp_send_ping_raw(struct ETCP_DGRAM* dgram, struct ETCP_SOCKET* e_so
return -1;
}
int len = dgram->data_len - dgram->noencrypt_len;
if (len < 0 || len > PACKET_DATA_SIZE - IP_UDP_OVERHEAD_V4) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "ping packet data invalid len=%d", len);
uint8_t enc_buf[1600];
if (len < 0 || len + (int)dgram->noencrypt_len + SC_ENCRYPT_OVERHEAD > (int)sizeof(enc_buf)) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "ping packet too large len=%d ne=%d", len, dgram->noencrypt_len);
return -1;
}
uint8_t enc_buf[1600];
size_t enc_buf_len = 0;
dgram->timestamp = get_current_timestamp();
dgram->flag_up = 1;
@ -1477,7 +1477,7 @@ int etcp_send_ping_to_socket(struct UTUN_INSTANCE* instance, struct ETCP_SOCKET*
ctx->user_data_len = user_data_len;
}
memcpy(ctx->peer_pubkey, peer_pubkey_bin, SC_PUBKEY_SIZE);
struct ETCP_DGRAM* dgram = u_malloc(PACKET_DATA_SIZE);
struct ETCP_DGRAM* dgram = u_malloc(sizeof(struct ETCP_DGRAM) + PACKET_DATA_SIZE);
if (!dgram) {
if (ctx->user_data) u_free(ctx->user_data);
u_free(ctx);
@ -1629,6 +1629,7 @@ static int handle_ping(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, const
uint64_t peer_id = be64toh(*(uint64_t*)(pkt->data + 2));
uint64_t nonce = be64toh(*(uint64_t*)(pkt->data + 10));
uint16_t ulen = be16toh(*(uint16_t*)(pkt->data + 18));
if (ulen > pkt->data_len - 20) ulen = (uint16_t)(pkt->data_len - 20);
const uint8_t* udata = (ulen > 0) ? (pkt->data + 20) : NULL;
if ((flags & ETCP_PING_FLAG_SEND_RTT) && ulen >= 2) {
@ -1641,7 +1642,7 @@ static int handle_ping(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, const
if (e_sock->instance->topo_groups && topo_node_ping_request_cbk(e_sock->instance->topo_groups, peer_id))
pong_flags |= ETCP_PING_FLAG_WANT_RTT;
struct ETCP_DGRAM* resp = u_malloc(PACKET_DATA_SIZE);
struct ETCP_DGRAM* resp = u_malloc(sizeof(struct ETCP_DGRAM) + PACKET_DATA_SIZE);
if (resp) {
resp->link = NULL;
resp->noencrypt_len = SC_PUBKEY_ENC_SIZE;

Loading…
Cancel
Save