mirror of
https://github.com/meshtastic/firmware.git
synced 2026-11-07 23:04:49 -05:00
AdminModule: trust from == 0 only when the dispatcher reports a local origin (#12242)
AdminModule treats from == 0 as a local client, skipping the admin_key and session-passkey checks. That trust rested entirely on every ingress path dropping from == 0 (RadioLibInterface, MQTT downlink, UDP multicast and frame injection all do). Make the handler check it itself: - MeshModule gains a static currentRequestSource, set by callModules() alongside currentRequest, so modules can see the RxSource of the packet they are handling. - AdminModule drops a from == 0 payload unless callModules() is dispatching that exact packet with RX_SRC_USER or RX_SRC_LOCAL. It fails closed for a radio source, for no dispatch context, and for a context that belongs to another packet. The drop is silent (no NAK to a forged sender). Tests: AdminModuleTestShim::handleReceivedProtobuf now runs the handler inside a dispatch context (default RX_SRC_USER, the phone client existing suites stand in for), plus handleWithDispatchContext() for the negative cases. test_admin_session_repro adds six cases: from == 0 via RX_SRC_RADIO, with no context, and with another packet's context are rejected, both directly and through MeshModule::callModules(); the phone-client controls still apply the setter. With the gate removed, the four rejection cases fail. Claude-Session: https://claude.ai/code/session_01Y1BYe4ahUHxyhw3nGTX67D Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
1 parent
4da58c3c90
commit
e6ed4b5f6a
6 files changed
+147
-5
No files matched your search
@@ -135,6 +135,12 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
||||
if (mp.which_payload_variant != meshtastic_MeshPacket_decoded_tag) {
|
||||
return handled;
|
||||
}
|
||||
// from == 0 is trusted as a local client below, so require callModules() to vouch for its origin.
|
||||
if (mp.from == 0 &&
|
||||
!(currentRequest == &mp && (currentRequestSource == RX_SRC_USER || currentRequestSource == RX_SRC_LOCAL))) {
|
||||
LOG_WARN("Drop admin payload with from=0 that did not arrive from a local client");
|
||||
return handled;
|
||||
}
|
||||
#ifdef ARCH_PORTDUINO
|
||||
// Simulator only: honor exit_simulator unconditionally for the local client (from==0).
|
||||
// The from==0 branch below now covers pki_encrypted local packets too, but is_managed
|
||||
@@ -161,8 +167,8 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
||||
LOG_TRACE("Allow admin response message");
|
||||
} else if (mp.from == 0) {
|
||||
// Local admin from a BLE/USB/TCP client. from == 0 cannot arrive from the
|
||||
// mesh: RF drops packets without a sender (RadioLibInterface) and MQTT treats
|
||||
// from == 0 as our own downlink and ignores it. Clients may set pki_encrypted
|
||||
// mesh: RF, MQTT and UDP ingress drop it, and the source gate above rejects
|
||||
// any from == 0 not dispatched as RX_SRC_USER/LOCAL. Clients may set pki_encrypted
|
||||
// on self-addressed admin (the python CLI does), so don't use it to reroute
|
||||
// local packets into the remote-PKC key check.
|
||||
//
|
||||
|
||||
Reference in new issue
Block a user