memcpy is leaking secret data through ZMM vector registers
Jan Sebastian Götte
linux@jaseg.de
Wed Aug 12 09:38:00 GMT 2026
On 4/20/24 05:29, Zack Weinberg wrote:
> On Fri, Apr 19, 2024, at 7:27 PM, Florian Weimer wrote:
>> * Mikulas Patocka:
>>> On Fri, 19 Apr 2024, Zack Weinberg wrote:
>>>> On Fri, Apr 19, 2024, at 4:15 PM, Mikulas Patocka wrote:
>>>>> On Fri, 19 Apr 2024, Zack Weinberg wrote:
>>>>>> ... the copy
>>>>>> of round_keys in the vector registers *won't* get erased -- the exact
>>>>>> problem being discussed in this thread.
>>>>>
>>>>> On the SYSV ABI, all the vector registers are volatile, so you can erase
>>>>> them in explicit_bzero.
>>>>>
>>>>> On Windows 64-bit ABI, it is more problematic, because some of the vector
>>>>> registers must be preserved.
>>>>
>>>> Oh, huh. Yes, that would work.
>>>
>>> I've just realized that this wouldn't work - if the function
>>> explicit_bzero is lazily resolved, the dynamic linker would spill the
>>> vector registers to the stack prior to calling explicit_bzero.
>>
>> No, the dynamic linker makes a tail call to explicit_bzero. There's no
>> register restore on the return path, all that happens before the tail
>> call.
>
> Doesn't help — if the vector registers get spilled at all, we lose.
I've recently come across a similar issue as reported in this old
thread. I was checking for key residue in memory dumps of a crashed
system, and I saw parts of keys persist in memory long after they were
deleted by the application. The leakage mechanism I observed was:
* app memcpy()s key from one place to another
-- key residue left in SIMD regs now (in my case ARM NEON, but would be
the same on x86)
* app does something with it
* app properly zero's everything
-- key residue in SIMD regs not cleared
* app continues running
* context switch happens, kernel switches to another task. Kernel saves
SIMD reg contents behind struct task_struct
* system crashes, RAM dump taken. Key residue in kernel memory.
So even if the vector regs never get spilled to the stack, they still
can easily end up in kernel memory long after the original data was
erased. While this is not a big issue if everything works alright, it's
still counter-intuitive and I think it would be good to do defense in
depth and zero these vector regs after they are no longer needed.
I'm not sure the general purpose memcpy() would be the right place for a
mitigation though. While AVX has VZEROALL, ARM NEON doesn't and requires
32 separate instructions, which I think could impact in a measurable
performance hit even if you only issue the ones a particular call
actually uses.
- Jan
More information about the Libc-alpha
mailing list