init: Fix writing "reboot recovery" to BCB

When BCB (bootloader message structure inside of misc partition) is
malformed (contains some non-printable characters in its fields),
"reboot recovery" command won't be able to write required string to
"command" field. It can happen for example when partition table was
created anew and 'misc' partition area contains some garbage. Also this
behavior can be emulated with this command:

    $ fastboot erase misc

which leads to 'misc' partition to be filled with 0xFF characters. Hence
this code:

    if (boot.command[0] == '\0') {

won't let us to set new string to "command" field. Let's check if
"command" field is malformed and fix it, before actually checking for
previously set content.

"fastboot erase" shouldn't be used for testing purposes though, as it
doesn't work sometimes due to alignment, on bootloader side:

    Erasing blocks 6144 to 6144 due to alignment
    ........ erased 0 bytes from 'misc'

Instead one might use "dd" command to fill 'misc' with 0xFF's:

    $ dd if=/dev/zero ibs=2k count=1 | tr "\000" "\377" >misc.img
    $ fastboot flash misc misc.img

Test: Fill 'misc' partition with 0xFF's, then do "adb reboot recovery"
Change-Id: Ica8ca31012b9b2249645e7305830c07a20dd013c
Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
This commit is contained in:
Sam Protsenko 2019-12-26 21:55:08 +02:00
parent aceb837ced
commit 2c7c3c7402

View file

@ -860,6 +860,30 @@ static void HandleUserspaceReboot() {
am.QueueBuiltinAction(handler, "userspace-reboot");
}
/**
* Check if "command" field is set in bootloader message.
*
* If "command" field is broken (contains non-printable characters prior to
* terminating zero), it will be zeroed.
*
* @param[in,out] boot Bootloader message (BCB) structure
* @return true if "command" field is already set, and false if it's empty
*/
static bool CommandIsPresent(bootloader_message* boot) {
if (boot->command[0] == '\0')
return false;
for (size_t i = 0; i < arraysize(boot->command); ++i) {
if (boot->command[i] == '\0')
return true;
if (!isprint(boot->command[i]))
break;
}
memset(boot->command, 0, sizeof(boot->command));
return false;
}
void HandlePowerctlMessage(const std::string& command) {
unsigned int cmd = 0;
std::vector<std::string> cmd_params = Split(command, ",");
@ -912,7 +936,7 @@ void HandlePowerctlMessage(const std::string& command) {
}
// Update the boot command field if it's empty, and preserve
// the other arguments in the bootloader message.
if (boot.command[0] == '\0') {
if (!CommandIsPresent(&boot)) {
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
if (std::string err; !write_bootloader_message(boot, &err)) {
LOG(ERROR) << "Failed to set bootloader message: " << err;