From patchwork Fri Sep 18 10:47:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boyan Karatotev X-Patchwork-Id: 11784653 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A521C618 for ; Fri, 18 Sep 2020 10:47:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7B88921D24 for ; Fri, 18 Sep 2020 10:47:51 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Tkku6M8k" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726301AbgIRKrr (ORCPT ); Fri, 18 Sep 2020 06:47:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49800 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725941AbgIRKrq (ORCPT ); Fri, 18 Sep 2020 06:47:46 -0400 Received: from mail-wr1-x444.google.com (mail-wr1-x444.google.com [IPv6:2a00:1450:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2AF92C06174A; Fri, 18 Sep 2020 03:47:46 -0700 (PDT) Received: by mail-wr1-x444.google.com with SMTP id w5so5126626wrp.8; Fri, 18 Sep 2020 03:47:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=vCpwNFL5WsulLvsRaSslKFqGKBqySbME6CCaIMG6l/c=; b=Tkku6M8k5OZ1uFd+qd7N/NV6gdYFkCEg8b3cW2d2ah0ZE+XcsNYpG6ZkXDOxMG0xUJ /QrVIc8nU7+eyBFBGxo8TQ3OE8Jf80kdwk0/Fva5r5mrwvovDt7/z5LU8RrSQ4OW6nV1 1Q/14sylBHrM/jOJaUwNzOzSoG/PM+j1tQcA8ZXwCGsNJlSUcfqz1EcQ8zpfThRq0xVM hLBoa6apXbEh06qRuu3mzM+AH8zKZKWEteHemPpXu2HLUJza60s9cLkwUjkCSXdLz+UZ +JflaaD6r9lOim5NRdWiQYonKGFGHDcU2+av3qA29lqEULOdwkiM57zQBVmzbUxaEe1o lq4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=vCpwNFL5WsulLvsRaSslKFqGKBqySbME6CCaIMG6l/c=; b=hmmrZBnA1Sliyx1Koz/leu9D+BDLP6Vq8YlnZ24k74xNlJEDbxUUNAmCwFiPxqrDMk oZuJ1wfh3FYXfNWdXPxhx+7sS+wBqrGAPTyFu+dEq36eVHHzB9i6jlpToJ7t7rGImGxA d8kpSfKMNkrvA1ca3y+r1Ygn7wmVZX+54x8U0rqReKuivoMzU0OYZeW8Miz5vCCH7FdG djuinlPHASNtn8Tj01x9evhbKGSpGCQoAVSt9VS2kJedH4dWd2PT71ByK1MNf4nTAaTk Jt9R3SBLAArFbozM+bVzQQY6k54blFzMHcRYAyFPP264xfuwgKaPeNWMuIRDB03GXdiB 2H6Q== X-Gm-Message-State: AOAM532pEZPv/WgjMC+6tUdBE2pIPAqWB/Xn5qbb19NSlWMF5MHFHtaZ WOK4B97ewujLqxQ6YYjsMHE= X-Google-Smtp-Source: ABdhPJxq0TC8XUB6r9vQce7URu6nHJAPnXtki1Fd7qRog7U6btUK1yicrTQGiSjkcASdaa2LbttPWQ== X-Received: by 2002:adf:fa52:: with SMTP id y18mr37533018wrr.264.1600426064796; Fri, 18 Sep 2020 03:47:44 -0700 (PDT) Received: from trantor.home (cpc153975-seac28-2-0-cust722.7-2.cable.virginm.net. [81.109.38.211]) by smtp.gmail.com with ESMTPSA id h4sm5197846wrm.54.2020.09.18.03.47.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 18 Sep 2020 03:47:44 -0700 (PDT) From: Boyan Karatotev To: linux-arm-kernel@lists.infradead.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Boyan Karatotev , Boyan Karatotev , Shuah Khan , Catalin Marinas , Will Deacon , Vincenzo Frascino , Amit Daniel Kachhap , Shuah Khan Subject: [PATCH v3 1/4] kselftests/arm64: add a basic Pointer Authentication test Date: Fri, 18 Sep 2020 11:47:12 +0100 Message-Id: <20200918104715.182310-2-boian4o1@gmail.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200918104715.182310-1-boian4o1@gmail.com> References: <20200918104715.182310-1-boian4o1@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org From: Boyan Karatotev PAuth signs and verifies return addresses on the stack. It does so by inserting a Pointer Authentication code (PAC) into some of the unused top bits of an address. This is achieved by adding paciasp/autiasp instructions at the beginning and end of a function. This feature is partially backwards compatible with earlier versions of the ARM architecture. To coerce the compiler into emitting fully backwards compatible code the main file is compiled to target an earlier ARM version. This allows the tests to check for the feature and print meaningful error messages instead of crashing. Add a test to verify that corrupting the return address results in a SIGSEGV on return. Cc: Shuah Khan Cc: Catalin Marinas Cc: Will Deacon Reviewed-by: Vincenzo Frascino Reviewed-by: Amit Daniel Kachhap Acked-by: Shuah Khan Signed-off-by: Boyan Karatotev --- tools/testing/selftests/arm64/Makefile | 2 +- .../testing/selftests/arm64/pauth/.gitignore | 1 + tools/testing/selftests/arm64/pauth/Makefile | 32 ++++++++++++++ tools/testing/selftests/arm64/pauth/helper.h | 9 ++++ tools/testing/selftests/arm64/pauth/pac.c | 44 +++++++++++++++++++ .../selftests/arm64/pauth/pac_corruptor.S | 19 ++++++++ 6 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/arm64/pauth/.gitignore create mode 100644 tools/testing/selftests/arm64/pauth/Makefile create mode 100644 tools/testing/selftests/arm64/pauth/helper.h create mode 100644 tools/testing/selftests/arm64/pauth/pac.c create mode 100644 tools/testing/selftests/arm64/pauth/pac_corruptor.S diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile index 93b567d23c8b..525506fd97b9 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 +ARM64_SUBTARGETS ?= tags signal pauth else ARM64_SUBTARGETS := endif diff --git a/tools/testing/selftests/arm64/pauth/.gitignore b/tools/testing/selftests/arm64/pauth/.gitignore new file mode 100644 index 000000000000..b557c916720a --- /dev/null +++ b/tools/testing/selftests/arm64/pauth/.gitignore @@ -0,0 +1 @@ +pac diff --git a/tools/testing/selftests/arm64/pauth/Makefile b/tools/testing/selftests/arm64/pauth/Makefile new file mode 100644 index 000000000000..01d35aaa610a --- /dev/null +++ b/tools/testing/selftests/arm64/pauth/Makefile @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2020 ARM Limited + +# preserve CC value from top level Makefile +ifeq ($(CC),cc) +CC := $(CROSS_COMPILE)gcc +endif + +CFLAGS += -mbranch-protection=pac-ret +# check if the compiler supports ARMv8.3 and branch protection with PAuth +pauth_cc_support := $(shell if ($(CC) $(CFLAGS) -march=armv8.3-a -E -x c /dev/null -o /dev/null 2>&1) then echo "1"; fi) + +ifeq ($(pauth_cc_support),1) +TEST_GEN_PROGS := pac +TEST_GEN_FILES := pac_corruptor.o +endif + +include ../../lib.mk + +ifeq ($(pauth_cc_support),1) +# pac* and aut* instructions are not available on architectures berfore +# ARMv8.3. Therefore target ARMv8.3 wherever they are used directly +$(OUTPUT)/pac_corruptor.o: pac_corruptor.S + $(CC) -c $^ -o $@ $(CFLAGS) -march=armv8.3-a + +# when -mbranch-protection is enabled and the target architecture is ARMv8.3 or +# greater, gcc emits pac* instructions which are not in HINT NOP space, +# preventing the tests from occurring at all. Compile for ARMv8.2 so tests can +# run on earlier targets and print a meaningful error messages +$(OUTPUT)/pac: pac.c $(OUTPUT)/pac_corruptor.o + $(CC) $^ -o $@ $(CFLAGS) -march=armv8.2-a +endif diff --git a/tools/testing/selftests/arm64/pauth/helper.h b/tools/testing/selftests/arm64/pauth/helper.h new file mode 100644 index 000000000000..3e0a2a404bf4 --- /dev/null +++ b/tools/testing/selftests/arm64/pauth/helper.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2020 ARM Limited */ + +#ifndef _HELPER_H_ +#define _HELPER_H_ + +void pac_corruptor(void); + +#endif diff --git a/tools/testing/selftests/arm64/pauth/pac.c b/tools/testing/selftests/arm64/pauth/pac.c new file mode 100644 index 000000000000..0293310ba70a --- /dev/null +++ b/tools/testing/selftests/arm64/pauth/pac.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2020 ARM Limited + +#include +#include +#include + +#include "../../kselftest_harness.h" +#include "helper.h" + +#define ASSERT_PAUTH_ENABLED() \ +do { \ + unsigned long hwcaps = getauxval(AT_HWCAP); \ + /* data key instructions are not in NOP space. This prevents a SIGILL */ \ + ASSERT_NE(0, hwcaps & HWCAP_PACA) TH_LOG("PAUTH not enabled"); \ +} while (0) + +sigjmp_buf jmpbuf; +void pac_signal_handler(int signum, siginfo_t *si, void *uc) +{ + if (signum == SIGSEGV || signum == SIGILL) + siglongjmp(jmpbuf, 1); +} + +/* check that a corrupted PAC results in SIGSEGV or SIGILL */ +TEST(corrupt_pac) +{ + struct sigaction sa; + + ASSERT_PAUTH_ENABLED(); + if (sigsetjmp(jmpbuf, 1) == 0) { + sa.sa_sigaction = pac_signal_handler; + sa.sa_flags = SA_SIGINFO | SA_RESETHAND; + sigemptyset(&sa.sa_mask); + + sigaction(SIGSEGV, &sa, NULL); + sigaction(SIGILL, &sa, NULL); + + pac_corruptor(); + ASSERT_TRUE(0) TH_LOG("SIGSEGV/SIGILL signal did not occur"); + } +} + +TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/arm64/pauth/pac_corruptor.S b/tools/testing/selftests/arm64/pauth/pac_corruptor.S new file mode 100644 index 000000000000..aa6588050752 --- /dev/null +++ b/tools/testing/selftests/arm64/pauth/pac_corruptor.S @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2020 ARM Limited */ + +.global pac_corruptor + +.text +/* + * Corrupting a single bit of the PAC ensures the authentication will fail. It + * also guarantees no possible collision. TCR_EL1.TBI0 is set by default so no + * top byte PAC is tested + */ + pac_corruptor: + paciasp + + /* corrupt the top bit of the PAC */ + eor lr, lr, #1 << 53 + + autiasp + ret From patchwork Fri Sep 18 10:47:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boyan Karatotev X-Patchwork-Id: 11784659 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 646B16CA for ; Fri, 18 Sep 2020 10:48:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 47BAF21D92 for ; Fri, 18 Sep 2020 10:48:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Tn8eW1Rj" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726344AbgIRKry (ORCPT ); Fri, 18 Sep 2020 06:47:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49808 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726298AbgIRKrr (ORCPT ); Fri, 18 Sep 2020 06:47:47 -0400 Received: from mail-wm1-x341.google.com (mail-wm1-x341.google.com [IPv6:2a00:1450:4864:20::341]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 62867C06174A; Fri, 18 Sep 2020 03:47:47 -0700 (PDT) Received: by mail-wm1-x341.google.com with SMTP id q9so4868815wmj.2; Fri, 18 Sep 2020 03:47:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=7f3R/YrvQ9iFIR/7ACD20Akwt7csQcsSAaA3rblwrRI=; b=Tn8eW1Rjz007/784pM3YefcDbmG4YjwpGGbcJ1/DxH1X0k0lmKZ+f68oJXbODQOPLe xawP1m2IQElO5OutuocP6IHxPtSki+dKI8XsMCO8NAmKXM6GMrG7F6tGi5key6gsSP95 pRxIHzXILPWBmP+AhKh9jmu9iF2qn3msRShdcf+pjHQP+soRtqvwR0Kx2oAwpW/ue/tR 8sDYgA+fMKoGpQkwC0TATYNfiga/iOFI3H/ChypeV3PdObuWBePGcsXSKHkpVWefvKme GwITjI1YHlkucw12HeVA20pU3TxBwPe+oyKgCrXiMK1fEKYLmcjb0LEcX8PACGSlTk2Y Qr6A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=7f3R/YrvQ9iFIR/7ACD20Akwt7csQcsSAaA3rblwrRI=; b=VHswDuX/24QQ9F6hfi20V54/FYl1kdtmE2YiU6XJXpEuIpfXJtRN8WODMkyDlw1qmG o42w70qehf17aO5viZhy+YxP+0UzqNzRj/1KutO/ClccJOIrNyrHC+x5rpRo7hhC16s9 DWXacBtnxH9TbVcOsmzVBxhOBWPwYeYey3U3aH/lj72mZmwmtDo/rjLHWXmNTvh9ft4Y nmpBfAIL1t0xf0WlEujeckd1mc5fbOkUE7NW/8AFOGj/kVSqbvRHZAG0CpSWVfRx+Z2A AsdC2dRCeZGBebSLCx9mKWiTigAc+Tgm1QUK7woBqk+Bd7MyEzo+JDryYjvmvveuAAu3 +wtQ== X-Gm-Message-State: AOAM5337zkCGUJaAN2ilU1wYmJsgyPXk+TTUQPLc41EzogEHAVRLvM30 7ZHlB4tZRj/fEtXmB+72OxM= X-Google-Smtp-Source: ABdhPJz08Z6EApZk2T6twKvkYavHoMZs2cp6r9bDJj8jGscZ0eIBYB4qzH/kgB82N+X/a8j3srrAPA== X-Received: by 2002:a1c:7215:: with SMTP id n21mr15770441wmc.154.1600426065931; Fri, 18 Sep 2020 03:47:45 -0700 (PDT) Received: from trantor.home (cpc153975-seac28-2-0-cust722.7-2.cable.virginm.net. [81.109.38.211]) by smtp.gmail.com with ESMTPSA id h4sm5197846wrm.54.2020.09.18.03.47.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 18 Sep 2020 03:47:45 -0700 (PDT) From: Boyan Karatotev To: linux-arm-kernel@lists.infradead.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Boyan Karatotev , Boyan Karatotev , Shuah Khan , Catalin Marinas , Will Deacon , Vincenzo Frascino , Amit Daniel Kachhap , Shuah Khan Subject: [PATCH v3 2/4] kselftests/arm64: add nop checks for PAuth tests Date: Fri, 18 Sep 2020 11:47:13 +0100 Message-Id: <20200918104715.182310-3-boian4o1@gmail.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200918104715.182310-1-boian4o1@gmail.com> References: <20200918104715.182310-1-boian4o1@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org From: Boyan Karatotev PAuth adds sign/verify controls to enable and disable groups of instructions in hardware for compatibility with libraries that do not implement PAuth. The kernel always enables them if it detects PAuth. Add a test that checks that each group of instructions is enabled, if the kernel reports PAuth as detected. Note: For groups, for the purpose of this patch, we intend instructions that use a certain key. Cc: Shuah Khan Cc: Catalin Marinas Cc: Will Deacon Reviewed-by: Vincenzo Frascino Reviewed-by: Amit Daniel Kachhap Acked-by: Shuah Khan Signed-off-by: Boyan Karatotev --- .../testing/selftests/arm64/pauth/.gitignore | 1 + tools/testing/selftests/arm64/pauth/Makefile | 7 ++- tools/testing/selftests/arm64/pauth/helper.c | 39 ++++++++++++++ tools/testing/selftests/arm64/pauth/helper.h | 9 ++++ tools/testing/selftests/arm64/pauth/pac.c | 51 +++++++++++++++++++ 5 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/arm64/pauth/helper.c diff --git a/tools/testing/selftests/arm64/pauth/.gitignore b/tools/testing/selftests/arm64/pauth/.gitignore index b557c916720a..155137d92722 100644 --- a/tools/testing/selftests/arm64/pauth/.gitignore +++ b/tools/testing/selftests/arm64/pauth/.gitignore @@ -1 +1,2 @@ +exec_target pac diff --git a/tools/testing/selftests/arm64/pauth/Makefile b/tools/testing/selftests/arm64/pauth/Makefile index 01d35aaa610a..5c0dd129562f 100644 --- a/tools/testing/selftests/arm64/pauth/Makefile +++ b/tools/testing/selftests/arm64/pauth/Makefile @@ -12,7 +12,7 @@ pauth_cc_support := $(shell if ($(CC) $(CFLAGS) -march=armv8.3-a -E -x c /dev/nu ifeq ($(pauth_cc_support),1) TEST_GEN_PROGS := pac -TEST_GEN_FILES := pac_corruptor.o +TEST_GEN_FILES := pac_corruptor.o helper.o endif include ../../lib.mk @@ -23,10 +23,13 @@ ifeq ($(pauth_cc_support),1) $(OUTPUT)/pac_corruptor.o: pac_corruptor.S $(CC) -c $^ -o $@ $(CFLAGS) -march=armv8.3-a +$(OUTPUT)/helper.o: helper.c + $(CC) -c $^ -o $@ $(CFLAGS) -march=armv8.3-a + # when -mbranch-protection is enabled and the target architecture is ARMv8.3 or # greater, gcc emits pac* instructions which are not in HINT NOP space, # preventing the tests from occurring at all. Compile for ARMv8.2 so tests can # run on earlier targets and print a meaningful error messages -$(OUTPUT)/pac: pac.c $(OUTPUT)/pac_corruptor.o +$(OUTPUT)/pac: pac.c $(OUTPUT)/pac_corruptor.o $(OUTPUT)/helper.o $(CC) $^ -o $@ $(CFLAGS) -march=armv8.2-a endif diff --git a/tools/testing/selftests/arm64/pauth/helper.c b/tools/testing/selftests/arm64/pauth/helper.c new file mode 100644 index 000000000000..2c201e7d0d50 --- /dev/null +++ b/tools/testing/selftests/arm64/pauth/helper.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2020 ARM Limited + +#include "helper.h" + +size_t keyia_sign(size_t ptr) +{ + asm volatile("paciza %0" : "+r" (ptr)); + return ptr; +} + +size_t keyib_sign(size_t ptr) +{ + asm volatile("pacizb %0" : "+r" (ptr)); + return ptr; +} + +size_t keyda_sign(size_t ptr) +{ + asm volatile("pacdza %0" : "+r" (ptr)); + return ptr; +} + +size_t keydb_sign(size_t ptr) +{ + asm volatile("pacdzb %0" : "+r" (ptr)); + return ptr; +} + +size_t keyg_sign(size_t ptr) +{ + /* output is encoded in the upper 32 bits */ + size_t dest = 0; + size_t modifier = 0; + + asm volatile("pacga %0, %1, %2" : "=r" (dest) : "r" (ptr), "r" (modifier)); + + return dest; +} diff --git a/tools/testing/selftests/arm64/pauth/helper.h b/tools/testing/selftests/arm64/pauth/helper.h index 3e0a2a404bf4..35c4f3357ae3 100644 --- a/tools/testing/selftests/arm64/pauth/helper.h +++ b/tools/testing/selftests/arm64/pauth/helper.h @@ -4,6 +4,15 @@ #ifndef _HELPER_H_ #define _HELPER_H_ +#include + void pac_corruptor(void); +/* PAuth sign a value with key ia and modifier value 0 */ +size_t keyia_sign(size_t val); +size_t keyib_sign(size_t val); +size_t keyda_sign(size_t val); +size_t keydb_sign(size_t val); +size_t keyg_sign(size_t val); + #endif diff --git a/tools/testing/selftests/arm64/pauth/pac.c b/tools/testing/selftests/arm64/pauth/pac.c index 0293310ba70a..bd3d4c0eca9d 100644 --- a/tools/testing/selftests/arm64/pauth/pac.c +++ b/tools/testing/selftests/arm64/pauth/pac.c @@ -8,12 +8,25 @@ #include "../../kselftest_harness.h" #include "helper.h" +#define PAC_COLLISION_ATTEMPTS 10 +/* + * The kernel sets TBID by default. So bits 55 and above should remain + * untouched no matter what. + * The VA space size is 48 bits. Bigger is opt-in. + */ +#define PAC_MASK (~0xff80ffffffffffff) #define ASSERT_PAUTH_ENABLED() \ do { \ unsigned long hwcaps = getauxval(AT_HWCAP); \ /* data key instructions are not in NOP space. This prevents a SIGILL */ \ ASSERT_NE(0, hwcaps & HWCAP_PACA) TH_LOG("PAUTH not enabled"); \ } while (0) +#define ASSERT_GENERIC_PAUTH_ENABLED() \ +do { \ + unsigned long hwcaps = getauxval(AT_HWCAP); \ + /* generic key instructions are not in NOP space. This prevents a SIGILL */ \ + ASSERT_NE(0, hwcaps & HWCAP_PACG) TH_LOG("Generic PAUTH not enabled"); \ +} while (0) sigjmp_buf jmpbuf; void pac_signal_handler(int signum, siginfo_t *si, void *uc) @@ -41,4 +54,42 @@ TEST(corrupt_pac) } } +/* + * There are no separate pac* and aut* controls so checking only the pac* + * instructions is sufficient + */ +TEST(pac_instructions_not_nop) +{ + size_t keyia = 0; + size_t keyib = 0; + size_t keyda = 0; + size_t keydb = 0; + + ASSERT_PAUTH_ENABLED(); + + for (int i = 0; i < PAC_COLLISION_ATTEMPTS; i++) { + keyia |= keyia_sign(i) & PAC_MASK; + keyib |= keyib_sign(i) & PAC_MASK; + keyda |= keyda_sign(i) & PAC_MASK; + keydb |= keydb_sign(i) & PAC_MASK; + } + + ASSERT_NE(0, keyia) TH_LOG("keyia instructions did nothing"); + ASSERT_NE(0, keyib) TH_LOG("keyib instructions did nothing"); + ASSERT_NE(0, keyda) TH_LOG("keyda instructions did nothing"); + ASSERT_NE(0, keydb) TH_LOG("keydb instructions did nothing"); +} + +TEST(pac_instructions_not_nop_generic) +{ + size_t keyg = 0; + + ASSERT_GENERIC_PAUTH_ENABLED(); + + for (int i = 0; i < PAC_COLLISION_ATTEMPTS; i++) + keyg |= keyg_sign(i) & PAC_MASK; + + ASSERT_NE(0, keyg) TH_LOG("keyg instructions did nothing"); +} + TEST_HARNESS_MAIN From patchwork Fri Sep 18 10:47:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boyan Karatotev X-Patchwork-Id: 11784657 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0C409618 for ; Fri, 18 Sep 2020 10:48:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D89ED21D92 for ; Fri, 18 Sep 2020 10:48:03 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="o/l08dU0" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726361AbgIRKrz (ORCPT ); Fri, 18 Sep 2020 06:47:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49812 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726309AbgIRKrt (ORCPT ); Fri, 18 Sep 2020 06:47:49 -0400 Received: from mail-wr1-x441.google.com (mail-wr1-x441.google.com [IPv6:2a00:1450:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B9872C061756; Fri, 18 Sep 2020 03:47:48 -0700 (PDT) Received: by mail-wr1-x441.google.com with SMTP id w5so5126747wrp.8; Fri, 18 Sep 2020 03:47:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=mIUKYQBe5Fl+GZXzuMdAIZ0zeMrQ+6eL85ZD/kHw8aY=; b=o/l08dU0a3iblTzC+cQL18/yCNFr+G6et9Nfymcwn3P7xz+BuqkejV3JvsJI4gVLq+ nN3aArF1cqbbiT00q1Sd0xLznM6Hr9WQAVN12rzM3eQMRX5QkYum4QFvbWnt9upRItHo 1NRxIeeMeeoNyr2KaWG3U4dk97gxDRlY1XYEzwtVstTPU7YFvR9SWxA0orlnIRuKl9Md sycaJp8s0tg9su+5g5VscOmyRIqkulX6lyPNCPJIwTZZplkm/dauDGzaNgbpEyRzTetS uyPUkYK1mmfNZm7AffTQTN/WzdLNN2CXGYq+LSpWj2IkcZ3LhDGMn3HFN6i79mqrO7fW p+YA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=mIUKYQBe5Fl+GZXzuMdAIZ0zeMrQ+6eL85ZD/kHw8aY=; b=Zwkpuos2GP2wY7NqDq8FLiwdmc8TF1kJtQhi7YVyo4Q1lI0NuGSYsz8V8al63P+TMA wqAwtwGSVdIpszMHs/knK78g3C3VBdW1jyOrFPzH9jmljA20TSeG63o1JnEGm2nX3GJY Qchn3UfK801W1ddAsc4Bdv4sMqLav6U2rc5mqTinxdovGKaoKNIwmnry5JpZ+fvdpAkn M2wiyeubQW7k+0M0GKKU8g02PQWFIUDB4IG5ZiZOhEaviP9QZJoOL2qgs55FzbBR4pR8 LMlp4oTuYbm7Tgk11N4ftCzdUapCQr0nxsFpDZGEVDHsAcOL5e+uEK0ShU6oMvB5ffMk 40Rw== X-Gm-Message-State: AOAM533x7JpVsZHUvx02pYfvQ4dZ2SPdBwLVaY2+L+AcmA8JeaJKzqj2 4LwqNw/FEirUuaiOFkqUipQ= X-Google-Smtp-Source: ABdhPJyDY4zAyIqiiJ/zK6mMJVToLY91t8rOydnNP7+wypwPmVLmuAtew63ljrzeKgiu1sV0AjqoKQ== X-Received: by 2002:a5d:430d:: with SMTP id h13mr39405899wrq.41.1600426067296; Fri, 18 Sep 2020 03:47:47 -0700 (PDT) Received: from trantor.home (cpc153975-seac28-2-0-cust722.7-2.cable.virginm.net. [81.109.38.211]) by smtp.gmail.com with ESMTPSA id h4sm5197846wrm.54.2020.09.18.03.47.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 18 Sep 2020 03:47:46 -0700 (PDT) From: Boyan Karatotev To: linux-arm-kernel@lists.infradead.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Boyan Karatotev , Boyan Karatotev , Shuah Khan , Catalin Marinas , Will Deacon , Vincenzo Frascino , Amit Daniel Kachhap , Shuah Khan Subject: [PATCH v3 3/4] kselftests/arm64: add PAuth test for whether exec() changes keys Date: Fri, 18 Sep 2020 11:47:14 +0100 Message-Id: <20200918104715.182310-4-boian4o1@gmail.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200918104715.182310-1-boian4o1@gmail.com> References: <20200918104715.182310-1-boian4o1@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org From: Boyan Karatotev Kernel documentation states that it will change PAuth keys on exec() calls. Verify that all keys are correctly switched to new ones. Cc: Shuah Khan Cc: Catalin Marinas Cc: Will Deacon Reviewed-by: Vincenzo Frascino Reviewed-by: Amit Daniel Kachhap Acked-by: Shuah Khan Signed-off-by: Boyan Karatotev --- tools/testing/selftests/arm64/pauth/Makefile | 4 + .../selftests/arm64/pauth/exec_target.c | 34 ++++ tools/testing/selftests/arm64/pauth/helper.h | 10 ++ tools/testing/selftests/arm64/pauth/pac.c | 150 ++++++++++++++++++ 4 files changed, 198 insertions(+) create mode 100644 tools/testing/selftests/arm64/pauth/exec_target.c diff --git a/tools/testing/selftests/arm64/pauth/Makefile b/tools/testing/selftests/arm64/pauth/Makefile index 5c0dd129562f..72e290b0b10c 100644 --- a/tools/testing/selftests/arm64/pauth/Makefile +++ b/tools/testing/selftests/arm64/pauth/Makefile @@ -13,6 +13,7 @@ pauth_cc_support := $(shell if ($(CC) $(CFLAGS) -march=armv8.3-a -E -x c /dev/nu ifeq ($(pauth_cc_support),1) TEST_GEN_PROGS := pac TEST_GEN_FILES := pac_corruptor.o helper.o +TEST_GEN_PROGS_EXTENDED := exec_target endif include ../../lib.mk @@ -30,6 +31,9 @@ $(OUTPUT)/helper.o: helper.c # greater, gcc emits pac* instructions which are not in HINT NOP space, # preventing the tests from occurring at all. Compile for ARMv8.2 so tests can # run on earlier targets and print a meaningful error messages +$(OUTPUT)/exec_target: exec_target.c $(OUTPUT)/helper.o + $(CC) $^ -o $@ $(CFLAGS) -march=armv8.2-a + $(OUTPUT)/pac: pac.c $(OUTPUT)/pac_corruptor.o $(OUTPUT)/helper.o $(CC) $^ -o $@ $(CFLAGS) -march=armv8.2-a endif diff --git a/tools/testing/selftests/arm64/pauth/exec_target.c b/tools/testing/selftests/arm64/pauth/exec_target.c new file mode 100644 index 000000000000..4435600ca400 --- /dev/null +++ b/tools/testing/selftests/arm64/pauth/exec_target.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2020 ARM Limited + +#include +#include +#include + +#include "helper.h" + +int main(void) +{ + struct signatures signed_vals; + unsigned long hwcaps; + size_t val; + + fread(&val, sizeof(size_t), 1, stdin); + + /* don't try to execute illegal (unimplemented) instructions) caller + * should have checked this and keep worker simple + */ + hwcaps = getauxval(AT_HWCAP); + + if (hwcaps & HWCAP_PACA) { + signed_vals.keyia = keyia_sign(val); + signed_vals.keyib = keyib_sign(val); + signed_vals.keyda = keyda_sign(val); + signed_vals.keydb = keydb_sign(val); + } + signed_vals.keyg = (hwcaps & HWCAP_PACG) ? keyg_sign(val) : 0; + + fwrite(&signed_vals, sizeof(struct signatures), 1, stdout); + + return 0; +} diff --git a/tools/testing/selftests/arm64/pauth/helper.h b/tools/testing/selftests/arm64/pauth/helper.h index 35c4f3357ae3..652496c7b411 100644 --- a/tools/testing/selftests/arm64/pauth/helper.h +++ b/tools/testing/selftests/arm64/pauth/helper.h @@ -6,6 +6,16 @@ #include +#define NKEYS 5 + +struct signatures { + size_t keyia; + size_t keyib; + size_t keyda; + size_t keydb; + size_t keyg; +}; + void pac_corruptor(void); /* PAuth sign a value with key ia and modifier value 0 */ diff --git a/tools/testing/selftests/arm64/pauth/pac.c b/tools/testing/selftests/arm64/pauth/pac.c index bd3d4c0eca9d..b363ad6a0b50 100644 --- a/tools/testing/selftests/arm64/pauth/pac.c +++ b/tools/testing/selftests/arm64/pauth/pac.c @@ -2,6 +2,8 @@ // Copyright (C) 2020 ARM Limited #include +#include +#include #include #include @@ -28,6 +30,117 @@ do { \ ASSERT_NE(0, hwcaps & HWCAP_PACG) TH_LOG("Generic PAUTH not enabled"); \ } while (0) +void sign_specific(struct signatures *sign, size_t val) +{ + sign->keyia = keyia_sign(val); + sign->keyib = keyib_sign(val); + sign->keyda = keyda_sign(val); + sign->keydb = keydb_sign(val); +} + +void sign_all(struct signatures *sign, size_t val) +{ + sign->keyia = keyia_sign(val); + sign->keyib = keyib_sign(val); + sign->keyda = keyda_sign(val); + sign->keydb = keydb_sign(val); + sign->keyg = keyg_sign(val); +} + +int n_same(struct signatures *old, struct signatures *new, int nkeys) +{ + int res = 0; + + res += old->keyia == new->keyia; + res += old->keyib == new->keyib; + res += old->keyda == new->keyda; + res += old->keydb == new->keydb; + if (nkeys == NKEYS) + res += old->keyg == new->keyg; + + return res; +} + +int exec_sign_all(struct signatures *signed_vals, size_t val) +{ + int new_stdin[2]; + int new_stdout[2]; + int status; + ssize_t ret; + pid_t pid; + + ret = pipe(new_stdin); + if (ret == -1) { + perror("pipe returned error"); + return -1; + } + + ret = pipe(new_stdout); + if (ret == -1) { + perror("pipe returned error"); + return -1; + } + + pid = fork(); + // child + if (pid == 0) { + dup2(new_stdin[0], STDIN_FILENO); + if (ret == -1) { + perror("dup2 returned error"); + exit(1); + } + + dup2(new_stdout[1], STDOUT_FILENO); + if (ret == -1) { + perror("dup2 returned error"); + exit(1); + } + + close(new_stdin[0]); + close(new_stdin[1]); + close(new_stdout[0]); + close(new_stdout[1]); + + ret = execl("exec_target", "exec_target", (char *)NULL); + if (ret == -1) { + perror("exec returned error"); + exit(1); + } + } + + close(new_stdin[0]); + close(new_stdout[1]); + + ret = write(new_stdin[1], &val, sizeof(size_t)); + if (ret == -1) { + perror("write returned error"); + return -1; + } + + /* + * wait for the worker to finish, so that read() reads all data + * will also context switch with worker so that this function can be used + * for context switch tests + */ + waitpid(pid, &status, 0); + if (WIFEXITED(status) == 0) { + fprintf(stderr, "worker exited unexpectedly\n"); + return -1; + } + if (WEXITSTATUS(status) != 0) { + fprintf(stderr, "worker exited with error\n"); + return -1; + } + + ret = read(new_stdout[0], signed_vals, sizeof(struct signatures)); + if (ret == -1) { + perror("read returned error"); + return -1; + } + + return 0; +} + sigjmp_buf jmpbuf; void pac_signal_handler(int signum, siginfo_t *si, void *uc) { @@ -92,4 +205,41 @@ TEST(pac_instructions_not_nop_generic) ASSERT_NE(0, keyg) TH_LOG("keyg instructions did nothing"); } +/* + * fork() does not change keys. Only exec() does so call a worker program. + * Its only job is to sign a value and report back the resutls + */ +TEST(exec_changed_keys) +{ + struct signatures new_keys; + struct signatures old_keys; + int ret; + int same = 10; + int nkeys = NKEYS; + unsigned long hwcaps = getauxval(AT_HWCAP); + + /* generic and data key instructions are not in NOP space. This prevents a SIGILL */ + ASSERT_NE(0, hwcaps & HWCAP_PACA) TH_LOG("PAUTH not enabled"); + if (!(hwcaps & HWCAP_PACG)) { + TH_LOG("WARNING: Generic PAUTH not enabled. Skipping generic key checks"); + nkeys = NKEYS - 1; + } + + for (int i = 0; i < PAC_COLLISION_ATTEMPTS; i++) { + ret = exec_sign_all(&new_keys, i); + ASSERT_EQ(0, ret) TH_LOG("failed to run worker"); + + if (nkeys == NKEYS) + sign_all(&old_keys, i); + else + sign_specific(&old_keys, i); + + ret = n_same(&old_keys, &new_keys, nkeys); + if (ret < same) + same = ret; + } + + ASSERT_EQ(0, same) TH_LOG("exec() did not change %d keys", same); +} + TEST_HARNESS_MAIN From patchwork Fri Sep 18 10:47:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boyan Karatotev X-Patchwork-Id: 11784661 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 33C65618 for ; Fri, 18 Sep 2020 10:48:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 18B0E2311B for ; Fri, 18 Sep 2020 10:48:05 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="tLIzLF13" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726333AbgIRKry (ORCPT ); Fri, 18 Sep 2020 06:47:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49816 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725941AbgIRKru (ORCPT ); Fri, 18 Sep 2020 06:47:50 -0400 Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BA8C9C061788; Fri, 18 Sep 2020 03:47:49 -0700 (PDT) Received: by mail-wm1-x344.google.com with SMTP id q9so4868942wmj.2; Fri, 18 Sep 2020 03:47:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=RXEWTobRs9s4LJElS8zg1xI5BJD4hPEpT7/WyMI0e3E=; b=tLIzLF1385PXg1qesSX6Ao/H78e7i6GpdmrAz11ynssT3DtTjFVN2OJ5aykNxkqPVD 1wdd0ygyRWN03W9bYycXGfGflKa2zAulQT3+TFSXAr3G8XVwSgFoCNp4GtudmijXbVkQ vXA4XqqaH/0+v5dfDffV7dwV08iwMe8lg45Gt9hacm8RaQKM6pGKgx4dvhpyg/4IkKDn zT4OXsSSaMl3MSutU2MfWNZlKeuwCV/mBH4Uoum0XYJeuCWvnygWWshK1A7lJPGD4oDT ITsb1PYfO17ipwV6UaekjbQAg6RZHvN76urKQjGUWDok5r2yevKby5vgYefS9VHz8vGy XWig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=RXEWTobRs9s4LJElS8zg1xI5BJD4hPEpT7/WyMI0e3E=; b=hRO7wvBHdPENMz+ONCVoWeg8qrwnH3yR7cdLkBF2dGo/tlHhJiEfOQEnyn74F5cdjg wITEInsUly0uRFlWNugwBGWhY3iHrfXuepoRgNfTTGeCZnzwY5cralt3foFVtX5C7aGt AkmtLK9QMXbn/71zxero8rbHPmwJZ2weRzZn/C8HX7p+JndR30l7LN8slsUfdvpYSHxZ I30lAutPBxtTAQWfqJfGKXPMzQZDLJ7cAMf1T3VDOA7zRw84sW6BdnKpvhOVGJ8omAG2 dqZlhzPu8+/h3Vff1UfnDXIgLuFxIACnc+Pl4lN0co5O8BfmEkHl+tNKYIDELlAqXj1F /GTA== X-Gm-Message-State: AOAM5306Q6ZO/YK2XeYveDK3k5Nea5FSHtmkT89RCPus+DYQpASnZFEE hsu1bGJoz/Uy50ovr7E6dzI= X-Google-Smtp-Source: ABdhPJx+JMAvI8aS57FSOrkxf9jA7gU15ImEW1d0y0N9Gei37t0QRZBKOUQzrhl5UZIy8UQvPwZ93A== X-Received: by 2002:a7b:c210:: with SMTP id x16mr14534401wmi.37.1600426068480; Fri, 18 Sep 2020 03:47:48 -0700 (PDT) Received: from trantor.home (cpc153975-seac28-2-0-cust722.7-2.cable.virginm.net. [81.109.38.211]) by smtp.gmail.com with ESMTPSA id h4sm5197846wrm.54.2020.09.18.03.47.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 18 Sep 2020 03:47:48 -0700 (PDT) From: Boyan Karatotev To: linux-arm-kernel@lists.infradead.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Boyan Karatotev , Boyan Karatotev , Shuah Khan , Catalin Marinas , Will Deacon , Vincenzo Frascino , Amit Daniel Kachhap , Shuah Khan Subject: [PATCH v3 4/4] kselftests/arm64: add PAuth tests for single threaded consistency and differently initialized keys Date: Fri, 18 Sep 2020 11:47:15 +0100 Message-Id: <20200918104715.182310-5-boian4o1@gmail.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200918104715.182310-1-boian4o1@gmail.com> References: <20200918104715.182310-1-boian4o1@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org From: Boyan Karatotev PAuth adds 5 different keys that can be used to sign addresses. Add a test that verifies that the kernel initializes them to different values and preserves them across context switches. Cc: Shuah Khan Cc: Catalin Marinas Cc: Will Deacon Reviewed-by: Vincenzo Frascino Reviewed-by: Amit Daniel Kachhap Acked-by: Shuah Khan Signed-off-by: Boyan Karatotev --- tools/testing/selftests/arm64/pauth/pac.c | 123 ++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/tools/testing/selftests/arm64/pauth/pac.c b/tools/testing/selftests/arm64/pauth/pac.c index b363ad6a0b50..592fe538506e 100644 --- a/tools/testing/selftests/arm64/pauth/pac.c +++ b/tools/testing/selftests/arm64/pauth/pac.c @@ -1,11 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2020 ARM Limited +#define _GNU_SOURCE + #include #include #include #include #include +#include #include "../../kselftest_harness.h" #include "helper.h" @@ -17,6 +20,7 @@ * The VA space size is 48 bits. Bigger is opt-in. */ #define PAC_MASK (~0xff80ffffffffffff) +#define ARBITRARY_VALUE (0x1234) #define ASSERT_PAUTH_ENABLED() \ do { \ unsigned long hwcaps = getauxval(AT_HWCAP); \ @@ -61,13 +65,37 @@ int n_same(struct signatures *old, struct signatures *new, int nkeys) return res; } +int n_same_single_set(struct signatures *sign, int nkeys) +{ + size_t vals[nkeys]; + int same = 0; + + vals[0] = sign->keyia & PAC_MASK; + vals[1] = sign->keyib & PAC_MASK; + vals[2] = sign->keyda & PAC_MASK; + vals[3] = sign->keydb & PAC_MASK; + + if (nkeys >= 4) + vals[4] = sign->keyg & PAC_MASK; + + for (int i = 0; i < nkeys - 1; i++) { + for (int j = i + 1; j < nkeys; j++) { + if (vals[i] == vals[j]) + same += 1; + } + } + return same; +} + int exec_sign_all(struct signatures *signed_vals, size_t val) { int new_stdin[2]; int new_stdout[2]; int status; + int i; ssize_t ret; pid_t pid; + cpu_set_t mask; ret = pipe(new_stdin); if (ret == -1) { @@ -81,6 +109,20 @@ int exec_sign_all(struct signatures *signed_vals, size_t val) return -1; } + /* + * pin this process and all its children to a single CPU, so it can also + * guarantee a context switch with its child + */ + sched_getaffinity(0, sizeof(mask), &mask); + + for (i = 0; i < sizeof(cpu_set_t); i++) + if (CPU_ISSET(i, &mask)) + break; + + CPU_ZERO(&mask); + CPU_SET(i, &mask); + sched_setaffinity(0, sizeof(mask), &mask); + pid = fork(); // child if (pid == 0) { @@ -205,6 +247,44 @@ TEST(pac_instructions_not_nop_generic) ASSERT_NE(0, keyg) TH_LOG("keyg instructions did nothing"); } +TEST(single_thread_different_keys) +{ + int same = 10; + int nkeys = NKEYS; + int tmp; + struct signatures signed_vals; + unsigned long hwcaps = getauxval(AT_HWCAP); + + /* generic and data key instructions are not in NOP space. This prevents a SIGILL */ + ASSERT_NE(0, hwcaps & HWCAP_PACA) TH_LOG("PAUTH not enabled"); + if (!(hwcaps & HWCAP_PACG)) { + TH_LOG("WARNING: Generic PAUTH not enabled. Skipping generic key checks"); + nkeys = NKEYS - 1; + } + + /* + * In Linux the PAC field can be up to 7 bits wide. Even if keys are + * different, there is about 5% chance for PACs to collide with + * different addresses. This chance rapidly increases with fewer bits + * allocated for the PAC (e.g. wider address). A comparison of the keys + * directly will be more reliable. + * All signed values need to be different at least once out of n + * attempts to be certain that the keys are different + */ + for (int i = 0; i < PAC_COLLISION_ATTEMPTS; i++) { + if (nkeys == NKEYS) + sign_all(&signed_vals, i); + else + sign_specific(&signed_vals, i); + + tmp = n_same_single_set(&signed_vals, nkeys); + if (tmp < same) + same = tmp; + } + + ASSERT_EQ(0, same) TH_LOG("%d keys clashed every time", same); +} + /* * fork() does not change keys. Only exec() does so call a worker program. * Its only job is to sign a value and report back the resutls @@ -242,4 +322,47 @@ TEST(exec_changed_keys) ASSERT_EQ(0, same) TH_LOG("exec() did not change %d keys", same); } +TEST(context_switch_keep_keys) +{ + int ret; + struct signatures trash; + struct signatures before; + struct signatures after; + + ASSERT_PAUTH_ENABLED(); + + sign_specific(&before, ARBITRARY_VALUE); + + /* will context switch with a process with different keys at least once */ + ret = exec_sign_all(&trash, ARBITRARY_VALUE); + ASSERT_EQ(0, ret) TH_LOG("failed to run worker"); + + sign_specific(&after, ARBITRARY_VALUE); + + ASSERT_EQ(before.keyia, after.keyia) TH_LOG("keyia changed after context switching"); + ASSERT_EQ(before.keyib, after.keyib) TH_LOG("keyib changed after context switching"); + ASSERT_EQ(before.keyda, after.keyda) TH_LOG("keyda changed after context switching"); + ASSERT_EQ(before.keydb, after.keydb) TH_LOG("keydb changed after context switching"); +} + +TEST(context_switch_keep_keys_generic) +{ + int ret; + struct signatures trash; + size_t before; + size_t after; + + ASSERT_GENERIC_PAUTH_ENABLED(); + + before = keyg_sign(ARBITRARY_VALUE); + + /* will context switch with a process with different keys at least once */ + ret = exec_sign_all(&trash, ARBITRARY_VALUE); + ASSERT_EQ(0, ret) TH_LOG("failed to run worker"); + + after = keyg_sign(ARBITRARY_VALUE); + + ASSERT_EQ(before, after) TH_LOG("keyg changed after context switching"); +} + TEST_HARNESS_MAIN