@@ -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. */
25462568static 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 }
0 commit comments