fix(core): fix syshandle_write_blocking behavior
What changed, and why it matters
This commit fixes a bug in a low-level Trezor firmware function that writes data from the device. Previously, when a timeout was requested, the code only waited for the channel to become ready but then tried to write all data at once, ignoring that the hardware might only accept a portion. The fix loops, writing in chunks and waiting again until all data is sent or the timeout expires. This is a reliability/robustness fix that could prevent incomplete or failed writes in communication with the host.
Treat as a normal bug-fix commit. Review whether any higher-level protocol assumes atomic full-buffer writes and could have misbehaved under partial writes. No immediate security response indicated, but include in firmware release notes as a communication reliability improvement.
Security signals we found
Fixes incomplete blocking I/O behavior that could leave data partially transmitted
Improves robustness of device-to-host communication channel
No explicit security claim in commit message or changelog
Evidence from the diff
The function syshandle_write_blocking in core/embed/sys/task/sysevent.c is updated to correctly perform blocking writes with a timeout. The old implementation called sysevents_poll once to wait for write readiness, then called syshandle_write with the full buffer. The new implementation loops: waits for write_ready, writes whatever portion succeeds, advances the pointer, and repeats until all bytes are sent or the deadline passes. It also handles timeout==0 as a single non-blocking write. Error handling returns either the full error if nothing was written, or the partial byte count if some data was already sent.
Changed components
core/embed/sys/task/sysevent.csyshandle_write_blocking functionInspect captured patch +30 / −5
diff --git a/core/embed/sys/task/sysevent.c b/core/embed/sys/task/sysevent.c
index 6dc89f13e..b778b41d6 100644
--- a/core/embed/sys/task/sysevent.c
+++ b/core/embed/sys/task/sysevent.c
@@ -325,10 +325,35 @@ ssize_t syshandle_read_blocking(syshandle_t handle, void *buffer,
ssize_t syshandle_write_blocking(syshandle_t handle, const void *data,
size_t data_size, uint32_t timeout) {
- if (timeout > 0) {
- sysevents_t awaited = {.write_ready = 1 << handle};
- sysevents_t signalled = {0};
- sysevents_poll(&awaited, &signalled, ticks_timeout(timeout));
+ if (timeout == 0) {
+ return syshandle_write(handle, data, data_size);
+ } else {
+ ticks_t deadline = ticks_timeout(timeout);
+
+ const uint8_t *ptr = (const uint8_t *)data;
+ size_t remaining = data_size;
+
+ // Send data in a loop until all data is sent or timeout occurs
+ while (remaining > 0) {
+ sysevents_t awaited = {.write_ready = 1 << handle};
+ sysevents_t signalled = {0};
+ sysevents_poll(&awaited, &signalled, deadline);
+
+ if (signalled.write_ready == 0) {
+ // Timeout
+ break;
+ }
+
+ ssize_t written = syshandle_write(handle, ptr, remaining);
+
+ if (written < 0) {
+ return remaining == data_size ? written : data_size - remaining;
+ }
+
+ ptr += written;
+ remaining -= written;
+ }
+
+ return data_size - remaining;
}
- return syshandle_write(handle, data, data_size);
}
Why this scored 32/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.