Fix AVP decode DoS, missing Origin-State-Id on DWA and MSCC dictionary bound - #259
Open
kulcsartibor wants to merge 1 commit into
Open
Fix AVP decode DoS, missing Origin-State-Id on DWA and MSCC dictionary bound#259kulcsartibor wants to merge 1 commit into
kulcsartibor wants to merge 1 commit into
Conversation
…y bound Three independent fixes. diam: remote-DoS panic on malformed AVPs in decodeAVPs On a DecodeError, decodeAVPs appended the partially-decoded AVP and called a.Len() on it, dereferencing a nil Data and panicking — any peer able to reach the endpoint could crash it with a crafted message. A zero or garbage AVP length could also leave the loop without forward progress. decodeAVPs now advances by the validated on-wire length on the error path and stops on non-advancing lengths; (*AVP).Len() guards against nil Data as defense in depth. Adds TestReadMessageMalformed and FuzzReadMessage. Complementary to the panic fixes in fiorix#249, which cover DecodeFromBytes and DecodeGroupedFromBytes rather than the top-level loop. sm: send Origin-State-Id on DWA, not back into the request handleDWR appended Origin-State-Id to the received request (m) instead of the answer (a) it was building — the two lines above it correctly use a. The DWA therefore never carried Origin-State-Id despite the code's intent, and the inbound request object was mutated (its Message-Length grew), which also corrupts the message handed to sm.Error's ErrorReport on a write failure. This is the only occurrence of the pattern in handler code; every other m.NewAVP in diam/sm builds a request, where m is correct. Adds TestHandleDWR_OriginStateID; the existing tests missed it because they only assert the DWA Result-Code. dict: Multiple-Services-Credit-Control is unbounded in CCR/CCA The Credit-Control command rules declared the AVP with max="1", while RFC 4006 lists it as *[ Multiple-Services-Credit-Control ] in both CCR and CCA and the Ro rule in tgpp_ro_rf.xml is already unbounded — the dictionary contradicted both the RFC and its own sibling for the same message structure. Corrected in testdata/credit_control.xml and in the embedded duplicate in dict/default.go, which is kept in sync by hand. Behaviourally inert: Rule.Max is only read for the human-readable dictionary dump and is never enforced on decode or encode, so nothing that parsed before parses differently now. Adds TestCreditControlMSCCUnbounded.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three independent fixes, each with a regression test that fails before the
change. They are unrelated to each other, so happy to split into separate PRs
if you'd prefer.
1.
diam: remote-DoS panic on malformed AVPs indecodeAVPsdecodeAVPstreats aDecodeErroras non-fatal and keeps going, but itappended the partially-decoded AVP and then called
a.Len()on it. For an AVPwhose payload failed to decode,
Datais nil, soLen()dereferences nil andpanics. Any peer that can reach the endpoint can crash it with a crafted
message. A zero or garbage AVP length could also leave the loop without forward
progress.
Changes:
decodeAVPsnow advances by the validated on-wire AVP length (padded to thenext 4-byte boundary) on the
DecodeErrorpath instead of callinga.Len(),and breaks out on a non-advancing or out-of-range length so a malformed
length field cannot spin the loop.
(*AVP).Len()falls back to the header length whenData == nil, as defensein depth for any other caller iterating a partially-decoded message.
This is complementary to #249, which fixed the same panic class in
DecodeFromBytes(type/length mismatch fallback) andDecodeGroupedFromBytes(nil
Datain the sub-AVP loop). Neither covers the top-leveldecodeAVPsloop, which is what this addresses.
Tests:
TestReadMessageMalformed(table of malformed buffers, incl. theoriginal crash input, an AVP with a too-short payload, and a zero-length AVP)
and
FuzzReadMessage, assertingReadMessagenever panics on arbitrary input.2.
sm: send Origin-State-Id on DWA, not back into the requestIn
handleDWR, Origin-State-Id was appended to the received requestminstead of the answer
abeing built — the two lines immediately above itcorrectly use
a:Two consequences: the DWA never carried Origin-State-Id despite the code's
clear intent, and the inbound request object was mutated (its
Message-Lengthgrew), which also corrupts the message passed to
sm.Error'sErrorReportifthe answer fails to write.
I checked every other
m.NewAVPindiam/sm: they all build requests, wheremis correct. This was the only occurrence in handler code.Test:
TestHandleDWR_OriginStateIDcompletes the handshake, sends a DWR andasserts the DWA carries Origin-State-Id matching the configured value. The
existing DWR tests missed this because they only assert the DWA's Result-Code.
3.
dict: Multiple-Services-Credit-Control is unbounded in CCR/CCAThe Credit-Control command rules declared
<rule avp="Multiple-Services-Credit-Control" required="false" max="1"/>.RFC 4006 lists the AVP as
*[ Multiple-Services-Credit-Control ]in both CCRand CCA, and the Ro rule in
tgpp_ro_rf.xmlis already unbounded — so thedictionary contradicted both the RFC and its own sibling for the same message
structure.
Corrected in
diam/dict/testdata/credit_control.xmland in the embeddedduplicate inside
diam/dict/default.go(the two are kept in sync by hand;editing only the XML would leave the shipped dictionary unchanged).
This is behaviourally inert:
Rule.Maxis only read byprintCommand/printAVPfor the human-readable dictionary dump and is neverenforced on decode or encode, so nothing that parsed before parses differently
now. The only observable change is the dump, which prints
max=0for theserules.
Test:
TestCreditControlMSCCUnbounded.Verification
All green on
linuxanddarwin/arm64, except the pre-existingTestServerClose/sctpfailure on darwin. The 30 s fuzz runcompleted ~2.3M executions with no crashes.
8 files changed, 236 insertions(+), 8 deletions(-).