From edc81e94e416e45b49c698456c9c6e5cd2caa041 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 10 Nov 2021 01:14:53 +0300 Subject: [PATCH 2/4] Add support for bootldr images Add support for BOOTLDR! images found e.g. in the Pixel2/2XL binary blobs archive. They are used with the msm8998 (SDM835) Snapdragon SoCs. Signed-off-by: Dmitry Baryshkov --- src/bootldr_image.c | 132 ++++++++++++++++++++++++++++++++++++++++ src/bootldr_image.h | 50 +++++++++++++++ src/qc_image_unpacker.c | 7 +++ 3 files changed, 189 insertions(+) create mode 100644 src/bootldr_image.c create mode 100644 src/bootldr_image.h diff --git a/src/bootldr_image.c b/src/bootldr_image.c new file mode 100644 index 000000000000..739f6eb2a9c6 --- /dev/null +++ b/src/bootldr_image.c @@ -0,0 +1,132 @@ +/* + + qc_image_unpacker + ----------------------------------------- + + Dmitry Baryshkov + Copyright 2019 - 2020 by CENSUS S.A. All Rights Reserved. + Copyright 2021 by Linaro Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +#include "bootldr_image.h" + +#include "common.h" +#include "utils.h" + +bool bootldr_image_detect(u1 *buf, size_t bufSz) +{ + bootldr_header_t *pBootLdrHeader; + + if (bufSz < sizeof(bootldr_header_t)) + return false; + + pBootLdrHeader = (bootldr_header_t *)buf; + + return (pBootLdrHeader->magic1 == BOOTLDR_IMG_MAGIC1) && + (pBootLdrHeader->magic2 == BOOTLDR_IMG_MAGIC2); +} + +bool bootldr_image_extract(u1 *buf, size_t bufSz, char *filePath, char *outputDir) { + bootldr_header_t *pBootLdrHeader; + bootldr_img_header_entry_t *pImgHeaderEntry; + u4 i = 0, j = 0, images, start_offset; + u1 *pImageEnd = NULL; + bool PnameTerminated = false; + char outPath[PATH_MAX], outFile[PATH_MAX]; + + if (bufSz < sizeof(bootldr_header_t)) { + LOGMSG(l_ERROR, "Invalid input size (%zu < %zu)", bufSz, sizeof(bootldr_header_t)); + return false; + } + + pBootLdrHeader = (bootldr_header_t *)buf; + if (pBootLdrHeader->magic1 != BOOTLDR_IMG_MAGIC1) { + LOGMSG(l_ERROR, "Invalid magic header (0x%x != 0x%x)", pBootLdrHeader->magic1, BOOTLDR_IMG_MAGIC1); + return false; + } + + if (pBootLdrHeader->magic2 != BOOTLDR_IMG_MAGIC2) { + LOGMSG(l_ERROR, "Invalid magic header (0x%x != 0x%x)", pBootLdrHeader->magic2, BOOTLDR_IMG_MAGIC2); + return false; + } + + pImgHeaderEntry = (bootldr_img_header_entry_t *)(buf + sizeof(bootldr_header_t)); + images = pBootLdrHeader->images; + start_offset = pBootLdrHeader->start_offset; + + if ((size_t)bufSz <= sizeof(bootldr_header_t) + images * sizeof(bootldr_img_header_entry_t)) { + LOGMSG(l_ERROR, "The size is smaller than image header size + entry size"); + return false; + } + + pImageEnd = buf + bufSz; + + // Create output root directory to place extracted images + memset(outPath, 0, sizeof(outPath)); + snprintf(outPath, sizeof(outPath), "%s/%s_images", outputDir, utils_fileBasename(filePath)); + if (mkdir(outPath, 0755)) { + LOGMSG_P(l_ERROR, "mkdir(%s) failed", outPath); + return false; + } + + LOGMSG(l_DEBUG, "Processing '%u' images", images); + for (i = 0; i < images; i++) { + int dstfd = -1; + PnameTerminated = false; + if (pImgHeaderEntry[i].ptn_name[0] == 0x00 || + pImgHeaderEntry[i].size == 0) + break; + + if (pImageEnd < buf + start_offset + pImgHeaderEntry[i].size) { + LOGMSG(l_ERROR, "Image size mismatch"); + return false; + } + + for (j = 0; j < BOOTLDR_PARTITION_NAME_SZ; j++) { + if (!(pImgHeaderEntry[i].ptn_name[j])) { + PnameTerminated = true; + break; + } + } + if (!PnameTerminated) { + LOGMSG(l_ERROR, "ptn_name string not terminated properly"); + return false; + } + + // Write output file + memset(outFile, 0, sizeof(outFile)); + if (snprintf(outFile, sizeof(outFile), "%s/%s", outPath, pImgHeaderEntry[i].ptn_name) < 0) { + LOGMSG(l_ERROR, "Failed to construct output path string"); + return false; + } + dstfd = open(outFile, O_CREAT | O_EXCL | O_RDWR, 0644); + if (dstfd == -1) { + LOGMSG_P(l_ERROR, "Couldn't create output file '%s' in input directory", outFile); + return false; + } + + if (!utils_writeToFd(dstfd, buf + start_offset, pImgHeaderEntry[i].size)) { + close(dstfd); + return false; + } + + close(dstfd); + + start_offset += pImgHeaderEntry[i].size; + } + + return true; +} diff --git a/src/bootldr_image.h b/src/bootldr_image.h new file mode 100644 index 000000000000..15e188491b79 --- /dev/null +++ b/src/bootldr_image.h @@ -0,0 +1,50 @@ +/* + + qc_image_unpacker + ----------------------------------------- + + Dmitry Baryshkov + Copyright 2019 - 2020 by CENSUS S.A. All Rights Reserved. + Copyright 2021 by Linaro Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +#ifndef _BOOTLDR_IMAGE_H_ +#define _BOOTLDR_IMAGE_H_ + +#include "common.h" + +#define BOOTLDR_IMG_MAGIC1 0x544f4f42 +#define BOOTLDR_IMG_MAGIC2 0x2152444c +#define BOOTLDR_PARTITION_NAME_SZ 0x40 +//#define MAX_IMAGES_IN_BOOTLDRIMG 32 + +typedef struct bootldr_header { + u4 magic1; + u4 magic2; + u4 images; + u4 start_offset; + u4 full_size; +} bootldr_header_t; + +typedef struct bootldr_img_header_entry { + char ptn_name[BOOTLDR_PARTITION_NAME_SZ]; + u4 size; +} bootldr_img_header_entry_t; + +bool bootldr_image_detect(u1 *, size_t); +bool bootldr_image_extract(u1 *, size_t, char *, char *); + +#endif diff --git a/src/qc_image_unpacker.c b/src/qc_image_unpacker.c index 44d737803ea0..ea7fd0779645 100644 --- a/src/qc_image_unpacker.c +++ b/src/qc_image_unpacker.c @@ -25,6 +25,7 @@ #include "common.h" #include "log.h" +#include "bootldr_image.h" #include "meta_image.h" #include "packed_image.h" #include "utils.h" @@ -152,6 +153,12 @@ int main(int argc, char **argv) { LOGMSG(l_ERROR, "Skipping '%s'", pFiles.files[f]); goto next_file; } + } else if (bootldr_image_detect(buf, (size_t)fileSz)) { + LOGMSG(l_DEBUG, "bootldr image header found"); + if (!bootldr_image_extract(buf, (size_t)fileSz, pFiles.files[f], pRunArgs.outputDir)) { + LOGMSG(l_ERROR, "Skipping '%s'", pFiles.files[f]); + goto next_file; + } } else { LOGMSG(l_ERROR, "Invalid magic header 0x%x - skipping '%s'", *(u4*)buf, pFiles.files[f]); -- 2.35.1