Re: [PATCH 1/3] x86/entry: Clear extra registers beyond syscall arguments for 64bit kernels
From: Ingo Molnar
Date: Mon Feb 05 2018 - 15:06:07 EST
* Ingo Molnar <mingo@xxxxxxxxxx> wrote:
> Btw., to underline these arguments, here's some statistical data about actual
> register usage the x86 kernel.
So this caveat was bothering me:
> List of caveats/notes:
>
> Note #4:
> The 'avg uses per fn' number is over-estimates the real uses per function,
> because I counted total number of uses, not rounded down to a per function
> register usage heat-map. I believe this does not change the _ordering_ of the
> register usage histograms, so it's a valid simplification.
as averaging all uses over the functions over-estimates the per function usage of
registers significantly, so I implemented a real, per function register usage
tracking.
For the x86 defconfig kernel the results are:
r11: used in 1704 fns, not used in 43310 fns, usage ratio: 3.8%
r10: used in 3809 fns, not used in 41205 fns, usage ratio: 8.5%
r15: used in 6599 fns, not used in 38415 fns, usage ratio: 14.7%
r9: used in 8120 fns, not used in 36894 fns, usage ratio: 18.0%
r14: used in 9243 fns, not used in 35771 fns, usage ratio: 20.5%
r8: used in 12614 fns, not used in 32400 fns, usage ratio: 28.0%
r13: used in 12708 fns, not used in 32306 fns, usage ratio: 28.2%
r12: used in 17144 fns, not used in 27870 fns, usage ratio: 38.1%
rbp: used in 23289 fns, not used in 21725 fns, usage ratio: 51.7%
rcx: used in 23897 fns, not used in 21117 fns, usage ratio: 53.1%
rbx: used in 29226 fns, not used in 15788 fns, usage ratio: 64.9%
rdx: used in 33205 fns, not used in 11809 fns, usage ratio: 73.8%
rsi: used in 35415 fns, not used in 9599 fns, usage ratio: 78.7%
rdi: used in 40628 fns, not used in 4386 fns, usage ratio: 90.3%
rax: used in 43120 fns, not used in 1894 fns, usage ratio: 95.8%
As a comparison, here's the previous estimate:
# nr of =y .config options: 1255
# nr of functions: 45490
# nr of instructions: 1963956
# nr of register uses: 3183680
register | # of uses | avg uses per fn
--------------------------------------
%r11 | 11608 | 0.3
%r10 | 23398 | 0.5
%r9 | 37431 | 0.8
%r8 | 56140 | 1.2
%r15 | 77468 | 1.7
%r14 | 89285 | 2.0
%r13 | 111665 | 2.5
%r12 | 151977 | 3.3
%rcx | 166425 | 3.7
%rsi | 226536 | 5.0
%rbp | 238286 | 5.2
%rdi | 306709 | 6.7
%rdx | 313569 | 6.9
%rbx | 349496 | 7.7
%rax | 728036 | 16.0
The ordering of the registers is similar, but it's not the same - and the actual
percentages changed drastically.
In particular R10 and R11 are used only in a small minority of the functions:
r11: used in 1704 fns, not used in 43310 fns, usage ratio: 3.8%
r10: used in 3809 fns, not used in 41205 fns, usage ratio: 8.5%
and if deeper inside the kernel a Spectre-gadget uses R10 or R11 then chances are
high that user-space R10/R11 values will be passed through to it without
disturbance from other C functions.
So I think these numbers increase the urgency of clearing R10/R11 as well.
Note that this too is still only a statistical estimate, the _real_ impact could
only be judged if we created a call graph of the whole kernel, with 100% coverage,
and analyzed register use through this tree.
The other registers:
r15: used in 6599 fns, not used in 38415 fns, usage ratio: 14.7%
r9: used in 8120 fns, not used in 36894 fns, usage ratio: 18.0%
r14: used in 9243 fns, not used in 35771 fns, usage ratio: 20.5%
r8: used in 12614 fns, not used in 32400 fns, usage ratio: 28.0%
r13: used in 12708 fns, not used in 32306 fns, usage ratio: 28.2%
r12: used in 17144 fns, not used in 27870 fns, usage ratio: 38.1%
R12-R15 will be cleared with tis patchset, so that angle should be handled, which
leaves us:
r9: used in 8120 fns, not used in 36894 fns, usage ratio: 18.0%
r8: used in 12614 fns, not used in 32400 fns, usage ratio: 28.0%
These are arguments #5 and #6 of the x86-64 C calling convention ABI. In practice
they will be overwritten in many code paths - especially they will be overwritten
in some of the richer ABIs of Linux: ioctls, socketcalls and the other high level
demux system calls.
R8 is also spontaneously used by GCC once a function's size grows about ~130
instructions. For R9 the average threshold is about ~160 instructions.
Thanks,
Ingo