Skip to content

chore(core): remove double check when changing pin#6132

Merged
M-pasta merged 2 commits into
mainfrom
mpastyrik/pin_verification_optimization
Feb 6, 2026
Merged

chore(core): remove double check when changing pin#6132
M-pasta merged 2 commits into
mainfrom
mpastyrik/pin_verification_optimization

Conversation

@M-pasta
Copy link
Copy Markdown
Contributor

@M-pasta M-pasta commented Nov 6, 2025

Remove the second pin check during pin change.

[no changelog]

@trezor-bot trezor-bot Bot added this to Firmware Nov 6, 2025
@github-project-automation github-project-automation Bot moved this to 🔎 Needs review in Firmware Nov 6, 2025
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Nov 6, 2025

en main(all)

model device_test click_test persistence_test
T2T1 test(all) main(all) test(all) main(all) test(all) main(all)
T3B1 test(all) main(all) test(all) main(all) test(all) main(all)
T3T1 test(all) main(all) test(all) main(all) test(all) main(all)
T3W1 test(all) main(all) test(all) main(all) test(all) main(all)
Translations

cs main(all)

model device_test click_test
T2T1 test(all) main(all) test(all) main(all)
T3B1 test(all) main(all) test(all) main(all)
T3T1 test(all) main(all) test(all) main(all)
T3W1 test(all) main(all) test(all) main(all)

de main(all)

model device_test click_test
T2T1 test(all) main(all) test(all) main(all)
T3B1 test(all) main(all) test(all) main(all)
T3T1 test(all) main(all) test(all) main(all)
T3W1 test(all) main(all) test(all) main(all)

es main(all)

model device_test click_test
T2T1 test(all) main(all) test(all) main(all)
T3B1 test(all) main(all) test(all) main(all)
T3T1 test(all) main(all) test(all) main(all)
T3W1 test(all) main(all) test(all) main(all)

fr main(all)

model device_test click_test
T2T1 test(all) main(all) test(all) main(all)
T3B1 test(all) main(all) test(all) main(all)
T3T1 test(all) main(all) test(all) main(all)
T3W1 test(all) main(all) test(all) main(all)

pt main(all)

model device_test click_test
T2T1 test(all) main(all) test(all) main(all)
T3B1 test(all) main(all) test(all) main(all)
T3T1 test(all) main(all) test(all) main(all)
T3W1 test(all) main(all) test(all) main(all)

Latest CI run: 21754504002

@github-actions
Copy link
Copy Markdown

Looks like you changed Cargo.lock. Please make sure to review the dependencies and update internal version list.

@M-pasta M-pasta force-pushed the mpastyrik/pin_verification_optimization branch from c526f71 to 7fd0ed1 Compare December 16, 2025 14:27
@M-pasta M-pasta added the translations Put this label on a PR to run tests in all languages label Jan 2, 2026
@M-pasta M-pasta force-pushed the mpastyrik/pin_verification_optimization branch from 2b1e5ec to 24d8160 Compare January 2, 2026 14:40
@M-pasta M-pasta marked this pull request as ready for review January 5, 2026 11:55
Comment thread core/src/apps/management/recovery_device/__init__.py Outdated
Comment thread core/src/apps/management/change_pin.py Outdated
Comment thread core/src/apps/management/change_pin.py Outdated
Comment thread core/src/apps/management/sd_protect.py
Comment thread core/tests/test_trezor.config.py
Comment thread legacy/firmware/protect.c Outdated
Comment thread storage/storage.c
Comment thread core/src/apps/management/change_pin.py
Comment thread storage/tests/c/storage.py
Comment thread storage/storage.c Outdated
Comment thread storage/storage.c Outdated
Comment thread storage/storage.c Outdated
Comment thread storage/storage.c Outdated
Comment thread core/embed/upymod/modtrezorconfig/modtrezorconfig.c
Comment thread core/src/apps/management/sd_protect.py Outdated
Comment thread core/src/apps/management/sd_protect.py Outdated
Comment thread core/src/apps/management/sd_protect.py Outdated
Comment thread core/src/apps/management/sd_protect.py Outdated
Comment thread core/src/apps/management/sd_protect.py Outdated
Comment thread core/src/apps/management/sd_protect.py Outdated
Comment thread legacy/firmware/config.c Outdated
Comment thread storage/tests/c/storage.py Outdated
Comment thread storage/storage.c Outdated
@M-pasta M-pasta force-pushed the mpastyrik/pin_verification_optimization branch from 7ef7b49 to b920599 Compare January 29, 2026 10:33
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 29, 2026

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

💤 Files selected but had no reviewable changes (1)
  • tests/ui_tests/fixtures.json

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review

Walkthrough

The PR replaces boolean return values for storage unlock and PIN-change operations with two new enums (storage_unlock_result_t, storage_pin_change_result_t) that expose detailed outcome codes. The storage PIN-change API is simplified to accept only the new PIN and its external salt (old PIN/old salt parameters removed). These API and return-type changes propagate through storage headers/implementation, syscall/smcall stubs and verifiers, legacy firmware, Rust bindgen config, MicroPython module bindings, Python apps/tests, and storage tests; call sites and error handling were updated to use the new enums and parameter ordering.

Sequence Diagram(s)

sequenceDiagram
  participant UI as Client/UI
  participant App as Application
  participant Bind as Language Bindings
  participant Sys as Syscall/SMCall Verifier
  participant Stor as Secure Storage

  UI->>App: request change PIN (new_pin, new_ext_salt)
  App->>Bind: config.change_pin(new_pin, new_ext_salt)
  Bind->>Sys: syscall/storage_change_pin(newpin, newpin_len, new_ext_salt)
  Sys->>Stor: storage_change_pin(newpin, newpin_len, new_ext_salt)
  Stor-->>Sys: storage_pin_change_result_t (e.g. PIN_CHANGE_OK / PIN_CHANGE_*)
  Sys-->>Bind: storage_pin_change_result_t
  Bind-->>App: propagate enum result
  App-->>UI: success / raise error based on enum
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description is minimal but does not follow the template structure. While it briefly mentions the change intent, it lacks sections for context, rationale, testing, and other structured information recommended in the template. Consider adding structured sections to explain the motivation, affected systems, testing performed, and any breaking changes to help reviewers understand the full scope of the PIN verification optimization.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: removing a redundant PIN check during PIN change operations, which is reflected consistently across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mpastyrik/pin_verification_optimization

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
storage/tests/tests/storage_model.py (1)

40-48: Inconsistent behavior: unlock() vs check_pin() for old PIN verification.

The StorageModel.change_pin() uses self.unlock(oldpin) to verify the old PIN (line 43), but the equivalent implementation in storage/tests/python/src/storage.py uses self.check_pin(oldpin) instead. This creates a behavioral difference:

  • unlock() decrements pin_rem and can trigger a wipe on wrong PIN
  • check_pin() (if it exists in this model) would typically just verify without side effects

Since the storage is already unlocked at this point, calling unlock() with a wrong oldpin would unexpectedly decrement the PIN counter and potentially wipe storage, which seems like unintended behavior for a PIN change operation.

Consider aligning with the Python storage implementation by using a check_pin() method instead, or documenting this as intentional behavior.

core/src/apps/management/change_pin.py (1)

41-54: Replace config.check_pin() with config.unlock() to unlock storage before calling change_pin().

The config.change_pin() call requires unlocked storage (per mock docstring), but the code only calls config.check_pin(curpin, salt), which validates the PIN without unlocking. This should be config.unlock(curpin, salt) instead.

core/embed/sys/smcall/stm32/smcall_verifiers.c (2)

278-281: Critical: Type mismatch returns success on access violation.

The function returns storage_unlock_result_t, but the access_violation path returns secfalse. If secfalse equals 0 (which is common), this would incorrectly return UNLOCK_OK (which is also 0), indicating a successful unlock on access violation.

This is a security issue - an access violation should return a failure code like UNLOCK_UNKNOWN or a dedicated access violation error code.

🐛 Proposed fix
 access_violation:
   apptask_access_violation();
-  return secfalse;
+  return UNLOCK_UNKNOWN;
 }

295-298: Critical: Type mismatch returns success on access violation.

Same issue as storage_unlock__verified - returning secfalse for a storage_pin_change_result_t would incorrectly indicate PIN_CHANGE_OK if secfalse equals 0.

🐛 Proposed fix
 access_violation:
   apptask_access_violation();
-  return secfalse;
+  return PIN_CHANGE_UNKNOWN;
 }
core/embed/sys/syscall/stm32/syscall_verifiers.c (2)

655-658: Critical: Type mismatch returns success on access violation.

Same issue as in smcall_verifiers.c - the function returns storage_unlock_result_t, but secfalse is returned on access violation, which would incorrectly indicate UNLOCK_OK if secfalse equals 0.

🐛 Proposed fix
 access_violation:
   apptask_access_violation();
-  return secfalse;
+  return UNLOCK_UNKNOWN;
 }

672-675: Critical: Type mismatch returns success on access violation.

Same issue - returning secfalse for a storage_pin_change_result_t would incorrectly indicate PIN_CHANGE_OK.

🐛 Proposed fix
 access_violation:
   apptask_access_violation();
-  return secfalse;
+  return PIN_CHANGE_UNKNOWN;
 }
🤖 Fix all issues with AI agents
In `@core/embed/sys/syscall/stm32/syscall_verifiers.h`:
- Around line 183-188: The verifier functions storage_unlock__verified and
storage_change_pin__verified currently return the generic secfalse on
access_violation which doesn't match their declared return types
storage_unlock_result_t and storage_pin_change_result_t; change the
access_violation return to a proper enum sentinel (e.g. return
UNLOCK_NOT_INITIALIZED for storage_unlock__verified and
PIN_CHANGE_NOT_INITIALIZED for storage_change_pin__verified) or add and return a
dedicated ACCESS_VIOLATION variant in those enums, and keep the
apptask_access_violation() call intact; update any enum definitions and usages
to ensure the chosen enum constants are defined and mapped consistently.

In `@legacy/firmware/protect.c`:
- Around line 283-287: config_changePin currently returns only bool so every
failure maps to the wipe‑code message; update the fix by changing
config_changePin to return a discriminated result (enum) describing outcomes
(e.g., Success, Error_SameAsWipeCode, Error_RemovalNotAllowed,
Error_StorageFailure), then update the caller in protect.c to inspect that enum
and call fsm_sendFailure(FailureType_Failure_ProcessError, ...) with a specific
message for Error_SameAsWipeCode and a generic "Could not change PIN" (or
appropriate messages) for other errors; alternatively, if changing the API is
infeasible, replace the hardcoded wipe‑code string with a single generic failure
message so non‑wipe failures are not misleading.
🧹 Nitpick comments (4)
core/embed/upymod/modtrezorconfig/modtrezorconfig.c (1)

88-134: Document that most failures raise exceptions.

The unlock path now raises RuntimeError for many failure codes, but the docstring above still says “False on failure.” Consider updating it to avoid misleading callers.

core/src/apps/management/sd_protect.py (3)

68-94: Consider using exception chaining for clearer error tracing.

The raise wire.ProcessError(...) on line 94 should use exception chaining to preserve the original error context or explicitly suppress it.

♻️ Proposed fix
     except RuntimeError:
         # Failed to set salt in storage. Clean up the prepared salt file.
         try:
             storage_sd_salt.remove_sd_salt()
         except Exception:
             # The cleanup is not necessary for the correct functioning of
             # SD-protection. If it fails for any reason, we suppress the
             # exception.
             pass
-        raise wire.ProcessError("Failed to set salt in storage")
+        raise wire.ProcessError("Failed to set salt in storage") from None

121-124: Use exception chaining for consistency.

Similar to the enable flow, use from None to explicitly suppress the exception chain.

♻️ Proposed fix
     try:
         config.change_pin(pin, None)
     except RuntimeError:
-        raise wire.FirmwareError("Failed to remove SD salt")
+        raise wire.FirmwareError("Failed to remove SD salt") from None

163-166: Use exception chaining for consistency.

Same pattern as the other flows.

♻️ Proposed fix
     try:
         config.change_pin(pin, new_salt)
     except RuntimeError:
-        raise wire.FirmwareError("Failed to set new salt in storage")
+        raise wire.FirmwareError("Failed to set new salt in storage") from None

Comment thread core/embed/sys/syscall/stm32/syscall_verifiers.h
Comment thread legacy/firmware/protect.c
@M-pasta M-pasta force-pushed the mpastyrik/pin_verification_optimization branch from 28796b3 to e05002a Compare February 6, 2026 12:17
@M-pasta M-pasta merged commit 8a1128a into main Feb 6, 2026
166 checks passed
@M-pasta M-pasta deleted the mpastyrik/pin_verification_optimization branch February 6, 2026 15:17
@github-project-automation github-project-automation Bot moved this from 🔎 Needs review to 🤝 Needs QA in Firmware Feb 6, 2026
@STew790 STew790 moved this from 🤝 Needs QA to ✅ Approved by QA in Firmware Feb 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

translations Put this label on a PR to run tests in all languages

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

3 participants