Implement first working draft of CRC patching
This commit is contained in:
parent
c8da6e4f4c
commit
341e0cecf8
2
crc.c
2
crc.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file is part of patchelfcrc .
|
||||
* This file is part of patchelfcrc.
|
||||
* Copyright (c) 2022 Mario Hüttel.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
|
164
elfpatch.c
164
elfpatch.c
@ -43,7 +43,46 @@ struct elfpatch {
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define print_err(fmt, ...) fprintf(stderr, (fmt), ## __VA_ARGS__);
|
||||
/**
|
||||
* @brief Convert a series of 4 bytes into a uint32_t dpending on endianess
|
||||
* @param data 4 bytes
|
||||
* @param little_endian data is little endian
|
||||
* @return uint32
|
||||
*/
|
||||
static uint32_t get_uint32_from_byte_string(const uint8_t *data, bool little_endian)
|
||||
{
|
||||
uint32_t out = 0ul;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (little_endian)
|
||||
out >>= 8u;
|
||||
else
|
||||
out <<= 8u;
|
||||
|
||||
out |= (((uint32_t)data[i]) << (little_endian ? 24u : 0u));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static void write_crc_to_byte_array(uint8_t *byte_array, uint32_t crc, uint8_t crc_size_bytes, bool little_endian)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!byte_array)
|
||||
return;
|
||||
|
||||
for (i = 0; i < crc_size_bytes; i++) {
|
||||
if (little_endian) {
|
||||
byte_array[i] = (uint8_t)(crc & 0xFFul);
|
||||
crc >>= 8u;
|
||||
} else {
|
||||
byte_array[i] = (uint8_t)((crc & 0xFF000000ul) >> 24u);
|
||||
crc <<= 8u;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void free_elf_section_element(struct elf_section *sec)
|
||||
{
|
||||
@ -278,7 +317,6 @@ static struct elf_section *find_section_in_list(SlList *list, const char *name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -368,6 +406,128 @@ int elf_patch_compute_crc_over_section(elfpatch_handle_t *ep, const char *sectio
|
||||
return 0;
|
||||
}
|
||||
|
||||
int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section, const SlList *section_name_list,
|
||||
const uint32_t *crcs, uint8_t crc_size_bits, uint32_t start_magic, uint32_t end_magic,
|
||||
bool check_start_magic, bool check_end_magic, enum crc_format format, bool little_endian)
|
||||
{
|
||||
int ret = -1;
|
||||
struct elf_section *output_section;
|
||||
Elf_Data *output_sec_data;
|
||||
const SlList *iter;
|
||||
size_t needed_space;
|
||||
size_t crc_count;
|
||||
uint8_t crc_size_bytes;
|
||||
uint8_t *sec_bytes;
|
||||
size_t idx;
|
||||
|
||||
ret_val_if_ep_err(ep, -1000);
|
||||
|
||||
print_debug("== Patch output file ==\n");
|
||||
|
||||
if (crc_size_bits < 1u || crc_size_bits > 32u) {
|
||||
print_err("Unsupported CRC size: %u", (unsigned int)crc_size_bits);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (format != FORMAT_BARE) {
|
||||
print_err("Currently only bare format is supported!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* All pointer parameters are required */
|
||||
if (!section || !section_name_list || !crcs)
|
||||
return -1000;
|
||||
|
||||
output_section = find_section_in_list(ep->sections, section);
|
||||
if (!output_section) {
|
||||
print_err("Cannot find output section '%s' to place CRCs. Exiting.\n", section);
|
||||
goto ret_err;
|
||||
}
|
||||
|
||||
/* Get data object of section */
|
||||
output_sec_data = elf_getdata(output_section->scn, NULL);
|
||||
sec_bytes = (uint8_t *)output_sec_data->d_buf;
|
||||
|
||||
/* Check the start and end magics */
|
||||
if (check_start_magic) {
|
||||
if (get_uint32_from_byte_string(sec_bytes, little_endian) != start_magic) {
|
||||
print_err("Start magic does not match: expected: 0x%08x, got: 0x%08x\n",
|
||||
start_magic, get_uint32_from_byte_string(sec_bytes, little_endian));
|
||||
goto ret_err;
|
||||
}
|
||||
print_debug("Start magic matching: 0x%08x\n", start_magic);
|
||||
}
|
||||
if (check_end_magic) {
|
||||
if (get_uint32_from_byte_string(&sec_bytes[output_sec_data->d_size - 4], little_endian) != end_magic) {
|
||||
print_err("End magic does not match: expected: 0x%08x, got: 0x%08x\n",
|
||||
end_magic,
|
||||
get_uint32_from_byte_string(&sec_bytes[output_sec_data->d_size - 4], little_endian));
|
||||
goto ret_err;
|
||||
}
|
||||
print_debug("End magic matching: 0x%08x\n", end_magic);
|
||||
}
|
||||
|
||||
/* Calculate Bytes needed for CRC */
|
||||
crc_size_bytes = (crc_size_bits + 7u) / 8u;
|
||||
crc_count = sl_list_length(section_name_list);
|
||||
|
||||
print_debug("CRC requires %u bytes.\n", (unsigned int)crc_size_bytes);
|
||||
switch (format) {
|
||||
case FORMAT_BARE:
|
||||
needed_space = crc_size_bytes * crc_count;
|
||||
break;
|
||||
default:
|
||||
needed_space = 0;
|
||||
print_err("Unsupported CRC output format\n");
|
||||
goto ret_err;
|
||||
}
|
||||
/* Add existing magic numbers to required space */
|
||||
if (check_start_magic)
|
||||
needed_space += 4u;
|
||||
if (check_end_magic)
|
||||
needed_space += 4u;
|
||||
|
||||
print_debug("Required space for %zu CRCs %s: %zu (available: %zu)\n",
|
||||
crc_count,
|
||||
(check_start_magic || check_end_magic ? "including magic values" : ""),
|
||||
needed_space,
|
||||
output_sec_data->d_size
|
||||
);
|
||||
if (needed_space > output_sec_data->d_size) {
|
||||
print_err("Not enough space in section. %zu bytes available but %zu needed\n",
|
||||
output_sec_data->d_size, needed_space);
|
||||
}
|
||||
|
||||
/* Checks finished. Write data to output section */
|
||||
if (format == FORMAT_BARE) {
|
||||
if (check_start_magic)
|
||||
sec_bytes += 4;
|
||||
|
||||
for (iter = section_name_list, idx = 0; iter; iter = sl_list_next(iter), idx++) {
|
||||
print_debug("Write CRC 0x%08x (%u bytes) for section %s\n", crcs[idx],
|
||||
(unsigned int)crc_size_bytes,
|
||||
iter->data);
|
||||
write_crc_to_byte_array(sec_bytes, crcs[idx], crc_size_bytes, little_endian);
|
||||
sec_bytes += crc_size_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update ELF file */
|
||||
if (ep->readonly) {
|
||||
print_debug("DRY RUN: File will not be updated\n");
|
||||
ret = 0;
|
||||
} else {
|
||||
if (elf_update(ep->elf, ELF_C_WRITE) < 0) {
|
||||
print_err("Error writing ELF file: %s\n", elf_errmsg(-1));
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ret_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void elf_patch_close_and_free(elfpatch_handle_t *ep)
|
||||
{
|
||||
ret_if_ep_err(ep);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <stdint.h>
|
||||
#include <patchelfcrc/crc.h>
|
||||
#include <stdbool.h>
|
||||
#include <linklist-lib/singly-linked-list.h>
|
||||
|
||||
typedef struct elfpatch elfpatch_handle_t;
|
||||
|
||||
@ -13,6 +14,10 @@ enum granularity {
|
||||
GRANULARITY_32BIT = 32,
|
||||
};
|
||||
|
||||
enum crc_format {
|
||||
FORMAT_BARE = 0,
|
||||
FORMAT_STRUCT,
|
||||
};
|
||||
|
||||
elfpatch_handle_t *elf_patch_open(const char *path, bool readonly);
|
||||
|
||||
@ -28,4 +33,17 @@ int elf_patch_compute_crc_over_section(elfpatch_handle_t *ep, const char *sectio
|
||||
|
||||
void elf_patch_close_and_free(elfpatch_handle_t *ep);
|
||||
|
||||
/**
|
||||
* @brief Write CRCs to output section. This will have no effect, if file is opened read onyl
|
||||
* @param ep Elf patch object
|
||||
* @param[in] section Section name to place CRCs in
|
||||
* @param[in] section_name_list The list of sections the data belongs to
|
||||
* @param[in] crcs CRCs. Must be of the same lenght as the \p section_name_list
|
||||
* @return 0 Success
|
||||
* @return -1000 Parameter error
|
||||
* @return -1 internal error
|
||||
*/
|
||||
int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section, const SlList *section_name_list,
|
||||
const uint32_t *crcs, uint8_t crc_size_bits, uint32_t start_magic, uint32_t end_magic,
|
||||
bool check_start_magic, bool check_end_magic, enum crc_format format, bool little_endian);
|
||||
#endif /* _ELFPATCH_H_ */
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define print_err(fmt, ...) fprintf(stderr, (fmt), ## __VA_ARGS__);
|
||||
#define print_err(fmt, ...) fprintf(stderr, "[ERR] " fmt, ## __VA_ARGS__);
|
||||
|
||||
void print_debug(const char *fmt, ...);
|
||||
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 18b3ab377ac30516f977e9831813ea37189d4028
|
||||
Subproject commit c20b5c2528a46fe6a4aa74631ae3b628f73ac24f
|
27
main.c
27
main.c
@ -31,11 +31,6 @@
|
||||
|
||||
const char *argp_program_bug_address = "<mario [dot] huettel [at] linux [dot] com>";
|
||||
|
||||
enum crc_format {
|
||||
FORMAT_BARE = 0,
|
||||
FORMAT_STRUCT,
|
||||
};
|
||||
|
||||
#define ARG_KEY_DRY_RUN (1)
|
||||
#define ARG_KEY_START_MAGIC (2)
|
||||
#define ARG_KEY_END_MAGIC (3)
|
||||
@ -55,6 +50,7 @@ struct command_line_options {
|
||||
bool list;
|
||||
SlList *section_list;
|
||||
const char *elf_path;
|
||||
const char *output_section;
|
||||
};
|
||||
|
||||
static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||
@ -108,6 +104,9 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||
else if (!strcmp(arg, "word"))
|
||||
args->granularity = GRANULARITY_32BIT;
|
||||
break;
|
||||
case 'O':
|
||||
args->output_section = arg;
|
||||
break;
|
||||
case ARGP_KEY_ARG:
|
||||
if (state->arg_num >= 1)
|
||||
argp_usage(state);
|
||||
@ -178,6 +177,7 @@ static void prepare_default_opts(struct command_line_options *opts)
|
||||
opts->list = false;
|
||||
opts->section_list = NULL;
|
||||
opts->elf_path = NULL;
|
||||
opts->output_section = NULL;
|
||||
}
|
||||
|
||||
static void print_verbose_start_info(const struct command_line_options *cmd_opts)
|
||||
@ -210,6 +210,10 @@ static void print_verbose_start_info(const struct command_line_options *cmd_opts
|
||||
print_debug("ELF file: %s\n", cmd_opts->elf_path);
|
||||
}
|
||||
|
||||
if (cmd_opts->output_section) {
|
||||
print_debug("Output section: %s\n", cmd_opts->output_section);
|
||||
}
|
||||
|
||||
if (cmd_opts->section_list) {
|
||||
for (list_iter = cmd_opts->section_list, i = 1; list_iter; list_iter = sl_list_next(list_iter), i++) {
|
||||
print_debug("Input section [%d]: \"%s\"\n", i, (const char *)list_iter->data);
|
||||
@ -342,6 +346,10 @@ int main(int argc, char **argv)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!cmd_opts.output_section) {
|
||||
print_err("No output section specified. Will continue but not patch file.\n");
|
||||
}
|
||||
|
||||
if (cmd_opts.list) {
|
||||
list_predefined_crcs();
|
||||
goto free_cmds;
|
||||
@ -377,6 +385,15 @@ int main(int argc, char **argv)
|
||||
print_crcs(cmd_opts.section_list, crcs);
|
||||
}
|
||||
|
||||
if (cmd_opts.output_section) {
|
||||
if (elf_patch_write_crcs_to_section(ep, cmd_opts.output_section, cmd_opts.section_list,
|
||||
crcs, 32, cmd_opts.start_magic, cmd_opts.end_magic,
|
||||
cmd_opts.has_start_magic, cmd_opts.has_end_magic,
|
||||
FORMAT_BARE, cmd_opts.little_endian)) {
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
elf_patch_close_and_free(ep);
|
||||
|
||||
free_cmds:
|
||||
|
Loading…
Reference in New Issue
Block a user