fix(launcher): verify self-update rollback sources
This commit is contained in:
parent
1955ca8ab5
commit
09d84387a8
6 changed files with 949 additions and 103 deletions
|
|
@ -580,11 +580,11 @@ owns the lease and therefore releases after process death.
|
|||
|
||||
Launcher self-update staging lives at
|
||||
`DataDirectory/launcher-update/transactions/<transactionId>/` and the sole
|
||||
durable authority is `DataDirectory/launcher-update/pending.json` (schema 2):
|
||||
durable authority is `DataDirectory/launcher-update/pending.json` (schema 3):
|
||||
|
||||
```json
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"schemaVersion": 3,
|
||||
"transactionId": "0123456789abcdef0123456789abcdef",
|
||||
"state": "staged",
|
||||
"version": "1.2.3",
|
||||
|
|
@ -608,18 +608,54 @@ owned metadata path, and obsolete paths from the previous ownership record:
|
|||
|
||||
```json
|
||||
[
|
||||
{ "path": "acdream-launcher.exe", "operation": "install", "hadOriginal": true },
|
||||
{ "path": "obsolete.dll", "operation": "remove", "hadOriginal": true }
|
||||
{
|
||||
"path": "acdream-launcher.exe",
|
||||
"operation": "install",
|
||||
"hadOriginal": true,
|
||||
"priorSha256": "<64 hex characters>",
|
||||
"priorSize": 123,
|
||||
"priorUnixMode": 0,
|
||||
"replacementSha256": "<64 hex characters>",
|
||||
"replacementSize": 456,
|
||||
"replacementUnixMode": 0
|
||||
},
|
||||
{
|
||||
"path": "new-support.dat",
|
||||
"operation": "install",
|
||||
"hadOriginal": false,
|
||||
"priorSha256": null,
|
||||
"priorSize": null,
|
||||
"priorUnixMode": null,
|
||||
"replacementSha256": "<64 hex characters>",
|
||||
"replacementSize": 456,
|
||||
"replacementUnixMode": 0
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Every `hadOriginal` entry persists the exact pre-mutation SHA-256, length, and
|
||||
Linux mode bits; a no-original entry has all three prior fields null. Every
|
||||
install entry likewise persists the verified replacement metadata, while a
|
||||
remove entry has all three replacement fields null. The journal is invalid
|
||||
unless those fields agree with `hadOriginal` and `operation`.
|
||||
|
||||
Existing targets are replaced with one same-filesystem atomic replace whose
|
||||
backup is also target-local. Previously absent noncanonical files use one
|
||||
same-filesystem rename; obsolete owned files use one rename into backup. The
|
||||
canonical launcher path therefore contains either the complete old file or the
|
||||
complete new file at every durable crash boundary. Rollback reverses the same
|
||||
operations atomically and is idempotent after a process/power loss. Linux mode
|
||||
bits come from the verified incoming file. A helper that cannot immediately
|
||||
complete new file at every durable crash boundary. Rollback first performs a
|
||||
zero-mutation preflight of the complete target-local transaction and every
|
||||
journal entry. It rejects reparse points, unsafe parents, unrecorded paths,
|
||||
ambiguous file layouts, and any SHA-256/length/mode mismatch in a prior,
|
||||
incoming, or discard file. Only a fully preflighted rollback may atomically
|
||||
restore backups; newly created files move to target-local discard rather than
|
||||
being deleted. The complete prior target set is then reverified before the
|
||||
plan enters durable `rolledBack` state while retaining the journal. Retry is
|
||||
allowed only after that prior set is reverified again and the plan returns to
|
||||
`staged`. Thus rollback is atomic per file and idempotent after a process/power
|
||||
loss. Any ambiguity preserves the applying plan and transaction evidence and
|
||||
forbids launching the canonical path for manual recovery. Linux mode bits come
|
||||
from the verified incoming file. A helper that cannot immediately
|
||||
acquire the exclusive update lease defers the staged plan and exits without
|
||||
restarting the old launcher, preventing restart loops.
|
||||
|
||||
|
|
@ -645,6 +681,9 @@ instruction, after which the helper releases its lease and the confirmed
|
|||
launcher reclaims plan, data-transaction, and target-local residue. An
|
||||
`applying` plan is rolled back before retry, and failure to start/confirm the
|
||||
new launcher restores every original (and removes every no-original target).
|
||||
The helper restarts the restored canonical launcher only after a fresh complete
|
||||
verification of the retained `rolledBack` journal; rollback corruption or an
|
||||
unsafe backup/discard tree exits without starting either launcher.
|
||||
Reading `pending.json` never performs cleanup. Ordinary startup attempts the
|
||||
exclusive lease without waiting and skips update cleanup entirely when another
|
||||
session/staging transaction owns it. All plan paths are re-derived/contained
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue