Skip to content

Commit a3560da

Browse files
authored
Merge pull request #8 from oroderico/restart-on-session-end
Reboot on the way out of a wallet session
2 parents f9266f3 + 6a4c40f commit a3560da

4 files changed

Lines changed: 42 additions & 18 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ never padded with blank rows. Only labels are listed. Values meant to be transcr
302302
instead, split by what fits the display.
303303

304304
The last row of every list with somewhere to return to is the way out of it —
305-
`Back`, `Erase and exit`, `[delete]` — and a rule is drawn above it so it is not
305+
`Back`, `Erase and restart`, `[delete]` — and a rule is drawn above it so it is not
306306
read as one more choice. That row is always last, in every such list, so
307307
leaving a screen is always in the same place. The one list with nowhere to
308308
return to is the main menu itself: there is no `Back` row there, and the

‎host/origo_simulator.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ static bool word_numbers_round_trip_is_sound(void)
431431
* last glyph that fits; nothing here is transcribed, but a silently shortened
432432
* label still misnames what the buttons are about to do. */
433433
static const char* const menu_labels[] = { "Master fingerprint", "Native SegWit (BIP84)", "Taproot (BIP86)",
434-
"Account key", "Addresses", "Account key format", "xpub", "zpub", "Erase and exit", "New Seed", "From entropy",
434+
"Account key", "Addresses", "Account key format", "xpub", "zpub", "Erase and restart", "New Seed", "From entropy",
435435
"Restore Seed", "Complete checksum", "About", "Settings", "11 words + 7 coins", "23 words + 3 coins",
436436
"No passphrase", "Enter passphrase", "D6 dice", "D20 dice", "Coin flips", "Cards", "Back", "12 words",
437437
"24 words", "[delete]", "[back]", "Type the letters", "Enter word numbers", "Plain text", "Backup",

‎main/seedtool_app.c‎

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,9 +1266,11 @@ static int review_and_confirm(char words[][SEEDTOOL_MAX_WORD_LEN + 1], const siz
12661266
* address_labels: these rows are the mnemonic in plain text, one word
12671267
* each, and they live in .bss rather than on a stack frame that the next
12681268
* screen would overwrite anyway. Leaving them behind kept a restored seed
1269-
* readable in RAM for the rest of the session - past "Erase and exit" and
1270-
* past the session-timeout screen, which erases nothing here. Clearing on
1271-
* entry as well as exit keeps a 12-word restore from leaving rows 12..23
1269+
* readable in RAM for the rest of the session. Both ways out of the wallet
1270+
* now reboot, and C startup zeroes .bss, so that particular leak would no
1271+
* longer outlive the session - but this wipe is what makes the rows gone
1272+
* while the session is still running, which the reboot cannot do. Clearing
1273+
* on entry as well as exit keeps a 12-word restore from leaving rows 12..23
12721274
* of a previous 24-word one on show. */
12731275
seedtool_zero(review_labels, sizeof(review_labels));
12741276
for (;;) {
@@ -2149,10 +2151,26 @@ static void show_wallet_data(const char* mnemonic)
21492151
(void)snprintf(wallet_title, sizeof(wallet_title), "Wallet @%s", fphex);
21502152
size_t cursor = 0;
21512153
for (;;) {
2152-
const char* menu[] = { "Backup", "Extended public key", "Derivation", "Addresses", "Erase and exit" };
2154+
const char* menu[] = { "Backup", "Extended public key", "Derivation", "Addresses", "Erase and restart" };
21532155
const int selected = choose_kept(wallet_title, menu, sizeof(menu) / sizeof(menu[0]), true, &cursor);
2156+
/* Both ways out of a wallet session reboot: the row, and the timeout
2157+
* that means the reader walked away from a device with a seed on it.
2158+
* Unwinding instead would leave every buffer between here and the main
2159+
* menu holding what it last held, wiped only where someone remembered
2160+
* to wipe it. A restart re-runs C startup, which zeroes .bss - the
2161+
* address cache and the review rows live there - and leaves nothing on
2162+
* a stack that is about to be reused from the top. The explicit wipes
2163+
* below still run first: the reboot is the belt, not a reason to drop
2164+
* the braces.
2165+
*
2166+
* The cost is the display settings, which are RAM-only by design and
2167+
* so go back to their defaults. That is the trade this makes
2168+
* deliberately: brightness is a preference, and the seed is not. */
21542169
if (selected < 0 || selected == 4) {
2155-
break;
2170+
seedtool_zero(fp, sizeof(fp));
2171+
seedtool_zero(fphex, sizeof(fphex));
2172+
seedtool_zero(passphrase, sizeof(passphrase));
2173+
seedtool_platform_restart();
21562174
}
21572175
switch (selected) {
21582176
case 0:
@@ -2538,11 +2556,15 @@ static int collect_entropy(const int source, const size_t words)
25382556
return outcome;
25392557
}
25402558

2541-
/* Returns whether a seed was actually generated and carried all the way
2542-
* through the wallet viewer to Erase and exit (or a timeout) - as opposed to the
2543-
* reader backing out of the source or length picker before ever starting.
2559+
/* Returns whether a seed was actually generated, as opposed to the reader
2560+
* backing out of the source or length picker before ever starting.
25442561
* show_new_seed_menu uses this to tell "done, go all the way home" apart from
2545-
* plain "back one level". */
2562+
* plain "back one level".
2563+
*
2564+
* Since leaving the wallet viewer reboots, the true case now only reaches its
2565+
* caller when the viewer returned without ever opening - a derivation failure
2566+
* on the way in. The distinction still has to exist for that, and for the
2567+
* false case, which is the ordinary back-out. */
25462568
static bool create_seed(void)
25472569
{
25482570
size_t cursor = 0;
@@ -2643,12 +2665,14 @@ static void show_new_seed_menu(void)
26432665
if (selected < 0 || selected == 2) {
26442666
return;
26452667
}
2646-
/* A seed that made it all the way to Erase and exit (or a timeout) closes
2647-
* this menu too, straight back to the Origo/Home menu, rather than
2648-
* reopening "New Seed" - that reopening was the actual bug: pressing
2649-
* Erase and exit landed back inside New Seed instead of at Home. Backing
2650-
* out of the source/length picker before anything was generated
2651-
* keeps the old "one level up" behaviour. */
2668+
/* A seed that was generated closes this menu too, straight back to the
2669+
* Origo/Home menu, rather than reopening "New Seed" - that reopening
2670+
* was the actual bug: ending a session landed back inside New Seed
2671+
* instead of at Home. Leaving the wallet viewer now reboots, which
2672+
* settles that case before it gets here; what is left for this to
2673+
* handle is the viewer failing to open at all. Backing out of the
2674+
* source/length picker before anything was generated keeps the old
2675+
* "one level up" behaviour. */
26522676
if (selected == 0 ? create_seed() : complete_checksum()) {
26532677
return;
26542678
}

‎main/seedtool_render.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ void seedtool_render_list(const char* title, const char* const* items, const siz
486486
const bool highlighted = top + row == selected;
487487
const int y = LIST_TOP + (int)row * LIST_ROW_HEIGHT;
488488
/* The last row of every list is the way out of it — Back, Erase and
489-
* exit, [delete]. A rule above it lifts it out of the choices,
489+
* restart, [delete]. A rule above it lifts it out of the choices,
490490
* which is what it is not. It goes in the gap between cells so the
491491
* selection bar never paints over it. */
492492
if (top + row == count - 1 && count > 1) {

0 commit comments

Comments
 (0)