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