What changed, and why it matters
This commit fixes the order in which a simulated Trezor task (running on Unix/emulator) terminates itself when marked for shutdown. Previously, a killed task could briefly wake up and run again after yielding, because the 'am I killed?' check happened too late. Now the task exits immediately when it yields while killed, preventing a killed task from resuming and possibly executing unwanted code or mishandling an exception. The change is in the Unix emulator build, not the real hardware firmware, and the commit message does not call it a security fix.
Treat as a hardening/robustness fix rather than an urgent vulnerability. Review callers of systask_kill() and pushed_fn_call usage to confirm no security-critical path relied on the old late-termination behavior. Include this fix in regular emulator releases; no CVE or advisory is indicated from the commit alone.
Security signals we found
Killed-task resurrection window removed
Task termination ordering changed to prevent post-kill execution
Exception/pushed-call handling no longer reachable after kill flag is set
Unix emulator task scheduler only; not device firmware
Evidence from the diff
In core/embed/sys/task/unix/systask.c, systask_yield() is the cooperative scheduling primitive for the Unix emulator. Before the patch, the function swapped the active task, parked the current task, and only after re-awakening checked current_task->killed and called pthread_exit(0). That ordering meant a task marked killed while parked could still return from the cond_wait loop, process a pushed function call/exception, and continue executing. The patch moves the killed check immediately after the active-task handoff and before the parking loop, so a killed task exits without re-entering task code. The wait loop predicate also already includes !current_task->killed, so the change is primarily about not processing pushed_fn_call or returning to caller after a spurious wake-up.
Changed components
core/embed/sys/task/unix/systask.cTrezor Core Unix emulator task schedulerCooperative multitasking yield pathInspect captured patch +7 / −5
diff --git a/core/embed/sys/task/unix/systask.c b/core/embed/sys/task/unix/systask.c
index 79f545ad..6fe67777 100644
--- a/core/embed/sys/task/unix/systask.c
+++ b/core/embed/sys/task/unix/systask.c
@@ -110,6 +110,13 @@ static void systask_yield(void) {
scheduler->active_task = scheduler->waiting_task;
pthread_cond_signal(&scheduler->waiting_task->cv);
+ // If the current task is being killed, do not park it
+ // and terminate it instead
+ if (current_task->killed) {
+ pthread_mutex_unlock(&scheduler->lock);
+ pthread_exit(0);
+ }
+
// Park until someone makes us active again (or we’re exiting)
while (scheduler->active_task != current_task && !current_task->killed) {
pthread_cond_wait(¤t_task->cv, &scheduler->lock);
@@ -119,11 +126,6 @@ static void systask_yield(void) {
// Now the task called systask_yield() is active again
- // Do not return to a killed task
- if (current_task->killed) {
- pthread_exit(0);
- }
-
// Process the pushed call first, if any
// (used to throw exceptions into the task)
if (current_task->pushed_fn_call.fn != NULL) {
Why this scored 41/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.