Path: blob/master/tools/testing/selftests/arm64/gcs/gcs-locking.c
29270 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);166167ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,168variant->mode);169ASSERT_EQ(ret, 0);170171ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0);172ASSERT_EQ(ret, 0);173ASSERT_EQ(mode, variant->mode);174175_exit(0);176}177178int main(int argc, char **argv)179{180unsigned long mode;181int ret;182183if (!(getauxval(AT_HWCAP) & HWCAP_GCS))184ksft_exit_skip("SKIP GCS not supported\n");185186ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0);187if (ret) {188ksft_print_msg("Failed to read GCS state: %d\n", ret);189return EXIT_FAILURE;190}191192if (mode & PR_SHADOW_STACK_ENABLE) {193ksft_print_msg("GCS was enabled, test unsupported\n");194return KSFT_SKIP;195}196197return test_harness_run(argc, argv);198}199200201