Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Database reads on key-related fields should be atomic #5177

Closed
AaronFeickert opened this issue Feb 13, 2023 · 0 comments · Fixed by #5178
Closed

Database reads on key-related fields should be atomic #5177

AaronFeickert opened this issue Feb 13, 2023 · 0 comments · Fixed by #5178

Comments

@AaronFeickert
Copy link
Collaborator

It was pointed out that database reads on multiple fields have no inherent guarantee of consistency, and may return unexpected results due to write operations. However, SQLite apparently does guarantee read consistency within a read-only transaction.

While the use case in question will fail safe in the event this edge case happens, it's something of a footgun to rely on failed key derivation to catch this.

A more comprehensive and general approach to read transactions may be warranted, but for now, the read operations used for key-related database fields (version identifier, secondary key salt, and encrypted main key) should be done atomically. Even if these reads produce outdated but consistent data due to a write transaction, they will still produce a valid database cipher with the correct main key.

This is also a good opportunity to refactor the atomic write operations for these same fields to reduce code duplication and make intent more clear.

stringhandler pushed a commit that referenced this issue Feb 14, 2023
Description
---
Refactors key-related database field operations to be atomic.

Closes [issue 5177](#5177). 

Motivation and Context
---
Key-related database fields always travel together. We need a consistent set of secondary key version identifier, secondary key salt, and encrypted main key in order to set up the `XChaCha20-Poly1305` cipher used for database encryption operations and passphrase changes.

While a [recent PR](#5175) ensures that write operations for these fields are done atomically via a write transaction, there is no corresponding read transaction. It's therefore possible that those fields are inconsistent. While this should only result in an error and require the user to load their wallet again, it seemed like a smart idea to ensure that reads are consistent for any future use cases.

This PR refactors the handling of those fields to reduce redundancy and ensure atomicity for reads and writes. It introduces a new `DatabaseKeyFields` struct that handles reads and writes, and additionally takes care of encoding and decoding of the underlying data.

It also makes the handling of the three fields more consistent. Previously, individual reads and writes required the use of a complex `match` to handle different states. This functionality has been mostly moved into `DatabaseKeyFields` to make these states more apparent.

How Has This Been Tested?
---
Existing unit tests pass. Manually tested the following operations:
- setting up a new wallet and successfully loading it with the correct passphrase
- setting up a new wallet and unsuccessfully loading it with an incorrect passphrase
- setting up a new wallet and unsuccessfully loading it due to a simulated read transaction failure
- failing to set up a new wallet due to a simulated write transaction failure
- failing to set up a new wallet due to a simulated read transaction failure
- a successful passphrase change via CLI
- an unsuccessful passphrase change via CLI due to an incorrect existing passphrase
- an unsuccessful passphrase change via CLI due to a mismatched new passphrase
- an unsuccessful passphrase change via CLI due to a simulated write transaction failure
- an unsuccessful passphrase change via CLI due to a simulated read transaction failure

It does not seem possible to directly test read operation inconsistency caused by a simultaneous write operation.
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 a pull request may close this issue.

1 participant