From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 96C89C4707B for ; Thu, 18 Jan 2024 12:41:39 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 2859C6B00A0; Thu, 18 Jan 2024 07:41:39 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 235716B00A1; Thu, 18 Jan 2024 07:41:39 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 0AFF06B00A2; Thu, 18 Jan 2024 07:41:39 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0014.hostedemail.com [216.40.44.14]) by kanga.kvack.org (Postfix) with ESMTP id EC5496B00A0 for ; Thu, 18 Jan 2024 07:41:38 -0500 (EST) Received: from smtpin04.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay02.hostedemail.com (Postfix) with ESMTP id ADB7D120C4C for ; Thu, 18 Jan 2024 12:41:38 +0000 (UTC) X-FDA: 81692393076.04.2C7D0E7 Received: from mail-pf1-f177.google.com (mail-pf1-f177.google.com [209.85.210.177]) by imf06.hostedemail.com (Postfix) with ESMTP id D718918000D for ; Thu, 18 Jan 2024 12:41:36 +0000 (UTC) Authentication-Results: imf06.hostedemail.com; dkim=pass header.d=bytedance.com header.s=google header.b=JmdXqMXi; dmarc=pass (policy=quarantine) header.from=bytedance.com; spf=pass (imf06.hostedemail.com: domain of lizhe.67@bytedance.com designates 209.85.210.177 as permitted sender) smtp.mailfrom=lizhe.67@bytedance.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1705581696; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=/7QhB8TKXSng5TkzJ8qXu0ZMAf7utNsR4jcyGuAQsHs=; b=IqMIA3+0QVQXaNr9yG8X3xpbHBeZ8PK21wzgU9ah0/7wLCzIVSWVuv/kNoaZHebDRukoYD O5UjqIv/NpoSPIdNpyXQgbof8pO5ac7OoCx9thkHxJnF7YOLv5ceTgezoaM9vJF9N6cZH6 ECQ5VYCJ47WKMhJIUjDKeJq+nKm7hhc= ARC-Authentication-Results: i=1; imf06.hostedemail.com; dkim=pass header.d=bytedance.com header.s=google header.b=JmdXqMXi; dmarc=pass (policy=quarantine) header.from=bytedance.com; spf=pass (imf06.hostedemail.com: domain of lizhe.67@bytedance.com designates 209.85.210.177 as permitted sender) smtp.mailfrom=lizhe.67@bytedance.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1705581696; a=rsa-sha256; cv=none; b=t/z0mPpVausFPgbMF2oShAOiNevjbWje+hzmXZBzixaLsOaI+lZ25IGVwbetTXp8bFiq8y 3d5k3uDesh1e5ly6twnin7/6l9TTVbJrvcl9X/etfVQFpNOpqI60th9EzbLLfBvc+NM70P CWZeodVmLZj/9PX9octxtf1R8AfcVKE= Received: by mail-pf1-f177.google.com with SMTP id d2e1a72fcca58-6d9b13fe9e9so9313496b3a.2 for ; Thu, 18 Jan 2024 04:41:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance.com; s=google; t=1705581696; x=1706186496; darn=kvack.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=/7QhB8TKXSng5TkzJ8qXu0ZMAf7utNsR4jcyGuAQsHs=; b=JmdXqMXiPWHnqx5VJUSipFpMz4kytqu5i+2ayMdlgohrEt5GxQghtAyVNZCZtgGGVg 2EHvG1sqx5ZulPQUFD6iVMEGoc02TxDcseIr7DutTUBYMoflnV5/l6e6qlPDgbp8zn0r xjZzzVhvnzhlTK1Hd0MKyLGnnPH8Xngar2k1chHbCYEfdMdBowMpoq37d/25ELHFS7O2 nZl+/XUXuypG3wcaKXCPXLMmT4oq/p6t1bLIpeKvgR1iGKkaxtxp8DSVlRkmI3rD/Q3R CyQU6JEx5mWLem/W36jitzTrhAVNVwnxQqykjuM60RhAfwUfBoBf/BOSDRRTOuiQl8XE KFEA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1705581696; x=1706186496; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=/7QhB8TKXSng5TkzJ8qXu0ZMAf7utNsR4jcyGuAQsHs=; b=tBjZSbP29X4/ggdje3v+hXRe8nopLHcmbQeblzfZa2gwVTKMquE4n2E8Q6UQ2Nal1M R0AsULE2VBoKM2tgTIJF25aoAOUOl4B5Gd3tSJU/TE7IvBKhcon/ecC10da72c2xALbb 1fSKxXQx7B1vvZJqnkWSLuCVsLqxvBU/ErkjVJMGCN7Rv033DSj6EN9QIaNiqKK3pSIg A5G+6H8pJ2GtpYGCAtK+OrTUJCJVAly1DpBr9AaQWGN16nNw5JIBbuSet4LKZMMdU+yE moqiekQqYlcKgWzipPSsIQgfMT6hHMgZSTHi7fpD76SXqt6Ki1mVsVXT3zftiGPsmHjO o0hg== X-Gm-Message-State: AOJu0YydD0mSFb+fsvtIDZh81QTQtEmk17b6BteNH08DkyPUGeqR/sJs 0jnSJn+CUejRXLB5mIZW/qANL+Z/Nq2vwsRKtpO5pwqbN7d4v/cAgaCGorX1P/c= X-Google-Smtp-Source: AGHT+IH12OAH517c08I8+dwjpo76aFTy4zWQyFh69Sd9+ejFmgQepL+pHYwT7Ngq2s/q9eEPec1vEA== X-Received: by 2002:a05:6a00:93a6:b0:6db:883a:ffc0 with SMTP id ka38-20020a056a0093a600b006db883affc0mr893007pfb.12.1705581695652; Thu, 18 Jan 2024 04:41:35 -0800 (PST) Received: from GQ6QX3JCW2.bytedance.net ([203.208.189.13]) by smtp.gmail.com with ESMTPSA id y17-20020a056a00191100b006d977f70cd5sm3199744pfi.23.2024.01.18.04.41.31 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 18 Jan 2024 04:41:35 -0800 (PST) From: lizhe.67@bytedance.com To: ryabinin.a.a@gmail.com, glider@google.com, andreyknvl@gmail.com, dvyukov@google.com, vincenzo.frascino@arm.com, akpm@linux-foundation.org Cc: kasan-dev@googlegroups.com, linux-mm@kvack.org, lizefan.x@bytedance.com, lizhe.67@bytedance.com Subject: [RFC 2/2] kasan: add mem track interface and its test cases Date: Thu, 18 Jan 2024 20:41:09 +0800 Message-ID: <20240118124109.37324-3-lizhe.67@bytedance.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240118124109.37324-1-lizhe.67@bytedance.com> References: <20240118124109.37324-1-lizhe.67@bytedance.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: D718918000D X-Rspam-User: X-Rspamd-Server: rspam05 X-Stat-Signature: pop9h44ktgcxgmzjtzysyuamwrraemre X-HE-Tag: 1705581696-135629 X-HE-Meta: U2FsdGVkX1+a90uJl1aI1Rq5MsGKL+J00qCtbHJ3iUuyM/5iAjNrndZE1YeEiWPUEoMgCg56cCXG53PzjD5aSgqN/Tsj1O098pFHj5I32d+0Cr0tmejRsAQvLBl4PXkZgFt8Mjr0tGI4zf7xC91hgO+gsT9UiVHeX2cpXm2wA5yj9ICg37iWHYyS613Nw9sGSdTLAco+cGWfBPdM4T2yXYvD5Nk9n1+oSoo4dDgf476Tc0jICxfSnIKmyl6+k6iRyhMyyPsFg1e0sgXf+4chGUIYPagNuzHMitYsVZkunJBVfuiqBADEedv4X/cOk/06czScgHINP/OO8yXbw+HuLgf12wF+2lqxr7P8WwTiAcllT4ngaI8ByKnrMViVOAqD2opQr4jEE6HjL3jH2qqnHbL5/npAqtq9DiN8cjNy+Mt32lDhkSequHmGdMRUG5MLYGkzWl9Mu1r8FFa3ovKVNL4Qf3zg4GMg02hxwT/M4m7M4qtMZUyVWX8jXNIMtcGnna4an+d6vRuLvqFBegCMovr1avaWCIWasGERpMFNr0mEqiM1mkcQIOiru5LXKfO2qAxMKu07aA9IwlSElFFRd9Uqecq66NM/Y3Xj5nUGKT74Yz3UoHE0Ytlg+nUaizIL69oq5az62oDpwce/pSq4EJpucNaSvDAST1Tp0KNgffIIQT+HaVebp3HR4/IWjJzFXiIvU/C99VV2KjxTx8nKE5G44qiWCi+vtgtougDdUd6gtS5SRtOUfOx+7xQJao23cO1bXNCpr20CgYGVv9BlBuntmqwfSoCY7bhh3Tmy/M6GsO5slRhNuR25sUZ9EOQmkmOhBlAW8/SxIC4AbmuXthKx9V8fcTRWY84KMRztvjKptE4I3O9fz+95TEXV0YrpioU8CmILfD7D8uSlNzobmWzOm3hDvyuMdNMg/L/md+97PLogO0BM1IWNTjpXEmPCQjBbIAjU/5xRWYhb2sB hNiKr0t/ O2QLjEruVAKRbsTbj9G+4Rwkxy1Bp7PxkYmckDlK3jUl2iyTuC0BkySsIEnXnBy6w09U97xt94qZEE3S//DyGiQz3UppuWaXkCjni5xLhnqUrVvPYMrZ0QvGJzJX/hfwmbCkaxlyQzIZwd5c5j51JiEdy+PCX7YxK3V32UlCfPr5IrsrDwBozX/HQlIOfzj2WJZoet7X1gfuTue8BCjIkq/OGRvYt53VoeBdw0jmz2gaYl9lyLyrZAAuDV2xuyv+OjxclmXmirIW20aW32NR9LQS7pVcyV5EQ5CGVN2jC9/l0Ii4E8WnJH3FYV893v2ooAwPS+z9sCkm8yVuzicA1NxjcLhqB3dpEQWcCiT0ai8rMyV3VR1L7fpQmnsXs+em/+PTWGDfUVgsAxEtXlt1yp1jaKEpE/XP2EkKUiI9cH+5WL9NIsYa+mJvo9q0okb6rpBQclBpgHz1I/GL8ufRqVYhWry8iEjUI5XQoXcKyAzTW87o= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: Li Zhe kasan_track_memory() and kasan_untrack_memory() are two interfaces used to track memory write operations. We can use them to locate problems where memory has been accidentally rewritten. Examples of interface usages are shown in kasan_test_module.c Signed-off-by: Li Zhe --- include/linux/kasan.h | 5 ++ mm/kasan/generic.c | 161 +++++++++++++++++++++++++++++++++++ mm/kasan/kasan_test_module.c | 26 ++++++ 3 files changed, 192 insertions(+) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index dbb06d789e74..ca5d93629ccf 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -604,4 +604,9 @@ void kasan_non_canonical_hook(unsigned long addr); static inline void kasan_non_canonical_hook(unsigned long addr) { } #endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */ +#ifdef CONFIG_KASAN_MEM_TRACK +int kasan_track_memory(const void *addr, size_t size); +int kasan_untrack_memory(const void *addr, size_t size); +#endif + #endif /* LINUX_KASAN_H */ diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index a204ddcbaa3f..61f3f5125338 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -402,6 +402,167 @@ static __always_inline bool memory_is_tracked(const void *addr, size_t size) return memory_is_tracked_n(addr, size); } + +/* deal with addr do not cross 8(shadow size)-byte boundary */ +static void __kasan_track_memory(const void *shadow_addr, size_t offset, size_t size) +{ + s8 mask; + + if ((offset & 0x01) || (size & 0x01)) + mask = kasan_track_mask_odd(size); + else + mask = kasan_track_mask_even(size); + offset = offset >> 1; + *(s8 *)shadow_addr |= mask << (KASAN_TRACK_VALUE_OFFSET + offset); +} + +static void _kasan_track_memory(const void *addr, size_t size) +{ + unsigned int words; + const void *start = kasan_mem_to_shadow(addr); + unsigned int prefix = (unsigned long)addr % 8; + + if (prefix) { + unsigned int tmp_size = (unsigned int)size; + + tmp_size = min(8 - prefix, tmp_size); + __kasan_track_memory(start, prefix, tmp_size); + start++; + size -= tmp_size; + } + + words = size / 8; + while (words) { + __kasan_track_memory(start, 0, 8); + start++; + words--; + } + + if (size % 8) + __kasan_track_memory(start, 0, size % 8); +} + +static inline bool is_cpu_entry_area_addr(unsigned long addr) +{ + return ((addr >= CPU_ENTRY_AREA_BASE) && + (addr < CPU_ENTRY_AREA_BASE + CPU_ENTRY_AREA_MAP_SIZE)); +} + +static inline bool is_kernel_text_data(unsigned long addr) +{ + return ((addr >= (unsigned long)_stext) && (addr < (unsigned long)_end)); +} + +static bool can_track(unsigned long addr) +{ + if (!virt_addr_valid(addr) && + !is_module_address(addr) && +#ifdef CONFIG_KASAN_VMALLOC + !is_vmalloc_addr((const void *)addr) && +#endif + !is_cpu_entry_area_addr(addr) && + !is_kernel_text_data(addr) + ) + return false; + + return true; +} + +int kasan_track_memory(const void *addr, size_t size) +{ + if (!kasan_arch_is_ready()) + return -EINVAL; + + if (unlikely(size == 0)) + return -EINVAL; + + if (unlikely(addr + size < addr)) + return -EINVAL; + + if (unlikely(!addr_has_metadata(addr))) + return -EINVAL; + + if (likely(memory_is_poisoned(addr, size))) + return -EINVAL; + + if (!can_track((unsigned long)addr)) + return -EINVAL; + + _kasan_track_memory(addr, size); + return 0; +} +EXPORT_SYMBOL(kasan_track_memory); + +/* deal with addr do not cross 8(shadow size)-byte boundary */ +static void __kasan_untrack_memory(const void *shadow_addr, size_t offset, size_t size) +{ + s8 mask; + + if (size % 0x01) { + offset = (offset - 1) >> 1; + mask = kasan_track_mask_odd(size); + /* + * SIZE is odd, which means we may clear someone else's tracking flags of + * nearby tracked memory. + */ + pr_info("It's possible to clear someone else's tracking flags\n"); + } else { + offset = offset >> 1; + mask = kasan_track_mask_even(size); + } + *(s8 *)shadow_addr &= ~(mask << (KASAN_TRACK_VALUE_OFFSET + offset)); +} + +static void _kasan_untrack_memory(const void *addr, size_t size) +{ + unsigned int words; + const void *start = kasan_mem_to_shadow(addr); + unsigned int prefix = (unsigned long)addr % 8; + + if (prefix) { + unsigned int tmp_size = (unsigned int)size; + + tmp_size = min(8 - prefix, tmp_size); + __kasan_untrack_memory(start, prefix, tmp_size); + start++; + size -= tmp_size; + } + + words = size / 8; + while (words) { + __kasan_untrack_memory(start, 0, 8); + start++; + words--; + } + + if (size % 8) + __kasan_untrack_memory(start, 0, size % 8); +} + +int kasan_untrack_memory(const void *addr, size_t size) +{ + if (!kasan_arch_is_ready()) + return -EINVAL; + + if (unlikely(size == 0)) + return -EINVAL; + + if (unlikely(addr + size < addr)) + return -EINVAL; + + if (unlikely(!addr_has_metadata(addr))) + return -EINVAL; + + if (likely(memory_is_poisoned(addr, size))) + return -EINVAL; + + if (!can_track((unsigned long)addr)) + return -EINVAL; + + _kasan_untrack_memory(addr, size); + return 0; +} +EXPORT_SYMBOL(kasan_untrack_memory); #endif static __always_inline bool check_region_inline(const void *addr, diff --git a/mm/kasan/kasan_test_module.c b/mm/kasan/kasan_test_module.c index 8b7b3ea2c74e..1dba44dbfc81 100644 --- a/mm/kasan/kasan_test_module.c +++ b/mm/kasan/kasan_test_module.c @@ -62,6 +62,31 @@ static noinline void __init copy_user_test(void) kfree(kmem); } +#ifdef CONFIG_KASAN_MEM_TRACK +static noinline void __init mem_track_test(void) +{ + int ret; + int *ptr = kmalloc(sizeof(int), GFP_KERNEL); + + if (!ptr) + return; + + ret = kasan_track_memory(ptr, sizeof(int)); + if (ret) { + pr_warn("There is a bug of mem_track\n"); + goto out; + } + pr_info("trigger mem_track\n"); + WRITE_ONCE(*ptr, 1); + kasan_untrack_memory(ptr, sizeof(int)); + +out: + kfree(ptr); +} +#else +static inline void __init mem_track_test(void) {} +#endif + static int __init test_kasan_module_init(void) { /* @@ -72,6 +97,7 @@ static int __init test_kasan_module_init(void) bool multishot = kasan_save_enable_multi_shot(); copy_user_test(); + mem_track_test(); kasan_restore_multi_shot(multishot); return -EAGAIN; -- 2.20.1