What changed, and why it matters
This commit adds a new secure hardware feature that lets the device read small protected data slots from a Tropic security chip. It is a feature addition, not a bug fix. The code includes the usual memory-access checks, so there is no obvious security flaw in the diff itself. However, it expands the attack surface by exposing another privileged operation to less-trusted firmware, and the review is limited because the underlying Tropic library code is not shown.
Treat as a routine feature addition with no immediate action required. As part of normal secure-development practice, verify that probe_write_access correctly handles overlapping or aliased mappings, that R_MEM_DATA_SIZE_MAX matches the Tropic library's maximum, and that the Tropic library's lt_r_mem_data_read does not underflow or overwrite beyond the probed length. Review callers once they are added to ensure the slot index and returned size are used safely.
Security signals we found
New privileged syscall/SMCall added for reading secure-chip data slots
Verified wrappers check write access to output buffer and size pointer
Slot index validated against R_MEM_DATA_SLOT_MAX in driver
No input length is passed by caller; size is determined by the Tropic library and written to caller-supplied size pointer
Feature addition rather than bug fix; security relevance not stated by vendor
Evidence from the diff
The patch wires a new tropic_data_read() capability through the Trezor firmware’s privilege-separation layers: the secure-mode Tropic driver, the SMC (secure monitor call) dispatcher used by the application core, and the syscall dispatcher used by the kernel. Both dispatcher paths use a __verified wrapper that probes the caller-supplied output buffer (R_MEM_DATA_SIZE_MAX bytes) and the caller-supplied size pointer (sizeof(uint16_t)) for write access before forwarding the call. The slot index is bounded against R_MEM_DATA_SLOT_MAX in the driver. No vulnerability is visible in the supplied diff, but the change increases the trusted computing base and relies on the correctness of probe_write_access and the Tropic library implementation.
Changed components
core/embed/sec/tropic/tropic.ccore/embed/sys/smcall/stm32/smcall_dispatch.ccore/embed/sys/smcall/stm32/smcall_numbers.hcore/embed/sys/smcall/stm32/smcall_stubs.ccore/embed/sys/smcall/stm32/smcall_verifiers.ccore/embed/sys/smcall/stm32/smcall_verifiers.hcore/embed/sys/syscall/inc/sys/syscall_numbers.hcore/embed/sys/syscall/stm32/syscall_dispatch.ccore/embed/sys/syscall/stm32/syscall_stubs.ccore/embed/sys/syscall/stm32/syscall_verifiers.ccore/embed/sys/syscall/stm32/syscall_verifiers.hInspect captured patch +83 / −0
diff --git a/core/embed/sec/tropic/inc/sec/tropic.h b/core/embed/sec/tropic/inc/sec/tropic.h
index 5aa26d43d..043916f21 100644
--- a/core/embed/sec/tropic/inc/sec/tropic.h
+++ b/core/embed/sec/tropic/inc/sec/tropic.h
@@ -61,3 +61,5 @@ bool tropic_ecc_key_generate(uint16_t slot_index);
bool tropic_ecc_sign(uint16_t key_slot_index, const uint8_t* dig,
uint16_t dig_len, uint8_t* sig);
+
+bool tropic_data_read(uint16_t udata_slot, uint8_t* data, uint16_t* size);
diff --git a/core/embed/sec/tropic/tropic.c b/core/embed/sec/tropic/tropic.c
index f211d9dad..a98f62374 100644
--- a/core/embed/sec/tropic/tropic.c
+++ b/core/embed/sec/tropic/tropic.c
@@ -169,4 +169,19 @@ bool tropic_ecc_sign(uint16_t key_slot_index, const uint8_t *dig,
return true;
}
+bool tropic_data_read(uint16_t udata_slot, uint8_t *data, uint16_t *size) {
+ tropic_driver_t *drv = &g_tropic_driver;
+
+ if (!drv->initialized) {
+ return false;
+ }
+
+ if (udata_slot > R_MEM_DATA_SLOT_MAX) {
+ return false;
+ }
+
+ lt_ret_t res = lt_r_mem_data_read(&drv->handle, udata_slot, data, size);
+ return res == LT_OK;
+}
+
#endif // SECURE_MODE
diff --git a/core/embed/sys/smcall/stm32/smcall_dispatch.c b/core/embed/sys/smcall/stm32/smcall_dispatch.c
index 53890e5df..f48c0ec23 100644
--- a/core/embed/sys/smcall/stm32/smcall_dispatch.c
+++ b/core/embed/sys/smcall/stm32/smcall_dispatch.c
@@ -342,6 +342,13 @@ __attribute((no_stack_protector)) void smcall_handler(uint32_t *args,
uint8_t *sig = (uint8_t *)args[3];
args[0] = tropic_ecc_sign__verified(key_slot_index, dig, dig_len, sig);
} break;
+
+ case SMCALL_TROPIC_DATA_READ: {
+ uint16_t udata_slot = (uint16_t)args[0];
+ uint8_t *data = (uint8_t *)args[1];
+ uint16_t *size = (uint16_t *)args[2];
+ args[0] = tropic_data_read__verified(udata_slot, data, size);
+ } break;
#endif
#ifdef USE_BACKUP_RAM
diff --git a/core/embed/sys/smcall/stm32/smcall_numbers.h b/core/embed/sys/smcall/stm32/smcall_numbers.h
index 077d9e375..0efb2f3cd 100644
--- a/core/embed/sys/smcall/stm32/smcall_numbers.h
+++ b/core/embed/sys/smcall/stm32/smcall_numbers.h
@@ -92,6 +92,7 @@ typedef enum {
SMCALL_TROPIC_PING,
SMCALL_TROPIC_ECC_KEY_GENERATE,
SMCALL_TROPIC_ECC_SIGN,
+ SMCALL_TROPIC_DATA_READ,
SMCALL_BACKUP_RAM_SEARCH,
SMCALL_BACKUP_RAM_READ,
diff --git a/core/embed/sys/smcall/stm32/smcall_stubs.c b/core/embed/sys/smcall/stm32/smcall_stubs.c
index fc5d1c999..47264157f 100644
--- a/core/embed/sys/smcall/stm32/smcall_stubs.c
+++ b/core/embed/sys/smcall/stm32/smcall_stubs.c
@@ -334,6 +334,11 @@ bool tropic_ecc_sign(uint16_t key_slot_index, const uint8_t *dig,
(uint32_t)sig, SMCALL_TROPIC_ECC_SIGN);
}
+bool tropic_data_read(uint16_t udata_slot, uint8_t *data, uint16_t *size) {
+ return (bool)smcall_invoke3((uint32_t)udata_slot, (uint32_t)data,
+ (uint32_t)size, SMCALL_TROPIC_DATA_READ);
+}
+
#endif
// =============================================================================
diff --git a/core/embed/sys/smcall/stm32/smcall_verifiers.c b/core/embed/sys/smcall/stm32/smcall_verifiers.c
index e18bd3678..d4dbcdae1 100644
--- a/core/embed/sys/smcall/stm32/smcall_verifiers.c
+++ b/core/embed/sys/smcall/stm32/smcall_verifiers.c
@@ -405,6 +405,7 @@ access_violation:
// ---------------------------------------------------------------------
#ifdef USE_TROPIC
+#include <libtropic_common.h>
#include <sec/tropic.h>
#include "ecdsa.h"
@@ -443,6 +444,22 @@ access_violation:
apptask_access_violation();
return false;
}
+
+bool tropic_data_read__verified(uint16_t udata_slot, uint8_t *data,
+ uint16_t *size) {
+ if (!probe_write_access(data, R_MEM_DATA_SIZE_MAX)) {
+ goto access_violation;
+ }
+
+ if (!probe_write_access(size, sizeof(*size))) {
+ goto access_violation;
+ }
+
+ return tropic_data_read(udata_slot, data, size);
+access_violation:
+ apptask_access_violation();
+ return false;
+}
#endif
#ifdef USE_BACKUP_RAM
diff --git a/core/embed/sys/smcall/stm32/smcall_verifiers.h b/core/embed/sys/smcall/stm32/smcall_verifiers.h
index b5f112431..432a9404a 100644
--- a/core/embed/sys/smcall/stm32/smcall_verifiers.h
+++ b/core/embed/sys/smcall/stm32/smcall_verifiers.h
@@ -118,6 +118,9 @@ bool tropic_ecc_key_generate__verified(uint16_t slot_index);
bool tropic_ecc_sign__verified(uint16_t key_slot_index, const uint8_t *dig,
uint16_t dig_len, uint8_t *sig);
+bool tropic_data_read__verified(uint16_t udata_slot, uint8_t *data,
+ uint16_t *size);
+
#endif
// ---------------------------------------------------------------------
diff --git a/core/embed/sys/syscall/inc/sys/syscall_numbers.h b/core/embed/sys/syscall/inc/sys/syscall_numbers.h
index 33732c3bd..49c9003d6 100644
--- a/core/embed/sys/syscall/inc/sys/syscall_numbers.h
+++ b/core/embed/sys/syscall/inc/sys/syscall_numbers.h
@@ -163,6 +163,7 @@ typedef enum {
SYSCALL_TROPIC_PING,
SYSCALL_TROPIC_ECC_KEY_GENERATE,
SYSCALL_TROPIC_ECC_SIGN,
+ SYSCALL_TROPIC_DATA_READ,
SYSCALL_STORAGE_GET,
diff --git a/core/embed/sys/syscall/stm32/syscall_dispatch.c b/core/embed/sys/syscall/stm32/syscall_dispatch.c
index dfa327b5d..785544807 100644
--- a/core/embed/sys/syscall/stm32/syscall_dispatch.c
+++ b/core/embed/sys/syscall/stm32/syscall_dispatch.c
@@ -798,6 +798,13 @@ __attribute((no_stack_protector)) void syscall_handler(uint32_t *args,
uint8_t *sig = (uint8_t *)args[3];
args[0] = tropic_ecc_sign__verified(key_slot_index, dig, dig_len, sig);
} break;
+
+ case SYSCALL_TROPIC_DATA_READ: {
+ uint16_t udata_slot = (uint16_t)args[0];
+ uint8_t *data = (uint8_t *)args[1];
+ uint16_t *size = (uint16_t *)args[2];
+ args[0] = tropic_data_read__verified(udata_slot, data, size);
+ } break;
#endif
default:
diff --git a/core/embed/sys/syscall/stm32/syscall_stubs.c b/core/embed/sys/syscall/stm32/syscall_stubs.c
index 463496d86..f8c4ff53d 100644
--- a/core/embed/sys/syscall/stm32/syscall_stubs.c
+++ b/core/embed/sys/syscall/stm32/syscall_stubs.c
@@ -789,6 +789,11 @@ bool tropic_ecc_sign(uint16_t key_slot_index, const uint8_t *dig,
(uint32_t)sig, SYSCALL_TROPIC_ECC_SIGN);
}
+bool tropic_data_read(uint16_t udata_slot, uint8_t *data, uint16_t *size) {
+ return (bool)syscall_invoke3((uint32_t)udata_slot, (uint32_t)data,
+ (uint32_t)size, SYSCALL_TROPIC_DATA_READ);
+}
+
#endif
#endif // KERNEL_MODE
diff --git a/core/embed/sys/syscall/stm32/syscall_verifiers.c b/core/embed/sys/syscall/stm32/syscall_verifiers.c
index bac493963..971721fae 100644
--- a/core/embed/sys/syscall/stm32/syscall_verifiers.c
+++ b/core/embed/sys/syscall/stm32/syscall_verifiers.c
@@ -1149,6 +1149,7 @@ access_violation:
#endif
#ifdef USE_TROPIC
+#include <libtropic_common.h>
#include <sec/tropic.h>
#include "ecdsa.h"
@@ -1187,6 +1188,22 @@ access_violation:
apptask_access_violation();
return false;
}
+
+bool tropic_data_read__verified(uint16_t udata_slot, uint8_t *data,
+ uint16_t *size) {
+ if (!probe_write_access(data, R_MEM_DATA_SIZE_MAX)) {
+ goto access_violation;
+ }
+
+ if (!probe_write_access(size, sizeof(*size))) {
+ goto access_violation;
+ }
+
+ return tropic_data_read(udata_slot, data, size);
+access_violation:
+ apptask_access_violation();
+ return false;
+}
#endif
#endif // KERNEL
diff --git a/core/embed/sys/syscall/stm32/syscall_verifiers.h b/core/embed/sys/syscall/stm32/syscall_verifiers.h
index 78d54f1a6..7e67dc99a 100644
--- a/core/embed/sys/syscall/stm32/syscall_verifiers.h
+++ b/core/embed/sys/syscall/stm32/syscall_verifiers.h
@@ -285,6 +285,9 @@ bool tropic_ecc_key_generate__verified(uint16_t slot_index);
bool tropic_ecc_sign__verified(uint16_t key_slot_index, const uint8_t *dig,
uint16_t dig_len, uint8_t *sig);
+bool tropic_data_read__verified(uint16_t udata_slot, uint8_t *data,
+ uint16_t *size);
+
#endif
#endif // KERNEL
Why this scored 27/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.