fix(core): fix syscall set filter verifier
What changed, and why it matters
This commit fixes a security boundary check in the Trezor firmware's system-call verifier. The old code trusted a user-supplied string pointer and measured its length with strlen(), which can read beyond allowed memory if the string is malformed or malicious. The fix makes the caller provide the string length explicitly and checks exactly that many bytes. This closes a likely path for a restricted app to trick the device into reading memory it shouldn't, potentially causing a crash or leaking secrets.
Treat this as a security fix and include it in the next firmware release. Review other syscall verifiers for similar strlen()/unbounded reads on untrusted pointers. Add regression tests that exercise the verifier with unterminated or short-permission buffers. Consider whether the caller (APP layer) already passes a length that can be trusted, or if it too needs validation.
Security signals we found
Removal of unvalidated strlen() on a user/APP-supplied pointer inside a syscall verifier
Verifier now uses caller-provided length for probe_read_access()
Signature mismatch between verified wrapper and underlying syslog_set_filter() corrected
Potential out-of-bounds read / access-control bypass in a security boundary function
Evidence from the diff
syscall_verifiers.c contained syslog_set_filter__verified(), a syscall wrapper that validates an untrusted pointer before passing it to the kernel-side syslog_set_filter(). The original implementation called strlen(module_name) to determine the read-probe size. Because strlen() itself reads user memory without validation, a malicious or unterminated pointer could trigger an out-of-bounds read before the verifier ran, or cause the verifier to approve a different region than intended. The patch changes the syscall signature to accept an explicit filter_len and probes exactly filter_len bytes. This aligns the verifier with the actual kernel API and removes the unvalidated strlen() traversal.
Changed components
core/embed/sys/syscall/stm32/syscall_verifiers.ccore/embed/sys/syscall/stm32/syscall_verifiers.hTrezor Core firmware syscall layer (STM32)syslog_set_filter syscall wrapperInspect captured patch +4 / −4
diff --git a/core/embed/sys/syscall/stm32/syscall_verifiers.c b/core/embed/sys/syscall/stm32/syscall_verifiers.c
index d8b00677..c464eff7 100644
--- a/core/embed/sys/syscall/stm32/syscall_verifiers.c
+++ b/core/embed/sys/syscall/stm32/syscall_verifiers.c
@@ -148,12 +148,12 @@ access_violation:
return -1;
}
-bool syslog_set_filter__verified(const char *module_name, log_level_t level) {
- if (!probe_read_access(module_name, strlen(module_name))) {
+bool syslog_set_filter__verified(const char *filter, size_t filter_len) {
+ if (!probe_read_access(filter, filter_len)) {
goto access_violation;
}
- return syslog_set_filter(module_name, level);
+ return syslog_set_filter(filter, filter_len);
access_violation:
apptask_access_violation();
diff --git a/core/embed/sys/syscall/stm32/syscall_verifiers.h b/core/embed/sys/syscall/stm32/syscall_verifiers.h
index dfd8b1fa..2e7088f8 100644
--- a/core/embed/sys/syscall/stm32/syscall_verifiers.h
+++ b/core/embed/sys/syscall/stm32/syscall_verifiers.h
@@ -67,7 +67,7 @@ bool syslog_start_record__verified(const log_source_t *source,
ssize_t syslog_write_chunk__verified(const char *text, size_t text_len,
bool end_record);
-bool syslog_set_filter__verified(const char *module_name, log_level_t level);
+bool syslog_set_filter__verified(const char *filter, size_t filter_len);
#endif // USE_DBG_CONSOLE
Why this scored 61/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.