Implement first working draft of CRC patching
This commit is contained in:
parent
c8da6e4f4c
commit
341e0cecf8
164
elfpatch.c
164
elfpatch.c
@ -43,7 +43,46 @@ struct elfpatch {
|
|||||||
} \
|
} \
|
||||||
} while(0)
|
} 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)
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,6 +406,128 @@ int elf_patch_compute_crc_over_section(elfpatch_handle_t *ep, const char *sectio
|
|||||||
return 0;
|
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)
|
void elf_patch_close_and_free(elfpatch_handle_t *ep)
|
||||||
{
|
{
|
||||||
ret_if_ep_err(ep);
|
ret_if_ep_err(ep);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <patchelfcrc/crc.h>
|
#include <patchelfcrc/crc.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <linklist-lib/singly-linked-list.h>
|
||||||
|
|
||||||
typedef struct elfpatch elfpatch_handle_t;
|
typedef struct elfpatch elfpatch_handle_t;
|
||||||
|
|
||||||
@ -13,6 +14,10 @@ enum granularity {
|
|||||||
GRANULARITY_32BIT = 32,
|
GRANULARITY_32BIT = 32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum crc_format {
|
||||||
|
FORMAT_BARE = 0,
|
||||||
|
FORMAT_STRUCT,
|
||||||
|
};
|
||||||
|
|
||||||
elfpatch_handle_t *elf_patch_open(const char *path, bool readonly);
|
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);
|
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_ */
|
#endif /* _ELFPATCH_H_ */
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#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, ...);
|
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>";
|
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_DRY_RUN (1)
|
||||||
#define ARG_KEY_START_MAGIC (2)
|
#define ARG_KEY_START_MAGIC (2)
|
||||||
#define ARG_KEY_END_MAGIC (3)
|
#define ARG_KEY_END_MAGIC (3)
|
||||||
@ -55,6 +50,7 @@ struct command_line_options {
|
|||||||
bool list;
|
bool list;
|
||||||
SlList *section_list;
|
SlList *section_list;
|
||||||
const char *elf_path;
|
const char *elf_path;
|
||||||
|
const char *output_section;
|
||||||
};
|
};
|
||||||
|
|
||||||
static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
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"))
|
else if (!strcmp(arg, "word"))
|
||||||
args->granularity = GRANULARITY_32BIT;
|
args->granularity = GRANULARITY_32BIT;
|
||||||
break;
|
break;
|
||||||
|
case 'O':
|
||||||
|
args->output_section = arg;
|
||||||
|
break;
|
||||||
case ARGP_KEY_ARG:
|
case ARGP_KEY_ARG:
|
||||||
if (state->arg_num >= 1)
|
if (state->arg_num >= 1)
|
||||||
argp_usage(state);
|
argp_usage(state);
|
||||||
@ -178,6 +177,7 @@ static void prepare_default_opts(struct command_line_options *opts)
|
|||||||
opts->list = false;
|
opts->list = false;
|
||||||
opts->section_list = NULL;
|
opts->section_list = NULL;
|
||||||
opts->elf_path = NULL;
|
opts->elf_path = NULL;
|
||||||
|
opts->output_section = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_verbose_start_info(const struct command_line_options *cmd_opts)
|
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);
|
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) {
|
if (cmd_opts->section_list) {
|
||||||
for (list_iter = cmd_opts->section_list, i = 1; list_iter; list_iter = sl_list_next(list_iter), i++) {
|
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);
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!cmd_opts.output_section) {
|
||||||
|
print_err("No output section specified. Will continue but not patch file.\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (cmd_opts.list) {
|
if (cmd_opts.list) {
|
||||||
list_predefined_crcs();
|
list_predefined_crcs();
|
||||||
goto free_cmds;
|
goto free_cmds;
|
||||||
@ -377,6 +385,15 @@ int main(int argc, char **argv)
|
|||||||
print_crcs(cmd_opts.section_list, crcs);
|
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);
|
elf_patch_close_and_free(ep);
|
||||||
|
|
||||||
free_cmds:
|
free_cmds:
|
||||||
|
Loading…
Reference in New Issue
Block a user