From 2bc8b6803a604a10d7d6b45bf62abfa09ea2de56 Mon Sep 17 00:00:00 2001 From: Ming Tan Date: Wed, 13 Feb 2019 13:56:52 +0800 Subject: [PATCH] [DO NOT MERGE] Tune the code of checking kernelflinger upgrade. This code will be merge with an other PR, so not need to merge it. Move the code to libkernelflinger, so other program can call this function. Also change the logical of checking upgrade file. Also add the function StrcaseCmp. Change-Id: I7311ab9a2a8a97e6ada2fcac6b0c64a8418b04aa Tracked-On: OAM-76158 Signed-off-by: Ming Tan --- include/libkernelflinger/lib.h | 2 + include/libkernelflinger/uefi_utils.h | 5 + kernelflinger.c | 149 +-------------------- libkernelflinger/lib.c | 30 ++++- libkernelflinger/uefi_utils.c | 179 ++++++++++++++++++++++++++ 5 files changed, 218 insertions(+), 147 deletions(-) diff --git a/include/libkernelflinger/lib.h b/include/libkernelflinger/lib.h index b6bb170..eb5ba7f 100644 --- a/include/libkernelflinger/lib.h +++ b/include/libkernelflinger/lib.h @@ -200,6 +200,8 @@ void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *)) __attribute__((weak)); +INTN StrcaseCmp(CHAR16 *s1, CHAR16 *s2); + /* * misc */ diff --git a/include/libkernelflinger/uefi_utils.h b/include/libkernelflinger/uefi_utils.h index 6506690..9f75b25 100644 --- a/include/libkernelflinger/uefi_utils.h +++ b/include/libkernelflinger/uefi_utils.h @@ -57,5 +57,10 @@ EFI_STATUS uefi_create_directory_root(EFI_FILE_IO_INTERFACE *io, CHAR16 *dirname EFI_STATUS uefi_rename_file(EFI_FILE_IO_INTERFACE *io, CHAR16 *oldname, CHAR16 *newname); EFI_STATUS verify_image(EFI_HANDLE handle, CHAR16 *path); EFI_STATUS uefi_bios_update_capsule(EFI_HANDLE root_dir, CHAR16 *name); +EFI_STATUS uefi_enter_binary(EFI_HANDLE part_handle, CHAR16 *path, + BOOLEAN delete, UINT32 load_options_size, VOID *load_options); +EFI_STATUS uefi_check_upgrade(EFI_LOADED_IMAGE *loaded_image, + CHAR16 *partition, CHAR16 *upgrade_file, + CHAR16 *self_path1, CHAR16 *bak_path1, CHAR16 *self_path2, CHAR16 *bak_path2); #endif /* __UEFI_UTILS_H__ */ diff --git a/kernelflinger.c b/kernelflinger.c index 4e96b10..eaba2a6 100644 --- a/kernelflinger.c +++ b/kernelflinger.c @@ -830,57 +830,6 @@ static EFI_STATUS load_boot_image( } #endif -/* Chainload another EFI application on the ESP with the specified path, - * optionally deleting the file before entering - */ -static EFI_STATUS enter_efi_binary(CHAR16 *path, BOOLEAN delete, UINT32 load_options_size, VOID *load_options) -{ - EFI_DEVICE_PATH *edp; - EFI_STATUS ret; - EFI_HANDLE image; - EFI_LOADED_IMAGE *loaded_image; - - - edp = FileDevicePath(g_disk_device, path); - if (!edp) { - error(L"Couldn't generate a path"); - return EFI_INVALID_PARAMETER; - } - - ret = uefi_call_wrapper(BS->LoadImage, 6, FALSE, g_parent_image, - edp, NULL, 0, &image); - if (EFI_ERROR(ret)) { - efi_perror(ret, L"BS->LoadImage '%s'", path); - } else { - if (delete) { - ret = file_delete(g_disk_device, path); - if (EFI_ERROR(ret)) - efi_perror(ret, L"Couldn't delete %s", path); - } - if (load_options_size > 0) { - // Set the command line option - ret = uefi_call_wrapper(BS->OpenProtocol, 6, image, - &LoadedImageProtocol, (VOID **)&loaded_image, - image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if (EFI_ERROR(ret)) { - efi_perror(ret, L"OpenProtocol: LoadedImageProtocol"); - return ret; - } - if (loaded_image == NULL) { - error(L"LoadedImageProtocol, but return image is NULL"); - return EFI_INVALID_PARAMETER; - } - loaded_image->LoadOptionsSize = load_options_size; - loaded_image->LoadOptions = load_options; - } - ret = uefi_call_wrapper(BS->StartImage, 3, image, NULL, NULL); - uefi_call_wrapper(BS->UnloadImage, 1, image); - } - FreePool(edp); - return ret; -} - - #define OEMVARS_MAGIC "#OEMVARS\n" #define OEMVARS_MAGIC_SZ 9 @@ -1260,99 +1209,6 @@ static void flash_bootloader_policy(__attribute__((__unused__)) UINT8 boot_state } #endif -EFI_STATUS check_kf_upgrade(void) -{ - EFI_STATUS ret; - EFI_FILE_IO_INTERFACE *io = NULL; - EFI_GUID SimpleFileSystemProtocol = SIMPLE_FILE_SYSTEM_PROTOCOL; - EFI_HANDLE esp_handle = NULL; - CHAR16 *self_path = BOOTLOADER_FILE; - CHAR16 *bak_path = BOOTLOADER_FILE_BAK; - - ret = gpt_get_partition_handle(BOOTLOADER_LABEL, LOGICAL_UNIT_USER, - &esp_handle); - if (EFI_ERROR(ret)) { - efi_perror(ret, L"Failed to get ESP partition"); - goto out; - } - - ret = handle_protocol(esp_handle, &SimpleFileSystemProtocol, - (void **)&io); - if (EFI_ERROR(ret)) { - efi_perror(ret, L"HandleProtocol for ESP partition failed"); - goto out; - } - - if (!uefi_exist_file_root(io, KFUPDATE_FILE)) { - debug(L"Kernelflinger upgrade file is not exist"); - goto out; - } - debug(L"Kernelflinger upgrade file is exist"); - - ret = verify_image(esp_handle, KFUPDATE_FILE); - if (EFI_ERROR(ret)) { - efi_perror(ret, L"Verify upgrade image failed"); - uefi_delete_file(io, KFUPDATE_FILE); - goto out; - } - debug(L"Success to verify the upgrade image"); - - if (g_loaded_image != NULL - && g_loaded_image->FilePath != NULL - && g_loaded_image->FilePath->Type == MEDIA_DEVICE_PATH - && g_loaded_image->FilePath->SubType == MEDIA_FILEPATH_DP) { - debug(L"Self path name: %s", ((FILEPATH_DEVICE_PATH *)(g_loaded_image->FilePath))->PathName); - self_path = ((FILEPATH_DEVICE_PATH *)(g_loaded_image->FilePath))->PathName; - if (StriCmp(self_path, BOOTLOADER_FILE)) { - if (StriCmp(self_path, KFSELF_FILE)) { - error(L"Skip check the upgrade file"); - goto out; - } - bak_path = KFBACKUP_FILE; - } - } else { - // maybe loaded by the "fastboot boot" command, or the BIOS not support - // Use the default value - error(L"Loaded image or FilePath is NULL"); - } - - // Verify it again - if (!uefi_exist_file_root(io, self_path)) { - error(L"Can't find file %s", self_path); - ret = EFI_NOT_FOUND; - goto out; - } - - if (uefi_exist_file_root(io, bak_path)) { - ret = uefi_delete_file(io, bak_path); - if (EFI_ERROR(ret)) { - efi_perror(ret, L"Failed to delete %s", bak_path); - goto out; - } - debug(L"Success to delete old %s", bak_path); - } - ret = uefi_rename_file(io, self_path, bak_path); - if (EFI_ERROR(ret)) { - efi_perror(ret, L"Failed to rename the %s to %s", self_path, bak_path); - goto out; - } - debug(L"Success rename file %s to %s", self_path, bak_path); - ret = uefi_rename_file(io, KFUPDATE_FILE, self_path); - if (EFI_ERROR(ret)) { - efi_perror(ret, L"Failed to rename the upgrade file %s to %s", KFUPDATE_FILE, self_path); - goto out; - } - debug(L"Success rename the upgrade file %s to %s", KFUPDATE_FILE, self_path); - - error(L"I am about to load the new boot loader after upgrade it"); - if (g_loaded_image != NULL) - enter_efi_binary(self_path, FALSE, g_loaded_image->LoadOptionsSize, g_loaded_image->LoadOptions); - reboot(NULL, EfiResetCold); - -out: - return ret; -} - EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { EFI_STATUS ret; @@ -1408,7 +1264,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) uefi_bios_update_capsule(g_disk_device, FWUPDATE_FILE); - check_kf_upgrade(); + uefi_check_upgrade(g_loaded_image, BOOTLOADER_LABEL, KFUPDATE_FILE, + BOOTLOADER_FILE, BOOTLOADER_FILE_BAK, KFSELF_FILE, KFBACKUP_FILE); #ifdef USE_TPM if (!is_boot_device_removable()) { @@ -1518,7 +1375,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) debug(L"entering EFI binary"); if (!target_path) return EFI_INVALID_PARAMETER; - ret = enter_efi_binary(target_path, oneshot, 0, NULL); + ret = uefi_enter_binary(g_disk_device, target_path, oneshot, 0, NULL); if (EFI_ERROR(ret)) { efi_perror(ret, L"EFI Application exited abnormally"); pause(3); diff --git a/libkernelflinger/lib.c b/libkernelflinger/lib.c index 04fa3b1..a867333 100644 --- a/libkernelflinger/lib.c +++ b/libkernelflinger/lib.c @@ -1143,6 +1143,34 @@ VOID __stack_chk_fail() panic(L"stack-protector: kernelflinger stack is corrupted"); } +INTN StrcaseCmp(CHAR16 *s1, CHAR16 *s2) +{ + CHAR16 *p1 = s1; + CHAR16 *p2 = s2; + CHAR16 c1, c2; + + if (s1 == NULL) + return (s2 == NULL) ? 0 : -1; + if (s2 == NULL) + return 1; + + while (*p1 != 0) { + c1 = *p1; + if (c1 >= L'A' && c1 <= L'Z') + c1 += L'a' - L'A'; + c2 = *p2; + if (c2 >= L'A' && c2 <= L'Z') + c2 += L'a' - L'A'; + if (c1 > c2) + return 1; + if (c1 < c2) + return -1; + p1++; + p2++; + } + + return (*p2 == 0) ? 0 : -1; +} + /* vim: softtabstop=8:shiftwidth=8:expandtab */ - diff --git a/libkernelflinger/uefi_utils.c b/libkernelflinger/uefi_utils.c index 42f2f14..b1cf97c 100644 --- a/libkernelflinger/uefi_utils.c +++ b/libkernelflinger/uefi_utils.c @@ -38,6 +38,7 @@ #include #include "protocol.h" #include "uefi_utils.h" +#include "options.h" /* GUID for ESP partition on gmin */ const EFI_GUID esp_ptn_guid = { 0x2568845d, 0x2332, 0x4675, @@ -498,3 +499,181 @@ EFI_STATUS uefi_bios_update_capsule(EFI_HANDLE root_dir, CHAR16 *name) return ret; } + +/* Chainload another EFI application on the ESP with the specified path, + * optionally deleting the file before entering + */ +EFI_STATUS uefi_enter_binary(EFI_HANDLE part_handle, CHAR16 *path, + BOOLEAN delete, UINT32 load_options_size, VOID *load_options) +{ + EFI_DEVICE_PATH *edp; + EFI_STATUS ret; + EFI_HANDLE image; + EFI_LOADED_IMAGE *loaded_image; + + edp = FileDevicePath(part_handle, path); + if (!edp) { + error(L"Couldn't generate a path"); + return EFI_INVALID_PARAMETER; + } + + ret = uefi_call_wrapper(BS->LoadImage, 6, FALSE, g_parent_image, + edp, NULL, 0, &image); + FreePool(edp); + if (EFI_ERROR(ret)) { + efi_perror(ret, L"BS->LoadImage '%s'", path); + return ret; + } + if (delete) { + ret = file_delete(part_handle, path); + if (EFI_ERROR(ret)) + efi_perror(ret, L"Couldn't delete %s", path); + } + if (load_options_size > 0) { + // Set the command line option + ret = uefi_call_wrapper(BS->OpenProtocol, 6, image, + &LoadedImageProtocol, (VOID **)&loaded_image, + image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(ret)) { + efi_perror(ret, L"OpenProtocol: LoadedImageProtocol"); + goto out; + } + if (loaded_image == NULL) { + error(L"LoadedImageProtocol, but return image is NULL"); + ret = EFI_INVALID_PARAMETER; + goto out; + } + loaded_image->LoadOptionsSize = load_options_size; + loaded_image->LoadOptions = load_options; + } + ret = uefi_call_wrapper(BS->StartImage, 3, image, NULL, NULL); + +out: + uefi_call_wrapper(BS->UnloadImage, 1, image); + + return ret; +} + +EFI_STATUS uefi_check_upgrade(EFI_LOADED_IMAGE *loaded_image, + CHAR16 *partition, CHAR16 *upgrade_file, + CHAR16 *self_path1, CHAR16 *bak_path1, CHAR16 *self_path2, CHAR16 *bak_path2) +{ + EFI_STATUS ret; + EFI_FILE_IO_INTERFACE *io = NULL; + EFI_GUID SimpleFileSystemProtocol = SIMPLE_FILE_SYSTEM_PROTOCOL; + EFI_HANDLE part_handle = NULL; + CHAR16 *self_path = NULL; + UINTN self_path_len; + CHAR16 efi_full_path[512]; + CHAR16 *bak_path = NULL; + UINTN argc; + CHAR16 **argv; + + if (loaded_image == NULL + || loaded_image->FilePath == NULL + || loaded_image->FilePath->Type != MEDIA_DEVICE_PATH + || loaded_image->FilePath->SubType != MEDIA_FILEPATH_DP) { + // maybe loaded by the "fastboot boot" command, or the BIOS not support + debug(L"Loaded image or FilePath is NULL"); + return EFI_INVALID_PARAMETER; + } + + self_path = ((FILEPATH_DEVICE_PATH *)(loaded_image->FilePath))->PathName; + ret = get_argv(loaded_image, &argc, &argv); + if (EFI_ERROR(ret)) + goto out; + if (argc > 0 && argv[0][0] != L'-') { + // If load from EFI shell, then the loaded_image->FilePath is the working directory of shell, + // and argv[0] is the efi application path. + // If load from BIOS boot manager, or other EFI application, then the loaded_image->FilePath + // is the full path of efi application path. + self_path_len = StrLen(self_path); + if (self_path_len > 0) { + // Build the full path of efi application path. + if (self_path[self_path_len - 1] == L'\\') { + // Loaded from EFI shell root directory, ended with '\'. + SPrint(efi_full_path, sizeof(efi_full_path), L"%s%s", self_path, argv[0]); + self_path = efi_full_path; + } else if (self_path_len <= 4 || StrcaseCmp(self_path + self_path_len - 4, L".EFI")) { + // Loaded from EFI shell and not root directory, need add '\'. + SPrint(efi_full_path, sizeof(efi_full_path), L"%s\\%s", self_path, argv[0]); + self_path = efi_full_path; + } + } else + self_path = argv[0]; + } + FreePool(argv); + debug(L"EFI path: %s", self_path); + + if (!StrcaseCmp(self_path, self_path1)) + bak_path = bak_path1; + else if (!StrcaseCmp(self_path, self_path2)) + bak_path = bak_path2; + else { + debug(L"Unsupported running path for check upgrade"); + goto out; + } + + ret = gpt_get_partition_handle(partition, LOGICAL_UNIT_USER, &part_handle); + if (EFI_ERROR(ret)) { + if (ret != EFI_NOT_FOUND) + efi_perror(ret, L"Failed to find partition %s", partition); + goto out; + } + + ret = handle_protocol(part_handle, &SimpleFileSystemProtocol, (void **)&io); + if (EFI_ERROR(ret)) { + efi_perror(ret, L"HandleProtocol for FAT in partition %s failed", partition); + goto out; + } + + if (!uefi_exist_file_root(io, upgrade_file)) { + debug(L"Upgrade file %s is not exist", upgrade_file); + goto out; + } + debug(L"Upgrade file %s is exist", upgrade_file); + + ret = verify_image(part_handle, upgrade_file); + if (EFI_ERROR(ret)) { + efi_perror(ret, L"Verify upgrade image failed"); + uefi_delete_file(io, upgrade_file); + goto out; + } + debug(L"Success to verify the upgrade image"); + + // Verify it again + if (!uefi_exist_file_root(io, self_path)) { + error(L"Can't find file %s", self_path); + ret = EFI_NOT_FOUND; + goto out; + } + + if (uefi_exist_file_root(io, bak_path)) { + ret = uefi_delete_file(io, bak_path); + if (EFI_ERROR(ret)) { + efi_perror(ret, L"Failed to delete %s", bak_path); + goto out; + } + debug(L"Success to delete old %s", bak_path); + } + ret = uefi_rename_file(io, self_path, bak_path); + if (EFI_ERROR(ret)) { + efi_perror(ret, L"Failed to rename the %s to %s", self_path, bak_path); + goto out; + } + debug(L"Success rename file %s to %s", self_path, bak_path); + ret = uefi_rename_file(io, upgrade_file, self_path); + if (EFI_ERROR(ret)) { + efi_perror(ret, L"Failed to rename the upgrade file %s to %s", upgrade_file, self_path); + goto out; + } + debug(L"Success rename the upgrade file %s to %s", upgrade_file, self_path); + + error(L"I am about to load the new boot loader after upgrade it"); + if (loaded_image != NULL) + uefi_enter_binary(part_handle, self_path, FALSE, loaded_image->LoadOptionsSize, loaded_image->LoadOptions); + reboot(NULL, EfiResetCold); + +out: + return ret; +}