Skip to content

Commit

Permalink
wip: POC of checksums using bindesc
Browse files Browse the repository at this point in the history
Signed-off-by: Yonatan Schachter <yonatan.schachter@gmail.com>
  • Loading branch information
yonsch committed Oct 1, 2023
1 parent ed7d56f commit 2250154
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 0 deletions.
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1504,6 +1504,14 @@ set_target_properties(${logical_target_for_zephyr_elf} PROPERTIES OUTPUT_NAME ${
set(post_build_commands "")
set(post_build_byproducts "")

if(CONFIG_BINDESC_DEFINE_CHECKSUMS)
list(APPEND
post_build_commands
COMMAND
${Python3_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/gen_bindesc_checksums.py ${KERNEL_ELF_NAME}
)
endif()

list(APPEND
post_build_commands
COMMAND
Expand Down
6 changes: 6 additions & 0 deletions include/zephyr/bindesc.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ extern "C" {
/** The C++ compiler version */
#define BINDESC_ID_CXX_COMPILER_VERSION 0xb04

/** The MD5 checksum as bytes */
#define BINDESC_ID_CHECKSUM_MD5_BYTES 0xc00

/** The MD5 checksum as a string */
#define BINDESC_ID_CHECKSUM_MD5_STRING 0xc01

#define BINDESC_TAG_DESCRIPTORS_END BINDESC_TAG(DESCRIPTORS_END, 0x0fff)

/**
Expand Down
6 changes: 6 additions & 0 deletions samples/subsys/bindesc/hello_bindesc/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,9 @@ CONFIG_BINDESC_APP_VERSION_STRING=y
CONFIG_BINDESC_DEFINE_HOST_INFO=y
CONFIG_BINDESC_C_COMPILER_NAME=y
CONFIG_BINDESC_C_COMPILER_VERSION=y


CONFIG_BINDESC_DEFINE_CHECKSUMS=y
CONFIG_BINDESC_CHECKSUM_MD5_STRING=y
CONFIG_BINDESC_CHECKSUM_MD5_BYTES=y
CONFIG_BINDESC_DEFINE_DESCRIPTORS_SIZE=512
72 changes: 72 additions & 0 deletions scripts/build/gen_bindesc_checksums.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env python3

import sys
import hashlib
from elftools.elf.elffile import ELFFile
from elftools.elf.constants import SH_FLAGS

Check warning on line 6 in scripts/build/gen_bindesc_checksums.py

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

W0611

scripts/build/gen_bindesc_checksums.py:6 Unused SH_FLAGS imported from elftools.elf.constants (unused-import)


BINDESC_OFFSETOF_DATA = 4
HASH_ALGORITHMS = {
"md5": hashlib.md5,
}


def set_checksums(filename):
with open(filename, 'rb+') as file_stream:
elffile = ELFFile(file_stream)

# Variable for storing the raw bytes of the image
image_data = b""

# Iterate over the segments to produce the image to calculate the
# checksums over.
for segment in elffile.iter_segments():
if segment.header.p_type != "PT_LOAD":
continue

if segment.header.p_filesz == 0:
continue

for section in elffile.iter_sections():
if segment.section_in_segment(section):
if not (section.name == "rom_start" and segment.section_in_segment(section)):
# Don't include rom_start in the checksum calculation
image_data += section.data()

symbol_table = elffile.get_section_by_name(".symtab")

# The binary descriptors to modify are found in the rom_start section
rom_start = elffile.get_section_by_name("rom_start")

for symbol in symbol_table.iter_symbols():
# Iterate over all the symbols, modify the checksums
if symbol.name.startswith("bindesc_entry_checksum"):
# Determine the alorithm and data type
_, _, _, algorithm, data_type = symbol.name.split("_")

# Calculate the checksum
checksum = HASH_ALGORITHMS[algorithm](image_data)
if data_type == "bytes":
to_write = checksum.digest()
else:
to_write = checksum.hexdigest().encode()

# Calculate the offset of the ELF file to write the checksum to
# The formula is: offset of rom_start + address of the symbol minus
# the base address of rom_start + offset of the data inside the descriptor
# entry.
offset = rom_start.header.sh_offset + \
symbol.entry.st_value - rom_start.header.sh_addr + \
BINDESC_OFFSETOF_DATA

# Write the hash to the file
elffile.stream.seek(offset)
elffile.stream.write(to_write)


def main():
set_checksums(sys.argv[1])

if __name__ == "__main__":
main()
2 changes: 2 additions & 0 deletions scripts/west_commands/bindesc.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ def __init__(self):
self.bindesc_gen_tag(self.TYPE_STR, 0xb02): 'C_COMPILER_VERSION',
self.bindesc_gen_tag(self.TYPE_STR, 0xb03): 'CXX_COMPILER_NAME',
self.bindesc_gen_tag(self.TYPE_STR, 0xb04): 'CXX_COMPILER_VERSION',
self.bindesc_gen_tag(self.TYPE_BYTES, 0xc00): 'CHECKSUM_MD5_BYTES',
self.bindesc_gen_tag(self.TYPE_STR, 0xc01): 'CHECKSUM_MD5_STRING',
}
self.NAME_TO_TAG = {v: k for k, v in self.TAG_TO_NAME.items()}

Expand Down
2 changes: 2 additions & 0 deletions subsys/bindesc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,5 @@ if(CONFIG_BINDESC_DEFINE_HOST_INFO)
gen_str_definition(CXX_COMPILER_NAME ${CMAKE_CXX_COMPILER_ID})
gen_str_definition(CXX_COMPILER_VERSION ${CMAKE_CXX_COMPILER_VERSION})
endif()

zephyr_library_sources_ifdef(CONFIG_BINDESC_DEFINE_CHECKSUMS bindesc_checksums.c)
19 changes: 19 additions & 0 deletions subsys/bindesc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,28 @@ config BINDESC_DEFINE

if BINDESC_DEFINE

config BINDESC_DEFINE_DESCRIPTORS_SIZE
int "Binary descriptors descriptors size"
default 0
help
Determines the total amount of bytes allocated to the descriptors.
If the size is larger than the actual size of the descriptors, padding
will be added to ensure that the total amount is equal to this symbol.
If the size is smaller, it will have no effect.
This might be useful to ensure that the checksum of the image remains
the same even if the descriptors change in size (the descriptors themselves
are not part of the checksum calculation).
For example, if an app uses the host name descriptor and an md5 checksum descriptor,
compiling on machines with names of different sizes will result in images
with different checksums. By allocating a constant size for the descriptors, the
descriptors have room to grow.
The size should be set by the app to a value slightly larger than the size of the
descriptors. Setting this to zero will disable this feature.

source "subsys/bindesc/Kconfig.version"
source "subsys/bindesc/Kconfig.build_time"
source "subsys/bindesc/Kconfig.host_info"
source "subsys/bindesc/Kconfig.checksums"

endif # BINDESC_DEFINE

Expand Down
21 changes: 21 additions & 0 deletions subsys/bindesc/Kconfig.checksums
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright (c) 2023 Yonatan Schachter
# SPDX-License-Identifier: Apache-2.0

menuconfig BINDESC_DEFINE_CHECKSUMS
bool "Checksum binary descriptors"
help
Add checksum binary descriptors

if BINDESC_DEFINE_CHECKSUMS

config BINDESC_CHECKSUM_MD5_BYTES
bool "MD5 checksum as bytes"
help
MD5 checksum as bytes

config BINDESC_CHECKSUM_MD5_STRING
bool "MD5 checksum as a string"
help
MD5 checksum as a string

endif # BINDESC_DEFINE_CHECKSUMS
6 changes: 6 additions & 0 deletions subsys/bindesc/bindesc.ld
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@
#include <zephyr/linker/iterable_sections.h>
#include <zephyr/bindesc.h>

#define BINDESC_MAX(a, b) (((a) > (b)) ? (a) : (b))

bindesc_start = .;
SQUAD(BINDESC_MAGIC);
Z_LINK_ITERABLE(bindesc_entry);
. = ALIGN(BINDESC_ALIGNMENT);
LONG(BINDESC_TAG_DESCRIPTORS_END)
. = BINDESC_MAX(bindesc_start + CONFIG_BINDESC_DEFINE_DESCRIPTORS_SIZE, .);
. = ALIGN(BINDESC_ALIGNMENT);
bindesc_end = .;
18 changes: 18 additions & 0 deletions subsys/bindesc/bindesc_checksums.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright (c) 2023 Yonatan Schachter
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/kernel.h>
#include <zephyr/bindesc.h>

#if IS_ENABLED(CONFIG_BINDESC_CHECKSUM_MD5_BYTES)
BINDESC_BYTES_DEFINE(checksum_md5_bytes, BINDESC_ID_CHECKSUM_MD5_BYTES,
({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}));
#endif /* IS_ENABLED(CONFIG_BINDESC_CHECKSUM_MD5_BYTES) */

#if IS_ENABLED(CONFIG_BINDESC_CHECKSUM_MD5_STRING)
BINDESC_STR_DEFINE(checksum_md5_string, BINDESC_ID_CHECKSUM_MD5_STRING,
"00000000000000000000000000000000");
#endif /* IS_ENABLED(CONFIG_BINDESC_CHECKSUM_MD5_STRING) */

0 comments on commit 2250154

Please sign in to comment.