fix(modules): null-check packetPool/clientNotificationPool/mqttClientProxyMessagePool allocations (#10951)
* fix(modules): null-check packetPool/clientNotificationPool/mqttClientProxyMessagePool allocations Follow-up to fix/meshpacket-alloc-null-checks (PR meshtastic/firmware#10948), which fixed the core routing path (Router/NextHopRouter/ReliableRouter/ MeshService/RadioLibInterface) after reproducing a HardFault on STM32WL hardware under real mesh traffic. This covers the same allocCopy()/ allocZeroed() unchecked-return pattern in lower-frequency paths that were out of scope for that PR: SimRadio.cpp (portduino sim RX/TX), NodeInfoModule, the Telemetry modules' power-saving-sleep notifications, MQTT (map report, client-proxy messages, config-validation notifications), PositionModule, SerialModule, and KeyVerificationModule. Sites where the allocation result was already read back through an existing null check downstream (e.g. Telemetry's lastMeasurementPacket, SimRadio's receivingPacket, AdminModule::sendWarning) were left as-is - verified safe, not touched. Router::allocForSending() (and everything that funnels through it, e.g. allocDataProtobuf()) remains unguarded and out of scope here too - it's called from 30+ sites across the codebase and needs its own audit. Assisted-by: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Andrew Yong <me@ndoo.sg> * fix(KeyVerificationModule): bound cn->message writes with snprintf CodeRabbit flagged unbounded sprintf() writes into the fixed-size ClientNotification.message buffer as a static-analysis nitpick while reviewing this PR's allocation null-checks. Align these four sites with the snprintf(dest, sizeof(dest), ...) pattern already used for the same field elsewhere in this PR (SerialModule.cpp, MQTT.cpp). Assisted-by: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Andrew Yong <me@ndoo.sg> --------- Signed-off-by: Andrew Yong <me@ndoo.sg> Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
This commit is contained in:
co-authored by
GitHub
Ben Meadors
parent
515fe8b94f
commit
6768bd08df
+6
-4
@@ -1053,10 +1053,12 @@ void setup()
|
||||
if (nodeDB->keyIsLowEntropy && !nodeDB->hasWarned) {
|
||||
LOG_WARN(LOW_ENTROPY_WARNING);
|
||||
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
|
||||
cn->level = meshtastic_LogRecord_Level_WARNING;
|
||||
cn->time = getValidTime(RTCQualityFromNet);
|
||||
sprintf(cn->message, LOW_ENTROPY_WARNING);
|
||||
service->sendClientNotification(cn);
|
||||
if (cn) {
|
||||
cn->level = meshtastic_LogRecord_Level_WARNING;
|
||||
cn->time = getValidTime(RTCQualityFromNet);
|
||||
sprintf(cn->message, LOW_ENTROPY_WARNING);
|
||||
service->sendClientNotification(cn);
|
||||
}
|
||||
nodeDB->hasWarned = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -81,14 +81,16 @@ bool KeyVerificationModule::handleReceivedProtobuf(const meshtastic_MeshPacket &
|
||||
});)
|
||||
|
||||
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
|
||||
cn->level = meshtastic_LogRecord_Level_WARNING;
|
||||
sprintf(cn->message, "Enter Security Number for Key Verification");
|
||||
cn->which_payload_variant = meshtastic_ClientNotification_key_verification_number_request_tag;
|
||||
cn->payload_variant.key_verification_number_request.nonce = currentNonce;
|
||||
copyNodeLongNameOrUnknown(cn->payload_variant.key_verification_number_request.remote_longname,
|
||||
sizeof(cn->payload_variant.key_verification_number_request.remote_longname),
|
||||
nodeDB->getMeshNode(currentRemoteNode));
|
||||
service->sendClientNotification(cn);
|
||||
if (cn) {
|
||||
cn->level = meshtastic_LogRecord_Level_WARNING;
|
||||
snprintf(cn->message, sizeof(cn->message), "Enter Security Number for Key Verification");
|
||||
cn->which_payload_variant = meshtastic_ClientNotification_key_verification_number_request_tag;
|
||||
cn->payload_variant.key_verification_number_request.nonce = currentNonce;
|
||||
copyNodeLongNameOrUnknown(cn->payload_variant.key_verification_number_request.remote_longname,
|
||||
sizeof(cn->payload_variant.key_verification_number_request.remote_longname),
|
||||
nodeDB->getMeshNode(currentRemoteNode));
|
||||
service->sendClientNotification(cn);
|
||||
}
|
||||
LOG_INFO("Received hash2");
|
||||
currentState = KEY_VERIFICATION_SENDER_AWAITING_NUMBER;
|
||||
return true;
|
||||
@@ -114,15 +116,17 @@ bool KeyVerificationModule::handleReceivedProtobuf(const meshtastic_MeshPacket &
|
||||
};
|
||||
screen->showOverlayBanner(options);)
|
||||
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
|
||||
cn->level = meshtastic_LogRecord_Level_WARNING;
|
||||
sprintf(cn->message, "Final confirmation for incoming manual key verification %s", message);
|
||||
cn->which_payload_variant = meshtastic_ClientNotification_key_verification_final_tag;
|
||||
cn->payload_variant.key_verification_final.nonce = currentNonce;
|
||||
copyNodeLongNameOrUnknown(cn->payload_variant.key_verification_final.remote_longname,
|
||||
sizeof(cn->payload_variant.key_verification_final.remote_longname),
|
||||
nodeDB->getMeshNode(currentRemoteNode));
|
||||
cn->payload_variant.key_verification_final.isSender = false;
|
||||
service->sendClientNotification(cn);
|
||||
if (cn) {
|
||||
cn->level = meshtastic_LogRecord_Level_WARNING;
|
||||
snprintf(cn->message, sizeof(cn->message), "Final confirmation for incoming manual key verification %s", message);
|
||||
cn->which_payload_variant = meshtastic_ClientNotification_key_verification_final_tag;
|
||||
cn->payload_variant.key_verification_final.nonce = currentNonce;
|
||||
copyNodeLongNameOrUnknown(cn->payload_variant.key_verification_final.remote_longname,
|
||||
sizeof(cn->payload_variant.key_verification_final.remote_longname),
|
||||
nodeDB->getMeshNode(currentRemoteNode));
|
||||
cn->payload_variant.key_verification_final.isSender = false;
|
||||
service->sendClientNotification(cn);
|
||||
}
|
||||
|
||||
currentState = KEY_VERIFICATION_RECEIVER_AWAITING_USER;
|
||||
return true;
|
||||
@@ -211,16 +215,18 @@ meshtastic_MeshPacket *KeyVerificationModule::allocReply()
|
||||
IF_SCREEN(snprintf(message, 25, "Security Number \n%03u %03u", currentSecurityNumber / 1000, currentSecurityNumber % 1000);
|
||||
screen->showSimpleBanner(message, 30000); LOG_WARN("%s", message);)
|
||||
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
|
||||
cn->level = meshtastic_LogRecord_Level_WARNING;
|
||||
sprintf(cn->message, "Incoming Key Verification.\nSecurity Number\n%03u %03u", currentSecurityNumber / 1000,
|
||||
currentSecurityNumber % 1000);
|
||||
cn->which_payload_variant = meshtastic_ClientNotification_key_verification_number_inform_tag;
|
||||
cn->payload_variant.key_verification_number_inform.nonce = currentNonce;
|
||||
copyNodeLongNameOrUnknown(cn->payload_variant.key_verification_number_inform.remote_longname,
|
||||
sizeof(cn->payload_variant.key_verification_number_inform.remote_longname),
|
||||
nodeDB->getMeshNode(currentRemoteNode));
|
||||
cn->payload_variant.key_verification_number_inform.security_number = currentSecurityNumber;
|
||||
service->sendClientNotification(cn);
|
||||
if (cn) {
|
||||
cn->level = meshtastic_LogRecord_Level_WARNING;
|
||||
snprintf(cn->message, sizeof(cn->message), "Incoming Key Verification.\nSecurity Number\n%03u %03u",
|
||||
currentSecurityNumber / 1000, currentSecurityNumber % 1000);
|
||||
cn->which_payload_variant = meshtastic_ClientNotification_key_verification_number_inform_tag;
|
||||
cn->payload_variant.key_verification_number_inform.nonce = currentNonce;
|
||||
copyNodeLongNameOrUnknown(cn->payload_variant.key_verification_number_inform.remote_longname,
|
||||
sizeof(cn->payload_variant.key_verification_number_inform.remote_longname),
|
||||
nodeDB->getMeshNode(currentRemoteNode));
|
||||
cn->payload_variant.key_verification_number_inform.security_number = currentSecurityNumber;
|
||||
service->sendClientNotification(cn);
|
||||
}
|
||||
LOG_WARN("Security Number %04u, nonce %llu", currentSecurityNumber, currentNonce);
|
||||
return responsePacket;
|
||||
}
|
||||
@@ -275,15 +281,17 @@ void KeyVerificationModule::processSecurityNumber(uint32_t incomingNumber)
|
||||
currentState = KEY_VERIFICATION_SENDER_AWAITING_USER;
|
||||
IF_SCREEN(screen->requestMenu(graphics::menuHandler::KeyVerificationFinalPrompt);)
|
||||
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
|
||||
cn->level = meshtastic_LogRecord_Level_WARNING;
|
||||
sprintf(cn->message, "Final confirmation for outgoing manual key verification %s", message);
|
||||
cn->which_payload_variant = meshtastic_ClientNotification_key_verification_final_tag;
|
||||
cn->payload_variant.key_verification_final.nonce = currentNonce;
|
||||
copyNodeLongNameOrUnknown(cn->payload_variant.key_verification_final.remote_longname,
|
||||
sizeof(cn->payload_variant.key_verification_final.remote_longname),
|
||||
nodeDB->getMeshNode(currentRemoteNode));
|
||||
cn->payload_variant.key_verification_final.isSender = true;
|
||||
service->sendClientNotification(cn);
|
||||
if (cn) {
|
||||
cn->level = meshtastic_LogRecord_Level_WARNING;
|
||||
snprintf(cn->message, sizeof(cn->message), "Final confirmation for outgoing manual key verification %s", message);
|
||||
cn->which_payload_variant = meshtastic_ClientNotification_key_verification_final_tag;
|
||||
cn->payload_variant.key_verification_final.nonce = currentNonce;
|
||||
copyNodeLongNameOrUnknown(cn->payload_variant.key_verification_final.remote_longname,
|
||||
sizeof(cn->payload_variant.key_verification_final.remote_longname),
|
||||
nodeDB->getMeshNode(currentRemoteNode));
|
||||
cn->payload_variant.key_verification_final.isSender = true;
|
||||
service->sendClientNotification(cn);
|
||||
}
|
||||
LOG_INFO(message);
|
||||
|
||||
return;
|
||||
|
||||
@@ -69,12 +69,13 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
|
||||
// if user has changed while packet was not for us, inform phone
|
||||
if (hasChanged && !wasBroadcast && !isToUs(&mp)) {
|
||||
auto packetCopy = packetPool.allocCopy(mp); // Keep a copy of the packet for later analysis
|
||||
if (packetCopy) {
|
||||
// Re-encode the user protobuf, as we have stripped out the user.id
|
||||
packetCopy->decoded.payload.size = pb_encode_to_bytes(
|
||||
packetCopy->decoded.payload.bytes, sizeof(packetCopy->decoded.payload.bytes), &meshtastic_User_msg, &p);
|
||||
|
||||
// Re-encode the user protobuf, as we have stripped out the user.id
|
||||
packetCopy->decoded.payload.size = pb_encode_to_bytes(
|
||||
packetCopy->decoded.payload.bytes, sizeof(packetCopy->decoded.payload.bytes), &meshtastic_User_msg, &p);
|
||||
|
||||
service->sendToPhone(packetCopy);
|
||||
service->sendToPhone(packetCopy);
|
||||
}
|
||||
}
|
||||
|
||||
pruneLastNodeInfoCache();
|
||||
|
||||
@@ -418,12 +418,14 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t cha
|
||||
meshtastic_Config_DeviceConfig_Role_TAK_TRACKER) &&
|
||||
config.power.is_power_saving) {
|
||||
meshtastic_ClientNotification *notification = clientNotificationPool.allocZeroed();
|
||||
notification->level = meshtastic_LogRecord_Level_INFO;
|
||||
notification->time = getValidTime(RTCQualityFromNet);
|
||||
sprintf(notification->message, "Sending position and sleeping for %us interval in a moment",
|
||||
Default::getConfiguredOrDefaultMs(config.position.position_broadcast_secs, default_broadcast_interval_secs) /
|
||||
1000U);
|
||||
service->sendClientNotification(notification);
|
||||
if (notification) {
|
||||
notification->level = meshtastic_LogRecord_Level_INFO;
|
||||
notification->time = getValidTime(RTCQualityFromNet);
|
||||
sprintf(notification->message, "Sending position and sleeping for %us interval in a moment",
|
||||
Default::getConfiguredOrDefaultMs(config.position.position_broadcast_secs, default_broadcast_interval_secs) /
|
||||
1000U);
|
||||
service->sendClientNotification(notification);
|
||||
}
|
||||
sleepOnNextExecution = true;
|
||||
LOG_DEBUG("Start next execution in 5s, then sleep");
|
||||
setIntervalFromNow(FIVE_SECONDS_MS);
|
||||
|
||||
@@ -96,10 +96,12 @@ bool SerialModule::isValidConfig(const meshtastic_ModuleConfig_SerialConfig &con
|
||||
LOG_ERROR(warning);
|
||||
#ifndef PIO_UNIT_TESTING
|
||||
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
|
||||
cn->level = meshtastic_LogRecord_Level_ERROR;
|
||||
cn->time = getValidTime(RTCQualityFromNet);
|
||||
snprintf(cn->message, sizeof(cn->message), "%s", warning);
|
||||
service->sendClientNotification(cn);
|
||||
if (cn) {
|
||||
cn->level = meshtastic_LogRecord_Level_ERROR;
|
||||
cn->time = getValidTime(RTCQualityFromNet);
|
||||
snprintf(cn->message, sizeof(cn->message), "%s", warning);
|
||||
service->sendClientNotification(cn);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -485,13 +485,15 @@ bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
|
||||
if (isPowerSavingSensor()) {
|
||||
meshtastic_ClientNotification *notification = clientNotificationPool.allocZeroed();
|
||||
notification->level = meshtastic_LogRecord_Level_INFO;
|
||||
notification->time = getValidTime(RTCQualityFromNet);
|
||||
sprintf(notification->message, "Sending telemetry and sleeping for %us interval in a moment",
|
||||
Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.air_quality_interval,
|
||||
default_telemetry_broadcast_interval_secs) /
|
||||
1000U);
|
||||
service->sendClientNotification(notification);
|
||||
if (notification) {
|
||||
notification->level = meshtastic_LogRecord_Level_INFO;
|
||||
notification->time = getValidTime(RTCQualityFromNet);
|
||||
sprintf(notification->message, "Sending telemetry and sleeping for %us interval in a moment",
|
||||
Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.air_quality_interval,
|
||||
default_telemetry_broadcast_interval_secs) /
|
||||
1000U);
|
||||
service->sendClientNotification(notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -681,13 +681,15 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
|
||||
if (isPowerSavingSensor()) {
|
||||
meshtastic_ClientNotification *notification = clientNotificationPool.allocZeroed();
|
||||
notification->level = meshtastic_LogRecord_Level_INFO;
|
||||
notification->time = getValidTime(RTCQualityFromNet);
|
||||
sprintf(notification->message, "Sending telemetry and sleeping for %us interval in a moment",
|
||||
Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval,
|
||||
default_telemetry_broadcast_interval_secs) /
|
||||
1000U);
|
||||
service->sendClientNotification(notification);
|
||||
if (notification) {
|
||||
notification->level = meshtastic_LogRecord_Level_INFO;
|
||||
notification->time = getValidTime(RTCQualityFromNet);
|
||||
sprintf(notification->message, "Sending telemetry and sleeping for %us interval in a moment",
|
||||
Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval,
|
||||
default_telemetry_broadcast_interval_secs) /
|
||||
1000U);
|
||||
service->sendClientNotification(notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+20
-10
@@ -392,6 +392,8 @@ bool MQTT::publish(const char *topic, const char *payload, bool retained)
|
||||
{
|
||||
if (moduleConfig.mqtt.proxy_to_client_enabled) {
|
||||
meshtastic_MqttClientProxyMessage *msg = mqttClientProxyMessagePool.allocZeroed();
|
||||
if (!msg)
|
||||
return false;
|
||||
msg->which_payload_variant = meshtastic_MqttClientProxyMessage_text_tag;
|
||||
strncpy(msg->topic, topic, sizeof(msg->topic));
|
||||
msg->topic[sizeof(msg->topic) - 1] = '\0';
|
||||
@@ -413,6 +415,8 @@ bool MQTT::publish(const char *topic, const uint8_t *payload, size_t length, boo
|
||||
{
|
||||
if (moduleConfig.mqtt.proxy_to_client_enabled) {
|
||||
meshtastic_MqttClientProxyMessage *msg = mqttClientProxyMessagePool.allocZeroed();
|
||||
if (!msg)
|
||||
return false;
|
||||
msg->which_payload_variant = meshtastic_MqttClientProxyMessage_data_tag;
|
||||
strncpy(msg->topic, topic, sizeof(msg->topic));
|
||||
msg->topic[sizeof(msg->topic) - 1] = '\0'; // Ensure null termination
|
||||
@@ -595,11 +599,13 @@ bool MQTT::isValidConfig(const meshtastic_ModuleConfig_MQTTConfig &config, MQTTC
|
||||
LOG_ERROR(warning);
|
||||
#ifndef PIO_UNIT_TESTING
|
||||
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
|
||||
cn->level = meshtastic_LogRecord_Level_ERROR;
|
||||
cn->time = getValidTime(RTCQualityFromNet);
|
||||
strncpy(cn->message, warning, sizeof(cn->message) - 1);
|
||||
cn->message[sizeof(cn->message) - 1] = '\0'; // Ensure null termination
|
||||
service->sendClientNotification(cn);
|
||||
if (cn) {
|
||||
cn->level = meshtastic_LogRecord_Level_ERROR;
|
||||
cn->time = getValidTime(RTCQualityFromNet);
|
||||
strncpy(cn->message, warning, sizeof(cn->message) - 1);
|
||||
cn->message[sizeof(cn->message) - 1] = '\0'; // Ensure null termination
|
||||
service->sendClientNotification(cn);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
#endif
|
||||
@@ -611,11 +617,13 @@ bool MQTT::isValidConfig(const meshtastic_ModuleConfig_MQTTConfig &config, MQTTC
|
||||
LOG_ERROR(warning);
|
||||
#ifndef PIO_UNIT_TESTING
|
||||
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
|
||||
cn->level = meshtastic_LogRecord_Level_ERROR;
|
||||
cn->time = getValidTime(RTCQualityFromNet);
|
||||
strncpy(cn->message, warning, sizeof(cn->message) - 1);
|
||||
cn->message[sizeof(cn->message) - 1] = '\0'; // Ensure null termination
|
||||
service->sendClientNotification(cn);
|
||||
if (cn) {
|
||||
cn->level = meshtastic_LogRecord_Level_ERROR;
|
||||
cn->time = getValidTime(RTCQualityFromNet);
|
||||
strncpy(cn->message, warning, sizeof(cn->message) - 1);
|
||||
cn->message[sizeof(cn->message) - 1] = '\0'; // Ensure null termination
|
||||
service->sendClientNotification(cn);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
@@ -746,6 +754,8 @@ void MQTT::perhapsReportToMap()
|
||||
|
||||
// Allocate MeshPacket and fill it
|
||||
meshtastic_MeshPacket *mp = packetPool.allocZeroed();
|
||||
if (!mp)
|
||||
return;
|
||||
mp->which_payload_variant = meshtastic_MeshPacket_decoded_tag;
|
||||
mp->from = nodeDB->getNodeNum();
|
||||
mp->to = NODENUM_BROADCAST;
|
||||
|
||||
@@ -209,6 +209,8 @@ void SimRadio::startSend(meshtastic_MeshPacket *txp)
|
||||
isReceiving = false;
|
||||
size_t numbytes = beginSending(txp);
|
||||
meshtastic_MeshPacket *p = packetPool.allocCopy(*txp);
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
// A packet we originate that's encrypted for someone else (a PKI DM, channel == 0) can't be
|
||||
// decrypted here. Attempting it only logs a spurious "no suitable channel" miss, and the
|
||||
@@ -361,6 +363,8 @@ void SimRadio::handleReceiveInterrupt()
|
||||
meshtastic_MeshPacket *mp = packetPool.allocCopy(*receivingPacket); // keep a copy in packetPool
|
||||
packetPool.release(receivingPacket); // release the original
|
||||
receivingPacket = nullptr;
|
||||
if (!mp)
|
||||
return;
|
||||
|
||||
printPacket("Lora RX", mp);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user