From: Frederic Lecaille Date: Thu, 22 Oct 2026 11:55:00 +0000 (+0200) Subject: BUG/MINOR: peers: use overflow-safe length checks when parsing updates X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=979b64f940edfe7db28222694c2878f32a6a16a4;p=haproxy.git BUG/MINOR: peers: use overflow-safe length checks when parsing updates peer_treat_updatemsg() checks dictionary lengths using pointer additions which may overflow (undefined behavior) and bypass validation. On 64-bit platforms, value_len == UINT64_MAX may pass both the pointer check and the chunk size check, since value_len + 1 wraps to zero. chunk_memcpy() rejects the copy, but its failure is ignored. The cursor then moves back one byte and subsequent fields are decoded incorrectly. For string keys, only the stored part is checked, but the cursor advances by the full announced length. A truncated key may thus be accepted if no data follow. Compare lengths against the remaining bytes instead. Keep decoded lengths as uint64_t to avoid truncation to unsigned int or 32-bit size_t. This requires a malformed peer update. HAProxy peers are expected to communicate over protected local networks between trusted participants. No crash or out-of-bounds write has been established. This fix should be backported to all supported stable branches. --- diff --git a/src/peers.c b/src/peers.c index b59eb5725..3282463c3 100644 --- a/src/peers.c +++ b/src/peers.c @@ -1896,7 +1896,8 @@ int peer_treat_updatemsg(struct appctx *appctx, struct peer *p, int updt, int ex } if (table->type == SMP_T_STR) { - unsigned int to_read, to_store; + uint64_t to_read; + unsigned int to_store; to_read = intdecode(msg_cur, msg_end); if (!*msg_cur) { @@ -1905,7 +1906,7 @@ int peer_treat_updatemsg(struct appctx *appctx, struct peer *p, int updt, int ex } to_store = MIN(to_read, table->key_size - 1); - if (*msg_cur + to_store > msg_end) { + if (to_read > (uint64_t)(msg_end - *msg_cur)) { TRACE_ERROR("malformed update message: invalid string (too big)", PEERS_EV_SESS_IO|PEERS_EV_RX_MSG|PEERS_EV_PROTO_ERR, appctx, p, st); goto malformed_free_newts; } @@ -2129,7 +2130,7 @@ int peer_treat_updatemsg(struct appctx *appctx, struct peer *p, int updt, int ex } case STD_T_DICT: { struct buffer *chunk; - size_t data_len, value_len; + uint64_t data_len, value_len; unsigned int id; struct dict_entry *de; struct dcache *dc; @@ -2140,7 +2141,7 @@ int peer_treat_updatemsg(struct appctx *appctx, struct peer *p, int updt, int ex break; } data_len = decoded_int; - if (*msg_cur + data_len > msg_end) { + if (data_len > (uint64_t)(msg_end - *msg_cur)) { TRACE_ERROR("malformed update message: invalid dict value", PEERS_EV_SESS_IO|PEERS_EV_RX_MSG|PEERS_EV_PROTO_ERR, appctx, p, st); goto malformed_unlock; } @@ -2168,7 +2169,7 @@ int peer_treat_updatemsg(struct appctx *appctx, struct peer *p, int updt, int ex else { chunk = get_trash_chunk(); value_len = intdecode(msg_cur, end); - if (!*msg_cur || *msg_cur + value_len > end || + if (!*msg_cur || value_len > (uint64_t)(end - *msg_cur) || unlikely(value_len + 1 >= chunk->size)) { TRACE_ERROR("malformed update message: invalid dict value", PEERS_EV_SESS_IO|PEERS_EV_RX_MSG|PEERS_EV_PROTO_ERR, appctx, p, st); goto malformed_unlock;