From patchwork Thu May 26 01:01:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Gow X-Patchwork-Id: 1635683 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=yVMDFnNv; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20210112 header.b=D4OFEhQ+; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org; envelope-from=linux-um-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4L7qRk3k8tz9sCq for ; Thu, 26 May 2022 11:02:58 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:References: Mime-Version:Message-Id:In-Reply-To:Date:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=sOyusWi8gNKk8vK1wKbP2agSMNGN/etYiKrguiO1gaY=; b=yVMDFnNvsGZWyQSTjlmCPKXPXC Cr8YSk1F6VURtctqWtKTVGO95Ftyj6XLnsPO3YROoa6FuuAI66FZLNc5cNVozaTwQon41GawQQgYM 4XU+oUKsdU0rgCzo4JsFIIpDMh1vRu9hstuuUpfCrakb4z4YyCPwlBGGwnnwYi46Z2iy/Vvv59dCm mXtkViaiBvdGFNZ8B6znM4Ujx1nfIMV7ObqWqgUHoIpYTrVXjcGfg0+tRlZFg04X7N8VepSAtorHK ekE1EEiffPeZMzMOHcYyFbgPdMcEmvDGPqAAsld+3G+IRv2n1+sT5w8jkhnSTwQdJrWb658GPsVo4 KOU5Sxcw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nu1tm-00D8xF-VJ; Thu, 26 May 2022 01:02:46 +0000 Received: from mail-yw1-x1149.google.com ([2607:f8b0:4864:20::1149]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nu1tj-00D8wJ-06 for linux-um@lists.infradead.org; Thu, 26 May 2022 01:02:45 +0000 Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-2eb7d137101so921907b3.12 for ; Wed, 25 May 2022 18:02:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=EEiYE3N4C+FiTTiGz2/4DMmfamDqDEZrPCXEkusGckA=; b=D4OFEhQ+9/QhoFcHtWzYTxElBqybYzfwjOxzCImFGL/WiAmazKOVOdr6yklM5hMXvn 1/V391T+QZEe4YfUBrvhn3LI8BSGxWcuF1sgKfEd+GEvGbgRaV8P9lNRIwk7tBzMLp5J TdV+nmwNlxEJ3t+PcKYE/oMvHcNWPhY1Hqf8/Fjcrwq2A9ev06OViuWEv7w6YEoWQC5t 2rbjedl2X5EmaGO2TBNrTolIQsYZ9zzSufXkaby+Zo4wnTlIbW2XbQ8E6gxJwDsqA7Lr eQV/cJH/hJjVXy0TIvcXlMQMS/R5516rSIPlPBgBGnKKQ9+hyHlB0LzZrE5vNr+cSQdU xONw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=EEiYE3N4C+FiTTiGz2/4DMmfamDqDEZrPCXEkusGckA=; b=g7EBT83ejODyGknp2hgsSGg3pvFRTgmmuG84MECWaFYgVbBHgexxqloVLY9Wtw8j/s u8pRjiU5XizzRWvesYm6XuOTP7aooOXlWhtlafG1jMyxn3xkdsxWvCf1OOKWMKtQNLdU MsEuRQdvXmOOlGz/T5ZXXRR83idseZf1bpVBZD3KHnD2nujb4UPd6poC4rIw8u6Ao+gG OoPHR7v9O23O0m+tRD6RCEnyKlzzjwSLfA05hZ333qZdZc4BTNRZ9YrK8B7lFn+1G3iO 2oCDZsncBxMX1bchXZJ1Y+tZxEk6jfOZK49I/LwPB16TqXhFxQJQXPIcKIk6ZhYKoIfp ggfA== X-Gm-Message-State: AOAM530Albc/FG+bnIKhwxwlhWqNxVoBlgoV0wo+rnKobcAA1QG8ucBx SWQd81Lv1O11RS+h5qE1Ot91k0DyBAixWQ== X-Google-Smtp-Source: ABdhPJyJPExlK3VESLRoGB3DdLev2vu2xE0//ugdy0NtIs6BiRNGOsfOAuc2Uo1QVs9qKOY3MY/eYYZlbpkJaQ== X-Received: from spirogrip.svl.corp.google.com ([2620:15c:2cb:201:cd2b:6bc3:8646:2eaa]) (user=davidgow job=sendgmr) by 2002:a25:cb89:0:b0:652:964e:909d with SMTP id b131-20020a25cb89000000b00652964e909dmr9872550ybg.241.1653526960292; Wed, 25 May 2022 18:02:40 -0700 (PDT) Date: Wed, 25 May 2022 18:01:11 -0700 In-Reply-To: <20220525111756.GA15955@axis.com> Message-Id: <20220526010111.755166-1-davidgow@google.com> Mime-Version: 1.0 References: <20220525111756.GA15955@axis.com> X-Mailer: git-send-email 2.36.1.124.g0e6072fb45-goog Subject: [RFC PATCH v3] UML: add support for KASAN under x86_64 From: David Gow To: Vincent Whitchurch , Johannes Berg , Patricia Alfonso , Jeff Dike , Richard Weinberger , anton.ivanov@cambridgegreys.com, Dmitry Vyukov , Brendan Higgins Cc: kasan-dev , linux-um@lists.infradead.org, LKML , Daniel Latypov , David Gow X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220525_180243_094976_E8FB7FBE X-CRM114-Status: GOOD ( 36.47 ) X-Spam-Score: -7.7 (-------) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: Patricia Alfonso Make KASAN run on User Mode Linux on x86_64. The UML-specific KASAN initializer uses mmap to map the roughly 2.25TB of shadow memory to the location defined by KASAN_SHADOW_OFFSET. kasan_init() utilizes constructors to initialize KASAN before ma [...] Content analysis details: (-7.7 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:1149 listed in] [list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -7.5 USER_IN_DEF_DKIM_WL From: address is in the default DKIM white-list -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.0 DKIMWL_WL_MED DKIMwl.org - Medium trust sender X-BeenThere: linux-um@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-um" Errors-To: linux-um-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: Patricia Alfonso Make KASAN run on User Mode Linux on x86_64. The UML-specific KASAN initializer uses mmap to map the roughly 2.25TB of shadow memory to the location defined by KASAN_SHADOW_OFFSET. kasan_init() utilizes constructors to initialize KASAN before main(). The location of the KASAN shadow memory, starting at KASAN_SHADOW_OFFSET, can be configured using the KASAN_SHADOW_OFFSET option. UML uses roughly 18TB of address space, and KASAN requires 1/8th of this. The default location of this offset is 0x100000000000, which keeps it out-of-the-way even on UML setups with more "physical" memory. For low-memory setups, 0x7fff8000 can be used instead, which fits in an immediate and is therefore faster, as suggested by Dmitry Vyukov. There is usually enough free space at this location; however, it is a config option so that it can be easily changed if needed. Note that, unlike KASAN on other architectures, vmalloc allocations still use the shadow memory allocated upfront, rather than allocating and free-ing it per-vmalloc allocation. Signed-off-by: Patricia Alfonso Co-developed-by: Vincent Whitchurch Signed-off-by: Vincent Whitchurch Signed-off-by: David Gow --- This is a new RFC for the KASAN/UML port, based on the patch v1: https://lore.kernel.org/all/20200226004608.8128-1-trishalfonso@google.com/ With several fixes by Vincent Whitchurch: https://lore.kernel.org/all/20220525111756.GA15955@axis.com/ That thread describes the differences from the v1 (and hence the previous RFCs better than I can here), but the gist of it is: - Support for KASAN_VMALLOC, by changing the way kasan_{populate,release}_vmalloc work to update existing shadow memory, rather than allocating anything new. - A similar fix for modules' shadow memory. - Support for KASAN_STACK - This requires the bugfix here: https://lore.kernel.org/lkml/20220523140403.2361040-1-vincent.whitchurch@axis.com/ - Plus a couple of files excluded from KASAN. - Revert the default shadow offset to 0x100000000000 - This was breaking when mem=1G for me, at least. - A few minor fixes to linker sections and scripts. - I've added one to dyn.lds.S on top of the ones Vincent added. There are still a few things to be sorted out before this is ready to go upstream, in particular: - We've got a bunch of checks for CONFIG_UML, where a more specific config option might be better. For example: CONFIG_KASAN_NO_SHADOW_ALLOC. - Alternatively, the vmalloc (and module) shadow memory allocators could support per-architecture replacements. - Do we want to the alignment before or after the __memset() in kasan_populate_vmalloc()? - This doesn't seem to work when CONFIG_STATIC_LINK is enabled (because libc crt0 code calls memory functions, which expect the shadow memory to already exist, due to multiple symbols being resolved. - I think we should just make this depend on dynamic UML. - For that matter, I think static UML is actually broken at the moment. I'll send a patch out tomorrow. - And there's a checkpatch complaint about a long __memset() line. Thanks again to everyone who's contributed and looked at these patches! Note that I removed the Reviewed-by tags, as I think this version has enough changes to warrant a re-review. -- David --- arch/um/Kconfig | 15 +++++++++++++++ arch/um/Makefile | 6 ++++++ arch/um/include/asm/common.lds.S | 2 ++ arch/um/kernel/Makefile | 3 +++ arch/um/kernel/dyn.lds.S | 6 +++++- arch/um/kernel/mem.c | 18 ++++++++++++++++++ arch/um/os-Linux/mem.c | 22 ++++++++++++++++++++++ arch/um/os-Linux/user_syms.c | 4 ++-- arch/x86/um/Makefile | 3 ++- arch/x86/um/vdso/Makefile | 3 +++ mm/kasan/shadow.c | 20 +++++++++++++++++++- 11 files changed, 97 insertions(+), 5 deletions(-) diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 4d398b80aea8..c28ea5c89381 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -11,6 +11,8 @@ config UML select ARCH_HAS_STRNLEN_USER select ARCH_NO_PREEMPT select HAVE_ARCH_AUDITSYSCALL + select HAVE_ARCH_KASAN if X86_64 + select HAVE_ARCH_KASAN_VMALLOC if HAVE_ARCH_KASAN select HAVE_ARCH_SECCOMP_FILTER select HAVE_ASM_MODVERSIONS select HAVE_UID16 @@ -219,6 +221,19 @@ config UML_TIME_TRAVEL_SUPPORT It is safe to say Y, but you probably don't need this. +config KASAN_SHADOW_OFFSET + hex + depends on KASAN + default 0x100000000000 + help + This is the offset at which the ~2.25TB of shadow memory is + mapped and used by KASAN for memory debugging. This can be any + address that has at least KASAN_SHADOW_SIZE(total address space divided + by 8) amount of space so that the KASAN shadow memory does not conflict + with anything. The default is 0x100000000000, which works even if mem is + set to a large value. On low-memory systems, try 0x7fff8000, as it fits + into the immediate of most instructions, improving performance. + endmenu source "arch/um/drivers/Kconfig" diff --git a/arch/um/Makefile b/arch/um/Makefile index f2fe63bfd819..a98405f4ecb8 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -75,6 +75,12 @@ USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -I%,,$(KBUILD_CFLAGS))) \ -D_FILE_OFFSET_BITS=64 -idirafter $(srctree)/include \ -idirafter $(objtree)/include -D__KERNEL__ -D__UM_HOST__ +# Kernel config options are not included in USER_CFLAGS, but the option for KASAN +# should be included if the KASAN config option was set. +ifdef CONFIG_KASAN + USER_CFLAGS+=-DCONFIG_KASAN=y +endif + #This will adjust *FLAGS accordingly to the platform. include $(srctree)/$(ARCH_DIR)/Makefile-os-$(OS) diff --git a/arch/um/include/asm/common.lds.S b/arch/um/include/asm/common.lds.S index eca6c452a41b..fd481ac371de 100644 --- a/arch/um/include/asm/common.lds.S +++ b/arch/um/include/asm/common.lds.S @@ -83,6 +83,8 @@ } .init_array : { __init_array_start = .; + *(.kasan_init) + *(.init_array.*) *(.init_array) __init_array_end = .; } diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 1c2d4b29a3d4..a089217e2f0e 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -27,6 +27,9 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_GENERIC_PCI_IOMAP) += ioport.o +KASAN_SANITIZE_stacktrace.o := n +KASAN_SANITIZE_sysrq.o := n + USER_OBJS := config.o include arch/um/scripts/Makefile.rules diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S index 2f2a8ce92f1e..2b7fc5b54164 100644 --- a/arch/um/kernel/dyn.lds.S +++ b/arch/um/kernel/dyn.lds.S @@ -109,7 +109,11 @@ SECTIONS be empty, which isn't pretty. */ . = ALIGN(32 / 8); .preinit_array : { *(.preinit_array) } - .init_array : { *(.init_array) } + .init_array : { + *(.kasan_init) + *(.init_array.*) + *(.init_array) + } .fini_array : { *(.fini_array) } .data : { INIT_TASK_DATA(KERNEL_STACK_SIZE) diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 15295c3237a0..a32cfce53efb 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -18,6 +18,24 @@ #include #include #include +#include + +#ifdef CONFIG_KASAN +void kasan_init(void) +{ + /* + * kasan_map_memory will map all of the required address space and + * the host machine will allocate physical memory as necessary. + */ + kasan_map_memory((void *)KASAN_SHADOW_START, KASAN_SHADOW_SIZE); + init_task.kasan_depth = 0; + os_info("KernelAddressSanitizer initialized\n"); +} + +static void (*kasan_init_ptr)(void) +__section(".kasan_init") __used += kasan_init; +#endif /* allocated in paging_init, zeroed in mem_init, and unchanged thereafter */ unsigned long *empty_zero_page = NULL; diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index 3c1b77474d2d..8530b2e08604 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c @@ -17,6 +17,28 @@ #include #include +/* + * kasan_map_memory - maps memory from @start with a size of @len. + * The allocated memory is filled with zeroes upon success. + * @start: the start address of the memory to be mapped + * @len: the length of the memory to be mapped + * + * This function is used to map shadow memory for KASAN in uml + */ +void kasan_map_memory(void *start, size_t len) +{ + if (mmap(start, + len, + PROT_READ|PROT_WRITE, + MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, + -1, + 0) == MAP_FAILED) { + os_info("Couldn't allocate shadow memory: %s\n.", + strerror(errno)); + exit(1); + } +} + /* Set by make_tempfile() during early boot. */ static char *tempdir = NULL; diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c index 715594fe5719..cb667c9225ab 100644 --- a/arch/um/os-Linux/user_syms.c +++ b/arch/um/os-Linux/user_syms.c @@ -27,10 +27,10 @@ EXPORT_SYMBOL(strstr); #ifndef __x86_64__ extern void *memcpy(void *, const void *, size_t); EXPORT_SYMBOL(memcpy); -#endif - EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(memset); +#endif + EXPORT_SYMBOL(printf); /* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms. diff --git a/arch/x86/um/Makefile b/arch/x86/um/Makefile index ba5789c35809..f778e37494ba 100644 --- a/arch/x86/um/Makefile +++ b/arch/x86/um/Makefile @@ -28,7 +28,8 @@ else obj-y += syscalls_64.o vdso/ -subarch-y = ../lib/csum-partial_64.o ../lib/memcpy_64.o ../entry/thunk_64.o +subarch-y = ../lib/csum-partial_64.o ../lib/memcpy_64.o ../entry/thunk_64.o \ + ../lib/memmove_64.o ../lib/memset_64.o endif diff --git a/arch/x86/um/vdso/Makefile b/arch/x86/um/vdso/Makefile index 5943387e3f35..8c0396fd0e6f 100644 --- a/arch/x86/um/vdso/Makefile +++ b/arch/x86/um/vdso/Makefile @@ -3,6 +3,9 @@ # Building vDSO images for x86. # +# do not instrument on vdso because KASAN is not compatible with user mode +KASAN_SANITIZE := n + # Prevents link failures: __sanitizer_cov_trace_pc() is not linked in. KCOV_INSTRUMENT := n diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c index a4f07de21771..d8c518bd0e7d 100644 --- a/mm/kasan/shadow.c +++ b/mm/kasan/shadow.c @@ -295,8 +295,14 @@ int kasan_populate_vmalloc(unsigned long addr, unsigned long size) return 0; shadow_start = (unsigned long)kasan_mem_to_shadow((void *)addr); - shadow_start = ALIGN_DOWN(shadow_start, PAGE_SIZE); shadow_end = (unsigned long)kasan_mem_to_shadow((void *)addr + size); + + if (IS_ENABLED(CONFIG_UML)) { + __memset(kasan_mem_to_shadow((void *)addr), KASAN_VMALLOC_INVALID, shadow_end - shadow_start); + return 0; + } + + shadow_start = ALIGN_DOWN(shadow_start, PAGE_SIZE); shadow_end = ALIGN(shadow_end, PAGE_SIZE); ret = apply_to_page_range(&init_mm, shadow_start, @@ -466,6 +472,10 @@ void kasan_release_vmalloc(unsigned long start, unsigned long end, if (shadow_end > shadow_start) { size = shadow_end - shadow_start; + if (IS_ENABLED(CONFIG_UML)) { + __memset(shadow_start, KASAN_SHADOW_INIT, shadow_end - shadow_start); + return; + } apply_to_existing_page_range(&init_mm, (unsigned long)shadow_start, size, kasan_depopulate_vmalloc_pte, @@ -531,6 +541,11 @@ int kasan_alloc_module_shadow(void *addr, size_t size, gfp_t gfp_mask) if (WARN_ON(!PAGE_ALIGNED(shadow_start))) return -EINVAL; + if (IS_ENABLED(CONFIG_UML)) { + __memset((void *)shadow_start, KASAN_SHADOW_INIT, shadow_size); + return 0; + } + ret = __vmalloc_node_range(shadow_size, 1, shadow_start, shadow_start + shadow_size, GFP_KERNEL, @@ -554,6 +569,9 @@ int kasan_alloc_module_shadow(void *addr, size_t size, gfp_t gfp_mask) void kasan_free_module_shadow(const struct vm_struct *vm) { + if (IS_ENABLED(CONFIG_UML)) + return; + if (vm->flags & VM_KASAN) vfree(kasan_mem_to_shadow(vm->addr)); }