Skip to content

Malformed or missing AVPs raise unhandled exceptions in the request handlers (no answer sent) #308

Description

@Dongoing

PyHSS 1.0.2.

A request that is well-formed at the Diameter layer but carries an unexpected AVP value (or omits an expected AVP) makes the handler throw before it builds the answer, so the transaction just times out on the peer. A few I hit while sending malformed Cx/S6a requests:

User-Name that isn't a SIP URI — MAR (Answer_16777216_303) does username.split('@')[1]:

File "/pyhss/lib/diameter.py", line 2569, in Answer_16777216_303
    domain = username.split('@')[1]
IndexError: list index out of range

Missing Session-Id — UAR (Answer_16777216_300) indexes an empty list:

File "/pyhss/lib/diameter.py", line 822, in generateDiameterResponse
File "/pyhss/lib/diameter.py", line 2316, in Answer_16777216_300
    session_id = self.get_avp_data(avps, 263)[0]
IndexError: list index out of range

User-Name that isn't hex / isn't UTF-8 — same handler, later:

    username = binascii.unhexlify(username).decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfe in position 0: invalid start byte

Same shape shows up in the S6a handlers too (AIR/PUR do the same unhexlify(...).decode() on User-Name, ULR/AIR index get_avp_data(...)[0]), and passing a grouped AVP where a scalar is expected hits binascii.unhexlify() with a list → TypeError.

Root cause is the handlers assume the AVP is present and well-formed. get_avp_data(avps, N)[0] throws IndexError when the AVP is absent, and binascii.unhexlify(x).decode('utf-8') throws when x isn't hex / isn't UTF-8. Would it make sense to validate these centrally — return DIAMETER_MISSING_AVP / DIAMETER_INVALID_AVP_VALUE instead of letting the exception kill the response? Happy to send a PoC packet for any of these.

Line numbers below are against current master.

The MAR handler Answer_16777216_303 reads several AVPs at the top of the function with no guarding:

lib/diameter.py
3151  public_identity = self.get_avp_data(avps, 601)[0]
3152  public_identity = binascii.unhexlify(public_identity).decode('utf-8')
3154  username = self.get_avp_data(avps, 1)[0]
3155  username = binascii.unhexlify(username).decode('utf-8')
3156  imsi   = username.split('@')[0]
3157  domain = username.split('@')[1]
3162  session_id = self.get_avp_data(avps, 263)[0]

A single malformed MAR reaches each of these:

  • a missing Public-Identity / User-Name / Session-Id makes get_avp_data(...)[0] index an empty list and raises IndexError
  • a User-Name that isn't hex or isn't UTF-8 raises binascii.Error / UnicodeDecodeError at 3152/3155
  • a User-Name without an @ raises IndexError at 3157

None of this is inside a try/except — the first try starts at 3169 around Get_Subscriber. The exception propagates out of the handler and no MAA is generated, so the transaction times out on the peer.

The same unguarded extraction is in the S6a handlers: AIR/PUR unhexlify(...).decode() the User-Name, ULR/AIR index get_avp_data(...)[0].

UAR (Answer_16777216_300) already wraps its User-Name handling in try/except (2915–2924), so it is not affected in the same way — MAR is the representative case here. (The UAR except branch has a separate defect, filed on its own.)

The fix is to check presence and wrap the decode before use, returning DIAMETER_MISSING_AVP / DIAMETER_INVALID_AVP_VALUE instead of letting the handler raise.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions