When reading message from the pipe, we first peek the pipe to get the size
of the message waiting to be read and then read the message. A compromised
OpenVPN process could send an excessively large message, which would result
in a stack-allocated message buffer overflow.
To address this, we terminate the misbehaving process if the peeked message
size exceeds the maximum allowable size.
This commit is backported from 9b2693f in release/2.6 branch, fixing
merge conflicts around &ring_buffer_handles and wins_cfg_message_t.
CVE: 2024-27459
Microsoft case number: 85932
Reported-by: Vladimir Tokarev <vtokarev@microsoft.com>
Change-Id: Ib5743cba0741ea11f9ee62c4978b2c6789b81ada
Signed-off-by: Lev Stipakov <lev@openvpn.net>
Acked-by: Heiko Hund <heiko@openvpn.net>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <20240320082000.284-2-lev@openvpn.net>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg28433.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
| ... | ... |
@@ -111,6 +111,17 @@ typedef struct {
|
| 111 | 111 |
HANDLE device; |
| 112 | 112 |
} ring_buffer_handles_t; |
| 113 | 113 |
|
| 114 |
+typedef union {
|
|
| 115 |
+ message_header_t header; |
|
| 116 |
+ address_message_t address; |
|
| 117 |
+ route_message_t route; |
|
| 118 |
+ flush_neighbors_message_t flush_neighbors; |
|
| 119 |
+ block_dns_message_t block_dns; |
|
| 120 |
+ dns_cfg_message_t dns; |
|
| 121 |
+ enable_dhcp_message_t dhcp; |
|
| 122 |
+ register_ring_buffers_message_t rrb; |
|
| 123 |
+ set_mtu_message_t mtu; |
|
| 124 |
+} pipe_message_t; |
|
| 114 | 125 |
|
| 115 | 126 |
static DWORD |
| 116 | 127 |
AddListItem(list_item_t **pfirst, LPVOID data) |
| ... | ... |
@@ -1444,18 +1455,7 @@ static VOID |
| 1444 | 1444 |
HandleMessage(HANDLE pipe, HANDLE ovpn_proc, ring_buffer_handles_t *ring_buffer_handles, |
| 1445 | 1445 |
DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists) |
| 1446 | 1446 |
{
|
| 1447 |
- DWORD read; |
|
| 1448 |
- union {
|
|
| 1449 |
- message_header_t header; |
|
| 1450 |
- address_message_t address; |
|
| 1451 |
- route_message_t route; |
|
| 1452 |
- flush_neighbors_message_t flush_neighbors; |
|
| 1453 |
- block_dns_message_t block_dns; |
|
| 1454 |
- dns_cfg_message_t dns; |
|
| 1455 |
- enable_dhcp_message_t dhcp; |
|
| 1456 |
- register_ring_buffers_message_t rrb; |
|
| 1457 |
- set_mtu_message_t mtu; |
|
| 1458 |
- } msg; |
|
| 1447 |
+ pipe_message_t msg; |
|
| 1459 | 1448 |
ack_message_t ack = {
|
| 1460 | 1449 |
.header = {
|
| 1461 | 1450 |
.type = msg_acknowledgement, |
| ... | ... |
@@ -1465,7 +1465,7 @@ HandleMessage(HANDLE pipe, HANDLE ovpn_proc, ring_buffer_handles_t *ring_buffer_ |
| 1465 | 1465 |
.error_number = ERROR_MESSAGE_DATA |
| 1466 | 1466 |
}; |
| 1467 | 1467 |
|
| 1468 |
- read = ReadPipeAsync(pipe, &msg, bytes, count, events); |
|
| 1468 |
+ DWORD read = ReadPipeAsync(pipe, &msg, bytes, count, events); |
|
| 1469 | 1469 |
if (read != bytes || read < sizeof(msg.header) || read != msg.header.size) |
| 1470 | 1470 |
{
|
| 1471 | 1471 |
goto out; |
| ... | ... |
@@ -1884,6 +1884,13 @@ RunOpenvpn(LPVOID p) |
| 1884 | 1884 |
break; |
| 1885 | 1885 |
} |
| 1886 | 1886 |
|
| 1887 |
+ if (bytes > sizeof(pipe_message_t)) |
|
| 1888 |
+ {
|
|
| 1889 |
+ /* process at the other side of the pipe is misbehaving, shut it down */ |
|
| 1890 |
+ MsgToEventLog(MSG_FLAGS_ERROR, TEXT("OpenVPN process sent too large payload length to the pipe (%lu bytes), it will be terminated"), bytes);
|
|
| 1891 |
+ break; |
|
| 1892 |
+ } |
|
| 1893 |
+ |
|
| 1887 | 1894 |
HandleMessage(ovpn_pipe, proc_info.hProcess, &ring_buffer_handles, bytes, 1, &exit_event, &undo_lists); |
| 1888 | 1895 |
} |
| 1889 | 1896 |
|