From: Ryan Roberts <ryan.roberts@arm.com>
To: Kees Cook <kees@kernel.org>, Ard Biesheuvel <ardb+git@google.com>,
Will Deacon <will@kernel.org>, Arnd Bergmann <arnd@arndb.de>,
Jeremy Linton <jeremy.linton@arm.com>,
Catalin Marinas <Catalin.Marinas@arm.com>,
Mark Rutland <mark.rutland@arm.com>,
"Jason A . Donenfeld" <Jason@zx2c4.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>,
linux-hardening@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
Subject: [RFC PATCH v1 0/2] Fix bugs and performance of kstack offset randomisation
Date: Thu, 27 Nov 2025 10:59:54 +0000 [thread overview]
Message-ID: <20251127105958.2427758-1-ryan.roberts@arm.com> (raw)
Hi All,
I guess this is an alternative to Ard's series since he beat me to it. I'll
benchmark his series so we have comparable numbers...
As I reported at [1], kstack offset randomisation suffers from a couple of bugs
and, on arm64 at least, the performance is poor. This series attempts to fix
both; patch 1 provides back-portable fixes for the functional bugs. Patch 2
proposes a performance improvement approach.
I've looked at a few different options but ultimately decided that Jeremy's
original prng approach is the fastest, and I want to make the argument that it
is "secure enough" for this use case. This could be combined with an occasional
reseed from the crng; If amortized over ~10K syscalls it makes no difference to
mean performance. But I'm not convinced of the value. I think we should aim to
keep it simple and architecture agnostic.
Ultimately we are only randomising the offset with 6 bits. So an attack that
depnds on knowing the stack offset would get lucky 1 in 64 attempts. Surely
that's trivially brute forcable? Given that, why go to so much effort to ensure
the 6 bits are strong random?
More details in the commit logs.
Performance
===========
Mean and tail performance of 3 "small" syscalls was measured. syscall was made
10 million times and each individually measured and binned. These results have
low noise so I'm confident that they are trustworthy.
The baseline if v6.18-rc5 with stack randomization turned *off*. So I'm showing
performance cost of turning it on without any changes to the implementation,
then the reduced performance cost of turning it on with my changes applied.
arm64 (AWS Graviton3):
+-----------------+--------------+-------------+---------------+
| Benchmark | Result Class | v6.18-rc5 | per-task-prng |
| | | rndstack-on | |
| | | | |
+=================+==============+=============+===============+
| syscall/getpid | mean (ns) | (R) 15.62% | (R) 3.43% |
| | p99 (ns) | (R) 155.01% | (R) 3.20% |
| | p99.9 (ns) | (R) 156.71% | (R) 2.93% |
+-----------------+--------------+-------------+---------------+
| syscall/getppid | mean (ns) | (R) 14.09% | (R) 2.12% |
| | p99 (ns) | (R) 152.81% | 1.55% |
| | p99.9 (ns) | (R) 153.67% | 1.77% |
+-----------------+--------------+-------------+---------------+
| syscall/invalid | mean (ns) | (R) 13.89% | (R) 3.32% |
| | p99 (ns) | (R) 165.82% | (R) 3.51% |
| | p99.9 (ns) | (R) 168.83% | (R) 3.77% |
+-----------------+--------------+-------------+---------------+
Because arm64 was previously using get_random_u16(), it was expensive when it
didn't have any buffered bits and had to call into the crng. That's what caused
the enormous tail latency.
x86 (AWS Sapphire Rapids):
+-----------------+--------------+-------------+---------------+
| Benchmark | Result Class | v6.18-rc5 | per-task-prng |
| | | rndstack-on | |
| | | | |
+=================+==============+=============+===============+
| syscall/getpid | mean (ns) | (R) 13.32% | (R) 4.60% |
| | p99 (ns) | (R) 13.38% | (R) 18.08% |
| | p99.9 (ns) | 16.26% | (R) 19.38% |
+-----------------+--------------+-------------+---------------+
| syscall/getppid | mean (ns) | (R) 11.96% | (R) 5.26% |
| | p99 (ns) | (R) 11.83% | (R) 8.35% |
| | p99.9 (ns) | (R) 11.42% | (R) 22.37% |
+-----------------+--------------+-------------+---------------+
| syscall/invalid | mean (ns) | (R) 10.58% | (R) 2.91% |
| | p99 (ns) | (R) 10.51% | (R) 4.36% |
| | p99.9 (ns) | (R) 10.35% | (R) 21.97% |
+-----------------+--------------+-------------+---------------+
I was surprised to see that the baseline cost on x86 is 10-12% since it is just
using rdtsc. But as I say, I believe the results are accurate.
Thanks,
Ryan
Ryan Roberts (2):
randomize_kstack: Maintain kstack_offset per task
randomize_kstack: Unify random source across arches
arch/Kconfig | 5 ++-
arch/arm64/kernel/syscall.c | 11 ------
arch/loongarch/kernel/syscall.c | 11 ------
arch/powerpc/kernel/syscall.c | 12 -------
arch/riscv/kernel/traps.c | 12 -------
arch/s390/include/asm/entry-common.h | 8 -----
arch/x86/include/asm/entry-common.h | 12 -------
include/linux/prandom.h | 7 +++-
include/linux/randomize_kstack.h | 53 ++++++++++------------------
include/linux/sched.h | 5 +++
init/main.c | 1 -
kernel/fork.c | 2 ++
12 files changed, 34 insertions(+), 105 deletions(-)
--
2.43.0
next reply other threads:[~2025-11-27 11:00 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-27 10:59 Ryan Roberts [this message]
2025-11-27 10:59 ` [RFC PATCH v1 1/2] randomize_kstack: Maintain kstack_offset per task Ryan Roberts
2025-11-27 10:59 ` [RFC PATCH v1 2/2] randomize_kstack: Unify random source across arches Ryan Roberts
2025-11-28 11:01 ` Ard Biesheuvel
2025-12-01 18:20 ` Ryan Roberts
2025-12-02 9:15 ` Ard Biesheuvel
2025-12-02 9:34 ` Ryan Roberts
2025-12-02 9:35 ` Mark Rutland
2025-12-02 9:39 ` Ryan Roberts
2025-12-02 9:53 ` Mark Rutland
2025-12-02 11:04 ` Ryan Roberts
2025-12-02 9:47 ` Ard Biesheuvel
2025-12-02 10:02 ` Mark Rutland
2025-12-02 16:59 ` [RFC PATCH v1 0/2] Fix bugs and performance of kstack offset randomisation Kees Cook
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251127105958.2427758-1-ryan.roberts@arm.com \
--to=ryan.roberts@arm.com \
--cc=Catalin.Marinas@arm.com \
--cc=Jason@zx2c4.com \
--cc=ardb+git@google.com \
--cc=arnd@arndb.de \
--cc=jeremy.linton@arm.com \
--cc=kees@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).