Skip to content

espressif: Clear sensitive buffers from stack after use - #2800

Open
d3zd3z wants to merge 1 commit into
mcu-tools:mainfrom
d3zd3z:fix-cf018
Open

espressif: Clear sensitive buffers from stack after use#2800
d3zd3z wants to merge 1 commit into
mcu-tools:mainfrom
d3zd3z:fix-cf018

Conversation

@d3zd3z

@d3zd3z d3zd3z commented Jul 23, 2026

Copy link
Copy Markdown
Member

The Espressif flash-encryption HAL keeps two stack buffers holding key/plaintext
material live after use:

  • check_and_generate_encryption_keys() populates a local keys array with the
    raw XTS-AES flash-encryption key, writes it to eFuse via esp_efuse_write_keys(),
    and returns with keys still resident on the stack — on both the success and the
    error paths.
  • esp_flash_encrypt_region() reads each plaintext flash sector into a local buf
    to re-encrypt it in place, and returns (both the success return and the
    flash_failed path) with the last plaintext sector still resident in buf.

This clears both buffers before they go out of scope.

The wipe uses bootutil_wipe_memory() rather than memset()/bzero(): a plain
memset/bzero on a buffer that is not read again before it leaves scope is a
dead store the compiler may legally eliminate, so it is not a reliable way to
clear a buffer. bootutil_wipe_memory() writes through a volatile pointer and
is not elided. Its translation unit (boot/bootutil/src/bootutil_misc.c) is
already linked into the Espressif target, so it is forward-declared locally to
avoid pulling the full bootutil/bootutil.h include chain into the HAL
sub-library.

This is Espressif-port code, so it is not built by the Rust simulator; verified by
inspection and covered by the espressif CI build.

The flash-encryption HAL left two stack buffers holding secret material
live after use. check_and_generate_encryption_keys() populated a local
keys array with the raw XTS-AES flash-encryption key and passed it to
esp_efuse_write_keys() without clearing it before returning, on either
the success or the error path. esp_flash_encrypt_region() read each
plaintext flash sector into a local buffer to re-encrypt it in place and
returned with the last sector's plaintext still resident, on both the
success and failure returns.

Clear both buffers before they go out of scope with
bootutil_wipe_memory(), which writes through a volatile pointer so the
stores are not elided as a dead store the way a plain memset() or
bzero() on a soon-discarded buffer can be.

Assisted-by: Claude:opus-4.8
Signed-off-by: David Brown <david.brown@linaro.org>
@d3zd3z
d3zd3z requested a review from almir-okato as a code owner July 23, 2026 20:23
Copilot AI review requested due to automatic review settings July 23, 2026 20:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants