From patchwork Thu Aug 9 19:20:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Andrey Konovalov X-Patchwork-Id: 10561741 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BEF621057 for ; Thu, 9 Aug 2018 19:21:48 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AD6E82B855 for ; Thu, 9 Aug 2018 19:21:48 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AAC242B93B; Thu, 9 Aug 2018 19:21:48 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,DKIM_VALID,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id D671C2B942 for ; Thu, 9 Aug 2018 19:21:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-Id:Date:Subject:To :From: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=H4sWmC8lpST+zsx+fi/IDREQOYJiepD2z9QKCb8uYrk=; b=PQ59cXcFD1VbvQ AtR7GOnQ4fSumUlGQVDzzJKAFRmu/YuXb0hFktkdcKCKsrLGp+adLAd9js24kmoQETeT1GE2vpsk2 5d67fjevreg57BOFiChADxmVT3Q1MKsucSM6YYMLHIz53OktmPPVFz7bYc1VaLdMA6pDeGpI8BiaD rwEb0IqaeqkpbWFui54bEi4IpufFgT8d0mLrVIyv6d2jZ7590T7RqU1vHgB9n0pLMv43osIvYvRqC 5p2VhSrE8yy1x/ByddBGqNnr8FTJwEQNw0015IkWMI5dB31Ifi7nXXISGBrKPJAaJAN8UxMS/P3zm +qckmdXlHF4emKZzNdOw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fnqVE-0000O9-RK; Thu, 09 Aug 2018 19:21:44 +0000 Received: from mail-wr1-x441.google.com ([2a00:1450:4864:20::441]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fnqUz-000051-Uu for linux-arm-kernel@lists.infradead.org; Thu, 09 Aug 2018 19:21:32 +0000 Received: by mail-wr1-x441.google.com with SMTP id h14-v6so6067236wrw.13 for ; Thu, 09 Aug 2018 12:21:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=sYOtkPk+LjjrvrLFndeQZE28t2ttWE+vThtxXb9GtN4=; b=JS/NJfp65mpiOOZn2qNDwefF0izCLijMlUwrNK3TOaz5XUOA9ol6D5Zv9YpYvKqk7X kbl9ATdI2vsF66RpaF1PzSNQLgYkg4HwWjBBzKgG9EhkC8438H+ExPSGCf9Rt724MiQJ T4DYiCojVtc3KK8+OgUDBYVqz6pyrA8eTsF/9v2OsQH2RPwwZ2p0HiIdqGLy3cOrOFEs KJ6igU5HGedFcwjX3IqMVw0bVQDfovA3YvsTXJbYbPzKvMU4v6OklAHGHoGyCN90rzKu 5MrYArXQXf3LGZxLOLYWG2AOEb6A8iiNXYguDP+YN63r5ukfhvpKygphGZogMeBcxOcP ygIg== 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:mime-version :content-transfer-encoding; bh=sYOtkPk+LjjrvrLFndeQZE28t2ttWE+vThtxXb9GtN4=; b=RlbAF1rqoDRVMcnoJOcn6kDnD5rfQhcia5UFk3Bn5d3ExGWyMw92BVhGDyBvcAVdVP 8ojm6UQyG+rGdUKYYSUdjkILDI/KIJ/Xjxnajn5v2XZwHM55JCdcuvXVmpX/XN1ExSiw qvmq5ym81+eyY/LQSkL3zD8G4XJWxRAzA+qKWLNbb/PLWI8eZ8swdzVWvlq3ekIlx+HY an/+5tr6u8dmrxjk+Q9KhlKTkvJq8fAXC965GR0yH6ABdNeQ6tr6m3pKkvxcoZo/zf7E 4sJCejl0bwmxbNa3CQtoH+oyXdnZZUpDPq/GGMYsZxkb8ZjhU85judIHaItYSUzQmkYX K+yw== X-Gm-Message-State: AOUpUlHBWUv3W3efbL4ofsxaHj6P1HYEbHk2a+dWeQxUNS2JlFFsall5 XDqdrpLILEA/yscOUDHWdqKsAQ== X-Google-Smtp-Source: AA+uWPyQGRVKuxcJmJNMJ8NjyBKtSaKncBrPCI1026HMp+G9Ck5E3vhPEIJVG/bkkjQr++r9H54Tuw== X-Received: by 2002:a5d:63c1:: with SMTP id c1-v6mr2331295wrw.106.1533842474624; Thu, 09 Aug 2018 12:21:14 -0700 (PDT) Received: from andreyknvl0.muc.corp.google.com ([2a00:79e0:15:10:84be:a42a:826d:c530]) by smtp.gmail.com with ESMTPSA id o14-v6sm14738797wmd.35.2018.08.09.12.21.12 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 09 Aug 2018 12:21:13 -0700 (PDT) From: Andrey Konovalov To: Andrey Ryabinin , Alexander Potapenko , Dmitry Vyukov , Catalin Marinas , Will Deacon , Christoph Lameter , Andrew Morton , Mark Rutland , Nick Desaulniers , Marc Zyngier , Dave Martin , Ard Biesheuvel , "Eric W . Biederman" , Ingo Molnar , Paul Lawrence , Geert Uytterhoeven , Arnd Bergmann , "Kirill A . Shutemov" , Greg Kroah-Hartman , Kate Stewart , Mike Rapoport , kasan-dev@googlegroups.com, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sparse@vger.kernel.org, linux-mm@kvack.org, linux-kbuild@vger.kernel.org Subject: [PATCH v5 00/18] khwasan: kernel hardware assisted address sanitizer Date: Thu, 9 Aug 2018 21:20:52 +0200 Message-Id: X-Mailer: git-send-email 2.18.0.597.ga71716f1ad-goog MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180809_122129_994206_9D461E55 X-CRM114-Status: GOOD ( 28.62 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Vishwath Mohan , Chintan Pandya , Jacob Bramley , Jann Horn , Ruben Ayrapetyan , Andrey Konovalov , Lee Smith , Kostya Serebryany , Mark Brand , Ramana Radhakrishnan , Evgeniy Stepanov Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP This patchset adds a new mode to KASAN [1], which is called KHWASAN (Kernel HardWare assisted Address SANitizer). The plan is to implement HWASan [2] for the kernel with the incentive, that it's going to have comparable to KASAN performance, but in the same time consume much less memory, trading that off for somewhat imprecise bug detection and being supported only for arm64. The overall idea of the approach used by KHWASAN is the following: 1. By using the Top Byte Ignore arm64 CPU feature, we can store pointer tags in the top byte of each kernel pointer. 2. Using shadow memory, we can store memory tags for each chunk of kernel memory. 3. On each memory allocation, we can generate a random tag, embed it into the returned pointer and set the memory tags that correspond to this chunk of memory to the same value. 4. By using compiler instrumentation, before each memory access we can add a check that the pointer tag matches the tag of the memory that is being accessed. 5. On a tag mismatch we report an error. [1] https://www.kernel.org/doc/html/latest/dev-tools/kasan.html [2] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html ====== Rationale On mobile devices KASAN's memory usage is significant problem. One of the main reasons to have KWHASAN is to be able to perform a similar set of checks that KASAN does, but with lower memory requirements. Comment from Vishwath Mohan : I don't have data on-hand, but anecdotally both ASAN and KASAN have proven problematic to enable for environments that don't tolerate the increased memory pressure well. This includes, (a) Low-memory form factors - Wear, TV, Things, lower-tier phones like Go, (c) Connected components like Pixel's visual core [1]. These are both places I'd love to have a low(er) memory footprint option at my disposal. Comment from Evgenii Stepanov : Looking at a live Android device under load, slab (according to /proc/meminfo) + kernel stack take 8-10% available RAM (~350MB). KASAN's overhead of 2x - 3x on top of it is not insignificant. Not having this overhead enables near-production use - ex. running KASAN/KHWASAN kernel on a personal, daily-use device to catch bugs that do not reproduce in test configuration. These are the ones that often cost the most engineering time to track down. CPU overhead is bad, but generally tolerable. RAM is critical, in our experience. Once it gets low enough, OOM-killer makes your life miserable. [1] https://www.blog.google/products/pixel/pixel-visual-core-image-processing-and-machine-learning-pixel-2/ ====== Technical details KHWASAN is implemented in a very similar way to KASAN. This patchset essentially does the following: 1. TCR_TBI1 is set to enable Top Byte Ignore. 2. Shadow memory is used (with a different scale, 1:16, so each shadow byte corresponds to 16 bytes of kernel memory) to store memory tags. 3. All slab objects are aligned to shadow scale, which is 16 bytes. 4. All pointers returned from the slab allocator are tagged with a random tag and the corresponding shadow memory is poisoned with the same value. 5. Compiler instrumentation is used to insert tag checks. Either by calling callbacks or by inlining them (CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE flags are reused). 6. When a tag mismatch is detected in callback instrumentation mode KHWASAN simply prints a bug report. In case of inline instrumentation, clang inserts a brk instruction, and KHWASAN has it's own brk handler, which reports the bug. 7. The memory in between slab objects is marked with a reserved tag, and acts as a redzone. 8. When a slab object is freed it's marked with a reserved tag. Bug detection is imprecise for two reasons: 1. We won't catch some small out-of-bounds accesses, that fall into the same shadow cell, as the last byte of a slab object. 2. We only have 1 byte to store tags, which means we have a 1/256 probability of a tag match for an incorrect access (actually even slightly less due to reserved tag values). Despite that there's a particular type of bugs that KHWASAN can detect compared to KASAN: use-after-free after the object has been allocated by someone else. ====== Benchmarks The following numbers were collected on Odroid C2 board. Both KASAN and KHWASAN were used in inline instrumentation mode. Boot time [1]: * ~1.7 sec for clean kernel * ~5.0 sec for KASAN * ~5.0 sec for KHWASAN Network performance [2]: * 8.33 Gbits/sec for clean kernel * 3.17 Gbits/sec for KASAN * 2.85 Gbits/sec for KHWASAN Slab memory usage after boot [3]: * ~40 kb for clean kernel * ~105 kb (~260% overhead) for KASAN * ~47 kb (~20% overhead) for KHWASAN KASAN memory overhead consists of three main parts: 1. Increased slab memory usage due to redzones. 2. Shadow memory (the whole reserved once during boot). 3. Quaratine (grows gradually until some preset limit; the more the limit, the more the chance to detect a use-after-free). Comparing KWHASAN vs KASAN for each of these points: 1. 20% vs 260% overhead. 2. 1/16th vs 1/8th of physical memory. 3. KHWASAN doesn't require quarantine. [1] Time before the ext4 driver is initialized. [2] Measured as `iperf -s & iperf -c 127.0.0.1 -t 30`. [3] Measured as `cat /proc/meminfo | grep Slab`. ====== Some notes A few notes: 1. The patchset can be found here: https://github.com/xairy/kasan-prototype/tree/khwasan 2. Building requires a recent LLVM version (r330044 or later). 3. Stack instrumentation is not supported yet and will be added later. ====== Changes Changes in v5: - Rebased onto 1ffaddd029 (4.18-rc8). - Preassign tags for objects from caches with constructors and SLAB_TYPESAFE_BY_RCU caches. - Fix SLAB allocator support by untagging page->s_mem in kasan_poison_slab(). - Performed dynamic testing to find potential places where pointer tagging might result in bugs [1]. - Clarified and fixed memory usage benchmarks in the cover letter. - Added a rationale for having KHWASAN to the cover letter. Changes in v4: - Fixed SPDX comment style in mm/kasan/kasan.h. - Fixed mm/kasan/kasan.h changes being included in a wrong patch. - Swapped "khwasan, arm64: fix up fault handling logic" and "khwasan: add tag related helper functions" patches order. - Rebased onto 6f0d349d (4.18-rc2+). Changes in v3: - Minor documentation fixes. - Fixed CFLAGS variable name in KASAN makefile. - Added a "SPDX-License-Identifier: GPL-2.0" line to all source files under mm/kasan. - Rebased onto 81e97f013 (4.18-rc1+). Changes in v2: - Changed kmalloc_large_node_hook to return tagged pointer instead of using an output argument. - Fix checking whether -fsanitize=hwaddress is supported by the compiler. - Removed duplication of -fno-builtin for KASAN and KHWASAN. - Removed {} block for one line for_each_possible_cpu loop. - Made set_track() static inline as it is used only in common.c. - Moved optimal_redzone() to common.c. - Fixed using tagged pointer for shadow calculation in kasan_unpoison_shadow(). - Restored setting cache->align in kasan_cache_create(), which was accidentally lost. - Simplified __kasan_slab_free(), kasan_alloc_pages() and kasan_kmalloc(). - Removed tagging from kasan_kmalloc_large(). - Added page_kasan_tag_reset() to kasan_poison_slab() and removed !PageSlab() check from page_to_virt. - Reset pointer tag in _virt_addr_is_linear. - Set page tag for each page when multiple pages are allocated or freed. - Added a comment as to why we ignore cma allocated pages. Changes in v1: - Rebased onto 4.17-rc4. - Updated benchmarking stats. - Documented compiler version requirements, memory usage and slowdown. - Dropped kvm patches, as clang + arm64 + kvm is completely broken [1]. Changes in RFC v3: - Renamed CONFIG_KASAN_CLASSIC and CONFIG_KASAN_TAGS to CONFIG_KASAN_GENERIC and CONFIG_KASAN_HW respectively. - Switch to -fsanitize=kernel-hwaddress instead of -fsanitize=hwaddress. - Removed unnecessary excessive shadow initialization. - Removed khwasan_enabled flag (it’s not needed since KHWASAN is initialized before any slab caches are used). - Split out kasan_report.c and khwasan_report.c from report.c. - Moved more common KASAN and KHWASAN functions to common.c. - Added tagging to pagealloc. - Rebased onto 4.17-rc1. - Temporarily dropped patch that adds kvm support (arm64 + kvm + clang combo is broken right now [2]). Changes in RFC v2: - Removed explicit casts to u8 * for kasan_mem_to_shadow() calls. - Introduced KASAN_TCR_FLAGS for setting the TCR_TBI1 flag. - Added a comment regarding the non-atomic RMW sequence in khwasan_random_tag(). - Made all tag related functions accept const void *. - Untagged pointers in __kimg_to_phys, which is used by virt_to_phys. - Untagged pointers in show_ptr in fault handling logic. - Untagged pointers passed to KVM. - Added two reserved tag values: 0xFF and 0xFE. - Used the reserved tag 0xFF to disable validity checking (to resolve the issue with pointer tag being lost after page_address + kmap usage). - Used the reserved tag 0xFE to mark redzones and freed objects. - Added mnemonics for esr manipulation in KHWASAN brk handler. - Added a comment about the -recover flag. - Some minor cleanups and fixes. - Rebased onto 3215b9d5 (4.16-rc6+). - Tested on real hardware (Odroid C2 board). - Added better benchmarks. [1] https://lkml.org/lkml/2018/7/18/765 [2] https://lkml.org/lkml/2018/4/19/775 Andrey Konovalov (18): khwasan, mm: change kasan hooks signatures khwasan: move common kasan and khwasan code to common.c khwasan: add CONFIG_KASAN_GENERIC and CONFIG_KASAN_HW khwasan, arm64: adjust shadow size for CONFIG_KASAN_HW khwasan: initialize shadow to 0xff khwasan, arm64: untag virt address in __kimg_to_phys and _virt_addr_is_linear khwasan: add tag related helper functions khwasan: preassign tags to objects with ctors or SLAB_TYPESAFE_BY_RCU khwasan, arm64: fix up fault handling logic khwasan, arm64: enable top byte ignore for the kernel khwasan, mm: perform untagged pointers comparison in krealloc khwasan: split out kasan_report.c from report.c khwasan: add bug reporting routines khwasan: add hooks implementation khwasan, arm64: add brk handler for inline instrumentation khwasan, mm, arm64: tag non slab memory allocated via pagealloc khwasan: update kasan documentation kasan: add SPDX-License-Identifier mark to source files Documentation/dev-tools/kasan.rst | 213 ++++---- arch/arm64/Kconfig | 1 + arch/arm64/Makefile | 2 +- arch/arm64/include/asm/brk-imm.h | 2 + arch/arm64/include/asm/memory.h | 41 +- arch/arm64/include/asm/pgtable-hwdef.h | 1 + arch/arm64/kernel/traps.c | 69 ++- arch/arm64/mm/fault.c | 3 + arch/arm64/mm/kasan_init.c | 18 +- arch/arm64/mm/proc.S | 8 +- include/linux/compiler-clang.h | 5 +- include/linux/compiler-gcc.h | 4 + include/linux/compiler.h | 3 +- include/linux/kasan.h | 90 +++- include/linux/mm.h | 29 ++ include/linux/page-flags-layout.h | 10 + lib/Kconfig.kasan | 77 ++- mm/cma.c | 11 + mm/kasan/Makefile | 9 +- mm/kasan/common.c | 663 +++++++++++++++++++++++++ mm/kasan/kasan.c | 565 +-------------------- mm/kasan/kasan.h | 85 +++- mm/kasan/kasan_init.c | 1 + mm/kasan/kasan_report.c | 156 ++++++ mm/kasan/khwasan.c | 181 +++++++ mm/kasan/khwasan_report.c | 61 +++ mm/kasan/quarantine.c | 1 + mm/kasan/report.c | 272 +++------- mm/page_alloc.c | 1 + mm/slab.c | 18 +- mm/slab.h | 2 +- mm/slab_common.c | 6 +- mm/slub.c | 21 +- scripts/Makefile.kasan | 27 +- 34 files changed, 1736 insertions(+), 920 deletions(-) create mode 100644 mm/kasan/common.c create mode 100644 mm/kasan/kasan_report.c create mode 100644 mm/kasan/khwasan.c create mode 100644 mm/kasan/khwasan_report.c