recovery-utils: ask for confirmation when changing the encryption key

If we trigger a key change while there are partitions that are encrypted,
print a warning and ask for confirmation so users know that the operation will
erase the contents of said partitions.

Like in the partition (un)encryption mechanism, add the possibility to skip
both the warning message and the confirmation prompt.

Signed-off-by: Gabriel Valcazar <gabriel.valcazar@digi.com>
This commit is contained in:
Gabriel Valcazar 2021-05-20 13:19:54 +02:00
parent e2cd4f6d9a
commit 32984efc90
3 changed files with 72 additions and 11 deletions

View File

@ -52,10 +52,11 @@ int wipe_update_partition(void);
* *
* Params: * Params:
* 'key' (input) Encryption key to use, NULL or empty to generate a random one * 'key' (input) Encryption key to use, NULL or empty to generate a random one
* 'force' (input) Skips warning and confirmation prompt if non-zero
* *
* Return: 0 on sucess, -1 on failure * Return: 0 on sucess, -1 on failure and 1 on success with no recovery command set
*/ */
int set_encryption_key(char *key); int set_encryption_key(char *key, unsigned char force);
/* /*
* Configure recovery commands to encrypt/un-encrypt provided partitions. * Configure recovery commands to encrypt/un-encrypt provided partitions.

View File

@ -70,6 +70,8 @@ static char *emmc_parts_blacklist[] = {
NULL NULL
}; };
static char *rootfs[] = { "rootfs", NULL };
/* /*
* Function: append_recovery_command * Function: append_recovery_command
* Description: append configuration to the 'recovery_command' variable * Description: append configuration to the 'recovery_command' variable
@ -640,11 +642,19 @@ int wipe_update_partition(void)
* Function: set_encryption_key * Function: set_encryption_key
* Description: configure recovery commands to set a partition encryption key * Description: configure recovery commands to set a partition encryption key
*/ */
int set_encryption_key(char *key) int set_encryption_key(char *key, unsigned char force)
{ {
char *parts[MAX_PARTITIONS];
char *encrypted[MAX_PARTITIONS];
char *key_cmd = NULL; char *key_cmd = NULL;
char confirmation;
int generate_random_key = 0; int generate_random_key = 0;
int ret = -1; int ret = -1;
unsigned char i = 0;
/* Initialize arrays */
parts[0] = NULL;
encrypted[0] = NULL;
generate_random_key = (!key || strlen(key) == 0); generate_random_key = (!key || strlen(key) == 0);
@ -656,6 +666,46 @@ int set_encryption_key(char *key)
print_open_device_warning(); print_open_device_warning();
if (!force) {
/* Check if there are any currently encrypted partitions */
ret = PARSE_PARTITION_INFO(parts, encrypted, MAX_PARTITIONS);
if (ret) {
fprintf(stderr, "Error: parse_partition_info\n");
goto err;
}
/*
* Key changes with an encrypted rootfs are only possible if
* an update package is provided, in which case, we're already
* substituting the current rootfs image with another one.
* Because of this, there's no need to print the warning if the
* rootfs is the only encrypted partition in the system.
*/
subtract_array(rootfs, encrypted);
/*
* If we have at least one encrypted partition, ask for
* confirmation before continuing.
*/
if (encrypted[0]) {
printf("\n"
" *****************************************************************\n"
" * Warning: Changing the encryption key will erase the contents *\n"
" * of all currently encrypted partitions. *\n"
" *****************************************************************\n"
" Affected partitions:\n");
while (encrypted[i])
printf(" %s\n", encrypted[i++]);
printf("\n Continue? (y/n): ");
confirmation = getchar();
if (confirmation != 'y' && confirmation != 'Y') {
printf("\nSkipping encryption key change\n");
ret = 1;
goto err;
}
}
}
key_cmd = key_cmd =
calloc(1, calloc(1,
strlen("encryption_key=") + strlen("encryption_key=") +
@ -676,7 +726,10 @@ err:
if (!generate_random_key) if (!generate_random_key)
secure_memzero(key, strlen(key)); secure_memzero(key, strlen(key));
return ret ? -1 : 0; free_array(encrypted);
free_array(parts);
return ret < 0 ? -1 : ret;
} }
/* /*
@ -685,8 +738,6 @@ err:
*/ */
int encrypt_partitions(char *to_encrypt, char *to_unencrypt, unsigned char force) int encrypt_partitions(char *to_encrypt, char *to_unencrypt, unsigned char force)
{ {
char *rootfs[] = { "rootfs", NULL };
char *parts[MAX_PARTITIONS]; char *parts[MAX_PARTITIONS];
char *encrypted[MAX_PARTITIONS]; char *encrypted[MAX_PARTITIONS];
char *new_encrypted[MAX_PARTITIONS]; char *new_encrypted[MAX_PARTITIONS];

View File

@ -48,7 +48,7 @@
" Empty to generate a random key.\n" \ " Empty to generate a random key.\n" \
" -w --wipe-update-partition Wipe 'update' partition\n" \ " -w --wipe-update-partition Wipe 'update' partition\n" \
" -T <N> --reboot-timeout=<N> Reboot after N seconds (default %d)\n" \ " -T <N> --reboot-timeout=<N> Reboot after N seconds (default %d)\n" \
" -f --force Force (un)encryption operations.\n" \ " -f --force Force (un)encryption and key change operations.\n" \
" --help Print help and exit\n" \ " --help Print help and exit\n" \
"\n" \ "\n" \
"<SWU-package-path> Absolute path to the firmware update package\n" \ "<SWU-package-path> Absolute path to the firmware update package\n" \
@ -64,6 +64,7 @@
" -k [<key>] --encryption-key[=<key>] Set <key> as file system encryption key.\n" \ " -k [<key>] --encryption-key[=<key>] Set <key> as file system encryption key.\n" \
" Empty to generate a random key.\n" \ " Empty to generate a random key.\n" \
" -T <N> --reboot-timeout=<N> Reboot after N seconds (default %d)\n" \ " -T <N> --reboot-timeout=<N> Reboot after N seconds (default %d)\n" \
" -f --force Force (un)encryption and key change operations.\n" \
" --help Print help and exit\n" \ " --help Print help and exit\n" \
"\n" \ "\n" \
"<SWU-package-path> Absolute path to the firmware update package\n" \ "<SWU-package-path> Absolute path to the firmware update package\n" \
@ -81,7 +82,7 @@
" -k [<key>] --encryption-key[=<key>] Set <key> as file system encryption key.\n" \ " -k [<key>] --encryption-key[=<key>] Set <key> as file system encryption key.\n" \
" Empty to generate a random key.\n" \ " Empty to generate a random key.\n" \
" -T <N> --reboot-timeout=<N> Reboot after N seconds (default %d)\n" \ " -T <N> --reboot-timeout=<N> Reboot after N seconds (default %d)\n" \
" -f --force Force (un)encryption operations.\n" \ " -f --force Force (un)encryption and key change operations.\n" \
" --help Print help and exit\n" \ " --help Print help and exit\n" \
"\n" "\n"
@ -227,12 +228,20 @@ int main(int argc, char *argv[])
if (set_key) { if (set_key) {
/* Configure recovery commands to set a fs encryption key */ /* Configure recovery commands to set a fs encryption key */
ret = set_encryption_key(key); ret = set_encryption_key(key, force);
if (ret) { if (ret < 0) {
printf("Error: set_encryption_key\n"); printf("Error: set_encryption_key\n");
goto out; goto out;
} else if (ret == 0) {
/*
* Only reboot if strictly necessary, since the function
* might succeed without setting a recovery command
* (for example, if a user cancels the operation).
*/
need_reboot++;
} else {
ret = 0;
} }
need_reboot++;
} }
if (swu_package) { if (swu_package) {