mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2026-05-04 20:46:11 +02:00
BUG/MINOR: quic: fix buffer overflow with sockaddr_in46
New type sockaddr_in46 has been recently introduced. It serves as a
union which can store either an IPv4 or IPv6 address. The objective is
to reduce the storage size for QUIC datagrams which previously uses a
sockaddr_storage field.
On qc_new_conn(), source and destination addresses from the datagram are
passed to the function as sockaddr_storage so that they are copied into
the newly built quic_conn instance. However, the involved memcpy() is
producing a buffer overflow as sockaddr_in46 is smaller than
sockaddr_storage type.
This patch fixes this by defining a new helper function
in46un_to_addr(). This allows to convert safely sockaddr_in46 to a plain
sockaddr type. The function is now used before invoking qc_new_conn().
Note that there is still other several places where union sockaddr_in46
is casted as sockaddr_storage type. However, these should be safe as in
these cases sockaddr fields are accessed individually after checking
ss_family. The memory issue only exists when plain memcpy is used.
This bug was detected using ASAN. It generates the following traces when
a QUIC connection is instantiated.
==37474==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7c3bb9a61100 at pc 0x5631f52c3946 bp 0x7ffc83e45b50 sp 0x7ffc83e45310
READ of size 128 at 0x7c3bb9a61100 thread T0
#0 0x5631f52c3945 in __asan_memcpy (/home/amaury/work/haproxy-quic-dev/haproxy+0x3ae945) (BuildId: a7ccfd74b7a71a869b8ff8d13f6dcde8c82c1487)
#1 0x5631f55f9e34 in qc_new_conn /home/amaury/work/haproxy-quic-dev/src/quic_conn.c:1311:2
#2 0x5631f558d5c3 in quic_rx_pkt_retrieve_conn /home/amaury/work/haproxy-quic-dev/src/quic_rx.c:1875:10
#3 0x5631f558330b in quic_dgram_parse /home/amaury/work/haproxy-quic-dev/src/quic_rx.c:2463:29
#4 0x5631f5625da6 in quic_lstnr_dghdlr /home/amaury/work/haproxy-quic-dev/src/quic_sock.c:206:3
#5 0x5631f6a64173 in run_tasks_from_lists /home/amaury/work/haproxy-quic-dev/src/task.c:660:26
#6 0x5631f6a6ba1e in process_runnable_tasks /home/amaury/work/haproxy-quic-dev/src/task.c:913:9
#7 0x5631f5e984c3 in run_poll_loop /home/amaury/work/haproxy-quic-dev/src/haproxy.c:2982:3
#8 0x5631f5e9a715 in run_thread_poll_loop /home/amaury/work/haproxy-quic-dev/src/haproxy.c:3212:2
#9 0x5631f5e9f732 in main /home/amaury/work/haproxy-quic-dev/src/haproxy.c:3853:2
#10 0x7f2bba8276c0 (/usr/lib/libc.so.6+0x276c0) (BuildId: ca0db5ab57a36507d61bbcf4988d344974331f19)
#11 0x7f2bba8277f8 in __libc_start_main (/usr/lib/libc.so.6+0x277f8) (BuildId: ca0db5ab57a36507d61bbcf4988d344974331f19)
#12 0x5631f51be594 in _start (/home/amaury/work/haproxy-quic-dev/haproxy+0x2a9594) (BuildId: a7ccfd74b7a71a869b8ff8d13f6dcde8c82c1487)
No need to backport.
This commit is contained in:
parent
9b722520a9
commit
63f853957a
@ -109,6 +109,40 @@ static inline int quic_increment_curr_handshake(struct listener *l)
|
||||
return next;
|
||||
}
|
||||
|
||||
/* Initializes <dst> sockaddr_storage from <src> union sockaddr_in46 type.
|
||||
* Only unspec, IPv4 and IPv6 addresses are supported.
|
||||
*/
|
||||
static inline void in46un_to_addr(const union sockaddr_in46 *src,
|
||||
struct sockaddr_storage *dst)
|
||||
{
|
||||
struct sockaddr_in *in;
|
||||
struct sockaddr_in6 *in6;
|
||||
|
||||
switch (((struct sockaddr_storage *)src)->ss_family) {
|
||||
case AF_UNSPEC:
|
||||
memset(dst, 0, sizeof(*dst));
|
||||
break;
|
||||
|
||||
case AF_INET:
|
||||
in = (struct sockaddr_in *)dst;
|
||||
in->sin_family = AF_INET;
|
||||
in->sin_addr = src->in4.sin_addr;
|
||||
in->sin_port = src->in4.sin_port;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
in6 = (struct sockaddr_in6 *)dst;
|
||||
in6->sin6_family = AF_INET6;
|
||||
in6->sin6_addr = src->in6.sin6_addr;
|
||||
in6->sin6_port = src->in6.sin6_port;
|
||||
break;
|
||||
|
||||
default:
|
||||
ABORT_NOW();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* USE_QUIC */
|
||||
#endif /* _HAPROXY_QUIC_SOCK_H */
|
||||
|
||||
|
||||
@ -1868,9 +1868,12 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt,
|
||||
pool_free(pool_head_quic_connection_id, conn_id);
|
||||
}
|
||||
else {
|
||||
struct sockaddr_storage saddr, daddr;
|
||||
in46un_to_addr(&pkt->saddr, &saddr);
|
||||
in46un_to_addr(&dgram->daddr, &daddr);
|
||||
|
||||
qc = qc_new_conn(l, pkt, &token_odcid, NULL, conn_id,
|
||||
(struct sockaddr_storage *)&dgram->daddr,
|
||||
(struct sockaddr_storage *)&pkt->saddr);
|
||||
&daddr, &saddr);
|
||||
if (qc == NULL) {
|
||||
quic_cid_delete(conn_id); /* Removes CID from global tree as it points to a NULL qc. */
|
||||
pool_free(pool_head_quic_connection_id, conn_id);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user