Path: blob/master/tools/testing/selftests/arm64/gcs/gcs-locking.c
26292 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Copyright (C) 2023 ARM Limited.3*4* Tests for GCS mode locking. These tests rely on both having GCS5* unconfigured on entry and on the kselftest harness running each6* test in a fork()ed process which will have it's own mode.7*/89#include <limits.h>1011#include <sys/auxv.h>12#include <sys/prctl.h>1314#include <asm/hwcap.h>1516#include "kselftest_harness.h"1718#include "gcs-util.h"1920#define my_syscall2(num, arg1, arg2) \21({ \22register long _num __asm__ ("x8") = (num); \23register long _arg1 __asm__ ("x0") = (long)(arg1); \24register long _arg2 __asm__ ("x1") = (long)(arg2); \25register long _arg3 __asm__ ("x2") = 0; \26register long _arg4 __asm__ ("x3") = 0; \27register long _arg5 __asm__ ("x4") = 0; \28\29__asm__ volatile ( \30"svc #0\n" \31: "=r"(_arg1) \32: "r"(_arg1), "r"(_arg2), \33"r"(_arg3), "r"(_arg4), \34"r"(_arg5), "r"(_num) \35: "memory", "cc" \36); \37_arg1; \38})3940/* No mode bits are rejected for locking */41TEST(lock_all_modes)42{43int ret;4445ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, ULONG_MAX, 0, 0, 0);46ASSERT_EQ(ret, 0);47}4849FIXTURE(valid_modes)50{51};5253FIXTURE_VARIANT(valid_modes)54{55unsigned long mode;56};5758FIXTURE_VARIANT_ADD(valid_modes, enable)59{60.mode = PR_SHADOW_STACK_ENABLE,61};6263FIXTURE_VARIANT_ADD(valid_modes, enable_write)64{65.mode = PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE,66};6768FIXTURE_VARIANT_ADD(valid_modes, enable_push)69{70.mode = PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_PUSH,71};7273FIXTURE_VARIANT_ADD(valid_modes, enable_write_push)74{75.mode = PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE |76PR_SHADOW_STACK_PUSH,77};7879FIXTURE_SETUP(valid_modes)80{81}8283FIXTURE_TEARDOWN(valid_modes)84{85}8687/* We can set the mode at all */88TEST_F(valid_modes, set)89{90int ret;9192ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,93variant->mode);94ASSERT_EQ(ret, 0);9596_exit(0);97}9899/* Enabling, locking then disabling is rejected */100TEST_F(valid_modes, enable_lock_disable)101{102unsigned long mode;103int ret;104105ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,106variant->mode);107ASSERT_EQ(ret, 0);108109ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0);110ASSERT_EQ(ret, 0);111ASSERT_EQ(mode, variant->mode);112113ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, variant->mode, 0, 0, 0);114ASSERT_EQ(ret, 0);115116ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 0);117ASSERT_EQ(ret, -EBUSY);118119_exit(0);120}121122/* Locking then enabling is rejected */123TEST_F(valid_modes, lock_enable)124{125unsigned long mode;126int ret;127128ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, variant->mode, 0, 0, 0);129ASSERT_EQ(ret, 0);130131ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,132variant->mode);133ASSERT_EQ(ret, -EBUSY);134135ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0);136ASSERT_EQ(ret, 0);137ASSERT_EQ(mode, 0);138139_exit(0);140}141142/* Locking then changing other modes is fine */143TEST_F(valid_modes, lock_enable_disable_others)144{145unsigned long mode;146int ret;147148ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,149variant->mode);150ASSERT_EQ(ret, 0);151152ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0);153ASSERT_EQ(ret, 0);154ASSERT_EQ(mode, variant->mode);155156ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, variant->mode, 0, 0, 0);157ASSERT_EQ(ret, 0);158159ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,160PR_SHADOW_STACK_ALL_MODES);161ASSERT_EQ(ret, 0);162163ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0);164ASSERT_EQ(ret, 0);165ASSERT_EQ(mode, PR_SHADOW_STACK_ALL_MODES);166167168ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,169variant->mode);170ASSERT_EQ(ret, 0);171172ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0);173ASSERT_EQ(ret, 0);174ASSERT_EQ(mode, variant->mode);175176_exit(0);177}178179int main(int argc, char **argv)180{181unsigned long mode;182int ret;183184if (!(getauxval(AT_HWCAP) & HWCAP_GCS))185ksft_exit_skip("SKIP GCS not supported\n");186187ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0);188if (ret) {189ksft_print_msg("Failed to read GCS state: %d\n", ret);190return EXIT_FAILURE;191}192193if (mode & PR_SHADOW_STACK_ENABLE) {194ksft_print_msg("GCS was enabled, test unsupported\n");195return KSFT_SKIP;196}197198return test_harness_run(argc, argv);199}200201202