From patchwork Fri Nov 20 23:02:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Collingbourne X-Patchwork-Id: 11922733 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CF8E2C5519F for ; Fri, 20 Nov 2020 23:03:38 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4D2F72240B for ; Fri, 20 Nov 2020 23:03:38 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="x4EkTnOo"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=google.com header.i=@google.com header.b="pOPwinrc" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4D2F72240B Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:To:From:Subject:Mime-Version:Message-Id:Date: Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender :Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Owner; bh=ZMqiodC8zsA4iTEyWkBDFb/vumk9PSoZWIgZ4JAxtfs=; b=x4EkTnOos5VFUnBkbIybQWStNL 4opJbpWBD4vZxDHny2rfsBrWOTkVhvuFQvI++b0VqJM2faTjsHS/mYocNdUx1qkv0tF/h5+nCH0Fc 4WjIOGZHzueUpqQUW2oy0zAsEJPOqgwp/fE+IFDLBeQE6du/AI+I94lzOHB+kRbWufydFV3uKfsA1 87TbdxdxmvTbjkSima6in0SRqGizawguZxCO/Mea3XHRzVQ76WPFBaE/P7qacPtSP0QmoEy96etBq E1hrKFCdTQ5LZ/Z11zP7LoJJIoTylnFP2mW0SvRTOUiPYTRleuGmprGWuzpKgGn1iEP2L5nEi7CeY OFciljSQ==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kgFQ7-000500-CO; Fri, 20 Nov 2020 23:02:23 +0000 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kgFQ4-0004zH-Ln for linux-arm-kernel@lists.infradead.org; Fri, 20 Nov 2020 23:02:21 +0000 Received: by mail-yb1-xb4a.google.com with SMTP id v12so13675225ybi.6 for ; Fri, 20 Nov 2020 15:02:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:message-id:mime-version:subject:from:to:cc; bh=y5BRJ5AhZaJM5fZeYUlR0Lh8RJMilGhzJYairjlsb7A=; b=pOPwinrc5KW/n+Ge5zl0gbUlsZzKEHzteeU/iFEfMycf7lrZoZ9EogjKued/B47Pjm N8PnZpmCrWthSL4aoPGizcqjw/9U0Zq2lf+DU5cbI6S9rD3sIlL4G/2gctoe+zKoyToF AgHAVZAFsuSMPDilbE1plJV3vIVG+ANNgW/EYObNBj7MSiKNV3+CnOk7MXKE6u8XXPcd hOqlYNYlAI43apsMKso3a3pFsRhiwRjk7CiJndjB+C+PuXyxoMeKIhwOkmB10grlYn1n MSUWwyD9uqCc9PxuBZwK+gGzMm4LDBXdQYerGTIdqI7n+3FsURnFWCMteIAHt0U9DooH AK6Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:message-id:mime-version:subject:from :to:cc; bh=y5BRJ5AhZaJM5fZeYUlR0Lh8RJMilGhzJYairjlsb7A=; b=sbJkpZ3VGxeXssEITyvrsmbxC1k5kDJ8fDk/OBWJ4oyIWV4ojJAlhpPC9SgGkZ2eV3 6l5he0Zci1wGZarjkkCvSr2dnZfE7sfCOXZ2uSHmBdt/pGhmfpDrueHvkexnruPxxI// 6DMK5ubtJIXDf9aH7+ufrDcDgrJTk3nRDKTTFfCSVetXo/d8lCZFDEGlnqe3+2UsJfuJ ewyJAzTJtalBCGa+aIM8yvfQaozxQvEcL+Ja9qGEnoTuqsTmnAU24TIT8QF+UpcY4tkQ /WIc8MLMTenniIVQHxxAN+PQEEj2qlMP44Dx9bySARhK1l6mZerQ87uuciOzDNNzdjfO EHsA== X-Gm-Message-State: AOAM530dhL3D06anoD4Ff6IXjTOTpAU6l4BU2Or8zU4pv2ryycaBqI8f h7GENr3C4GPfUE+PsWyVi1QHdIk= X-Google-Smtp-Source: ABdhPJy5Tr8WGVYaqNanW42c1r+mNc4AjLNYfW+MxrPIr+PAZ6/R1o0+dHIQtoHrYvbrU9SPVazy3vU= X-Received: from pcc-desktop.svl.corp.google.com ([2620:15c:2ce:0:7220:84ff:fe09:385a]) (user=pcc job=sendgmr) by 2002:a25:e6d7:: with SMTP id d206mr24874166ybh.67.1605913336561; Fri, 20 Nov 2020 15:02:16 -0800 (PST) Date: Fri, 20 Nov 2020 15:02:11 -0800 Message-Id: <20201120230211.584929-1-pcc@google.com> Mime-Version: 1.0 X-Mailer: git-send-email 2.29.2.454.gaff20da3a2-goog Subject: [PATCH v2] kasan: arm64: support specialized outlined tag mismatch checks From: Peter Collingbourne To: Mark Brown , Mark Rutland , Will Deacon , Catalin Marinas , Andrey Konovalov , Evgenii Stepanov , Ard Biesheuvel X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20201120_180220_769981_B85123B8 X-CRM114-Status: GOOD ( 33.10 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Collingbourne , Linux ARM Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org By using outlined checks we can achieve a significant code size improvement by moving the tag-based ASAN checks into separate functions. Unlike the existing CONFIG_KASAN_OUTLINE mode these functions have a custom calling convention that preserves most registers and is specialized to the register containing the address and the type of access, and as a result we can eliminate the code size and performance overhead of a standard calling convention such as AAPCS for these functions. This change depends on a separate series of changes to Clang [1] to support outlined checks in the kernel, although the change works fine without them (we just don't get outlined checks). This is because the flag -mllvm -hwasan-inline-all-checks=0 has no effect until the Clang changes land. The flag was introduced in the Clang 9.0 timeframe as part of the support for outlined checks in userspace and because our minimum Clang version is 10.0 we can pass it unconditionally. Outlined checks require a new runtime function with a custom calling convention. Add this function to arch/arm64/lib. I measured the code size of defconfig + tag-based KASAN, as well as boot time (i.e. time to init launch) on a DragonBoard 845c with an Android arm64 GKI kernel. The results are below: code size boot time CONFIG_KASAN_INLINE=y before 92824064 6.18s CONFIG_KASAN_INLINE=y after 38822400 6.65s CONFIG_KASAN_OUTLINE=y 39215616 11.48s We can see straight away that specialized outlined checks beat the existing CONFIG_KASAN_OUTLINE=y on both code size and boot time for tag-based ASAN. As for the comparison between CONFIG_KASAN_INLINE=y before and after we saw similar performance numbers in userspace [2] and decided that since the performance overhead is minimal compared to the overhead of tag-based ASAN itself as well as compared to the code size improvements we would just replace the inlined checks with the specialized outlined checks without the option to select between them, and that is what I have implemented in this patch. But we may make a different decision for the kernel such as having CONFIG_KASAN_OUTLINE=y turn on specialized outlined checks if Clang is new enough. Signed-off-by: Peter Collingbourne Link: https://linux-review.googlesource.com/id/I1a30036c70ab3c3ee78d75ed9b87ef7cdc3fdb76 Link: [1] https://reviews.llvm.org/D90426 Link: [2] https://reviews.llvm.org/D56954 Acked-by: Andrey Konovalov --- v2: - use calculations in the stack spills and restores - improve the comment at the top of the function - add a BTI instruction arch/arm64/include/asm/asm-prototypes.h | 6 +++ arch/arm64/include/asm/module.lds.h | 17 ++++++- arch/arm64/lib/Makefile | 2 + arch/arm64/lib/kasan_sw_tags.S | 60 +++++++++++++++++++++++++ mm/kasan/tags.c | 7 +++ scripts/Makefile.kasan | 1 + 6 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/lib/kasan_sw_tags.S diff --git a/arch/arm64/include/asm/asm-prototypes.h b/arch/arm64/include/asm/asm-prototypes.h index 1c9a3a0c5fa5..ec1d9655f885 100644 --- a/arch/arm64/include/asm/asm-prototypes.h +++ b/arch/arm64/include/asm/asm-prototypes.h @@ -23,4 +23,10 @@ long long __ashlti3(long long a, int b); long long __ashrti3(long long a, int b); long long __lshrti3(long long a, int b); +/* + * This function uses a custom calling convention and cannot be called from C so + * this prototype is not entirely accurate. + */ +void __hwasan_tag_mismatch(unsigned long addr, unsigned long access_info); + #endif /* __ASM_PROTOTYPES_H */ diff --git a/arch/arm64/include/asm/module.lds.h b/arch/arm64/include/asm/module.lds.h index 691f15af788e..4a6d717f75f3 100644 --- a/arch/arm64/include/asm/module.lds.h +++ b/arch/arm64/include/asm/module.lds.h @@ -1,7 +1,20 @@ -#ifdef CONFIG_ARM64_MODULE_PLTS SECTIONS { +#ifdef CONFIG_ARM64_MODULE_PLTS .plt (NOLOAD) : { BYTE(0) } .init.plt (NOLOAD) : { BYTE(0) } .text.ftrace_trampoline (NOLOAD) : { BYTE(0) } -} #endif + +#ifdef CONFIG_KASAN_SW_TAGS + /* + * Outlined checks go into comdat-deduplicated sections named .text.hot. + * Because they are in comdats they are not combined by the linker and + * we otherwise end up with multiple sections with the same .text.hot + * name in the .ko file. The kernel module loader warns if it sees + * multiple sections with the same name so we use this sections + * directive to force them into a single section and silence the + * warning. + */ + .text.hot : { *(.text.hot) } +#endif +} diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile index d31e1169d9b8..8e60d76a1b47 100644 --- a/arch/arm64/lib/Makefile +++ b/arch/arm64/lib/Makefile @@ -18,3 +18,5 @@ obj-$(CONFIG_CRC32) += crc32.o obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o obj-$(CONFIG_ARM64_MTE) += mte.o + +obj-$(CONFIG_KASAN_SW_TAGS) += kasan_sw_tags.o diff --git a/arch/arm64/lib/kasan_sw_tags.S b/arch/arm64/lib/kasan_sw_tags.S new file mode 100644 index 000000000000..5c179b32af71 --- /dev/null +++ b/arch/arm64/lib/kasan_sw_tags.S @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 Google LLC + */ + +#include +#include + +/* + * Report a tag mismatch detected by tag-based KASAN. + * + * This function has a custom calling convention in order to minimize the sizes + * of the compiler-generated thunks that call it. All registers except for x16 + * and x17 must be preserved. This includes x0 and x1 which are used by the + * caller to pass arguments. In order to allow these registers to be restored + * the caller spills x0 and x1 to sp+0 and sp+8. The registers x29 and x30 are + * spilled to sp+232 and sp+240, and although it is not strictly necessary for + * the caller to spill them, that is how the ABI for these functions has been + * defined. The 256 bytes of stack space allocated by the caller must be + * deallocated on return. + * + * This function takes care of transitioning to the standard AAPCS calling + * convention and calls the C function kasan_tag_mismatch to report the error. + * + * Parameters: + * x0 - the fault address + * x1 - an encoded description of the faulting access + */ +SYM_CODE_START(__hwasan_tag_mismatch) +#ifdef BTI_C + BTI_C +#endif + add x29, sp, #232 + stp x2, x3, [sp, #8 * 2] + stp x4, x5, [sp, #8 * 4] + stp x6, x7, [sp, #8 * 6] + stp x8, x9, [sp, #8 * 8] + stp x10, x11, [sp, #8 * 10] + stp x12, x13, [sp, #8 * 12] + stp x14, x15, [sp, #8 * 14] +#ifndef CONFIG_SHADOW_CALL_STACK + str x18, [sp, #8 * 18] +#endif + mov x2, x30 + bl kasan_tag_mismatch + ldp x29, x30, [sp, #8 * 29] +#ifndef CONFIG_SHADOW_CALL_STACK + ldr x18, [sp, #8 * 18] +#endif + ldp x14, x15, [sp, #8 * 14] + ldp x12, x13, [sp, #8 * 12] + ldp x10, x11, [sp, #8 * 10] + ldp x8, x9, [sp, #8 * 8] + ldp x6, x7, [sp, #8 * 6] + ldp x4, x5, [sp, #8 * 4] + ldp x2, x3, [sp, #8 * 2] + ldp x0, x1, [sp], #256 + ret +SYM_CODE_END(__hwasan_tag_mismatch) +EXPORT_SYMBOL(__hwasan_tag_mismatch) diff --git a/mm/kasan/tags.c b/mm/kasan/tags.c index e02a36a51f42..d00613956c79 100644 --- a/mm/kasan/tags.c +++ b/mm/kasan/tags.c @@ -198,3 +198,10 @@ struct kasan_track *kasan_get_free_track(struct kmem_cache *cache, return &alloc_meta->free_track[i]; } + +void kasan_tag_mismatch(unsigned long addr, unsigned long access_info, + unsigned long ret_ip) +{ + kasan_report(addr, 1 << (access_info & 0xf), access_info & 0x10, + ret_ip); +} diff --git a/scripts/Makefile.kasan b/scripts/Makefile.kasan index 1e000cc2e7b4..1f2cccc264d8 100644 --- a/scripts/Makefile.kasan +++ b/scripts/Makefile.kasan @@ -44,6 +44,7 @@ endif CFLAGS_KASAN := -fsanitize=kernel-hwaddress \ -mllvm -hwasan-instrument-stack=$(CONFIG_KASAN_STACK) \ -mllvm -hwasan-use-short-granules=0 \ + -mllvm -hwasan-inline-all-checks=0 \ $(instrumentation_flags) endif # CONFIG_KASAN_SW_TAGS