Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kernel: version: option to enable GNU build ID #51532

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions Kconfig.zephyr
Expand Up @@ -200,6 +200,18 @@ config KERNEL_ENTRY
help
Code entry symbol, to be set at linking phase.

config TOOLCHAIN_SUPPORTS_GNU_BUILD_ID
bool
default y
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd make this default n, and explicitly set it y for those that support it.


config LINKER_GNU_BUILD_ID
bool "Generate a GNU build ID for the binary"
depends on TOOLCHAIN_SUPPORTS_GNU_BUILD_ID
help
This turns on the linker flag to generate a 160 bit SHA1 hash of
the final `zephyr.elf` contents. This hash can be used to uniquely
identify a firmware image. Total structure size is 36 bytes.

config LINKER_SORT_BY_ALIGNMENT
bool "Sort input sections by alignment"
default y
Expand Down
7 changes: 6 additions & 1 deletion cmake/linker/ld/target_base.cmake
Expand Up @@ -17,9 +17,14 @@ macro(toolchain_ld_base)

zephyr_ld_options(
${LINKERFLAGPREFIX},--gc-sections
${LINKERFLAGPREFIX},--build-id=none
)

if(CONFIG_LINKER_GNU_BUILD_ID)
zephyr_ld_options(${LINKERFLAGPREFIX},--build-id)
else()
zephyr_ld_options(${LINKERFLAGPREFIX},--build-id=none)
endif()

# Sort the common symbols and each input section by alignment
# in descending order to minimize padding between these symbols.
zephyr_ld_option_ifdef(
Expand Down
7 changes: 6 additions & 1 deletion cmake/linker/lld/target_base.cmake
Expand Up @@ -17,9 +17,14 @@ macro(toolchain_ld_base)

zephyr_ld_options(
${LINKERFLAGPREFIX},--gc-sections
${LINKERFLAGPREFIX},--build-id=none
)

if(CONFIG_LINKER_GNU_BUILD_ID)
zephyr_ld_options(${LINKERFLAGPREFIX},--build-id)
else()
zephyr_ld_options(${LINKERFLAGPREFIX},--build-id=none)
endif()

# Sort each input section by alignment.
zephyr_ld_option_ifdef(
CONFIG_LINKER_SORT_BY_ALIGNMENT
Expand Down
4 changes: 4 additions & 0 deletions cmake/toolchain/arcmwdt/Kconfig
Expand Up @@ -4,3 +4,7 @@
config TOOLCHAIN_ARCMWDT_SUPPORTS_THREAD_LOCAL_STORAGE
def_bool y
select TOOLCHAIN_SUPPORTS_THREAD_LOCAL_STORAGE

config TOOLCHAIN_SUPPORTS_GNU_BUILD_ID
bool
default n
4 changes: 4 additions & 0 deletions cmake/toolchain/armclang/Kconfig
@@ -1,6 +1,10 @@
# Copyright (c) 2021 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

config TOOLCHAIN_SUPPORTS_GNU_BUILD_ID
bool
default n

config LD_LINKER_SCRIPT_SUPPORTED
bool
default n
Expand Down
12 changes: 12 additions & 0 deletions include/zephyr/kernel_version.h
Expand Up @@ -46,6 +46,18 @@ extern "C" {
*/
extern uint32_t sys_kernel_version_get(void);

#ifdef CONFIG_LINKER_GNU_BUILD_ID
/**
* @brief Return the pointer to the GNU build ID
*
* The GNU build ID is a 160bit (20 byte) SHA1 hash of the elf header bits and
* section data.
*
* @retval build_id Pointer to 20 byte build ID
*/
const uint8_t *sys_gnu_build_id_get(void);
#endif /* CONFIG_LINKER_GNU_BUILD_ID */

/**
* @}
*/
Expand Down
8 changes: 8 additions & 0 deletions include/zephyr/linker/common-rom/common-rom-misc.ld
Expand Up @@ -25,6 +25,14 @@
} GROUP_LINK_IN(ROMABLE_REGION)
#endif /* CONFIG_EMUL */

#if defined (CONFIG_LINKER_GNU_BUILD_ID)
SECTION_PROLOGUE(.gnu_build_id,,)
{
__g_note_build_id = .;
*(.note.gnu.build-id)
} GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
#endif /* CONFIG_LINKER_GNU_BUILD_ID */

SECTION_DATA_PROLOGUE(symbol_to_keep,,)
{
__symbol_to_keep_start = .;
Expand Down
22 changes: 22 additions & 0 deletions kernel/version.c
Expand Up @@ -5,6 +5,7 @@
*/

#include <zephyr/types.h>
#include <zephyr/sys/__assert.h>
#include "version.h" /* generated by MAKE, at compile time */

/**
Expand All @@ -19,3 +20,24 @@ uint32_t sys_kernel_version_get(void)
{
return KERNELVERSION;
}

#ifdef CONFIG_LINKER_GNU_BUILD_ID

/* Structure of .elf notes */
struct elf_note_section {
uint32_t name_sz;
uint32_t desc_sz;
uint32_t type;
uint8_t data[];
};

/* Variable instantiated by the linker */
extern const struct elf_note_section __g_note_build_id;

const uint8_t *sys_gnu_build_id_get(void)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the event that this expands out into supporting other toolchains, the build ID may be differently sized... I'd suggest an interface more like this.

Suggested change
const uint8_t *sys_gnu_build_id_get(void)
void sys_build_id_get(const uint8_t **buf, size_t *len)

{
__ASSERT_NO_MSG(__g_note_build_id.desc_sz == 20);
return &__g_note_build_id.data[__g_note_build_id.name_sz];
}

#endif /* CONFIG_LINKER_GNU_BUILD_ID */
1 change: 1 addition & 0 deletions tests/kernel/common/prj.conf
Expand Up @@ -4,6 +4,7 @@ CONFIG_LOG=y
CONFIG_POLL=y
CONFIG_BOOT_DELAY=500
CONFIG_IRQ_OFFLOAD=y
CONFIG_LINKER_GNU_BUILD_ID=y
CONFIG_TEST_USERSPACE=y
CONFIG_BOUNDS_CHECK_BYPASS_MITIGATION=y
CONFIG_ZTEST_NEW_API=y
27 changes: 27 additions & 0 deletions tests/kernel/common/src/main.c
Expand Up @@ -52,6 +52,33 @@ ZTEST(common, test_version)

}

/**
* @brief Test sys_gnu_build_id_get() functionality
*
* @ingroup kernel_common_tests
*
* @see sys_gnu_build_id_get()
*/
ZTEST(common, test_build_id)
{
#ifdef CONFIG_LINKER_GNU_BUILD_ID
const uint8_t *build_id = sys_gnu_build_id_get();
bool not_zero = false;

zassert_not_null(build_id);

printk("GNU Build ID: ");
for (int i = 0; i < 20; i++) {
printk("%02x", build_id[i]);
if (build_id[i]) {
not_zero = true;
}
}
printk("\n");
zassert_true(not_zero, "GNU Build ID all 0's");
#endif /* CONFIG_LINKER_GNU_BUILD_ID */
}

ZTEST(common, test_bounds_check_mitigation)
{
/* Very hard to test against speculation attacks, but we can
Expand Down