From: Ard Biesheuvel <ard.biesheuvel@linaro.org>
To: kernel-hardening@lists.openwall.com
Cc: keescook@chromium.org, christoffer.dall@arm.com,
will.deacon@arm.com, catalin.marinas@arm.com,
mark.rutland@arm.com, labbott@fedoraproject.org,
linux-arm-kernel@lists.infradead.org,
Ard Biesheuvel <ard.biesheuvel@linaro.org>
Subject: [RFC/PoC PATCH 3/3] arm64: enable ROP protection by clearing SP bit #55 across function returns
Date: Thu, 2 Aug 2018 15:21:32 +0200 [thread overview]
Message-ID: <20180802132133.23999-4-ard.biesheuvel@linaro.org> (raw)
In-Reply-To: <20180802132133.23999-1-ard.biesheuvel@linaro.org>
ROP attacks rely on a large supply of so-called 'gadgets', which are
(in this context) short sequences of instructions ending in a stack
pop and a return instruction. By exploiting a stack overflow to create
a specially crafted stack frame, each gadget jumps to the next by
popping off the next gadget's address as a fake return address,
allowing non-trivial 'programs' to be executed by piecing together
a large number of such gadgets.
This attack vector relies heavily on the ability to jump to arbitrary
places in the code. If we could limit where a function could return to,
it is much more difficult to obtain critical mass in terms of a gadget
collection that allows arbitrary attacks to be mounted.
So let's try and do so by clearing bit #55 in the stack pointer register
before returning from a function, and setting it again right after a
'bl' or 'blr' instruction. That way, jumping to arbitrary places in the
code and popping the next gadget's address becomes a lot more complicated,
since the stack pointer will not be valid after a function return until
the 'reset' sequence is executed (or after an exception is taken).
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/Kconfig | 10 ++++++++++
arch/arm64/include/asm/assembler.h | 9 +++++++++
arch/arm64/kernel/entry.S | 18 ++++++++++++++++++
3 files changed, 37 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 42c090cf0292..4562af0250b9 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1011,6 +1011,16 @@ config ARM64_SW_TTBR0_PAN
zeroed area and reserved ASID. The user access routines
restore the valid TTBR0_EL1 temporarily.
+config ARM64_ROP_SHIELD
+ bool "Enable basic ROP protection through the stack pointer sign bit"
+ depends on GCC_PLUGINS && VMAP_STACK
+ select GCC_PLUGIN_ARM64_ROP_SHIELD
+ help
+ Enable protection against ROP attacks by clearing bit #55 in the
+ stack pointer register across a function return.
+
+ If paranoid, say Y here. If unsure, say N.
+
menu "ARMv8.1 architectural features"
config ARM64_HW_AFDBM
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 346ada4de48a..95d3ec98eb58 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -701,12 +701,21 @@ USER(\label, ic ivau, \tmp2) // invalidate I line PoU
.Lyield_out_\@ :
.endm
+ .macro unclobber_sp, tmp
+#ifdef CONFIG_ARM64_ROP_SHIELD
+ mov \tmp, sp
+ orr sp, \tmp, #(1 << 55)
+#endif
+ .endm
+
.macro bl_c, target
bl \target
+ unclobber_sp x30
.endm
.macro blr_c, reg
blr \reg
+ unclobber_sp x30
.endm
#endif /* __ASM_ASSEMBLER_H */
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index eba5b6b528ea..2adebca74f11 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -95,6 +95,9 @@ alternative_else_nop_endif
*/
add sp, sp, x0 // sp' = sp + x0
sub x0, sp, x0 // x0' = sp' - x0 = (sp + x0) - x0 = sp
+#ifdef CONFIG_ARM64_ROP_SHIELD
+ tbz x0, #55, 1f
+#endif
tbnz x0, #THREAD_SHIFT, 0f
sub x0, sp, x0 // x0'' = sp' - x0' = (sp + x0) - sp = x0
sub sp, sp, x0 // sp'' = sp' - x0 = (sp + x0) - x0 = sp
@@ -129,6 +132,21 @@ alternative_else_nop_endif
/* We were already on the overflow stack. Restore sp/x0 and carry on. */
sub sp, sp, x0
mrs x0, tpidrro_el0
+ b el\()\el\()_\label
+
+#ifdef CONFIG_ARM64_ROP_SHIELD
+1: /*
+ * We have to do a little dance here to set bit 55 in the stack
+ * pointer register without clobbering anything else.
+ */
+ orr x0, x0, #(1 << 55)
+ str x1, [x0]
+ mov x1, sp
+ mov sp, x0
+ and x0, x0, #~(1 << 55)
+ sub x0, x1, x0
+ ldr x1, [sp]
+#endif
#endif
b el\()\el\()_\label
.endm
--
2.18.0
WARNING: multiple messages have this Message-ID (diff)
From: ard.biesheuvel@linaro.org (Ard Biesheuvel)
To: linux-arm-kernel@lists.infradead.org
Subject: [RFC/PoC PATCH 3/3] arm64: enable ROP protection by clearing SP bit #55 across function returns
Date: Thu, 2 Aug 2018 15:21:32 +0200 [thread overview]
Message-ID: <20180802132133.23999-4-ard.biesheuvel@linaro.org> (raw)
In-Reply-To: <20180802132133.23999-1-ard.biesheuvel@linaro.org>
ROP attacks rely on a large supply of so-called 'gadgets', which are
(in this context) short sequences of instructions ending in a stack
pop and a return instruction. By exploiting a stack overflow to create
a specially crafted stack frame, each gadget jumps to the next by
popping off the next gadget's address as a fake return address,
allowing non-trivial 'programs' to be executed by piecing together
a large number of such gadgets.
This attack vector relies heavily on the ability to jump to arbitrary
places in the code. If we could limit where a function could return to,
it is much more difficult to obtain critical mass in terms of a gadget
collection that allows arbitrary attacks to be mounted.
So let's try and do so by clearing bit #55 in the stack pointer register
before returning from a function, and setting it again right after a
'bl' or 'blr' instruction. That way, jumping to arbitrary places in the
code and popping the next gadget's address becomes a lot more complicated,
since the stack pointer will not be valid after a function return until
the 'reset' sequence is executed (or after an exception is taken).
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/Kconfig | 10 ++++++++++
arch/arm64/include/asm/assembler.h | 9 +++++++++
arch/arm64/kernel/entry.S | 18 ++++++++++++++++++
3 files changed, 37 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 42c090cf0292..4562af0250b9 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1011,6 +1011,16 @@ config ARM64_SW_TTBR0_PAN
zeroed area and reserved ASID. The user access routines
restore the valid TTBR0_EL1 temporarily.
+config ARM64_ROP_SHIELD
+ bool "Enable basic ROP protection through the stack pointer sign bit"
+ depends on GCC_PLUGINS && VMAP_STACK
+ select GCC_PLUGIN_ARM64_ROP_SHIELD
+ help
+ Enable protection against ROP attacks by clearing bit #55 in the
+ stack pointer register across a function return.
+
+ If paranoid, say Y here. If unsure, say N.
+
menu "ARMv8.1 architectural features"
config ARM64_HW_AFDBM
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 346ada4de48a..95d3ec98eb58 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -701,12 +701,21 @@ USER(\label, ic ivau, \tmp2) // invalidate I line PoU
.Lyield_out_\@ :
.endm
+ .macro unclobber_sp, tmp
+#ifdef CONFIG_ARM64_ROP_SHIELD
+ mov \tmp, sp
+ orr sp, \tmp, #(1 << 55)
+#endif
+ .endm
+
.macro bl_c, target
bl \target
+ unclobber_sp x30
.endm
.macro blr_c, reg
blr \reg
+ unclobber_sp x30
.endm
#endif /* __ASM_ASSEMBLER_H */
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index eba5b6b528ea..2adebca74f11 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -95,6 +95,9 @@ alternative_else_nop_endif
*/
add sp, sp, x0 // sp' = sp + x0
sub x0, sp, x0 // x0' = sp' - x0 = (sp + x0) - x0 = sp
+#ifdef CONFIG_ARM64_ROP_SHIELD
+ tbz x0, #55, 1f
+#endif
tbnz x0, #THREAD_SHIFT, 0f
sub x0, sp, x0 // x0'' = sp' - x0' = (sp + x0) - sp = x0
sub sp, sp, x0 // sp'' = sp' - x0 = (sp + x0) - x0 = sp
@@ -129,6 +132,21 @@ alternative_else_nop_endif
/* We were already on the overflow stack. Restore sp/x0 and carry on. */
sub sp, sp, x0
mrs x0, tpidrro_el0
+ b el\()\el\()_\label
+
+#ifdef CONFIG_ARM64_ROP_SHIELD
+1: /*
+ * We have to do a little dance here to set bit 55 in the stack
+ * pointer register without clobbering anything else.
+ */
+ orr x0, x0, #(1 << 55)
+ str x1, [x0]
+ mov x1, sp
+ mov sp, x0
+ and x0, x0, #~(1 << 55)
+ sub x0, x1, x0
+ ldr x1, [sp]
+#endif
#endif
b el\()\el\()_\label
.endm
--
2.18.0
next prev parent reply other threads:[~2018-08-02 13:21 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-08-02 13:21 [RFC/PoC PATCH 0/3] arm64: basic ROP mitigation Ard Biesheuvel
2018-08-02 13:21 ` Ard Biesheuvel
2018-08-02 13:21 ` [RFC/PoC PATCH 1/3] arm64: use wrapper macro for bl/blx instructions from asm code Ard Biesheuvel
2018-08-02 13:21 ` Ard Biesheuvel
2018-08-02 13:21 ` [RFC/PoC PATCH 2/3] gcc: plugins: add ROP shield plugin for arm64 Ard Biesheuvel
2018-08-02 13:21 ` Ard Biesheuvel
2018-08-02 13:21 ` Ard Biesheuvel [this message]
2018-08-02 13:21 ` [RFC/PoC PATCH 3/3] arm64: enable ROP protection by clearing SP bit #55 across function returns Ard Biesheuvel
2018-08-06 10:07 ` [RFC/PoC PATCH 0/3] arm64: basic ROP mitigation Florian Weimer
2018-08-06 10:07 ` Florian Weimer
2018-08-06 10:31 ` Ard Biesheuvel
2018-08-06 10:31 ` Ard Biesheuvel
2018-08-06 13:55 ` Robin Murphy
2018-08-06 13:55 ` Robin Murphy
2018-08-06 14:04 ` Ard Biesheuvel
2018-08-06 14:04 ` Ard Biesheuvel
2018-08-06 15:20 ` Ard Biesheuvel
2018-08-06 15:20 ` Ard Biesheuvel
2018-08-06 15:38 ` Robin Murphy
2018-08-06 15:38 ` Robin Murphy
2018-08-06 15:50 ` Ard Biesheuvel
2018-08-06 15:50 ` Ard Biesheuvel
2018-08-06 16:04 ` Ard Biesheuvel
2018-08-06 16:04 ` Ard Biesheuvel
2018-08-06 17:45 ` Robin Murphy
2018-08-06 17:45 ` Robin Murphy
2018-08-06 18:49 ` Kees Cook
2018-08-06 18:49 ` Kees Cook
2018-08-06 19:35 ` Ard Biesheuvel
2018-08-06 19:35 ` Ard Biesheuvel
2018-08-06 19:50 ` Kees Cook
2018-08-06 19:50 ` Kees Cook
2018-08-06 19:54 ` Ard Biesheuvel
2018-08-06 19:54 ` Ard Biesheuvel
2018-08-07 3:05 ` Mark Brand
2018-08-07 9:21 ` Ard Biesheuvel
2018-08-07 9:21 ` Ard Biesheuvel
2018-08-08 16:09 ` Mark Brand
2018-08-08 16:09 ` Mark Brand
2018-08-08 22:02 ` Kees Cook
2018-08-08 22:02 ` Kees Cook
2018-08-13 7:39 ` Ard Biesheuvel
2018-08-18 1:27 ` Laura Abbott
2018-08-18 1:27 ` Laura Abbott
2018-08-20 6:30 ` Ard Biesheuvel
2018-08-20 6:30 ` Ard Biesheuvel
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=20180802132133.23999-4-ard.biesheuvel@linaro.org \
--to=ard.biesheuvel@linaro.org \
--cc=catalin.marinas@arm.com \
--cc=christoffer.dall@arm.com \
--cc=keescook@chromium.org \
--cc=kernel-hardening@lists.openwall.com \
--cc=labbott@fedoraproject.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=mark.rutland@arm.com \
--cc=will.deacon@arm.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.