feat(core): expose get device serial number via smcalls and syscalls
What changed, and why it matters
This commit adds a new internal interface that lets trusted and less-trusted software running on the Trezor device read the device's serial number. The code checks that the caller is allowed to write to the memory it provides, then copies the serial number there. There is no direct evidence in the commit that this is a security fix or that it introduces a vulnerability; it appears to be a feature exposing information that was already available elsewhere in firmware.
Review the implementation of unit_properties_get_sn and the caller to confirm the serial number is not derived from sensitive material and that the new interface is restricted to authorized callers. Treat as a routine feature commit unless additional context emerges.
Security signals we found
New SMCALL/SYSCALL surface for reading device serial number
Verified wrappers check write access to caller-supplied buffers
No input validation shown for max_device_sn_size beyond probe_write_access
No vendor security framing or changelog entry in commit
Evidence from the diff
The patch exposes unit_properties_get_sn through both SMCALL (secure monitor call) and SYSCALL (system call) interfaces on STM32. It adds new call numbers, dispatch cases, user-space stubs, and verified wrappers. The verifiers probe_write_access on the output buffer and size pointer before invoking the underlying implementation. No implementation of unit_properties_get_sn itself is shown in the diff, and no changelog or security context is provided.
Changed components
core/embed/sys/smcall/stm32core/embed/sys/syscall/stm32Trezor Core firmware secure monitor and syscall layersInspect captured patch +76 / −0
diff --git a/core/embed/sys/smcall/stm32/smcall_dispatch.c b/core/embed/sys/smcall/stm32/smcall_dispatch.c
index 60a795615..4ce8254ae 100644
--- a/core/embed/sys/smcall/stm32/smcall_dispatch.c
+++ b/core/embed/sys/smcall/stm32/smcall_dispatch.c
@@ -126,6 +126,14 @@ __attribute((no_stack_protector)) void smcall_handler(uint32_t *args,
unit_properties_get__verified(props);
} break;
+ case SMCALL_UNIT_PROPERTIES_GET_SN: {
+ uint8_t *device_sn = (uint8_t *)args[0];
+ size_t max_device_sn_size = args[1];
+ size_t *device_sn_size = (size_t *)args[2];
+ args[0] = unit_properties_get_sn__verified(device_sn, max_device_sn_size,
+ device_sn_size);
+ } break;
+
#ifdef LOCKABLE_BOOTLOADER
case SMCALL_SECRET_BOOTLOADER_LOCKED: {
args[0] = secret_bootloader_locked();
diff --git a/core/embed/sys/smcall/stm32/smcall_numbers.h b/core/embed/sys/smcall/stm32/smcall_numbers.h
index d42e7a0e9..bbfda6be4 100644
--- a/core/embed/sys/smcall/stm32/smcall_numbers.h
+++ b/core/embed/sys/smcall/stm32/smcall_numbers.h
@@ -50,6 +50,7 @@ typedef enum {
SMCALL_GET_BOARDLOADER_VERSION,
SMCALL_UNIT_PROPERTIES_GET,
+ SMCALL_UNIT_PROPERTIES_GET_SN,
SMCALL_SECRET_BOOTLOADER_LOCKED,
SMCALL_SECRET_VALIDATE_NRF_PAIRING,
diff --git a/core/embed/sys/smcall/stm32/smcall_stubs.c b/core/embed/sys/smcall/stm32/smcall_stubs.c
index 1c280e4b4..425bf1e6a 100644
--- a/core/embed/sys/smcall/stm32/smcall_stubs.c
+++ b/core/embed/sys/smcall/stm32/smcall_stubs.c
@@ -133,6 +133,13 @@ void unit_properties_get(unit_properties_t *props) {
smcall_invoke1((uint32_t)props, SMCALL_UNIT_PROPERTIES_GET);
}
+bool unit_properties_get_sn(uint8_t *device_sn, size_t max_device_sn_size,
+ size_t *device_sn_size) {
+ return (bool)smcall_invoke3((uint32_t)device_sn, max_device_sn_size,
+ (uint32_t)device_sn_size,
+ SMCALL_UNIT_PROPERTIES_GET_SN);
+}
+
// =============================================================================
// secret.h
// =============================================================================
diff --git a/core/embed/sys/smcall/stm32/smcall_verifiers.c b/core/embed/sys/smcall/stm32/smcall_verifiers.c
index ba7329c3c..f3b239d87 100644
--- a/core/embed/sys/smcall/stm32/smcall_verifiers.c
+++ b/core/embed/sys/smcall/stm32/smcall_verifiers.c
@@ -127,6 +127,24 @@ access_violation:
apptask_access_violation();
}
+bool unit_properties_get_sn__verified(uint8_t *device_sn,
+ size_t max_device_sn_size,
+ size_t *device_sn_size) {
+ if (!probe_write_access(device_sn, max_device_sn_size)) {
+ goto access_violation;
+ }
+
+ if (!probe_write_access(device_sn_size, sizeof(*device_sn_size))) {
+ goto access_violation;
+ }
+
+ return unit_properties_get_sn(device_sn, max_device_sn_size, device_sn_size);
+
+access_violation:
+ apptask_access_violation();
+ return false;
+}
+
// ---------------------------------------------------------------------
#ifdef USE_OPTIGA
diff --git a/core/embed/sys/smcall/stm32/smcall_verifiers.h b/core/embed/sys/smcall/stm32/smcall_verifiers.h
index c91841390..75d728286 100644
--- a/core/embed/sys/smcall/stm32/smcall_verifiers.h
+++ b/core/embed/sys/smcall/stm32/smcall_verifiers.h
@@ -49,6 +49,10 @@ void reboot_with_rsod__verified(const systask_postmortem_t *pminfo);
void unit_properties_get__verified(unit_properties_t *props);
+bool unit_properties_get_sn__verified(uint8_t *device_sn,
+ size_t max_device_sn_size,
+ size_t *device_sn_size);
+
// ---------------------------------------------------------------------
#ifdef USE_OPTIGA
diff --git a/core/embed/sys/syscall/inc/sys/syscall_numbers.h b/core/embed/sys/syscall/inc/sys/syscall_numbers.h
index 1d5e7509f..c85079936 100644
--- a/core/embed/sys/syscall/inc/sys/syscall_numbers.h
+++ b/core/embed/sys/syscall/inc/sys/syscall_numbers.h
@@ -79,6 +79,7 @@ typedef enum {
SYSCALL_SDCARD_WRITE_BLOCKS,
SYSCALL_UNIT_PROPERTIES_GET,
+ SYSCALL_UNIT_PROPERTIES_GET_SN,
SYSCALL_SECRET_BOOTLOADER_LOCKED,
diff --git a/core/embed/sys/syscall/stm32/syscall_dispatch.c b/core/embed/sys/syscall/stm32/syscall_dispatch.c
index e033a71b4..cfaa7a00c 100644
--- a/core/embed/sys/syscall/stm32/syscall_dispatch.c
+++ b/core/embed/sys/syscall/stm32/syscall_dispatch.c
@@ -310,6 +310,14 @@ __attribute((no_stack_protector)) void syscall_handler(uint32_t *args,
unit_properties_get__verified(props);
} break;
+ case SYSCALL_UNIT_PROPERTIES_GET_SN: {
+ uint8_t *device_sn = (uint8_t *)args[0];
+ size_t max_device_sn_size = args[1];
+ size_t *device_sn_size = (size_t *)args[2];
+ args[0] = unit_properties_get_sn__verified(device_sn, max_device_sn_size,
+ device_sn_size);
+ } break;
+
#ifdef LOCKABLE_BOOTLOADER
case SYSCALL_SECRET_BOOTLOADER_LOCKED: {
args[0] = secret_bootloader_locked();
diff --git a/core/embed/sys/syscall/stm32/syscall_stubs.c b/core/embed/sys/syscall/stm32/syscall_stubs.c
index ba378b373..ba23291e9 100644
--- a/core/embed/sys/syscall/stm32/syscall_stubs.c
+++ b/core/embed/sys/syscall/stm32/syscall_stubs.c
@@ -272,6 +272,13 @@ void unit_properties_get(unit_properties_t *props) {
syscall_invoke1((uint32_t)props, SYSCALL_UNIT_PROPERTIES_GET);
}
+bool unit_properties_get_sn(uint8_t *device_sn, size_t max_device_sn_size,
+ size_t *device_sn_size) {
+ return (bool)syscall_invoke3((uint32_t)device_sn, max_device_sn_size,
+ (uint32_t)device_sn_size,
+ SYSCALL_UNIT_PROPERTIES_GET_SN);
+}
+
// =============================================================================
// secret.h
// =============================================================================
diff --git a/core/embed/sys/syscall/stm32/syscall_verifiers.c b/core/embed/sys/syscall/stm32/syscall_verifiers.c
index 53e82cb68..1d44228a8 100644
--- a/core/embed/sys/syscall/stm32/syscall_verifiers.c
+++ b/core/embed/sys/syscall/stm32/syscall_verifiers.c
@@ -389,6 +389,24 @@ access_violation:
apptask_access_violation();
}
+bool unit_properties_get_sn__verified(uint8_t *device_sn,
+ size_t max_device_sn_size,
+ size_t *device_sn_size) {
+ if (!probe_write_access(device_sn, max_device_sn_size)) {
+ goto access_violation;
+ }
+
+ if (!probe_write_access(device_sn_size, sizeof(*device_sn_size))) {
+ goto access_violation;
+ }
+
+ return unit_properties_get_sn(device_sn, max_device_sn_size, device_sn_size);
+
+access_violation:
+ apptask_access_violation();
+ return false;
+}
+
// ---------------------------------------------------------------------
#ifdef USE_OPTIGA
diff --git a/core/embed/sys/syscall/stm32/syscall_verifiers.h b/core/embed/sys/syscall/stm32/syscall_verifiers.h
index 36a691ba2..fa1e87ec6 100644
--- a/core/embed/sys/syscall/stm32/syscall_verifiers.h
+++ b/core/embed/sys/syscall/stm32/syscall_verifiers.h
@@ -107,6 +107,10 @@ secbool __wur sdcard_write_blocks__verified(const uint32_t *src,
void unit_properties_get__verified(unit_properties_t *props);
+bool unit_properties_get_sn__verified(uint8_t *device_sn,
+ size_t max_device_sn_size,
+ size_t *device_sn_size);
+
// ---------------------------------------------------------------------
#ifdef USE_OPTIGA
Why this scored 26/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.