Skip to content

Commit 8a2c1c0

Browse files
committed
Make trustdb walker read-only
The trust database walker was documented as a read-only CLI operation, but it opened the daemon's live LMDB environment through init_db(). That path can create metadata, start a write transaction, use lock.mdb, and mutate global daemon database state. The walker now owns a private MDB_RDONLY|MDB_NOLOCK environment, opens the active named trust database from metadata, and keeps only its read transaction and cursor alive while iterating. It no longer calls init_db(), trust_db_read_open(), or close_db().
1 parent e2d52cd commit 8a2c1c0

1 file changed

Lines changed: 127 additions & 38 deletions

File tree

src/library/database.c

Lines changed: 127 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,6 @@ struct trust_db_metrics {
272272
};
273273

274274
static struct trust_db_metrics trust_metrics;
275-
static struct trust_db_read_handle walk_read;
276275

277276
struct trust_db_sizing_state {
278277
size_t page_size;
@@ -373,6 +372,7 @@ static int do_memfd_update_to_dbi_in_env(MDB_env *target_env, int memfd,
373372
MDB_dbi target_dbi, unsigned int maxkeysize, long *entries);
374373
static void close_env(int do_close_dbi);
375374
static void log_lmdb_state(int priority, const char *context, int lmdb_rc);
375+
static void walk_database_reset(void);
376376

377377
// External variables
378378
extern atomic_bool stop;
@@ -2633,7 +2633,6 @@ static void close_env(int do_close_dbi)
26332633
env = NULL;
26342634
dbi_init = 0;
26352635
metadata_dbi_init = 0;
2636-
memset(&walk_read, 0, sizeof(walk_read));
26372636
}
26382637

26392638
struct lmdb_reader_log {
@@ -5518,65 +5517,150 @@ void database_compact_from_backends(conf_t *config)
55185517
* only operation.
55195518
***********************************************************************/
55205519
static walkdb_entry_t wdb_entry;
5520+
static MDB_env *walk_env;
5521+
static MDB_txn *walk_txn;
5522+
static MDB_cursor *walk_cursor;
55215523

5522-
// Returns WALK_DATABASE_SUCCESS, WALK_DATABASE_EMPTY, or WALK_DATABASE_ERROR
5524+
/*
5525+
* walk_database_reset - close private read-only CLI walk state.
5526+
* @void: no arguments are required.
5527+
*
5528+
* The walker owns these handles. They are intentionally separate from the
5529+
* daemon's global LMDB environment so cleanup here never closes or mutates
5530+
* daemon state.
5531+
*
5532+
* Returns nothing.
5533+
*/
5534+
static void walk_database_reset(void)
5535+
{
5536+
if (walk_cursor)
5537+
mdb_cursor_close(walk_cursor);
5538+
if (walk_txn)
5539+
mdb_txn_abort(walk_txn);
5540+
if (walk_env)
5541+
mdb_env_close(walk_env);
5542+
walk_cursor = NULL;
5543+
walk_txn = NULL;
5544+
walk_env = NULL;
5545+
}
5546+
5547+
/*
5548+
* walk_database_start - open the trust DB for CLI verification.
5549+
* @config: Unused legacy argument kept for the CLI walker API.
5550+
*
5551+
* This must stay a read-only walk. Do not call init_db() or
5552+
* trust_db_read_open() here: those paths open the daemon-style environment and
5553+
* may take write-side LMDB state while setting up handles. The CLI verifier
5554+
* only needs a private read transaction and cursor over the active named DB.
5555+
*
5556+
* Returns WALK_DATABASE_SUCCESS, WALK_DATABASE_EMPTY, or WALK_DATABASE_ERROR.
5557+
*/
55235558
int walk_database_start(conf_t *config)
55245559
{
5560+
MDB_dbi walk_metadata_dbi, walk_dbi;
5561+
struct trust_db_metadata metadata;
5562+
char active_name[TRUST_DB_GENERATION_NAME_SIZE];
55255563
int rc;
55265564

5527-
// Initialize the database
5528-
if (init_db(config)) {
5529-
printf("Cannot open the trust database\n");
5530-
return WALK_DATABASE_ERROR;
5531-
}
5532-
rc = database_empty();
5533-
if (rc > 0) {
5534-
printf("The trust database is empty - nothing to do\n");
5535-
close_db(0);
5536-
return WALK_DATABASE_EMPTY;
5537-
} else if (rc < 0) {
5538-
close_db(0);
5539-
return WALK_DATABASE_ERROR;
5540-
}
5565+
(void)config;
5566+
walk_database_reset();
5567+
snprintf(active_name, sizeof(active_name), "%s", db);
55415568

5542-
// Position to the first entry
5543-
if (trust_db_read_open(&walk_read)) {
5544-
puts("Cannot open the trust database for reading");
5545-
close_db(0);
5569+
rc = mdb_env_create(&walk_env);
5570+
if (rc) {
5571+
printf("Cannot create the trust database environment\n");
55465572
return WALK_DATABASE_ERROR;
55475573
}
55485574

5549-
if ((rc = mdb_cursor_get(walk_read.cursor, &wdb_entry.path,
5550-
&wdb_entry.data,
5551-
MDB_FIRST)) == 0)
5575+
rc = mdb_env_set_maxdbs(walk_env, TRUST_DB_MAX_NAMED_DBS);
5576+
if (rc)
5577+
goto error;
5578+
5579+
/*
5580+
* MDB_NOLOCK is paired with MDB_RDONLY so the verifier never opens
5581+
* lock.mdb or touches LMDB's shared robust mutexes.
5582+
*/
5583+
rc = mdb_env_open(walk_env, data_dir, MDB_RDONLY|MDB_NOLOCK, 0);
5584+
if (rc)
5585+
goto error;
5586+
5587+
rc = mdb_txn_begin(walk_env, NULL, MDB_RDONLY, &walk_txn);
5588+
if (rc)
5589+
goto error;
5590+
5591+
rc = mdb_dbi_open(walk_txn, TRUST_DB_METADATA_NAME, 0,
5592+
&walk_metadata_dbi);
5593+
if (rc == 0) {
5594+
rc = trust_db_metadata_read_from_dbi(walk_txn, walk_metadata_dbi,
5595+
&metadata);
5596+
if (rc == 0)
5597+
snprintf(active_name, sizeof(active_name), "%s",
5598+
metadata.name);
5599+
else if (rc != MDB_NOTFOUND)
5600+
goto error;
5601+
} else if (rc != MDB_NOTFOUND)
5602+
goto error;
5603+
5604+
rc = mdb_dbi_open(walk_txn, active_name, MDB_DUPSORT, &walk_dbi);
5605+
if (rc)
5606+
goto error;
5607+
5608+
rc = mdb_cursor_open(walk_txn, walk_dbi, &walk_cursor);
5609+
if (rc)
5610+
goto error;
5611+
5612+
/*
5613+
* Keep walk_txn open for the cursor lifetime. The returned MDB_val
5614+
* buffers point into LMDB-managed memory and remain valid until the
5615+
* cursor/transaction is closed by walk_database_reset().
5616+
*/
5617+
rc = mdb_cursor_get(walk_cursor, &wdb_entry.path, &wdb_entry.data,
5618+
MDB_FIRST);
5619+
if (rc == 0) {
5620+
/* Keep handles open so walk_database_next() can continue. */
55525621
return WALK_DATABASE_SUCCESS;
5622+
}
55535623

5554-
if (rc != MDB_NOTFOUND) {
5555-
puts(mdb_strerror(rc));
5556-
rc = WALK_DATABASE_ERROR;
5557-
} else {
5624+
if (rc == MDB_NOTFOUND) {
55585625
printf("The trust database is empty - nothing to do\n");
5559-
rc = WALK_DATABASE_EMPTY;
5626+
walk_database_reset();
5627+
return WALK_DATABASE_EMPTY;
55605628
}
55615629

5562-
trust_db_read_close(&walk_read);
5563-
close_db(0);
5564-
return rc;
5630+
error:
5631+
if (rc)
5632+
puts(mdb_strerror(rc));
5633+
walk_database_reset();
5634+
return WALK_DATABASE_ERROR;
55655635
}
55665636

5637+
/*
5638+
* walk_database_get_entry - return the current walker entry.
5639+
* @void: no arguments are required.
5640+
*
5641+
* The entry's MDB_val buffers are owned by LMDB and are valid until the next
5642+
* walk_database_next() call or walk_database_finish().
5643+
*
5644+
* Returns a pointer to the current walker entry.
5645+
*/
55675646
walkdb_entry_t *walk_database_get_entry(void)
55685647
{
55695648
return &wdb_entry;
55705649
}
55715650

5572-
// Returns 1 on success and 0 in error
5651+
/*
5652+
* walk_database_next - advance the CLI verification cursor.
5653+
* @void: no arguments are required.
5654+
*
5655+
* Returns 1 when another entry is available and 0 at end of walk or on error.
5656+
*/
55735657
int walk_database_next(void)
55745658
{
55755659
int rc;
55765660

5577-
if ((rc = mdb_cursor_get(walk_read.cursor, &wdb_entry.path,
5578-
&wdb_entry.data,
5579-
MDB_NEXT)) == 0)
5661+
rc = mdb_cursor_get(walk_cursor, &wdb_entry.path, &wdb_entry.data,
5662+
MDB_NEXT);
5663+
if (rc == 0)
55805664
return 1;
55815665

55825666
if (rc != MDB_NOTFOUND)
@@ -5585,8 +5669,13 @@ int walk_database_next(void)
55855669
return 0;
55865670
}
55875671

5672+
/*
5673+
* walk_database_finish - close the CLI verification cursor.
5674+
* @void: no arguments are required.
5675+
*
5676+
* Returns nothing.
5677+
*/
55885678
void walk_database_finish(void)
55895679
{
5590-
trust_db_read_close(&walk_read);
5591-
close_db(0);
5680+
walk_database_reset();
55925681
}

0 commit comments

Comments
 (0)