Skip to content

fix(rep,cds): don't crash on two NULL slots reachable from public APIs (#149) - #155

Merged
gburd merged 1 commit into
masterfrom
fix/149-null-derefs
Sep 7, 2026
Merged

fix(rep,cds): don't crash on two NULL slots reachable from public APIs (#149)#155
gburd merged 1 commit into
masterfrom
fix/149-null-derefs

Conversation

@gburd

@gburd gburd commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Fixes #149. Both parts reproduced as hard SIGSEGVs from documented public APIs with valid arguments, then fixed and gated.

1. rep_get_nsites() on a repmgr-configured but unopened environment

Program received signal SIGSEGV
#0  __repmgr_get_nsites (...) at ../src/repmgr/repmgr_util.c:520
#1  main () at b.c:10

__repmgr_get_nsites() dereferenced db_rep->region, which is only attached at env open. The caller's guard is the problem: ENV_NOT_CONFIGURED() expands to nothing until ENV_OPEN_CALLED is set (src/dbinc/db_int.in:614), so a pre-open call fell straight through.

Now returns the BDB3672 Nsites unknown before repmgr_start() error the function already had for the analogous unknown-nsites case. Note the trigger is touching any repmgr setting — that allocates DB_REP without attaching its region. A plain db_env_create + rep_get_nsites does not crash, which is why this needed the repmgr variant to reproduce.

2. __cdsgroup_begin() left 4 of DB_TXN's 12 method slots NULL

get_priority, set_priority, set_commit_token, set_txn_lsnp — calling any one was an indirect call through a NULL function pointer.

The three int-returning slots now use the file's existing __cdsgroup_notsup() helper (DB_OPNOTSUP, "CDS groups do not support %s"), matching the eight already-installed methods. set_txn_lsnp is declared void and so cannot report an error — it nulls its out-parameters instead, which is what the log-path callers already test for.

Test

test/db/null_method_slots.c — 9 checks:

  rep_get_nsites(unopened env): ret=22 (Invalid argument)
  cdsgroup get_priority:     ret=95
  cdsgroup set_priority:     ret=95
  cdsgroup set_commit_token: ret=95
  cdsgroup set_txn_lsnp:     rlsnp=(nil) lsnp=(nil)
null_method_slots: 9 checks, 0 failures

It asserts each slot is non-NULL and that calling it returns, and skips case 1 gracefully if a build lacks repmgr. Proven to have teeth: reverting either fix makes the runner report FAIL (rc=139, Segmentation fault). Wired into the CI regression-runner step.

Notes

  • No new message ids — both paths reuse existing strings (3672, 0687), so dist/s_message_id is unaffected (verified: it rewrites nothing).
  • Regression: 6/6 test/db runners, lockmatrix, isolation, soak, fuzz all PASS.

Found by the coverage-driver work in #147.

Fixes #149. Both reproduced as hard SIGSEGVs, then fixed and gated.

1. DB_ENV->rep_get_nsites() on a repmgr-configured but UNOPENED environment.
   __repmgr_get_nsites() (src/repmgr/repmgr_util.c:520) dereferenced
   db_rep->region, which is only attached at env open. The caller's guard,
   ENV_NOT_CONFIGURED(), expands to nothing until ENV_OPEN_CALLED is set
   (src/dbinc/db_int.in:614), so a pre-open call fell straight through:

     Program received signal SIGSEGV
     #0  __repmgr_get_nsites (...) at ../src/repmgr/repmgr_util.c:520
     #1  main () at b.c:10

   It now reports the same BDB3672 'Nsites unknown before repmgr_start()' error
   the function already had for the analogous unknown-nsites case.

2. __cdsgroup_begin() installed only 8 of DB_TXN's 12 methods, leaving
   get_priority, set_priority, set_commit_token and set_txn_lsnp as NULL
   function pointers, so calling one was an indirect call through NULL.
   The three int-returning slots now use the file's existing
   __cdsgroup_notsup() helper (DB_OPNOTSUP, 'CDS groups do not support %s').
   set_txn_lsnp is declared void and so cannot report an error; it nulls its
   out-parameters instead, which is what the log-path callers already test for.

No new message ids: both paths reuse existing strings (3672, 0687), so
dist/s_message_id is unaffected.

test/db/null_method_slots.c (9 checks) covers both, asserts all four slots are
non-NULL as well as callable, and skips case 1 gracefully if a build has no
repmgr. Proven to have teeth: reverting either fix makes the runner report
FAIL (rc=139, Segmentation fault). Added to the CI regression-runner step.

Found by the coverage-driver work in #147.
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

Coccinelle convention checks

No new violations. ✅

Resolved since baseline (2) -- update dist/cocci/baseline.txt to lock these in.
rule_mutex_unbalanced|MUTEX_UNBALANCED|src/crypto/mersenne/mt19937db.c|return (ret);
rule_mutex_unbalanced|MUTEX_UNBALANCED|src/mp/mp_register.c|return (ret);

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

ABI diff vs v5.3.34 (libabigail — authoritative)

Functions changes summary: 0 Removed, 0 Changed, 2 Added functions
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable

2 Added functions:

  [A] 'function int __lock_sireap_lockers(ENV*)'    {__lock_sireap_lockers}
  [A] 'function int __os_csprng(ENV*, void*, size_t)'    {__os_csprng}

Removed exported symbols (nm -D, _NNNN version suffix normalized)

None.


Advisory: libabigail/nm is the authoritative binary-ABI check; Coccinelle is complementary source-level early warning. See dist/cocci/README.md.

@gburd
gburd merged commit 6d2b071 into master Sep 7, 2026
50 of 52 checks passed
@gburd
gburd deleted the fix/149-null-derefs branch September 7, 2026 12:15
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.

NULL dereference: DB_ENV->rep_get_nsites() and DB_TXN method gaps in __cdsgroup_begin

1 participant