Implement first working draft of CRC patching
This commit is contained in:
		
							
								
								
									
										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, ...);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
 Submodule linklist-lib updated: 18b3ab377a...c20b5c2528
									
								
							
							
								
								
									
										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:
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user