In our software that we mentioned a few days ago, in addition to the lockups, we observed a problem when we apparently received an incoming call, but CreateConnection is called with a valid PDU that is not a Setup Message one.
It happens when the incoming call comes from a Cisco gateway, and the call hangs up at a point where the gateway has sent the Admission Request to the gatekeeper, receives its corresponding admission confirm, but has not sent yet the setup message to our software / destination endpoint.
In these circumstances we saw that the gateway has opened the signaling socket with our endpoint, but the first packet it sends is a Release Complete because the call was hung before sending the setup.
PDU trace from our Gatekeeper:
2017-05-27 14:46:28.853 5d37 INFO pdu.call.a.ARQ.recv : Received from ip$x.x.x.x:54432. 2017-05-27 14:46:28.855 5d37 INFO pdu.call.a.ACF.send : Sending to ip$x.x.x.x:54432. 2017-05-27 14:46:28.865 5d37 INFO pdu.call.d.DRQ.recv : Received from ip$x.x.x.x:54432. 2017-05-27 14:46:28.866 5d37 INFO pdu.call.d.DCF.send : Sending to ip$x.x.x.x:54432.
See the time-stamps, showing that the ACF and DRQ are closely followed. We receive the call at our endpoint, in the CreateConnection function at the same time point as the DRQ / DCF.
In our software, in some cases we return NULL if we cannot handle the incoming connection (not enough setup data, e.g.), and if we are running an executable compiled in Debug mode, an assert fails on the following operator:
H225_H323_UU_PDU_h323_message_body :: operator const H225_Setup_UUIE & () const #endif { #ifndef PASN_LEANANDMEAN PAssert (PIsDescendant (PAssertNULL (choice), H225_Setup_UUIE), PInvalidCast); #endif Return * (H225_Setup_UUIE *) choice; }
It is caused by the following line (transports.cxx: 1126):
H225_Setup_UUIE & setup = pdu.m_h323_uu_pdu.m_h323_message_body;
This code assumes that the initial PDU is a Setup one without checking it, when it may not necessarily be. That can cause a DoS in a software that has core dump enabled when an assert occurs, or if there is some code in HandleFirstSignallingChannelPDU / OnIncomingConnection and sub-calls that trust and handles the PDU object assuming it is a Setup message.
I've made the following patch on the HandleFirstSignallingChannelPDU function, which verifies that the PDU is a Setup message, otherwise it returns FALSE (same behavior as if it had not been able to read a valid q931 pdu), since we think it does not make much sense to call OnIncomingConnection if the initial PDU is not a Setup one:
--------------------------------------------------------------------------------
--- src/transports.cxx.orig 2015-11-24 18:51:06.385755223 +0100 +++ src/transports.cxx 2017-05-29 11:15:20.777411444 +0200 @@ -1106,7 +1106,13 @@ return FALSE; }
- unsigned callReference = pdu.GetQ931().GetCallReference(); + const Q931 &firstQ931PDU = pdu.GetQ931(); + if (firstQ931PDU.GetMessageType() != Q931::SetupMsg) { + PTRACE(1, "H225\tFirst pdu is not a setup one, connection not started."); + return FALSE; + } + + unsigned callReference = firstQ931PDU.GetCallReference(); PTRACE(3, "H225\tIncoming call, first PDU: callReference=" << callReference);
// Get a new (or old) connection from the endpoint
--------------------------------------------------------------------------------
A place where we could also put the patch is in the HandleSignallingSocket function, which apparently is only used from HandleFirstSignallingChannelPDU, but as it has a more generic name and may give rise to doubts of its behavior.
Regards,
Jose Uceda