Skip to content

KeyVerificationModule: null-check getMeshNode() before dereference#10258

Open
nightjoker7 wants to merge 5 commits into
meshtastic:developfrom
nightjoker7:fix/keyverification-null-checks
Open

KeyVerificationModule: null-check getMeshNode() before dereference#10258
nightjoker7 wants to merge 5 commits into
meshtastic:developfrom
nightjoker7:fix/keyverification-null-checks

Conversation

@nightjoker7
Copy link
Copy Markdown
Contributor

Summary

Six sites in KeyVerificationModule.cpp dereferenced nodeDB->getMeshNode(currentRemoteNode)->user (or ->bitfield) without a null check. Four of these carry a literal // should really check for nulls, etc comment from the original commit, acknowledging the bug was known at merge time.

getMeshNode() returns NULL when the node number isn't in the NodeDB — which can happen between key-verification state transitions if the DB evicts the remote node (eg. DB fills up while we wait for the user to punch in a Security Number on the banner overlay). When that happens, the firmware crashes instead of cancelling verification cleanly.

Sites fixed

  1. handleAdminMessageForModuleDO_VERIFY path: null-check before setting NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK.
  2. handleReceivedProtobuf — hash2-received path: null-check before copying user.long_name into the Security Number Request ClientNotification.
  3. handleReceivedProtobuf — hash1-match banner callback: null-check inside the lambda before setting the verified bitfield.
  4. handleReceivedProtobuf — hash1-match notification: null-check before copying user.long_name into the Final ClientNotification.
  5. allocReply — null-check before copying user.long_name into the Number Inform ClientNotification.
  6. processSecurityNumber — reuse the remoteNodePtr already null-checked at the top of the function, instead of calling getMeshNode() a second time.

When the node is missing, the long_name copy falls back to an empty string so the notification still fires — blank remote name is better than a crash.

Test plan

  • Grep confirms no remaining nodeDB->getMeshNode(currentRemoteNode)-> dereferences without a preceding null check in this file
  • The existing null-check at line 222 in processSecurityNumber already guards site some minor cleanups #6's remoteNodePtr reuse
  • Build verification (existing CI)

This is part of an ongoing null-deref sweep across the codebase; related PRs in flight: #10226 (Router PKI decode), #10229 (MeshService has_user check).

Six sites dereferenced nodeDB->getMeshNode(currentRemoteNode)->user
or ->bitfield without null check. Four of them were flagged with the
comment "should really check for nulls, etc" in the original commit.

NodeDB can evict a node between key-verification state transitions
(e.g. if the DB fills up with other heard nodes while we wait for
the user to punch in a security number), at which point getMeshNode
returns NULL and the dereference crashes.

Fixes:
- handleAdminMessageForModule DO_VERIFY: null-check before setting
  IS_KEY_MANUALLY_VERIFIED_MASK bitfield
- handleReceivedProtobuf (hash2 path): null-check before copying
  long_name into ClientNotification
- handleReceivedProtobuf (hash1 match banner callback): null-check
  inside lambda before setting bitfield
- handleReceivedProtobuf (hash1 match notification): null-check
  before copying long_name
- allocReply: null-check before copying long_name
- processSecurityNumber: reuse the remoteNodePtr already null-checked
  at the top of the function instead of calling getMeshNode again

When the node is missing, the long_name copy uses an empty string
so the notification still fires but with a blank remote name.
@github-actions github-actions Bot added the bugfix Pull request that fixes bugs label Apr 23, 2026
@thebentern thebentern requested a review from Copilot April 23, 2026 11:40
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens KeyVerificationModule against NodeDB eviction races by null-checking nodeDB->getMeshNode(currentRemoteNode) before dereferencing node fields during key-verification state transitions, preventing firmware crashes and allowing verification to cancel/continue gracefully.

Changes:

  • Add null checks around getMeshNode(currentRemoteNode) dereferences in multiple key-verification flows (admin verify, hash2 request, hash1 accept, notifications).
  • Reuse an already-null-checked remoteNodePtr in processSecurityNumber() instead of re-querying NodeDB.
  • When the node is missing, fall back to an empty remote long name and (in one path) log a warning.

Comment thread src/modules/KeyVerificationModule.cpp Outdated
Comment thread src/modules/KeyVerificationModule.cpp Outdated
Comment thread src/modules/KeyVerificationModule.cpp Outdated
Comment thread src/modules/KeyVerificationModule.cpp Outdated
Review feedback from @Copilot on PR meshtastic#10258: strncpy(dst, src,
sizeof(dst)) does NOT guarantee NUL-termination when the source length
reaches or exceeds the buffer size. meshtastic_User.long_name is 40
bytes (39 usable chars + NUL), and remote_longname destinations are
similarly sized — a 40-char long_name would fill the buffer and leave
it unterminated. Downstream clients would then read garbage past the
buffer.

Fix: at each of the 4 strncpy call sites, copy sizeof(dst) - 1 bytes
and explicitly set the final byte to '\0'. Works whether the source
is short (strncpy zero-pads the trailing bytes naturally) or long
(we terminate at index sizeof-1).

Sites:
- handleReceivedProtobuf hash2 path
- handleReceivedProtobuf hash1-match banner callback path
- allocReply number-inform path
- processSecurityNumber final-confirmation path
@nightjoker7
Copy link
Copy Markdown
Contributor Author

Addressed in bfaa1cfed: at each of the 4 strncpy sites, copy sizeof(dst) - 1 and explicitly set the last byte to '\0'. Guarantees NUL-termination even when user.long_name fills the buffer.

Copy link
Copy Markdown
Collaborator

@jp-bennett jp-bennett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks OK to me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix Pull request that fixes bugs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants