X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=common%2Fautoboot.c;h=223e06274025bea71afd2b15052ca2337d07d7bb;hb=0745008145e0a30db06b21533512893ba0f706a2;hp=984389885f2c0a66007a490e1e29e75888e3e337;hpb=b26440f1fa243396000536028ea00e5e185b6b6a;p=u-boot diff --git a/common/autoboot.c b/common/autoboot.c index 984389885f..223e062740 100644 --- a/common/autoboot.c +++ b/common/autoboot.c @@ -6,11 +6,14 @@ */ #include +#include #include #include +#include #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -22,25 +25,92 @@ DECLARE_GLOBAL_DATA_PTR; #define debug_bootkeys(fmt, args...) \ debug_cond(DEBUG_BOOTKEYS, fmt, ##args) -/*************************************************************************** - * Watch for 'delay' seconds for autoboot stop or autoboot delay string. - * returns: 0 - no key string, allow autoboot 1 - got key string, abort +/* Stored value of bootdelay, used by autoboot_command() */ +static int stored_bootdelay; + +#if defined(CONFIG_AUTOBOOT_KEYED) +#if defined(CONFIG_AUTOBOOT_STOP_STR_SHA256) + +/* + * Use a "constant-length" time compare function for this + * hash compare: + * + * https://crackstation.net/hashing-security.htm */ -# if defined(CONFIG_AUTOBOOT_KEYED) -static int abortboot_keyed(int bootdelay) +static int slow_equals(u8 *a, u8 *b, int len) +{ + int diff = 0; + int i; + + for (i = 0; i < len; i++) + diff |= a[i] ^ b[i]; + + return diff == 0; +} + +static int passwd_abort(uint64_t etime) +{ + const char *sha_env_str = getenv("bootstopkeysha256"); + u8 sha_env[SHA256_SUM_LEN]; + u8 sha[SHA256_SUM_LEN]; + char presskey[MAX_DELAY_STOP_STR]; + const char *algo_name = "sha256"; + u_int presskey_len = 0; + int abort = 0; + int size; + int ret; + + if (sha_env_str == NULL) + sha_env_str = CONFIG_AUTOBOOT_STOP_STR_SHA256; + + /* + * Generate the binary value from the environment hash value + * so that we can compare this value with the computed hash + * from the user input + */ + ret = hash_parse_string(algo_name, sha_env_str, sha_env); + if (ret) { + printf("Hash %s not supported!\n", algo_name); + return 0; + } + + /* + * We don't know how long the stop-string is, so we need to + * generate the sha256 hash upon each input character and + * compare the value with the one saved in the environment + */ + do { + if (tstc()) { + /* Check for input string overflow */ + if (presskey_len >= MAX_DELAY_STOP_STR) + return 0; + + presskey[presskey_len++] = getc(); + + /* Calculate sha256 upon each new char */ + hash_block(algo_name, (const void *)presskey, + presskey_len, sha, &size); + + /* And check if sha matches saved value in env */ + if (slow_equals(sha, sha_env, SHA256_SUM_LEN)) + abort = 1; + } + } while (!abort && get_ticks() <= etime); + + return abort; +} +#else +static int passwd_abort(uint64_t etime) { int abort = 0; - uint64_t etime = endtick(bootdelay); struct { char *str; u_int len; int retry; } delaykey[] = { - { str: getenv("bootdelaykey"), retry: 1 }, - { str: getenv("bootdelaykey2"), retry: 1 }, - { str: getenv("bootstopkey"), retry: 0 }, - { str: getenv("bootstopkey2"), retry: 0 }, + { .str = getenv("bootdelaykey"), .retry = 1 }, + { .str = getenv("bootstopkey"), .retry = 0 }, }; char presskey[MAX_DELAY_STOP_STR]; @@ -48,30 +118,13 @@ static int abortboot_keyed(int bootdelay) u_int presskey_max = 0; u_int i; -#ifndef CONFIG_ZERO_BOOTDELAY_CHECK - if (bootdelay == 0) - return 0; -#endif - -# ifdef CONFIG_AUTOBOOT_PROMPT - printf(CONFIG_AUTOBOOT_PROMPT); -# endif - # ifdef CONFIG_AUTOBOOT_DELAY_STR if (delaykey[0].str == NULL) delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR; # endif -# ifdef CONFIG_AUTOBOOT_DELAY_STR2 - if (delaykey[1].str == NULL) - delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2; -# endif # ifdef CONFIG_AUTOBOOT_STOP_STR - if (delaykey[2].str == NULL) - delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR; -# endif -# ifdef CONFIG_AUTOBOOT_STOP_STR2 - if (delaykey[3].str == NULL) - delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2; + if (delaykey[1].str == NULL) + delaykey[1].str = CONFIG_AUTOBOOT_STOP_STR; # endif for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) { @@ -121,6 +174,33 @@ static int abortboot_keyed(int bootdelay) } } while (!abort && get_ticks() <= etime); + return abort; +} +#endif + +/*************************************************************************** + * Watch for 'delay' seconds for autoboot stop or autoboot delay string. + * returns: 0 - no key string, allow autoboot 1 - got key string, abort + */ +static int abortboot_keyed(int bootdelay) +{ + int abort; + uint64_t etime = endtick(bootdelay); + +#ifndef CONFIG_ZERO_BOOTDELAY_CHECK + if (bootdelay == 0) + return 0; +#endif + +# ifdef CONFIG_AUTOBOOT_PROMPT + /* + * CONFIG_AUTOBOOT_PROMPT includes the %d for all boards. + * To print the bootdelay value upon bootup. + */ + printf(CONFIG_AUTOBOOT_PROMPT, bootdelay); +# endif + + abort = passwd_abort(etime); if (!abort) debug_bootkeys("key timeout\n"); @@ -205,57 +285,9 @@ static int abortboot(int bootdelay) #endif } -/* - * Runs the given boot command securely. Specifically: - * - Doesn't run the command with the shell (run_command or parse_string_outer), - * since that's a lot of code surface that an attacker might exploit. - * Because of this, we don't do any argument parsing--the secure boot command - * has to be a full-fledged u-boot command. - * - Doesn't check for keypresses before booting, since that could be a - * security hole; also disables Ctrl-C. - * - Doesn't allow the command to return. - * - * Upon any failures, this function will drop into an infinite loop after - * printing the error message to console. - */ - -#if defined(CONFIG_OF_CONTROL) -static void secure_boot_cmd(char *cmd) -{ - cmd_tbl_t *cmdtp; - int rc; - - if (!cmd) { - printf("## Error: Secure boot command not specified\n"); - goto err; - } - - /* Disable Ctrl-C just in case some command is used that checks it. */ - disable_ctrlc(1); - - /* Find the command directly. */ - cmdtp = find_cmd(cmd); - if (!cmdtp) { - printf("## Error: \"%s\" not defined\n", cmd); - goto err; - } - - /* Run the command, forcing no flags and faking argc and argv. */ - rc = (cmdtp->cmd)(cmdtp, 0, 1, &cmd); - - /* Shouldn't ever return from boot command. */ - printf("## Error: \"%s\" returned (code %d)\n", cmd, rc); - -err: - /* - * Not a whole lot to do here. Rebooting won't help much, since we'll - * just end up right back here. Just loop. - */ - hang(); -} - static void process_fdt_options(const void *blob) { +#if defined(CONFIG_OF_CONTROL) && defined(CONFIG_SYS_TEXT_BASE) ulong addr; /* Add an env variable to point to a kernel payload, if available */ @@ -267,14 +299,11 @@ static void process_fdt_options(const void *blob) addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0); if (addr) setenv_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); +#endif /* CONFIG_OF_CONTROL && CONFIG_SYS_TEXT_BASE */ } -#endif /* CONFIG_OF_CONTROL */ -void bootdelay_process(void) +const char *bootdelay_process(void) { -#ifdef CONFIG_OF_CONTROL - char *env; -#endif char *s; int bootdelay; #ifdef CONFIG_BOOTCOUNT_LIMIT @@ -318,27 +347,18 @@ void bootdelay_process(void) } else #endif /* CONFIG_BOOTCOUNT_LIMIT */ s = getenv("bootcmd"); -#ifdef CONFIG_OF_CONTROL - /* Allow the fdt to override the boot command */ - env = fdtdec_get_config_string(gd->fdt_blob, "bootcmd"); - if (env) - s = env; process_fdt_options(gd->fdt_blob); + stored_bootdelay = bootdelay; - /* - * If the bootsecure option was chosen, use secure_boot_cmd(). - * Always use 'env' in this case, since bootsecure requres that the - * bootcmd was specified in the FDT too. - */ - if (fdtdec_get_config_int(gd->fdt_blob, "bootsecure", 0)) - secure_boot_cmd(env); - -#endif /* CONFIG_OF_CONTROL */ + return s; +} +void autoboot_command(const char *s) +{ debug("### main_loop: bootcmd=\"%s\"\n", s ? s : ""); - if (bootdelay != -1 && s && !abortboot(bootdelay)) { + if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) { #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC) int prev = disable_ctrlc(1); /* disable Control C checking */ #endif