From patchwork Thu Apr 23 15:45:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Daniel Axtens X-Patchwork-Id: 11505961 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 27530159A for ; Thu, 23 Apr 2020 15:45:17 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id DE1EF20767 for ; Thu, 23 Apr 2020 15:45:16 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=axtens.net header.i=@axtens.net header.b="jPvZSIVR" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DE1EF20767 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=axtens.net Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 0BB958E0006; Thu, 23 Apr 2020 11:45:16 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 06C578E0003; Thu, 23 Apr 2020 11:45:16 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id EC4818E0006; Thu, 23 Apr 2020 11:45:15 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0183.hostedemail.com [216.40.44.183]) by kanga.kvack.org (Postfix) with ESMTP id D63438E0003 for ; Thu, 23 Apr 2020 11:45:15 -0400 (EDT) Received: from smtpin03.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay02.hostedemail.com (Postfix) with ESMTP id 9BDBBA2BD for ; Thu, 23 Apr 2020 15:45:15 +0000 (UTC) X-FDA: 76739543790.03.wren72_680f88dbde153 X-Spam-Summary: 2,0,0,7d04e15ebc39d12d,d41d8cd98f00b204,dja@axtens.net,,RULES_HIT:2:41:69:152:355:379:541:800:960:966:973:988:989:1260:1277:1311:1313:1314:1345:1359:1431:1437:1515:1516:1518:1535:1593:1594:1605:1606:1730:1747:1777:1792:2196:2199:2380:2393:2559:2562:2693:3138:3139:3140:3141:3142:3865:3866:3867:3868:3870:3871:3874:4119:4250:4321:4385:4605:5007:6119:6261:6653:7514:7808:8603:9121:10004:11026:11233:11473:11658:11914:12043:12048:12291:12296:12297:12438:12517:12519:12555:12679:12683:12895:12986:13161:13229:13255:13894:14394:14659:21063:21080:21444:21451:21627:21796:21990:30012:30030:30034:30036:30054:30070,0,RBL:209.85.215.195:@axtens.net:.lbl8.mailshell.net-66.100.201.201 62.2.0.100,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:ft,MSBL:0,DNSBL:none,Custom_rules:0:0:0,LFtime:27,LUA_SUMMARY:none X-HE-Tag: wren72_680f88dbde153 X-Filterd-Recvd-Size: 8365 Received: from mail-pg1-f195.google.com (mail-pg1-f195.google.com [209.85.215.195]) by imf11.hostedemail.com (Postfix) with ESMTP for ; Thu, 23 Apr 2020 15:45:14 +0000 (UTC) Received: by mail-pg1-f195.google.com with SMTP id s18so407479pgl.12 for ; Thu, 23 Apr 2020 08:45:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=axtens.net; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Rm9KJcgesHnxEUAmWee/mQjOLa+QTtuSP9X5sIq0tgA=; b=jPvZSIVRZtIuE/ljLJ3/1SMhxZNEYVUDCJn9nhJ1b8Rl/QIVp+M4bzvcP3LLZPvbj+ Ep1FWxzMDYCy8ID1pym0moYcnagwj44Z0fGnTNV/px2InnO20wPoAGY2Lehuaau4EKhV MgAEZsw3rHya1t16HQL+3GnyKd8WKAqsljxmA= 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=Rm9KJcgesHnxEUAmWee/mQjOLa+QTtuSP9X5sIq0tgA=; b=kNbNcxz7dB7wyfbBAHujS93iuqcdcWI7Glm/JrJ3sZRFEgBPWKF1Tf32pvRJDgQrHy Xg7i4vOmLfEtN3Ap0EbhNbgRc5V/+bdlbmME2dk5dtoY/eTeBbxb8PLAo7CGOjYQ8BFz j8pQolJO3FS6lY4iLYnoHiZ2nnyGX1ulqbbjZijeYDexRYDlhyj/Gd4mdGqSz5jdzrif ltEgYHRE2/j8ntpx8U9w1jdw2pHS+psb5w0WfAGIZ9pQTBKvjQj39wmU9cmqzzxFzN3n WVN/8ygdRTEaGmAbcFtP+qW0GUcu8qgwVlw75esKDxOb9IhkC9nkoUBMK2FkJCNyjqNk IbmA== X-Gm-Message-State: AGi0PuaHdYDlbb96hmDO89k9oewHvPMCBo5YCVdQZjI0eTvV63pGZVaX FxIxCwQKWfDh+BsRu/p8a8z18w== X-Google-Smtp-Source: APiQypJYVTiq1ojI2FxBtYaYdroS0cYv8IN+wrMRkcl61wXgxQMLYHKSmaDJF4pzqDaEJ9/oI6GZmg== X-Received: by 2002:a62:1d48:: with SMTP id d69mr4369984pfd.102.1587656714044; Thu, 23 Apr 2020 08:45:14 -0700 (PDT) Received: from localhost (2001-44b8-111e-5c00-7979-720a-9390-aec6.static.ipv6.internode.on.net. [2001:44b8:111e:5c00:7979:720a:9390:aec6]) by smtp.gmail.com with ESMTPSA id w125sm2435466pgw.22.2020.04.23.08.45.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Apr 2020 08:45:13 -0700 (PDT) From: Daniel Axtens To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, akpm@linux-foundation.org, kasan-dev@googlegroups.com Cc: dvyukov@google.com, christophe.leroy@c-s.fr, Daniel Axtens , Daniel Micay , Andrey Ryabinin , Alexander Potapenko Subject: [PATCH v3 1/3] kasan: stop tests being eliminated as dead code with FORTIFY_SOURCE Date: Fri, 24 Apr 2020 01:45:01 +1000 Message-Id: <20200423154503.5103-2-dja@axtens.net> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200423154503.5103-1-dja@axtens.net> References: <20200423154503.5103-1-dja@axtens.net> MIME-Version: 1.0 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: 3 KASAN self-tests fail on a kernel with both KASAN and FORTIFY_SOURCE: memchr, memcmp and strlen. When FORTIFY_SOURCE is on, a number of functions are replaced with fortified versions, which attempt to check the sizes of the operands. However, these functions often directly invoke __builtin_foo() once they have performed the fortify check. The compiler can detect that the results of these functions are not used, and knows that they have no other side effects, and so can eliminate them as dead code. Why are only memchr, memcmp and strlen affected? ================================================ Of string and string-like functions, kasan_test tests: * strchr -> not affected, no fortified version * strrchr -> likewise * strcmp -> likewise * strncmp -> likewise * strnlen -> not affected, the fortify source implementation calls the underlying strnlen implementation which is instrumented, not a builtin * strlen -> affected, the fortify souce implementation calls a __builtin version which the compiler can determine is dead. * memchr -> likewise * memcmp -> likewise * memset -> not affected, the compiler knows that memset writes to its first argument and therefore is not dead. Why does this not affect the functions normally? ================================================ In string.h, these functions are not marked as __pure, so the compiler cannot know that they do not have side effects. If relevant functions are marked as __pure in string.h, we see the following warnings and the functions are elided: lib/test_kasan.c: In function ‘kasan_memchr’: lib/test_kasan.c:606:2: warning: statement with no effect [-Wunused-value] memchr(ptr, '1', size + 1); ^~~~~~~~~~~~~~~~~~~~~~~~~~ lib/test_kasan.c: In function ‘kasan_memcmp’: lib/test_kasan.c:622:2: warning: statement with no effect [-Wunused-value] memcmp(ptr, arr, size+1); ^~~~~~~~~~~~~~~~~~~~~~~~ lib/test_kasan.c: In function ‘kasan_strings’: lib/test_kasan.c:645:2: warning: statement with no effect [-Wunused-value] strchr(ptr, '1'); ^~~~~~~~~~~~~~~~ ... This annotation would make sense to add and could be added at any point, so the behaviour of test_kasan.c should change. The fix ======= Make all the functions that are pure write their results to a global, which makes them live. The strlen and memchr tests now pass. The memcmp test still fails to trigger, which is addressed in the next patch. Cc: Daniel Micay Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Dmitry Vyukov Fixes: 0c96350a2d2f ("lib/test_kasan.c: add tests for several string/memory API functions") Reviewed-by: Dmitry Vyukov Signed-off-by: Daniel Axtens --- lib/test_kasan.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index e3087d90e00d..939f395a5392 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -23,6 +23,14 @@ #include +/* + * We assign some test results to these globals to make sure the tests + * are not eliminated as dead code. + */ + +int kasan_int_result; +void *kasan_ptr_result; + /* * Note: test functions are marked noinline so that their names appear in * reports. @@ -622,7 +630,7 @@ static noinline void __init kasan_memchr(void) if (!ptr) return; - memchr(ptr, '1', size + 1); + kasan_ptr_result = memchr(ptr, '1', size + 1); kfree(ptr); } @@ -637,8 +645,7 @@ static noinline void __init kasan_memcmp(void) if (!ptr) return; - memset(arr, 0, sizeof(arr)); - memcmp(ptr, arr, size+1); + kasan_int_result = memcmp(ptr, arr, size + 1); kfree(ptr); } @@ -661,22 +668,22 @@ static noinline void __init kasan_strings(void) * will likely point to zeroed byte. */ ptr += 16; - strchr(ptr, '1'); + kasan_ptr_result = strchr(ptr, '1'); pr_info("use-after-free in strrchr\n"); - strrchr(ptr, '1'); + kasan_ptr_result = strrchr(ptr, '1'); pr_info("use-after-free in strcmp\n"); - strcmp(ptr, "2"); + kasan_int_result = strcmp(ptr, "2"); pr_info("use-after-free in strncmp\n"); - strncmp(ptr, "2", 1); + kasan_int_result = strncmp(ptr, "2", 1); pr_info("use-after-free in strlen\n"); - strlen(ptr); + kasan_int_result = strlen(ptr); pr_info("use-after-free in strnlen\n"); - strnlen(ptr, 1); + kasan_int_result = strnlen(ptr, 1); } static noinline void __init kasan_bitops(void) @@ -743,11 +750,12 @@ static noinline void __init kasan_bitops(void) __test_and_change_bit(BITS_PER_LONG + BITS_PER_BYTE, bits); pr_info("out-of-bounds in test_bit\n"); - (void)test_bit(BITS_PER_LONG + BITS_PER_BYTE, bits); + kasan_int_result = test_bit(BITS_PER_LONG + BITS_PER_BYTE, bits); #if defined(clear_bit_unlock_is_negative_byte) pr_info("out-of-bounds in clear_bit_unlock_is_negative_byte\n"); - clear_bit_unlock_is_negative_byte(BITS_PER_LONG + BITS_PER_BYTE, bits); + kasan_int_result = clear_bit_unlock_is_negative_byte(BITS_PER_LONG + + BITS_PER_BYTE, bits); #endif kfree(bits); } From patchwork Thu Apr 23 15:45:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Axtens X-Patchwork-Id: 11505963 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 DEB98159A for ; Thu, 23 Apr 2020 15:45:21 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 922222076C for ; Thu, 23 Apr 2020 15:45:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=axtens.net header.i=@axtens.net header.b="kwPI21rA" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 922222076C Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=axtens.net Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 7C0948E0007; Thu, 23 Apr 2020 11:45:20 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 771498E0003; Thu, 23 Apr 2020 11:45:20 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 686F48E0007; Thu, 23 Apr 2020 11:45:20 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0243.hostedemail.com [216.40.44.243]) by kanga.kvack.org (Postfix) with ESMTP id 4F56E8E0003 for ; Thu, 23 Apr 2020 11:45:20 -0400 (EDT) Received: from smtpin07.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay01.hostedemail.com (Postfix) with ESMTP id 0CD85180AD830 for ; Thu, 23 Apr 2020 15:45:20 +0000 (UTC) X-FDA: 76739544000.07.low94_68b578388c819 X-Spam-Summary: 2,0,0,0bd15c4d95835dc6,d41d8cd98f00b204,dja@axtens.net,,RULES_HIT:1:41:355:379:541:800:960:973:988:989:1260:1311:1314:1345:1359:1431:1437:1515:1605:1730:1747:1777:1792:2393:2553:2559:2562:2637:2691:2693:3138:3139:3140:3141:3142:3865:3866:3867:3868:3870:3871:3872:3873:3874:4031:4250:4321:5007:6119:6261:6653:6691:7514:7875:7903:7974:8603:8660:9040:10004:11026:11473:11658:11914:12043:12048:12291:12296:12297:12438:12517:12519:12555:12663:12679:12683:12895:12986:13148:13161:13229:13230:13894:14096:14394:21080:21325:21444:21451:21627:21740:21809:21966:21972:21990:30003:30012:30034:30054:30056:30062:30070:30090,0,RBL:209.85.210.195:@axtens.net:.lbl8.mailshell.net-66.100.201.201 62.2.0.100,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:ft,MSBL:0,DNSBL:none,Custom_rules:0:0:0,LFtime:23,LUA_SUMMARY:none X-HE-Tag: low94_68b578388c819 X-Filterd-Recvd-Size: 14798 Received: from mail-pf1-f195.google.com (mail-pf1-f195.google.com [209.85.210.195]) by imf39.hostedemail.com (Postfix) with ESMTP for ; Thu, 23 Apr 2020 15:45:19 +0000 (UTC) Received: by mail-pf1-f195.google.com with SMTP id 145so3118430pfw.13 for ; Thu, 23 Apr 2020 08:45:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=axtens.net; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=oXOurz7xYFBUiiG0C2v689zvA4JfO+b6Z1z6+hi408A=; b=kwPI21rAfFxHk+Rneuyf73zvl0rKOeRIsN9XwRIa7wxlUJlEmlvFJxENn3XL4GwSCU X3tXu0ODwWcE95i/+L/355zN2y3V8OGqnPCCz1LAhZp8pQk2ZvlPvtnguQyJt+ngGlkY uNIhoRq1TCE+/D5oxSfmMiAITyCi5E8ommDlQ= 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=oXOurz7xYFBUiiG0C2v689zvA4JfO+b6Z1z6+hi408A=; b=JlQqQeOc95tbgtxd7pNfXTeKyMFcn79DvnNYVJDtHnosMrWfwm1Q1qMaJ0YweBr/Jf kftpPL3JKletwWQr8hUCgFesq6wqEV/8da0EyZIFizCu3l8CCanNyqyrqBdjeDSNBc1C mMAB6waoiuqRsFof9bHizcdhlY3r0XyY7rVEOm7GPv3NSXnEPvw7+9krCcHwasCfWGlq ihMDomn+m5XPcNRyTK7dN/DnYMjXj1hXTxNl7AJFA9FHifSGpL9gqJEPaIAqS+4C3Lxd YDFli7rVd2BKU44YVwwbBCMVN0XveanZvp0tH5MtSqlFjwbeksNI1iDoXTAFImSVOkQ7 aJHQ== X-Gm-Message-State: AGi0PubBLrJ6Zt22fI6gjLLyrC7SDt/bAGnZylnAE1r9uDhnmrV/2Fvf m6NGdcOdFTvOG9/grSqCXLBobw== X-Google-Smtp-Source: APiQypL3KAQGfqOTn69jgev4AlMUi6b2xyY5Z1JVk41lWXWlD1CJMbAFjbK6ijDW+ZYZEeGR107ZuA== X-Received: by 2002:a62:7cca:: with SMTP id x193mr4234270pfc.96.1587656718305; Thu, 23 Apr 2020 08:45:18 -0700 (PDT) Received: from localhost (2001-44b8-111e-5c00-7979-720a-9390-aec6.static.ipv6.internode.on.net. [2001:44b8:111e:5c00:7979:720a:9390:aec6]) by smtp.gmail.com with ESMTPSA id 22sm2961746pfb.132.2020.04.23.08.45.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Apr 2020 08:45:17 -0700 (PDT) From: Daniel Axtens To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, akpm@linux-foundation.org, kasan-dev@googlegroups.com Cc: dvyukov@google.com, christophe.leroy@c-s.fr, Daniel Axtens , Daniel Micay , Andrey Ryabinin , Alexander Potapenko Subject: [PATCH v3 2/3] string.h: fix incompatibility between FORTIFY_SOURCE and KASAN Date: Fri, 24 Apr 2020 01:45:02 +1000 Message-Id: <20200423154503.5103-3-dja@axtens.net> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200423154503.5103-1-dja@axtens.net> References: <20200423154503.5103-1-dja@axtens.net> MIME-Version: 1.0 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: The memcmp KASAN self-test fails on a kernel with both KASAN and FORTIFY_SOURCE. When FORTIFY_SOURCE is on, a number of functions are replaced with fortified versions, which attempt to check the sizes of the operands. However, these functions often directly invoke __builtin_foo() once they have performed the fortify check. Using __builtins may bypass KASAN checks if the compiler decides to inline it's own implementation as sequence of instructions, rather than emit a function call that goes out to a KASAN-instrumented implementation. Why is only memcmp affected? ============================ Of the string and string-like functions that kasan_test tests, only memcmp is replaced by an inline sequence of instructions in my testing on x86 with gcc version 9.2.1 20191008 (Ubuntu 9.2.1-9ubuntu2). I believe this is due to compiler heuristics. For example, if I annotate kmalloc calls with the alloc_size annotation (and disable some fortify compile-time checking!), the compiler will replace every memset except the one in kmalloc_uaf_memset with inline instructions. (I have some WIP patches to add this annotation.) Does this affect other functions in string.h? ============================================= Yes. Anything that uses __builtin_* rather than __real_* could be affected. This looks like: - strncpy - strcat - strlen - strlcpy maybe, under some circumstances? - strncat under some circumstances - memset - memcpy - memmove - memcmp (as noted) - memchr - strcpy Whether a function call is emitted always depends on the compiler. Most bugs should get caught by FORTIFY_SOURCE, but the missed memcmp test shows that this is not always the case. Isn't FORTIFY_SOURCE disabled with KASAN? ========================================- The string headers on all arches supporting KASAN disable fortify with kasan, but only when address sanitisation is _also_ disabled. For example from x86: #if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__) /* * For files that are not instrumented (e.g. mm/slub.c) we * should use not instrumented version of mem* functions. */ #define memcpy(dst, src, len) __memcpy(dst, src, len) #define memmove(dst, src, len) __memmove(dst, src, len) #define memset(s, c, n) __memset(s, c, n) #ifndef __NO_FORTIFY #define __NO_FORTIFY /* FORTIFY_SOURCE uses __builtin_memcpy, etc. */ #endif #endif This comes from commit 6974f0c4555e ("include/linux/string.h: add the option of fortified string.h functions"), and doesn't work when KASAN is enabled and the file is supposed to be sanitised - as with test_kasan.c I'm pretty sure this is not wrong, but not as expansive it should be: * we shouldn't use __builtin_memcpy etc in files where we don't have instrumentation - it could devolve into a function call to memcpy, which will be instrumented. Rather, we should use __memcpy which by convention is not instrumented. * we also shouldn't be using __builtin_memcpy when we have a KASAN instrumented file, because it could be replaced with inline asm that will not be instrumented. What is correct behaviour? ========================== Firstly, there is some overlap between fortification and KASAN: both provide some level of _runtime_ checking. Only fortify provides compile-time checking. KASAN and fortify can pick up different things at runtime: - Some fortify functions, notably the string functions, could easily be modified to consider sub-object sizes (e.g. members within a struct), and I have some WIP patches to do this. KASAN cannot detect these because it cannot insert poision between members of a struct. - KASAN can detect many over-reads/over-writes when the sizes of both operands are unknown, which fortify cannot. So there are a couple of options: 1) Flip the test: disable fortify in santised files and enable it in unsanitised files. This at least stops us missing KASAN checking, but we lose the fortify checking. 2) Make the fortify code always call out to real versions. Do this only for KASAN, for fear of losing the inlining opportunities we get from __builtin_*. (We can't use kasan_check_{read,write}: because the fortify functions are _extern inline_, you can't include _static_ inline functions without a compiler warning. kasan_check_{read,write} are static inline so we can't use them even when they would otherwise be suitable.) Take approach 2 and call out to real versions when KASAN is enabled. Use __underlying_foo to distinguish from __real_foo: __real_foo always refers to the kernel's implementation of foo, __underlying_foo could be either the kernel implementation or the __builtin_foo implementation. This is sometimes enough to make the memcmp test succeed with FORTIFY_SOURCE enabled. It is at least enough to get the function call into the module. One more fix is needed to make it reliable: see the next patch. Cc: Daniel Micay Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Dmitry Vyukov Fixes: 6974f0c4555e ("include/linux/string.h: add the option of fortified string.h functions") Signed-off-by: Daniel Axtens Reviewed-by: Dmitry Vyukov --- include/linux/string.h | 60 +++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/include/linux/string.h b/include/linux/string.h index 6dfbb2efa815..9b7a0632e87a 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -272,6 +272,31 @@ void __read_overflow3(void) __compiletime_error("detected read beyond size of ob void __write_overflow(void) __compiletime_error("detected write beyond size of object passed as 1st parameter"); #if !defined(__NO_FORTIFY) && defined(__OPTIMIZE__) && defined(CONFIG_FORTIFY_SOURCE) + +#ifdef CONFIG_KASAN +extern void *__underlying_memchr(const void *p, int c, __kernel_size_t size) __RENAME(memchr); +extern int __underlying_memcmp(const void *p, const void *q, __kernel_size_t size) __RENAME(memcmp); +extern void *__underlying_memcpy(void *p, const void *q, __kernel_size_t size) __RENAME(memcpy); +extern void *__underlying_memmove(void *p, const void *q, __kernel_size_t size) __RENAME(memmove); +extern void *__underlying_memset(void *p, int c, __kernel_size_t size) __RENAME(memset); +extern char *__underlying_strcat(char *p, const char *q) __RENAME(strcat); +extern char *__underlying_strcpy(char *p, const char *q) __RENAME(strcpy); +extern __kernel_size_t __underlying_strlen(const char *p) __RENAME(strlen); +extern char *__underlying_strncat(char *p, const char *q, __kernel_size_t count) __RENAME(strncat); +extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) __RENAME(strncpy); +#else +#define __underlying_memchr __builtin_memchr +#define __underlying_memcmp __builtin_memcmp +#define __underlying_memcpy __builtin_memcpy +#define __underlying_memmove __builtin_memmove +#define __underlying_memset __builtin_memset +#define __underlying_strcat __builtin_strcat +#define __underlying_strcpy __builtin_strcpy +#define __underlying_strlen __builtin_strlen +#define __underlying_strncat __builtin_strncat +#define __underlying_strncpy __builtin_strncpy +#endif + __FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size) { size_t p_size = __builtin_object_size(p, 0); @@ -279,14 +304,14 @@ __FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size) __write_overflow(); if (p_size < size) fortify_panic(__func__); - return __builtin_strncpy(p, q, size); + return __underlying_strncpy(p, q, size); } __FORTIFY_INLINE char *strcat(char *p, const char *q) { size_t p_size = __builtin_object_size(p, 0); if (p_size == (size_t)-1) - return __builtin_strcat(p, q); + return __underlying_strcat(p, q); if (strlcat(p, q, p_size) >= p_size) fortify_panic(__func__); return p; @@ -300,7 +325,7 @@ __FORTIFY_INLINE __kernel_size_t strlen(const char *p) /* Work around gcc excess stack consumption issue */ if (p_size == (size_t)-1 || (__builtin_constant_p(p[p_size - 1]) && p[p_size - 1] == '\0')) - return __builtin_strlen(p); + return __underlying_strlen(p); ret = strnlen(p, p_size); if (p_size <= ret) fortify_panic(__func__); @@ -333,7 +358,7 @@ __FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size) __write_overflow(); if (len >= p_size) fortify_panic(__func__); - __builtin_memcpy(p, q, len); + __underlying_memcpy(p, q, len); p[len] = '\0'; } return ret; @@ -346,12 +371,12 @@ __FORTIFY_INLINE char *strncat(char *p, const char *q, __kernel_size_t count) size_t p_size = __builtin_object_size(p, 0); size_t q_size = __builtin_object_size(q, 0); if (p_size == (size_t)-1 && q_size == (size_t)-1) - return __builtin_strncat(p, q, count); + return __underlying_strncat(p, q, count); p_len = strlen(p); copy_len = strnlen(q, count); if (p_size < p_len + copy_len + 1) fortify_panic(__func__); - __builtin_memcpy(p + p_len, q, copy_len); + __underlying_memcpy(p + p_len, q, copy_len); p[p_len + copy_len] = '\0'; return p; } @@ -363,7 +388,7 @@ __FORTIFY_INLINE void *memset(void *p, int c, __kernel_size_t size) __write_overflow(); if (p_size < size) fortify_panic(__func__); - return __builtin_memset(p, c, size); + return __underlying_memset(p, c, size); } __FORTIFY_INLINE void *memcpy(void *p, const void *q, __kernel_size_t size) @@ -378,7 +403,7 @@ __FORTIFY_INLINE void *memcpy(void *p, const void *q, __kernel_size_t size) } if (p_size < size || q_size < size) fortify_panic(__func__); - return __builtin_memcpy(p, q, size); + return __underlying_memcpy(p, q, size); } __FORTIFY_INLINE void *memmove(void *p, const void *q, __kernel_size_t size) @@ -393,7 +418,7 @@ __FORTIFY_INLINE void *memmove(void *p, const void *q, __kernel_size_t size) } if (p_size < size || q_size < size) fortify_panic(__func__); - return __builtin_memmove(p, q, size); + return __underlying_memmove(p, q, size); } extern void *__real_memscan(void *, int, __kernel_size_t) __RENAME(memscan); @@ -419,7 +444,7 @@ __FORTIFY_INLINE int memcmp(const void *p, const void *q, __kernel_size_t size) } if (p_size < size || q_size < size) fortify_panic(__func__); - return __builtin_memcmp(p, q, size); + return __underlying_memcmp(p, q, size); } __FORTIFY_INLINE void *memchr(const void *p, int c, __kernel_size_t size) @@ -429,7 +454,7 @@ __FORTIFY_INLINE void *memchr(const void *p, int c, __kernel_size_t size) __read_overflow(); if (p_size < size) fortify_panic(__func__); - return __builtin_memchr(p, c, size); + return __underlying_memchr(p, c, size); } void *__real_memchr_inv(const void *s, int c, size_t n) __RENAME(memchr_inv); @@ -460,11 +485,22 @@ __FORTIFY_INLINE char *strcpy(char *p, const char *q) size_t p_size = __builtin_object_size(p, 0); size_t q_size = __builtin_object_size(q, 0); if (p_size == (size_t)-1 && q_size == (size_t)-1) - return __builtin_strcpy(p, q); + return __underlying_strcpy(p, q); memcpy(p, q, strlen(q) + 1); return p; } +/* Don't use these outside the FORITFY_SOURCE implementation */ +#undef __underlying_memchr +#undef __underlying_memcmp +#undef __underlying_memcpy +#undef __underlying_memmove +#undef __underlying_memset +#undef __underlying_strcat +#undef __underlying_strcpy +#undef __underlying_strlen +#undef __underlying_strncat +#undef __underlying_strncpy #endif /** From patchwork Thu Apr 23 15:45:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Axtens X-Patchwork-Id: 11505965 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 4FD6E912 for ; Thu, 23 Apr 2020 15:45:25 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 1C8F020776 for ; Thu, 23 Apr 2020 15:45:25 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=axtens.net header.i=@axtens.net header.b="IqBvaW2G" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1C8F020776 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=axtens.net Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 10C448E0008; Thu, 23 Apr 2020 11:45:24 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 093C28E0003; Thu, 23 Apr 2020 11:45:24 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id EEB6E8E0008; Thu, 23 Apr 2020 11:45:23 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id CEC4F8E0003 for ; Thu, 23 Apr 2020 11:45:23 -0400 (EDT) Received: from smtpin08.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay05.hostedemail.com (Postfix) with ESMTP id 913FF181AC9C6 for ; Thu, 23 Apr 2020 15:45:23 +0000 (UTC) X-FDA: 76739544126.08.book93_693fccf178b60 X-Spam-Summary: 2,0,0,96ed7bd097e90c9c,d41d8cd98f00b204,dja@axtens.net,,RULES_HIT:41:355:379:541:800:960:973:988:989:1260:1311:1314:1345:1359:1431:1437:1515:1534:1541:1711:1730:1747:1777:1792:2380:2393:2553:2559:2562:3138:3139:3140:3141:3142:3352:3865:3866:3867:3870:3871:4321:5007:6119:6261:6653:8603:10004:11658:11914:12048:12297:12517:12519:12555:12895:12986:13069:13311:13357:13894:14181:14384:14394:14721:21080:21444:21451:21627:30012:30054:30090,0,RBL:209.85.215.195:@axtens.net:.lbl8.mailshell.net-62.2.0.100 66.100.201.201,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:ft,MSBL:0,DNSBL:neutral,Custom_rules:0:0:0,LFtime:25,LUA_SUMMARY:none X-HE-Tag: book93_693fccf178b60 X-Filterd-Recvd-Size: 4051 Received: from mail-pg1-f195.google.com (mail-pg1-f195.google.com [209.85.215.195]) by imf14.hostedemail.com (Postfix) with ESMTP for ; Thu, 23 Apr 2020 15:45:23 +0000 (UTC) Received: by mail-pg1-f195.google.com with SMTP id d17so3096836pgo.0 for ; Thu, 23 Apr 2020 08:45:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=axtens.net; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=+SloOzgks90oP9C6mvgapac7rntE6LuQE/iY+UvGdqE=; b=IqBvaW2GJu0QG+ZWgBIXE1KXL1ya6B4MBW23tQvRqVMiJqNihLu7ElQNpdOWuKXf2D e7fOcA8oeZHNM3l4zTGseuDdu7cySBLdVZCmqMt5FT1XF4o5RIHje5hfbbfRfuuQIF9l wlt0YjK5vcwOmbln9gLApxVOyBNzdy/PZ8FPk= 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=+SloOzgks90oP9C6mvgapac7rntE6LuQE/iY+UvGdqE=; b=SKqaK39zuMzMD6Qb4cgmbS3XQvP9XwHpYr0RdicMT5KZfb+uqnoTKJtEffa7U2RhWE Pqh0lOnNs70BRRrLTpMCTl4wxFyh2HXnbXunvBDsmJ+/qlO9+fr93Xftuvd0/nwiVo/8 a5OaX+KXTQnWDaSYwTlNgwEjdO8vXl9/IlzEdjXpHW+iqAUCEziwwLz2YucSDfHC/4sm r7RvghdliagWmVSJZxFyA0fxooUKPcbM5sG05R8m5LWEcmMKqH4htIL1J5hS8Q61L0dn 4s66EqXv/1GTMUKkEYVAZRvyAzbRz3pNtf6wg849ZzADmPndi5yLAh+Az6AIO+DQWUWP kBeQ== X-Gm-Message-State: AGi0PuZqDr0MyL4cYNHXIGhdJT2sm9cJUnQfqttqRrjLNjKjyg/UzyWp OnWZONmcKj3lfJFj5KfH5B3cEg== X-Google-Smtp-Source: APiQypI9GuOWUlHBu6sSOoBDP8OTkF209Ci68BXqNi3aY+8I1lm6ymh949tU0rIRJW1ZfPbwVMB3sQ== X-Received: by 2002:aa7:9f0a:: with SMTP id g10mr4217244pfr.109.1587656722363; Thu, 23 Apr 2020 08:45:22 -0700 (PDT) Received: from localhost (2001-44b8-111e-5c00-7979-720a-9390-aec6.static.ipv6.internode.on.net. [2001:44b8:111e:5c00:7979:720a:9390:aec6]) by smtp.gmail.com with ESMTPSA id z6sm2200624pgg.39.2020.04.23.08.45.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Apr 2020 08:45:21 -0700 (PDT) From: Daniel Axtens To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, akpm@linux-foundation.org, kasan-dev@googlegroups.com Cc: dvyukov@google.com, christophe.leroy@c-s.fr, Daniel Axtens , Andrey Ryabinin , Alexander Potapenko Subject: [PATCH v3 3/3] kasan: initialise array in kasan_memcmp test Date: Fri, 24 Apr 2020 01:45:03 +1000 Message-Id: <20200423154503.5103-4-dja@axtens.net> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200423154503.5103-1-dja@axtens.net> References: <20200423154503.5103-1-dja@axtens.net> MIME-Version: 1.0 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: memcmp may bail out before accessing all the memory if the buffers contain differing bytes. kasan_memcmp calls memcmp with a stack array. Stack variables are not necessarily initialised (in the absence of a compiler plugin, at least). Sometimes this causes the memcpy to bail early thus fail to trigger kasan. Make sure the array initialised to zero in the code. No other test is dependent on the contents of an array on the stack. Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Dmitry Vyukov Signed-off-by: Daniel Axtens Reviewed-by: Dmitry Vyukov --- lib/test_kasan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index 939f395a5392..7700097842c8 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -638,7 +638,7 @@ static noinline void __init kasan_memcmp(void) { char *ptr; size_t size = 24; - int arr[9]; + int arr[9] = {}; pr_info("out-of-bounds in memcmp\n"); ptr = kmalloc(size, GFP_KERNEL | __GFP_ZERO);