Skip to content

Database permission hardening races with SQLite WAL removal #309

Description

@munezaclovis

Summary

A reconciliation failed transiently because PV observed pv.db-wal, then SQLite removed the ephemeral WAL before PV could chmod/validate it:

state error: filesystem error at ~/.pv/pv.db-wal:
No such file or directory (os error 2)

The next reconciliation started normally 12 seconds later. The evidence points to a TOCTOU race in database-file permission hardening rather than database corruption.

Current code path

Database::open_with_migrations opens SQLite and calls secure_database_files before and after connection configuration/migrations: database.rs.

secure_database_files checks each database/WAL/SHM path for existence and then performs separate chmod/metadata operations: fs.rs.

The database-side files include ephemeral pv.db-wal and pv.db-shm: fs.rs.

The Project config watcher opens a writable/migrating Database every 100 ms poll: watcher.rs, increasing opportunities for the race.

Likely sequence:

  1. path_exists(pv.db-wal) returns true.
  2. SQLite checkpoints/closes and removes the WAL.
  3. secure_sensitive_file(pv.db-wal) receives ENOENT.
  4. The whole database open/reconciliation fails.

Expected behavior

Disappearance of SQLite's optional WAL/SHM files during secure inspection should be handled as a benign race. Real permission, ownership, or I/O failures must remain errors, and the persistent main database must still be hardened.

Acceptance criteria

  • A WAL or SHM file disappearing between discovery and chmod/metadata validation does not fail Database::open.
  • A missing persistent pv.db after creation/open is not silently ignored.
  • Permission and owner mismatches on existing database-side files still fail clearly.
  • Add deterministic coverage that removes an auxiliary file between existence observation and the security operation.
  • Preserve user-only permissions for database, WAL, and SHM whenever those files exist.
  • Verify Project watcher polling cannot create failed reconciliation jobs from this race.
  • Avoid broad retry loops or weakening filesystem ownership checks.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcontrol-planeControl-plane architecturepriority-mediumP2 medium priorityready-for-agentFully specified, ready for an AFK agentruntimeRuntime and toolchainvalue-mediumMedium value

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions