Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions kernel/include/sentry/zlib/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,18 @@ void *sentry_memset(void *s, int c, unsigned int n);
*/
void *sentry_memcpy(void * restrict dest, const void* restrict src, size_t n);

/*@
requires \valid_read((uint8_t*)s1+(0..n-1));
requires \valid_read((uint8_t*)s2+(0..n-1));
requires \initialized((uint8_t*)s1+(0..n-1));
requires \initialized((uint8_t*)s2+(0..n-1));
assigns \result \from indirect:s1, indirect:s2, indirect:n;
ensures \result == 0 <==> \forall integer k; 0 <= k < n ==> ((uint8_t*)s1)[k] == ((uint8_t*)s2)[k];
ensures \result < 0 <==> \exists integer k; 0 <= k < n && ((uint8_t*)s1)[k] < ((uint8_t*)s2)[k] && \forall integer j; 0 <= j < k ==> ((uint8_t*)s1)[j] == ((uint8_t*)s2)[j];
ensures \result > 0 <==> \exists integer k; 0 <= k < n && ((uint8_t*)s1)[k] > ((uint8_t*)s2)[k] && \forall integer j; 0 <= j < k ==> ((uint8_t*)s1)[j] == ((uint8_t*)s2)[j];
*/
int sentry_memcmp(const void *s1, const void *s2, size_t n);

/**
* Note: because frama-c as no link notion and uses cpp+internal analysis, we cannot
* use the __attribute__((alias("fct"))) trick to alias the sentry_ prefixed
Expand Down
39 changes: 32 additions & 7 deletions kernel/src/managers/task/task_init.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2023 Ledger SAS
// SPDX-FileCopyrightText: 2026 H2Lab Development Team
// SPDX-License-Identifier: Apache-2.0

/**
Expand All @@ -15,6 +16,7 @@
#include <sentry/arch/asm-generic/membarriers.h>
#include <sentry/arch/asm-generic/platform.h>
#include <sentry/arch/asm-generic/panic.h>
#include <sentry/zlib/crypto.h>
#include <sentry/zlib/sort.h>

#include "task_core.h"
Expand All @@ -34,14 +36,14 @@ typedef enum task_mgr_state {
TASK_MANAGER_STATE_BOOT = 0x0UL, /**< at boot time */
/* for each cell of task_meta_table */
TASK_MANAGER_STATE_DISCOVER_SANITATION, /**< magic & version check */
TASK_MANAGER_STATE_CHECK_META_INTEGRITY,/**< metadata HMAC check */
TASK_MANAGER_STATE_CHECK_TSK_INTEGRITY, /**< task HMAC check */
TASK_MANAGER_STATE_CHECK_META_INTEGRITY,/**< metadata SHA-256 check */
TASK_MANAGER_STATE_CHECK_TSK_INTEGRITY, /**< task SHA-256 check */
TASK_MANAGER_STATE_INIT_LOCALINFO, /**< init dynamic task info into local struct */
TASK_MANAGER_STATE_TSK_MAP, /**< task data copy, bss zeroify, stack init */
TASK_MANAGER_STATE_TSK_SCHEDULE, /**< schedule task (if start at bootup) */
TASK_MANAGER_STATE_FINALIZE, /**< all tasks added, finalize (sort task list) */
TASK_MANAGER_STATE_READY, /**< ready state, everything is clean */
TASK_MANAGER_STATE_ERROR_SECURITY, /**< hmac or magic error */
TASK_MANAGER_STATE_ERROR_SECURITY, /**< sha256 or magic error */
TASK_MANAGER_STATE_ERROR_RUNTIME, /**< others (sched...) */
} task_mgr_state_t;

Expand Down Expand Up @@ -71,7 +73,7 @@ static struct task_mgr_ctx ctx;
* the task mapping order is based on the label list (from the smaller to the higher)
* so that binary search can be done on the task set below
* 3. upgrade each task ELF based on the calculated memory mapping
* 4. forge the task metadata from the new ELF, including HMACs, save it to a dediacted file
* 4. forge the task metadata from the new ELF, including SHA-256 digests, save it to a dediacted file
* 5. store the metadata in the first free cell of the .task_list section bellow
*
* In a different (v2?) mode, it is possible to consider that tasks metadata can be stored
Expand Down Expand Up @@ -139,8 +141,31 @@ static inline kstatus_t task_init_check_meta_integrity(task_meta_t const * const
ctx.state = TASK_MANAGER_STATE_ERROR_SECURITY;
goto end;
}
/* FIXME: call the hmac service in order to validate metadata integrity,
and return the result */
#if CONFIG_SECU_METADATA_SHA256_CHECK
task_meta_t meta_copy;
uint8_t digest[SHA256_DIGEST_SIZE];

if (memcpy(&meta_copy, meta, sizeof(meta_copy)) != &meta_copy) {
pr_err("[task %08x] unable to copy metadata for sha256 verification", meta->label);
ctx.state = TASK_MANAGER_STATE_ERROR_SECURITY;
goto end;
}

(void)memset(meta_copy.metadata_sha256, 0x0, sizeof(meta_copy.metadata_sha256));

/* recalculate the sha256 of the metadata. the metadata_sha256 is not a part of the calculation */
if (sha256((const uint8_t *)meta, offsetof(task_meta_t, metadata_sha256), digest) != 0) {
pr_err("[task %08x] metadata sha256 computation failed", meta->label);
ctx.state = TASK_MANAGER_STATE_ERROR_SECURITY;
goto end;
}

if (memcmp(meta->metadata_sha256, digest, sizeof(digest)) != 0) {
pr_err("[task %08x] metadata sha256 mismatch", meta->label);
ctx.state = TASK_MANAGER_STATE_ERROR_SECURITY;
goto end;
}
#endif
pr_info("[task %08x] metadata integrity ok", meta->label);
ctx.state = TASK_MANAGER_STATE_CHECK_TSK_INTEGRITY;
status = K_STATUS_OKAY;
Expand All @@ -164,7 +189,7 @@ static inline kstatus_t task_init_check_tsk_integrity(task_meta_t const * const
ctx.state = TASK_MANAGER_STATE_ERROR_SECURITY;
goto end;
}
/* FIXME: call the hmac service in order to validate metadata integrity,
/* FIXME: call the sha256 service in order to validate metadata integrity,
and return the result */
pr_info("[task %08x] task code+data integrity ok", meta->label);
ctx.state = TASK_MANAGER_STATE_INIT_LOCALINFO;
Expand Down
1 change: 1 addition & 0 deletions kernel/src/syscalls/sysgate_int_acknowledge.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ stack_frame_t *gate_int_acknowledge(stack_frame_t *frame, uint16_t IRQn)
mgr_task_set_sysreturn(current, STATUS_DENIED);
goto end;
}

/* push the inth event into the task input events queue */
if (unlikely(mgr_interrupt_acknowledge_irq(IRQn) != K_STATUS_OKAY)) {
/* should not rise while IRQ ownership has been checked! see dts file */
Expand Down
44 changes: 44 additions & 0 deletions kernel/src/zlib/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,56 @@ void *sentry_memcpy(void * restrict dest, const void* restrict src, size_t n)
return dest;
}

/**
* @brief Compare n first bytes of s1 and s2, returning an integer less than, equal to, or greater than zero if s1 is found, respectively, to be less than, to match, or be greater than s2.
*
* INFO: The C standard says that null argument(s) to string functions produce undefined behavior. Here such a case is trapped.
*
* @conforming to:
* POSIX.1-2001, POSIX.1-2008, C89, C99, SVr4, 4.3BSD.
*
* @param s1 first memory area to compare
* @param s2 second memory area to compare
* @param n number of bytes to compare
*
* @return an integer less than, equal to, or greater than zero if s1 is found, respectively, to be less than, to match, or be greater than s2.
*/
int sentry_memcmp(const void *s1, const void *s2, size_t n)
{
int res = 0;
if (unlikely(s1 == NULL || s2 == NULL)) {
goto err;
}
/*@ assert \valid_read((uint8_t*)s1 + (0 .. (n-1))); */
/*@ assert \valid_read((uint8_t*)s2 + (0 .. (n-1))); */
/*@ assert \initialized((uint8_t*)s1+(0..n-1)); */
/*@ assert \initialized((uint8_t*)s2+(0..n-1)); */
/*@ assert \separated((uint8_t*)s1 + (0 .. n-1), (uint8_t*)s2 + (0 .. n-1)); */

/*@
loop invariant 0 <= i <= n;
loop invariant res == 0;
loop invariant \forall integer k; 0 <= k < i ==> ((uint8_t*)s1)[k] == ((uint8_t*)s2)[k];
loop assigns i, res;
loop variant n - i;
*/
for (size_t i = 0; i < n; i++) {
if (((uint8_t*)s1)[i] != ((uint8_t*)s2)[i]) {
res = ((uint8_t*)s1)[i] - ((uint8_t*)s2)[i];
goto err;
}
}
err:
return res;
}

#ifndef TEST_MODE
#ifndef __FRAMAC__
/** NOTE: FramaC requires that we use its own compiler builtins (see -eva-builtins-list for more info) */
/* if not in the test suite case, aliasing to POSIX symbols, standard string.h header can be added */
size_t strnlen(const char *s, size_t maxlen) __attribute__((alias("sentry_strnlen")));
void* memset(void *s, int c, unsigned int n) __attribute__((alias("sentry_memset")));
void* memcpy(void * restrict d, const void * restrict s, size_t) __attribute__((alias("sentry_memcpy")));
int memcmp(const void *s1, const void *s2, size_t n) __attribute__((alias("sentry_memcmp")));
#endif
#endif/*!TEST_MODE*/
8 changes: 4 additions & 4 deletions schemas/task/metadata.schema.json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@
"minItems": 0,
"maxItems": CONFIG_MAX_DMA_STREAMS_PER_TASK
},
"task_hmac": {
"task_sha256": {
"type": "array",
"items": {
"type": "object",
Expand All @@ -648,7 +648,7 @@
]
}
},
"metadata_hmac": {
"metadata_sha256": {
"type": "array",
"items": {
"type": "object",
Expand Down Expand Up @@ -695,7 +695,7 @@
"devs",
"num_dma",
"dmas",
"task_hmac",
"metadata_hmac"
"task_sha256",
"metadata_sha256"
]
}
4 changes: 2 additions & 2 deletions schemas/task/sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,14 @@
"description": "number of task dma stream(s)",
"dmas": []
},
"task_hmac": [
"task_sha256": [
{
"c_type": "uint8_t",
"rust_type": "u8",
"value": 12
}
],
"metadata_hmac": [
"metadata_sha256": [
{
"c_type": "uint8_t",
"rust_type": "u8",
Expand Down
4 changes: 2 additions & 2 deletions schemas/task/sample.toml
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,12 @@ description = "number of task dma stream(s)"

dmas = [ ]

[[task_hmac]]
[[task_sha256]]
c_type = "uint8_t"
rust_type = "u8"
value = 12

[[metadata_hmac]]
[[metadata_sha256]]
c_type = "uint8_t"
rust_type = "u8"
value = 12
8 changes: 4 additions & 4 deletions schemas/task/task_metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -152,22 +152,22 @@
"description": "dma stream handler identifier"
}
},
"task_hmac": {
"task_sha256": {
"array": true,
"array_size": 32,
"element": {
"c_type": "uint8_t",
"rust_type": "u8",
"description": "task .text+.rodata+.data build time hmac calculation (TBD)"
"description": "task .text+.rodata+.data build time SHA-256 digest"
}
},
"metadata_hmac": {
"metadata_sha256": {
"array": true,
"array_size": 32,
"element": {
"c_type": "uint8_t",
"rust_type": "u8",
"description": "current struct build time hmac calculation"
"description": "current struct build time SHA-256 digest"
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion tools/genmetadata/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ add_languages('cpp', native: true, required: true)

nl_json = dependency('nlohmann_json', native: true, version: '>=3.11')
argparse = dependency('argparse', native: true, version: '>=3')
openssl = dependency('openssl', native: true)

subdir('src')

Expand All @@ -15,7 +16,7 @@ genmetadata = executable(
include_directories: kernel_inc,
link_language: 'cpp',
override_options: ['cpp_std=gnu++20'],
dependencies: [ nl_json, argparse ],
dependencies: [ nl_json, argparse, openssl ],
build_by_default: true,
install_dir: get_option('libexecdir'),
native: true,
Expand Down
9 changes: 9 additions & 0 deletions tools/genmetadata/src/arch/arch.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2024 Ledger SAS
// SPDX-FileCopyrightText: 2026 H2Lab
// SPDX-License-Identifier: Apache-2.0

/*
Expand Down Expand Up @@ -30,3 +31,11 @@ template<typename T, typename ... U>
concept IsAnyOf = (std::same_as<T, U> || ...);

} // namespace arch

#include "armv8m.hpp"

namespace arch {

using memory_spec = armv8m::memory_spec;

} // namespace arch
22 changes: 20 additions & 2 deletions tools/genmetadata/src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2024 Ledger SAS
// SPDX-FileCopyrightText: 2026 H2Lab
// SPDX-License-Identifier: Apache-2.0

/*
Expand All @@ -23,13 +24,16 @@
#include <string>
#include <iostream>
#include <sstream>
#include <array>
#include <stdexcept>

#include <nlohmann/json.hpp>
#include <argparse/argparse.hpp>
#include <openssl/sha.h>

#include "task_meta.hpp"
#include "reflect.hpp"
#include "arch/armv8m.hpp"
#include "arch/arch.hpp"

using json = nlohmann::json;

Expand All @@ -46,7 +50,21 @@ int main(int argc, char *argv[])
std::string out{program.get<std::string>("output")};
auto data = json::parse(in);
auto meta = taskMetadata::from_json(data["task_meta"]);
reflect_to_bin<arch::armv8m::memory_spec>(meta, out);

std::array<uint8_t, SHA256_DIGEST_LENGTH> sha256{};
auto blob = reflect::to_bytes<arch::memory_spec>(meta);
const auto hashed_blob_size = blob.size() - sha256.size();
if (SHA256(reinterpret_cast<const unsigned char*>(blob.data()), hashed_blob_size, sha256.data()) == nullptr) {
throw std::runtime_error("failed to compute metadata_sha256");
}

// update sha256 in bytearray which is the last field, has to be written at the end of container.
// reverse copy of sha256 (i.e.from end IT to start IT) into reverse begin blob IT.
auto sha256_raw = std::as_bytes(std::span{sha256});
std::reverse_copy(std::begin(sha256_raw), std::end(sha256_raw), std::rbegin(blob));

std::ofstream f(out, std::ios::binary);
f.write(reinterpret_cast<const char*>(blob.data()), static_cast<std::streamsize>(blob.size()));
}
catch (const std::exception& err) {
std::cerr << err.what() << std::endl;
Expand Down
Loading
Loading