summaryrefslogtreecommitdiffstats
path: root/piolium/attack-surface/state-concurrency-summary.md
blob: 48677b3fc709054bdd4a50383165e7c7d883f811 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# State & Concurrency Audit

## State-Holding Entities Catalogued

| Entity | Table | State Columns | Allowable Values | Concurrency Risk |
|--------|-------|---------------|-----------------|------------------|
| Account | `accounts` | `is_superuser` | 0/1 | Low (rarely mutated) |
| Account | `accounts` | `password_change_required` | 0/1 | Low |
| Session | `sessions` | `created_at` | datetime | **High** — no TTL enforcement |
| Instance | `instances` | `is_active` | 0/1 | **CRITICAL** — background task stale writes |
| Instance | `instances` | `container_state` | stopped/pulling/booting/running/error | **CRITICAL** — not bound to instance ID in background writes |
| Instance | `instances` | `has_modpack` | 0/1 | Medium — RMW across mutex acquisitions |
| Instance | `instances` | `name` | TEXT (UNIQUE) | **HIGH** — name-reuse race between delete and create |
| Mod | `mods` | `accepted` | 0/1 | Low |
| Backup | `backups` | `filename`, `created_at` | TEXT, datetime | Medium — orphan ZIP on concurrent delete |
| All | — | — | — | **No idempotency infrastructure** |

**Total state-holding entities catalogued:** 10 (across 5 tables)

## Concurrency Primitives Observed

| Primitive | Location | Scope | Limitation |
|-----------|----------|-------|------------|
| `Arc<Mutex<Connection>>` | `src/db.rs:7` | SQLite connection | Serialises per-statement, not per-transaction |
| `MutexGuard::drop()` implicit | Every `let conn = state.db.conn()` / `drop(conn)` pattern | Statement boundaries | Mutex released between read and write in multiple handlers |
| Tokio async tasks (background spawn) | `src/routes/instances.rs:457` | container lifecycle | **No instance ID binding** — uses `WHERE is_active = 1` |
| SQLite WAL mode | `src/db.rs:19` (PRAGMA) | Write-ahead logging | Allows concurrent reads during writes but does not prevent any of the races documented |

**No distributed locks, no advisory locks, no `SELECT ... FOR UPDATE`, no explicit BEGIN/COMMIT boundaries.**

## Idempotency Infrastructure

**Absent.** No `idempotency_key` table, no deduplication tokens, no request ID storage, no unique constraints leveraged for dedup (except `accounts.username` and `instances.name`). Every POST handler is vulnerable to replay/double-submit.

## Drafts Filed

| Draft | Severity | Class | Summary |
|-------|----------|-------|---------|
| p6-001 | CRITICAL | toctou | Background task in `activate_instance` uses `WHERE is_active = 1` (no instance ID bound). After deactivation/reactivation, stale task writes `container_state` on the wrong instance. |
| p6-002 | HIGH | toctou | `delete_instance` releases DB mutex before `remove_dir_all`. Concurrent `create_instance` with same name has its data directory wiped. Cross-resource TOCTOU with data loss. |
| p6-003 | MEDIUM | state-machine-violation | `edit_instance` stops container on active instances without restarting. `is_active=1` and stale `container_state='running'` persist. Instance appears running but isn't. |
| p6-004 | HIGH | idempotency | No idempotency infrastructure on any POST handler. Mod upload, backup create, login, account create all vulnerable to replay/double-submit. |
| p6-005 | MEDIUM | rmw-no-txn | `process_jar_upload` writes file to disk before DB INSERT. Crash between file write and DB insert leaves orphaned mod file. Also performs `has_modpack` update across separate mutex acquisition. |
| p6-006 | MEDIUM | toctou | `create_backup` reads instance name, releases mutex, creates ZIP file (long I/O window), then re-acquires mutex. Concurrent instance deletion causes FK violation — orphaned ZIP file with no DB record. |

**Total draft findings filed: 6**