Replica: discard unwanted InitDynamicPacket
Normally the host sends InitDynamicPacket only once when a new
dynamic replica is aquired on the client side.
The client code searched for the replica by the received name and
unconditionally updated the replica's metatype and property values
with the information from the packet. The only existing guards are
Q_ASSERT()s that are not enabled in release builds.
As a result, a malicious InitDynamicPacket could corrupt both
static and dynamic replicas:
* for static replica it will replace the replica's metaobject,
but all the code would keep using the compile-time indices of
signals, slots, and properties. This can lead to out of bounds
reads and writes.
* for dynamic replicas replacing the metatype at runtime means
that any previously cached QMetaObject, QMetaProperty, or
QMetaMethod becomes stale, so using it will also trigger out of
bounds access.
Fix it by applying the new metaobject and the new properties only
when the replica does not have a metaobject yet.
One tricky thing here is that we still need to fully deserialize
the incoming packet, but
QRemoteObjectMetaObjectManager::addDynamicType() caches the
metatypes and can thus overwrite a valid metatype with the new one
from the malformed command. So, use a temporary manager instance
if we know that we need to discard the packet anyway.
A cleaner solution would be to rewrite the entire reading code to
use a data stream that is backed up by the data from the single
packet, rather than all the incoming data from the connection. But
that is a larger change that affects way more code paths, so I do
not want to implement it in a security fix that will be picked all
the way down to Qt 5.15.
Add new unit tests that send hand-crafted InitDynamicPacket to
both statically and dynamically acquired replicas. The cached
metatype from QRemoteObjectMetaObjectManager is only accessed when
a child replica is updated, so the
repeatedDynamicInitForDynamicReplica() test uses PrentWithChild
object. It is also data-driven to cover all potential codepaths:
re-init a vaild parent replica, re-init a valid child replica,
init an unknown replica.
The tests were either triggering Q_ASSERT()s or crashing without
the fix.
Fixes: QTBUG-151085
Pick-to: 6.12 6.8 6.5 5.15
Change-Id: I277fb35c2b2b23bdd160160ac699397e9c0c709b
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>