Prepare v2024.10
[platform/kernel/u-boot.git] / common / autoboot.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2000
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  */
6
7 #include <config.h>
8 #include <autoboot.h>
9 #include <bootretry.h>
10 #include <cli.h>
11 #include <command.h>
12 #include <console.h>
13 #include <env.h>
14 #include <errno.h>
15 #include <fdtdec.h>
16 #include <hash.h>
17 #include <log.h>
18 #include <malloc.h>
19 #include <memalign.h>
20 #include <menu.h>
21 #include <post.h>
22 #include <time.h>
23 #include <asm/global_data.h>
24 #include <linux/delay.h>
25 #include <u-boot/sha256.h>
26 #include <bootcount.h>
27 #include <crypt.h>
28 #include <dm/ofnode.h>
29
30 DECLARE_GLOBAL_DATA_PTR;
31
32 #define DELAY_STOP_STR_MAX_LENGTH 64
33
34 #ifndef DEBUG_BOOTKEYS
35 #define DEBUG_BOOTKEYS 0
36 #endif
37 #define debug_bootkeys(fmt, args...)            \
38         debug_cond(DEBUG_BOOTKEYS, fmt, ##args)
39
40 /* Stored value of bootdelay, used by autoboot_command() */
41 static int stored_bootdelay;
42 static int menukey;
43
44 #if defined(CONFIG_AUTOBOOT_STOP_STR_CRYPT)
45 #define AUTOBOOT_STOP_STR_CRYPT CONFIG_AUTOBOOT_STOP_STR_CRYPT
46 #else
47 #define AUTOBOOT_STOP_STR_CRYPT ""
48 #endif
49 #if defined(CONFIG_AUTOBOOT_STOP_STR_SHA256)
50 #define AUTOBOOT_STOP_STR_SHA256        CONFIG_AUTOBOOT_STOP_STR_SHA256
51 #else
52 #define AUTOBOOT_STOP_STR_SHA256        ""
53 #endif
54
55 #ifdef CONFIG_AUTOBOOT_USE_MENUKEY
56 #define AUTOBOOT_MENUKEY CONFIG_AUTOBOOT_MENUKEY
57 #else
58 #define AUTOBOOT_MENUKEY 0
59 #endif
60
61 /**
62  * passwd_abort_crypt() - check for a crypt-style hashed key sequence to abort booting
63  *
64  * This checks for the user entering a password within a given time.
65  *
66  * The entered password is hashed via one of the crypt-style hash methods
67  * and compared to the pre-defined value from either
68  *   the environment variable "bootstopkeycrypt"
69  * or
70  *   the config value CONFIG_AUTOBOOT_STOP_STR_CRYPT
71  *
72  * In case the config value CONFIG_AUTOBOOT_NEVER_TIMEOUT has been enabled
73  * this function never times out if the user presses the <Enter> key
74  * before starting to enter the password.
75  *
76  * @etime: Timeout value ticks (stop when get_ticks() reachs this)
77  * Return: 0 if autoboot should continue, 1 if it should stop
78  */
79 static int passwd_abort_crypt(uint64_t etime)
80 {
81         const char *crypt_env_str = env_get("bootstopkeycrypt");
82         char presskey[DELAY_STOP_STR_MAX_LENGTH];
83         u_int presskey_len = 0;
84         int abort = 0;
85         int never_timeout = 0;
86         int err;
87
88         if (IS_ENABLED(CONFIG_AUTOBOOT_STOP_STR_ENABLE) && !crypt_env_str)
89                 crypt_env_str = AUTOBOOT_STOP_STR_CRYPT;
90
91         if (!crypt_env_str)
92                 return 0;
93
94         /* We expect the stop-string to be newline-terminated */
95         do {
96                 if (tstc()) {
97                         /* Check for input string overflow */
98                         if (presskey_len >= sizeof(presskey))
99                                 return 0;
100
101                         presskey[presskey_len] = getchar();
102
103                         if ((presskey[presskey_len] == '\r') ||
104                             (presskey[presskey_len] == '\n')) {
105                                 if (IS_ENABLED(CONFIG_AUTOBOOT_NEVER_TIMEOUT) &&
106                                     !presskey_len) {
107                                         never_timeout = 1;
108                                         continue;
109                                 }
110                                 presskey[presskey_len] = '\0';
111                                 err = crypt_compare(crypt_env_str, presskey,
112                                                     &abort);
113                                 if (err)
114                                         debug_bootkeys(
115                                                 "crypt_compare() failed with: %s\n",
116                                                 errno_str(err));
117                                 /* you had one chance */
118                                 break;
119                         } else {
120                                 presskey_len++;
121                         }
122                 }
123                 udelay(10000);
124         } while (never_timeout || get_ticks() <= etime);
125
126         return abort;
127 }
128
129 /*
130  * Use a "constant-length" time compare function for this
131  * hash compare:
132  *
133  * https://crackstation.net/hashing-security.htm
134  */
135 static int slow_equals(u8 *a, u8 *b, int len)
136 {
137         int diff = 0;
138         int i;
139
140         for (i = 0; i < len; i++)
141                 diff |= a[i] ^ b[i];
142
143         return diff == 0;
144 }
145
146 /**
147  * passwd_abort_sha256() - check for a hashed key sequence to abort booting
148  *
149  * This checks for the user entering a SHA256 hash within a given time.
150  *
151  * @etime: Timeout value ticks (stop when get_ticks() reachs this)
152  * Return: 0 if autoboot should continue, 1 if it should stop
153  */
154 static int passwd_abort_sha256(uint64_t etime)
155 {
156         const char *sha_env_str = env_get("bootstopkeysha256");
157         u8 sha_env[SHA256_SUM_LEN];
158         u8 *sha;
159         char *presskey;
160         char *c;
161         const char *algo_name = "sha256";
162         u_int presskey_len = 0;
163         int abort = 0;
164         int size = sizeof(sha);
165         int ret;
166
167         if (sha_env_str == NULL)
168                 sha_env_str = AUTOBOOT_STOP_STR_SHA256;
169
170         presskey = malloc_cache_aligned(DELAY_STOP_STR_MAX_LENGTH);
171         if (!presskey)
172                 return -ENOMEM;
173
174         c = strstr(sha_env_str, ":");
175         if (c && (c - sha_env_str < DELAY_STOP_STR_MAX_LENGTH)) {
176                 /* preload presskey with salt */
177                 memcpy(presskey, sha_env_str, c - sha_env_str);
178                 presskey_len = c - sha_env_str;
179                 sha_env_str = c + 1;
180         }
181         /*
182          * Generate the binary value from the environment hash value
183          * so that we can compare this value with the computed hash
184          * from the user input
185          */
186         ret = hash_parse_string(algo_name, sha_env_str, sha_env);
187         if (ret) {
188                 printf("Hash %s not supported!\n", algo_name);
189                 return 0;
190         }
191
192         sha = malloc_cache_aligned(SHA256_SUM_LEN);
193         size = SHA256_SUM_LEN;
194         /*
195          * We don't know how long the stop-string is, so we need to
196          * generate the sha256 hash upon each input character and
197          * compare the value with the one saved in the environment
198          */
199         do {
200                 if (tstc()) {
201                         /* Check for input string overflow */
202                         if (presskey_len >= DELAY_STOP_STR_MAX_LENGTH) {
203                                 free(presskey);
204                                 free(sha);
205                                 return 0;
206                         }
207
208                         presskey[presskey_len++] = getchar();
209
210                         /* Calculate sha256 upon each new char */
211                         hash_block(algo_name, (const void *)presskey,
212                                    presskey_len, sha, &size);
213
214                         /* And check if sha matches saved value in env */
215                         if (slow_equals(sha, sha_env, SHA256_SUM_LEN))
216                                 abort = 1;
217                 }
218                 udelay(10000);
219         } while (!abort && get_ticks() <= etime);
220
221         free(presskey);
222         free(sha);
223         return abort;
224 }
225
226 /**
227  * passwd_abort_key() - check for a key sequence to aborted booting
228  *
229  * This checks for the user entering a string within a given time.
230  *
231  * @etime: Timeout value ticks (stop when get_ticks() reachs this)
232  * Return: 0 if autoboot should continue, 1 if it should stop
233  */
234 static int passwd_abort_key(uint64_t etime)
235 {
236         int abort = 0;
237         struct {
238                 char *str;
239                 u_int len;
240                 int retry;
241         }
242         delaykey[] = {
243                 { .str = env_get("bootdelaykey"),  .retry = 1 },
244                 { .str = env_get("bootstopkey"),   .retry = 0 },
245         };
246
247         char presskey[DELAY_STOP_STR_MAX_LENGTH];
248         int presskey_len = 0;
249         int presskey_max = 0;
250         int i;
251
252 #  ifdef CONFIG_AUTOBOOT_DELAY_STR
253         if (delaykey[0].str == NULL)
254                 delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
255 #  endif
256 #  ifdef CONFIG_AUTOBOOT_STOP_STR
257         if (delaykey[1].str == NULL)
258                 delaykey[1].str = CONFIG_AUTOBOOT_STOP_STR;
259 #  endif
260
261         for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) {
262                 delaykey[i].len = delaykey[i].str == NULL ?
263                                     0 : strlen(delaykey[i].str);
264                 delaykey[i].len = delaykey[i].len > DELAY_STOP_STR_MAX_LENGTH ?
265                                     DELAY_STOP_STR_MAX_LENGTH : delaykey[i].len;
266
267                 presskey_max = presskey_max > delaykey[i].len ?
268                                     presskey_max : delaykey[i].len;
269
270                 debug_bootkeys("%s key:<%s>\n",
271                                delaykey[i].retry ? "delay" : "stop",
272                                delaykey[i].str ? delaykey[i].str : "NULL");
273         }
274
275         /* In order to keep up with incoming data, check timeout only
276          * when catch up.
277          */
278         do {
279                 if (tstc()) {
280                         if (presskey_len < presskey_max) {
281                                 presskey[presskey_len++] = getchar();
282                         } else {
283                                 for (i = 0; i < presskey_max - 1; i++)
284                                         presskey[i] = presskey[i + 1];
285
286                                 presskey[i] = getchar();
287                         }
288                 }
289
290                 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) {
291                         if (delaykey[i].len > 0 &&
292                             presskey_len >= delaykey[i].len &&
293                                 memcmp(presskey + presskey_len -
294                                         delaykey[i].len, delaykey[i].str,
295                                         delaykey[i].len) == 0) {
296                                         debug_bootkeys("got %skey\n",
297                                                 delaykey[i].retry ? "delay" :
298                                                 "stop");
299
300                                 /* don't retry auto boot */
301                                 if (!delaykey[i].retry)
302                                         bootretry_dont_retry();
303                                 abort = 1;
304                         }
305                 }
306                 udelay(10000);
307         } while (!abort && get_ticks() <= etime);
308
309         return abort;
310 }
311
312 /**
313  * flush_stdin() - drops all pending characters from stdin
314  */
315 static void flush_stdin(void)
316 {
317         while (tstc())
318                 (void)getchar();
319 }
320
321 /**
322  * fallback_to_sha256() - check whether we should fall back to sha256
323  *                        password checking
324  *
325  * This checks for the environment variable `bootstopusesha256` in case
326  * sha256-fallback has been enabled via the config setting
327  * `AUTOBOOT_SHA256_FALLBACK`.
328  *
329  * Return: `false` if we must not fall-back, `true` if plain sha256 should be tried
330  */
331 static bool fallback_to_sha256(void)
332 {
333         if (IS_ENABLED(CONFIG_AUTOBOOT_SHA256_FALLBACK))
334                 return env_get_yesno("bootstopusesha256") == 1;
335         else if (IS_ENABLED(CONFIG_CRYPT_PW))
336                 return false;
337         else
338                 return true;
339 }
340
341 /***************************************************************************
342  * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
343  * returns: 0 -  no key string, allow autoboot 1 - got key string, abort
344  */
345 static int abortboot_key_sequence(int bootdelay)
346 {
347         int abort;
348         uint64_t etime = endtick(bootdelay);
349
350         if (IS_ENABLED(CONFIG_AUTOBOOT_FLUSH_STDIN))
351                 flush_stdin();
352 #  ifdef CONFIG_AUTOBOOT_PROMPT
353         /*
354          * CONFIG_AUTOBOOT_PROMPT includes the %d for all boards.
355          * To print the bootdelay value upon bootup.
356          */
357         printf(CONFIG_AUTOBOOT_PROMPT, bootdelay);
358 #  endif
359
360         if (IS_ENABLED(CONFIG_AUTOBOOT_ENCRYPTION)) {
361                 if (IS_ENABLED(CONFIG_CRYPT_PW) && !fallback_to_sha256())
362                         abort = passwd_abort_crypt(etime);
363                 else
364                         abort = passwd_abort_sha256(etime);
365         } else {
366                 abort = passwd_abort_key(etime);
367         }
368         if (!abort)
369                 debug_bootkeys("key timeout\n");
370
371         return abort;
372 }
373
374 static int abortboot_single_key(int bootdelay)
375 {
376         int abort = 0;
377         unsigned long ts;
378
379         printf("Hit any key to stop autoboot: %2d ", bootdelay);
380
381         /*
382          * Check if key already pressed
383          */
384         if (tstc()) {   /* we got a key press   */
385                 getchar();      /* consume input        */
386                 puts("\b\b\b 0");
387                 abort = 1;      /* don't auto boot      */
388         }
389
390         while ((bootdelay > 0) && (!abort)) {
391                 --bootdelay;
392                 /* delay 1000 ms */
393                 ts = get_timer(0);
394                 do {
395                         if (tstc()) {   /* we got a key press   */
396                                 int key;
397
398                                 abort  = 1;     /* don't auto boot      */
399                                 bootdelay = 0;  /* no more delay        */
400                                 key = getchar();/* consume input        */
401                                 if (IS_ENABLED(CONFIG_AUTOBOOT_USE_MENUKEY))
402                                         menukey = key;
403                                 break;
404                         }
405                         udelay(10000);
406                 } while (!abort && get_timer(ts) < 1000);
407
408                 printf("\b\b\b%2d ", bootdelay);
409         }
410
411         putc('\n');
412
413         return abort;
414 }
415
416 static int abortboot(int bootdelay)
417 {
418         int abort = 0;
419
420         if (bootdelay >= 0) {
421                 if (autoboot_keyed())
422                         abort = abortboot_key_sequence(bootdelay);
423                 else
424                         abort = abortboot_single_key(bootdelay);
425         }
426
427         if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && abort)
428                 gd->flags &= ~GD_FLG_SILENT;
429
430         return abort;
431 }
432
433 static void process_fdt_options(void)
434 {
435 #ifdef CONFIG_TEXT_BASE
436         ulong addr;
437
438         /* Add an env variable to point to a kernel payload, if available */
439         addr = ofnode_conf_read_int("kernel-offset", 0);
440         if (addr)
441                 env_set_addr("kernaddr", (void *)(CONFIG_TEXT_BASE + addr));
442
443         /* Add an env variable to point to a root disk, if available */
444         addr = ofnode_conf_read_int("rootdisk-offset", 0);
445         if (addr)
446                 env_set_addr("rootaddr", (void *)(CONFIG_TEXT_BASE + addr));
447 #endif /* CONFIG_TEXT_BASE */
448 }
449
450 const char *bootdelay_process(void)
451 {
452         char *s;
453         int bootdelay;
454
455         bootcount_inc();
456
457         s = env_get("bootdelay");
458         bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
459
460         /*
461          * Does it really make sense that the devicetree overrides the user
462          * setting? It is possibly helpful for security since the device tree
463          * may be signed whereas the environment is often loaded from storage.
464          */
465         if (IS_ENABLED(CONFIG_OF_CONTROL))
466                 bootdelay = ofnode_conf_read_int("bootdelay", bootdelay);
467
468         debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);
469
470         if (IS_ENABLED(CONFIG_AUTOBOOT_MENU_SHOW))
471                 bootdelay = menu_show(bootdelay);
472         bootretry_init_cmd_timeout();
473
474 #ifdef CONFIG_POST
475         if (gd->flags & GD_FLG_POSTFAIL) {
476                 s = env_get("failbootcmd");
477         } else
478 #endif /* CONFIG_POST */
479         if (bootcount_error())
480                 s = env_get("altbootcmd");
481         else
482                 s = env_get("bootcmd");
483
484         if (IS_ENABLED(CONFIG_OF_CONTROL))
485                 process_fdt_options();
486         stored_bootdelay = bootdelay;
487
488         return s;
489 }
490
491 void autoboot_command(const char *s)
492 {
493         debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
494
495         if (s && (stored_bootdelay == -2 ||
496                  (stored_bootdelay != -1 && !abortboot(stored_bootdelay)))) {
497                 bool lock;
498                 int prev;
499
500                 lock = autoboot_keyed() &&
501                         !IS_ENABLED(CONFIG_AUTOBOOT_KEYED_CTRLC);
502                 if (lock)
503                         prev = disable_ctrlc(1); /* disable Ctrl-C checking */
504
505                 run_command_list(s, -1, 0);
506
507                 if (lock)
508                         disable_ctrlc(prev);    /* restore Ctrl-C checking */
509         }
510
511         if (IS_ENABLED(CONFIG_AUTOBOOT_USE_MENUKEY) &&
512             menukey == AUTOBOOT_MENUKEY) {
513                 s = env_get("menucmd");
514                 if (s)
515                         run_command_list(s, -1, 0);
516         }
517 }