linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0
@ 2023-07-16 21:50 Mark Brown
  2023-07-16 21:50 ` [PATCH 01/35] prctl: arch-agnostic prctl for shadow stack Mark Brown
                   ` (34 more replies)
  0 siblings, 35 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:50 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

The arm64 Guarded Control Stack (GCS) feature provides support for
hardware protected stacks of return addresses, intended to provide
hardening against return oriented programming (ROP) attacks and to make
it easier to gather call stacks for applications such as profiling.

When GCS is active a secondary stack called the Guarded Control Stack is
maintained, protected with a memory attribute which means that it can
only be written with specific GCS operations.  When a BL is executed the
value stored in LR is also pushed onto the GCS, and when a RET is
executed the top of the GCS is popped and compared to LR with a fault
being raised if the values do not match.  GCS operations may only be
performed on GCS pages, a data abort is generated if they are not.

This series implements support for use of GCS by EL0, along with support
for use of GCS within KVM guests.  It does not enable use of GCS by
either EL1 or EL2.  Executables are started without GCS and must use a
prctl() to enable it, it is expected that this will be done very early
in application execution by the dynamic linker or other startup code.

x86 has an equivalent feature called shadow stacks, this series depends
on the x86 patches for generic memory management support for the new
guarded/shadow stack page type and shares APIs as much as possible.  As
there has been extensive discussion with the wider community around the
ABI for shadow stacks I have as far as practical kept implementation
decisions close to those for x86, anticipating that review would lead to
similar conclusions in the absence of strong reasoning for divergence.

The main divergence I am concious of is that x86 allows shadow stack to
be enabled and disabled repeatedly, freeing the shadow stack for the
thread whenever disabled, while this implementation keeps the GCS
allocated after disable but refuses to reenable it.  This is to avoid
races with things actively walking the GCS during a disable, we do
anticipate that some systems will wish to disable GCS at runtime but are
not aware of any demand for subsequently reenabling it.

x86 uses an arch_prctl() to manage enable and disable, since only x86
and S/390 use arch_prctl() a generic prctl() was proposed[1] as part of a
patch set for the equivalent RISC-V zisslpcfi feature which is adopted
with some enhancements here.

There's a few bits where I'm not convinced with where I've placed
things, in particular the GCS write operation is in the GCS header not
in uaccess.h, I wasn't sure what was clearest there and am probably too
close to the code to have a clear opinion.

The series depends on the x86 shadow stack support:

   https://lore.kernel.org/lkml/20230227222957.24501-1-rick.p.edgecombe@intel.com/

I've rebased this onto v6.5-rc1 but not included it in the series in
order to avoid confusion with Rick's work and cut down the size of the
series, you can see the branch at:

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/misc.git arm64-gcs

[1] https://lore.kernel.org/lkml/20230213045351.3945824-1-debug@rivosinc.com/

Signed-off-by: Mark Brown <broonie@kernel.org>
---
Deepak Gupta (1):
      prctl: arch-agnostic prctl for shadow stack

Mark Brown (34):
      prctl: Add flag for shadow stack writeability and push/pop
      arm64: Document boot requirements for Guarded Control Stacks
      arm64/gcs: Document the ABI for Guarded Control Stacks
      arm64/sysreg: Add new system registers for GCS
      arm64/sysreg: Add definitions for architected GCS caps
      arm64/gcs: Add manual encodings of GCS instructions
      arm64/gcs: Provide copy_to_user_gcs()
      arm64/cpufeature: Runtime detection of Guarded Control Stack (GCS)
      arm64/mm: Allocate PIE slots for EL0 guarded control stack
      mm: Define VM_SHADOW_STACK for arm64 when we support GCS
      arm64/mm: Map pages for guarded control stack
      KVM: arm64: Manage GCS registers for guests
      arm64: Disable traps for GCS usage at EL0 and EL1
      arm64/idreg: Add overrride for GCS
      arm64/hwcap: Add hwcap for GCS
      arm64/traps: Handle GCS exceptions
      arm64/mm: Handle GCS data aborts
      arm64/gcs: Context switch GCS registers for EL0
      arm64/gcs: Allocate a new GCS for threads with GCS enabled
      arm64/gcs: Implement shadow stack prctl() interface
      arm64/mm: Implement map_shadow_stack()
      arm64/signal: Set up and restore the GCS context for signal handlers
      arm64/signal: Expose GCS state in signal frames
      arm64/ptrace: Expose GCS via ptrace and core files
      arm64: Add Kconfig for Guarded Control Stack (GCS)
      kselftest/arm64: Verify the GCS hwcap
      kselftest/arm64: Add GCS as a detected feature in the signal tests
      kselftest/arm64: Add framework support for GCS to signal handling tests
      kselftest/arm64: Allow signals tests to specify an expected si_code
      kselftest/arm64: Always run signals tests with GCS enabled
      kselftest/arm64: Add very basic GCS test program
      kselftest/arm64: Add a GCS test program built with the system libc
      selftests/arm64: Add GCS signal tests
      kselftest/arm64: Enable GCS for the FP stress tests

 Documentation/admin-guide/kernel-parameters.txt    |   3 +
 Documentation/arch/arm64/booting.rst               |  22 ++
 Documentation/arch/arm64/elf_hwcaps.rst            |   3 +
 Documentation/arch/arm64/gcs.rst                   | 216 +++++++++++++
 Documentation/arch/arm64/index.rst                 |   1 +
 Documentation/filesystems/proc.rst                 |   2 +-
 arch/arm64/Kconfig                                 |  19 ++
 arch/arm64/include/asm/cpufeature.h                |   6 +
 arch/arm64/include/asm/el2_setup.h                 |   9 +
 arch/arm64/include/asm/esr.h                       |  26 +-
 arch/arm64/include/asm/exception.h                 |   2 +
 arch/arm64/include/asm/gcs.h                       |  88 ++++++
 arch/arm64/include/asm/hwcap.h                     |   1 +
 arch/arm64/include/asm/kvm_host.h                  |  12 +
 arch/arm64/include/asm/pgtable-prot.h              |  14 +-
 arch/arm64/include/asm/processor.h                 |   6 +
 arch/arm64/include/asm/sysreg.h                    |  20 ++
 arch/arm64/include/asm/uaccess.h                   |  42 +++
 arch/arm64/include/uapi/asm/hwcap.h                |   1 +
 arch/arm64/include/uapi/asm/ptrace.h               |   7 +
 arch/arm64/include/uapi/asm/sigcontext.h           |   9 +
 arch/arm64/kernel/cpufeature.c                     |  23 ++
 arch/arm64/kernel/cpuinfo.c                        |   1 +
 arch/arm64/kernel/entry-common.c                   |  23 ++
 arch/arm64/kernel/idreg-override.c                 |   2 +
 arch/arm64/kernel/process.c                        |  77 +++++
 arch/arm64/kernel/ptrace.c                         |  50 +++
 arch/arm64/kernel/signal.c                         | 240 +++++++++++++-
 arch/arm64/kernel/traps.c                          |  11 +
 arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h         |  17 +
 arch/arm64/kvm/sys_regs.c                          |  22 ++
 arch/arm64/mm/Makefile                             |   1 +
 arch/arm64/mm/fault.c                              |  75 ++++-
 arch/arm64/mm/gcs.c                                | 202 ++++++++++++
 arch/arm64/mm/mmap.c                               |  17 +-
 arch/arm64/tools/cpucaps                           |   1 +
 arch/arm64/tools/sysreg                            |  55 ++++
 fs/proc/task_mmu.c                                 |   3 +
 include/linux/mm.h                                 |  15 +-
 include/linux/syscalls.h                           |   1 +
 include/uapi/asm-generic/unistd.h                  |   5 +-
 include/uapi/linux/elf.h                           |   1 +
 include/uapi/linux/prctl.h                         |  19 ++
 kernel/sys.c                                       |  20 ++
 kernel/sys_ni.c                                    |   1 +
 tools/testing/selftests/arm64/Makefile             |   2 +-
 tools/testing/selftests/arm64/abi/hwcap.c          |  19 ++
 tools/testing/selftests/arm64/fp/assembler.h       |  15 +
 tools/testing/selftests/arm64/fp/fpsimd-test.S     |   2 +
 tools/testing/selftests/arm64/fp/sve-test.S        |   2 +
 tools/testing/selftests/arm64/fp/za-test.S         |   2 +
 tools/testing/selftests/arm64/fp/zt-test.S         |   2 +
 tools/testing/selftests/arm64/gcs/.gitignore       |   2 +
 tools/testing/selftests/arm64/gcs/Makefile         |  19 ++
 tools/testing/selftests/arm64/gcs/basic-gcs.c      | 350 +++++++++++++++++++++
 tools/testing/selftests/arm64/gcs/gcs-util.h       |  65 ++++
 tools/testing/selftests/arm64/gcs/libc-gcs.c       | 217 +++++++++++++
 tools/testing/selftests/arm64/signal/.gitignore    |   1 +
 .../testing/selftests/arm64/signal/test_signals.c  |  17 +-
 .../testing/selftests/arm64/signal/test_signals.h  |   6 +
 .../selftests/arm64/signal/test_signals_utils.c    |  32 +-
 .../selftests/arm64/signal/test_signals_utils.h    |  39 +++
 .../arm64/signal/testcases/gcs_exception_fault.c   |  59 ++++
 .../selftests/arm64/signal/testcases/gcs_frame.c   |  78 +++++
 .../arm64/signal/testcases/gcs_write_fault.c       |  67 ++++
 .../selftests/arm64/signal/testcases/testcases.c   |   7 +
 .../selftests/arm64/signal/testcases/testcases.h   |   1 +
 67 files changed, 2363 insertions(+), 32 deletions(-)
---
base-commit: 023ee2d672f3d7c2d15acf62bcfc4bc49c3677e5
change-id: 20230303-arm64-gcs-e311ab0d8729

Best regards,
-- 
Mark Brown <broonie@kernel.org>


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH 01/35] prctl: arch-agnostic prctl for shadow stack
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
@ 2023-07-16 21:50 ` Mark Brown
  2023-07-18 17:45   ` Edgecombe, Rick P
  2023-07-16 21:50 ` [PATCH 02/35] prctl: Add flag for shadow stack writeability and push/pop Mark Brown
                   ` (33 subsequent siblings)
  34 siblings, 1 reply; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:50 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

From: Deepak Gupta <debug@rivosinc.com>

Three architectures (x86, aarch64, riscv) have announced support for
shadow stack.  This patch adds arch-agnostic prtcl support to enable
/disable/get/set status of shadow stack and forward control (landing pad)
flow cfi statuses.

New prctls are
      - PR_GET_SHADOW_STACK_STATUS, PR_SET_SHADOW_STACK_STATUS

Signed-off-by: Deepak Gupta <debug@rivosinc.com>
[Rebased onto current kernels, renumbering to track other allocations
 already upstream, dropping indirect LP, updating to pass arg to set
  by value, fix missing prototypes for weak functions and update title.
  -- broonie]
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 include/linux/mm.h         |  3 +++
 include/uapi/linux/prctl.h | 17 +++++++++++++++++
 kernel/sys.c               | 20 ++++++++++++++++++++
 3 files changed, 40 insertions(+)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 97eddc83d19c..bf16edf2fcd9 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -3947,4 +3947,7 @@ static inline void accept_memory(phys_addr_t start, phys_addr_t end)
 
 #endif
 
+int arch_get_shadow_stack_status(struct task_struct *t, unsigned long __user *status);
+int arch_set_shadow_stack_status(struct task_struct *t, unsigned long status);
+
 #endif /* _LINUX_MM_H */
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 3c36aeade991..9fdc77fa2bfe 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -305,4 +305,21 @@ struct prctl_mm_map {
 # define PR_RISCV_V_VSTATE_CTRL_NEXT_MASK	0xc
 # define PR_RISCV_V_VSTATE_CTRL_MASK		0x1f
 
+/*
+ * get shadow stack status for current thread. Assumes shadow stack is min 4 byte aligned.
+ * Note shadow stack can be 8 byte aligned on 64bit.
+ * Lower 2 bits can give status of locked and enabled/disabled.
+ * size and address range can be obtained via /proc/maps. get_shadow_stack_status will
+ * return base of shadow stack.
+ */
+#define PR_GET_SHADOW_STACK_STATUS      71
+/*
+ * set shadow stack status for current thread (including enabling, disabling or locking)
+ * note that it will only set the status and setup of the shadow stack. Allocating shadow
+ * stack should be done separately using mmap.
+ */
+#define PR_SET_SHADOW_STACK_STATUS      72
+# define PR_SHADOW_STACK_LOCK           (1UL << 0)
+# define PR_SHADOW_STACK_ENABLE         (1UL << 1)
+
 #endif /* _LINUX_PRCTL_H */
diff --git a/kernel/sys.c b/kernel/sys.c
index 05f838929e72..ebf9ea5f0fae 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2302,6 +2302,16 @@ int __weak arch_prctl_spec_ctrl_set(struct task_struct *t, unsigned long which,
 	return -EINVAL;
 }
 
+int __weak arch_get_shadow_stack_status(struct task_struct *t, unsigned long __user *status)
+{
+	return -EINVAL;
+}
+
+int __weak arch_set_shadow_stack_status(struct task_struct *t, unsigned long status)
+{
+	return -EINVAL;
+}
+
 #define PR_IO_FLUSHER (PF_MEMALLOC_NOIO | PF_LOCAL_THROTTLE)
 
 #ifdef CONFIG_ANON_VMA_NAME
@@ -2720,6 +2730,16 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
 	case PR_RISCV_V_GET_CONTROL:
 		error = RISCV_V_GET_CONTROL();
 		break;
+	case PR_GET_SHADOW_STACK_STATUS:
+		if (arg3 || arg4 || arg5)
+			return -EINVAL;
+		error = arch_get_shadow_stack_status(me, (unsigned long __user *) arg2);
+		break;
+	case PR_SET_SHADOW_STACK_STATUS:
+		if (arg3 || arg4 || arg5)
+			return -EINVAL;
+		error = arch_set_shadow_stack_status(me, arg2);
+		break;
 	default:
 		error = -EINVAL;
 		break;

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 02/35] prctl: Add flag for shadow stack writeability and push/pop
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
  2023-07-16 21:50 ` [PATCH 01/35] prctl: arch-agnostic prctl for shadow stack Mark Brown
@ 2023-07-16 21:50 ` Mark Brown
  2023-07-18 17:47   ` Edgecombe, Rick P
  2023-07-16 21:50 ` [PATCH 03/35] arm64: Document boot requirements for Guarded Control Stacks Mark Brown
                   ` (32 subsequent siblings)
  34 siblings, 1 reply; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:50 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

On arm64 and x86 the kernel can control if there is write access to the
shadow stack via specific instructions defined for the purpose, useful
for things like userspace threading at the expense of some security.
Add a flag to allow this to be selected when changing the shadow stack
status.

On arm64 the kernel can separately control if userspace is able to pop
and push values directly onto the shadow stack via GCS push and pop
instructions, supporting many scenarios where userspace needs to write
to the stack with less security exposure than full write access.  Add a
flag to allow this to be selected when changing the shadow stack status.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 include/uapi/linux/prctl.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 9fdc77fa2bfe..e88d2ddcdb2d 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -321,5 +321,7 @@ struct prctl_mm_map {
 #define PR_SET_SHADOW_STACK_STATUS      72
 # define PR_SHADOW_STACK_LOCK           (1UL << 0)
 # define PR_SHADOW_STACK_ENABLE         (1UL << 1)
+# define PR_SHADOW_STACK_WRITE		(1UL << 2)
+# define PR_SHADOW_STACK_PUSH		(1UL << 3)
 
 #endif /* _LINUX_PRCTL_H */

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 03/35] arm64: Document boot requirements for Guarded Control Stacks
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
  2023-07-16 21:50 ` [PATCH 01/35] prctl: arch-agnostic prctl for shadow stack Mark Brown
  2023-07-16 21:50 ` [PATCH 02/35] prctl: Add flag for shadow stack writeability and push/pop Mark Brown
@ 2023-07-16 21:50 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 04/35] arm64/gcs: Document the ABI " Mark Brown
                   ` (31 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:50 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

FEAT_GCS introduces a number of new system registers, we require that
access to these registers is not trapped when we identify that the feature
is detected.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 Documentation/arch/arm64/booting.rst | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/Documentation/arch/arm64/booting.rst b/Documentation/arch/arm64/booting.rst
index b57776a68f15..de3679770c64 100644
--- a/Documentation/arch/arm64/booting.rst
+++ b/Documentation/arch/arm64/booting.rst
@@ -411,6 +411,28 @@ Before jumping into the kernel, the following conditions must be met:
 
     - HFGRWR_EL2.nPIRE0_EL1 (bit 57) must be initialised to 0b1.
 
+ - For features with Guarded Control Stacks (FEAT_GCS):
+
+  - If EL3 is present:
+
+    - SCR_EL3.GCSEn (bit 39) must be initialised to 0b1.
+
+ - If the kernel is entered at EL1 and EL2 is present:
+
+    - HFGITR_EL2.nGCSEPP (bit 59) must be initialised to 0b1.
+
+    - HFGITR_EL2.nGCSSTR_EL1 (bit 58) must be initialised to 0b1.
+
+    - HFGITR_EL2.nGCSPUSHM_EL1 (bit 57) must be initialised to 0b1.
+
+    - HFGRTR_EL2.nGCS_EL1 (bit 53) must be initialised to 0b1.
+
+    - HFGRTR_EL2.nGCS_EL0 (bit 52) must be initialised to 0b1.
+
+    - HFGWTR_EL2.nGCS_EL1 (bit 53) must be initialised to 0b1.
+
+    - HFGWTR_EL2.nGCS_EL0 (bit 52) must be initialised to 0b1.
+
 The requirements described above for CPU mode, caches, MMUs, architected
 timers, coherency and system registers apply to all CPUs.  All CPUs must
 enter the kernel in the same exception level.  Where the values documented

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 04/35] arm64/gcs: Document the ABI for Guarded Control Stacks
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (2 preceding siblings ...)
  2023-07-16 21:50 ` [PATCH 03/35] arm64: Document boot requirements for Guarded Control Stacks Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-17 11:42   ` Jonathan Cameron
  2023-07-19 11:44   ` Mike Rapoport
  2023-07-16 21:51 ` [PATCH 05/35] arm64/sysreg: Add new system registers for GCS Mark Brown
                   ` (30 subsequent siblings)
  34 siblings, 2 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Add some documentation of the userspace ABI for Guarded Control Stacks.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 Documentation/arch/arm64/gcs.rst   | 216 +++++++++++++++++++++++++++++++++++++
 Documentation/arch/arm64/index.rst |   1 +
 2 files changed, 217 insertions(+)

diff --git a/Documentation/arch/arm64/gcs.rst b/Documentation/arch/arm64/gcs.rst
new file mode 100644
index 000000000000..27ba72d27952
--- /dev/null
+++ b/Documentation/arch/arm64/gcs.rst
@@ -0,0 +1,216 @@
+===============================================
+Guarded Control Stack support for AArch64 Linux
+===============================================
+
+This document outlines briefly the interface provided to userspace by Linux in
+order to support use of the ARM Guarded Control Stack (GCS) feature.
+
+This is an outline of the most important features and issues only and not
+intended to be exhaustive.
+
+
+
+1.  General
+-----------
+
+* GCS is an architecture feature intended to provide greater protection
+  against return oriented programming (ROP) attacks and to simplify the
+  implementation of features that need to collect stack traces such as
+  profiling.
+
+* When GCS is enabled a separate guarded control stack is maintained by the
+  PE which is writeable only through specific GCS operations.  This
+  stores the call stack only, when a procedure call instruction is
+  performed the current PC is pushed onto the GCS and on RET the
+  address in the LR is verified against that on the top of the GCS.
+
+* When active current GCS pointer is stored in the system register
+  GCSPR_EL0.  This is readable by userspace but can only be updated
+  via specific GCS instructions.
+
+* The architecture provides instructions for switching between guarded
+  control stacks with checks to ensure that the new stack is a valid
+  target for switching.
+
+* The functionality of GCS is similar to that provided by the x86 Shadow
+  Stack feature, due to sharing of userspace interfaces the ABI refers to
+  shadow stacks rather than GCS.
+
+* Support for GCS is reported to userspace via HWCAP2_GCS in the aux vector
+  AT_HWCAP2 entry.
+
+* GCS is enabled per thread.  While there is support for disabling GCS
+  at runtime this should be done with great care.
+
+* GCS memory access faults are reported as normal memory access faults.
+
+* GCS specific errors (those reported with EC 0x2d) will be reported as
+  SIGSEGV with a si_code of SEGV_CPERR (control protection error).
+
+* GCS is supported only for AArch64.
+
+* On systems where GCS is supported GCSPR_EL0 is always readable by EL0
+  regardless of the GCS configuration for the thread.
+
+* The architecture supports enabling GCS without verifying that return values
+  in LR match those in the GCS, the LR will be ignored.  This is not supported
+  by Linux.
+
+* EL0 GCS entries with bit 63 set are reserved for use, one such use is defined
+  below for signals and should be ignored when parsing the stack if not
+  understood.
+
+
+2.  Enabling and disabling Guarded Control Stacks
+-------------------------------------------------
+
+* GCS is enabled and disabled for a thread via the PR_SET_SHADOW_STACK_STATUS
+  prctl(), this takes a single flags argument specifying which GCS features
+  should be used.
+
+* When set PR_SHADOW_STACK_ENABLE flag allocates a Guarded Control Stack for
+  and enables GCS for the thread, enabling the functionality controlled by
+  GCSPRE0_EL1.{nTR, RVCHKEN, PCRSEL}.
+
+* When set the PR_SHADOW_STACK_PUSH flag enables the functionality controlled
+  by GCSCRE0_EL1.PUSHMEn, allowing explicit GCS push and pops.
+
+* When set the PR_SHADOW_STACK_WRITE flag enables the functionality controlled
+  by GCSCRE0_EL1.STREn, allowing explicit stores to the Guarded Control Stack.
+
+* When set the PR_SHADOW_STACK_LOCK flag prevents any further configuration of
+  the GCS settings for the thread, further attempts to configure GCS will
+  return -EBUSY.
+
+* Any unknown flags will cause PR_SET_SHADOW_STACK_STATUS to return -EINVAL.
+
+* PR_SET_SHADOW_STACK_STATUS affects only the thread the called it, any
+  other running threads will be unaffected.
+
+* New threads inherit the GCS configuration of the thread that created them.
+
+* GCS is disabled on exec().
+
+* The current GCS configuration for a thread may be read with the
+  PR_GET_SHADOW_STACK_STATUS prctl(), this returns the same flags that
+  are passed to PR_SET_SHADOW_STACK_STATUS.
+
+* If GCS is disabled for a thread after having previously been enabled then
+  the stack will remain allocated for the lifetime of the thread.  At present
+  any attempt to reenable GCS for the thread will be rejected, this may be
+  revisited in future.
+
+* It should be noted that since enabling GCS will result in GCS becoming
+  active immediately it is not normally possible to return from the function
+  that invoked the prctl() that enabled GCS.  It is expected that the normal
+  usage will be that GCS is enabled very early in execution of a program.
+
+
+
+3.  Allocation of Guarded Control Stacks
+----------------------------------------
+
+* When GCS is enabled for a thread a new Guarded Control Stack will be
+  allocated for it of size RLIMIT_STACK / 2 or 2 gigabytes, whichever is
+  smaller.
+
+* When a new thread is created by a thread which has GCS enabled then a
+  new Guarded Control Stack will be allocated for the new thread with
+  half the size of the standard stack.
+
+* When a stack is allocated by enabling GCS or during thread creation then
+  the top 8 bytes of the stack will be initialised to 0 and GCSPR_EL0 will
+  be set to point to the address of this 0 value, this can be used to
+  detect the top of the stack.
+
+* Additional Guarded Control Stacks can be allocated using the
+  map_shadow_stack() system call.
+
+* Stacks allocated using map_shadow_stack() will have the top 8 bytes
+  set to 0 and the 8 bytes below that initialised with an architecturally
+  valid GCS cap value, this allows switching to these stacks using the
+  stack switch instructions provided by the architecture.
+
+* When GCS is disabled for a thread the Guarded Control Stack initially
+  allocated for that thread will be freed.  Note carefully that if the
+  stack has been switched this may not be the stack currently in use by
+  the thread.
+
+
+4.  Signal handling
+--------------------
+
+* A new signal frame record gcs_context encodes the current GCS mode and
+  pointer for the interrupted context on signal delivery.  This will always
+  be present on systems that support GCS.
+
+* The record contains a flag field which reports the current GCS configuration
+  for the interrupted context as PR_GET_SHADOW_STACK_STATUS would.
+
+* The signal handler is run with the same GCS configuration as the interrupted
+  context.
+
+* When GCS is enabled for the interrupted thread a signal handling specific
+  GCS cap token will be written to the GCS, this is an architectural GCS cap
+  token with bit 63 set.  The GCSPR_EL0 reported in the signal frame will
+  point to this cap token.
+
+* The signal handler will use the same GCS as the interrupted context.
+
+* When GCS is enabled on signal entry a frame with the address of the signal
+  return handler will be pushed onto the GCS, allowing return from the signal
+  handler via RET as normal.  This will not be reported in the gcs_context in
+  the signal frame.
+
+
+5.  Signal return
+-----------------
+
+When returning from a signal handler:
+
+* If there is a gcs_context record in the signal frame then the GCS flags
+  and GCSPR_EL0 will be restored from that context prior to further
+  validation.
+
+* If there is no gcs_context record in the signal frame then the GCS
+  configuration will be unchanged.
+
+* If GCS is enabled on return from a signal handler then GCSPR_EL0 must
+  point to a valid GCS signal cap record, this will be popped from the
+  GCS prior to signal return.
+
+* If the GCS configuration is locked when returning from a signal then any
+  attempt to change the GCS configuration will be treated as an error.  This
+  is true even if GCS was not enabled prior to signal entry.
+
+* GCS may be disabled via signal return but any attempt to enable GCS via
+  signal return will be rejected.
+
+
+7.  ptrace extensions
+---------------------
+
+* A new regset NT_ARM_GCS is defined for use with PTRACE_GETREGSET and
+  PTRACE_SETREGSET.
+
+* Due to the complexity surrounding allocation and deallocation of stakcs and
+  lack of practical application changes to the GCS configuration via ptrace
+  are not supported.
+
+
+
+8.  ELF coredump extensions
+---------------------------
+
+* NT_ARM_GCS notes will be added to each coredump for each thread of the
+  dumped process.  The contents will be equivalent to the data that would
+  have been read if a PTRACE_GETREGSET of the corresponding type were
+  executed for each thread when the coredump was generated.
+
+
+
+9.  /proc extensions
+--------------------
+
+* Guarded Control Stack pages will include "ss" in their VmFlags in
+  /proc/<pid>/smaps.
diff --git a/Documentation/arch/arm64/index.rst b/Documentation/arch/arm64/index.rst
index d08e924204bf..dcf3ee3eb8c0 100644
--- a/Documentation/arch/arm64/index.rst
+++ b/Documentation/arch/arm64/index.rst
@@ -14,6 +14,7 @@ ARM64 Architecture
     booting
     cpu-feature-registers
     elf_hwcaps
+    gcs
     hugetlbpage
     kdump
     legacy_instructions

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 05/35] arm64/sysreg: Add new system registers for GCS
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (3 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 04/35] arm64/gcs: Document the ABI " Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 06/35] arm64/sysreg: Add definitions for architected GCS caps Mark Brown
                   ` (29 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

FEAT_GCS introduces a number of new system registers. Add the registers
available up to EL2 to sysreg as per DDI0601 2022-12.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/tools/sysreg | 55 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 1ea4a3dc68f8..516aef38eab7 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -1780,6 +1780,41 @@ Sysreg	SMCR_EL1	3	0	1	2	6
 Fields	SMCR_ELx
 EndSysreg
 
+SysregFields	GCSCR_ELx
+Res0	63:10
+Field	9	STREn
+Field	8	PUSHMEn
+Res0	7
+Field	6	EXLOCKEN
+Field	5	RVCHKEN
+Res0	4:1
+Field	0	PCRSEL
+EndSysregFields
+
+Sysreg	GCSCR_EL1	3	0	2	5	0
+Fields	GCSCR_ELx
+EndSysreg
+
+SysregFields	GCSPR_ELx
+Field	63:3	PTR
+Res0	2:0
+EndSysregFields
+
+Sysreg	GCSPR_EL1	3	0	2	5	1
+Fields	GCSPR_ELx
+EndSysreg
+
+Sysreg	GCSCRE0_EL1	3	0	2	5	2
+Res0	63:11
+Field	10	nTR
+Field	9	STREn
+Field	8	PUSHMEn
+Res0	7:6
+Field	5	RVCHKEN
+Res0	4:1
+Field	0	PCRSEL
+EndSysreg
+
 Sysreg	ALLINT	3	0	4	3	0
 Res0	63:14
 Field	13	ALLINT
@@ -2010,6 +2045,10 @@ Field	4	DZP
 Field	3:0	BS
 EndSysreg
 
+Sysreg	GCSPR_EL0	3	3	2	5	1
+Fields	GCSPR_ELx
+EndSysreg
+
 Sysreg	SVCR	3	3	4	2	2
 Res0	63:2
 Field	1	ZA
@@ -2209,6 +2248,14 @@ Sysreg	SMCR_EL2	3	4	1	2	6
 Fields	SMCR_ELx
 EndSysreg
 
+Sysreg	GCSCR_EL2	3	4	2	5	0
+Fields	GCSCR_ELx
+EndSysreg
+
+Sysreg	GCSPR_EL2	3	4	2	5	1
+Fields	GCSPR_ELx
+EndSysreg
+
 Sysreg	DACR32_EL2	3	4	3	0	0
 Res0	63:32
 Field	31:30	D15
@@ -2268,6 +2315,14 @@ Sysreg	SMCR_EL12	3	5	1	2	6
 Fields	SMCR_ELx
 EndSysreg
 
+Sysreg	GCSCR_EL12	3	5	2	5	0
+Fields	GCSCR_ELx
+EndSysreg
+
+Sysreg	GCSPR_EL12	3	5	2	5	1
+Fields	GCSPR_ELx
+EndSysreg
+
 Sysreg	FAR_EL12	3	5	6	0	0
 Field	63:0	ADDR
 EndSysreg

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 06/35] arm64/sysreg: Add definitions for architected GCS caps
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (4 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 05/35] arm64/sysreg: Add new system registers for GCS Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 07/35] arm64/gcs: Add manual encodings of GCS instructions Mark Brown
                   ` (28 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

The architecture defines a format for guarded control stack caps, used
to mark the top of an unused GCS in order to limit the potential for
exploitation via stack switching. Add definitions associated with these.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/asm/sysreg.h | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index b481935e9314..3d7f9b25b8fb 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -730,6 +730,26 @@
 
 #define PIRx_ELx_PERM(idx, perm)	((perm) << ((idx) * 4))
 
+/*
+ * Definitions for Guarded Control Stack
+ */
+
+#define GCS_CAP_ADDR_MASK		GENMASK(63, 12)
+#define GCS_CAP_ADDR_SHIFT		12
+#define GCS_CAP_ADDR_WIDTH		52
+#define GCS_CAP_ADDR(x)			FIELD_GET(GCS_CAP_ADDR_MASK, x)
+
+#define GCS_CAP_TOKEN_MASK		GENMASK(11, 0)
+#define GCS_CAP_TOKEN_SHIFT		0
+#define GCS_CAP_TOKEN_WIDTH		12
+#define GCS_CAP_TOKEN(x)		FIELD_GET(GCS_CAP_TOKEN_MASK, x)
+
+#define GCS_CAP_VALID_TOKEN		0x1
+#define GCS_CAP_IN_PROGRESS_TOKEN	0x5
+
+#define GCS_CAP(x)	((((unsigned long)x) & GCS_CAP_ADDR_MASK) | \
+					       GCS_CAP_VALID_TOKEN)
+
 #define ARM64_FEATURE_FIELD_BITS	4
 
 /* Defined for compatibility only, do not add new users. */

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 07/35] arm64/gcs: Add manual encodings of GCS instructions
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (5 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 06/35] arm64/sysreg: Add definitions for architected GCS caps Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 08/35] arm64/gcs: Provide copy_to_user_gcs() Mark Brown
                   ` (27 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Define C callable functions for GCS instructions used by the kernel. In
order to avoid ambitious toolchain requirements for GCS support these are
manually encoded, this means we have fixed register numbers which will be
a bit limiting for the compiler but none of these should be used in
sufficiently fast paths for this to be a problem.

Note that GCSSTTR is used to store to EL0.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/asm/gcs.h     | 51 ++++++++++++++++++++++++++++++++++++++++
 arch/arm64/include/asm/uaccess.h | 22 +++++++++++++++++
 2 files changed, 73 insertions(+)

diff --git a/arch/arm64/include/asm/gcs.h b/arch/arm64/include/asm/gcs.h
new file mode 100644
index 000000000000..7c5e95218db6
--- /dev/null
+++ b/arch/arm64/include/asm/gcs.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+#ifndef __ASM_GCS_H
+#define __ASM_GCS_H
+
+#include <asm/types.h>
+#include <asm/uaccess.h>
+
+static inline void gcsb_dsync(void)
+{
+	asm volatile(".inst 0xd503227f" : : : "memory");
+}
+
+static inline void gcsstr(u64 *addr, u64 val)
+{
+	register u64 *_addr __asm__ ("x0") = addr;
+	register long _val __asm__ ("x1") = val;
+
+	/* GCSSTTR x1, x0 */
+	asm volatile(
+		".inst 0xd91f1c01\n"
+		:
+		: "rZ" (_val), "r" (_addr)
+		: "memory");
+}
+
+static inline void gcsss1(u64 Xt)
+{
+	asm volatile (
+		"sys #3, C7, C7, #2, %0\n"
+		:
+		: "rZ" (Xt)
+		: "memory");
+}
+
+static inline u64 gcsss2(void)
+{
+	u64 Xt;
+
+	asm volatile(
+		"SYSL %0, #3, C7, C7, #3\n"
+		: "=r" (Xt)
+		:
+		: "memory");
+
+	return Xt;
+}
+
+#endif
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 14be5000c5a0..22e10e79f56a 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -425,4 +425,26 @@ static inline size_t probe_subpage_writeable(const char __user *uaddr,
 
 #endif /* CONFIG_ARCH_HAS_SUBPAGE_FAULTS */
 
+#ifdef CONFIG_ARM64_GCS
+
+static inline int gcssttr(unsigned long __user *addr, unsigned long val)
+{
+	register unsigned long __user *_addr __asm__ ("x0") = addr;
+	register unsigned long _val __asm__ ("x1") = val;
+	int err = 0;
+
+	/* GCSSTTR x1, x0 */
+	asm volatile(
+		"1: .inst 0xd91f1c01\n"
+		"2: \n"
+		_ASM_EXTABLE_UACCESS_ERR(1b, 2b, %w0)
+		: "+r" (err)
+		: "rZ" (_val), "r" (_addr)
+		: "memory");
+
+	return err;
+}
+
+#endif /* CONFIG_ARM64_GCS */
+
 #endif /* __ASM_UACCESS_H */

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 08/35] arm64/gcs: Provide copy_to_user_gcs()
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (6 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 07/35] arm64/gcs: Add manual encodings of GCS instructions Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 09/35] arm64/cpufeature: Runtime detection of Guarded Control Stack (GCS) Mark Brown
                   ` (26 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

In order for EL1 to write to an EL0 GCS it must use the GCSSTTR instruction
rather than a normal STTR. Provide a copy_to_user_gcs() which does this.
Since it is not possible to store anything other than a 64 bit value the
interface is presented in terms of 64 bit values, using unsigned long
rather than u64 due to sparse.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/asm/uaccess.h | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 22e10e79f56a..24aa804e95a7 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -445,6 +445,26 @@ static inline int gcssttr(unsigned long __user *addr, unsigned long val)
 	return err;
 }
 
+static inline int copy_to_user_gcs(unsigned long __user *addr,
+				   unsigned long *val,
+				   int count)
+{
+	int ret = -EFAULT;
+	int i;
+
+	if (access_ok((char __user *)addr, count * sizeof(u64))) {
+		uaccess_ttbr0_enable();
+		for (i = 0; i < count; i++) {
+			ret = gcssttr(addr++, *val++);
+			if (ret != 0)
+				break;
+		}
+		uaccess_ttbr0_disable();
+	}
+
+	return ret;
+}
+
 #endif /* CONFIG_ARM64_GCS */
 
 #endif /* __ASM_UACCESS_H */

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 09/35] arm64/cpufeature: Runtime detection of Guarded Control Stack (GCS)
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (7 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 08/35] arm64/gcs: Provide copy_to_user_gcs() Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 10/35] arm64/mm: Allocate PIE slots for EL0 guarded control stack Mark Brown
                   ` (25 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Add a cpufeature for GCS, allowing other code to conditionally support it
at runtime.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/asm/cpufeature.h |  6 ++++++
 arch/arm64/kernel/cpufeature.c      | 20 ++++++++++++++++++++
 arch/arm64/tools/cpucaps            |  1 +
 3 files changed, 27 insertions(+)

diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 96e50227f940..189783142a96 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -831,6 +831,12 @@ static inline bool system_supports_tlb_range(void)
 		cpus_have_const_cap(ARM64_HAS_TLB_RANGE);
 }
 
+static inline bool system_supports_gcs(void)
+{
+	return IS_ENABLED(CONFIG_ARM64_GCS) &&
+		cpus_have_const_cap(ARM64_HAS_GCS);
+}
+
 int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
 bool try_emulate_mrs(struct pt_regs *regs, u32 isn);
 
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index f9d456fe132d..92e730027d84 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -254,6 +254,8 @@ static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
 };
 
 static const struct arm64_ftr_bits ftr_id_aa64pfr1[] = {
+	ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_GCS),
+		       FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_EL1_GCS_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
 		       FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_EL1_SME_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_EL1_MPAM_frac_SHIFT, 4, 0),
@@ -2219,6 +2221,12 @@ static void cpu_enable_mops(const struct arm64_cpu_capabilities *__unused)
 	sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_MSCEn);
 }
 
+static void cpu_enable_gcs(const struct arm64_cpu_capabilities *__unused)
+{
+	/* GCS is not currently used at EL1 */
+	write_sysreg_s(0, SYS_GCSCR_EL1);
+}
+
 /* Internal helper functions to match cpu capability type */
 static bool
 cpucap_late_cpu_optional(const struct arm64_cpu_capabilities *cap)
@@ -2715,6 +2723,18 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		.min_field_value = ID_AA64MMFR2_EL1_EVT_IMP,
 		.matches = has_cpuid_feature,
 	},
+	{
+		.desc = "Guarded Control Stack (GCS)",
+		.capability = ARM64_HAS_GCS,
+		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.sys_reg = SYS_ID_AA64PFR1_EL1,
+		.sign = FTR_UNSIGNED,
+		.field_pos = ID_AA64PFR1_EL1_GCS_SHIFT,
+		.field_width = 4,
+		.min_field_value = ID_AA64PFR1_EL1_GCS_IMP,
+		.matches = has_cpuid_feature,
+		.cpu_enable = cpu_enable_gcs,
+	},
 	{},
 };
 
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index c80ed4f3cbce..ab582f592131 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -26,6 +26,7 @@ HAS_ECV
 HAS_ECV_CNTPOFF
 HAS_EPAN
 HAS_EVT
+HAS_GCS
 HAS_GENERIC_AUTH
 HAS_GENERIC_AUTH_ARCH_QARMA3
 HAS_GENERIC_AUTH_ARCH_QARMA5

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 10/35] arm64/mm: Allocate PIE slots for EL0 guarded control stack
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (8 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 09/35] arm64/cpufeature: Runtime detection of Guarded Control Stack (GCS) Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 11/35] mm: Define VM_SHADOW_STACK for arm64 when we support GCS Mark Brown
                   ` (24 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Pages used for guarded control stacks need to be described to the hardware
using the Permission Indirection Extension, GCS is not supported without
PIE. In order to support copy on write for guarded stacks we allocate two
values, one for active GCSs and one for GCS pages marked as read only prior
to copy.

Since the actual effect is defined using PIE the specific bit pattern used
does not matter to the hardware but we choose two values which differ only
in PTE_WRITE in order to help share code with non-PIE cases.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/asm/pgtable-prot.h | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
index eed814b00a38..b157ae0420ed 100644
--- a/arch/arm64/include/asm/pgtable-prot.h
+++ b/arch/arm64/include/asm/pgtable-prot.h
@@ -131,15 +131,23 @@ extern bool arm64_use_ng_mappings;
 /* 6:                                PTE_PXN | PTE_WRITE            */
 /* 7: PAGE_SHARED_EXEC               PTE_PXN | PTE_WRITE | PTE_USER */
 /* 8: PAGE_KERNEL_ROX      PTE_UXN                                  */
-/* 9:                      PTE_UXN |                       PTE_USER */
+/* 9: PAGE_GCS_RO          PTE_UXN |                       PTE_USER */
 /* a: PAGE_KERNEL_EXEC     PTE_UXN |           PTE_WRITE            */
-/* b:                      PTE_UXN |           PTE_WRITE | PTE_USER */
+/* b: PAGE_GCS             PTE_UXN |           PTE_WRITE | PTE_USER */
 /* c: PAGE_KERNEL_RO       PTE_UXN | PTE_PXN                        */
 /* d: PAGE_READONLY        PTE_UXN | PTE_PXN |             PTE_USER */
 /* e: PAGE_KERNEL          PTE_UXN | PTE_PXN | PTE_WRITE            */
 /* f: PAGE_SHARED          PTE_UXN | PTE_PXN | PTE_WRITE | PTE_USER */
 
+#define _PAGE_GCS	(_PAGE_DEFAULT | PTE_UXN | PTE_WRITE | PTE_USER)
+#define _PAGE_GCS_RO	(_PAGE_DEFAULT | PTE_UXN | PTE_USER)
+
+#define PAGE_GCS	__pgprot(_PAGE_GCS)
+#define PAGE_GCS_RO	__pgprot(_PAGE_GCS_RO)
+
 #define PIE_E0	( \
+	PIRx_ELx_PERM(pte_pi_index(_PAGE_GCS),           PIE_GCS)  | \
+	PIRx_ELx_PERM(pte_pi_index(_PAGE_GCS_RO),        PIE_R)   | \
 	PIRx_ELx_PERM(pte_pi_index(_PAGE_EXECONLY),      PIE_X_O) | \
 	PIRx_ELx_PERM(pte_pi_index(_PAGE_READONLY_EXEC), PIE_RX)  | \
 	PIRx_ELx_PERM(pte_pi_index(_PAGE_SHARED_EXEC),   PIE_RWX) | \
@@ -147,6 +155,8 @@ extern bool arm64_use_ng_mappings;
 	PIRx_ELx_PERM(pte_pi_index(_PAGE_SHARED),        PIE_RW))
 
 #define PIE_E1	( \
+	PIRx_ELx_PERM(pte_pi_index(_PAGE_GCS),           PIE_RW)      | \
+	PIRx_ELx_PERM(pte_pi_index(_PAGE_GCS_RO),        PIE_R)      | \
 	PIRx_ELx_PERM(pte_pi_index(_PAGE_EXECONLY),      PIE_NONE_O) | \
 	PIRx_ELx_PERM(pte_pi_index(_PAGE_READONLY_EXEC), PIE_R)      | \
 	PIRx_ELx_PERM(pte_pi_index(_PAGE_SHARED_EXEC),   PIE_RW)     | \

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 11/35] mm: Define VM_SHADOW_STACK for arm64 when we support GCS
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (9 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 10/35] arm64/mm: Allocate PIE slots for EL0 guarded control stack Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 12/35] arm64/mm: Map pages for guarded control stack Mark Brown
                   ` (23 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Use VM_HIGH_ARCH_5 for guarded control stack pages.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 Documentation/filesystems/proc.rst |  2 +-
 fs/proc/task_mmu.c                 |  3 +++
 include/linux/mm.h                 | 12 +++++++++++-
 3 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst
index 6ccb57089a06..086a0408a4d7 100644
--- a/Documentation/filesystems/proc.rst
+++ b/Documentation/filesystems/proc.rst
@@ -566,7 +566,7 @@ encoded manner. The codes are the following:
     mt    arm64 MTE allocation tags are enabled
     um    userfaultfd missing tracking
     uw    userfaultfd wr-protect tracking
-    ss    shadow stack page
+    ss    shadow/guarded control stack page
     ==    =======================================
 
 Note that there is no guarantee that every flag and associated mnemonic will
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index cfab855fe7e9..e8c50848bb16 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -711,6 +711,9 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
 #endif /* CONFIG_HAVE_ARCH_USERFAULTFD_MINOR */
 #ifdef CONFIG_X86_USER_SHADOW_STACK
 		[ilog2(VM_SHADOW_STACK)] = "ss",
+#endif
+#ifdef CONFIG_ARM64_GCS
+		[ilog2(VM_SHADOW_STACK)] = "ss",
 #endif
 	};
 	size_t i;
diff --git a/include/linux/mm.h b/include/linux/mm.h
index bf16edf2fcd9..f526032c4dc6 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -372,7 +372,17 @@ extern unsigned int kobjsize(const void *objp);
  * having a PAGE_SIZE guard gap.
  */
 # define VM_SHADOW_STACK	VM_HIGH_ARCH_5
-#else
+#endif
+
+#if defined(CONFIG_ARM64_GCS)
+/*
+ * arm64's Guarded Control Stack implements similar functionality and
+ * has similar constraints to shadow stacks.
+ */
+# define VM_SHADOW_STACK	VM_HIGH_ARCH_5
+#endif
+
+#ifndef VM_SHADOW_STACK
 # define VM_SHADOW_STACK	VM_NONE
 #endif
 

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 12/35] arm64/mm: Map pages for guarded control stack
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (10 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 11/35] mm: Define VM_SHADOW_STACK for arm64 when we support GCS Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 13/35] KVM: arm64: Manage GCS registers for guests Mark Brown
                   ` (22 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Map pages flagged as being part of a GCS as such rather than using the
full set of generic VM flags.

This is done using a conditional rather than extending the size of
protection_map since that would make for a very sparse array.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/mm/mmap.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c
index 8f5b7ce857ed..e2ca770920ed 100644
--- a/arch/arm64/mm/mmap.c
+++ b/arch/arm64/mm/mmap.c
@@ -79,8 +79,23 @@ arch_initcall(adjust_protection_map);
 
 pgprot_t vm_get_page_prot(unsigned long vm_flags)
 {
-	pteval_t prot = pgprot_val(protection_map[vm_flags &
+	pteval_t prot;
+
+	/*
+	 * If this is a GCS then only interpret VM_WRITE.
+	 *
+	 * TODO: Just make protection_map[] bigger?  Nothing seems
+	 * ideal here.
+	 */
+	if (system_supports_gcs() && (vm_flags & VM_SHADOW_STACK)) {
+		if (vm_flags & VM_WRITE)
+			prot = _PAGE_GCS;
+		else
+			prot = _PAGE_GCS_RO;
+	} else {
+		prot = pgprot_val(protection_map[vm_flags &
 				   (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]);
+	}
 
 	if (vm_flags & VM_ARM64_BTI)
 		prot |= PTE_GP;

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 13/35] KVM: arm64: Manage GCS registers for guests
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (11 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 12/35] arm64/mm: Map pages for guarded control stack Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 14/35] arm64: Disable traps for GCS usage at EL0 and EL1 Mark Brown
                   ` (21 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

GCS introduces a number of system registers for EL1 and EL0, on systems
with GCS we need to context switch them and expose them to VMMs to allow
guests to use GCS.  Traps are already disabled.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/asm/kvm_host.h          | 12 ++++++++++++
 arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 17 +++++++++++++++++
 arch/arm64/kvm/sys_regs.c                  | 22 ++++++++++++++++++++++
 3 files changed, 51 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 8b6096753740..67f3894a86f1 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -364,6 +364,12 @@ enum vcpu_sysreg {
 	PIR_EL1,       /* Permission Indirection Register 1 (EL1) */
 	PIRE0_EL1,     /*  Permission Indirection Register 0 (EL1) */
 
+	/* Guarded Control Stack registers */
+	GCSCRE0_EL1,	/* Guarded Control Stack Control (EL0) */
+	GCSCR_EL1,	/* Guarded Control Stack Control (EL1) */
+	GCSPR_EL0,	/* Guarded Control Stack Pointer (EL0) */
+	GCSPR_EL1,	/* Guarded Control Stack Pointer (EL1) */
+
 	/* 32bit specific registers. */
 	DACR32_EL2,	/* Domain Access Control Register */
 	IFSR32_EL2,	/* Instruction Fault Status Register */
@@ -1134,6 +1140,12 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
 #define kvm_vm_has_ran_once(kvm)					\
 	(test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &(kvm)->arch.flags))
 
+static inline bool has_gcs(void)
+{
+	return IS_ENABLED(CONFIG_ARM64_GCS) &&
+		cpus_have_final_cap(ARM64_HAS_GCS);
+}
+
 int kvm_trng_call(struct kvm_vcpu *vcpu);
 #ifdef CONFIG_KVM
 extern phys_addr_t hyp_mem_base;
diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
index bb6b571ec627..ec34d4a90717 100644
--- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
+++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
@@ -25,6 +25,8 @@ static inline void __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
 {
 	ctxt_sys_reg(ctxt, TPIDR_EL0)	= read_sysreg(tpidr_el0);
 	ctxt_sys_reg(ctxt, TPIDRRO_EL0)	= read_sysreg(tpidrro_el0);
+	if (has_gcs())
+		ctxt_sys_reg(ctxt, GCSPR_EL0) = read_sysreg_s(SYS_GCSPR_EL0);
 }
 
 static inline bool ctxt_has_mte(struct kvm_cpu_context *ctxt)
@@ -62,6 +64,12 @@ static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 	ctxt_sys_reg(ctxt, PAR_EL1)	= read_sysreg_par();
 	ctxt_sys_reg(ctxt, TPIDR_EL1)	= read_sysreg(tpidr_el1);
 
+	if (has_gcs()) {
+		ctxt_sys_reg(ctxt, GCSPR_EL1)	= read_sysreg_el1(SYS_GCSPR);
+		ctxt_sys_reg(ctxt, GCSCR_EL1)	= read_sysreg_el1(SYS_GCSCR);
+		ctxt_sys_reg(ctxt, GCSCRE0_EL1)	= read_sysreg_s(SYS_GCSCRE0_EL1);
+	}
+
 	if (ctxt_has_mte(ctxt)) {
 		ctxt_sys_reg(ctxt, TFSR_EL1) = read_sysreg_el1(SYS_TFSR);
 		ctxt_sys_reg(ctxt, TFSRE0_EL1) = read_sysreg_s(SYS_TFSRE0_EL1);
@@ -95,6 +103,8 @@ static inline void __sysreg_restore_user_state(struct kvm_cpu_context *ctxt)
 {
 	write_sysreg(ctxt_sys_reg(ctxt, TPIDR_EL0),	tpidr_el0);
 	write_sysreg(ctxt_sys_reg(ctxt, TPIDRRO_EL0),	tpidrro_el0);
+	if (has_gcs())
+		write_sysreg_s(ctxt_sys_reg(ctxt, GCSPR_EL0), SYS_GCSPR_EL0);
 }
 
 static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
@@ -138,6 +148,13 @@ static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
 	write_sysreg(ctxt_sys_reg(ctxt, PAR_EL1),	par_el1);
 	write_sysreg(ctxt_sys_reg(ctxt, TPIDR_EL1),	tpidr_el1);
 
+	if (has_gcs()) {
+		write_sysreg_el1(ctxt_sys_reg(ctxt, GCSPR_EL1),	SYS_GCSPR);
+		write_sysreg_el1(ctxt_sys_reg(ctxt, GCSCR_EL1),	SYS_GCSCR);
+		write_sysreg_s(ctxt_sys_reg(ctxt, GCSCRE0_EL1),
+			       SYS_GCSCRE0_EL1);
+	}
+
 	if (ctxt_has_mte(ctxt)) {
 		write_sysreg_el1(ctxt_sys_reg(ctxt, TFSR_EL1), SYS_TFSR);
 		write_sysreg_s(ctxt_sys_reg(ctxt, TFSRE0_EL1), SYS_TFSRE0_EL1);
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index bd3431823ec5..e829400aa911 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1768,6 +1768,23 @@ static unsigned int mte_visibility(const struct kvm_vcpu *vcpu,
 	.visibility = mte_visibility,		\
 }
 
+static unsigned int gcs_visibility(const struct kvm_vcpu *vcpu,
+				   const struct sys_reg_desc *rd)
+{
+	if (has_gcs())
+		return 0;
+
+	return REG_HIDDEN;
+}
+
+#define GCS_REG(name) {				\
+	SYS_DESC(SYS_##name),			\
+	.access = undef_access,			\
+	.reset = reset_unknown,			\
+	.reg = name,				\
+	.visibility = gcs_visibility,		\
+}
+
 static unsigned int el2_visibility(const struct kvm_vcpu *vcpu,
 				   const struct sys_reg_desc *rd)
 {
@@ -2080,6 +2097,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	PTRAUTH_KEY(APDB),
 	PTRAUTH_KEY(APGA),
 
+	GCS_REG(GCSCR_EL1),
+	GCS_REG(GCSPR_EL1),
+	GCS_REG(GCSCRE0_EL1),
+
 	{ SYS_DESC(SYS_SPSR_EL1), access_spsr},
 	{ SYS_DESC(SYS_ELR_EL1), access_elr},
 
@@ -2162,6 +2183,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ SYS_DESC(SYS_SMIDR_EL1), undef_access },
 	{ SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 },
 	{ SYS_DESC(SYS_CTR_EL0), access_ctr },
+	GCS_REG(GCSPR_EL0),
 	{ SYS_DESC(SYS_SVCR), undef_access },
 
 	{ PMU_SYS_REG(SYS_PMCR_EL0), .access = access_pmcr,

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 14/35] arm64: Disable traps for GCS usage at EL0 and EL1
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (12 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 13/35] KVM: arm64: Manage GCS registers for guests Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 15/35] arm64/idreg: Add overrride for GCS Mark Brown
                   ` (20 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

There are fine grained traps for GCS usage at EL0 and EL1, disable them
for the host kernel if we detect GCS.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/asm/el2_setup.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
index 8e5ffb58f83e..c941b0dc0418 100644
--- a/arch/arm64/include/asm/el2_setup.h
+++ b/arch/arm64/include/asm/el2_setup.h
@@ -186,6 +186,15 @@
 	orr	x0, x0, #HFGxTR_EL2_nPIR_EL1
 	orr	x0, x0, #HFGxTR_EL2_nPIRE0_EL1
 
+	/* GCS depends on PIE so we don't check it if PIE is absent */
+	mrs_s	x1, SYS_ID_AA64PFR1_EL1
+	ubfx	x1, x1, #ID_AA64PFR1_EL1_GCS_SHIFT, #4
+	cbz	x1, .Lset_fgt_\@
+
+	/* Disable traps of access to GCS registers at EL0 and EL1 */
+	orr	x0, x0, #HFGxTR_EL2_nGCS_EL1_MASK
+	orr	x0, x0, #HFGxTR_EL2_nGCS_EL0_MASK
+
 .Lset_fgt_\@:
 	msr_s	SYS_HFGRTR_EL2, x0
 	msr_s	SYS_HFGWTR_EL2, x0

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 15/35] arm64/idreg: Add overrride for GCS
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (13 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 14/35] arm64: Disable traps for GCS usage at EL0 and EL1 Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 16/35] arm64/hwcap: Add hwcap " Mark Brown
                   ` (19 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Hook up an override for GCS, allowing it to be disabled from the command
line by specifying arm64.nogcs in case there are problems.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 Documentation/admin-guide/kernel-parameters.txt | 3 +++
 arch/arm64/kernel/idreg-override.c              | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index a1457995fd41..86662eed3003 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -418,6 +418,9 @@
 	arm64.nobti	[ARM64] Unconditionally disable Branch Target
 			Identification support
 
+	arm64.nogcs	[ARM64] Unconditionally disable Guarded Control Stack
+			support
+
 	arm64.nopauth	[ARM64] Unconditionally disable Pointer Authentication
 			support
 
diff --git a/arch/arm64/kernel/idreg-override.c b/arch/arm64/kernel/idreg-override.c
index 2fe2491b692c..49269a5cff10 100644
--- a/arch/arm64/kernel/idreg-override.c
+++ b/arch/arm64/kernel/idreg-override.c
@@ -99,6 +99,7 @@ static const struct ftr_set_desc pfr1 __initconst = {
 	.override	= &id_aa64pfr1_override,
 	.fields		= {
 		FIELD("bt", ID_AA64PFR1_EL1_BT_SHIFT, NULL ),
+		FIELD("gcs", ID_AA64PFR1_EL1_GCS_SHIFT, NULL),
 		FIELD("mte", ID_AA64PFR1_EL1_MTE_SHIFT, NULL),
 		FIELD("sme", ID_AA64PFR1_EL1_SME_SHIFT, pfr1_sme_filter),
 		{}
@@ -178,6 +179,7 @@ static const struct {
 	{ "arm64.nosve",		"id_aa64pfr0.sve=0" },
 	{ "arm64.nosme",		"id_aa64pfr1.sme=0" },
 	{ "arm64.nobti",		"id_aa64pfr1.bt=0" },
+	{ "arm64.nogcs",		"id_aa64pfr1.gcs=0" },
 	{ "arm64.nopauth",
 	  "id_aa64isar1.gpi=0 id_aa64isar1.gpa=0 "
 	  "id_aa64isar1.api=0 id_aa64isar1.apa=0 "

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 16/35] arm64/hwcap: Add hwcap for GCS
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (14 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 15/35] arm64/idreg: Add overrride for GCS Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 17/35] arm64/traps: Handle GCS exceptions Mark Brown
                   ` (18 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Provide a hwcap to enable userspace to detect support for GCS.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 Documentation/arch/arm64/elf_hwcaps.rst | 3 +++
 arch/arm64/include/asm/hwcap.h          | 1 +
 arch/arm64/include/uapi/asm/hwcap.h     | 1 +
 arch/arm64/kernel/cpufeature.c          | 3 +++
 arch/arm64/kernel/cpuinfo.c             | 1 +
 5 files changed, 9 insertions(+)

diff --git a/Documentation/arch/arm64/elf_hwcaps.rst b/Documentation/arch/arm64/elf_hwcaps.rst
index 8c8addb4194c..75f3960cad39 100644
--- a/Documentation/arch/arm64/elf_hwcaps.rst
+++ b/Documentation/arch/arm64/elf_hwcaps.rst
@@ -305,6 +305,9 @@ HWCAP2_SMEF16F16
 HWCAP2_MOPS
     Functionality implied by ID_AA64ISAR2_EL1.MOPS == 0b0001.
 
+HWCAP2_GCS
+    Functionality implied by ID_AA64PFR1_EL1.GCS == 0b1
+
 4. Unused AT_HWCAP bits
 -----------------------
 
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
index 692b1ec663b2..39f397a2b5b2 100644
--- a/arch/arm64/include/asm/hwcap.h
+++ b/arch/arm64/include/asm/hwcap.h
@@ -138,6 +138,7 @@
 #define KERNEL_HWCAP_SME_B16B16		__khwcap2_feature(SME_B16B16)
 #define KERNEL_HWCAP_SME_F16F16		__khwcap2_feature(SME_F16F16)
 #define KERNEL_HWCAP_MOPS		__khwcap2_feature(MOPS)
+#define KERNEL_HWCAP_GCS		__khwcap2_feature(GCS)
 
 /*
  * This yields a mask that user programs can use to figure out what
diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h
index a2cac4305b1e..7510c35e6864 100644
--- a/arch/arm64/include/uapi/asm/hwcap.h
+++ b/arch/arm64/include/uapi/asm/hwcap.h
@@ -103,5 +103,6 @@
 #define HWCAP2_SME_B16B16	(1UL << 41)
 #define HWCAP2_SME_F16F16	(1UL << 42)
 #define HWCAP2_MOPS		(1UL << 43)
+#define HWCAP2_GCS		(1UL << 44)
 
 #endif /* _UAPI__ASM_HWCAP_H */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 92e730027d84..595d982d318f 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -2844,6 +2844,9 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
 	HWCAP_CAP(ID_AA64ZFR0_EL1, I8MM, IMP, CAP_HWCAP, KERNEL_HWCAP_SVEI8MM),
 	HWCAP_CAP(ID_AA64ZFR0_EL1, F32MM, IMP, CAP_HWCAP, KERNEL_HWCAP_SVEF32MM),
 	HWCAP_CAP(ID_AA64ZFR0_EL1, F64MM, IMP, CAP_HWCAP, KERNEL_HWCAP_SVEF64MM),
+#endif
+#ifdef CONFIG_ARM64_GCS
+	HWCAP_CAP(ID_AA64PFR1_EL1, GCS, IMP, CAP_HWCAP, KERNEL_HWCAP_GCS),
 #endif
 	HWCAP_CAP(ID_AA64PFR1_EL1, SSBS, SSBS2, CAP_HWCAP, KERNEL_HWCAP_SSBS),
 #ifdef CONFIG_ARM64_BTI
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index 58622dc85917..451fbbeffa39 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -126,6 +126,7 @@ static const char *const hwcap_str[] = {
 	[KERNEL_HWCAP_SME_B16B16]	= "smeb16b16",
 	[KERNEL_HWCAP_SME_F16F16]	= "smef16f16",
 	[KERNEL_HWCAP_MOPS]		= "mops",
+	[KERNEL_HWCAP_GCS]		= "gcs",
 };
 
 #ifdef CONFIG_COMPAT

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 17/35] arm64/traps: Handle GCS exceptions
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (15 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 16/35] arm64/hwcap: Add hwcap " Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-17 12:12   ` Jonathan Cameron
  2023-07-16 21:51 ` [PATCH 18/35] arm64/mm: Handle GCS data aborts Mark Brown
                   ` (17 subsequent siblings)
  34 siblings, 1 reply; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

A new exception code is defined for GCS specific faults other than
standard load/store faults, for example GCS token validation failures,
add handling for this. These faults are reported to userspace as
segfaults with code SEGV_CPERR (protection error), mirroring the
reporting for x86 shadow stack errors.

GCS faults due to memory load/store operations generate data aborts with
a flag set, these will be handled separately as part of the data abort
handling.

Since we do not currently enable GCS for EL1 we should not get any faults
there but while we're at it we wire things up there, treating any GCS
fault as fatal.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/asm/esr.h       | 26 +++++++++++++++++++++++++-
 arch/arm64/include/asm/exception.h |  2 ++
 arch/arm64/kernel/entry-common.c   | 23 +++++++++++++++++++++++
 arch/arm64/kernel/traps.c          | 11 +++++++++++
 4 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index ae35939f395b..c5a72172fcf1 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -51,7 +51,8 @@
 #define ESR_ELx_EC_FP_EXC32	(0x28)
 /* Unallocated EC: 0x29 - 0x2B */
 #define ESR_ELx_EC_FP_EXC64	(0x2C)
-/* Unallocated EC: 0x2D - 0x2E */
+#define ESR_ELx_EC_GCS		(0x2D)
+/* Unallocated EC: 0x2E */
 #define ESR_ELx_EC_SERROR	(0x2F)
 #define ESR_ELx_EC_BREAKPT_LOW	(0x30)
 #define ESR_ELx_EC_BREAKPT_CUR	(0x31)
@@ -382,6 +383,29 @@
 #define ESR_ELx_MOPS_ISS_SRCREG(esr)	(((esr) & (UL(0x1f) << 5)) >> 5)
 #define ESR_ELx_MOPS_ISS_SIZEREG(esr)	(((esr) & (UL(0x1f) << 0)) >> 0)
 
+/* ISS field definitions for GCS */
+#define ESR_ELx_ExType_SHIFT	(20)
+#define ESR_ELx_ExType_MASK	GENMASK(23, 20)
+#define ESR_ELx_Raddr_SHIFT	(14)
+#define ESR_ELx_Raddr_MASK	GENMASK(14, 10)
+#define ESR_ELx_Rn_SHIFT	(5)
+#define ESR_ELx_Rn_MASK		GENMASK(9, 5)
+#define ESR_ELx_IT_SHIFT	(0)
+#define ESR_ELx_IT_MASK		GENMASK(4, 0)
+
+#define ESR_ELx_ExType_DATA_CHECK	0
+#define ESR_ELx_ExType_EXLOCK		1
+#define ESR_ELx_ExType_STR		2
+
+#define ESR_ELx_IT_RET			0
+#define ESR_ELx_IT_GCSPOPM		1
+#define ESR_ELx_IT_RET_KEYA		2
+#define ESR_ELx_IT_RET_KEYB		3
+#define ESR_ELx_IT_GCSSS1		4
+#define ESR_ELx_IT_GCSSS2		5
+#define ESR_ELx_IT_GCSPOPCX		6
+#define ESR_ELx_IT_GCSPOPX		7
+
 #ifndef __ASSEMBLY__
 #include <asm/types.h>
 
diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h
index ad688e157c9b..99caff458e20 100644
--- a/arch/arm64/include/asm/exception.h
+++ b/arch/arm64/include/asm/exception.h
@@ -57,6 +57,8 @@ void do_el0_undef(struct pt_regs *regs, unsigned long esr);
 void do_el1_undef(struct pt_regs *regs, unsigned long esr);
 void do_el0_bti(struct pt_regs *regs);
 void do_el1_bti(struct pt_regs *regs, unsigned long esr);
+void do_el0_gcs(struct pt_regs *regs, unsigned long esr);
+void do_el1_gcs(struct pt_regs *regs, unsigned long esr);
 void do_debug_exception(unsigned long addr_if_watchpoint, unsigned long esr,
 			struct pt_regs *regs);
 void do_fpsimd_acc(unsigned long esr, struct pt_regs *regs);
diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c
index 6b2e0c367702..4d86216962e5 100644
--- a/arch/arm64/kernel/entry-common.c
+++ b/arch/arm64/kernel/entry-common.c
@@ -400,6 +400,15 @@ static void noinstr el1_bti(struct pt_regs *regs, unsigned long esr)
 	exit_to_kernel_mode(regs);
 }
 
+static void noinstr el1_gcs(struct pt_regs *regs, unsigned long esr)
+{
+	enter_from_kernel_mode(regs);
+	local_daif_inherit(regs);
+	do_el1_gcs(regs, esr);
+	local_daif_mask();
+	exit_to_kernel_mode(regs);
+}
+
 static void noinstr el1_dbg(struct pt_regs *regs, unsigned long esr)
 {
 	unsigned long far = read_sysreg(far_el1);
@@ -442,6 +451,9 @@ asmlinkage void noinstr el1h_64_sync_handler(struct pt_regs *regs)
 	case ESR_ELx_EC_BTI:
 		el1_bti(regs, esr);
 		break;
+	case ESR_ELx_EC_GCS:
+		el1_gcs(regs, esr);
+		break;
 	case ESR_ELx_EC_BREAKPT_CUR:
 	case ESR_ELx_EC_SOFTSTP_CUR:
 	case ESR_ELx_EC_WATCHPT_CUR:
@@ -621,6 +633,14 @@ static void noinstr el0_mops(struct pt_regs *regs, unsigned long esr)
 	exit_to_user_mode(regs);
 }
 
+static void noinstr el0_gcs(struct pt_regs *regs, unsigned long esr)
+{
+	enter_from_user_mode(regs);
+	local_daif_restore(DAIF_PROCCTX);
+	do_el0_gcs(regs, esr);
+	exit_to_user_mode(regs);
+}
+
 static void noinstr el0_inv(struct pt_regs *regs, unsigned long esr)
 {
 	enter_from_user_mode(regs);
@@ -701,6 +721,9 @@ asmlinkage void noinstr el0t_64_sync_handler(struct pt_regs *regs)
 	case ESR_ELx_EC_MOPS:
 		el0_mops(regs, esr);
 		break;
+	case ESR_ELx_EC_GCS:
+		el0_gcs(regs, esr);
+		break;
 	case ESR_ELx_EC_BREAKPT_LOW:
 	case ESR_ELx_EC_SOFTSTP_LOW:
 	case ESR_ELx_EC_WATCHPT_LOW:
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 8b70759cdbb9..65dab959f620 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -500,6 +500,16 @@ void do_el1_bti(struct pt_regs *regs, unsigned long esr)
 	die("Oops - BTI", regs, esr);
 }
 
+void do_el0_gcs(struct pt_regs *regs, unsigned long esr)
+{
+	force_signal_inject(SIGSEGV, SEGV_CPERR, regs->pc, 0);
+}
+
+void do_el1_gcs(struct pt_regs *regs, unsigned long esr)
+{
+	die("Oops - GCS", regs, esr);
+}
+
 void do_el0_fpac(struct pt_regs *regs, unsigned long esr)
 {
 	force_signal_inject(SIGILL, ILL_ILLOPN, regs->pc, esr);
@@ -884,6 +894,7 @@ static const char *esr_class_str[] = {
 	[ESR_ELx_EC_MOPS]		= "MOPS",
 	[ESR_ELx_EC_FP_EXC32]		= "FP (AArch32)",
 	[ESR_ELx_EC_FP_EXC64]		= "FP (AArch64)",
+	[ESR_ELx_EC_GCS]		= "Guarded Control Stack",
 	[ESR_ELx_EC_SERROR]		= "SError",
 	[ESR_ELx_EC_BREAKPT_LOW]	= "Breakpoint (lower EL)",
 	[ESR_ELx_EC_BREAKPT_CUR]	= "Breakpoint (current EL)",

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 18/35] arm64/mm: Handle GCS data aborts
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (16 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 17/35] arm64/traps: Handle GCS exceptions Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 19/35] arm64/gcs: Context switch GCS registers for EL0 Mark Brown
                   ` (16 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

All GCS operations at EL0 must happen on a page which is marked as
having UnprivGCS access, including read operations.  If a GCS operation
attempts to access a page without this then it will generate a data
abort with the GCS bit set in ESR_EL1.ISS2.

EL0 may validly generate such faults, for example due to copy on write
which will cause the GCS data to be stored in a read only page with no
GCS permissions until the actual copy happens.  Since UnprivGCS allows
both reads and writes to the GCS (though only through GCS operations) we
need to ensure that the memory management subsystem handles GCS accesses
as writes at all times.  Do this by adding FAULT_FLAG_WRITE to any GCS
page faults, adding handling to ensure that invalid cases are identfied
as such early so the memory management core does not think they will
succeed.  The core cannot distinguish between VMAs which are generally
writeable and VMAs which are only writeable through GCS operations.

EL1 may validly write to EL0 GCS for management purposes (eg, while
initialising with cap tokens).

We also report any GCS faults in VMAs not marked as part of a GCS as
access violations, causing a fault to be delivered to userspace if it
attempts to do GCS operations outside a GCS.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/mm/fault.c | 75 +++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 67 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 3fe516b32577..facade819abb 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -494,13 +494,30 @@ static void do_bad_area(unsigned long far, unsigned long esr,
 	}
 }
 
+/*
+ * Note: not valid for EL1 DC IVAC, but we never use that such that it
+ * should fault. EL0 cannot issue DC IVAC (undef).
+ */
+static bool is_write_abort(unsigned long esr)
+{
+	return (esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM);
+}
+
+static bool is_gcs_fault(unsigned long esr)
+{
+	if (!esr_is_data_abort(esr))
+		return false;
+
+	return ESR_ELx_ISS2(esr) & ESR_ELx_GCS;
+}
+
 #define VM_FAULT_BADMAP		((__force vm_fault_t)0x010000)
 #define VM_FAULT_BADACCESS	((__force vm_fault_t)0x020000)
 
 static vm_fault_t __do_page_fault(struct mm_struct *mm,
 				  struct vm_area_struct *vma, unsigned long addr,
 				  unsigned int mm_flags, unsigned long vm_flags,
-				  struct pt_regs *regs)
+				  unsigned long esr, struct pt_regs *regs)
 {
 	/*
 	 * Ok, we have a good vm_area for this memory access, so we can handle
@@ -510,6 +527,26 @@ static vm_fault_t __do_page_fault(struct mm_struct *mm,
 	 */
 	if (!(vma->vm_flags & vm_flags))
 		return VM_FAULT_BADACCESS;
+
+	if (vma->vm_flags & VM_SHADOW_STACK) {
+		/*
+		 * Writes to a GCS must either be generated by a GCS
+		 * operation or be from EL1.
+		 */
+		if (is_write_abort(esr) &&
+		    !(is_gcs_fault(esr) || is_el1_data_abort(esr)))
+			return VM_FAULT_BADACCESS;
+	} else {
+		/*
+		 * GCS faults should never happen for pages that are
+		 * not part of a GCS and the operation being attempted
+		 * can never succeed.
+		 */
+		if (is_gcs_fault(esr))
+			return VM_FAULT_BADACCESS;
+	}
+
+
 	return handle_mm_fault(vma, addr, mm_flags, regs);
 }
 
@@ -518,13 +555,15 @@ static bool is_el0_instruction_abort(unsigned long esr)
 	return ESR_ELx_EC(esr) == ESR_ELx_EC_IABT_LOW;
 }
 
-/*
- * Note: not valid for EL1 DC IVAC, but we never use that such that it
- * should fault. EL0 cannot issue DC IVAC (undef).
- */
-static bool is_write_abort(unsigned long esr)
+static bool is_invalid_el0_gcs_access(struct vm_area_struct *vma, u64 esr)
 {
-	return (esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM);
+	if (!system_supports_gcs())
+		return false;
+	if (likely(!(vma->vm_flags & VM_SHADOW_STACK)))
+		return false;
+	if (is_gcs_fault(esr))
+		return false;
+	return is_write_abort(esr);
 }
 
 static int __kprobes do_page_fault(unsigned long far, unsigned long esr,
@@ -573,6 +612,13 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,
 		/* If EPAN is absent then exec implies read */
 		if (!cpus_have_const_cap(ARM64_HAS_EPAN))
 			vm_flags |= VM_EXEC;
+		/*
+		 * Upgrade read faults to write faults, GCS reads must
+		 * occur on a page marked as GCS so we need to trigger
+		 * copy on write always.
+		 */
+		if (is_gcs_fault(esr))
+			mm_flags |= FAULT_FLAG_WRITE;
 	}
 
 	if (is_ttbr0_addr(addr) && is_el1_permission_fault(addr, esr, regs)) {
@@ -595,6 +641,19 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,
 	if (!vma)
 		goto lock_mmap;
 
+	/*
+	 * We get legitimate write faults for GCS pages from GCS
+	 * operations and from EL1 writes to EL0 pages but just plain
+	 * EL0 writes are invalid.  Specifically check for this since
+	 * as a result of upgrading read faults to write faults for
+	 * CoW the mm core isn't able to distinguish these invalid
+	 * writes.
+	 */
+	if (is_invalid_el0_gcs_access(vma, esr)) {
+		vma_end_read(vma);
+		goto lock_mmap;
+	}
+
 	if (!(vma->vm_flags & vm_flags)) {
 		vma_end_read(vma);
 		goto lock_mmap;
@@ -624,7 +683,7 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,
 		goto done;
 	}
 
-	fault = __do_page_fault(mm, vma, addr, mm_flags, vm_flags, regs);
+	fault = __do_page_fault(mm, vma, addr, mm_flags, vm_flags, esr, regs);
 
 	/* Quick path to respond to signals */
 	if (fault_signal_pending(fault, regs)) {

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 19/35] arm64/gcs: Context switch GCS registers for EL0
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (17 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 18/35] arm64/mm: Handle GCS data aborts Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 20/35] arm64/gcs: Allocate a new GCS for threads with GCS enabled Mark Brown
                   ` (15 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

There are two registers controlling the GCS state of EL0, GCSPR_EL0 which
is the current GCS pointer and GCSCRE0_EL1 which has enable bits for the
specific GCS functionality enabled for EL0. Manage these on context switch
and process lifetime events, GCS is reset on exec().

Since the current GCS configuration of a thread will be visible to
userspace we store the configuration in the format used with userspace
and provide a helper which configures the system register as needed.

On systems that support GCS we always allow access to GCSPR_EL0, this
facilitates reporting of GCS faults if userspace implements disabling of
GCS on error - the GCS can still be discovered and examined even if GCS
has been disabled.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/asm/gcs.h       | 24 +++++++++++++++++++
 arch/arm64/include/asm/processor.h |  6 +++++
 arch/arm64/kernel/process.c        | 47 ++++++++++++++++++++++++++++++++++++++
 arch/arm64/mm/Makefile             |  1 +
 arch/arm64/mm/gcs.c                | 39 +++++++++++++++++++++++++++++++
 5 files changed, 117 insertions(+)

diff --git a/arch/arm64/include/asm/gcs.h b/arch/arm64/include/asm/gcs.h
index 7c5e95218db6..04594ef59dad 100644
--- a/arch/arm64/include/asm/gcs.h
+++ b/arch/arm64/include/asm/gcs.h
@@ -48,4 +48,28 @@ static inline u64 gcsss2(void)
 	return Xt;
 }
 
+#ifdef CONFIG_ARM64_GCS
+
+static inline bool task_gcs_el0_enabled(struct task_struct *task)
+{
+	return current->thread.gcs_el0_mode & PR_SHADOW_STACK_ENABLE;
+}
+
+void gcs_set_el0_mode(struct task_struct *task);
+void gcs_free(struct task_struct *task);
+void gcs_preserve_current_state(void);
+
+#else
+
+static inline bool task_gcs_el0_enabled(struct task_struct *task)
+{
+	return false;
+}
+
+static inline void gcs_set_el0_mode(struct task_struct *task) { }
+static inline void gcs_free(struct task_struct *task) { }
+static inline void gcs_preserve_current_state(void) { }
+
+#endif
+
 #endif
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 3918f2a67970..f1551228a143 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -179,6 +179,12 @@ struct thread_struct {
 	u64			sctlr_user;
 	u64			svcr;
 	u64			tpidr2_el0;
+#ifdef CONFIG_ARM64_GCS
+	unsigned int		gcs_el0_mode;
+	u64			gcspr_el0;
+	u64			gcs_base;
+	u64			gcs_size;
+#endif
 };
 
 static inline unsigned int thread_get_vl(struct thread_struct *thread,
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 0fcc4eb1a7ab..0d07f78b6c85 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -48,6 +48,7 @@
 #include <asm/cacheflush.h>
 #include <asm/exec.h>
 #include <asm/fpsimd.h>
+#include <asm/gcs.h>
 #include <asm/mmu_context.h>
 #include <asm/mte.h>
 #include <asm/processor.h>
@@ -271,12 +272,30 @@ static void flush_tagged_addr_state(void)
 		clear_thread_flag(TIF_TAGGED_ADDR);
 }
 
+#ifdef CONFIG_ARM64_GCS
+
+static void flush_gcs(void)
+{
+	if (system_supports_gcs()) {
+		gcs_free(current);
+		write_sysreg_s(0, SYS_GCSCRE0_EL1);
+		write_sysreg_s(0, SYS_GCSPR_EL0);
+	}
+}
+
+#else
+
+static void flush_gcs(void) { }
+
+#endif
+
 void flush_thread(void)
 {
 	fpsimd_flush_thread();
 	tls_thread_flush();
 	flush_ptrace_hw_breakpoint(current);
 	flush_tagged_addr_state();
+	flush_gcs();
 }
 
 void arch_release_task_struct(struct task_struct *tsk)
@@ -474,6 +493,33 @@ static void entry_task_switch(struct task_struct *next)
 	__this_cpu_write(__entry_task, next);
 }
 
+#ifdef CONFIG_ARM64_GCS
+
+void gcs_preserve_current_state(void)
+{
+	if (task_gcs_el0_enabled(current))
+		current->thread.gcspr_el0 = read_sysreg_s(SYS_GCSPR_EL0);
+}
+
+static void gcs_thread_switch(struct task_struct *next)
+{
+	if (!system_supports_gcs())
+		return;
+
+	gcs_preserve_current_state();
+
+	gcs_set_el0_mode(next);
+	write_sysreg_s(next->thread.gcspr_el0, SYS_GCSPR_EL0);
+}
+
+#else
+
+static void gcs_thread_switch(struct task_struct *next)
+{
+}
+
+#endif
+
 /*
  * ARM erratum 1418040 handling, affecting the 32bit view of CNTVCT.
  * Ensure access is disabled when switching to a 32bit task, ensure
@@ -533,6 +579,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
 	ssbs_thread_switch(next);
 	erratum_1418040_thread_switch(next);
 	ptrauth_thread_switch_user(next);
+	gcs_thread_switch(next);
 
 	/*
 	 * Complete any pending TLB or cache maintenance on this CPU in case
diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile
index dbd1bc95967d..4e7cb2f02999 100644
--- a/arch/arm64/mm/Makefile
+++ b/arch/arm64/mm/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_TRANS_TABLE)	+= trans_pgd.o
 obj-$(CONFIG_TRANS_TABLE)	+= trans_pgd-asm.o
 obj-$(CONFIG_DEBUG_VIRTUAL)	+= physaddr.o
 obj-$(CONFIG_ARM64_MTE)		+= mteswap.o
+obj-$(CONFIG_ARM64_GCS)		+= gcs.o
 KASAN_SANITIZE_physaddr.o	+= n
 
 obj-$(CONFIG_KASAN)		+= kasan_init.o
diff --git a/arch/arm64/mm/gcs.c b/arch/arm64/mm/gcs.c
new file mode 100644
index 000000000000..b0a67efc522b
--- /dev/null
+++ b/arch/arm64/mm/gcs.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/syscalls.h>
+#include <linux/types.h>
+
+#include <asm/cpufeature.h>
+#include <asm/page.h>
+
+/*
+ * Apply the GCS mode configured for the specified task to the
+ * hardware.
+ */
+void gcs_set_el0_mode(struct task_struct *task)
+{
+	u64 gcscre0_el1 = GCSCRE0_EL1_nTR;
+
+	if (task->thread.gcs_el0_mode & PR_SHADOW_STACK_ENABLE)
+		gcscre0_el1 |= GCSCRE0_EL1_RVCHKEN | GCSCRE0_EL1_PCRSEL;
+
+	if (task->thread.gcs_el0_mode & PR_SHADOW_STACK_WRITE)
+		gcscre0_el1 |= GCSCRE0_EL1_STREn;
+
+	if (task->thread.gcs_el0_mode & PR_SHADOW_STACK_PUSH)
+		gcscre0_el1 |= GCSCRE0_EL1_PUSHMEn;
+
+	write_sysreg_s(gcscre0_el1, SYS_GCSCRE0_EL1);
+}
+
+void gcs_free(struct task_struct *task)
+{
+	if (task->thread.gcs_base)
+		vm_munmap(task->thread.gcs_base, task->thread.gcs_size);
+
+	task->thread.gcspr_el0 = 0;
+	task->thread.gcs_base = 0;
+	task->thread.gcs_size = 0;
+}

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 20/35] arm64/gcs: Allocate a new GCS for threads with GCS enabled
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (18 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 19/35] arm64/gcs: Context switch GCS registers for EL0 Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 21/35] arm64/gcs: Implement shadow stack prctl() interface Mark Brown
                   ` (14 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

We do not currently have a mechanism to specify a new GCS for a new
thread so when a thread is created which has GCS enabled allocate one
for it.  Since there is no current API for specifying the size of the
GCS we follow the extensively discussed x86 implementation and allocate
min(RLIMIT_STACK, 4G).  Since the GCS only stores the call stack and not
any variables this should be more than sufficient for most applications.

When allocating the stack we initialise GCSPR_EL0 to point to one entry
below the end of the region allocated, this keeps the top entry of the
stack 0 so software walking the GCS can easily detect the end of the
region.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/asm/gcs.h |  7 ++++++
 arch/arm64/kernel/process.c  | 30 ++++++++++++++++++++++++
 arch/arm64/mm/gcs.c          | 56 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 93 insertions(+)

diff --git a/arch/arm64/include/asm/gcs.h b/arch/arm64/include/asm/gcs.h
index 04594ef59dad..4371a2f99b4a 100644
--- a/arch/arm64/include/asm/gcs.h
+++ b/arch/arm64/include/asm/gcs.h
@@ -58,6 +58,8 @@ static inline bool task_gcs_el0_enabled(struct task_struct *task)
 void gcs_set_el0_mode(struct task_struct *task);
 void gcs_free(struct task_struct *task);
 void gcs_preserve_current_state(void);
+unsigned long gcs_alloc_thread_stack(struct task_struct *tsk,
+			    unsigned long clone_flags, size_t size);
 
 #else
 
@@ -69,6 +71,11 @@ static inline bool task_gcs_el0_enabled(struct task_struct *task)
 static inline void gcs_set_el0_mode(struct task_struct *task) { }
 static inline void gcs_free(struct task_struct *task) { }
 static inline void gcs_preserve_current_state(void) { }
+static inline unsigned long gcs_alloc_thread_stack(struct task_struct *tsk,
+				     unsigned long clone_flags, size_t size)
+{
+	return -ENOTSUPP;
+}
 
 #endif
 
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 0d07f78b6c85..ce0a68d3539f 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -283,9 +283,34 @@ static void flush_gcs(void)
 	}
 }
 
+static int copy_thread_gcs(struct task_struct *p, unsigned long clone_flags,
+			   size_t stack_size)
+{
+	unsigned long gcs;
+
+	if (!system_supports_gcs())
+		return 0;
+
+	if (!task_gcs_el0_enabled(p))
+		return 0;
+
+	p->thread.gcspr_el0 = read_sysreg_s(SYS_GCSPR_EL0);
+
+	gcs = gcs_alloc_thread_stack(p, clone_flags, stack_size);
+	if (IS_ERR_VALUE(gcs))
+		return PTR_ERR((void *)gcs);
+
+	return 0;
+}
+
 #else
 
 static void flush_gcs(void) { }
+static int copy_thread_gcs(struct task_struct *p, unsigned long clone_flags,
+			   size_t stack_size)
+{
+	return 0;
+}
 
 #endif
 
@@ -367,6 +392,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
 	unsigned long stack_start = args->stack;
 	unsigned long tls = args->tls;
 	struct pt_regs *childregs = task_pt_regs(p);
+	int ret;
 
 	memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
 
@@ -408,6 +434,10 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
 			p->thread.uw.tp_value = tls;
 			p->thread.tpidr2_el0 = 0;
 		}
+
+		ret = copy_thread_gcs(p, clone_flags, args->stack_size);
+		if (ret != 0)
+			return ret;
 	} else {
 		/*
 		 * A kthread has no context to ERET to, so ensure any buggy
diff --git a/arch/arm64/mm/gcs.c b/arch/arm64/mm/gcs.c
index b0a67efc522b..1e059c37088d 100644
--- a/arch/arm64/mm/gcs.c
+++ b/arch/arm64/mm/gcs.c
@@ -8,6 +8,62 @@
 #include <asm/cpufeature.h>
 #include <asm/page.h>
 
+static unsigned long alloc_gcs(unsigned long addr, unsigned long size,
+			       unsigned long token_offset, bool set_res_tok)
+{
+	int flags = MAP_ANONYMOUS | MAP_PRIVATE;
+	struct mm_struct *mm = current->mm;
+	unsigned long mapped_addr, unused;
+
+	if (addr)
+		flags |= MAP_FIXED_NOREPLACE;
+
+	mmap_write_lock(mm);
+	mapped_addr = do_mmap(NULL, addr, size, PROT_READ, flags,
+			      VM_SHADOW_STACK | VM_WRITE, 0, &unused, NULL);
+	mmap_write_unlock(mm);
+
+	return mapped_addr;
+}
+
+static unsigned long gcs_size(unsigned long size)
+{
+	if (size)
+		return PAGE_ALIGN(size);
+
+	/* Allocate RLIMIT_STACK with limits of PAGE_SIZE..4G */
+	size = PAGE_ALIGN(min_t(unsigned long long,
+				rlimit(RLIMIT_STACK), SZ_4G));
+	return max(PAGE_SIZE, size);
+}
+
+unsigned long gcs_alloc_thread_stack(struct task_struct *tsk,
+				     unsigned long clone_flags, size_t size)
+{
+	unsigned long addr;
+
+	if (!system_supports_gcs())
+		return 0;
+
+	if (!task_gcs_el0_enabled(tsk))
+		return 0;
+
+	if ((clone_flags & (CLONE_VFORK | CLONE_VM)) != CLONE_VM)
+		return 0;
+
+	size = gcs_size(size);
+
+	addr = alloc_gcs(0, size, 0, 0);
+	if (IS_ERR_VALUE(addr))
+		return addr;
+
+	tsk->thread.gcs_base = addr;
+	tsk->thread.gcs_size = size;
+	tsk->thread.gcspr_el0 = addr + size - sizeof(u64);
+
+	return addr;
+}
+
 /*
  * Apply the GCS mode configured for the specified task to the
  * hardware.

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 21/35] arm64/gcs: Implement shadow stack prctl() interface
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (19 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 20/35] arm64/gcs: Allocate a new GCS for threads with GCS enabled Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-18 17:51   ` Edgecombe, Rick P
  2023-07-16 21:51 ` [PATCH 22/35] arm64/mm: Implement map_shadow_stack() Mark Brown
                   ` (13 subsequent siblings)
  34 siblings, 1 reply; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Implement the architecture neutral prtctl() interface for setting the
shadow stack status, this supports setting and reading the current GCS
configuration for the current thread.

Userspace can enable basic GCS functionality and additionally also
support for GCS pushes and arbatrary GCS stores.  It is expected that
this prctl() will be called very early in application startup, for
example by the dynamic linker, and not subsequently adjusted during
normal operation.  Users should carefully note that after enabling GCS
for a thread GCS will become active with no call stack so it is not
normally possible to return from the function that invoked the prctl().

State is stored per thread, enabling GCS for a thread causes a GCS to be
allocated for that thread.

Userspace may lock the current GCS configuration by specifying
PR_SHADOW_STACK_ENABLE_LOCK, this prevents any further changes to the
GCS configuration via any means.

If GCS is not being enabled then all flags other than _LOCK are ignored,
it is not possible to enable stores or pops without enabling GCS.

When disabling the GCS we do not free the allocated stack, this allows
for inspection of the GCS after disabling as part of fault reporting.
Since it is not an expected use case and since it presents some
complications in determining what to do with previously initialsed data
on the GCS attempts to reenable GCS after this are rejected.  This can
be revisted if a use case arises.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/asm/gcs.h |  4 +++
 arch/arm64/mm/gcs.c          | 64 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+)

diff --git a/arch/arm64/include/asm/gcs.h b/arch/arm64/include/asm/gcs.h
index 4371a2f99b4a..8655ba8054c7 100644
--- a/arch/arm64/include/asm/gcs.h
+++ b/arch/arm64/include/asm/gcs.h
@@ -48,6 +48,10 @@ static inline u64 gcsss2(void)
 	return Xt;
 }
 
+#define PR_SHADOW_STACK_SUPPORTED_STATUS_MASK \
+	(PR_SHADOW_STACK_LOCK | PR_SHADOW_STACK_ENABLE | \
+	 PR_SHADOW_STACK_WRITE | PR_SHADOW_STACK_PUSH)
+
 #ifdef CONFIG_ARM64_GCS
 
 static inline bool task_gcs_el0_enabled(struct task_struct *task)
diff --git a/arch/arm64/mm/gcs.c b/arch/arm64/mm/gcs.c
index 1e059c37088d..b137493c594d 100644
--- a/arch/arm64/mm/gcs.c
+++ b/arch/arm64/mm/gcs.c
@@ -93,3 +93,67 @@ void gcs_free(struct task_struct *task)
 	task->thread.gcs_base = 0;
 	task->thread.gcs_size = 0;
 }
+
+int arch_set_shadow_stack_status(struct task_struct *task, unsigned long arg)
+{
+	unsigned long gcs, size;
+
+	if (!system_supports_gcs())
+		return -EINVAL;
+
+	if (is_compat_thread(task_thread_info(task)))
+		return -EINVAL;
+
+	/* Reject unknown flags */
+	if (arg & ~PR_SHADOW_STACK_SUPPORTED_STATUS_MASK)
+		return -EINVAL;
+
+	/* If the task has been locked block any attempted changes */
+	if (task->thread.gcs_el0_mode & PR_SHADOW_STACK_LOCK)
+		return -EBUSY;
+
+	/* Drop flags other than lock if disabling */
+	if (!(arg & PR_SHADOW_STACK_ENABLE))
+		arg &= ~PR_SHADOW_STACK_LOCK;
+
+	/* If we are enabling GCS then make sure we have a stack */
+	if (arg & PR_SHADOW_STACK_ENABLE) {
+		if (!task_gcs_el0_enabled(task)) {
+			/* Do not allow GCS to be reenabled */
+			if (task->thread.gcs_base)
+				return -EINVAL;
+
+			size = gcs_size(0);
+			gcs = alloc_gcs(task->thread.gcspr_el0, size,
+					0, 0);
+			if (!gcs)
+				return -ENOMEM;
+
+			task->thread.gcspr_el0 = gcs + size - sizeof(u64);
+			task->thread.gcs_base = gcs;
+			task->thread.gcs_size = size;
+			if (task == current)
+				write_sysreg_s(task->thread.gcspr_el0,
+					       SYS_GCSPR_EL0);
+
+		}
+	}
+
+	task->thread.gcs_el0_mode = arg;
+	if (task == current)
+		gcs_set_el0_mode(task);
+
+	return 0;
+}
+
+int arch_get_shadow_stack_status(struct task_struct *task,
+				 unsigned long __user *arg)
+{
+	if (!system_supports_gcs())
+		return -EINVAL;
+
+	if (is_compat_thread(task_thread_info(task)))
+		return -EINVAL;
+
+	return put_user(task->thread.gcs_el0_mode, arg);
+}

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 22/35] arm64/mm: Implement map_shadow_stack()
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (20 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 21/35] arm64/gcs: Implement shadow stack prctl() interface Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-18  9:10   ` Szabolcs Nagy
  2023-07-16 21:51 ` [PATCH 23/35] arm64/signal: Set up and restore the GCS context for signal handlers Mark Brown
                   ` (12 subsequent siblings)
  34 siblings, 1 reply; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

As discussed extensively in the changelog for the addition of this
syscall on x86 ("x86/shstk: Introduce map_shadow_stack syscall") the
existing mmap() and madvise() syscalls do not map entirely well onto the
security requirements for guarded control stacks since they lead to
windows where memory is allocated but not yet protected or stacks which
are not properly and safely initialised. Instead a new syscall
map_shadow_stack() has been defined which allocates and initialises a
shadow stack page.

Implement this for arm64, initialising memory allocated this way with
the top two entries in the stack being 0 (to allow detection of the end
of the GCS) and a GCS cap token (to allow switching to the newly
allocated GCS via the GCS switch instructions).

Since the x86 code has not yet been rebased to v6.5-rc1 this includes
the architecture neutral parts of Rick Edgecmbe's "x86/shstk: Introduce
map_shadow_stack syscall".

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/mm/gcs.c               | 44 ++++++++++++++++++++++++++++++++++++++-
 include/linux/syscalls.h          |  1 +
 include/uapi/asm-generic/unistd.h |  5 ++++-
 kernel/sys_ni.c                   |  1 +
 4 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/mm/gcs.c b/arch/arm64/mm/gcs.c
index b137493c594d..4a0a736800c0 100644
--- a/arch/arm64/mm/gcs.c
+++ b/arch/arm64/mm/gcs.c
@@ -52,7 +52,6 @@ unsigned long gcs_alloc_thread_stack(struct task_struct *tsk,
 		return 0;
 
 	size = gcs_size(size);
-
 	addr = alloc_gcs(0, size, 0, 0);
 	if (IS_ERR_VALUE(addr))
 		return addr;
@@ -64,6 +63,49 @@ unsigned long gcs_alloc_thread_stack(struct task_struct *tsk,
 	return addr;
 }
 
+SYSCALL_DEFINE3(map_shadow_stack, unsigned long, addr, unsigned long, size, unsigned int, flags)
+{
+	unsigned long aligned_size;
+	unsigned long __user *cap_ptr;
+	unsigned long cap_val;
+	int ret;
+
+	if (!system_supports_gcs())
+		return -EOPNOTSUPP;
+
+	if (flags)
+		return -EINVAL;
+
+	/*
+	 * An overflow would result in attempting to write the restore token
+	 * to the wrong location. Not catastrophic, but just return the right
+	 * error code and block it.
+	 */
+	aligned_size = PAGE_ALIGN(size);
+	if (aligned_size < size)
+		return -EOVERFLOW;
+
+	addr = alloc_gcs(addr, aligned_size, 0, false);
+	if (IS_ERR_VALUE(addr))
+		return addr;
+
+	/*
+	 * Put a cap token at the end of the allocated region so it
+	 * can be switched to.
+	 */
+	cap_ptr = (unsigned long __user *)(addr + aligned_size -
+					   (2 * sizeof(unsigned long)));
+	cap_val = GCS_CAP(cap_ptr);
+
+	ret = copy_to_user_gcs(cap_ptr, &cap_val, 1);
+	if (ret != 0) {
+		vm_munmap(addr, size);
+		return -EFAULT;
+	}
+
+	return addr;
+}
+
 /*
  * Apply the GCS mode configured for the specified task to the
  * hardware.
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 03e3d0121d5e..7f6dc0988197 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -953,6 +953,7 @@ asmlinkage long sys_set_mempolicy_home_node(unsigned long start, unsigned long l
 asmlinkage long sys_cachestat(unsigned int fd,
 		struct cachestat_range __user *cstat_range,
 		struct cachestat __user *cstat, unsigned int flags);
+asmlinkage long sys_map_shadow_stack(unsigned long addr, unsigned long size, unsigned int flags);
 
 /*
  * Architecture-specific system calls
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index fd6c1cb585db..38885a795ea6 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -820,8 +820,11 @@ __SYSCALL(__NR_set_mempolicy_home_node, sys_set_mempolicy_home_node)
 #define __NR_cachestat 451
 __SYSCALL(__NR_cachestat, sys_cachestat)
 
+#define __NR_map_shadow_stack 452
+__SYSCALL(__NR_map_shadow_stack, sys_map_shadow_stack)
+
 #undef __NR_syscalls
-#define __NR_syscalls 452
+#define __NR_syscalls 453
 
 /*
  * 32 bit systems traditionally used different
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 781de7cc6a4e..e137c1385c56 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -274,6 +274,7 @@ COND_SYSCALL(vm86old);
 COND_SYSCALL(modify_ldt);
 COND_SYSCALL(vm86);
 COND_SYSCALL(kexec_file_load);
+COND_SYSCALL(map_shadow_stack);
 
 /* s390 */
 COND_SYSCALL(s390_pci_mmio_read);

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 23/35] arm64/signal: Set up and restore the GCS context for signal handlers
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (21 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 22/35] arm64/mm: Implement map_shadow_stack() Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 24/35] arm64/signal: Expose GCS state in signal frames Mark Brown
                   ` (11 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

When invoking a signal handler we use the GCS configuration and stack
for the current thread.

Since we implement signal return by calling the signal handler with a
return address set up pointing to a trampoline in the vDSO we need to
also configure any active GCS for this by pushing a frame for the
trampoline onto the GCS.  If we do not do this then signal return will
generate a GCS protection fault.

In order to guard against attempts to bypass GCS protections via signal
return we only allow returning with GCSPR_EL0 pointing to an address
where it was previously preempted by a signal.  We do this by pushing a
cap onto the GCS, this takes the form of an architectural GCS cap token
with the top bit set which we add on signal entry and validate and pop
off on signal return.  Since the top bit is set address validation for
the token will fail if an attempt is made to use it with the stack
switch instructions.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/asm/gcs.h |   2 +
 arch/arm64/kernel/signal.c   | 134 +++++++++++++++++++++++++++++++++++++++++--
 arch/arm64/mm/gcs.c          |   1 +
 3 files changed, 132 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/gcs.h b/arch/arm64/include/asm/gcs.h
index 8655ba8054c7..8ef2313522b4 100644
--- a/arch/arm64/include/asm/gcs.h
+++ b/arch/arm64/include/asm/gcs.h
@@ -8,6 +8,8 @@
 #include <asm/types.h>
 #include <asm/uaccess.h>
 
+struct ksignal;
+
 static inline void gcsb_dsync(void)
 {
 	asm volatile(".inst 0xd503227f" : : : "memory");
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 0df8cc295ea5..922b694fa0aa 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -25,6 +25,7 @@
 #include <asm/elf.h>
 #include <asm/exception.h>
 #include <asm/cacheflush.h>
+#include <asm/gcs.h>
 #include <asm/ucontext.h>
 #include <asm/unistd.h>
 #include <asm/fpsimd.h>
@@ -34,6 +35,36 @@
 #include <asm/traps.h>
 #include <asm/vdso.h>
 
+#ifdef CONFIG_ARM64_GCS
+/* Extra bit set in the address distinguishing a signal cap token. */
+#define GCS_SIGNAL_CAP_FLAG BIT(63)
+
+#define GCS_SIGNAL_CAP(addr) (GCS_CAP(addr) | GCS_SIGNAL_CAP_FLAG)
+
+static bool gcs_signal_cap_valid(u64 addr, u64 val)
+{
+	/*
+	 * The top bit should be set, this is an invalid address for
+	 * EL0 and will only be set for caps created by signals.
+	 */
+	if (!(val & GCS_SIGNAL_CAP_FLAG))
+		return false;
+
+	/* The rest should be a standard architectural cap token. */
+	val &= ~GCS_SIGNAL_CAP_FLAG;
+
+	/* The cap must have the low bits set to a token value */
+	if (GCS_CAP_TOKEN(val) != GCS_CAP_VALID_TOKEN)
+		return false;
+
+	/* The cap must store the VA the cap was stored at */
+	if (GCS_CAP_ADDR(addr) != GCS_CAP_ADDR(val))
+		return false;
+
+	return true;
+}
+#endif
+
 /*
  * Do a signal return; undo the signal stack. These are aligned to 128-bit.
  */
@@ -815,6 +846,49 @@ static int restore_sigframe(struct pt_regs *regs,
 	return err;
 }
 
+#ifdef CONFIG_ARM64_GCS
+static int gcs_restore_signal(void)
+{
+	u64 gcspr_el0, cap;
+	int ret;
+
+	if (!system_supports_gcs())
+		return 0;
+
+	if (!(current->thread.gcs_el0_mode & PR_SHADOW_STACK_ENABLE))
+		return 0;
+
+	/*
+	 * We are exiting from a signal, the in memory state will be the
+	 * most up to date value.
+	 */
+	gcspr_el0 = current->thread.gcspr_el0;
+
+	/*
+	 * GCSPR_EL0 should be pointing at a capped GCS, read the cap...
+	 */
+	gcsb_dsync();
+	ret = copy_from_user(&cap, (__user void*)gcspr_el0, sizeof(cap));
+	if (ret)
+		return -EFAULT;
+
+	/*
+	 * ...then check that the cap is the actual GCS before
+	 * restoring it.
+	 */
+	if (!gcs_signal_cap_valid(gcspr_el0, cap))
+		return -EINVAL;
+
+	current->thread.gcspr_el0 = gcspr_el0 + sizeof(cap);
+	write_sysreg_s(current->thread.gcspr_el0, SYS_GCSPR_EL0);
+
+	return 0;
+}
+
+#else
+static int gcs_restore_signal(void) { return 0; }
+#endif
+
 SYSCALL_DEFINE0(rt_sigreturn)
 {
 	struct pt_regs *regs = current_pt_regs();
@@ -841,6 +915,9 @@ SYSCALL_DEFINE0(rt_sigreturn)
 	if (restore_altstack(&frame->uc.uc_stack))
 		goto badframe;
 
+	if (gcs_restore_signal())
+		goto badframe;
+
 	return regs->regs[0];
 
 badframe:
@@ -1071,7 +1148,52 @@ static int get_sigframe(struct rt_sigframe_user_layout *user,
 	return 0;
 }
 
-static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
+#ifdef CONFIG_ARM64_GCS
+
+static int gcs_signal_entry(__sigrestore_t sigtramp, struct ksignal *ksig)
+{
+	unsigned long __user *gcspr_el0;
+	unsigned long cap[2];
+	int ret;
+
+	if (!system_supports_gcs())
+		return 0;
+
+	if (!task_gcs_el0_enabled(current))
+		return 0;
+
+	/*
+	 * We are entering a signal handler, current register state is
+	 * active.
+	 */
+	gcspr_el0 = (unsigned long __user *)read_sysreg_s(SYS_GCSPR_EL0);
+
+	/*
+	 * Push a cap and the GCS entry for the trampoline onto the GCS.
+	 */
+	cap[1] = GCS_SIGNAL_CAP(gcspr_el0 - 1);
+	cap[0] = (unsigned long)sigtramp;
+	ret = copy_to_user_gcs(gcspr_el0 - 2, cap, ARRAY_SIZE(cap));
+	if (ret != 0)
+		return ret;
+
+	gcsb_dsync();
+
+	gcspr_el0 -= 2;
+	write_sysreg_s((unsigned long)gcspr_el0, SYS_GCSPR_EL0);
+
+	return 0;
+}
+#else
+
+static int gcs_signal_entry(__sigrestore_t sigtramp, struct ksignal *ksig)
+{
+	return 0;
+}
+
+#endif
+
+static int setup_return(struct pt_regs *regs, struct ksignal *ksig,
 			 struct rt_sigframe_user_layout *user, int usig)
 {
 	__sigrestore_t sigtramp;
@@ -1079,7 +1201,7 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
 	regs->regs[0] = usig;
 	regs->sp = (unsigned long)user->sigframe;
 	regs->regs[29] = (unsigned long)&user->next_frame->fp;
-	regs->pc = (unsigned long)ka->sa.sa_handler;
+	regs->pc = (unsigned long)ksig->ka.sa.sa_handler;
 
 	/*
 	 * Signal delivery is a (wacky) indirect function call in
@@ -1119,12 +1241,14 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
 		sme_smstop();
 	}
 
-	if (ka->sa.sa_flags & SA_RESTORER)
-		sigtramp = ka->sa.sa_restorer;
+	if (ksig->ka.sa.sa_flags & SA_RESTORER)
+		sigtramp = ksig->ka.sa.sa_restorer;
 	else
 		sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
 
 	regs->regs[30] = (unsigned long)sigtramp;
+
+	return gcs_signal_entry(sigtramp, ksig);
 }
 
 static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
@@ -1147,7 +1271,7 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
 	err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
 	err |= setup_sigframe(&user, regs, set);
 	if (err == 0) {
-		setup_return(regs, &ksig->ka, &user, usig);
+		err = setup_return(regs, ksig, &user, usig);
 		if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
 			err |= copy_siginfo_to_user(&frame->info, &ksig->info);
 			regs->regs[1] = (unsigned long)&frame->info;
diff --git a/arch/arm64/mm/gcs.c b/arch/arm64/mm/gcs.c
index 4a0a736800c0..ac7013fb05f3 100644
--- a/arch/arm64/mm/gcs.c
+++ b/arch/arm64/mm/gcs.c
@@ -6,6 +6,7 @@
 #include <linux/types.h>
 
 #include <asm/cpufeature.h>
+#include <asm/gcs.h>
 #include <asm/page.h>
 
 static unsigned long alloc_gcs(unsigned long addr, unsigned long size,

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 24/35] arm64/signal: Expose GCS state in signal frames
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (22 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 23/35] arm64/signal: Set up and restore the GCS context for signal handlers Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 25/35] arm64/ptrace: Expose GCS via ptrace and core files Mark Brown
                   ` (10 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Add a context for the GCS state and include it in the signal context when
running on a system that supports GCS. We reuse the same flags that the
prctl() uses to specify which GCS features are enabled and also provide the
current GCS pointer.

We do not support enabling GCS via signal return, there is a conflict
between specifying GCSPR_EL0 and allocation of a new GCS and this is not
an ancticipated use case.  We also enforce GCS configuration locking on
signal return.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/uapi/asm/sigcontext.h |   9 +++
 arch/arm64/kernel/signal.c               | 106 +++++++++++++++++++++++++++++++
 2 files changed, 115 insertions(+)

diff --git a/arch/arm64/include/uapi/asm/sigcontext.h b/arch/arm64/include/uapi/asm/sigcontext.h
index f23c1dc3f002..7b66d245f2d2 100644
--- a/arch/arm64/include/uapi/asm/sigcontext.h
+++ b/arch/arm64/include/uapi/asm/sigcontext.h
@@ -168,6 +168,15 @@ struct zt_context {
 	__u16 __reserved[3];
 };
 
+#define GCS_MAGIC	0x47435300
+
+struct gcs_context {
+	struct _aarch64_ctx head;
+	__u64 gcspr;
+	__u64 features_enabled;
+	__u64 reserved;
+};
+
 #endif /* !__ASSEMBLY__ */
 
 #include <asm/sve_context.h>
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 922b694fa0aa..83b464774cc0 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -87,6 +87,7 @@ struct rt_sigframe_user_layout {
 
 	unsigned long fpsimd_offset;
 	unsigned long esr_offset;
+	unsigned long gcs_offset;
 	unsigned long sve_offset;
 	unsigned long tpidr2_offset;
 	unsigned long za_offset;
@@ -213,6 +214,8 @@ struct user_ctxs {
 	u32 za_size;
 	struct zt_context __user *zt;
 	u32 zt_size;
+	struct gcs_context __user *gcs;
+	u32 gcs_size;
 };
 
 static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
@@ -605,6 +608,81 @@ extern int restore_zt_context(struct user_ctxs *user);
 
 #endif /* ! CONFIG_ARM64_SME */
 
+#ifdef CONFIG_ARM64_GCS
+
+static int preserve_gcs_context(struct gcs_context __user *ctx)
+{
+	int err = 0;
+	unsigned long gcspr = read_sysreg_s(SYS_GCSPR_EL0);
+
+	/*
+	 * We will add a cap token to the frame, include it in the
+	 * GCSPR_EL0 we report to support stack switching via
+	 * sigreturn.
+	 */
+	if (task_gcs_el0_enabled(current))
+		gcspr -= 8;
+
+	__put_user_error(GCS_MAGIC, &ctx->head.magic, err);
+	__put_user_error(sizeof(*ctx), &ctx->head.size, err);
+	__put_user_error(gcspr, &ctx->gcspr, err);
+	__put_user_error(current->thread.gcs_el0_mode,
+			 &ctx->features_enabled, err);
+
+	return err;
+}
+
+static int restore_gcs_context(struct user_ctxs *user)
+{
+	u64 gcspr, enabled;
+	int err = 0;
+
+	if (user->gcs_size != sizeof(*user->gcs))
+		return -EINVAL;
+
+	__get_user_error(gcspr, &user->gcs->gcspr, err);
+	__get_user_error(enabled, &user->gcs->features_enabled, err);
+	if (err)
+		return err;
+
+	/* Don't allow unknown modes */
+	if (enabled & ~PR_SHADOW_STACK_SUPPORTED_STATUS_MASK)
+		return -EINVAL;
+
+	/* Don't allow mode changes if the state has been locked */
+	if ((current->thread.gcs_el0_mode & PR_SHADOW_STACK_LOCK) &&
+	    (current->thread.gcs_el0_mode != enabled))
+		return -EINVAL;
+
+	/* Don't allow enabling */
+	if (!task_gcs_el0_enabled(current) &&
+	    (enabled & PR_SHADOW_STACK_ENABLE))
+		return -EINVAL;
+
+	/* If we are disabling disable everything */
+	if (!(enabled & PR_SHADOW_STACK_ENABLE))
+		enabled = 0;
+
+	current->thread.gcs_el0_mode = enabled;
+
+	/*
+	 * We let userspace set GCSPR_EL0 to anything here, we will
+	 * validate later in gcs_restore_signal().
+	 */
+	if (enabled & PR_SHADOW_STACK_ENABLE)
+		current->thread.gcspr_el0 = gcspr;
+
+	return 0;
+}
+
+#else /* ! CONFIG_ARM64_GCS */
+
+/* Turn any non-optimised out attempts to use these into a link error: */
+extern int preserve_gcs_context(void __user *ctx);
+extern int restore_gcs_context(struct user_ctxs *user);
+
+#endif /* ! CONFIG_ARM64_GCS */
+
 static int parse_user_sigframe(struct user_ctxs *user,
 			       struct rt_sigframe __user *sf)
 {
@@ -621,6 +699,7 @@ static int parse_user_sigframe(struct user_ctxs *user,
 	user->tpidr2 = NULL;
 	user->za = NULL;
 	user->zt = NULL;
+	user->gcs = NULL;
 
 	if (!IS_ALIGNED((unsigned long)base, 16))
 		goto invalid;
@@ -715,6 +794,17 @@ static int parse_user_sigframe(struct user_ctxs *user,
 			user->zt_size = size;
 			break;
 
+		case GCS_MAGIC:
+			if (!system_supports_gcs())
+				goto invalid;
+
+			if (user->gcs)
+				goto invalid;
+
+			user->gcs = (struct gcs_context __user *)head;
+			user->gcs_size = size;
+			break;
+
 		case EXTRA_MAGIC:
 			if (have_extra_context)
 				goto invalid;
@@ -834,6 +924,9 @@ static int restore_sigframe(struct pt_regs *regs,
 			err = restore_fpsimd_context(&user);
 	}
 
+	if (err == 0 && system_supports_gcs() && user.gcs)
+		err = restore_gcs_context(&user);
+
 	if (err == 0 && system_supports_tpidr2() && user.tpidr2)
 		err = restore_tpidr2_context(&user);
 
@@ -952,6 +1045,13 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
 			return err;
 	}
 
+	if (system_supports_gcs()) {
+		err = sigframe_alloc(user, &user->gcs_offset,
+				     sizeof(struct gcs_context));
+		if (err)
+			return err;
+	}
+
 	if (system_supports_sve() || system_supports_sme()) {
 		unsigned int vq = 0;
 
@@ -1045,6 +1145,12 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user,
 		__put_user_error(current->thread.fault_code, &esr_ctx->esr, err);
 	}
 
+	if (system_supports_gcs() && err == 0 && user->gcs_offset) {
+		struct gcs_context __user *gcs_ctx =
+			apply_user_offset(user, user->gcs_offset);
+		err |= preserve_gcs_context(gcs_ctx);
+	}
+
 	/* Scalable Vector Extension state (including streaming), if present */
 	if ((system_supports_sve() || system_supports_sme()) &&
 	    err == 0 && user->sve_offset) {

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 25/35] arm64/ptrace: Expose GCS via ptrace and core files
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (23 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 24/35] arm64/signal: Expose GCS state in signal frames Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 26/35] arm64: Add Kconfig for Guarded Control Stack (GCS) Mark Brown
                   ` (9 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Provide a new register type NT_ARM_GCS reporting the current GCS mode
and pointer for EL0.  Due to the interactions with allocation and
deallocation of Guarded Control Stacks we do not permit any changes to
the GCS mode via ptrace, only GCSPR_EL0 may be changed.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/uapi/asm/ptrace.h |  7 +++++
 arch/arm64/kernel/ptrace.c           | 50 ++++++++++++++++++++++++++++++++++++
 include/uapi/linux/elf.h             |  1 +
 3 files changed, 58 insertions(+)

diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
index 7fa2f7036aa7..342d5abaca87 100644
--- a/arch/arm64/include/uapi/asm/ptrace.h
+++ b/arch/arm64/include/uapi/asm/ptrace.h
@@ -324,6 +324,13 @@ struct user_za_header {
 #define ZA_PT_SIZE(vq)						\
 	(ZA_PT_ZA_OFFSET + ZA_PT_ZA_SIZE(vq))
 
+/* GCS state (NT_ARM_GCS) */
+
+struct user_gcs {
+	__u64 features_enabled;
+	__u64 gcspr_el0;
+};
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _UAPI__ASM_PTRACE_H */
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index d7f4f0d1ae12..09f671b8f188 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -33,6 +33,7 @@
 #include <asm/cpufeature.h>
 #include <asm/debug-monitors.h>
 #include <asm/fpsimd.h>
+#include <asm/gcs.h>
 #include <asm/mte.h>
 #include <asm/pointer_auth.h>
 #include <asm/stacktrace.h>
@@ -1390,6 +1391,42 @@ static int tagged_addr_ctrl_set(struct task_struct *target, const struct
 }
 #endif
 
+#ifdef CONFIG_ARM64_GCS
+static int gcs_get(struct task_struct *target,
+		   const struct user_regset *regset,
+		   struct membuf to)
+{
+	struct user_gcs user_gcs;
+
+	if (target == current)
+		gcs_preserve_current_state();
+
+	user_gcs.features_enabled = target->thread.gcs_el0_mode;
+	user_gcs.gcspr_el0 = target->thread.gcspr_el0;
+
+	return membuf_write(&to, &user_gcs, sizeof(user_gcs));
+}
+
+static int gcs_set(struct task_struct *target, const struct
+		   user_regset *regset, unsigned int pos,
+		   unsigned int count, const void *kbuf, const
+		   void __user *ubuf)
+{
+	int ret;
+	struct user_gcs user_gcs;
+
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &user_gcs, 0, -1);
+	if (ret)
+		return ret;
+
+	if (user_gcs.features_enabled != target->thread.gcs_el0_mode)
+		return -EBUSY;
+	target->thread.gcspr_el0 = user_gcs.gcspr_el0;
+
+	return 0;
+}
+#endif
+
 enum aarch64_regset {
 	REGSET_GPR,
 	REGSET_FPR,
@@ -1418,6 +1455,9 @@ enum aarch64_regset {
 #ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
 	REGSET_TAGGED_ADDR_CTRL,
 #endif
+#ifdef CONFIG_ARM64_GCS
+	REGSET_GCS,
+#endif
 };
 
 static const struct user_regset aarch64_regsets[] = {
@@ -1568,6 +1608,16 @@ static const struct user_regset aarch64_regsets[] = {
 		.set = tagged_addr_ctrl_set,
 	},
 #endif
+#ifdef CONFIG_ARM64_GCS
+	[REGSET_GCS] = {
+		.core_note_type = NT_ARM_GCS,
+		.n = sizeof(struct user_gcs) / sizeof(u64),
+		.size = sizeof(u64),
+		.align = sizeof(u64),
+		.regset_get = gcs_get,
+		.set = gcs_set,
+	},
+#endif
 };
 
 static const struct user_regset_view user_aarch64_view = {
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index 0c8cf359ea5b..00f698a2ab17 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -438,6 +438,7 @@ typedef struct elf64_shdr {
 #define NT_ARM_SSVE	0x40b		/* ARM Streaming SVE registers */
 #define NT_ARM_ZA	0x40c		/* ARM SME ZA registers */
 #define NT_ARM_ZT	0x40d		/* ARM SME ZT registers */
+#define NT_ARM_GCS	0x40e		/* ARM GCS state */
 #define NT_ARC_V2	0x600		/* ARCv2 accumulator/extra registers */
 #define NT_VMCOREDD	0x700		/* Vmcore Device Dump Note */
 #define NT_MIPS_DSP	0x800		/* MIPS DSP ASE registers */

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 26/35] arm64: Add Kconfig for Guarded Control Stack (GCS)
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (24 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 25/35] arm64/ptrace: Expose GCS via ptrace and core files Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-17 12:32   ` Jonathan Cameron
  2023-07-16 21:51 ` [PATCH 27/35] kselftest/arm64: Verify the GCS hwcap Mark Brown
                   ` (8 subsequent siblings)
  34 siblings, 1 reply; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Provide a Kconfig option allowing the user to select if GCS support is
built into the kernel.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/Kconfig | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 7856c3a3e35a..e1aeeda13c52 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2091,6 +2091,25 @@ config ARM64_EPAN
 	  if the cpu does not implement the feature.
 endmenu # "ARMv8.7 architectural features"
 
+menu "v9.4 architectural features"
+
+config ARM64_GCS
+	bool "Enable support for Guarded Control Stack (GCS)"
+	default y
+	select ARCH_USES_HIGH_VMA_FLAGS
+	help
+	  Guarded Control Stack (GCS) provides support for a separate
+	  stack with restricted access which contains only return
+	  addresses.  This can be used to harden against some attacks
+	  by comparing return address used by the program with what is
+	  stored in the GCS, and may also be used to efficiently obtain
+	  the call stack for applications such as profiling.
+
+	  The feature is detected at runtime, and will remain disabled
+	  if the system does not implement the feature.
+
+endmenu # "2022 archiectural features"
+
 config ARM64_SVE
 	bool "ARM Scalable Vector Extension support"
 	default y

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 27/35] kselftest/arm64: Verify the GCS hwcap
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (25 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 26/35] arm64: Add Kconfig for Guarded Control Stack (GCS) Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 28/35] kselftest/arm64: Add GCS as a detected feature in the signal tests Mark Brown
                   ` (7 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Add coverage of the GCS hwcap to the hwcap selftest, using a read of
GCSPR_EL0 to generate SIGILL without having to worry about enabling GCS.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 tools/testing/selftests/arm64/abi/hwcap.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/tools/testing/selftests/arm64/abi/hwcap.c b/tools/testing/selftests/arm64/abi/hwcap.c
index d4ad813fed10..38844e4c5aae 100644
--- a/tools/testing/selftests/arm64/abi/hwcap.c
+++ b/tools/testing/selftests/arm64/abi/hwcap.c
@@ -39,6 +39,17 @@ static void cssc_sigill(void)
 	asm volatile(".inst 0xdac01c00" : : : "x0");
 }
 
+static void gcs_sigill(void)
+{
+	unsigned long *gcspr;
+
+	asm volatile(
+		"mrs	%0, S3_3_C2_C5_1"
+	: "=r" (gcspr)
+	:
+	: "cc");
+}
+
 static void mops_sigill(void)
 {
 	char dst[1], src[1];
@@ -223,6 +234,14 @@ static const struct hwcap_data {
 		.cpuinfo = "cssc",
 		.sigill_fn = cssc_sigill,
 	},
+	{
+		.name = "GCS",
+		.at_hwcap = AT_HWCAP2,
+		.hwcap_bit = HWCAP2_GCS,
+		.cpuinfo = "gcs",
+		.sigill_fn = gcs_sigill,
+		.sigill_reliable = true,
+	},
 	{
 		.name = "MOPS",
 		.at_hwcap = AT_HWCAP2,

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 28/35] kselftest/arm64: Add GCS as a detected feature in the signal tests
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (26 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 27/35] kselftest/arm64: Verify the GCS hwcap Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 29/35] kselftest/arm64: Add framework support for GCS to signal handling tests Mark Brown
                   ` (6 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

In preparation for testing GCS related signal handling add it as a feature
we check for in the signal handling support code.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 tools/testing/selftests/arm64/signal/test_signals.h       | 2 ++
 tools/testing/selftests/arm64/signal/test_signals_utils.c | 3 +++
 2 files changed, 5 insertions(+)

diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
index 1e6273d81575..7ada43688c02 100644
--- a/tools/testing/selftests/arm64/signal/test_signals.h
+++ b/tools/testing/selftests/arm64/signal/test_signals.h
@@ -35,6 +35,7 @@ enum {
 	FSME_BIT,
 	FSME_FA64_BIT,
 	FSME2_BIT,
+	FGCS_BIT,
 	FMAX_END
 };
 
@@ -43,6 +44,7 @@ enum {
 #define FEAT_SME		(1UL << FSME_BIT)
 #define FEAT_SME_FA64		(1UL << FSME_FA64_BIT)
 #define FEAT_SME2		(1UL << FSME2_BIT)
+#define FEAT_GCS		(1UL << FGCS_BIT)
 
 /*
  * A descriptor used to describe and configure a test case.
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
index 0dc948db3a4a..89ef95c1af0e 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
@@ -30,6 +30,7 @@ static char const *const feats_names[FMAX_END] = {
 	" SME ",
 	" FA64 ",
 	" SME2 ",
+	" GCS ",
 };
 
 #define MAX_FEATS_SZ	128
@@ -329,6 +330,8 @@ int test_init(struct tdescr *td)
 			td->feats_supported |= FEAT_SME_FA64;
 		if (getauxval(AT_HWCAP2) & HWCAP2_SME2)
 			td->feats_supported |= FEAT_SME2;
+		if (getauxval(AT_HWCAP2) & HWCAP2_GCS)
+			td->feats_supported |= FEAT_GCS;
 		if (feats_ok(td)) {
 			if (td->feats_required & td->feats_supported)
 				fprintf(stderr,

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 29/35] kselftest/arm64: Add framework support for GCS to signal handling tests
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (27 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 28/35] kselftest/arm64: Add GCS as a detected feature in the signal tests Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 30/35] kselftest/arm64: Allow signals tests to specify an expected si_code Mark Brown
                   ` (5 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Teach the framework about the GCS signal context, avoiding warnings on
the unknown context.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 tools/testing/selftests/arm64/signal/testcases/testcases.c | 7 +++++++
 tools/testing/selftests/arm64/signal/testcases/testcases.h | 1 +
 2 files changed, 8 insertions(+)

diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
index 9f580b55b388..1cd124732be4 100644
--- a/tools/testing/selftests/arm64/signal/testcases/testcases.c
+++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
@@ -209,6 +209,13 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
 			zt = (struct zt_context *)head;
 			new_flags |= ZT_CTX;
 			break;
+		case GCS_MAGIC:
+			if (flags & GCS_CTX)
+				*err = "Multiple GCS_MAGIC";
+			if (head->size != sizeof(struct gcs_context))
+				*err = "Bad size for gcs_context";
+			new_flags |= GCS_CTX;
+			break;
 		case EXTRA_MAGIC:
 			if (flags & EXTRA_CTX)
 				*err = "Multiple EXTRA_MAGIC";
diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.h b/tools/testing/selftests/arm64/signal/testcases/testcases.h
index a08ab0d6207a..9b2599745c29 100644
--- a/tools/testing/selftests/arm64/signal/testcases/testcases.h
+++ b/tools/testing/selftests/arm64/signal/testcases/testcases.h
@@ -19,6 +19,7 @@
 #define ZA_CTX		(1 << 2)
 #define EXTRA_CTX	(1 << 3)
 #define ZT_CTX		(1 << 4)
+#define GCS_CTX		(1 << 5)
 
 #define KSFT_BAD_MAGIC	0xdeadbeef
 

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 30/35] kselftest/arm64: Allow signals tests to specify an expected si_code
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (28 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 29/35] kselftest/arm64: Add framework support for GCS to signal handling tests Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 31/35] kselftest/arm64: Always run signals tests with GCS enabled Mark Brown
                   ` (4 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Currently we ignore si_code unless the expected signal is a SIGSEGV, in
which case we enforce it being SEGV_ACCERR. Allow test cases to specify
exactly which si_code should be generated so we can validate this, and
test for other segfault codes.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 .../testing/selftests/arm64/signal/test_signals.h  |  4 +++
 .../selftests/arm64/signal/test_signals_utils.c    | 29 ++++++++++++++--------
 2 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
index 7ada43688c02..ee75a2c25ce7 100644
--- a/tools/testing/selftests/arm64/signal/test_signals.h
+++ b/tools/testing/selftests/arm64/signal/test_signals.h
@@ -71,6 +71,10 @@ struct tdescr {
 	 * Zero when no signal is expected on success
 	 */
 	int			sig_ok;
+	/*
+	 * expected si_code for sig_ok, or 0 to not check
+	 */
+	int			sig_ok_code;
 	/* signum expected on unsupported CPU features. */
 	int			sig_unsupp;
 	/* a timeout in second for test completion */
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
index 89ef95c1af0e..63deca32b0df 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
@@ -143,16 +143,25 @@ static bool handle_signal_ok(struct tdescr *td,
 			"current->token ZEROED...test is probably broken!\n");
 		abort();
 	}
-	/*
-	 * Trying to narrow down the SEGV to the ones generated by Kernel itself
-	 * via arm64_notify_segfault(). This is a best-effort check anyway, and
-	 * the si_code check may need to change if this aspect of the kernel
-	 * ABI changes.
-	 */
-	if (td->sig_ok == SIGSEGV && si->si_code != SEGV_ACCERR) {
-		fprintf(stdout,
-			"si_code != SEGV_ACCERR...test is probably broken!\n");
-		abort();
+	if (td->sig_ok_code) {
+		if (si->si_code != td->sig_ok_code) {
+			fprintf(stdout, "si_code is %d not %d\n",
+				si->si_code, td->sig_ok_code);
+			abort();
+		}
+	} else {
+		/*
+		 * Trying to narrow down the SEGV to the ones
+		 * generated by Kernel itself via
+		 * arm64_notify_segfault(). This is a best-effort
+		 * check anyway, and the si_code check may need to
+		 * change if this aspect of the kernel ABI changes.
+		 */
+		if (td->sig_ok == SIGSEGV && si->si_code != SEGV_ACCERR) {
+			fprintf(stdout,
+				"si_code != SEGV_ACCERR...test is probably broken!\n");
+			abort();
+		}
 	}
 	td->pass = 1;
 	/*

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 31/35] kselftest/arm64: Always run signals tests with GCS enabled
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (29 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 30/35] kselftest/arm64: Allow signals tests to specify an expected si_code Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 32/35] kselftest/arm64: Add very basic GCS test program Mark Brown
                   ` (3 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Since it is not possible to return from the function that enabled GCS
without disabling GCS it is very inconvenient to use the signal handling
tests to cover GCS when GCS is not enabled by the toolchain and runtime,
something that no current distribution does. Since none of the testcases
do anything with stacks that would cause problems with GCS we can sidestep
this issue by unconditionally enabling GCS on startup and exiting with a
call to exit() rather than a return from main().

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 .../testing/selftests/arm64/signal/test_signals.c  | 17 ++++++++++++-
 .../selftests/arm64/signal/test_signals_utils.h    | 29 ++++++++++++++++++++++
 2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/arm64/signal/test_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
index 00051b40d71e..30e95f50db19 100644
--- a/tools/testing/selftests/arm64/signal/test_signals.c
+++ b/tools/testing/selftests/arm64/signal/test_signals.c
@@ -7,6 +7,10 @@
  * Each test provides its own tde struct tdescr descriptor to link with
  * this wrapper. Framework provides common helpers.
  */
+
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+
 #include <kselftest.h>
 
 #include "test_signals.h"
@@ -16,6 +20,16 @@ struct tdescr *current = &tde;
 
 int main(int argc, char *argv[])
 {
+	/*
+	 * Ensure GCS is at least enabled throughout the tests if
+	 * supported, otherwise the inability to return from the
+	 * function that enabled GCS makes it very inconvenient to set
+	 * up test cases.  The prctl() may fail if GCS was locked by
+	 * libc setup code.
+	 */
+	if (getauxval(AT_HWCAP2) & HWCAP2_GCS)
+		gcs_set_state(PR_SHADOW_STACK_ENABLE);
+
 	ksft_print_msg("%s :: %s\n", current->name, current->descr);
 	if (test_setup(current) && test_init(current)) {
 		test_run(current);
@@ -23,5 +37,6 @@ int main(int argc, char *argv[])
 	}
 	test_result(current);
 
-	return current->result;
+	/* Do not return in case GCS was enabled */
+	exit(current->result);
 }
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
index 222093f51b67..1cea64986baa 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
@@ -16,6 +16,35 @@ void test_cleanup(struct tdescr *td);
 int test_run(struct tdescr *td);
 void test_result(struct tdescr *td);
 
+#ifndef __NR_prctl
+#define __NR_prctl 167
+#endif
+
+/*
+ * The prctl takes 1 argument but we need to ensure that the other
+ * values passed in registers to the syscall are zero since the kernel
+ * validates them.
+ */
+#define gcs_set_state(state)					\
+	({								\
+		register long _num  __asm__ ("x8") = __NR_prctl;	\
+		register long _arg1 __asm__ ("x0") =  PR_SET_SHADOW_STACK_STATUS; \
+		register long _arg2 __asm__ ("x1") = (long)(state);	\
+		register long _arg3 __asm__ ("x2") = 0;			\
+		register long _arg4 __asm__ ("x3") = 0;			\
+		register long _arg5 __asm__ ("x4") = 0;			\
+	                                                                      \
+		__asm__  volatile (					\
+			"svc #0\n"					\
+			: "=r"(_arg1)					\
+			: "r"(_arg1), "r"(_arg2),			\
+			  "r"(_arg3), "r"(_arg4),			\
+			  "r"(_arg5), "r"(_num)				\
+			: "memory", "cc"				\
+			);						\
+		_arg1;							\
+	})
+
 static inline bool feats_ok(struct tdescr *td)
 {
 	if (td->feats_incompatible & td->feats_supported)

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 32/35] kselftest/arm64: Add very basic GCS test program
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (30 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 31/35] kselftest/arm64: Always run signals tests with GCS enabled Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 33/35] kselftest/arm64: Add a GCS test program built with the system libc Mark Brown
                   ` (2 subsequent siblings)
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

This test program just covers the basic GCS ABI, covering aspects of the
ABI as standalone features without attempting to integrate things.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 tools/testing/selftests/arm64/Makefile        |   2 +-
 tools/testing/selftests/arm64/gcs/.gitignore  |   1 +
 tools/testing/selftests/arm64/gcs/Makefile    |  17 ++
 tools/testing/selftests/arm64/gcs/basic-gcs.c | 350 ++++++++++++++++++++++++++
 tools/testing/selftests/arm64/gcs/gcs-util.h  |  65 +++++
 5 files changed, 434 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
index 9460cbe81bcc..fd5d8d85aecb 100644
--- a/tools/testing/selftests/arm64/Makefile
+++ b/tools/testing/selftests/arm64/Makefile
@@ -4,7 +4,7 @@
 ARCH ?= $(shell uname -m 2>/dev/null || echo not)
 
 ifneq (,$(filter $(ARCH),aarch64 arm64))
-ARM64_SUBTARGETS ?= tags signal pauth fp mte bti abi
+ARM64_SUBTARGETS ?= tags signal pauth fp mte bti abi gcs
 else
 ARM64_SUBTARGETS :=
 endif
diff --git a/tools/testing/selftests/arm64/gcs/.gitignore b/tools/testing/selftests/arm64/gcs/.gitignore
new file mode 100644
index 000000000000..0e5e695ecba5
--- /dev/null
+++ b/tools/testing/selftests/arm64/gcs/.gitignore
@@ -0,0 +1 @@
+basic-gcs
diff --git a/tools/testing/selftests/arm64/gcs/Makefile b/tools/testing/selftests/arm64/gcs/Makefile
new file mode 100644
index 000000000000..322c40d25f2e
--- /dev/null
+++ b/tools/testing/selftests/arm64/gcs/Makefile
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2023 ARM Limited
+#
+# In order to avoid interaction with the toolchain and dynamic linker the
+# portions of these tests that interact with the GCS are implemented using
+# nolibc.
+#
+
+TEST_GEN_PROGS := basic-gcs
+
+include ../../lib.mk
+
+$(OUTPUT)/basic-gcs: basic-gcs.c
+	$(CC) -g -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \
+		-static -include ../../../../include/nolibc/nolibc.h \
+		-std=gnu99 -I../.. -g \
+		-ffreestanding -Wall $^ -o $@ -lgcc
diff --git a/tools/testing/selftests/arm64/gcs/basic-gcs.c b/tools/testing/selftests/arm64/gcs/basic-gcs.c
new file mode 100644
index 000000000000..1cc14836c991
--- /dev/null
+++ b/tools/testing/selftests/arm64/gcs/basic-gcs.c
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 ARM Limited.
+ */
+
+#include <limits.h>
+#include <stdbool.h>
+
+#include <linux/prctl.h>
+
+#include "kselftest.h"
+#include "gcs-util.h"
+
+/* nolibc doesn't have sysconf(), just hard code the maximum */
+static size_t page_size = 65536;
+
+static  __attribute__((noinline)) void valid_gcs_function(void)
+{
+	/* Do something the compiler can't optimise out */
+	my_syscall1(__NR_prctl, PR_SVE_GET_VL);
+}
+
+static inline int gcs_set_status(unsigned long mode)
+{
+	int ret;
+	unsigned long new_mode;
+
+	/*
+	 * The prctl takes 1 argument but we need to ensure that the
+	 * other 3 values passed in registers to the syscall are zero
+	 * since the kernel validates them.
+	 */
+	ret = my_syscall5(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, mode,
+			  0, 0, 0);
+
+	if (ret == 0) {
+		ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
+				  &new_mode, 0, 0, 0);
+		if (ret == 0) {
+			if (new_mode != mode) {
+				ksft_print_msg("Mode set to %x not %x\n",
+					       new_mode, mode);
+				ret = -EINVAL;
+			}
+		} else {
+			ksft_print_msg("Failed to validate mode: %d\n", ret);
+		}
+	}
+
+	return ret;
+}
+
+/* Try to read the status */
+static bool read_status(void)
+{
+	unsigned long state;
+	int ret;
+
+	ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
+			  &state, 0, 0, 0);
+	if (ret != 0) {
+		ksft_print_msg("Failed to read state: %d\n", ret);
+		return false;
+	}
+
+	return state & PR_SHADOW_STACK_ENABLE;
+}
+
+/* Just a straight enable */
+static bool base_enable(void)
+{
+	int ret;
+
+	ret = gcs_set_status(PR_SHADOW_STACK_ENABLE);
+	if (ret) {
+		ksft_print_msg("PR_SHADOW_STACK_ENABLE failed %d\n", ret);
+		return false;
+	}
+
+	return true;
+}
+
+/* Check we can read GCSPR_EL0 when GCS is enabled */
+static bool read_gcspr_el0(void)
+{
+	unsigned long *gcspr_el0;
+
+	ksft_print_msg("GET GCSPR\n");
+	gcspr_el0 = get_gcspr();
+	ksft_print_msg("GCSPR_EL0 is %p\n", gcspr_el0);
+
+	return true;
+}
+
+/* Also allow writes to stack */
+static bool enable_writeable(void)
+{
+	int ret;
+
+	ret = gcs_set_status(PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE);
+	if (ret) {
+		ksft_print_msg("PR_SHADOW_STACK_ENABLE writeable failed: %d\n", ret);
+		return false;
+	}
+
+	ret = gcs_set_status(PR_SHADOW_STACK_ENABLE);
+	if (ret) {
+		ksft_print_msg("failed to restore plain enable %d\n", ret);
+		return false;
+	}
+
+	return true;
+}
+
+/* Also allow writes to stack */
+static bool enable_push_pop(void)
+{
+	int ret;
+
+	ret = gcs_set_status(PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_PUSH);
+	if (ret) {
+		ksft_print_msg("PR_SHADOW_STACK_ENABLE with push failed: %d\n",
+			       ret);
+		return false;
+	}
+
+	ret = gcs_set_status(PR_SHADOW_STACK_ENABLE);
+	if (ret) {
+		ksft_print_msg("failed to restore plain enable %d\n", ret);
+		return false;
+	}
+
+	return true;
+}
+
+/* Enable GCS and allow everything */
+static bool enable_all(void)
+{
+	int ret;
+
+	ret = gcs_set_status(PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_PUSH |
+			     PR_SHADOW_STACK_WRITE);
+	if (ret) {
+		ksft_print_msg("PR_SHADOW_STACK_ENABLE with everything failed: %d\n",
+			       ret);
+		return false;
+	}
+
+	ret = gcs_set_status(PR_SHADOW_STACK_ENABLE);
+	if (ret) {
+		ksft_print_msg("failed to restore plain enable %d\n", ret);
+		return false;
+	}
+
+	return true;
+}
+
+static bool enable_invalid(void)
+{
+	int ret = gcs_set_status(ULONG_MAX);
+	if (ret == 0) {
+		ksft_print_msg("GCS_SET_STATUS %lx succeeded\n", ULONG_MAX);
+		return false;
+	}
+
+	return true;
+}
+
+/* Map a GCS */
+static bool map_guarded_stack(void)
+{
+	int ret;
+	uint64_t *buf;
+	uint64_t expected_cap;
+	int elem;
+	bool pass = true;
+
+	buf = (void *)my_syscall3(__NR_map_shadow_stack, 0, page_size, 0);
+	if (buf == MAP_FAILED) {
+		ksft_print_msg("Failed to map %d byte GCS: %d\n",
+			       page_size, errno);
+		return false;
+	}
+	ksft_print_msg("Mapped GCS at %p-%p\n", buf,
+		       (uint64_t)buf + page_size);
+
+	/* The top of the newly allocated region should be 0 */
+	elem = (page_size / sizeof(uint64_t)) - 1;
+	if (buf[elem]) {
+		ksft_print_msg("Last entry is 0x%lx not 0x0\n", buf[elem]);
+		pass = false;
+	}
+
+	/* Then a valid cap token */
+	elem--;
+	expected_cap = ((uint64_t)buf + page_size - 16);
+	expected_cap &= GCS_CAP_ADDR_MASK;
+	expected_cap |= GCS_CAP_VALID_TOKEN;
+	if (buf[elem] != expected_cap) {
+		ksft_print_msg("Cap entry is 0x%lx not 0x%lx\n",
+			       buf[elem], expected_cap);
+		pass = false;
+	}
+	ksft_print_msg("cap token is 0x%lx\n", buf[elem]);
+
+	/* The rest should be zeros */
+	for (elem = 0; elem < page_size / sizeof(uint64_t) - 2; elem++) {
+		if (!buf[elem])
+			continue;
+		ksft_print_msg("GCS slot %d is 0x%lx not 0x0\n",
+			       elem, buf[elem]);
+		pass = false;
+	}
+
+	ret = munmap(buf, page_size);
+	if (ret != 0) {
+		ksft_print_msg("Failed to unmap %d byte GCS: %d\n",
+			       page_size, errno);
+		pass = false;
+	}
+
+	return pass;
+}
+
+/* A fork()ed process can run */
+static bool test_fork(void)
+{
+	unsigned long child_mode;
+	int ret, status;
+	pid_t pid;
+	bool pass = true;
+
+	pid = fork();
+	if (pid == -1) {
+		ksft_print_msg("fork() failed: %d\n", errno);
+		pass = false;
+		goto out;
+	}
+	if (pid == 0) {
+		/* In child, make sure we can call a function, read
+		 * the GCS pointer and status and then exit */
+		valid_gcs_function();
+		get_gcspr();
+
+		ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
+				  &child_mode, 0, 0, 0);
+		if (ret == 0 && !(child_mode & PR_SHADOW_STACK_ENABLE)) {
+			ksft_print_msg("GCS not enabled in child\n");
+			ret = -EINVAL;
+		}
+
+		exit(ret);
+	}
+
+	/*
+	 * In parent, check we can still do function calls then block
+	 * for the child.
+	 */
+	valid_gcs_function();
+
+	ksft_print_msg("Waiting for child %d\n", pid);
+
+	ret = waitpid(pid, &status, 0);
+	if (ret == -1) {
+		ksft_print_msg("Failed to wait for child: %d\n",
+			       errno);
+		return false;
+	}
+
+	if (!WIFEXITED(status)) {
+		ksft_print_msg("Child exited due to signal %d\n",
+			       WTERMSIG(status));
+		pass = false;
+	} else {
+		if (WEXITSTATUS(status)) {
+			ksft_print_msg("Child exited with status %d\n",
+				       WEXITSTATUS(status));
+			pass = false;
+		}
+	}
+
+out:
+
+	return pass;
+}
+
+typedef bool (*gcs_test)(void);
+
+static struct {
+	char *name;
+	gcs_test test;
+	bool needs_enable;
+} tests[] = {
+	{ "read_status", read_status },
+	{ "base_enable", base_enable, true },
+	{ "read_gcspr_el0", read_gcspr_el0 },
+	{ "enable_writeable", enable_writeable, true },
+	{ "enable_push_pop", enable_push_pop, true },
+	{ "enable_all", enable_all, true },
+	{ "enable_invalid", enable_invalid, true },
+	{ "map_guarded_stack", map_guarded_stack },
+	{ "fork", test_fork },
+};
+
+int main(void)
+{
+	int i, ret;
+	unsigned long gcs_mode;
+	bool gcs_locked;
+
+	ksft_print_header();
+
+	/*
+	 * We don't have getauxval() with nolibc so treat a failure to
+	 * read GCS state as a lack of support and skip.
+	 */
+	ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
+			  &gcs_mode, 0, 0, 0);
+	if (ret != 0)
+		ksft_exit_skip("Failed to read GCS state: %d\n", ret);
+
+	if (!(gcs_mode & PR_SHADOW_STACK_ENABLE)) {
+		gcs_mode = PR_SHADOW_STACK_ENABLE;
+		ret = my_syscall5(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,
+				  gcs_mode, 0, 0, 0);
+		if (ret != 0)
+			ksft_exit_fail_msg("Failed to enable GCS: %d\n", ret);
+	}
+
+	gcs_locked = gcs_mode & PR_SHADOW_STACK_LOCK;
+
+	ksft_set_plan(ARRAY_SIZE(tests));
+
+	for (i = 0; i < ARRAY_SIZE(tests); i++) {
+		if (gcs_locked && tests[i].needs_enable)
+			ksft_test_result_skip("%s\n", tests[i].name);
+		else
+			ksft_test_result((*tests[i].test)(), "%s\n",
+					 tests[i].name);
+	}
+
+	/* One last test: disable GCS, we can do this one time */
+	my_syscall5(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 0, 0, 0, 0);
+	if (ret != 0)
+		ksft_print_msg("Failed to disable GCS: %d\n", ret);
+
+	ksft_finished();
+
+	return 0;
+}
diff --git a/tools/testing/selftests/arm64/gcs/gcs-util.h b/tools/testing/selftests/arm64/gcs/gcs-util.h
new file mode 100644
index 000000000000..90130c77463e
--- /dev/null
+++ b/tools/testing/selftests/arm64/gcs/gcs-util.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 ARM Limited.
+ */
+
+#ifndef GCS_UTIL_H
+#define GCS_UTIL_H
+
+#include <stdbool.h>
+
+#ifndef __NR_map_shadow_stack
+#define __NR_map_shadow_stack 452
+#endif
+
+#ifndef __NR_prctl
+#define __NR_prctl 167
+#endif
+
+/* Shadow Stack/Guarded Control Stack interface */
+#define PR_GET_SHADOW_STACK_STATUS	71
+#define PR_SET_SHADOW_STACK_STATUS      72
+# define PR_SHADOW_STACK_LOCK           (1UL << 0)
+# define PR_SHADOW_STACK_ENABLE         (1UL << 1)
+# define PR_SHADOW_STACK_WRITE		(1UL << 2)
+# define PR_SHADOW_STACK_PUSH		(1UL << 3)
+
+#define GCS_CAP_ADDR_MASK	(0xfffffffffffff000UL)
+#define GCS_CAP_VALID_TOKEN	1
+
+static unsigned long *get_gcspr(void)
+{
+	unsigned long *gcspr;
+
+	asm volatile(
+		"mrs	%0, S3_3_C2_C5_1"
+	: "=r" (gcspr)
+	:
+	: "cc");
+
+	return gcspr;
+}
+
+static inline void __attribute__((always_inline)) gcsss1(unsigned long Xt)
+{
+	asm volatile (
+		"sys #3, C7, C7, #2, %0\n"
+		:
+		: "rZ" (Xt)
+		: "memory");
+}
+
+static inline unsigned long __attribute__((always_inline)) gcsss2(void)
+{
+	unsigned long Xt;
+
+	asm volatile(
+		"SYSL %0, #3, C7, C7, #3\n"
+		: "=r" (Xt)
+		:
+		: "memory");
+
+	return Xt;
+}
+
+#endif

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 33/35] kselftest/arm64: Add a GCS test program built with the system libc
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (31 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 32/35] kselftest/arm64: Add very basic GCS test program Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 34/35] selftests/arm64: Add GCS signal tests Mark Brown
  2023-07-16 21:51 ` [PATCH 35/35] kselftest/arm64: Enable GCS for the FP stress tests Mark Brown
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

There are things like threads which nolibc struggles with which we want
to add coverage for, and the ABI allows us to test most of these even if
libc itself does not understand GCS so add a test application built
using the system libc.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 tools/testing/selftests/arm64/gcs/.gitignore |   1 +
 tools/testing/selftests/arm64/gcs/Makefile   |   4 +-
 tools/testing/selftests/arm64/gcs/libc-gcs.c | 217 +++++++++++++++++++++++++++
 3 files changed, 221 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/arm64/gcs/.gitignore b/tools/testing/selftests/arm64/gcs/.gitignore
index 0e5e695ecba5..5810c4a163d4 100644
--- a/tools/testing/selftests/arm64/gcs/.gitignore
+++ b/tools/testing/selftests/arm64/gcs/.gitignore
@@ -1 +1,2 @@
 basic-gcs
+libc-gcs
diff --git a/tools/testing/selftests/arm64/gcs/Makefile b/tools/testing/selftests/arm64/gcs/Makefile
index 322c40d25f2e..31fbd3a6bf27 100644
--- a/tools/testing/selftests/arm64/gcs/Makefile
+++ b/tools/testing/selftests/arm64/gcs/Makefile
@@ -6,7 +6,9 @@
 # nolibc.
 #
 
-TEST_GEN_PROGS := basic-gcs
+TEST_GEN_PROGS := basic-gcs libc-gcs
+
+LDLIBS+=-lpthread
 
 include ../../lib.mk
 
diff --git a/tools/testing/selftests/arm64/gcs/libc-gcs.c b/tools/testing/selftests/arm64/gcs/libc-gcs.c
new file mode 100644
index 000000000000..7ac3c3a2da52
--- /dev/null
+++ b/tools/testing/selftests/arm64/gcs/libc-gcs.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 ARM Limited.
+ */
+
+#include <pthread.h>
+#include <stdbool.h>
+
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+
+#include <asm/hwcap.h>
+
+#include "kselftest_harness.h"
+
+#include "gcs-util.h"
+
+#define my_syscall2(num, arg1, arg2)                                          \
+({                                                                            \
+	register long _num  __asm__ ("x8") = (num);                           \
+	register long _arg1 __asm__ ("x0") = (long)(arg1);                    \
+	register long _arg2 __asm__ ("x1") = (long)(arg2);                    \
+	register long _arg3 __asm__ ("x2") = 0;                               \
+	register long _arg4 __asm__ ("x3") = 0;                               \
+	register long _arg5 __asm__ ("x4") = 0;                               \
+	                                                                      \
+	__asm__  volatile (                                                   \
+		"svc #0\n"                                                    \
+		: "=r"(_arg1)                                                 \
+		: "r"(_arg1), "r"(_arg2),                                     \
+		  "r"(_arg3), "r"(_arg4),                                     \
+		  "r"(_arg5), "r"(_num)					      \
+		: "memory", "cc"                                              \
+	);                                                                    \
+	_arg1;                                                                \
+})
+
+static  __attribute__((noinline)) void valid_gcs_function(void)
+{
+	/* Do something the compiler can't optimise out */
+	prctl(PR_SVE_GET_VL);
+}
+
+/* Smoke test that a function call and return works*/
+TEST(can_call_function)
+{
+	valid_gcs_function();
+}
+
+/* Smoke test that GCS is enabled in the current thread */
+TEST(gcs_locked)
+{
+	unsigned long gcs_mode;
+	int ret;
+
+	ret = my_syscall2(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &gcs_mode);
+	ASSERT_EQ(ret, 0);
+	if (ret != 0)
+		return;
+
+	/* We are locked, even a noop reconfiguration should fail */
+	ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, gcs_mode);
+	ASSERT_NE(0, ret);
+}
+
+static void *gcs_test_thread(void *arg)
+{
+	int ret;
+	unsigned long mode;
+
+	/*
+	 * Some libcs don't seem to fill unused arguments with 0 but
+	 * the kernel validates this so we supply all 5 arguments.
+	 */
+	ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0);
+	if (ret != 0) {
+		ksft_print_msg("PR_GET_SHADOW_STACK_STATUS failed: %d\n", ret);
+		return NULL;
+	}
+
+	if (!(mode & PR_SHADOW_STACK_ENABLE)) {
+		ksft_print_msg("GCS not enabled in thread, mode is %u\n",
+			       mode);
+		return NULL;
+	}
+
+	/* Just in case... */
+	valid_gcs_function();
+
+	/* Use a non-NULL value to indicate a pass */
+	return &gcs_test_thread;
+}
+
+/* Verify that if we start a new thread it has GCS enabled */
+TEST(gcs_enabled_thread)
+{
+	pthread_t thread;
+	void *thread_ret;
+	int ret;
+
+	ret = pthread_create(&thread, NULL, gcs_test_thread, NULL);
+	ASSERT_TRUE(ret == 0);
+	if (ret != 0)
+		return;
+
+	ret = pthread_join(thread, &thread_ret);
+	ASSERT_TRUE(ret == 0);
+	if (ret != 0)
+		return;
+
+	ASSERT_TRUE(thread_ret != NULL);
+}
+
+/* Read the GCS until we find the terminator */
+TEST(gcs_find_terminator)
+{
+	uint64_t *gcs, *cur;
+
+	gcs = get_gcspr();
+	cur = gcs;
+	while (*cur)
+		cur++;
+
+	ksft_print_msg("GCS in use from %p-%p\n", gcs, cur);
+
+	/*
+	 * We should have at least whatever called into this test so
+	 * the two pointer should differ.
+	 */
+	ASSERT_TRUE(gcs != cur);
+}
+
+/* We can switch between stacks */
+TEST(switch_stacks)
+{
+	unsigned long orig_gcspr_el0, pivot_gcspr_el0;
+	unsigned long buf_base, buf_end;
+	int ret;
+	void *buf;
+
+	buf = (void *)syscall(__NR_map_shadow_stack, 0,
+			      sysconf(_SC_PAGE_SIZE), 0);
+	ASSERT_FALSE(buf == MAP_FAILED);
+	buf_base = (unsigned long)buf;
+	buf_end = buf_base + sysconf(_SC_PAGE_SIZE);
+
+	/* Skip over the stack terminator and point at the cap */
+	pivot_gcspr_el0 = buf_end - 16;
+
+	ksft_print_msg("Mapped GCS at %p-%p\n", buf, buf_end);
+
+	/* Pivot to the new GCS */
+	ksft_print_msg("pivoting to %p from %p, target has value 0x%lx\n",
+		       pivot_gcspr_el0, get_gcspr(),
+		       *((unsigned long *)pivot_gcspr_el0));
+	gcsss1(pivot_gcspr_el0);
+	orig_gcspr_el0 = gcsss2();
+	ksft_print_msg("pivoted to %p from %p, target has value 0x%lx\n",
+		       pivot_gcspr_el0, get_gcspr(),
+		       *((uint64_t *)pivot_gcspr_el0));
+
+	/* New GCS must be in the new buffer */
+	ASSERT_TRUE((unsigned long)get_gcspr() < buf_base);
+	ASSERT_TRUE((unsigned long)get_gcspr() > buf_end);
+
+	/* Make sure we can still do calls */
+	valid_gcs_function();
+	ksft_print_msg("Pivoted to %p\n", get_gcspr());
+
+	/* Pivot back to the original GCS */
+	gcsss1(orig_gcspr_el0);
+	pivot_gcspr_el0 = gcsss2();
+
+	valid_gcs_function();
+	ksft_print_msg("Pivoted back to 0x%lx\n", get_gcspr());
+
+	ret = munmap(buf, sysconf(_SC_PAGE_SIZE));
+	ASSERT_EQ(ret, 0);
+}
+
+int main(int argc, char **argv)
+{
+	unsigned long gcs_mode;
+	int ret;
+
+	if (!(getauxval(AT_HWCAP2) & HWCAP2_GCS))
+		ksft_exit_skip("SKIP GCS not supported\n");
+
+	/* 
+	 * Force shadow stacks on, our tests *should* be fine with or
+	 * without libc support and with or without this having ended
+	 * up tagged for GCS and enabled by the dynamic linker.  We
+	 * can't use the libc prctl() function since we can't return
+	 * from enabling the stack.  Also lock GCS if not already
+	 * locked so we can test behaviour when it's locked.
+	 */
+	ret = my_syscall2(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &gcs_mode);
+	if (ret) {
+		ksft_print_msg("Failed to read GCS state: %d\n", ret);
+		return EXIT_FAILURE;
+	}
+	
+	/* If we are already locked we can't configure */
+	if (!(gcs_mode & PR_SHADOW_STACK_LOCK)) {
+		gcs_mode |= PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_LOCK;
+
+		ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,
+				  gcs_mode);
+		if (ret) {
+			ksft_print_msg("Failed to configure GCS: %d\n", ret);
+			return EXIT_FAILURE;
+		}
+	}
+
+	/* Avoid returning in case libc doesn't understand GCS */
+	exit(test_harness_run(argc, argv));
+}

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 34/35] selftests/arm64: Add GCS signal tests
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (32 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 33/35] kselftest/arm64: Add a GCS test program built with the system libc Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  2023-07-16 21:51 ` [PATCH 35/35] kselftest/arm64: Enable GCS for the FP stress tests Mark Brown
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

Do some testing of the signal handling for GCS, checking that a GCS
frame has the expected information in it and that the expected signals
are delivered with invalid operations.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 tools/testing/selftests/arm64/signal/.gitignore    |  1 +
 .../selftests/arm64/signal/test_signals_utils.h    | 10 +++
 .../arm64/signal/testcases/gcs_exception_fault.c   | 59 ++++++++++++++++
 .../selftests/arm64/signal/testcases/gcs_frame.c   | 78 ++++++++++++++++++++++
 .../arm64/signal/testcases/gcs_write_fault.c       | 67 +++++++++++++++++++
 5 files changed, 215 insertions(+)

diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
index 839e3a252629..26de12918890 100644
--- a/tools/testing/selftests/arm64/signal/.gitignore
+++ b/tools/testing/selftests/arm64/signal/.gitignore
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 mangle_*
 fake_sigreturn_*
+gcs_*
 sme_*
 ssve_*
 sve_*
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
index 1cea64986baa..d41f237db28d 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
@@ -6,6 +6,7 @@
 
 #include <assert.h>
 #include <stdio.h>
+#include <stdint.h>
 #include <string.h>
 
 #include "test_signals.h"
@@ -45,6 +46,15 @@ void test_result(struct tdescr *td);
 		_arg1;							\
 	})
 
+static inline __attribute__((always_inline)) uint64_t get_gcspr_el0(void)
+{
+	uint64_t val;
+
+	asm volatile("mrs %0, S3_3_C2_C5_1" : "=r" (val));
+
+	return val;
+}
+
 static inline bool feats_ok(struct tdescr *td)
 {
 	if (td->feats_incompatible & td->feats_supported)
diff --git a/tools/testing/selftests/arm64/signal/testcases/gcs_exception_fault.c b/tools/testing/selftests/arm64/signal/testcases/gcs_exception_fault.c
new file mode 100644
index 000000000000..532d533592a1
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/gcs_exception_fault.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 ARM Limited
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+#include <sys/prctl.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+/* This should be includable from some standard header, but which? */
+#ifndef SEGV_CPERR
+#define SEGV_CPERR 10
+#endif
+
+static inline void gcsss1(uint64_t Xt)
+{
+	asm volatile (
+		"sys #3, C7, C7, #2, %0\n"
+		:
+		: "rZ" (Xt)
+		: "memory");
+}
+
+static int gcs_op_fault_trigger(struct tdescr *td)
+{
+	/*
+	 * The slot below our current GCS should be in a valid GCS but
+	 * must not have a valid cap in it.
+	 */
+	gcsss1(get_gcspr_el0() - 8);
+
+	return 0;
+}
+
+static int gcs_op_fault_signal(struct tdescr *td, siginfo_t *si,
+				  ucontext_t *uc)
+{
+	ASSERT_GOOD_CONTEXT(uc);
+
+	return 1;
+}
+
+struct tdescr tde = {
+	.name = "Invalid GCS operation",
+	.descr = "An invalid GCS operation generates the expected signal",
+	.feats_required = FEAT_GCS,
+	.timeout = 3,
+	.sig_ok = SIGSEGV,
+	.sig_ok_code = SEGV_CPERR,
+	.sanity_disabled = true,
+	.trigger = gcs_op_fault_trigger,
+	.run = gcs_op_fault_signal,
+};
diff --git a/tools/testing/selftests/arm64/signal/testcases/gcs_frame.c b/tools/testing/selftests/arm64/signal/testcases/gcs_frame.c
new file mode 100644
index 000000000000..d67cb26195a6
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/gcs_frame.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 ARM Limited
+ */
+
+#include <signal.h>
+#include <ucontext.h>
+#include <sys/prctl.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static union {
+	ucontext_t uc;
+	char buf[1024 * 64];
+} context;
+
+static int gcs_regs(struct tdescr *td, siginfo_t *si, ucontext_t *uc)
+{
+	size_t offset;
+	struct _aarch64_ctx *head = GET_BUF_RESV_HEAD(context);
+	struct gcs_context *gcs;
+	unsigned long expected, gcspr;
+	int ret;
+
+	ret = prctl(PR_GET_SHADOW_STACK_STATUS, &expected, 0, 0, 0);
+	if (ret != 0) {
+		fprintf(stderr, "Unable to query GCS status\n");
+		return 1;
+	}
+
+	/* We expect a cap to be added to the GCS in the signal frame */
+	gcspr = get_gcspr_el0();
+	gcspr -= 8;
+	fprintf(stderr, "Expecting GCSPR_EL0 %lx\n", gcspr);
+
+	if (!get_current_context(td, &context.uc, sizeof(context))) {
+		fprintf(stderr, "Failed getting context\n");
+		return 1;
+	}
+	fprintf(stderr, "Got context\n");
+
+	head = get_header(head, GCS_MAGIC, GET_BUF_RESV_SIZE(context),
+			  &offset);
+	if (!head) {
+		fprintf(stderr, "No GCS context\n");
+		return 1;
+	}
+
+	gcs = (struct gcs_context *)head;
+
+	/* Basic size validation is done in get_current_context() */
+
+	if (gcs->features_enabled != expected) {
+		fprintf(stderr, "Features enabled %llx but expected %lx\n",
+			gcs->features_enabled, expected);
+		return 1;
+	}
+
+	if (gcs->gcspr != gcspr) {
+		fprintf(stderr, "Got GCSPR %llx but expected %lx\n",
+			gcs->gcspr, gcspr);
+		return 1;
+	}
+
+	fprintf(stderr, "GCS context validated\n");
+	td->pass = 1;
+
+	return 0;
+}
+
+struct tdescr tde = {
+	.name = "GCS basics",
+	.descr = "Validate a GCS signal context",
+	.feats_required = FEAT_GCS,
+	.timeout = 3,
+	.run = gcs_regs,
+};
diff --git a/tools/testing/selftests/arm64/signal/testcases/gcs_write_fault.c b/tools/testing/selftests/arm64/signal/testcases/gcs_write_fault.c
new file mode 100644
index 000000000000..126b1a294a29
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/gcs_write_fault.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 ARM Limited
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+#include <sys/prctl.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static uint64_t *gcs_page;
+
+#ifndef __NR_map_shadow_stack
+#define __NR_map_shadow_stack 452
+#endif
+
+static bool alloc_gcs(struct tdescr *td)
+{
+	long page_size = sysconf(_SC_PAGE_SIZE);
+
+	gcs_page = (void *)syscall(__NR_map_shadow_stack, 0,
+				   page_size, 0);
+	if (gcs_page == MAP_FAILED) {
+		fprintf(stderr, "Failed to map %ld byte GCS: %d\n",
+			page_size, errno);
+		return false;
+	}
+
+	return true;
+}
+
+static int gcs_write_fault_trigger(struct tdescr *td)
+{
+	/* Verify that the page is readable (ie, not completely unmapped) */
+	fprintf(stderr, "Read value 0x%lx\n", gcs_page[0]);
+
+	/* A regular write should trigger a fault */
+	gcs_page[0] = EINVAL;
+
+	return 0;
+}
+
+static int gcs_write_fault_signal(struct tdescr *td, siginfo_t *si,
+				  ucontext_t *uc)
+{
+	ASSERT_GOOD_CONTEXT(uc);
+
+	return 1;
+}
+
+
+struct tdescr tde = {
+	.name = "GCS write fault",
+	.descr = "Normal writes to a GCS segfault",
+	.feats_required = FEAT_GCS,
+	.timeout = 3,
+	.sig_ok = SIGSEGV,
+	.sanity_disabled = true,
+	.init = alloc_gcs,
+	.trigger = gcs_write_fault_trigger,
+	.run = gcs_write_fault_signal,
+};

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 35/35] kselftest/arm64: Enable GCS for the FP stress tests
  2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
                   ` (33 preceding siblings ...)
  2023-07-16 21:51 ` [PATCH 34/35] selftests/arm64: Add GCS signal tests Mark Brown
@ 2023-07-16 21:51 ` Mark Brown
  34 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-16 21:51 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv, Mark Brown

While it's a bit off topic for them the floating point stress tests do give
us some coverage of context thrashing cases, and also of active signal
delivery separate to the relatively complicated framework in the actual
signals tests. Have the tests enable GCS on startup, ignoring failures so
they continue to work as before on systems without GCS.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 tools/testing/selftests/arm64/fp/assembler.h   | 15 +++++++++++++++
 tools/testing/selftests/arm64/fp/fpsimd-test.S |  2 ++
 tools/testing/selftests/arm64/fp/sve-test.S    |  2 ++
 tools/testing/selftests/arm64/fp/za-test.S     |  2 ++
 tools/testing/selftests/arm64/fp/zt-test.S     |  2 ++
 5 files changed, 23 insertions(+)

diff --git a/tools/testing/selftests/arm64/fp/assembler.h b/tools/testing/selftests/arm64/fp/assembler.h
index 9b38a0da407d..d01b61947f56 100644
--- a/tools/testing/selftests/arm64/fp/assembler.h
+++ b/tools/testing/selftests/arm64/fp/assembler.h
@@ -65,4 +65,19 @@ endfunction
 	bl	puts
 .endm
 
+#define PR_SET_SHADOW_STACK_STATUS      72
+# define PR_SHADOW_STACK_ENABLE         (1UL << 1)
+
+.macro enable_gcs
+	// Run with GCS
+	mov	x0, PR_SET_SHADOW_STACK_STATUS
+	mov	x1, PR_SHADOW_STACK_ENABLE
+	mov	x2, xzr
+	mov	x3, xzr
+	mov	x4, xzr
+	mov	x5, xzr
+	mov	x8, #__NR_prctl
+	svc	#0
+.endm
+
 #endif /* ! ASSEMBLER_H */
diff --git a/tools/testing/selftests/arm64/fp/fpsimd-test.S b/tools/testing/selftests/arm64/fp/fpsimd-test.S
index 8b960d01ed2e..b16fb7f42e3e 100644
--- a/tools/testing/selftests/arm64/fp/fpsimd-test.S
+++ b/tools/testing/selftests/arm64/fp/fpsimd-test.S
@@ -215,6 +215,8 @@ endfunction
 // Main program entry point
 .globl _start
 function _start
+	enable_gcs
+
 	mov	x23, #0		// signal count
 
 	mov	w0, #SIGINT
diff --git a/tools/testing/selftests/arm64/fp/sve-test.S b/tools/testing/selftests/arm64/fp/sve-test.S
index 4328895dfc87..486634bc7def 100644
--- a/tools/testing/selftests/arm64/fp/sve-test.S
+++ b/tools/testing/selftests/arm64/fp/sve-test.S
@@ -378,6 +378,8 @@ endfunction
 // Main program entry point
 .globl _start
 function _start
+	enable_gcs
+
 	mov	x23, #0		// Irritation signal count
 
 	mov	w0, #SIGINT
diff --git a/tools/testing/selftests/arm64/fp/za-test.S b/tools/testing/selftests/arm64/fp/za-test.S
index 9dcd70911397..f789694fa3ea 100644
--- a/tools/testing/selftests/arm64/fp/za-test.S
+++ b/tools/testing/selftests/arm64/fp/za-test.S
@@ -231,6 +231,8 @@ endfunction
 // Main program entry point
 .globl _start
 function _start
+	enable_gcs
+
 	mov	x23, #0		// signal count
 
 	mov	w0, #SIGINT
diff --git a/tools/testing/selftests/arm64/fp/zt-test.S b/tools/testing/selftests/arm64/fp/zt-test.S
index d63286397638..ea5e55310705 100644
--- a/tools/testing/selftests/arm64/fp/zt-test.S
+++ b/tools/testing/selftests/arm64/fp/zt-test.S
@@ -200,6 +200,8 @@ endfunction
 // Main program entry point
 .globl _start
 function _start
+	enable_gcs
+
 	mov	x23, #0		// signal count
 
 	mov	w0, #SIGINT

-- 
2.30.2


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Re: [PATCH 04/35] arm64/gcs: Document the ABI for Guarded Control Stacks
  2023-07-16 21:51 ` [PATCH 04/35] arm64/gcs: Document the ABI " Mark Brown
@ 2023-07-17 11:42   ` Jonathan Cameron
  2023-07-19 11:44   ` Mike Rapoport
  1 sibling, 0 replies; 51+ messages in thread
From: Jonathan Cameron @ 2023-07-17 11:42 UTC (permalink / raw)
  To: Mark Brown
  Cc: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy, H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv

On Sun, 16 Jul 2023 22:51:00 +0100
Mark Brown <broonie@kernel.org> wrote:

> Add some documentation of the userspace ABI for Guarded Control Stacks.
> 
> Signed-off-by: Mark Brown <broonie@kernel.org>
Hi Mark,

Nice document.  All I could find on a first read was one typo...

...

> +7.  ptrace extensions
> +---------------------
> +
> +* A new regset NT_ARM_GCS is defined for use with PTRACE_GETREGSET and
> +  PTRACE_SETREGSET.
> +
> +* Due to the complexity surrounding allocation and deallocation of stakcs and

stacks

> +  lack of practical application changes to the GCS configuration via ptrace
> +  are not supported.
> +


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 17/35] arm64/traps: Handle GCS exceptions
  2023-07-16 21:51 ` [PATCH 17/35] arm64/traps: Handle GCS exceptions Mark Brown
@ 2023-07-17 12:12   ` Jonathan Cameron
  0 siblings, 0 replies; 51+ messages in thread
From: Jonathan Cameron @ 2023-07-17 12:12 UTC (permalink / raw)
  To: Mark Brown
  Cc: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy, H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv

On Sun, 16 Jul 2023 22:51:13 +0100
Mark Brown <broonie@kernel.org> wrote:

> A new exception code is defined for GCS specific faults other than
> standard load/store faults, for example GCS token validation failures,
> add handling for this. These faults are reported to userspace as
> segfaults with code SEGV_CPERR (protection error), mirroring the
> reporting for x86 shadow stack errors.
> 
> GCS faults due to memory load/store operations generate data aborts with
> a flag set, these will be handled separately as part of the data abort
> handling.
> 
> Since we do not currently enable GCS for EL1 we should not get any faults
> there but while we're at it we wire things up there, treating any GCS
> fault as fatal.
> 
> Signed-off-by: Mark Brown <broonie@kernel.org>

See below.

> ---
>  arch/arm64/include/asm/esr.h       | 26 +++++++++++++++++++++++++-
>  arch/arm64/include/asm/exception.h |  2 ++
>  arch/arm64/kernel/entry-common.c   | 23 +++++++++++++++++++++++
>  arch/arm64/kernel/traps.c          | 11 +++++++++++
>  4 files changed, 61 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
> index ae35939f395b..c5a72172fcf1 100644
> --- a/arch/arm64/include/asm/esr.h
> +++ b/arch/arm64/include/asm/esr.h
...

> @@ -382,6 +383,29 @@
>  #define ESR_ELx_MOPS_ISS_SRCREG(esr)	(((esr) & (UL(0x1f) << 5)) >> 5)
>  #define ESR_ELx_MOPS_ISS_SIZEREG(esr)	(((esr) & (UL(0x1f) << 0)) >> 0)
>  
> +/* ISS field definitions for GCS */
> +#define ESR_ELx_ExType_SHIFT	(20)
> +#define ESR_ELx_ExType_MASK	GENMASK(23, 20)
> +#define ESR_ELx_Raddr_SHIFT	(14)

(10) ?

> +#define ESR_ELx_Raddr_MASK	GENMASK(14, 10)
> +#define ESR_ELx_Rn_SHIFT	(5)
> +#define ESR_ELx_Rn_MASK		GENMASK(9, 5)

I think this can also be ESR_ELx_RVALUE_MASK for some ExType
Worth adding that as well?

> +#define ESR_ELx_IT_SHIFT	(0)
> +#define ESR_ELx_IT_MASK		GENMASK(4, 0)
> +
> +#define ESR_ELx_ExType_DATA_CHECK	0
> +#define ESR_ELx_ExType_EXLOCK		1
> +#define ESR_ELx_ExType_STR		2
> +
> +#define ESR_ELx_IT_RET			0
> +#define ESR_ELx_IT_GCSPOPM		1
> +#define ESR_ELx_IT_RET_KEYA		2
> +#define ESR_ELx_IT_RET_KEYB		3
> +#define ESR_ELx_IT_GCSSS1		4
> +#define ESR_ELx_IT_GCSSS2		5
> +#define ESR_ELx_IT_GCSPOPCX		6
> +#define ESR_ELx_IT_GCSPOPX		7

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 26/35] arm64: Add Kconfig for Guarded Control Stack (GCS)
  2023-07-16 21:51 ` [PATCH 26/35] arm64: Add Kconfig for Guarded Control Stack (GCS) Mark Brown
@ 2023-07-17 12:32   ` Jonathan Cameron
  0 siblings, 0 replies; 51+ messages in thread
From: Jonathan Cameron @ 2023-07-17 12:32 UTC (permalink / raw)
  To: Mark Brown
  Cc: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy, H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv

On Sun, 16 Jul 2023 22:51:22 +0100
Mark Brown <broonie@kernel.org> wrote:

> Provide a Kconfig option allowing the user to select if GCS support is
> built into the kernel.
> 
> Signed-off-by: Mark Brown <broonie@kernel.org>
> ---
>  arch/arm64/Kconfig | 19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
> 
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 7856c3a3e35a..e1aeeda13c52 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -2091,6 +2091,25 @@ config ARM64_EPAN
>  	  if the cpu does not implement the feature.
>  endmenu # "ARMv8.7 architectural features"
>  
> +menu "v9.4 architectural features"
> +
> +config ARM64_GCS
> +	bool "Enable support for Guarded Control Stack (GCS)"
> +	default y
> +	select ARCH_USES_HIGH_VMA_FLAGS
> +	help
> +	  Guarded Control Stack (GCS) provides support for a separate
> +	  stack with restricted access which contains only return
> +	  addresses.  This can be used to harden against some attacks
> +	  by comparing return address used by the program with what is
> +	  stored in the GCS, and may also be used to efficiently obtain
> +	  the call stack for applications such as profiling.
> +
> +	  The feature is detected at runtime, and will remain disabled
> +	  if the system does not implement the feature.
> +
> +endmenu # "2022 archiectural features"

Inconsistent naming and spelling mistake.

> +
>  config ARM64_SVE
>  	bool "ARM Scalable Vector Extension support"
>  	default y
> 


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 22/35] arm64/mm: Implement map_shadow_stack()
  2023-07-16 21:51 ` [PATCH 22/35] arm64/mm: Implement map_shadow_stack() Mark Brown
@ 2023-07-18  9:10   ` Szabolcs Nagy
  2023-07-18 13:55     ` Mark Brown
  0 siblings, 1 reply; 51+ messages in thread
From: Szabolcs Nagy @ 2023-07-18  9:10 UTC (permalink / raw)
  To: Mark Brown, Catalin Marinas, Will Deacon, Jonathan Corbet,
	Andrew Morton, Marc Zyngier, Oliver Upton, James Morse,
	Suzuki K Poulose, Arnd Bergmann, Oleg Nesterov, Eric Biederman,
	Kees Cook, Shuah Khan, Rick P. Edgecombe, Deepak Gupta,
	Ard Biesheuvel
  Cc: H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv

The 07/16/2023 22:51, Mark Brown wrote:
> +SYSCALL_DEFINE3(map_shadow_stack, unsigned long, addr, unsigned long, size, unsigned int, flags)
> +{
> +	unsigned long aligned_size;
> +	unsigned long __user *cap_ptr;
> +	unsigned long cap_val;
> +	int ret;
> +
> +	if (!system_supports_gcs())
> +		return -EOPNOTSUPP;
> +
> +	if (flags)
> +		return -EINVAL;
> +
> +	/*
> +	 * An overflow would result in attempting to write the restore token
> +	 * to the wrong location. Not catastrophic, but just return the right
> +	 * error code and block it.
> +	 */
> +	aligned_size = PAGE_ALIGN(size);
> +	if (aligned_size < size)
> +		return -EOVERFLOW;
> +
> +	addr = alloc_gcs(addr, aligned_size, 0, false);
> +	if (IS_ERR_VALUE(addr))
> +		return addr;
> +
> +	/*
> +	 * Put a cap token at the end of the allocated region so it
> +	 * can be switched to.
> +	 */
> +	cap_ptr = (unsigned long __user *)(addr + aligned_size -
> +					   (2 * sizeof(unsigned long)));
> +	cap_val = GCS_CAP(cap_ptr);
> +
> +	ret = copy_to_user_gcs(cap_ptr, &cap_val, 1);

with

  uint64_t *p = map_shadow_stack(0, N*8, 0);

i'd expect p[N-1] to be the end token and p[N-2] to be the cap token,
not p[PAGE_ALIGN(N*8)/8-2].

if we allow misalligned size here (and in munmap) then i think it's
better to not page align.  size%8!=0 || size<16 can be an error.


> +	if (ret != 0) {
> +		vm_munmap(addr, size);
> +		return -EFAULT;
> +	}
> +
> +	return addr;
> +}

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 22/35] arm64/mm: Implement map_shadow_stack()
  2023-07-18  9:10   ` Szabolcs Nagy
@ 2023-07-18 13:55     ` Mark Brown
  2023-07-18 15:49       ` Edgecombe, Rick P
  0 siblings, 1 reply; 51+ messages in thread
From: Mark Brown @ 2023-07-18 13:55 UTC (permalink / raw)
  To: Szabolcs Nagy
  Cc: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv

[-- Attachment #1: Type: text/plain, Size: 696 bytes --]

On Tue, Jul 18, 2023 at 10:10:04AM +0100, Szabolcs Nagy wrote:

>   uint64_t *p = map_shadow_stack(0, N*8, 0);

> i'd expect p[N-1] to be the end token and p[N-2] to be the cap token,
> not p[PAGE_ALIGN(N*8)/8-2].

Yes, that probably would be more helpful.

> if we allow misalligned size here (and in munmap) then i think it's
> better to not page align.  size%8!=0 || size<16 can be an error.

Honestly I'd be a lot happier to just not allow misalignment but that
raises the issue with binaries randomly not working when moved to a
kernel with a different page size.  I'll have a think but possibly the
safest thing would be requiring a multiple of 4K then rounding up to our
actual page size.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 22/35] arm64/mm: Implement map_shadow_stack()
  2023-07-18 13:55     ` Mark Brown
@ 2023-07-18 15:49       ` Edgecombe, Rick P
  0 siblings, 0 replies; 51+ messages in thread
From: Edgecombe, Rick P @ 2023-07-18 15:49 UTC (permalink / raw)
  To: broonie, Szabolcs.Nagy
  Cc: corbet, ardb, maz, shuah, linux-kernel, keescook, james.morse,
	debug, akpm, palmer, catalin.marinas, hjl.tools, paul.walmsley,
	linux-mm, aou, oleg, arnd, ebiederm, will, suzuki.poulose,
	kvmarm, linux-doc, linux-arm-kernel, linux-fsdevel,
	linux-kselftest, linux-arch, oliver.upton, linux-riscv

On Tue, 2023-07-18 at 14:55 +0100, Mark Brown wrote:
> On Tue, Jul 18, 2023 at 10:10:04AM +0100, Szabolcs Nagy wrote:
> 
> >    uint64_t *p = map_shadow_stack(0, N*8, 0);
> 
> > i'd expect p[N-1] to be the end token and p[N-2] to be the cap
> > token,
> > not p[PAGE_ALIGN(N*8)/8-2].
> 
> Yes, that probably would be more helpful.

HJ made a similar request on the x86 side. He wanted an unaligned size
passed in to result in unaligned token placement.

> 
> > if we allow misalligned size here (and in munmap) then i think it's
> > better to not page align.  size%8!=0 || size<16 can be an error.
> 
> Honestly I'd be a lot happier to just not allow misalignment but that
> raises the issue with binaries randomly not working when moved to a
> kernel with a different page size.  I'll have a think but possibly
> the
> safest thing would be requiring a multiple of 4K then rounding up to
> our
> actual page size.


Someday when the x86 side is finally upstream I have a manpage for
map_shadow_stack. Any differences on the arm side would need to be
documented, but I'm not sure why there should be any differences. Like,
why not use the same flags? Or have a new flag for token+end marker
that x86 can use as well?

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 01/35] prctl: arch-agnostic prctl for shadow stack
  2023-07-16 21:50 ` [PATCH 01/35] prctl: arch-agnostic prctl for shadow stack Mark Brown
@ 2023-07-18 17:45   ` Edgecombe, Rick P
  2023-07-18 18:54     ` Mark Brown
  0 siblings, 1 reply; 51+ messages in thread
From: Edgecombe, Rick P @ 2023-07-18 17:45 UTC (permalink / raw)
  To: corbet, ardb, maz, shuah, Szabolcs.Nagy, keescook, james.morse,
	debug, akpm, catalin.marinas, oleg, arnd, ebiederm, will,
	suzuki.poulose, oliver.upton, broonie
  Cc: hjl.tools, linux-kernel, linux-riscv, linux-kselftest,
	linux-fsdevel, linux-mm, paul.walmsley, aou, palmer, linux-doc,
	kvmarm, linux-arm-kernel, linux-arch

On Sun, 2023-07-16 at 22:50 +0100, Mark Brown wrote:
> From: Deepak Gupta <debug@rivosinc.com>
> 
> Three architectures (x86, aarch64, riscv) have announced support for
> shadow stack.  This patch adds arch-agnostic prtcl support to enable
> /disable/get/set status of shadow stack and forward control (landing
> pad)
> flow cfi statuses.

What is this about forward control flow? Seems to be just about shadow
stack.

> 
> New prctls are
>       - PR_GET_SHADOW_STACK_STATUS, PR_SET_SHADOW_STACK_STATUS
> 
> Signed-off-by: Deepak Gupta <debug@rivosinc.com>
> [Rebased onto current kernels, renumbering to track other allocations
>  already upstream, dropping indirect LP, updating to pass arg to set
>   by value, fix missing prototypes for weak functions and update
> title.
>   -- broonie]
> Signed-off-by: Mark Brown <broonie@kernel.org>

This is similar to the arch_prctl() thing x86 does, but I actually see
a fair amount of differences:

1. PR_SET_SHADOW_STACK_STATUS seems like a strange name for the thing
actually doing the whole enabling of the feature which involves
allocating memory, etc. And in the future a growing array of different
things (enabling push, write, etc).

2. x86 only allows one enabling/disabling operation at a time. So you
can't enable shadow stack AND WRSS with one syscall, for example. This
is to make it so it's clear which operation failed. Also, since some
features depend on others (WRSS), there would need to be some ordering
and rollback logic. There was some discussion about a batch enabling
arch_prctl() that could report failures independently, but it was
deemed premature optimization.

3. It only allows you to lock the whole feature, and not individual
subfeatures. For things like WRSS, it came up that there might be an
elf bit, like the shadow stack one, but that works a bit different.
Instead of only enabling shadow stack when ALL DSOs support the
feature, it would want to be enabled if ANY DSOs require it. So
userspace might want to do something like lock shadow stack, but leave
WRSS unlocked in case a dlopen() call came across a WRSS-requiring DSO.

4. To support CRIU, there needed to be a ptrace-only unlock feature.
The arch_prctl() has a special ptrace route to enforce that this unlock
is only coming from ptrace. Is there some way to do this with a regular
prctl()?

5. I see in the next patch there is hinted support for write and push
as well (although I can't find the implementation in the patches, am I
missing it?). X86 has something close enough to write, but not push.
What is the idea for when the features don't exactly match?

I think when Deepak originally brought up this unified prctl-based
interface, it seemed far away before we could tell if it *could* be
unified. Do either of you have any thoughts on whether the above points
could be incorporated?

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 02/35] prctl: Add flag for shadow stack writeability and push/pop
  2023-07-16 21:50 ` [PATCH 02/35] prctl: Add flag for shadow stack writeability and push/pop Mark Brown
@ 2023-07-18 17:47   ` Edgecombe, Rick P
  2023-07-18 19:10     ` Mark Brown
  0 siblings, 1 reply; 51+ messages in thread
From: Edgecombe, Rick P @ 2023-07-18 17:47 UTC (permalink / raw)
  To: corbet, ardb, maz, shuah, Szabolcs.Nagy, keescook, james.morse,
	debug, akpm, catalin.marinas, oleg, arnd, ebiederm, will,
	suzuki.poulose, oliver.upton, broonie
  Cc: hjl.tools, linux-kernel, linux-riscv, linux-kselftest,
	linux-fsdevel, linux-mm, paul.walmsley, aou, palmer, linux-doc,
	kvmarm, linux-arm-kernel, linux-arch

On Sun, 2023-07-16 at 22:50 +0100, Mark Brown wrote:
> On arm64 and x86 the kernel can control if there is write access to
> the
> shadow stack via specific instructions defined for the purpose,
> useful
> for things like userspace threading at the expense of some security.
> Add a flag to allow this to be selected when changing the shadow
> stack
> status.
> 
> On arm64 the kernel can separately control if userspace is able to
> pop
> and push values directly onto the shadow stack via GCS push and pop
> instructions, supporting many scenarios where userspace needs to
> write
> to the stack with less security exposure than full write access.  Add
> a
> flag to allow this to be selected when changing the shadow stack
> status.

Is this correct? I thought Szabolcs was saying pop was always
supported, but push was optional.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 21/35] arm64/gcs: Implement shadow stack prctl() interface
  2023-07-16 21:51 ` [PATCH 21/35] arm64/gcs: Implement shadow stack prctl() interface Mark Brown
@ 2023-07-18 17:51   ` Edgecombe, Rick P
  2023-07-18 19:37     ` Mark Brown
  0 siblings, 1 reply; 51+ messages in thread
From: Edgecombe, Rick P @ 2023-07-18 17:51 UTC (permalink / raw)
  To: corbet, ardb, maz, shuah, Szabolcs.Nagy, keescook, james.morse,
	debug, akpm, catalin.marinas, oleg, arnd, ebiederm, will,
	suzuki.poulose, oliver.upton, broonie
  Cc: hjl.tools, linux-kernel, linux-riscv, linux-kselftest,
	linux-fsdevel, linux-mm, paul.walmsley, aou, palmer, linux-doc,
	kvmarm, linux-arm-kernel, linux-arch

On Sun, 2023-07-16 at 22:51 +0100, Mark Brown wrote:
> +int arch_set_shadow_stack_status(struct task_struct *task, unsigned
> long arg)
> +{
> +       unsigned long gcs, size;
> +
> +       if (!system_supports_gcs())
> +               return -EINVAL;
> +
> +       if (is_compat_thread(task_thread_info(task)))
> +               return -EINVAL;
> +
> +       /* Reject unknown flags */
> +       if (arg & ~PR_SHADOW_STACK_SUPPORTED_STATUS_MASK)
> +               return -EINVAL;
> +
> +       /* If the task has been locked block any attempted changes */
> +       if (task->thread.gcs_el0_mode & PR_SHADOW_STACK_LOCK)
> +               return -EBUSY;
> +
> +       /* Drop flags other than lock if disabling */
> +       if (!(arg & PR_SHADOW_STACK_ENABLE))
> +               arg &= ~PR_SHADOW_STACK_LOCK;
> +
> +       /* If we are enabling GCS then make sure we have a stack */
> +       if (arg & PR_SHADOW_STACK_ENABLE) {
> +               if (!task_gcs_el0_enabled(task)) {
> +                       /* Do not allow GCS to be reenabled */
> +                       if (task->thread.gcs_base)
> +                               return -EINVAL;
> +
> +                       size = gcs_size(0);
> +                       gcs = alloc_gcs(task->thread.gcspr_el0, size,
> +                                       0, 0);
> +                       if (!gcs)
> +                               return -ENOMEM;
> +
> +                       task->thread.gcspr_el0 = gcs + size -
> sizeof(u64);
> +                       task->thread.gcs_base = gcs;
> +                       task->thread.gcs_size = size;
> +                       if (task == current)
> +                               write_sysreg_s(task-
> >thread.gcspr_el0,
> +                                              SYS_GCSPR_EL0);
> +
> +               }
> +       }
> +
> +       task->thread.gcs_el0_mode = arg;
> +       if (task == current)
> +               gcs_set_el0_mode(task);
> +

Ah! So does this task == current part mean this can be called from
another task via ptrace?

If so, then is the alloc_gcs() part on the wrong mm?

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 01/35] prctl: arch-agnostic prctl for shadow stack
  2023-07-18 17:45   ` Edgecombe, Rick P
@ 2023-07-18 18:54     ` Mark Brown
  0 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-18 18:54 UTC (permalink / raw)
  To: Edgecombe, Rick P
  Cc: corbet, ardb, maz, shuah, Szabolcs.Nagy, keescook, james.morse,
	debug, akpm, catalin.marinas, oleg, arnd, ebiederm, will,
	suzuki.poulose, oliver.upton, hjl.tools, linux-kernel,
	linux-riscv, linux-kselftest, linux-fsdevel, linux-mm,
	paul.walmsley, aou, palmer, linux-doc, kvmarm, linux-arm-kernel,
	linux-arch

[-- Attachment #1: Type: text/plain, Size: 4617 bytes --]

On Tue, Jul 18, 2023 at 05:45:01PM +0000, Edgecombe, Rick P wrote:
> On Sun, 2023-07-16 at 22:50 +0100, Mark Brown wrote:

> > Three architectures (x86, aarch64, riscv) have announced support for
> > shadow stack.  This patch adds arch-agnostic prtcl support to enable
> > /disable/get/set status of shadow stack and forward control (landing
> > pad)
> > flow cfi statuses.

> What is this about forward control flow? Seems to be just about shadow
> stack.

Sorry, that's the original commit message - the original version of this
also had support for controlling landing pads but I don't need that and
cut them out of the series.  I forgot to update that bit of the commit
message.

> > [Rebased onto current kernels, renumbering to track other allocations
> >  already upstream, dropping indirect LP, updating to pass arg to set
> >   by value, fix missing prototypes for weak functions and update
> > title.
> >   -- broonie]

> 1. PR_SET_SHADOW_STACK_STATUS seems like a strange name for the thing
> actually doing the whole enabling of the feature which involves
> allocating memory, etc. And in the future a growing array of different
> things (enabling push, write, etc).

I have no strong opinion on naming here.  _MODE?  I didn't find any
discussions around this in the 

> 2. x86 only allows one enabling/disabling operation at a time. So you
> can't enable shadow stack AND WRSS with one syscall, for example. This
> is to make it so it's clear which operation failed. Also, since some
> features depend on others (WRSS), there would need to be some ordering
> and rollback logic. There was some discussion about a batch enabling
> arch_prctl() that could report failures independently, but it was
> deemed premature optimization.

I did see that the x86 implementation required a call per flag, the
logic wasn't hugely obvious there - it didn't seem super helpful.
There's nothing stopping userspace turning one flag at a time if it
wants to, we just don't require it.  I wasn't overly concerned about the
rollback logic since I was anticipating that the main complexity is the
base enable and allocate, everything else would just be storing a mode.

We can implement things with the one bit per call approach, I just
didn't see much upside to it.  Perhaps I'm missing some case though.

> 3. It only allows you to lock the whole feature, and not individual
> subfeatures. For things like WRSS, it came up that there might be an
> elf bit, like the shadow stack one, but that works a bit different.
> Instead of only enabling shadow stack when ALL DSOs support the
> feature, it would want to be enabled if ANY DSOs require it. So
> userspace might want to do something like lock shadow stack, but leave
> WRSS unlocked in case a dlopen() call came across a WRSS-requiring DSO.

We could add either a second argument with the lock or a separate lock
prctl() and matching query which takes the same bitmask, being able
to lock per feature does give more flexibility to userspace in how we do
the locking and isn't hugely more costly to implement.  My model for
locking had been that there would be a final decision on what the
features should be, I was modelling "can enable" as equivalent access to
"is enabled" when it came to what was locked.

> 4. To support CRIU, there needed to be a ptrace-only unlock feature.
> The arch_prctl() has a special ptrace route to enforce that this unlock
> is only coming from ptrace. Is there some way to do this with a regular
> prctl()?

For arm64 we need to add a regset to expose the GCS pointer anyway so
the GCS mode is in there, though at the minute we prevent any changes at
all via that mechanism it could be implemented later.  I'm not aware of
any way for prctl() to tell if it is being invoked via ptrace so that'd
need to be dealt with somehow.

> 5. I see in the next patch there is hinted support for write and push
> as well (although I can't find the implementation in the patches, am I
> missing it?). X86 has something close enough to write, but not push.
> What is the idea for when the features don't exactly match?

The implementation is in "arm64/gcs: Implement shadow stack prctl()
interface", it just boils down to turning on or off a register bit.

> I think when Deepak originally brought up this unified prctl-based
> interface, it seemed far away before we could tell if it *could* be
> unified. Do either of you have any thoughts on whether the above points
> could be incorporated?

Other than the issue with CRIU I don't see any huge difficulty.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 02/35] prctl: Add flag for shadow stack writeability and push/pop
  2023-07-18 17:47   ` Edgecombe, Rick P
@ 2023-07-18 19:10     ` Mark Brown
  0 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-18 19:10 UTC (permalink / raw)
  To: Edgecombe, Rick P
  Cc: corbet, ardb, maz, shuah, Szabolcs.Nagy, keescook, james.morse,
	debug, akpm, catalin.marinas, oleg, arnd, ebiederm, will,
	suzuki.poulose, oliver.upton, hjl.tools, linux-kernel,
	linux-riscv, linux-kselftest, linux-fsdevel, linux-mm,
	paul.walmsley, aou, palmer, linux-doc, kvmarm, linux-arm-kernel,
	linux-arch

[-- Attachment #1: Type: text/plain, Size: 731 bytes --]

On Tue, Jul 18, 2023 at 05:47:32PM +0000, Edgecombe, Rick P wrote:
> On Sun, 2023-07-16 at 22:50 +0100, Mark Brown wrote:

> > On arm64 the kernel can separately control if userspace is able to
> > pop
> > and push values directly onto the shadow stack via GCS push and pop
> > instructions, supporting many scenarios where userspace needs to
> > write
> > to the stack with less security exposure than full write access.  Add
> > a
> > flag to allow this to be selected when changing the shadow stack
> > status.

> Is this correct? I thought Szabolcs was saying pop was always
> supported, but push was optional.

It's not, I wrote this right after looking at hypervisor controls which
do control push and pop.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 21/35] arm64/gcs: Implement shadow stack prctl() interface
  2023-07-18 17:51   ` Edgecombe, Rick P
@ 2023-07-18 19:37     ` Mark Brown
  0 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2023-07-18 19:37 UTC (permalink / raw)
  To: Edgecombe, Rick P
  Cc: corbet, ardb, maz, shuah, Szabolcs.Nagy, keescook, james.morse,
	debug, akpm, catalin.marinas, oleg, arnd, ebiederm, will,
	suzuki.poulose, oliver.upton, hjl.tools, linux-kernel,
	linux-riscv, linux-kselftest, linux-fsdevel, linux-mm,
	paul.walmsley, aou, palmer, linux-doc, kvmarm, linux-arm-kernel,
	linux-arch

[-- Attachment #1: Type: text/plain, Size: 1259 bytes --]

On Tue, Jul 18, 2023 at 05:51:54PM +0000, Edgecombe, Rick P wrote:
> On Sun, 2023-07-16 at 22:51 +0100, Mark Brown wrote:

> > +                       gcs = alloc_gcs(task->thread.gcspr_el0, size,
> > +                                       0, 0);
> > +                       if (!gcs)
> > +                               return -ENOMEM;

> > +       task->thread.gcs_el0_mode = arg;
> > +       if (task == current)
> > +               gcs_set_el0_mode(task);
> > +

> Ah! So does this task == current part mean this can be called from
> another task via ptrace?

Ugh, right.  So I had been worried about preemption rather than invoking
prctl() via ptrace, though since ptrace can change the syscall invoked
by a task it could cause prctl() to be invoked that way (but that should
look like being run in the target process).

I'm not aware of an interface specifically intended to remotely invoke
prctls via ptrace but that doesn't mean there isn't one that I didn't
find yet.  I can't remember why I'm aware of the task != current case as
a concern which is worrying me.

> If so, then is the alloc_gcs() part on the wrong mm?

Yes, it will be.  I'll add a check in there to reject attempts to enable
GCS when task != current.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 04/35] arm64/gcs: Document the ABI for Guarded Control Stacks
  2023-07-16 21:51 ` [PATCH 04/35] arm64/gcs: Document the ABI " Mark Brown
  2023-07-17 11:42   ` Jonathan Cameron
@ 2023-07-19 11:44   ` Mike Rapoport
  2023-07-19 13:25     ` Mark Brown
  1 sibling, 1 reply; 51+ messages in thread
From: Mike Rapoport @ 2023-07-19 11:44 UTC (permalink / raw)
  To: Mark Brown
  Cc: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy, H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv

On Sun, Jul 16, 2023 at 10:51:00PM +0100, Mark Brown wrote:
> Add some documentation of the userspace ABI for Guarded Control Stacks.
> 
> Signed-off-by: Mark Brown <broonie@kernel.org>
> ---
>  Documentation/arch/arm64/gcs.rst   | 216 +++++++++++++++++++++++++++++++++++++
>  Documentation/arch/arm64/index.rst |   1 +
>  2 files changed, 217 insertions(+)
> 
> diff --git a/Documentation/arch/arm64/gcs.rst b/Documentation/arch/arm64/gcs.rst
> new file mode 100644
> index 000000000000..27ba72d27952
> --- /dev/null
> +++ b/Documentation/arch/arm64/gcs.rst
> @@ -0,0 +1,216 @@
> +===============================================
> +Guarded Control Stack support for AArch64 Linux
> +===============================================
> +
> +This document outlines briefly the interface provided to userspace by Linux in
> +order to support use of the ARM Guarded Control Stack (GCS) feature.
> +
> +This is an outline of the most important features and issues only and not
> +intended to be exhaustive.
> +
> +
> +
> +1.  General
> +-----------
> +
> +* GCS is an architecture feature intended to provide greater protection
> +  against return oriented programming (ROP) attacks and to simplify the
> +  implementation of features that need to collect stack traces such as
> +  profiling.
> +
> +* When GCS is enabled a separate guarded control stack is maintained by the
> +  PE which is writeable only through specific GCS operations.  This
> +  stores the call stack only, when a procedure call instruction is
> +  performed the current PC is pushed onto the GCS and on RET the
> +  address in the LR is verified against that on the top of the GCS.
> +
> +* When active current GCS pointer is stored in the system register
> +  GCSPR_EL0.  This is readable by userspace but can only be updated
> +  via specific GCS instructions.
> +
> +* The architecture provides instructions for switching between guarded
> +  control stacks with checks to ensure that the new stack is a valid
> +  target for switching.
> +
> +* The functionality of GCS is similar to that provided by the x86 Shadow
> +  Stack feature, due to sharing of userspace interfaces the ABI refers to
> +  shadow stacks rather than GCS.
> +
> +* Support for GCS is reported to userspace via HWCAP2_GCS in the aux vector
> +  AT_HWCAP2 entry.
> +
> +* GCS is enabled per thread.  While there is support for disabling GCS
> +  at runtime this should be done with great care.
> +
> +* GCS memory access faults are reported as normal memory access faults.
> +
> +* GCS specific errors (those reported with EC 0x2d) will be reported as
> +  SIGSEGV with a si_code of SEGV_CPERR (control protection error).
> +
> +* GCS is supported only for AArch64.
> +
> +* On systems where GCS is supported GCSPR_EL0 is always readable by EL0
> +  regardless of the GCS configuration for the thread.
> +
> +* The architecture supports enabling GCS without verifying that return values
> +  in LR match those in the GCS, the LR will be ignored.  This is not supported
> +  by Linux.
> +
> +* EL0 GCS entries with bit 63 set are reserved for use, one such use is defined
> +  below for signals and should be ignored when parsing the stack if not
> +  understood.
> +
> +
> +2.  Enabling and disabling Guarded Control Stacks
> +-------------------------------------------------
> +
> +* GCS is enabled and disabled for a thread via the PR_SET_SHADOW_STACK_STATUS
> +  prctl(), this takes a single flags argument specifying which GCS features
> +  should be used.
> +
> +* When set PR_SHADOW_STACK_ENABLE flag allocates a Guarded Control Stack for

                                                 'for' here looks excessive ^

> +  and enables GCS for the thread, enabling the functionality controlled by
> +  GCSPRE0_EL1.{nTR, RVCHKEN, PCRSEL}.
> +
> +* When set the PR_SHADOW_STACK_PUSH flag enables the functionality controlled
> +  by GCSCRE0_EL1.PUSHMEn, allowing explicit GCS push and pops.
> +
> +* When set the PR_SHADOW_STACK_WRITE flag enables the functionality controlled
> +  by GCSCRE0_EL1.STREn, allowing explicit stores to the Guarded Control Stack.
> +
> +* When set the PR_SHADOW_STACK_LOCK flag prevents any further configuration of
> +  the GCS settings for the thread, further attempts to configure GCS will
> +  return -EBUSY.
> +
> +* Any unknown flags will cause PR_SET_SHADOW_STACK_STATUS to return -EINVAL.
> +
> +* PR_SET_SHADOW_STACK_STATUS affects only the thread the called it, any
> +  other running threads will be unaffected.
> +
> +* New threads inherit the GCS configuration of the thread that created them.
> +
> +* GCS is disabled on exec().
> +
> +* The current GCS configuration for a thread may be read with the
> +  PR_GET_SHADOW_STACK_STATUS prctl(), this returns the same flags that
> +  are passed to PR_SET_SHADOW_STACK_STATUS.
> +
> +* If GCS is disabled for a thread after having previously been enabled then
> +  the stack will remain allocated for the lifetime of the thread.  At present
> +  any attempt to reenable GCS for the thread will be rejected, this may be
> +  revisited in future.
> +
> +* It should be noted that since enabling GCS will result in GCS becoming
> +  active immediately it is not normally possible to return from the function
> +  that invoked the prctl() that enabled GCS.  It is expected that the normal
> +  usage will be that GCS is enabled very early in execution of a program.
> +
> +
> +
> +3.  Allocation of Guarded Control Stacks
> +----------------------------------------
> +
> +* When GCS is enabled for a thread a new Guarded Control Stack will be
> +  allocated for it of size RLIMIT_STACK / 2 or 2 gigabytes, whichever is
> +  smaller.
> +
> +* When a new thread is created by a thread which has GCS enabled then a
> +  new Guarded Control Stack will be allocated for the new thread with
> +  half the size of the standard stack.
> +
> +* When a stack is allocated by enabling GCS or during thread creation then
> +  the top 8 bytes of the stack will be initialised to 0 and GCSPR_EL0 will
> +  be set to point to the address of this 0 value, this can be used to
> +  detect the top of the stack.
> +
> +* Additional Guarded Control Stacks can be allocated using the
> +  map_shadow_stack() system call.
> +
> +* Stacks allocated using map_shadow_stack() will have the top 8 bytes
> +  set to 0 and the 8 bytes below that initialised with an architecturally
> +  valid GCS cap value, this allows switching to these stacks using the
> +  stack switch instructions provided by the architecture.
> +
> +* When GCS is disabled for a thread the Guarded Control Stack initially
> +  allocated for that thread will be freed.  Note carefully that if the
> +  stack has been switched this may not be the stack currently in use by
> +  the thread.
> +
> +
> +4.  Signal handling
> +--------------------
> +
> +* A new signal frame record gcs_context encodes the current GCS mode and
> +  pointer for the interrupted context on signal delivery.  This will always
> +  be present on systems that support GCS.
> +
> +* The record contains a flag field which reports the current GCS configuration
> +  for the interrupted context as PR_GET_SHADOW_STACK_STATUS would.
> +
> +* The signal handler is run with the same GCS configuration as the interrupted
> +  context.
> +
> +* When GCS is enabled for the interrupted thread a signal handling specific
> +  GCS cap token will be written to the GCS, this is an architectural GCS cap
> +  token with bit 63 set.  The GCSPR_EL0 reported in the signal frame will
> +  point to this cap token.
> +
> +* The signal handler will use the same GCS as the interrupted context.
> +
> +* When GCS is enabled on signal entry a frame with the address of the signal
> +  return handler will be pushed onto the GCS, allowing return from the signal
> +  handler via RET as normal.  This will not be reported in the gcs_context in
> +  the signal frame.
> +
> +
> +5.  Signal return
> +-----------------
> +
> +When returning from a signal handler:
> +
> +* If there is a gcs_context record in the signal frame then the GCS flags
> +  and GCSPR_EL0 will be restored from that context prior to further
> +  validation.
> +
> +* If there is no gcs_context record in the signal frame then the GCS
> +  configuration will be unchanged.
> +
> +* If GCS is enabled on return from a signal handler then GCSPR_EL0 must
> +  point to a valid GCS signal cap record, this will be popped from the
> +  GCS prior to signal return.
> +
> +* If the GCS configuration is locked when returning from a signal then any
> +  attempt to change the GCS configuration will be treated as an error.  This
> +  is true even if GCS was not enabled prior to signal entry.
> +
> +* GCS may be disabled via signal return but any attempt to enable GCS via
> +  signal return will be rejected.
> +
> +
> +7.  ptrace extensions
> +---------------------
> +
> +* A new regset NT_ARM_GCS is defined for use with PTRACE_GETREGSET and
> +  PTRACE_SETREGSET.
> +
> +* Due to the complexity surrounding allocation and deallocation of stakcs and
> +  lack of practical application changes to the GCS configuration via ptrace
> +  are not supported.

On x86 CRIU needed to be able to temporarily unlock shadow stack features
to recreate the shadow stack of the thread being restored. I presume CRIU
will need something like that on arm64 as well.

> +
> +
> +
> +8.  ELF coredump extensions
> +---------------------------
> +
> +* NT_ARM_GCS notes will be added to each coredump for each thread of the
> +  dumped process.  The contents will be equivalent to the data that would
> +  have been read if a PTRACE_GETREGSET of the corresponding type were
> +  executed for each thread when the coredump was generated.
> +
> +
> +
> +9.  /proc extensions
> +--------------------
> +
> +* Guarded Control Stack pages will include "ss" in their VmFlags in
> +  /proc/<pid>/smaps.
> diff --git a/Documentation/arch/arm64/index.rst b/Documentation/arch/arm64/index.rst
> index d08e924204bf..dcf3ee3eb8c0 100644
> --- a/Documentation/arch/arm64/index.rst
> +++ b/Documentation/arch/arm64/index.rst
> @@ -14,6 +14,7 @@ ARM64 Architecture
>      booting
>      cpu-feature-registers
>      elf_hwcaps
> +    gcs
>      hugetlbpage
>      kdump
>      legacy_instructions
> 
> -- 
> 2.30.2
> 
> 

-- 
Sincerely yours,
Mike.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 04/35] arm64/gcs: Document the ABI for Guarded Control Stacks
  2023-07-19 11:44   ` Mike Rapoport
@ 2023-07-19 13:25     ` Mark Brown
  2023-07-19 14:04       ` Mike Rapoport
  0 siblings, 1 reply; 51+ messages in thread
From: Mark Brown @ 2023-07-19 13:25 UTC (permalink / raw)
  To: Mike Rapoport
  Cc: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy, H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv

[-- Attachment #1: Type: text/plain, Size: 1280 bytes --]

On Wed, Jul 19, 2023 at 02:44:37PM +0300, Mike Rapoport wrote:
> On Sun, Jul 16, 2023 at 10:51:00PM +0100, Mark Brown wrote:

> > +* When set PR_SHADOW_STACK_ENABLE flag allocates a Guarded Control Stack for
> 
>                                                  'for' here looks excessive ^

> > +  and enables GCS for the thread, enabling the functionality controlled by
> > +  GCSPRE0_EL1.{nTR, RVCHKEN, PCRSEL}.

It does scan fine to me as a native speaker.

> > +7.  ptrace extensions
> > +---------------------
> > +
> > +* A new regset NT_ARM_GCS is defined for use with PTRACE_GETREGSET and
> > +  PTRACE_SETREGSET.
> > +
> > +* Due to the complexity surrounding allocation and deallocation of stakcs and
> > +  lack of practical application changes to the GCS configuration via ptrace
> > +  are not supported.

> On x86 CRIU needed to be able to temporarily unlock shadow stack features
> to recreate the shadow stack of the thread being restored. I presume CRIU
> will need something like that on arm64 as well.

It would be good to understand why and what exactly is needed here.
I'm guessing the main thing would be stores?  It's relatively easy to
add features later, I think I'll just add support for everything except
enable just now.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 04/35] arm64/gcs: Document the ABI for Guarded Control Stacks
  2023-07-19 13:25     ` Mark Brown
@ 2023-07-19 14:04       ` Mike Rapoport
  0 siblings, 0 replies; 51+ messages in thread
From: Mike Rapoport @ 2023-07-19 14:04 UTC (permalink / raw)
  To: Mark Brown
  Cc: Catalin Marinas, Will Deacon, Jonathan Corbet, Andrew Morton,
	Marc Zyngier, Oliver Upton, James Morse, Suzuki K Poulose,
	Arnd Bergmann, Oleg Nesterov, Eric Biederman, Kees Cook,
	Shuah Khan, Rick P. Edgecombe, Deepak Gupta, Ard Biesheuvel,
	Szabolcs Nagy, H.J. Lu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-arm-kernel, linux-doc, kvmarm, linux-fsdevel, linux-arch,
	linux-mm, linux-kselftest, linux-kernel, linux-riscv

On Wed, Jul 19, 2023 at 02:25:38PM +0100, Mark Brown wrote:
> On Wed, Jul 19, 2023 at 02:44:37PM +0300, Mike Rapoport wrote:
> > On Sun, Jul 16, 2023 at 10:51:00PM +0100, Mark Brown wrote:
> 
> > > +7.  ptrace extensions
> > > +---------------------
> > > +
> > > +* A new regset NT_ARM_GCS is defined for use with PTRACE_GETREGSET and
> > > +  PTRACE_SETREGSET.
> > > +
> > > +* Due to the complexity surrounding allocation and deallocation of stakcs and
> > > +  lack of practical application changes to the GCS configuration via ptrace
> > > +  are not supported.
> 
> > On x86 CRIU needed to be able to temporarily unlock shadow stack features
> > to recreate the shadow stack of the thread being restored. I presume CRIU
> > will need something like that on arm64 as well.
> 
> It would be good to understand why and what exactly is needed here.
> I'm guessing the main thing would be stores? 

Yes, CRIU has to modify the shadow stack.

CRIU uses sigreturn directly, so we had to update the shadow stack before
calling sigreturn.
On x86 ptrace(POKEDATA) and update of the shadow stack pointer were enough,
but it looks like ptrace(POKEDATA) won't work on arm64.

Another place that requires shadow stack modifications is the restore of
the shadow stack from the checkpoint. On x86 we had to enable WRSS and that
required to temporarily unlock the features.

> It's relatively easy to add features later, I think I'll just add support
> for everything except enable just now.

Fair enough :)

-- 
Sincerely yours,
Mike.

^ permalink raw reply	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2023-07-19 14:04 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-16 21:50 [PATCH 00/35] arm64/gcs: Provide support for GCS at EL0 Mark Brown
2023-07-16 21:50 ` [PATCH 01/35] prctl: arch-agnostic prctl for shadow stack Mark Brown
2023-07-18 17:45   ` Edgecombe, Rick P
2023-07-18 18:54     ` Mark Brown
2023-07-16 21:50 ` [PATCH 02/35] prctl: Add flag for shadow stack writeability and push/pop Mark Brown
2023-07-18 17:47   ` Edgecombe, Rick P
2023-07-18 19:10     ` Mark Brown
2023-07-16 21:50 ` [PATCH 03/35] arm64: Document boot requirements for Guarded Control Stacks Mark Brown
2023-07-16 21:51 ` [PATCH 04/35] arm64/gcs: Document the ABI " Mark Brown
2023-07-17 11:42   ` Jonathan Cameron
2023-07-19 11:44   ` Mike Rapoport
2023-07-19 13:25     ` Mark Brown
2023-07-19 14:04       ` Mike Rapoport
2023-07-16 21:51 ` [PATCH 05/35] arm64/sysreg: Add new system registers for GCS Mark Brown
2023-07-16 21:51 ` [PATCH 06/35] arm64/sysreg: Add definitions for architected GCS caps Mark Brown
2023-07-16 21:51 ` [PATCH 07/35] arm64/gcs: Add manual encodings of GCS instructions Mark Brown
2023-07-16 21:51 ` [PATCH 08/35] arm64/gcs: Provide copy_to_user_gcs() Mark Brown
2023-07-16 21:51 ` [PATCH 09/35] arm64/cpufeature: Runtime detection of Guarded Control Stack (GCS) Mark Brown
2023-07-16 21:51 ` [PATCH 10/35] arm64/mm: Allocate PIE slots for EL0 guarded control stack Mark Brown
2023-07-16 21:51 ` [PATCH 11/35] mm: Define VM_SHADOW_STACK for arm64 when we support GCS Mark Brown
2023-07-16 21:51 ` [PATCH 12/35] arm64/mm: Map pages for guarded control stack Mark Brown
2023-07-16 21:51 ` [PATCH 13/35] KVM: arm64: Manage GCS registers for guests Mark Brown
2023-07-16 21:51 ` [PATCH 14/35] arm64: Disable traps for GCS usage at EL0 and EL1 Mark Brown
2023-07-16 21:51 ` [PATCH 15/35] arm64/idreg: Add overrride for GCS Mark Brown
2023-07-16 21:51 ` [PATCH 16/35] arm64/hwcap: Add hwcap " Mark Brown
2023-07-16 21:51 ` [PATCH 17/35] arm64/traps: Handle GCS exceptions Mark Brown
2023-07-17 12:12   ` Jonathan Cameron
2023-07-16 21:51 ` [PATCH 18/35] arm64/mm: Handle GCS data aborts Mark Brown
2023-07-16 21:51 ` [PATCH 19/35] arm64/gcs: Context switch GCS registers for EL0 Mark Brown
2023-07-16 21:51 ` [PATCH 20/35] arm64/gcs: Allocate a new GCS for threads with GCS enabled Mark Brown
2023-07-16 21:51 ` [PATCH 21/35] arm64/gcs: Implement shadow stack prctl() interface Mark Brown
2023-07-18 17:51   ` Edgecombe, Rick P
2023-07-18 19:37     ` Mark Brown
2023-07-16 21:51 ` [PATCH 22/35] arm64/mm: Implement map_shadow_stack() Mark Brown
2023-07-18  9:10   ` Szabolcs Nagy
2023-07-18 13:55     ` Mark Brown
2023-07-18 15:49       ` Edgecombe, Rick P
2023-07-16 21:51 ` [PATCH 23/35] arm64/signal: Set up and restore the GCS context for signal handlers Mark Brown
2023-07-16 21:51 ` [PATCH 24/35] arm64/signal: Expose GCS state in signal frames Mark Brown
2023-07-16 21:51 ` [PATCH 25/35] arm64/ptrace: Expose GCS via ptrace and core files Mark Brown
2023-07-16 21:51 ` [PATCH 26/35] arm64: Add Kconfig for Guarded Control Stack (GCS) Mark Brown
2023-07-17 12:32   ` Jonathan Cameron
2023-07-16 21:51 ` [PATCH 27/35] kselftest/arm64: Verify the GCS hwcap Mark Brown
2023-07-16 21:51 ` [PATCH 28/35] kselftest/arm64: Add GCS as a detected feature in the signal tests Mark Brown
2023-07-16 21:51 ` [PATCH 29/35] kselftest/arm64: Add framework support for GCS to signal handling tests Mark Brown
2023-07-16 21:51 ` [PATCH 30/35] kselftest/arm64: Allow signals tests to specify an expected si_code Mark Brown
2023-07-16 21:51 ` [PATCH 31/35] kselftest/arm64: Always run signals tests with GCS enabled Mark Brown
2023-07-16 21:51 ` [PATCH 32/35] kselftest/arm64: Add very basic GCS test program Mark Brown
2023-07-16 21:51 ` [PATCH 33/35] kselftest/arm64: Add a GCS test program built with the system libc Mark Brown
2023-07-16 21:51 ` [PATCH 34/35] selftests/arm64: Add GCS signal tests Mark Brown
2023-07-16 21:51 ` [PATCH 35/35] kselftest/arm64: Enable GCS for the FP stress tests Mark Brown

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).