Skip to content

Realloc scrubbed - #12128

Open
aidankeefe2022 wants to merge 3 commits into
wolfSSL:masterfrom
aidankeefe2022:realloc-scrubbed
Open

aidankeefe2022 wants to merge 3 commits into
wolfSSL:masterfrom
aidankeefe2022:realloc-scrubbed

Conversation

@aidankeefe2022

Copy link
Copy Markdown
Member

Description

When reallocating, allow for lost memory to be scrubbed. This also comes with a fix for IO pool size checking in wc_malloc, which used to just under-allocate instead of failing.

Testing

Added tests to make sure that the IO pool change works and does not fail or corrupt memory.
Added tests to make sure that scrubbing is occurring and that errors are caught.

Checklist

  • added tests
  • updated/added doxygen

wolfSSL_Malloc() handed out an IO buffer for any IN/OUT_BUFFER request
without checking the requested size against the buffer's.  A request
larger than WOLFMEM_IO_SZ would get a buffer too small for it.

- Fixed IO buffers (WOLFMEM_IO_POOL_FIXED) cannot grow, so fail such a
  request instead.
- For the shared IO pool (WOLFMEM_IO_POOL), leave the IO buffer on its
  list and fall through to the general buckets, which may hold a block
  large enough.

Add api.c coverage for both pool kinds.
Native realloc() may move a block and release the old one without
clearing it, leaving secret bytes on the free list.  Add
XREALLOC_SCRUBBED(p, old_size, size, heap, type), backed by
wc_ReallocScrubbed() in wc_port.c (built in every configuration), which
allocates with XMALLOC(), copies, ForceZero()s the old block and then
XFREE()s it.  It never calls native realloc(), so it is also available
with WOLFSSL_NO_REALLOC, and it handles fixed IO pools that hand back
the same block.

Use it where secrets are reallocated:
- der_to_enc_pem_alloc() (pk.c): the DER being padded is a plaintext
  private key.
- mp_grow() (integer.c): mp_ints routinely hold private values.

Add wolfcrypt tests, including a WOLFSSL_CHECK_MEM_ZERO test that checks
the old block is zero when freed (wc_MemZero_Add() is now
WOLFSSL_TEST_VIS for this), and the doxygen entries.
@aidankeefe2022 aidankeefe2022 self-assigned this Nov 13, 2026
Copilot AI balanced review requested due to automatic review settings November 13, 2026 16:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The new conditional in memory.h leaves the header guard unterminated, causing every inclusion to fail preprocessing.

1 open issue
What changed in this PR

This PR adds scrubbed reallocation to wolfSSL’s memory layer so sensitive data is cleared before old buffers are released. It also prevents static I/O pools from returning undersized buffers.

Changes:

  • Introduces XREALLOC_SCRUBBED and applies it to big-integer growth and private-key DER buffers.
  • Adds size checks for fixed and shared I/O pool allocations.
  • Adds regression tests and API documentation.
File Description
wolfssl/​wolfcrypt/​types.h Defines the scrubbed reallocation macro.
wolfssl/​wolfcrypt/​memory.h Declares the new API and exposes a scrubbing test hook.
wolfcrypt/​test/​test.c Tests reallocation, data preservation, failure handling, and scrubbing.
wolfcrypt/​src/​wc_port.c Implements scrubbed reallocation using existing allocator hooks.
wolfcrypt/​src/​memory.c Checks I/O buffer capacity before allocation.
wolfcrypt/​src/​integer.c Scrubs old digit buffers during big-integer growth.
tests/​api.c Tests fixed and shared static I/O pool behavior.
src/​pk.c Uses scrubbed reallocation for private-key DER buffers.
doc/​dox_comments/​header_files/​types.h Documents XREALLOC_SCRUBBED.
doc/​dox_comments/​header_files/​memory.h Documents wc_ReallocScrubbed and provides a usage example.

Review effort: Balanced

Comment thread wolfssl/wolfcrypt/memory.h Resolved

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot 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.

Fenrir Automated Review — PR #12128

⚠️ An internal error occurred during the automated review. This error has been logged. Please contact the Fenrir team if you need assistance.

Error: TimeoutExpired

@aidankeefe2022
aidankeefe2022 marked this pull request as ready for review November 13, 2026 17:07
@github-actions

Copy link
Copy Markdown

retest this please

@github-actions

github-actions Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

MemBrowse Memory Report · Explore what changed →

gcc-arm-cortex-m0plus

  • FLASH: .text +168 B (+0.2%, 71,479 B / 262,144 B, total: 27% used)

gcc-arm-cortex-m3

  • FLASH: .text +152 B (+0.1%, 132,441 B / 262,144 B, total: 51% used)

gcc-arm-cortex-m4

  • FLASH: .text +192 B (+0.1%, 209,768 B / 262,144 B, total: 80% used)

gcc-arm-cortex-m4-baremetal

  • FLASH: .text +128 B (+0.2%, 74,223 B / 262,144 B, total: 28% used)

gcc-arm-cortex-m4-crypto-only

  • FLASH: .text +192 B (+0.1%, 182,987 B / 262,144 B, total: 70% used)

gcc-arm-cortex-m4-dtls13

  • FLASH: .text +128 B (+0.1%, 197,472 B / 1,048,576 B, total: 19% used)

gcc-arm-cortex-m4-min-ecc

  • FLASH: .text +128 B (+0.2%, 68,689 B / 262,144 B, total: 26% used)

gcc-arm-cortex-m4-openssl-compat

  • FLASH: .text +128 B (+0.0%, 804,548 B / 1,048,576 B, total: 77% used)

gcc-arm-cortex-m4-pkcs7

  • FLASH: .text +192 B (+0.1%, 224,268 B / 262,144 B, total: 86% used)

gcc-arm-cortex-m4-pq

  • FLASH: .text +128 B (+0.0%, 314,416 B / 1,048,576 B, total: 30% used)

gcc-arm-cortex-m4-rsa-only

  • FLASH: .text +192 B (+0.1%, 344,680 B / 1,048,576 B, total: 33% used)

gcc-arm-cortex-m4-sp-math

  • FLASH: .text +128 B (+0.2%, 68,689 B / 262,144 B, total: 26% used)

gcc-arm-cortex-m4-tls12

  • FLASH: .text +128 B (+0.1%, 133,193 B / 262,144 B, total: 51% used)

gcc-arm-cortex-m4-tls13

  • FLASH: .text +192 B (+0.1%, 251,138 B / 262,144 B, total: 96% used)

gcc-arm-cortex-m7

  • FLASH: .text +128 B (+0.1%, 209,768 B / 262,144 B, total: 80% used)

gcc-arm-cortex-m7-pq

  • FLASH: .text +192 B (+0.1%, 315,248 B / 1,048,576 B, total: 30% used)

gcc-arm-cortex-m7-tls13

  • FLASH: .text +128 B (+0.1%, 251,074 B / 262,144 B, total: 96% used)

stm32-sim-stm32h753

  • FLASH: .text +576 B (+0.3%, 207,972 B / 2,097,152 B, total: 10% used)

zephyr-frdm_rw612

  • FLASH: datas +16 B, log_const_area -8 B, rodata +28 B, text +12,096 B (+4.3%, 294,596 B / 67,108,864 B, total: 0% used)
  • RAM: bss +49 B, datas +16 B (+0.1%, 58,423 B / 983,040 B, total: 6% used)

Catch memory regressions in CI with MemBrowse. Free for open source.

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot 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.

Fenrir Automated Review — PR #12128

Scan targets checked: wolfcrypt-src, wolfcrypt-bugs, wolfssl-src, wolfssl-bugs
Not reviewed (no scan target covers them): doc/dox_comments/header_files/memory.h, doc/dox_comments/header_files/types.h
Coverage: 8 of 8 in-scope changed file(s) opened by the reviewer

Fenrir result: Approved ✅

No new issues found in the changed files.

Advisory only — this automated result does not count as a GitHub approval.

Review tier: Max

@aidankeefe2022

Copy link
Copy Markdown
Member Author

retest this please

@dgarske dgarske left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Tested on x86_64 (default, --disable-memory, --enable-staticmemory, heapmath + opensslextra with and without ASan/UBSan, --enable-all with WOLFSSL_CHECK_MEM_ZERO, C89 cryptonly), armhf heapmath under qemu, and the MemBrowse Cortex-M4/M0+ builds. All pass.

The wolfSSL_Malloc() IO pool change fixes a heap overflow: an IN/OUT buffer request larger than the IO block used to get the IO block anyway. Please say so in the PR title/body (or split it into its own PR) so it can be tracked and backported. It also needs a ChangeLog note: static-memory users without headroom in the general buckets will now see an out-of-memory error where they used to get silent corruption. The fallback is safe on free, since a fallback block is never WOLFMEM_IO_SZ and goes back to the general buckets.

On XREALLOC_SCRUBBED:

  • wc_ReallocScrubbed is only called from inside the library, so I would make it WOLFSSL_LOCAL (with WOLFSSL_TEST_VIS for test.c) rather than WOLFSSL_API. As public API it is a permanent exported symbol whose oldSz argument overruns the block if a caller gets it wrong. It is also linked into every shared library and every embedded link without --gc-sections, which is where the MemBrowse +128..192 B comes from: none of those configs call it.
  • Under WOLFSSL_NO_FORCE_ZERO, memory.h already expects a user-supplied ForceZero(). Including misc.c unconditionally (as memory.c does) and calling ForceZero() would drop wc_ReallocScrub() and the private volatile loop, which currently bypasses the user's implementation.
  • mp_grow() loses glibc's in-place growth. On an i9 with --enable-heapmath, RSA-2048 is about 5-7% slower and DH-2048 agree about 5-10%. That may be fine for heapmath, but the comment calling it "an acceptable cost" should be a conscious decision.
  • size == 0 frees ptr and returns NULL, which a caller cannot tell from a failure that left ptr valid. No current caller passes 0, but rejecting it would be safer for a scrubbing helper.
  • Nits: put the macro next to the XMALLOC/XREALLOC definitions in types.h; XMEMCPY instead of XMEMMOVE; trim the pk.c/integer.c comments to one line.

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.

5 participants