bip39: scrub vector registers after mnemonic decoding#534
Conversation
test_clear finds plaintext secret material ~11KB deep on the stack after bip39_mnemonic_validate returns. The residue comes from XMM registers xsaved by the dynamic linker on subsequent PLT calls, not from a source-level local buffer. Adding a zeroed stack scratch in bip39_mnemonic_to_bytes forces glibc memset to issue SSE/AVX zero stores that clobber the vector registers before the function returns, so later xsave operations no longer spill secret bytes.
|
OK, I'm looking at this and having some trouble verifying it. Running locally, I see the same leak after I added Did this change resolve test_clear failing on your machine? |
|
yes it do on 2 different machines: |
|
Hmm, what is your full build line (configure args and initial make)? |
Details |
|
OK so there are a few things going on here:
Note that this issue disappears entirely if static linking, only dynamic linking is affected. I've addressed (1), I suspect for the remainder the answer is probably to replace memcpy/cmp/set with unoptimizable variants that prevent the "optimized" libc versions from being called, and therefore don't require clearing the registers at the end :( |
|
@pythcoiner @odudex Can you please try my attempt at a fix https://github.com/ElementsProject/libwally-core/tree/multi_updates and let me know if this allows test_clear to pass for you? Thanks |
I can confirm all tests, python and C, including test_clear are green for me in branch multi_updates @ 78499f0 |
|
@jgriffiths I can confirm |
During the work proposed on #533 I separated this out of scope, yet likely relevant commit from @pythcoiner, so it can be evaluated individually:
"test_clear finds plaintext secret material ~11KB deep on the stack after bip39_mnemonic_validate returns. The residue comes from XMM registers xsaved by the dynamic linker on subsequent PLT calls, not from a source-level local buffer. Adding a zeroed stack scratch in bip39_mnemonic_to_bytes forces glibc memset to issue SSE/AVX zero stores that clobber the vector registers before the function returns, so later xsave operations no longer spill secret bytes."