From 2f92eb8499c22958a08087d14b7d93d813a91e48 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 20 May 2026 10:18:46 -0500 Subject: [PATCH] Refactor position precision handling to honor explicit channel settings and prevent location leaks (#10513) --- src/mesh/PositionPrecision.cpp | 16 ++++---- src/mesh/PositionPrecision.h | 2 + test/test_position_precision/test_main.cpp | 43 ++++++++++++++++++++++ 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/mesh/PositionPrecision.cpp b/src/mesh/PositionPrecision.cpp index 04db01c79..75a17d6e9 100644 --- a/src/mesh/PositionPrecision.cpp +++ b/src/mesh/PositionPrecision.cpp @@ -4,17 +4,19 @@ #include -uint32_t getPositionPrecisionForChannel(uint8_t channelIndex) +uint32_t getPositionPrecisionForChannel(const meshtastic_Channel &channel) { - const meshtastic_Channel &channel = channels.getByIndex(channelIndex); - if (channel.settings.has_module_settings) { return channel.settings.module_settings.position_precision; - } else if (channel.role == meshtastic_Channel_Role_PRIMARY) { - return 32; - } else { - return 0; } + // No module settings: fail closed. A PRIMARY channel used to default to 32 + // here, leaking an exact position on a sharing-disabled channel. See #10509. + return 0; +} + +uint32_t getPositionPrecisionForChannel(uint8_t channelIndex) +{ + return getPositionPrecisionForChannel(channels.getByIndex(channelIndex)); } static int32_t truncateCoordinate(int32_t coordinate, uint32_t precision) diff --git a/src/mesh/PositionPrecision.h b/src/mesh/PositionPrecision.h index 6fdbd2f64..89828f2e0 100644 --- a/src/mesh/PositionPrecision.h +++ b/src/mesh/PositionPrecision.h @@ -1,8 +1,10 @@ #pragma once +#include "meshtastic/channel.pb.h" #include "meshtastic/mesh.pb.h" #include +uint32_t getPositionPrecisionForChannel(const meshtastic_Channel &channel); uint32_t getPositionPrecisionForChannel(uint8_t channelIndex); void applyPositionPrecision(meshtastic_Position &position, uint32_t precision); bool applyPositionPrecision(meshtastic_MeshPacket &packet, uint32_t precision); diff --git a/test/test_position_precision/test_main.cpp b/test/test_position_precision/test_main.cpp index 4f5aecfda..bb6118177 100644 --- a/test/test_position_precision/test_main.cpp +++ b/test/test_position_precision/test_main.cpp @@ -19,6 +19,16 @@ static meshtastic_Position makePosition() return position; } +static meshtastic_Channel makeChannel(meshtastic_Channel_Role role, bool hasModuleSettings, uint32_t positionPrecision) +{ + meshtastic_Channel channel = meshtastic_Channel_init_default; + channel.has_settings = true; + channel.role = role; + channel.settings.has_module_settings = hasModuleSettings; + channel.settings.module_settings.position_precision = positionPrecision; + return channel; +} + static void test_applyPositionPrecision_clampsLatLonAndSetsPrecisionBits() { meshtastic_Position position = makePosition(); @@ -80,6 +90,35 @@ static void test_applyPositionPrecision_reencodesPositionPacket() TEST_ASSERT_EQUAL_UINT32(16, decoded.precision_bits); } +static void test_getPositionPrecisionForChannel_explicitPrecisionIsHonored() +{ + meshtastic_Channel channel = makeChannel(meshtastic_Channel_Role_PRIMARY, true, 16); + + TEST_ASSERT_EQUAL_UINT32(16, getPositionPrecisionForChannel(channel)); +} + +static void test_getPositionPrecisionForChannel_explicitZeroDisablesPrimary() +{ + meshtastic_Channel channel = makeChannel(meshtastic_Channel_Role_PRIMARY, true, 0); + + TEST_ASSERT_EQUAL_UINT32(0, getPositionPrecisionForChannel(channel)); +} + +static void test_getPositionPrecisionForChannel_primaryWithoutModuleSettingsFailsClosed() +{ + // Regression guard for #10509: precision 32 below must be ignored (no module settings). + meshtastic_Channel channel = makeChannel(meshtastic_Channel_Role_PRIMARY, false, 32); + + TEST_ASSERT_EQUAL_UINT32(0, getPositionPrecisionForChannel(channel)); +} + +static void test_getPositionPrecisionForChannel_secondaryWithoutModuleSettingsFailsClosed() +{ + meshtastic_Channel channel = makeChannel(meshtastic_Channel_Role_SECONDARY, false, 32); + + TEST_ASSERT_EQUAL_UINT32(0, getPositionPrecisionForChannel(channel)); +} + void setUp(void) {} void tearDown(void) {} @@ -93,6 +132,10 @@ void setup() RUN_TEST(test_applyPositionPrecision_fullPrecisionKeepsLatLon); RUN_TEST(test_applyPositionPrecision_zeroScrubsLocationButKeepsTime); RUN_TEST(test_applyPositionPrecision_reencodesPositionPacket); + RUN_TEST(test_getPositionPrecisionForChannel_explicitPrecisionIsHonored); + RUN_TEST(test_getPositionPrecisionForChannel_explicitZeroDisablesPrimary); + RUN_TEST(test_getPositionPrecisionForChannel_primaryWithoutModuleSettingsFailsClosed); + RUN_TEST(test_getPositionPrecisionForChannel_secondaryWithoutModuleSettingsFailsClosed); exit(UNITY_END()); }