-
Notifications
You must be signed in to change notification settings - Fork 656
Description
Describe the bug
In src/tools/forwarder/quicforward.cpp, three allocation failure paths
are unhandled:
-
In ConnectionCallback (PEER_STREAM_STARTED), MsQuicStream objects are
allocated with new(std::nothrow) but never null-checked before being
dereferenced. On allocation failure, PeerStream->Context crashes with a
null pointer dereference. Additionally, if LocalStream allocation fails,
the raw stream handle from Event->PEER_STREAM_STARTED.Stream is never
closed, leaking it. -
In ListenerCallback (NEW_CONNECTION), MsQuicConnection objects are
allocated with new(std::nothrow) but never null-checked before being
dereferenced. On allocation failure, BackEndConn->Context crashes with a
null pointer dereference. -
In StreamCallback (RECEIVE), if StreamSend returns an unexpected error
status, CXPLAT_FRE_ASSERT fires without first freeing SendContext, causing
a resource leak before process termination.
The correct null-check pattern already exists in MsQuicAutoAcceptListener
in msquic.hpp and is not consistently applied in quicforward.cpp.
Affected OS
- Windows
- Linux
- macOS
- Other (specify below)
Additional OS information
No response
MsQuic version
main
Steps taken to reproduce bug
- Run the quicforward tool to establish an active forwarding session.
- Trigger an OOM condition during stream or connection setup to cause
new(std::nothrow) to return null in ConnectionCallback or
ListenerCallback. - For the third bug: cause StreamSend to return a failure status other than
QUIC_STATUS_ABORTED or QUIC_STATUS_INVALID_STATE during an active
forwarding session.
Note: these paths require OOM conditions or fault injection to trigger
reliably and cannot be easily reproduced without a dedicated test harness.
Expected behavior
Allocation failures are handled gracefully. On stream allocation failure, the inbound stream handle is closed cleanly and the connection continues. On connection allocation failure, QUIC_STATUS_OUT_OF_MEMORY is returned and MsQuic refuses the connection cleanly. On unexpected send failure, SendContext is freed before process termination.
Actual outcome
Null pointer dereference and crash when new(std::nothrow) returns null in ConnectionCallback or ListenerCallback. Resource leak before process termination when StreamSend returns an unexpected error in StreamCallback.
Additional details
Root cause traced across three files:
- quicforward.cpp: allocation results used without null checks
- msquic.hpp: MsQuicStream and MsQuicConnection constructors have no
internal null guard on the outer pointer; destructor calls StreamClose/
ConnectionClose, so delete on a successfully constructed wrapper will
close the handle — manual close only needed when new returns null - listener.c: confirmed that returning QUIC_STATUS_OUT_OF_MEMORY from
ListenerCallback is safe — MsQuic refuses the connection and retains
handle ownership on failure returns - spinquic.cpp: confirms that PEER_STREAM_STARTED requires explicit
StreamClose on rejection, not a bare break
I created a fix and will be submit it as a PR referencing this issue.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status