Skip to content

null-terminate peer shm_name in HelloMessage::Deserialize - #3605

Merged
chenBright merged 1 commit into
apache:masterfrom
ubeddulla:ubring-shm-name-nul-terminate
Oct 18, 2026
Merged

chenBright merged 1 commit into
apache:masterfrom
ubeddulla:ubring-shm-name-nul-terminate

Conversation

@ubeddulla

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number:

Problem Summary:
On the UBRing handshake, HelloMessage::Deserialize copies the 48-byte shm_name straight from the peer's HELLO message and never terminates it. A peer that fills every byte of SHM_MAX_NAME_BUFF_LEN with non-zero data leaves the field without a '\0', and the server side then treats it as a C-string: strncpy into same-size buffers, strrchr, snprintf("%s", client_name), and the shm allocate/map/log calls in shm_ubs.cpp all walk past the 48-byte buffer. Under ASAN this is a stack-buffer-overflow READ in strrchr on client_name. SHM_MAX_NAME_LEN is defined as SHM_MAX_NAME_BUFF_LEN - 1, so a conforming name already leaves room for the terminator; only a malformed or hostile name reaches this.

What is changed and the side effects?

Changed:
HelloMessage::Deserialize sets shm_name[SHM_MAX_NAME_BUFF_LEN - 1] = '\0' after the copy so the decoded name is always a valid C-string within the buffer. Names of 47 bytes or fewer are unchanged. HelloMessageTest.full_shm_name now asserts the decoded name is terminated; it fails on the current tree and passes with this change.

Side effects:

  • Performance effects: none.

  • Breaking backward compatibility: none; a conforming peer already sends a terminated name.


Check List:

@chenBright
chenBright requested a lite review from Copilot October 14, 2026 02:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

2 open findings
What changed in this PR

This PR fixes a handshake safety issue where HelloMessage::Deserialize could leave shm_name unterminated, allowing downstream code that treats it as a C-string to read past the buffer.

Changes:

  • Force shm_name to be NUL-terminated after deserialization.
  • Update HelloMessageTest.full_shm_name to assert proper termination and length behavior.
File Description
test/​brpc_ubring_unittest.cpp Tightens the unit test to validate NUL-termination and bounded length of decoded shm_name.
src/​brpc/​ubshm/​ub_endpoint.cpp Ensures deserialized shm_name is always a valid C-string by forcing a terminator.

🧠 Review effort: Lite


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +147 to +150
// shm_name arrives verbatim from the peer and is used downstream as a
// C-string (strncpy/strrchr/snprintf("%s")/shm allocate+map). A peer that
// fills all SHM_MAX_NAME_BUFF_LEN bytes without a terminator would make
// those scans run past the buffer, so force termination here.
// A peer that fills every byte of shm_name leaves no terminator on the
// wire. Deserialize must still hand back a valid C-string, because the
// handshake feeds the decoded name straight into strncpy/strrchr/
// snprintf("%s") and the shm allocate/map calls; without a terminator
@wwbmmm

wwbmmm commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

LGTM

@chenBright chenBright left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@chenBright
chenBright merged commit 8d1523f into apache:master Oct 18, 2026
25 checks passed
Sherlock0203 added a commit to Sherlock0203/brpc that referenced this pull request Oct 19, 2026
Bring the apache master line up to f0239d7 into this branch in a
single merge, replacing the two stacked merges with master@36c2d12e
and the macOS fix only. Everything the branch needs from that line is
included: the data-format negotiation (apache#3507), the IPC_V2 data path
(apache#3573), the macOS OpenSSL 4.0 build fix (apache#3616: X509 accessors return
const pointers in the current macos-26-arm64 runner image, fixed with
auto*), and the newer fixes, notably the null-termination of the peer
shm_name in HelloMessage::Deserialize (apache#3605), the MPSC queue node
release ordering (apache#3620) and the MultiFlatMap bucket-head erasure fix
(apache#3617).

Those master changes were built on the timerfd-era close path, which
this branch had replaced with the bthread timer facade,
generation-checked pool teardown and the cleanup worker, so both sides
evolved the same ubshm core after 9334389.

Resolution:
- Close/clear core (UbrTrxClose, UbrTrxCloseCallback,
  UbrClearResourceCheck, ClearTrxResource, UbrPassiveClearTrx,
  UbrTrxCloseCheck) keeps this branch's versions. Master's extra
  start_time/op parameters were unused, and UbrCloseType only chose
  between DeleteTimerSafe and DeleteTimer, which the facade subsumes:
  UbrTimerDelAndWait degrades to the non-blocking delete inside a
  callback. The unused UbrCloseType enum is therefore dropped.
- Master's format-aware initialization is kept: UbrServerTrxInit keeps
  the UbrDataFormat parameter and the Initialize*LegacyFormat split,
  UbrAllocateServerShm/UbrMapRemoteShm(UbrMapRemoteShmAddTimer) keep
  passing it, and ApplyAndMapLocalShm no longer presets the rx capacity
  (InitializeClientLocalLegacyFormat owns that now). All IPC_V2 ring
  code and the negotiation handshake are master's, unchanged, with
  master-side UNLIKELY/LIKELY converted to the module's BAIDU_* macros.
- This branch's fixes that master lacked merge on top: the poller
  re-ADD refresh, butil::atomic for the poller-group flag, the lazy
  bthread timers replacing TimerInit, and the cleanup-worker changes
  (leaked queue, start retry instead of the terminal latch).
- test/brpc_ubring_unittest.cpp: master's IPC_V2 assertions on the
  removed timer_fd/hb_timer_fd fields check the unarmed
  close_timer/hb_timer slots instead, and the UbrCleanupWorkerTest that
  PR LinQuickDev#74's squash dropped is restored alongside master's apache#3605
  hardening of the full_shm_name test. Both sides' suites run.

Tested: the close/cleanup/IPC_V2 resolution was verified on the
equivalent tree before apache#3605 came in -- cmake WITH_UBRING=ON build,
31/31 unit tests, the same under ASAN (detect_leaks=0), and an
example/ubring_performance e2e over the IPC backend (negotiated IPC_V2
path at ~148k QPS, clean teardowns, server kill -9 handled). The new
master commits are additive to that resolution; cmake --build build
--target brpc_ubring_unittest and ./build/test/brpc_ubring_unittest
pass on this exact tree as well.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants