sylae / ligrev

XMPP MUC Utility bot
GNU General Public License v3.0
2 stars 1 forks source link

Audit PHP7 support #54

Closed sylae closed 7 years ago

sylae commented 8 years ago

This is a long-term-ish thing, mostly because in a casual test, Ligrev loads, but JAXL hangs at trying to connect. Could be an issue with my system, could be JAXL, in any case once all that's sorted we want to make sure we can run smoothly on php7.

sylae commented 8 years ago

Update on this (since I forgot to provide an update on this). No parse errors or anything yet, we're hung up on JAXL's stream handling...something changed with php7 and it just hangs somewhere in the constructor.

cburschka commented 8 years ago

I don't have a clue what kind of log messages I should be expecting, but I'm surprised that it actually will return an error if you try to authenticate a non-matching domain: eg. connecting to "calref.net" and trying to log in as "arancaytar@ermarian.net". This will return an <error xmlns="http://etherx.jabber.org/streams"><host-unknown xmlns="urn:ietf:params:xml:ns:xmpp-streams" /></error> stanza.

On the other hand, trying to log in as a non-existant user, or with a bad password, will hang just as you said.

Assuming that the error is actually received from the server, it's weird that you can get an error doing that, while you just freeze otherwise.

cburschka commented 8 years ago

Nevermind, the server also responds in the latter case: <features xmlns="http://etherx.jabber.org/streams"><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"></starttls><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms><c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="http://www.process-one.net/en/ejabberd/" ver="gQW0zV0MKAlXgZTipe4VrrJWkFQ="></c></features>

It's only after that that it freezes.

cburschka commented 8 years ago

Okay, as near as I can tell, if you have TLS on, then it will successfully negotiate TLS, and hang immediately after the server tells you how to authenticate.

If you don't have TLS on, then it will successfully log in, but then restart the stream for some reason and hang after that.

Watching raw traffic (### is out, ___ is in)

string(181) "###<stream:stream xmlns:stream="http://etherx.jabber.org/streams" version="1.0" to="calref.net" xmlns="jabber:client" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace">"
string(491) "____<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='2031329371' from='calref.net' version='1.0' xml:lang='en'><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>PLAIN</mechanism></mechanisms><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://www.process-one.net/en/ejabberd/' ver='gQW0zV0MKAlXgZTipe4VrrJWkFQ='/></stream:features>"
string(119) "###<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">.....</auth>"
string(55) "____<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>"
string(181) "###<stream:stream xmlns:stream="http://etherx.jabber.org/streams" version="1.0" to="calref.net" xmlns="jabber:client" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace">"
string(448) "____<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='4224327357' from='calref.net' version='1.0' xml:lang='en'><stream:features><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://www.process-one.net/en/ejabberd/' ver='gQW0zV0MKAlXgZTipe4VrrJWkFQ='/></stream:features>"

With TLS:

string(181) "###<stream:stream xmlns:stream="http://etherx.jabber.org/streams" version="1.0" to="calref.net" xmlns="jabber:client" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace">"
string(491) "____<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='1454207711' from='calref.net' version='1.0' xml:lang='en'><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>PLAIN</mechanism></mechanisms><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://www.process-one.net/en/ejabberd/' ver='gQW0zV0MKAlXgZTipe4VrrJWkFQ='/></stream:features>"
string(64) "###<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"></starttls>"
string(54) "____<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"
string(181) "###<stream:stream xmlns:stream="http://etherx.jabber.org/streams" version="1.0" to="calref.net" xmlns="jabber:client" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace">"
string(170) "____<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='37312497' from='calref.net' version='1.0' xml:lang='en'>"
string(272) "____<stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>PLAIN</mechanism></mechanisms><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://www.process-one.net/en/ejabberd/' ver='gQW0zV0MKAlXgZTipe4VrrJWkFQ='/></stream:features>"
cburschka commented 8 years ago

I may have narrowed it down to the part where it resets the XML parser after negotiating starttls. Somehow the handle_start_tag() callback isn't called anymore after that.

Edit: Yep. For some reason, the new parser doesn't call its start element handler, even though that is supposed to have been set correctly.

Edit2: Parsing something immediately after resetting the parser does work correctly.

Edit3: I tried these things. Let $X be the first string that the newly reset parser gets, which it mysteriously fails to find any starting tag inside.

  1. Try to parse the XML string $X immediately after the parser is initialized: Works.
  2. Try to parse the string <test/> when it's supposed to parse $X: Works.
  3. Try to parse $X when it's supposed to parse $X: Doesn't work (as established).

So for some reason, the specific combination of the string and the parser state is causing a problem that neither one causes on its own.

cburschka commented 8 years ago

Update: The parser is complaining about a Reserved XML Name error.

Some sources on the internet say this happens if you feed it anything before feeding it a <?xml...?> element.

Aaaaand some more debug tracing shows that it's feeding the newly initiated parser the <proceed/> element (the last string it fed the old parser) again before it feeds it the <?xml?>.

So yeah, now we know exactly how JAXL is fucking up, just not why.

Edit: Looks like some kind of racing condition where it resets the parser while it's still in the middle of parsing? Or something? Getting closer.

Edit: Nope, the racing condition was only in the debug output. It really is parsing the <?xml... string with a parser that has previously read 0 bytes, and I'm about half ready to blame this on an actual bug in the PHP XML library.

sylae commented 7 years ago

we've been running php7 in production for some time, consider it audited.