refactor(core): remove coreapp specific logic from applets
What changed, and why it matters
This commit is a code cleanup that moves coreapp-specific logic out of the generic applet code into a new dedicated coreapp module. It does not appear to fix or introduce a security vulnerability; it is a structural refactor to make the applet abstraction more generic and prepare for future extension applets.
No security action required. Treat as a normal code-quality refactor; review as part of standard code review to ensure the moved logic preserves behavior, especially around TLS enablement and memory clearing.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The refactor removes coreapp-specific types (applet_header_t, applet_startup_t) and the applet_reset() function from the generic applet.h/applet.c, and introduces a new coreapp.h/coreapp.c module containing coreapp_header_t, coreapp_init(), coreapp_reset(), and helpers coreapp_get_code_area()/coreapp_get_tls_area(). The kernel main.c and secure_aes_unpriv.c are updated to use the new coreapp APIs. The build scripts add coreapp.c to the sources. The change also adds systask_enable_tls() during coreapp reset and records code/TLS areas for later use by extension applets.
Changed components
core/embed/sys/task/stm32/applet.ccore/embed/sys/task/stm32/coreapp.ccore/embed/sys/task/inc/sys/applet.hcore/embed/sys/task/inc/sys/coreapp.hcore/embed/projects/kernel/main.ccore/embed/sec/secure_aes/stm32u5/secure_aes_unpriv.ccore/site_scons/models/stm32f4_common.pycore/site_scons/models/stm32u5_common.pyInspect captured patch +205 / −116
diff --git a/core/embed/projects/kernel/main.c b/core/embed/projects/kernel/main.c
index 966b8189..10532a4f 100644
--- a/core/embed/projects/kernel/main.c
+++ b/core/embed/projects/kernel/main.c
@@ -17,6 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <trezor_model.h>
#include <trezor_rtl.h>
#include <gfx/gfx_bitblt.h>
@@ -24,8 +25,8 @@
#include <sec/random_delays.h>
#include <sec/secret.h>
#include <sec/secure_aes.h>
-#include <sys/applet.h>
#include <sys/bootutils.h>
+#include <sys/coreapp.h>
#include <sys/mpu.h>
#include <sys/syscall_ipc.h>
#include <sys/sysevent.h>
@@ -33,7 +34,6 @@
#include <sys/systick.h>
#include <util/board_capabilities.h>
#include <util/boot_image.h>
-#include <util/image.h>
#include <util/option_bytes.h>
#include <util/rsod.h>
#include <util/unit_properties.h>
@@ -54,6 +54,10 @@
#include <io/haptic.h>
#endif
+#ifdef USE_HASH_PROCESSOR
+#include <sec/hash_processor.h>
+#endif
+
#ifdef USE_OPTIGA
#include <sec/optiga_init.h>
#endif
@@ -212,42 +216,6 @@ static void kernel_loop(applet_t *coreapp) {
} while (applet_is_alive(coreapp));
}
-// defined in linker script
-extern uint32_t _kernel_flash_end;
-#define KERNEL_END COREAPP_CODE_ALIGN((uint32_t) & _kernel_flash_end)
-
-// Initializes coreapp applet
-static void coreapp_init(applet_t *applet) {
- const uint32_t CODE1_START = KERNEL_END;
-
-#ifdef FIRMWARE_P1_START
- const uint32_t CODE1_END = FIRMWARE_P1_START + FIRMWARE_P1_MAXSIZE;
-#else
- const uint32_t CODE1_END = FIRMWARE_START + FIRMWARE_MAXSIZE;
-#endif
-
- const applet_layout_t coreapp_layout = {
- .data1.start = (uint32_t)AUX1_RAM_START,
- .data1.size = (uint32_t)AUX1_RAM_SIZE,
-#ifdef AUX2_RAM_START
- .data2.start = (uint32_t)AUX2_RAM_START,
- .data2.size = (uint32_t)AUX2_RAM_SIZE,
-#endif
- .code1.start = CODE1_START,
- .code1.size = CODE1_END - CODE1_START,
-#ifdef FIRMWARE_P2_START
- .code2.start = FIRMWARE_P2_START,
- .code2.size = FIRMWARE_P2_MAXSIZE,
-#endif
- };
-
- applet_privileges_t coreapp_privileges = {
- .assets_area_access = true,
- };
-
- applet_init(applet, &coreapp_layout, &coreapp_privileges);
-}
-
#ifndef USE_BOOTARGS_RSOD
// Shows RSOD (Red Screen of Death)
@@ -257,7 +225,7 @@ static void show_rsod(const systask_postmortem_t *pminfo) {
coreapp_init(&coreapp);
// Reset and run the coreapp in RSOD mode
- if (applet_reset(&coreapp, 1, pminfo, sizeof(systask_postmortem_t))) {
+ if (coreapp_reset(&coreapp, 1, pminfo, sizeof(systask_postmortem_t))) {
// Run the applet & wait for it to finish
applet_run(&coreapp);
// Loop until the coreapp is terminated
@@ -320,12 +288,13 @@ int main(void) {
coreapp_init(&coreapp);
// Reset and run the coreapp
- if (!applet_reset(&coreapp, 0, NULL, 0)) {
+ if (!coreapp_reset(&coreapp, 0, NULL, 0)) {
error_shutdown("Cannot start coreapp");
}
// Run the applet
applet_run(&coreapp);
+
// Loop until the coreapp is terminated
kernel_loop(&coreapp);
// Release the coreapp resources
diff --git a/core/embed/sec/secure_aes/stm32u5/secure_aes_unpriv.c b/core/embed/sec/secure_aes/stm32u5/secure_aes_unpriv.c
index 7049acf8..dea1d8cf 100644
--- a/core/embed/sec/secure_aes/stm32u5/secure_aes_unpriv.c
+++ b/core/embed/sec/secure_aes/stm32u5/secure_aes_unpriv.c
@@ -110,6 +110,7 @@ __attribute((no_stack_protector)) void saes_unpriv_callback(void) {
#ifdef KERNEL
+#include <sys/coreapp.h>
#include <sys/mpu.h>
#include <sys/systask.h>
@@ -144,11 +145,12 @@ secbool secure_aes_unpriv_encrypt(const uint8_t *input, size_t size,
applet_t *applet = secure_aes_unpriv_applet;
- const applet_header_t *header = (applet_header_t *)applet->layout.code1.start;
+ const coreapp_header_t *header =
+ (coreapp_header_t *)applet->layout.code1.start;
- void *unpriv_input = header->coreapp.saes_input;
- void *unpriv_output = header->coreapp.saes_output;
- void *unpriv_callback = header->coreapp.saes_callback;
+ void *unpriv_input = header->saes_input;
+ void *unpriv_output = header->saes_output;
+ void *unpriv_callback = header->saes_callback;
memzero(unpriv_input, SAES_DATA_SIZE_WITH_UNPRIV_KEY);
memzero(unpriv_output, SAES_DATA_SIZE_WITH_UNPRIV_KEY);
diff --git a/core/embed/sys/task/inc/sys/applet.h b/core/embed/sys/task/inc/sys/applet.h
index 8565e97e..71acfc4b 100644
--- a/core/embed/sys/task/inc/sys/applet.h
+++ b/core/embed/sys/task/inc/sys/applet.h
@@ -25,28 +25,6 @@
#include <sys/systask.h>
-// Applet entry point
-typedef void (*applet_startup_t)(const char* args, uint32_t random);
-
-// Applet header found at the beginning of the applet binary
-typedef struct {
- // Applet entry point
- applet_startup_t startup;
- // Stack area
- mpu_area_t stack;
- // TLS area
- mpu_area_t tls;
- // Coreapp specific data
- struct {
- // Unprivileged SAES input buffer
- void* saes_input;
- // Unprivileged SAES output buffer
- void* saes_output;
- // Unprivileged SAES callback
- void* saes_callback;
- } coreapp;
-} applet_header_t;
-
// Applet privileges
typedef struct {
bool assets_area_access;
@@ -68,15 +46,6 @@ typedef struct {
void applet_init(applet_t* applet, const applet_layout_t* layout,
const applet_privileges_t* privileges);
-// Resets the applet and prepares it for execution from its entry point.
-//
-// Applet does not start immediately, it needs to be run by
-// `applet_run()` after calling this function.
-//
-// Returns `true` if the applet was successfully reset.
-bool applet_reset(applet_t* applet, uint32_t cmd, const void* arg,
- size_t arg_size);
-
// Runs the applet and waits until it finishes.
void applet_run(applet_t* applet);
diff --git a/core/embed/sys/task/inc/sys/coreapp.h b/core/embed/sys/task/inc/sys/coreapp.h
new file mode 100644
index 00000000..bb550a5a
--- /dev/null
+++ b/core/embed/sys/task/inc/sys/coreapp.h
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#ifdef KERNEL_MODE
+
+#include <trezor_types.h>
+
+#include <sys/applet.h>
+#include <sys/mpu.h>
+
+// Coreapp entry point
+typedef void (*coreapp_startup_t)(const char* args, uint32_t random);
+
+// Applet header found at the beginning of the coreapp binary
+typedef struct {
+ // Applet entry point
+ coreapp_startup_t startup;
+ // Stack area
+ mpu_area_t stack;
+ // TLS area
+ mpu_area_t tls;
+ // Unprivileged SAES input buffer
+ void* saes_input;
+ // Unprivileged SAES output buffer
+ void* saes_output;
+ // Unprivileged SAES callback
+ void* saes_callback;
+} coreapp_header_t;
+
+// Initializes the coreapp applet structure
+void coreapp_init(applet_t* applet);
+
+// Resets the coreapp and prepares it for execution from its entry point.
+//
+// Coreapp does not start immediately, it needs to be run by
+// `applet_run()` after calling this function.
+//
+// Returns `true` if the applet was successfully reset.
+bool coreapp_reset(applet_t* applet, uint32_t cmd, const void* arg,
+ size_t arg_size);
+
+mpu_area_t coreapp_get_code_area(void);
+
+mpu_area_t coreapp_get_tls_area(void);
+
+#endif // KERNEL_MODE
diff --git a/core/embed/sys/task/stm32/applet.c b/core/embed/sys/task/stm32/applet.c
index c8ee25b5..3d00cdf0 100644
--- a/core/embed/sys/task/stm32/applet.c
+++ b/core/embed/sys/task/stm32/applet.c
@@ -40,47 +40,6 @@ void applet_init(applet_t* applet, const applet_layout_t* layout,
applet->privileges = *privileges;
}
-static void applet_clear_memory(applet_t* applet) {
- mpu_set_active_applet(&applet->layout);
-
- if (applet->layout.data1.size > 0) {
- memset((void*)applet->layout.data1.start, 0, applet->layout.data1.size);
- }
- if (applet->layout.data2.size > 0) {
- memset((void*)applet->layout.data2.start, 0, applet->layout.data2.size);
- }
-}
-
-bool applet_reset(applet_t* applet, uint32_t cmd, const void* arg,
- size_t arg_size) {
- // Clear all memory the applet is allowed to use
- applet_clear_memory(applet);
-
- const applet_header_t* header = (applet_header_t*)applet->layout.code1.start;
-
- // Reset the applet task (stack pointer, etc.)
- if (!systask_init(&applet->task, header->stack.start, header->stack.size, 0,
- applet)) {
- return false;
- }
-
- // Copy the arguments onto the applet stack
- void* arg_copy = NULL;
- if (arg != NULL && arg_size > 0) {
- arg_copy = systask_push_data(&applet->task, arg, arg_size);
- if (arg_copy == NULL) {
- return false;
- }
- }
-
- // Schedule the applet task run
- uint32_t arg1 = cmd;
- uint32_t arg2 = (uint32_t)arg_copy;
- uint32_t arg3 = rng_get();
-
- return systask_push_call(&applet->task, header->startup, arg1, arg2, arg3);
-}
-
#ifdef USE_TRUSTZONE
// Sets unprivileged access to the applet memory regions
// and allows applet to use some specific peripherals.
diff --git a/core/embed/sys/task/stm32/coreapp.c b/core/embed/sys/task/stm32/coreapp.c
new file mode 100644
index 00000000..c3764471
--- /dev/null
+++ b/core/embed/sys/task/stm32/coreapp.c
@@ -0,0 +1,124 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef KERNEL
+
+#include <trezor_rtl.h>
+
+#include <sec/rng.h>
+#include <sys/applet.h>
+#include <sys/coreapp.h>
+#include <sys/mpu.h>
+#include <sys/systask.h>
+#include <util/image.h>
+
+static mpu_area_t coreapp_code_area;
+static mpu_area_t coreapp_tls_area;
+
+// defined in linker script
+extern uint32_t _kernel_flash_end;
+#define KERNEL_END COREAPP_CODE_ALIGN((uint32_t) & _kernel_flash_end)
+
+// Initializes coreapp applet
+void coreapp_init(applet_t* applet) {
+ const uint32_t CODE1_START = KERNEL_END;
+
+#ifdef FIRMWARE_P1_START
+ const uint32_t CODE1_END = FIRMWARE_P1_START + FIRMWARE_P1_MAXSIZE;
+#else
+ const uint32_t CODE1_END = FIRMWARE_START + FIRMWARE_MAXSIZE;
+#endif
+
+ const applet_layout_t coreapp_layout = {
+ .data1.start = (uint32_t)AUX1_RAM_START,
+ .data1.size = (uint32_t)AUX1_RAM_SIZE,
+#ifdef AUX2_RAM_START
+ .data2.start = (uint32_t)AUX2_RAM_START,
+ .data2.size = (uint32_t)AUX2_RAM_SIZE,
+#endif
+ .code1.start = CODE1_START,
+ .code1.size = CODE1_END - CODE1_START,
+#ifdef FIRMWARE_P2_START
+ .code2.start = FIRMWARE_P2_START,
+ .code2.size = FIRMWARE_P2_MAXSIZE,
+#endif
+ };
+
+ applet_privileges_t coreapp_privileges = {
+ .assets_area_access = true,
+ };
+
+ applet_init(applet, &coreapp_layout, &coreapp_privileges);
+}
+
+static void coreapp_clear_memory(applet_t* applet) {
+ if (applet->layout.data1.size > 0) {
+ memset((void*)applet->layout.data1.start, 0, applet->layout.data1.size);
+ }
+ if (applet->layout.data2.size > 0) {
+ memset((void*)applet->layout.data2.start, 0, applet->layout.data2.size);
+ }
+}
+
+bool coreapp_reset(applet_t* applet, uint32_t cmd, const void* arg,
+ size_t arg_size) {
+ // Enable access to coreapp memory regions
+ mpu_set_active_applet(&applet->layout);
+
+ // Clear all memory the applet is allowed to use
+ coreapp_clear_memory(applet);
+
+ const coreapp_header_t* header =
+ (coreapp_header_t*)applet->layout.code1.start;
+
+ // Remember code and TLS areas
+ // (we will need then later for extension applets)
+ coreapp_tls_area = header->tls;
+ coreapp_code_area = applet->layout.code1;
+
+ // Reset the applet task (stack pointer, etc.)
+ if (!systask_init(&applet->task, header->stack.start, header->stack.size, 0,
+ applet)) {
+ return false;
+ }
+
+ systask_enable_tls(&applet->task, header->tls);
+
+ // Copy the arguments onto the applet stack
+ void* arg_copy = NULL;
+ if (arg != NULL && arg_size > 0) {
+ arg_copy = systask_push_data(&applet->task, arg, arg_size);
+ if (arg_copy == NULL) {
+ return false;
+ }
+ }
+
+ // Schedule the applet task run
+ uint32_t arg1 = cmd;
+ uint32_t arg2 = (uint32_t)arg_copy;
+ uint32_t arg3 = rng_get();
+
+ return systask_push_call(&applet->task, header->startup, arg1, arg2, arg3);
+}
+
+mpu_area_t coreapp_get_code_area(void) { return coreapp_code_area; }
+
+mpu_area_t coreapp_get_tls_area(void) { return coreapp_tls_area; }
+
+#endif // KERNEL
diff --git a/core/site_scons/models/stm32f4_common.py b/core/site_scons/models/stm32f4_common.py
index 355a0808..3ea8485e 100644
--- a/core/site_scons/models/stm32f4_common.py
+++ b/core/site_scons/models/stm32f4_common.py
@@ -91,6 +91,7 @@ def stm32f4_common_files(env, features_wanted, defines, sources, paths):
"embed/sys/syscall/stm32/syscall_stubs.c",
"embed/sys/syscall/stm32/syscall_verifiers.c",
"embed/sys/task/stm32/applet.c",
+ "embed/sys/task/stm32/coreapp.c",
"embed/sys/task/stm32/systask.c",
"embed/sys/task/stm32/system.c",
"embed/sys/time/stm32/systick.c",
diff --git a/core/site_scons/models/stm32u5_common.py b/core/site_scons/models/stm32u5_common.py
index ec51ed0b..e5ba1da0 100644
--- a/core/site_scons/models/stm32u5_common.py
+++ b/core/site_scons/models/stm32u5_common.py
@@ -152,6 +152,7 @@ def stm32u5_common_files(env, features_wanted, defines, sources, paths):
if "applet" in features_wanted:
sources += ["embed/sys/task/stm32/applet.c"]
+ sources += ["embed/sys/task/stm32/coreapp.c"]
if "usb" in features_wanted:
sources += [
Why this scored 11/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.