diff --git a/bootloader/hos/pkg2.c b/bootloader/hos/pkg2.c index 5501edb..9c946ae 100644 --- a/bootloader/hos/pkg2.c +++ b/bootloader/hos/pkg2.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2021 CTCaer + * Copyright (c) 2018-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -72,17 +72,13 @@ void pkg2_get_ids(kip1_id_t **ids, u32 *entries) static void parse_external_kip_patches() { - static bool ext_patches_done = false; + static bool ext_patches_parsed = false; - if (ext_patches_done) + if (ext_patches_parsed) return; - u32 curr_kip_idx = 0; - char path[64]; - strcpy(path, "bootloader/patches.ini"); - LIST_INIT(ini_kip_sections); - if (ini_patch_parse(&ini_kip_sections, path)) + if (ini_patch_parse(&ini_kip_sections, "bootloader/patches.ini")) { // Copy ids into a new patchset. _kip_id_sets = calloc(sizeof(kip1_id_t), 256); // Max 256 kip ids. @@ -93,13 +89,15 @@ static void parse_external_kip_patches() { kip1_id_t* curr_kip = NULL; bool found = false; - for (curr_kip_idx = 0; curr_kip_idx < _kip_id_sets_cnt + 1; curr_kip_idx++) + for (u32 curr_kip_idx = 0; curr_kip_idx < _kip_id_sets_cnt + 1; curr_kip_idx++) { curr_kip = &_kip_id_sets[curr_kip_idx]; + // Check if reached the end of predefined list. if (!curr_kip->name) break; + // Check if name and hash match. if (!strcmp(curr_kip->name, ini_psec->name) && !memcmp(curr_kip->hash, ini_psec->hash, 8)) { found = true; @@ -140,23 +138,18 @@ static void parse_external_kip_patches() if (first_ext_patch) { first_ext_patch = false; - patchsets[curr_patchset_idx].name = malloc(strlen(pt->name) + 1); - strcpy(patchsets[curr_patchset_idx].name, pt->name); + patchsets[curr_patchset_idx].name = pt->name; patchsets[curr_patchset_idx].patches = patches; } - else + else if (strcmp(pt->name, patchsets[curr_patchset_idx].name)) { - // Check if new patchset name is found and create a new set. - if (strcmp(pt->name, patchsets[curr_patchset_idx].name)) - { - curr_patchset_idx++; - curr_patch_idx = 0; - patches = calloc(sizeof(kip1_patch_t), 16); // Max 16 patches per set. + // New patchset name found, create a new set. + curr_patchset_idx++; + curr_patch_idx = 0; + patches = calloc(sizeof(kip1_patch_t), 32); // Max 32 patches per set. - patchsets[curr_patchset_idx].name = malloc(strlen(pt->name) + 1); - strcpy(patchsets[curr_patchset_idx].name, pt->name); - patchsets[curr_patchset_idx].patches = patches; - } + patchsets[curr_patchset_idx].name = pt->name; + patchsets[curr_patchset_idx].patches = patches; } if (pt->length) @@ -164,10 +157,8 @@ static void parse_external_kip_patches() patches[curr_patch_idx].offset = pt->offset; patches[curr_patch_idx].length = pt->length; - patches[curr_patch_idx].srcData = malloc(pt->length); - patches[curr_patch_idx].dstData = malloc(pt->length); - memcpy(patches[curr_patch_idx].srcData, pt->srcData, pt->length); - memcpy(patches[curr_patch_idx].dstData, pt->dstData, pt->length); + patches[curr_patch_idx].srcData = (char *)pt->srcData; + patches[curr_patch_idx].dstData = (char *)pt->dstData; } else patches[curr_patch_idx].srcData = malloc(1); // Empty patches check. Keep everything else as 0. @@ -180,7 +171,7 @@ static void parse_external_kip_patches() } } - ext_patches_done = true; + ext_patches_parsed = true; } const pkg2_kernel_id_t *pkg2_identify(u8 *hash) @@ -436,19 +427,11 @@ static int _kipm_inject(const char *kipm_path, char *target_name, pkg2_kip1_info return 1; } -static bool ext_patches_parsed = false; - const char* pkg2_patch_kips(link_t *info, char* patchNames) { if (patchNames == NULL || patchNames[0] == 0) return NULL; - if (!ext_patches_parsed) - { - parse_external_kip_patches(); - ext_patches_parsed = true; - } - static const u32 MAX_NUM_PATCHES_REQUESTED = sizeof(u32) * 8; char* patches[MAX_NUM_PATCHES_REQUESTED]; @@ -498,6 +481,16 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames) DPRINTF("Requested patch: '%s'\n", patches[i]); } + // Parse external patches if needed. + for (u32 i = 0; i < numPatches; i++) + { + if (strcmp(patches[i], "emummc") && strcmp(patches[i], "nogc")) + { + parse_external_kip_patches(); + break; + } + } + u32 shaBuf[32 / sizeof(u32)]; LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link) { diff --git a/bootloader/hos/pkg2_ini_kippatch.c b/bootloader/hos/pkg2_ini_kippatch.c index ba8f0cd..e683320 100644 --- a/bootloader/hos/pkg2_ini_kippatch.c +++ b/bootloader/hos/pkg2_ini_kippatch.c @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019-2022 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include #include @@ -8,12 +24,12 @@ #define KPS(x) ((u32)(x) << 29) -static u8 *_htoa(u8 *result, const char *ptr, u8 byte_len) +static u8 *_htoa(u8 *result, const char *ptr, u8 byte_len, u8 *buf) { char ch = *ptr; u32 ascii_len = byte_len * 2; if (!result) - result = malloc(byte_len); + result = buf; u8 *dst = result; while (ch == ' ' || ch == '\t') @@ -46,24 +62,11 @@ static u8 *_htoa(u8 *result, const char *ptr, u8 byte_len) return result; } -static char *_strdup(char *str) -{ - if (!str) - return NULL; - if (str[0] == ' ' && (strlen(str) > 1)) - str++; - char *res = (char *)malloc(strlen(str) + 1); - strcpy(res, str); - if (res[strlen(res) - 1] == ' ' && (strlen(res) > 1)) - res[strlen(res) - 1] = 0; - - return res; -} - static u32 _find_patch_section_name(char *lbuf, u32 lblen, char schar) { u32 i; - for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n' && lbuf[i] != '\r'; i++) + // Depends on 'FF_USE_STRFUNC 2' that removes \r. + for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n'; i++) ; lbuf[i] = 0; @@ -75,12 +78,16 @@ static ini_kip_sec_t *_ini_create_kip_section(link_t *dst, ini_kip_sec_t *ksec, if (ksec) list_append(dst, &ksec->link); - ksec = (ini_kip_sec_t *)calloc(sizeof(ini_kip_sec_t), 1); - u32 i = _find_patch_section_name(name, strlen(name), ':') + 1; - ksec->name = _strdup(name); + // Calculate total allocation size. + u32 len = strlen(name); + char *buf = calloc(sizeof(ini_kip_sec_t) + len + 1, 1); + + ksec = (ini_kip_sec_t *)buf; + u32 i = _find_patch_section_name(name, len, ':') + 1; + ksec->name = strcpy_ns(buf + sizeof(ini_kip_sec_t), name); // Get hash section. - _htoa(ksec->hash, &name[i], 8); + _htoa(ksec->hash, &name[i], 8, NULL); return ksec; } @@ -89,13 +96,15 @@ int ini_patch_parse(link_t *dst, char *ini_path) { FIL fp; u32 lblen; - char lbuf[512]; + char *lbuf; ini_kip_sec_t *ksec = NULL; // Open ini. if (f_open(&fp, ini_path, FA_READ) != FR_OK) return 0; + lbuf = malloc(512); + do { // Fetch one line. @@ -111,37 +120,47 @@ int ini_patch_parse(link_t *dst, char *ini_path) { _find_patch_section_name(lbuf, lblen, ']'); + // Set patchset kip name and hash. ksec = _ini_create_kip_section(dst, ksec, &lbuf[1]); list_init(&ksec->pts); } - else if (ksec && lbuf[0] == '.') //Extract key/value. + else if (ksec && lbuf[0] == '.') // Extract key/value. { - u32 tmp = 0; - u32 i = _find_patch_section_name(lbuf, lblen, '='); + u32 str_start = 0; + u32 pos = _find_patch_section_name(lbuf, lblen, '='); - ini_patchset_t *pt = (ini_patchset_t *)calloc(sizeof(ini_patchset_t), 1); + // Calculate total allocation size. + char *buf = calloc(sizeof(ini_patchset_t) + strlen(&lbuf[1]) + 1, 1); + ini_patchset_t *pt = (ini_patchset_t *)buf; - pt->name = _strdup(&lbuf[1]); + // Set patch name. + pt->name = strcpy_ns(buf + sizeof(ini_patchset_t), &lbuf[1]); - u8 kip_sidx = lbuf[i + 1] - '0'; + u8 kip_sidx = lbuf[pos + 1] - '0'; + pos += 3; if (kip_sidx < 6) { + // Set patch offset. pt->offset = KPS(kip_sidx); - tmp = _find_patch_section_name(&lbuf[i + 3], lblen, ':'); - pt->offset |= strtol(&lbuf[i + 3], NULL, 16); + str_start = _find_patch_section_name(&lbuf[pos], lblen - pos, ':'); + pt->offset |= strtol(&lbuf[pos], NULL, 16); + pos += str_start + 1; - i += tmp + 4; + // Set patch size. + str_start = _find_patch_section_name(&lbuf[pos], lblen - pos, ':'); + pt->length = strtol(&lbuf[pos], NULL, 16); + pos += str_start + 1; - tmp = _find_patch_section_name(&lbuf[i], lblen, ':'); - pt->length = strtol(&lbuf[i], NULL, 16); + u8 *buf = malloc(pt->length * 2); - i += tmp + 1; + // Set patch source data. + str_start = _find_patch_section_name(&lbuf[pos], lblen - pos, ','); + pt->srcData = _htoa(NULL, &lbuf[pos], pt->length, buf); + pos += str_start + 1; - tmp = _find_patch_section_name(&lbuf[i], lblen, ','); - pt->srcData = _htoa(NULL, &lbuf[i], pt->length); - i += tmp + 1; - pt->dstData = _htoa(NULL, &lbuf[i], pt->length); + // Set patch destination data. + pt->dstData = _htoa(NULL, &lbuf[pos], pt->length, buf + pt->length); } list_append(&ksec->pts, &pt->link); @@ -153,5 +172,7 @@ int ini_patch_parse(link_t *dst, char *ini_path) if (ksec) list_append(dst, &ksec->link); + free(lbuf); + return 1; }