Segfault on disco#info result without a from attribute
#168
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
The client crashes with SIGSEGV immediately after login when the server answers the on-connect disco#info request with an iq result that has no
fromattribute, e.g.<iq type='result' id='...'/>. RFC 6120 §8.1.2.1 explicitly allows this: whenfromis omitted on a stanza received over a client-to-server stream, the client MUST treat it as coming from the server itself. So this is a crash on protocol-legal input, remotely triggerable by any server (or MITM on a plaintext/legacy connection).Crash path
_disco_info_response_id_handler()(src/xmpp/iq.c, ~line 2441) readsfrom = xmpp_stanza_get_from(stanza)—NULLwhen the attribute is absent — and passes it straight toconnection_features_received(from).connection_features_received()(src/xmpp/connection.c, ~line 753) callsg_hash_table_remove(conn.requested_features, NULL).conn.requested_featuresis ag_str_hashtable;g_str_hash(NULL)dereferences the NULL key → SIGSEGV.Last log lines before the crash:
Reproduction
Reproducible deterministically with a minimal fake server that completes legacy (XEP-0078) auth and replies
<iq type='result' id='...'/>(nofrom, no<query/>) to every iq:<stream:stream>open tag without aversionattribute (forces legacy auth), (b) replies<iq type='result' id='X'/>to every iq, echoing the id.profanity -l DEBUG, then/connect test@localhost server 127.0.0.1 port 5322 tls disable auth legacy, any password.Observed on
feat/ai-api-type@f7a818dc1(2026-07-16); the affected code is identical on current master.Suggested fix
Apply the RFC 6120 "no from = from the server" rule at the boundary: in
_disco_info_response_id_handler()(and any sibling result handlers that key onfrom), substituteconnection_get_domain()whenfromisNULLbefore touching the feature tables. Defense in depth: makeconnection_features_received()andconnection_get_features()NULL-safe (early return / domain fallback) so no other caller can reachg_str_hash(NULL).Note the same handler also calls
connection_get_features(from)and logs an error for an unknownfrom; with the domain substitution both paths become consistent with how the request was registered inconn.requested_features.Impact
from), but trivially triggerable by a hostile or minimal server implementation.