Skip to content

fix(ergasia,exousia): ref-count shared torrent_ids and constant-time login miss-path (#536, #540) - #572

Merged
forkwright merged 1 commit into
mainfrom
audit/misc
Jul 6, 2026
Merged

fix(ergasia,exousia): ref-count shared torrent_ids and constant-time login miss-path (#536, #540)#572
forkwright merged 1 commit into
mainfrom
audit/misc

Conversation

@forkwright

Copy link
Copy Markdown
Owner

Two verified fixes from the 2026-07-03 deep-audit workflow (adversarially verified + Opus-judged).

#536 — deleting one download destroyed a sibling's live torrent (ergasia). librqbit dedups a duplicate info-hash onto one torrent_id (returns AlreadyManaged), so two DownloadIds could map to the same torrent_id; delete_torrent then unconditionally called session.delete() on that shared id, destroying the other download's still-live torrent until a restart reconcile pruned it. Added a torrent_refcounts: DashMap<usize, usize> reverse index: acquire_torrent_ref on every mapping insert (add, delete-failure restore, reconcile-from-disk), release_torrent_ref on delete. session.delete() now runs only when the ref count hits zero; an earlier owner just drops its own mapping entry and leaves the torrent live. The decrement-and-test runs entirely inside DashMap's Entry shard lock, so two concurrent releases for one torrent_id can never both observe "last reference". Regression test (multi_thread) registers two DownloadIds onto one torrent_id, deletes the first, asserts the second's stats still resolve and the librqbit torrent is still present, then deletes the second and asserts it's gone.

#540 — login timing side-channel enabled username enumeration (exousia, SECURITY / CWE-203). login() returned InvalidCredentials immediately on a username miss but ran a full Argon2id verify when the username existed, so response latency alone distinguished existing from non-existing accounts. Fixed by routing both branches through a single verify_password call: against the real hash when the row exists, otherwise against a fixed precomputed Argon2id sentinel hash (default m=19456,t=2,p=1 params matching hash_password), so a non-existent (or too-corrupt-to-convert) username costs the same Argon2id work and wall-clock time as a real wrong-password attempt. The verify runs before the is_active check, keeping inactive accounts indistinguishable too. A #[cfg(test)] thread-local verify-call spy proves both miss-paths exercise exactly one Argon2id verify; a third test guards that the sentinel constant parses as valid PHC and never matches.

Gate: kanon gate --full green — fmt, check, clippy (-D warnings), nextest 1919 passed, deny, kanon lint (0/0/0). Two gate iterations fixed a collapsible_if, a deprecated-term lint, and a no-silent-result-swallow at root (not suppressed). Gate-Passed trailer stamped.

Closes #536
Closes #540

…login miss-path (#536, #540)

Gate-Passed: kanon 0.1.5 +stages:fmt,check,clippy,nextest,lint sha:fc0cd364788602ae6bd80e0307bff6d2562bf387
@forkwright
forkwright merged commit b899fee into main Jul 6, 2026
12 checks passed
@forkwright
forkwright deleted the audit/misc branch July 6, 2026 22:05
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.

auth: login timing side-channel enables username enumeration torrent lifecycle: duplicate torrent_id delete destroys sibling download

1 participant