From patchwork Thu Apr 6 00:02:00 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 79991 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp671139vqo; Wed, 5 Apr 2023 17:14:23 -0700 (PDT) X-Google-Smtp-Source: AKy350Yzj0fvVYPYiXRB4PGsXwH8b6J54xKstQrHfiiwpJggg0A10Wh4VOSFMKaXmDSLQI+KyiVx X-Received: by 2002:a17:906:4d8c:b0:8b1:88aa:46da with SMTP id s12-20020a1709064d8c00b008b188aa46damr4725219eju.48.1680740063509; Wed, 05 Apr 2023 17:14:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1680740063; cv=none; d=google.com; s=arc-20160816; b=jhbFiPKxlRNT7oSbKxRIPQtFMyDi8mPhAyS3Zq0CG5h0F9V6ld+3g5X8+8ivoc1G3G dXfqAUoaGEp96wF5AeIAy7NeqG+5XU/C+kMGkeHCX739Ksf2jxmS8EgkDyKVSK1lR2gU 1ZZZRtsVsn1x6i/a74zsjbj8e6kxMT2PdVeAujhKMWRapY1FiRf/xnoluI1gdKofzwJp +JPhLa6dp41ZZ3CnvtUzwks5vc2gcoQ46mDR9rbcKXI/wN5kS/MV3NppgQ60O7rfn7nc mzOU4K6Z4NndBDGWgN9QaVfvhYEVAn7mITRW9rydkzhazg38MRDN6o46zO9E+He5cq1m x4AA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=yl4oifEwokFvb7UV+3PIm/IUduHGwu9hGuhtq+IOj7k=; b=wnIVg7dzlMP0LSv+g0/+CjLhvILIGHqIHLRuLG6Eey09oqv74kENQUxZknM3FTjr5+ MF048AF1qPQDv+ijeR8W6ScHSWKz+vBoSqfCCkWIKV/uF+fW82tjm75qMpqT8J0Xxzzg zYR3fAB6x+fxMLvGl8ypbO8xkum2036eCKTpfUP7y6YOn7KXpKb4frNPaIy8dOqEf7fz 2zcQufvpBVJbhCo9/SifZabdG6fvc36MNFZXarl1Po/iQTWXiqwLgAT/PEFS+xMKZLQy atDFwuiRhrA4yhT+pmb4gNPGiYZoV9MEAU04aHotC1nAon5GqpEYypZOo5Lzk7rQNVuy uqjA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=c7cbXFjr; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id v3-20020a1709061dc300b00931b174e776si49682ejh.705.2023.04.05.17.14.00; Wed, 05 Apr 2023 17:14:23 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=c7cbXFjr; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231444AbjDFACR (ORCPT + 99 others); Wed, 5 Apr 2023 20:02:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47680 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229587AbjDFACP (ORCPT ); Wed, 5 Apr 2023 20:02:15 -0400 Received: from mail-pj1-x102b.google.com (mail-pj1-x102b.google.com [IPv6:2607:f8b0:4864:20::102b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 26CB359E2 for ; Wed, 5 Apr 2023 17:02:15 -0700 (PDT) Received: by mail-pj1-x102b.google.com with SMTP id l9-20020a17090a3f0900b0023d32684e7fso4825351pjc.1 for ; Wed, 05 Apr 2023 17:02:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1680739334; 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=yl4oifEwokFvb7UV+3PIm/IUduHGwu9hGuhtq+IOj7k=; b=c7cbXFjrLiWnvxHlZxDZRy65SnfcXBG7MdCPGJJ83MsAqWRNtFyns2n23kUsCLZ4hn 1T6sKpu2EQkDDkQ+m4lUJDgXXOtOk/VsL2gbb+1TkufqBn5kU5ZaUZYe+ThMfK7bqEFC IfqkVj//dOEjYyHc7kOeioK5PrTiEFgxpKWAc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680739334; 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=yl4oifEwokFvb7UV+3PIm/IUduHGwu9hGuhtq+IOj7k=; b=8SSfmf1thBae95R3OplixodJQzkA5EO0HnuB6K/OhxordzGsFRyEY4RRduBxz2pQrx dcIpX3I02c3wDGiNR271xCRGIn280Rn3ls2qq1zO74XR0uzOfcKnxxTMcIqiIw4ePTmM J7dfheNowsm0R5/LlvtAmLd7sdjOwOOS4KHx8xhCxiiMA5HOw/zfL7s02mqcD1fSxBGz OuSkmsWUFWIbM8g81eg1ETBcXNZ2bwzvlPK5pxlUorgB03/YLD7hyM4UJsGtXja6GYpg tGjhLyAD8sDqB9dpsSgXPFimEB/3KH/ILmcdlcsWC9O+Ca9fTSMxWI9o4pQ8TeL0MOJq 88mQ== X-Gm-Message-State: AAQBX9cfHuG462Zp+u6w9GFXlwoVaLKyaCp36pdR9EKf+VZsu8RAY3nY 8BNRRKYoQdHSbKRrfnKbrkAAtQ== X-Received: by 2002:a17:902:f685:b0:1a1:3320:be35 with SMTP id l5-20020a170902f68500b001a13320be35mr4569828plg.29.1680739334558; Wed, 05 Apr 2023 17:02:14 -0700 (PDT) Received: from www.outflux.net (198-0-35-241-static.hfc.comcastbusiness.net. [198.0.35.241]) by smtp.gmail.com with ESMTPSA id iy12-20020a170903130c00b0019aa5e0aadesm94957plb.110.2023.04.05.17.02.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Apr 2023 17:02:13 -0700 (PDT) From: Kees Cook To: linux-hardening@vger.kernel.org Cc: Kees Cook , Kees Cook , Andy Shevchenko , Cezary Rojewski , Puyou Lu , Mark Brown , Josh Poimboeuf , Peter Zijlstra , Brendan Higgins , David Gow , Andrew Morton , Nathan Chancellor , Alexander Potapenko , Zhaoyang Huang , Randy Dunlap , Geert Uytterhoeven , Miguel Ojeda , Nick Desaulniers , Liam Howlett , Vlastimil Babka , Dan Williams , Rasmus Villemoes , Yury Norov , "Jason A. Donenfeld" , Sander Vanheule , Eric Biggers , "Masami Hiramatsu (Google)" , Andrey Konovalov , Linus Walleij , Daniel Latypov , =?utf-8?b?Sm9zw6kgRXhww7NzaXRv?= , linux-kernel@vger.kernel.org, kunit-dev@googlegroups.com Subject: [PATCH 1/9] kunit: tool: Enable CONFIG_FORTIFY_SOURCE under UML Date: Wed, 5 Apr 2023 17:02:00 -0700 Message-Id: <20230406000212.3442647-1-keescook@chromium.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230405235832.never.487-kees@kernel.org> References: <20230405235832.never.487-kees@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=1288; i=keescook@chromium.org; h=from:subject; bh=vJg4ej+0zf5184Cn6hZT9ZDebanjHiE9mcbmpwHm1/Y=; b=owEBbQKS/ZANAwAKAYly9N/cbcAmAcsmYgBkLgv/xBxCluVnXo3PBfOHJyl251sCmrs8WnyVLVGG d0jLVMKJAjMEAAEKAB0WIQSlw/aPIp3WD3I+bhOJcvTf3G3AJgUCZC4L/wAKCRCJcvTf3G3AJioyD/ 45frMZpbUwAa/3Mzibgs8k057YB/OZAUl+jKPNwAm7gC4pvQX8tXYyGRlkhiJ1f4+gdXWDMUTws+Zb BtK5wLGDvCja19ksWutbgTiowgF3Uk3Ipzu1amZYOru+07rr9d1Oud0DGQPOxMqgTszbhRF9TjkR4k sCez3Ey9pylf9hHNakmuXr1RdGjlS4pysG1ELtNE82yUGf4T41/YHMspCYYUNI4Ww5KmaOX7blJxkV wqukEj2gAppyZPZAkUFKU59slkQLPUXP/VJGa7ZLCSEtVUxUNkf6tUBnQV4+NtkgQAffpTv40DHS0C bxGEkguixxvlv+m5yd2ONNaGfPSQGmcKn+JBgORFAo12/SOSPZ4tdiTguzhzDl4RQBlFvlpO9P33gG wuaHQt8MYZ937GrzO9nRpirP6ckub/I5mAwAHIMyeqb0fBn3/5EQrleyic/KAWZi3s+OgWVHl62rrq eUGR/yyXy//OEk5/9NvTUkzyjiRjY69IH/drENMObjunuJ8HUgSUdJfzycUmUjGbvjvnkRJ/uGW1L8 L9YKezQXJoANyGYQruQxZ/qq/CNLFiHWER4pDnXILHBDBsjIR8LuHIfHNtOYKyMf9tAjPMpEaoxAGw OUiWcRgLitBE2PJyEL+vPQgDLthqnJ/LYQRAKYmjRuWkQm1iKQeKd4oeQUEw== X-Developer-Key: i=keescook@chromium.org; a=openpgp; fpr=A5C3F68F229DD60F723E6E138972F4DFDC6DC026 X-Spam-Status: No, score=-0.2 required=5.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1762383692991625878?= X-GMAIL-MSGID: =?utf-8?q?1762383692991625878?= From: Kees Cook Since commit ba38961a069b ("um: Enable FORTIFY_SOURCE"), it's possible to run the FORTIFY tests under UML. Enable CONFIG_FORTIFY_SOURCE when running with --altests to gain additional coverage, and by default under UML. Signed-off-by: Kees Cook --- tools/testing/kunit/configs/all_tests.config | 2 ++ tools/testing/kunit/configs/arch_uml.config | 3 +++ 2 files changed, 5 insertions(+) diff --git a/tools/testing/kunit/configs/all_tests.config b/tools/testing/kunit/configs/all_tests.config index f990cbb73250..0393940c706a 100644 --- a/tools/testing/kunit/configs/all_tests.config +++ b/tools/testing/kunit/configs/all_tests.config @@ -9,6 +9,8 @@ CONFIG_KUNIT=y CONFIG_KUNIT_EXAMPLE_TEST=y CONFIG_KUNIT_ALL_TESTS=y +CONFIG_FORTIFY_SOURCE=y + CONFIG_IIO=y CONFIG_EXT4_FS=y diff --git a/tools/testing/kunit/configs/arch_uml.config b/tools/testing/kunit/configs/arch_uml.config index e824ce43b05a..54ad8972681a 100644 --- a/tools/testing/kunit/configs/arch_uml.config +++ b/tools/testing/kunit/configs/arch_uml.config @@ -3,3 +3,6 @@ # Enable virtio/pci, as a lot of tests require it. CONFIG_VIRTIO_UML=y CONFIG_UML_PCI_OVER_VIRTIO=y + +# Enable FORTIFY_SOURCE for wider checking. +CONFIG_FORTIFY_SOURCE=y From patchwork Thu Apr 6 00:02:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 79990 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp670899vqo; Wed, 5 Apr 2023 17:13:53 -0700 (PDT) X-Google-Smtp-Source: AKy350Y077r4CrAsG25ZoRpmNd+SR/YKEzm9NHGQDapzavbKmcfXN18lZoA310SRHBKKfU5zO9J9 X-Received: by 2002:a17:907:c30a:b0:8b1:779c:a8b1 with SMTP id tl10-20020a170907c30a00b008b1779ca8b1mr4478602ejc.5.1680740033058; Wed, 05 Apr 2023 17:13:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1680740033; cv=none; d=google.com; s=arc-20160816; b=YfE8X+9Lbu0vxyHRoQQuWWPk6Qu3kE4Qn/a3/DiqMkoAQ4cBycZ3Xxxry551daqyrJ OctfTZgH7HznjD6BZjv1J7d4DdEiId1qkFUhY3ghLxbZiq2A4Y9ERzWNelYYc6apaOTr atEOmcBOpqW+/OScSjc5iybmm1BGHvkq4iXvGB8qw0nneL/clm7HL/6F1PR6rFj+8aiq KxjQ7f2ZxhCmsADCe9STCZ72EvFGvmy/SC1D0BmeKgfsuLYNl0bXA2Cp/axXAqNe8eJu q87vfJ4Ru3oEvPfbrNvv5zMsF4ibZPKAJsWLjajVBuHtsDiabmIDGxl4pfZYomyAx/Ju lYew== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=PneGamL/mgm+LpVlf2vTq3MuyA+fcdySlbCCimj/eTM=; b=UJhkYSZEoovgbvnK0bQKcrhXJQj6Xh5yyARArdLUUbzP05dQf9mQVziTJVlKo32bMS SU3fdKRox2aCBCQvz2ri03Hsj8rmm8tzML5xlI5an/kJerdf/IyCvPxmxiyflZXiCXzT OcjEY9R5Vp5vAKHDkkGiMEkvxWJNlcb2V4UxehmEGuX6QtQnDJI6e9ZuZV0HsNcKLOHM 9tOPnrncP08P+ZLD9dNeC+kF051QWGI+ESgpGWDeHGZEA2gCIFOaSNZP2934UHmP1oRp HfkaecraF0yIWUyStGOFeqw9oSPQPWl1hGMptvuHkbF76s4EDpxovCAaF40pRYQ814zt 3lXg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=W4BgfyEW; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id v6-20020a17090606c600b009332b99a1d0si39981ejb.857.2023.04.05.17.13.28; Wed, 05 Apr 2023 17:13:53 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=W4BgfyEW; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233294AbjDFAJX (ORCPT + 99 others); Wed, 5 Apr 2023 20:09:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56418 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234280AbjDFAI4 (ORCPT ); Wed, 5 Apr 2023 20:08:56 -0400 Received: from mail-pl1-x632.google.com (mail-pl1-x632.google.com [IPv6:2607:f8b0:4864:20::632]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BFF731FEF for ; Wed, 5 Apr 2023 17:08:55 -0700 (PDT) Received: by mail-pl1-x632.google.com with SMTP id u10so35962351plz.7 for ; Wed, 05 Apr 2023 17:08:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1680739735; 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=PneGamL/mgm+LpVlf2vTq3MuyA+fcdySlbCCimj/eTM=; b=W4BgfyEWUsaBx+vivd2BLpkQi/WGqzeS+VVula1M+B91wAnaQaALuUOaa8hKiLd4nB LqiTn5zkTIB85QCcdYl/L/UwYX4Q39T5EvRlreapcfypsJR4buVcXpOQmpe9pyXP4ZTc K2VwuYVzEvRLWOcfVDr1/xS4PoWZgLKDLOg/s= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680739735; 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=PneGamL/mgm+LpVlf2vTq3MuyA+fcdySlbCCimj/eTM=; b=fkqM6VGHeYGaKZ1kLo7UQ/SQnuqtJmHqlAuuwt1fJRLHeDXG/xLK4KwBu+NtZrk7IX Tnm4926UFnVbyw9Hb+d9OJkFIrBwH7z9GZmxXU3NxUAkZw9KzcO5c478U3lUSKFuyJ05 7spJps1KMxMjo3ANvQIJ5GLAEkfJ32GudfCQFr3B2p9sKCDrWh89GCCrrkZUcKhhgPvA wXzDPDK0ffbfSYd5PqAmppW423bAxqt6m/ofnwVFbPJ1G33MGh0PvamdA/4sia08uQQB 9sP38u0wKheAtCJKOviUBBUdoO+wV/0x4xqSIlq/AWpKeXH4ssGhqJukoFXpPS3K3mji MX+g== X-Gm-Message-State: AAQBX9fdN9ddMsJkZgFSqWyL5Vpd3d3mbjnsnvy0F/GlQ4z6dbk9TM4G QFPPv/w5tFl9lc6MGtxEL48azg== X-Received: by 2002:a17:90b:4d05:b0:240:9e3d:d532 with SMTP id mw5-20020a17090b4d0500b002409e3dd532mr9052093pjb.8.1680739735192; Wed, 05 Apr 2023 17:08:55 -0700 (PDT) Received: from www.outflux.net (198-0-35-241-static.hfc.comcastbusiness.net. [198.0.35.241]) by smtp.gmail.com with ESMTPSA id kf7-20020a17090305c700b001a06b33923bsm93820plb.164.2023.04.05.17.08.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Apr 2023 17:08:54 -0700 (PDT) From: Kees Cook To: linux-hardening@vger.kernel.org Cc: Kees Cook , Kees Cook , Andy Shevchenko , Cezary Rojewski , Puyou Lu , Mark Brown , Josh Poimboeuf , Peter Zijlstra , Brendan Higgins , David Gow , Andrew Morton , Nathan Chancellor , Alexander Potapenko , Zhaoyang Huang , Randy Dunlap , Geert Uytterhoeven , Miguel Ojeda , Nick Desaulniers , Liam Howlett , Vlastimil Babka , Dan Williams , Rasmus Villemoes , Yury Norov , "Jason A. Donenfeld" , Sander Vanheule , Eric Biggers , "Masami Hiramatsu (Google)" , Andrey Konovalov , Linus Walleij , Daniel Latypov , =?utf-8?b?Sm9zw6kgRXhww7NzaXRv?= , linux-kernel@vger.kernel.org, kunit-dev@googlegroups.com Subject: [PATCH 2/9] fortify: Allow KUnit test to build without FORTIFY Date: Wed, 5 Apr 2023 17:02:01 -0700 Message-Id: <20230406000212.3442647-2-keescook@chromium.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230405235832.never.487-kees@kernel.org> References: <20230405235832.never.487-kees@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=2019; i=keescook@chromium.org; h=from:subject; bh=SpdgFxHiZ4ARZf+4i1NeU7Y8FK+0OW7wyr+j9YHonQM=; b=owEBbQKS/ZANAwAKAYly9N/cbcAmAcsmYgBkLgv/+oSAYnNTJZYXyeczo+2pwrJiX+S998cIveOx dv7sKJaJAjMEAAEKAB0WIQSlw/aPIp3WD3I+bhOJcvTf3G3AJgUCZC4L/wAKCRCJcvTf3G3AJnxJEA CNJYzScMB7ymRkvO6c4S//HNJjuM0W5yyy0EvjjCUlx+L8sCNKXmdALc985icEfYzfD5K8vw1PRXX7 C8uiv3CUHvw2fVT6NTmm6CdrXNuNUcMHjoSEOkEAJFarAGJESKN4ypcJPmvyTozFIvWoKkftYd1KhH dobf/C5zPIXz88aI44knQFGTZE/z5uyP4dGtvp9Sf64lU4+MnfWbZkPE4MWUVuk7lnPpE5MEKQ1Yqe yI8e7XFRVNCDXgoY0ltDMizSrwjG5DyBONZA1/OrBczdieYgJ3/MycxAVBWNbG3QQpCW8iY0ALx1mo 8j2wQ6/IT7Xxyurhz/hcpPX9OqCnTz9gkf0lCX60Uju7iPFRC9G3wYJ2MTHVAbn4E0Vv3cWkZhmmpe AQPx6KAMIj09/u6UyAf2o6FP3j6K0vqCq1ZfSc5c2yNuoihFq8XOmeKkBZLFJ8tOnY7tdZcArLbrMA chRKxelhk3wW8wtvC22yNIlNpH8Y35VXuQeJea8Jarrr1kYRPPQENEMwzPEKb442KET5sIxAZtZQRw TUblyPfA+RF3czGsvA2osA4DnJqsXoSYOR3oZ44qJMvjsglAdBFVBkoK/znA2MOL4ocWT8N8/qcluK iWvxlRaHFVkdmNeGPO3FL7lUDKnxNB+LigII/C6c9r1SNNqxfRqz1GjaX08A== X-Developer-Key: i=keescook@chromium.org; a=openpgp; fpr=A5C3F68F229DD60F723E6E138972F4DFDC6DC026 X-Spam-Status: No, score=-0.2 required=5.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1762383661064705141?= X-GMAIL-MSGID: =?utf-8?q?1762383661064705141?= From: Kees Cook In order for CI systems to notice all the skipped tests related to CONFIG_FORTIFY_SOURCE, allow the FORTIFY_SOURCE KUnit tests to build with or without CONFIG_FORTIFY_SOURCE. Signed-off-by: Kees Cook --- lib/Kconfig.debug | 2 +- lib/fortify_kunit.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index c8b379e2e9ad..d48a5f4b471e 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2614,7 +2614,7 @@ config STACKINIT_KUNIT_TEST config FORTIFY_KUNIT_TEST tristate "Test fortified str*() and mem*() function internals at runtime" if !KUNIT_ALL_TESTS - depends on KUNIT && FORTIFY_SOURCE + depends on KUNIT default KUNIT_ALL_TESTS help Builds unit tests for checking internals of FORTIFY_SOURCE as used diff --git a/lib/fortify_kunit.c b/lib/fortify_kunit.c index c8c33cbaae9e..d054fc20a7d5 100644 --- a/lib/fortify_kunit.c +++ b/lib/fortify_kunit.c @@ -25,8 +25,21 @@ static const char array_of_10[] = "this is 10"; static const char *ptr_of_11 = "this is 11!"; static char array_unknown[] = "compiler thinks I might change"; +/* Handle being built without CONFIG_FORTIFY_SOURCE */ +#ifndef __compiletime_strlen +# define __compiletime_strlen __builtin_strlen +#endif + +#define skip_without_fortify() \ +do { \ + if (!IS_ENABLED(CONFIG_FORTIFY_SOURCE)) \ + kunit_skip(test, "Not built with CONFIG_FORTIFY_SOURCE=y"); \ +} while (0) + static void known_sizes_test(struct kunit *test) { + skip_without_fortify(); + KUNIT_EXPECT_EQ(test, __compiletime_strlen("88888888"), 8); KUNIT_EXPECT_EQ(test, __compiletime_strlen(array_of_10), 10); KUNIT_EXPECT_EQ(test, __compiletime_strlen(ptr_of_11), 11); @@ -60,6 +73,8 @@ static noinline size_t want_minus_one(int pick) static void control_flow_split_test(struct kunit *test) { + skip_without_fortify(); + KUNIT_EXPECT_EQ(test, want_minus_one(pick), SIZE_MAX); } From patchwork Thu Apr 6 00:02:02 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 79992 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp671164vqo; Wed, 5 Apr 2023 17:14:26 -0700 (PDT) X-Google-Smtp-Source: AKy350Y4hwa7fRMWeC5UOeCE9mlkCsJixfLDoi9fl7zbzX2l4tBW8l3ffwWYOVAPrTf9V1dMs7MR X-Received: by 2002:a17:907:9908:b0:946:f71c:3b11 with SMTP id ka8-20020a170907990800b00946f71c3b11mr4329205ejc.76.1680740066264; Wed, 05 Apr 2023 17:14:26 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1680740066; cv=none; d=google.com; s=arc-20160816; b=OuUNOYkP80mRWgagl4qcJNu6oxaFLoXMQpgKandJ1+Nib6jW4JsEopt2DfDkPD8Bzl uSdZ9MfgJnUkaBSOX3k7AixwN8lAwn8MiYHls8ucgepr+at4BE/ND7AVQ0dvtobdJOeF +6AjDbHY1q8LVQhSV9m1jP8AejcVL/oIuwSInMId189OH+gCSFdal8R9TZNj67SHNrYt NEuT2pdaVWufF2nppiP1+9yqgFZW1S1nNa2Gden/pQ4y6n25o76As+c117ZZRg4IZZGi /WF1q//RS4VPq3Vb9InXOExNN4lxnFaXFoEQw6dJo6h1FLlTW1CXFlmSzqtSXqR1WYA8 rJQg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=ihHu/77nnwOlD0yIDOkgSICbQg4UYxIlXHTf7scrixI=; b=haaupj9AjKrxBXBUvS7/zy9NSZR41fvZQAXR6ZdDNOiw+UN3o6JBYbM/XfGd43RYEb 77ChSNYuxGqE5Y47Z4O/R8MU+SmROpc5FKFbTMpoDT7/P7BJCtbpAYMYTbGuQl0nsB6T nTlp/ySMsDingzKrRZEDJ2ekP/oJ+hX6OrEdK6PMp6OHSeOnZxgcX0kvaLjYvfKm2C03 I/vxeV+VR7aZioyIf8GdC/pNXOJrlg2CgBR0unoa/gJDSZ6rIxjsxGtTKAgd6joolfoJ PFaGiMmbByY/fNAmKWy5UUhB45VXS2u80EpZQfRr8juVTxlCd+cWToyApyuInHknyLIH RLvg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=C+wnnFr1; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id rv10-20020a1709068d0a00b008cdf4a9c9a1si48783ejc.622.2023.04.05.17.14.02; Wed, 05 Apr 2023 17:14:26 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=C+wnnFr1; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233828AbjDFAC1 (ORCPT + 99 others); Wed, 5 Apr 2023 20:02:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47808 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231950AbjDFACT (ORCPT ); Wed, 5 Apr 2023 20:02:19 -0400 Received: from mail-pf1-x436.google.com (mail-pf1-x436.google.com [IPv6:2607:f8b0:4864:20::436]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E16C859E3 for ; Wed, 5 Apr 2023 17:02:17 -0700 (PDT) Received: by mail-pf1-x436.google.com with SMTP id fb38so24781371pfb.7 for ; Wed, 05 Apr 2023 17:02:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1680739337; 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=ihHu/77nnwOlD0yIDOkgSICbQg4UYxIlXHTf7scrixI=; b=C+wnnFr1hwIr9HKbn6ntv8TFTvMwzfAwoDQnZM0sBfu9WX+uzyklLEx4XcRwUridjf /g3NAUcd1BBTIaKOaILN+Hr5Ysj2wpFac9yWZZ1XUWEjJBeUCaAmm/SvaJb7Qzd3DWI+ Fc9fqIxEG0Gjo9RQFjgPkvsQe4gYKXJmbZ2kk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680739337; 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=ihHu/77nnwOlD0yIDOkgSICbQg4UYxIlXHTf7scrixI=; b=HIdZv4bIXI4+YPIYoaAmKfIChvx0/NoHb6+40+hIbji+LBKCl5TwkVHmVmDim19cLd hAbelIKTYQIuc5A7DZI/5rLDibpP6oPAaTBZ90EFflkY/qoZ3JoADd/zGOnQATIqiuxB bUcX1/kaOo0sEcnUrtT0LVr99EmB6urWC0G79EWTTLdigQAatPOVdh4xd2af3JOswyQ9 8qfcyKC1c3LHK7LarBlZco055/eq94QP0KK7jU56aWJ27GVUReLl3hUCPQMfevFhsZzi P/zZiQJusLnvwKabVNq/Pncag+Qc+6kEAvF+gBoJH8yWoMrinNTES5Bo1PTyT4sM5fiX LtrA== X-Gm-Message-State: AAQBX9dw/ipayXsgxtnxm07FGRHPmF46ZEDbsmTjKdfT3Y5vWWd25Z8G 2dIa+KMJc+zPRzheZsvkJ/p0dA== X-Received: by 2002:aa7:9423:0:b0:627:8e40:68d8 with SMTP id y3-20020aa79423000000b006278e4068d8mr7319771pfo.18.1680739337281; Wed, 05 Apr 2023 17:02:17 -0700 (PDT) Received: from www.outflux.net (198-0-35-241-static.hfc.comcastbusiness.net. [198.0.35.241]) by smtp.gmail.com with ESMTPSA id n9-20020aa79049000000b00625e885a6ffsm11635623pfo.18.2023.04.05.17.02.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Apr 2023 17:02:13 -0700 (PDT) From: Kees Cook To: linux-hardening@vger.kernel.org Cc: Kees Cook , Kees Cook , Andy Shevchenko , Cezary Rojewski , Puyou Lu , Mark Brown , Josh Poimboeuf , Peter Zijlstra , Brendan Higgins , David Gow , Andrew Morton , Nathan Chancellor , Alexander Potapenko , Zhaoyang Huang , Randy Dunlap , Geert Uytterhoeven , Miguel Ojeda , Nick Desaulniers , Liam Howlett , Vlastimil Babka , Dan Williams , Rasmus Villemoes , Yury Norov , "Jason A. Donenfeld" , Sander Vanheule , Eric Biggers , "Masami Hiramatsu (Google)" , Andrey Konovalov , Linus Walleij , Daniel Latypov , =?utf-8?b?Sm9zw6kgRXhww7NzaXRv?= , linux-kernel@vger.kernel.org, kunit-dev@googlegroups.com Subject: [PATCH 3/9] string: Add Kunit tests for strcat() family Date: Wed, 5 Apr 2023 17:02:02 -0700 Message-Id: <20230406000212.3442647-3-keescook@chromium.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230405235832.never.487-kees@kernel.org> References: <20230405235832.never.487-kees@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=5480; i=keescook@chromium.org; h=from:subject; bh=TwKlXl0mlDA9aUwwDPbJaiGBGoVKgl4jR+SCssFeKos=; b=owEBbQKS/ZANAwAKAYly9N/cbcAmAcsmYgBkLgv/w9lYG8TKO2pLdSGWjeJdz4gWEQKB8J8NlI2U lCXR/oeJAjMEAAEKAB0WIQSlw/aPIp3WD3I+bhOJcvTf3G3AJgUCZC4L/wAKCRCJcvTf3G3AJkrPD/ 4tWkIiWa0xJaDvh14pSs0DPg5BaVbTIgpacy939WxRJYFB5IqVFbROCHrjrYPvw3RbO6Ur7PXfzA83 oVE0L4cdpb8ja3B7YicriDJnvI9DGSOytYgPGFOLXEzhgtgMywfa1RGUMu8xzJuX5GDyXoWD/0iNva MwIa+kUhPmik2QkyZBjjeBkryhnkaWcvn6so+24JKCPwvrnNEUpCGHFqG1QkM8KYF/WLBipLNCKopu RVYonEVOmVAjppym0p8STjAGhyJwrdOX6gizbCAoxgx74o1s3YQudGTloGoNOUvkrBtxOj66rFnFvj K4SWyZcQNeK7+W6hU2WHGeLiYMCVuqgyaeY+TKWfskT0fFbzjpAEp/VKsXFU0+8kwY4w09fYIreqhK Hpd24C9DQEbuc53RJ3gjcKjCHTrDgfIBn3lh8truyL/r68oF9npR5sgw8gsj2qM9GsM4T4iOCjmh/a AGKFFNNxtgNEbVQgiYdiFcDOMzI3rAHSyn7Bks/TVznBw75Jmlni9DddObi51AR39rGooGMB47Hh0c HWt6CsKuw3zBZIdfS/QrNvsx1Kufr+Xlt4edUaxBXh4kJGif10BfKXIqQjnUrJrpI9lYfw701wB7lo WI58U+HyG+iORfD+4byCR0LnU1t7yxCe6NnjLehv6DvuMISjiqxfBJQwj2oQ== X-Developer-Key: i=keescook@chromium.org; a=openpgp; fpr=A5C3F68F229DD60F723E6E138972F4DFDC6DC026 X-Spam-Status: No, score=-0.2 required=5.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1762383695414695535?= X-GMAIL-MSGID: =?utf-8?q?1762383695414695535?= From: Kees Cook Add tests to make sure the strcat() family of functions behave correctly. Signed-off-by: Kees Cook --- MAINTAINERS | 1 + lib/Kconfig.debug | 5 +++ lib/Makefile | 1 + lib/strcat_kunit.c | 100 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 lib/strcat_kunit.c diff --git a/MAINTAINERS b/MAINTAINERS index ec57c42ed544..86c0012b5130 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8021,6 +8021,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/har F: include/linux/fortify-string.h F: lib/fortify_kunit.c F: lib/memcpy_kunit.c +F: lib/strcat_kunit.c F: lib/strscpy_kunit.c F: lib/test_fortify/* F: scripts/test_fortify.sh diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index d48a5f4b471e..86157aa5e979 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2631,6 +2631,11 @@ config HW_BREAKPOINT_KUNIT_TEST If unsure, say N. +config STRCAT_KUNIT_TEST + tristate "Test strcat() family of functions at runtime" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + config STRSCPY_KUNIT_TEST tristate "Test strscpy*() family of functions at runtime" if !KUNIT_ALL_TESTS depends on KUNIT diff --git a/lib/Makefile b/lib/Makefile index baf2821f7a00..6582d8fe1a77 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -389,6 +389,7 @@ obj-$(CONFIG_STACKINIT_KUNIT_TEST) += stackinit_kunit.o CFLAGS_fortify_kunit.o += $(call cc-disable-warning, unsequenced) CFLAGS_fortify_kunit.o += $(DISABLE_STRUCTLEAK_PLUGIN) obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o +obj-$(CONFIG_STRCAT_KUNIT_TEST) += strcat_kunit.o obj-$(CONFIG_STRSCPY_KUNIT_TEST) += strscpy_kunit.o obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o diff --git a/lib/strcat_kunit.c b/lib/strcat_kunit.c new file mode 100644 index 000000000000..b6428c3a557f --- /dev/null +++ b/lib/strcat_kunit.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Kernel module for testing 'strcat' family of functions. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include + +static void strcat_test(struct kunit *test) +{ + char dest[8]; + + /* Destination is terminated. */ + memset(dest, 0, sizeof(dest)); + KUNIT_EXPECT_EQ(test, strlen(dest), 0); + /* Empty copy does nothing. */ + KUNIT_EXPECT_TRUE(test, strcat(dest, "") == dest); + KUNIT_EXPECT_STREQ(test, dest, ""); + /* 4 characters copied in, stops at %NUL. */ + KUNIT_EXPECT_TRUE(test, strcat(dest, "four\000123") == dest); + KUNIT_EXPECT_STREQ(test, dest, "four"); + KUNIT_EXPECT_EQ(test, dest[5], '\0'); + /* 2 more characters copied in okay. */ + KUNIT_EXPECT_TRUE(test, strcat(dest, "AB") == dest); + KUNIT_EXPECT_STREQ(test, dest, "fourAB"); +} + +static void strncat_test(struct kunit *test) +{ + char dest[8]; + + /* Destination is terminated. */ + memset(dest, 0, sizeof(dest)); + KUNIT_EXPECT_EQ(test, strlen(dest), 0); + /* Empty copy of size 0 does nothing. */ + KUNIT_EXPECT_TRUE(test, strncat(dest, "", 0) == dest); + KUNIT_EXPECT_STREQ(test, dest, ""); + /* Empty copy of size 1 does nothing too. */ + KUNIT_EXPECT_TRUE(test, strncat(dest, "", 1) == dest); + KUNIT_EXPECT_STREQ(test, dest, ""); + /* Copy of max 0 characters should do nothing. */ + KUNIT_EXPECT_TRUE(test, strncat(dest, "asdf", 0) == dest); + KUNIT_EXPECT_STREQ(test, dest, ""); + + /* 4 characters copied in, even if max is 8. */ + KUNIT_EXPECT_TRUE(test, strncat(dest, "four\000123", 8) == dest); + KUNIT_EXPECT_STREQ(test, dest, "four"); + KUNIT_EXPECT_EQ(test, dest[5], '\0'); + /* 2 characters copied in okay, 2 ignored. */ + KUNIT_EXPECT_TRUE(test, strncat(dest, "ABCD", 2) == dest); + KUNIT_EXPECT_STREQ(test, dest, "fourAB"); +} + +static void strlcat_test(struct kunit *test) +{ + char dest[8] = ""; + + /* Destination is terminated. */ + KUNIT_EXPECT_EQ(test, strlen(dest), 0); + /* Empty copy is size 0. */ + KUNIT_EXPECT_EQ(test, strlcat(dest, "", sizeof(dest)), 0); + KUNIT_EXPECT_STREQ(test, dest, ""); + /* Size 1 should keep buffer terminated, report size of source only. */ + KUNIT_EXPECT_EQ(test, strlcat(dest, "four", 1), 4); + KUNIT_EXPECT_STREQ(test, dest, ""); + + /* 4 characters copied in. */ + KUNIT_EXPECT_EQ(test, strlcat(dest, "four", sizeof(dest)), 4); + KUNIT_EXPECT_STREQ(test, dest, "four"); + /* 2 characters copied in okay, gets to 6 total. */ + KUNIT_EXPECT_EQ(test, strlcat(dest, "AB", sizeof(dest)), 6); + KUNIT_EXPECT_STREQ(test, dest, "fourAB"); + /* 2 characters ignored if max size (7) reached. */ + KUNIT_EXPECT_EQ(test, strlcat(dest, "CD", 7), 8); + KUNIT_EXPECT_STREQ(test, dest, "fourAB"); + /* 1 of 2 characters skipped, now at true max size. */ + KUNIT_EXPECT_EQ(test, strlcat(dest, "EFG", sizeof(dest)), 9); + KUNIT_EXPECT_STREQ(test, dest, "fourABE"); + /* Everything else ignored, now at full size. */ + KUNIT_EXPECT_EQ(test, strlcat(dest, "1234", sizeof(dest)), 11); + KUNIT_EXPECT_STREQ(test, dest, "fourABE"); +} + +static struct kunit_case strcat_test_cases[] = { + KUNIT_CASE(strcat_test), + KUNIT_CASE(strncat_test), + KUNIT_CASE(strlcat_test), + {} +}; + +static struct kunit_suite strcat_test_suite = { + .name = "strcat", + .test_cases = strcat_test_cases, +}; + +kunit_test_suite(strcat_test_suite); + +MODULE_LICENSE("GPL"); From patchwork Thu Apr 6 00:02:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 79983 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp665846vqo; Wed, 5 Apr 2023 17:03:21 -0700 (PDT) X-Google-Smtp-Source: AKy350bBq88r+/Napb4dQOM3nfQCXLYHDJHRD3Hwyoq6XL8Wcn2vkt6yTzy6FdHV5ZQys1zQCAYO X-Received: by 2002:a17:903:905:b0:19e:bc8e:6421 with SMTP id ll5-20020a170903090500b0019ebc8e6421mr6319354plb.47.1680739401127; Wed, 05 Apr 2023 17:03:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1680739401; cv=none; d=google.com; s=arc-20160816; b=pYfrBhczDZF0IdJkyg2P/m5d7xJPdAbuYOhd6+iSlj/gCIo9u4UyzoDFDx0xMavfNK DDN9YIT2ZhkyoDBPcBFAYUIham21MbjAGfKkTmdHwJGRwFrqlcnfyR5v3WsVO6gJjnbD y8snrYDvGqdXovu0f0h1rXdijPNt3h3jTbgUXbSKOtDXZ7/7QdGOkKaTsutbDqiUaZlB J+Z1bmUgPViyfIrzvKhUuRsVKt/IEJQLwOocInRL6xeCFKzN11oQMlaeJejOBbp8SVlD UkA93LzgHtnVIhHvrwllOH6LxVK4wO7cuJnxYRHbjWfwFP7eGIHvyRR3QIHmMj82AKeF 6Zfw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=ICBa1DtI6i1NF0+JonXqQyqUlpz7dmxfeFViA4mHGno=; b=AB7Xsg3mrOiS5xc/lK4JBdfb5luEf1Ni9pPqGu/zEue1HcQ+BGbMW+B4SpMrlQc2q4 wDUPtLMO9gle8Cy92ewRocrJ4Bi7Q/hUwov6KCwSjGeBMUjy8dV0s0XlbIKLiLh3h694 qNhX88rmWLek1WkhG0RnBuwWbgj8aLQfwUeCbFtrc7059a1VAG/I7zRMA5Te8DJeHgao bcaHkeTs6fZdf1N/NAWzsUNsAWBE/QvdAM1dC/tQ6msojHl7QwAo3rpHtugs66V6XwMP sNJ9awKbeH65m72s9fTphu/Pdh1KwmxbQyPVMhKjZlD+FHwuRIMqvto+ItW37156oaTP MXQQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=YwjTtcaH; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id kv5-20020a17090328c500b0019468fe44d5si235830plb.233.2023.04.05.17.02.51; Wed, 05 Apr 2023 17:03:21 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=YwjTtcaH; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232642AbjDFACU (ORCPT + 99 others); Wed, 5 Apr 2023 20:02:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47708 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229481AbjDFACR (ORCPT ); Wed, 5 Apr 2023 20:02:17 -0400 Received: from mail-pj1-x1033.google.com (mail-pj1-x1033.google.com [IPv6:2607:f8b0:4864:20::1033]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 90BB859E2 for ; Wed, 5 Apr 2023 17:02:16 -0700 (PDT) Received: by mail-pj1-x1033.google.com with SMTP id qe8-20020a17090b4f8800b0023f07253a2cso38923725pjb.3 for ; Wed, 05 Apr 2023 17:02:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1680739336; 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=ICBa1DtI6i1NF0+JonXqQyqUlpz7dmxfeFViA4mHGno=; b=YwjTtcaHeXgmNQCy+UZfNoSOdXZjRkV1nS2FVwslb/8WY3CT6punFfDFo1A6SEXcEN qgBvZR+YGmwakCTv/2s10NaRAHXxmobJgDox8sh2B8NnrDVlMF7kykKRvSfJHrnDfnaU CrwurUlZu5Q5vMrJKVxFEIoCEymN3rFYQ3lAE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680739336; 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=ICBa1DtI6i1NF0+JonXqQyqUlpz7dmxfeFViA4mHGno=; b=v4KygxbMR6Pznyh4hjTHwMEAimt/ulJGQc5/ePA3DhLttvT5lfboWu3nMoDvHqH5/z pBEm+JQXfKooeQJ/OQJJErD+i19oSmNY4D+/46OFyzD4mryUss0nvmdhWZQG44TD9mkj peaQcLbfkzszqDRFU/smtKAYbKE/kzGNSnJDpHSu4ONrmSog+wCgXl4903tlRjoUS8vY InhD4J15cwNDhdOAj8Plp4QjocZUE2pCZMWFGz7bq5esRU6TxV00H5FwF0LzlLzDh3PR AhdHl0thGisK/3ArecvsCKgxb5Et2nDjlYfPF5ci7MrwX694CggtNG6ZLveGnMeSZ2Hj iYfw== X-Gm-Message-State: AAQBX9fB5bsTKYaKFU1Gwf8C7PIFw6cQFKYhRGPRd+W/wT8IaXYYi2YL qItx0rZrV81ybnmtayUUvKvAfg== X-Received: by 2002:a05:6a20:835d:b0:d6:c9e2:1795 with SMTP id z29-20020a056a20835d00b000d6c9e21795mr788533pzc.27.1680739335996; Wed, 05 Apr 2023 17:02:15 -0700 (PDT) Received: from www.outflux.net (198-0-35-241-static.hfc.comcastbusiness.net. [198.0.35.241]) by smtp.gmail.com with ESMTPSA id e5-20020a62ee05000000b005e099d7c30bsm11029461pfi.205.2023.04.05.17.02.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Apr 2023 17:02:13 -0700 (PDT) From: Kees Cook To: linux-hardening@vger.kernel.org Cc: Kees Cook , Kees Cook , Andy Shevchenko , Cezary Rojewski , Puyou Lu , Mark Brown , Josh Poimboeuf , Peter Zijlstra , Brendan Higgins , David Gow , Andrew Morton , Nathan Chancellor , Alexander Potapenko , Zhaoyang Huang , Randy Dunlap , Geert Uytterhoeven , Miguel Ojeda , Nick Desaulniers , Liam Howlett , Vlastimil Babka , Dan Williams , Rasmus Villemoes , Yury Norov , "Jason A. Donenfeld" , Sander Vanheule , Eric Biggers , "Masami Hiramatsu (Google)" , Andrey Konovalov , Linus Walleij , Daniel Latypov , =?utf-8?b?Sm9zw6kgRXhww7NzaXRv?= , linux-kernel@vger.kernel.org, kunit-dev@googlegroups.com Subject: [PATCH 4/9] fortify: Add protection for strlcat() Date: Wed, 5 Apr 2023 17:02:03 -0700 Message-Id: <20230406000212.3442647-4-keescook@chromium.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230405235832.never.487-kees@kernel.org> References: <20230405235832.never.487-kees@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=3250; i=keescook@chromium.org; h=from:subject; bh=rj52x4JBej+qEjIHIHz74SGX8jVWOZs51u/oWt76v9o=; b=owEBbQKS/ZANAwAKAYly9N/cbcAmAcsmYgBkLgv//oEVXTENJ5N/QlhC1PcMOKe+fLOu/OWZjhUq cGEUJoqJAjMEAAEKAB0WIQSlw/aPIp3WD3I+bhOJcvTf3G3AJgUCZC4L/wAKCRCJcvTf3G3AJtbXD/ 0cKX83TNsTe99BigymaFdb/hrWnqygWzdMcLVPDMj6bXddgFVN05PUZvBqP0Jwk0Mq8PN+cVw1xnQK hhPe185jF6FVowhCd83A8Awzl37jFuXW3oIZnifmwtWfbrkV2NSpxlbyqqO1vdo0ZYVaCYCfiiyUql MMJn5QehjOT1vS6A+jJOPBaN9hyxiXjyUYtFvcwjbLXvSyU6plrXedx7Yw4T6Mc0rlBvcr19NfjVtx SBDX5WCJVrmYXhUQKAexomoOvuTHz7TW7gOBFNdtiVvHKOsM2QFnrcQ44xww1H1yZIeF21pWNK0Ure I2WsKEN9IDFqFN5sXbkRlKB5xgU3P3cO5wUw836+tvzaYwdYgrXCuMDD90mJ3kmNhj0NCdd8ugRoR9 xwidD22KGNV1BJA9dXt3yvPXn/p/zb5rgA2ltA+c+A2G17GmupmfOiRu+b/8PmYwyclrcAMVdMu7hr l5OyX3aP9Wy7l8plUlzY9SACEyxMyGShBhxL2VPBQRdQ3aOUdJ4Lx87cgMNGiP8UUNdUwd1PPuqGDF fVOmKgvKW7q4/GZZAwzD1UJJ9ByTmUdCbacrmlat93+NwU6D3/vpuhW5PYQVF6ZshQ7LFJvVU76sth fyZ5LHa4lq99coCOec13GLmFrtPJnP8d6IguezioiOVkUvn42/KNyEaccZiw== X-Developer-Key: i=keescook@chromium.org; a=openpgp; fpr=A5C3F68F229DD60F723E6E138972F4DFDC6DC026 X-Spam-Status: No, score=-0.2 required=5.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1762382998088038810?= X-GMAIL-MSGID: =?utf-8?q?1762382998088038810?= From: Kees Cook The definition of strcat() was was defined in terms of unfortified strlcat(), but that meant there was no bounds checking done on the internal strlen() calls, and the (bounded) copy would be performed before reporting a failure. Additionally, pathological cases (i.e. unterminated destination buffer) did not make calls to fortify_panic(), which will make future unit testing more difficult. Instead, explicitly define a fortified strlcat() wrapper for strcat() to use. Signed-off-by: Kees Cook --- include/linux/fortify-string.h | 64 ++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h index c9de1f59ee80..875689aa83c3 100644 --- a/include/linux/fortify-string.h +++ b/include/linux/fortify-string.h @@ -371,6 +371,70 @@ __FORTIFY_INLINE ssize_t strscpy(char * const POS p, const char * const POS q, s return __real_strscpy(p, q, len); } +/* Defined after fortified strlen() to reuse it. */ +extern size_t __real_strlcat(char *p, const char *q, size_t avail) __RENAME(strlcat); +/** + * strlcat - Append a string to an existing string + * + * @p: pointer to %NUL-terminated string to append to + * @q: pointer to %NUL-terminated string to append from + * @avail: Maximum bytes available in @p + * + * Appends %NUL-terminated string @q after the %NUL-terminated + * string at @p, but will not write beyond @avail bytes total, + * potentially truncating the copy from @q. @p will stay + * %NUL-terminated only if a %NUL already existed within + * the @avail bytes of @p. If so, the resulting number of + * bytes copied from @q will be at most "@avail - strlen(@p) - 1". + * + * Do not use this function. While FORTIFY_SOURCE tries to avoid + * read and write overflows, this is only possible when the sizes + * of @p and @q are known to the compiler. Prefer building the + * string with formatting, via scnprintf(), seq_buf, or similar. + * + * Returns total bytes that _would_ have been contained by @p + * regardless of truncation, similar to snprintf(). If return + * value is >= @avail, the string has been truncated. + * + */ +__FORTIFY_INLINE +size_t strlcat(char * const POS p, const char * const POS q, size_t avail) +{ + size_t p_len, copy_len; + size_t p_size = __member_size(p); + size_t q_size = __member_size(q); + size_t actual, wanted; + + /* Give up immediately if both buffer sizes are unknown. */ + if (p_size == SIZE_MAX && q_size == SIZE_MAX) + return __real_strlcat(p, q, avail); + + p_len = strnlen(p, avail); + copy_len = strlen(q); + wanted = actual = p_len + copy_len; + + /* Cannot append any more: report truncation. */ + if (avail <= p_len) + return wanted; + + /* Give up if string is already overflowed. */ + if (p_size <= p_len) + fortify_panic(__func__); + + if (actual >= avail) { + copy_len = avail - p_len - 1; + actual = p_len + copy_len; + } + + /* Give up if copy will overflow. */ + if (p_size <= actual) + fortify_panic(__func__); + __underlying_memcpy(p + p_len, q, copy_len); + p[actual] = '\0'; + + return wanted; +} + /** * strncat - Append a string to an existing string * From patchwork Thu Apr 6 00:02:04 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 79984 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp666082vqo; Wed, 5 Apr 2023 17:03:45 -0700 (PDT) X-Google-Smtp-Source: AKy350bVo+DeJpXE95SZXTA1H1/yLL7ujGJO2ORHs0pl2AhjOH5Yn8ytXs14VeQaTZo0c+SdqLU0 X-Received: by 2002:a17:902:da81:b0:1a2:8c7e:f301 with SMTP id j1-20020a170902da8100b001a28c7ef301mr9896612plx.45.1680739425220; Wed, 05 Apr 2023 17:03:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1680739425; cv=none; d=google.com; s=arc-20160816; b=viQyP1lxD6C4Ju4E3EMfP1jJwiG0M3Q40ad3WPByBW5S+SlNkWVzT3+uhr/feuPknB cO4CRL2WvlotOOzrPCy9G401AahS8LBulyhrkdjqZIxoC5thN99oaFW+Xt2BrcW1EN3W +sMe91OWOLg/0gsyTjdETyZfWLOpK0PDr1RQjC2QarH1Rq+s1D09FVxrysenmHdUodjh Nj6Sngs6NnsPxxbVUmrzYal6OtNIzGPLn0ZPGDuF6YBVZ47QRbA7oO9Kw/mdE6zT2j0u A4picZt62KOegYglK4ZXEBhWUnbsPf1tZyHzwPnK2K3KABtyDYp5i6fllU0CO45tylxy jFjw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=ExS1X1Asjk++jX2/Mr+aGsXWXjGWAeASIa6ARPjpF0s=; b=I/c3gbTiRV9ZTe3gPz36Qh9WtdO4hLAAdPTqfgKn26+cO9N2CqBJswj1FoM8QzUcy7 gmAqb9Am1n1dphlpwYuvqcm7bSm4i095HlQFrlxyLpxFQ2RDObWSQyEO2/oJkJDoEy9I Z831dnNiNuBe4QC40DEoELGkzuK9Bw6xXBlhJmHlX8TaUJrCAc8O7nel2Tbntb47KqIT JGjYDArek1aMbEi+ZQHsY8tY6AASU1Eu1r1Z0DVOzrve2bjPioyYyxV/ujZKWNystsiK k3u1rdljFU8L9tFaZl6h98WprEQ17Yzflr5qM2MBVYmbFmRxa4BFfgdBksKoCmKbhehc DISA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=KEWpEbnI; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id e9-20020a170902e0c900b0019ce0f430bbsi190390pla.476.2023.04.05.17.03.11; Wed, 05 Apr 2023 17:03:45 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=KEWpEbnI; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234058AbjDFACa (ORCPT + 99 others); Wed, 5 Apr 2023 20:02:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47810 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231889AbjDFACT (ORCPT ); Wed, 5 Apr 2023 20:02:19 -0400 Received: from mail-pl1-x634.google.com (mail-pl1-x634.google.com [IPv6:2607:f8b0:4864:20::634]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6023261AE for ; Wed, 5 Apr 2023 17:02:18 -0700 (PDT) Received: by mail-pl1-x634.google.com with SMTP id c18so35934991ple.11 for ; Wed, 05 Apr 2023 17:02:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1680739338; 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=ExS1X1Asjk++jX2/Mr+aGsXWXjGWAeASIa6ARPjpF0s=; b=KEWpEbnIM66/k6Fl8lCg8J+TrhHMvhMCQDYDaDVmogicejBB6916cUXGdx/RY09kcG hBmb95mrp2ZAvyKnwpzjCUiRTAl/+vYw5D3mc38QSjWeoBPBhN7v84E7UMtxWozTF2OJ sfIE6kWBGdOqf4Va5AZMZCWGF4srD5lcdldts= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680739338; 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=ExS1X1Asjk++jX2/Mr+aGsXWXjGWAeASIa6ARPjpF0s=; b=yqrdjQT3uV7sIdWFu/cmx3tcz/C7gKU2oUf1Mtm2bYl8uFcZAWcBgwBnx3kAL86gsA fDWP3bVNkGQDJ1ahZW+gASEgyLTNJBt/pEHRtjZh168cavOsZVUTv8RmJXg3EGsIgCrF 85jgy1q74K11POqYXSX+YX4CN7gIwgBOP0EokFgqYalOAhZ00jt5TkJzZxP8kXeQXypt tRoqrfgZpPWs3BWnl6dMoEytOikqraormFRW3c5iPjwFJLg0DF7Js+W8jDPao7D819a9 1XR5SJhtn8oEFbfLiV2HujAREuZMr+6wINXXU87z1V8I+ogu79lQqhaaBM0UCPU+MkV5 +Zbg== X-Gm-Message-State: AAQBX9d6pn8DVz8+eh3AyP8bldyPY0BhxgMiKvTjAiaYRvzQBBhd//Jo LWk/PrGBNE1FN2KT8oralEgblg== X-Received: by 2002:a17:902:c94e:b0:1a0:65d3:bae4 with SMTP id i14-20020a170902c94e00b001a065d3bae4mr9699691pla.38.1680739337837; Wed, 05 Apr 2023 17:02:17 -0700 (PDT) Received: from www.outflux.net (198-0-35-241-static.hfc.comcastbusiness.net. [198.0.35.241]) by smtp.gmail.com with ESMTPSA id p9-20020a170902b08900b0019e8915b1b5sm94611plr.105.2023.04.05.17.02.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Apr 2023 17:02:17 -0700 (PDT) From: Kees Cook To: linux-hardening@vger.kernel.org Cc: Kees Cook , Kees Cook , Andy Shevchenko , Cezary Rojewski , Puyou Lu , Mark Brown , Josh Poimboeuf , Peter Zijlstra , Brendan Higgins , David Gow , Andrew Morton , Nathan Chancellor , Alexander Potapenko , Zhaoyang Huang , Randy Dunlap , Geert Uytterhoeven , Miguel Ojeda , Nick Desaulniers , Liam Howlett , Vlastimil Babka , Dan Williams , Rasmus Villemoes , Yury Norov , "Jason A. Donenfeld" , Sander Vanheule , Eric Biggers , "Masami Hiramatsu (Google)" , Andrey Konovalov , Linus Walleij , Daniel Latypov , =?utf-8?b?Sm9zw6kgRXhww7NzaXRv?= , linux-kernel@vger.kernel.org, kunit-dev@googlegroups.com Subject: [PATCH 5/9] fortify: strcat: Move definition to use fortified strlcat() Date: Wed, 5 Apr 2023 17:02:04 -0700 Message-Id: <20230406000212.3442647-5-keescook@chromium.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230405235832.never.487-kees@kernel.org> References: <20230405235832.never.487-kees@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=2624; i=keescook@chromium.org; h=from:subject; bh=O4OjFtVJ1tD3TCO7wTWZXRQ046029J23gw/1XMQ1O9Q=; b=owEBbQKS/ZANAwAKAYly9N/cbcAmAcsmYgBkLgv/+JEBhkqs9VsEq7y+wgME8WyhveIf5l89VWz3 AvrwAtSJAjMEAAEKAB0WIQSlw/aPIp3WD3I+bhOJcvTf3G3AJgUCZC4L/wAKCRCJcvTf3G3AJniDD/ 0V5CRN6GGGJdY8FU0vXH9y7xdXiBbN5MFFeYHQoaCP7lqkYn1TRcvNrmtPkuQIGjZnGXbn+ldsUrvV jkxwJ8JpVpqfIC1ibhYHJ4o8YRe/uMFWzORpNOqmWTMoB/cei1+5afll5SMW1OjW1ch7EjDpYZXS1n WpLAB9D8ZQMcs6+gld3A3cB+CzR1IUQ6COJcvbOR8kV5iqWfXvsasBwPdwJiJHv/PYt6vaoKOrfOWg pfWcesAXe72Wmi2cV/+q0hCjv5+ayGB79Uc/VxtoaplGonA4rkJa9B7fywwIu5Ies8q3T5W4h3R2uX 5LdB8eqUuszkdjxxaVDGrNEUjqagVMNZnYpobfs+95DYhbu4gxBKfR+IZQW1KKogha4mJ8NJPDskUk Gr77XjOP8BCqdIodxcWGdaGaCYeIrcfTMu+c7j3xmoZLhxaVI29WqUkShAi46f20FIKxSLcHosBiuF T2tvZYSwpt/rC0gr135kL9xLZopQMxaSlKQUBXStie8QRRd2YsFNaxUxjUB3FMOqOY/dVqlRjnIdnh nHDMa2mwEohRoW7/IvyAeFHvR5GjE3R+PkfCSo0FnX2JGxTYmZqMCB5OWzdKgX7E1uzF80JFHJQNp+ 9DmWdlBGTPj0I+5Nwipfd7HfdVVNL5PTMVBo+TRgSWa+siRVBjLWKGBAQpIA== X-Developer-Key: i=keescook@chromium.org; a=openpgp; fpr=A5C3F68F229DD60F723E6E138972F4DFDC6DC026 X-Spam-Status: No, score=-0.2 required=5.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1762383023250858465?= X-GMAIL-MSGID: =?utf-8?q?1762383023250858465?= From: Kees Cook Move the definition of fortified strcat() to after strlcat() to use it for bounds checking. Signed-off-by: Kees Cook --- include/linux/fortify-string.h | 53 +++++++++++++++++----------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h index 875689aa83c3..41dbd641f55c 100644 --- a/include/linux/fortify-string.h +++ b/include/linux/fortify-string.h @@ -151,33 +151,6 @@ char *strncpy(char * const POS p, const char *q, __kernel_size_t size) return __underlying_strncpy(p, q, size); } -/** - * strcat - Append a string to an existing string - * - * @p: pointer to NUL-terminated string to append to - * @q: pointer to NUL-terminated source string to append from - * - * Do not use this function. While FORTIFY_SOURCE tries to avoid - * read and write overflows, this is only possible when the - * destination buffer size is known to the compiler. Prefer - * building the string with formatting, via scnprintf() or similar. - * At the very least, use strncat(). - * - * Returns @p. - * - */ -__FORTIFY_INLINE __diagnose_as(__builtin_strcat, 1, 2) -char *strcat(char * const POS p, const char *q) -{ - size_t p_size = __member_size(p); - - if (p_size == SIZE_MAX) - return __underlying_strcat(p, q); - if (strlcat(p, q, p_size) >= p_size) - fortify_panic(__func__); - return p; -} - extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen); /** * strnlen - Return bounded count of characters in a NUL-terminated string @@ -435,6 +408,32 @@ size_t strlcat(char * const POS p, const char * const POS q, size_t avail) return wanted; } +/* Defined after fortified strlcat() to reuse it. */ +/** + * strcat - Append a string to an existing string + * + * @p: pointer to NUL-terminated string to append to + * @q: pointer to NUL-terminated source string to append from + * + * Do not use this function. While FORTIFY_SOURCE tries to avoid + * read and write overflows, this is only possible when the + * destination buffer size is known to the compiler. Prefer + * building the string with formatting, via scnprintf() or similar. + * At the very least, use strncat(). + * + * Returns @p. + * + */ +__FORTIFY_INLINE __diagnose_as(__builtin_strcat, 1, 2) +char *strcat(char * const POS p, const char *q) +{ + size_t p_size = __member_size(p); + + if (strlcat(p, q, p_size) >= p_size) + fortify_panic(__func__); + return p; +} + /** * strncat - Append a string to an existing string * From patchwork Thu Apr 6 00:02:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 79985 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp666193vqo; Wed, 5 Apr 2023 17:03:55 -0700 (PDT) X-Google-Smtp-Source: AKy350bT2NfoxWE49FcOYuimQIr1tZmkHzMEAAO/WUXKnFqy5FNA2anHB3VAgOw31ah4t5M2U0a7 X-Received: by 2002:a05:6a20:8b1a:b0:e4:9940:d7c2 with SMTP id l26-20020a056a208b1a00b000e49940d7c2mr917491pzh.14.1680739434600; Wed, 05 Apr 2023 17:03:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1680739434; cv=none; d=google.com; s=arc-20160816; b=ozuslD8jfzzbxLOu9M/FKM1+OgX6H1pjG8+ncHiO8zBsyWm6abefE3GoUE9jWLYgh5 xb6rT4tAWFezGGSaGXOY5kmP863xzbkB1Cc3EfHp5iwV+hzwUJs/eN1K9k5QHpiZyT61 MhIxk/s6T1q7uQbM/u+fRG6vEXATEmuxdkpt1vM7whGB94yEYIVENYUU/ZapGgf2jO5k NFNBsZ50P/ExVw2gf6/LKE+Tlz7lMnj6t5G1egTHXkzGTWIcuRlCRF3pWwTG+rj7X0+u YM0XtSZHsvTbAQ9mrpRZO2u+hlfAvJsbe9rsuwiVV/xsk3fHo85XNoCRGQxE3VZwXy/W Dnwg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=GVeZITSFOSVosu4yNU0kSm2zQr6awWpiVL1awBqfF1Y=; b=Tjkcrawk+5fr3H4MF6bNwR1rvSzS6wVHVkX9NDHAD5KjJeDzbYihufGddEULtK7Al5 zNSNyJOv2+Ss2tfLcJ1FpWPZmOA1e1Q7scy1bk0XtWyILGPrZWQiGaCERBlq0itTEPN5 4K6wvnGGdbN5Aqf7zhIP4xxJvtGNVl+s3CzwUHXyf9oNZWtvKRURI9sh9EVWZe06bkSF N8Q3AMBUxcNCr/KZQ5e0sJmmDpcbRSC0v2XK5HizOZ3sCl1JTs6KqBYCH3hP3/cANiQu z+tIIT3nITHbLaCMbxhQ8D7hAZbmyPgppUcudJGtX7+ihYlmPDQ3iTlV58GtdEob8Poz Qvag== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b="B/TOjH/g"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id r11-20020a632b0b000000b0050f66d4e070si14462366pgr.417.2023.04.05.17.03.21; Wed, 05 Apr 2023 17:03:54 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b="B/TOjH/g"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233128AbjDFACh (ORCPT + 99 others); Wed, 5 Apr 2023 20:02:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47910 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229587AbjDFACV (ORCPT ); Wed, 5 Apr 2023 20:02:21 -0400 Received: from mail-pl1-x62b.google.com (mail-pl1-x62b.google.com [IPv6:2607:f8b0:4864:20::62b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 69F467684 for ; Wed, 5 Apr 2023 17:02:19 -0700 (PDT) Received: by mail-pl1-x62b.google.com with SMTP id kc4so35936855plb.10 for ; Wed, 05 Apr 2023 17:02:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1680739339; 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=GVeZITSFOSVosu4yNU0kSm2zQr6awWpiVL1awBqfF1Y=; b=B/TOjH/gJOJvYf37Vu/+Cs/gN7vffw64dSKGAky15XutUioGX5f8rLUB9TzZ4m3Ufj XexxluTFeBPrRAqfB7h5gMNZIl95Kgy77dUpp5Yk913Cx8biwmbNpK95u1Xufd4OlsLU +cxukVTpxvXiAZJx8YEOP64dJ5NbP/bw2zVcc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680739339; 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=GVeZITSFOSVosu4yNU0kSm2zQr6awWpiVL1awBqfF1Y=; b=K8ZHfLECl2wCY68PFaTT1jG5VsT2uQtl3bNUQ02/ApY+/Ig4lTY5bfGonNWuW2iRRL LsoG5xC4z1CWAr375MTAwIWvuaWDjHaeImCXPSLtpRkCfaW/nskoNFFwaXzCJM3LpKOs Qinu/e9EVpF2ZmiIA1i1xPDpKLhYK4PiGgLxK8wv0foMMTJFl7AbSPTsB57UdE37QbT6 tb/8D/kWqKYG104Vs9Y0+QRRJWD7iXGPGtfu4bufpLWtE9B14rfTu/w22WUO9vHmOtVo P6wNpIVVjJn58qsr7OFo44fq/zHKKxLMMnaj1a8DfldPlLJNx9FzncGjksrOdatM49pM Ubbg== X-Gm-Message-State: AAQBX9fDsOnbXZQpPkAuFw8sKB0oU6vnuQfKJCHZKtJk3bj0OGEQaE0G sKngiP3xBb3cyBfvOXiqVdyGIw== X-Received: by 2002:a17:902:f544:b0:1a1:b8cc:59da with SMTP id h4-20020a170902f54400b001a1b8cc59damr9433799plf.33.1680739338883; Wed, 05 Apr 2023 17:02:18 -0700 (PDT) Received: from www.outflux.net (198-0-35-241-static.hfc.comcastbusiness.net. [198.0.35.241]) by smtp.gmail.com with ESMTPSA id y4-20020a1709027c8400b001a04d37a4acsm106056pll.9.2023.04.05.17.02.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Apr 2023 17:02:17 -0700 (PDT) From: Kees Cook To: linux-hardening@vger.kernel.org Cc: Kees Cook , Andy Shevchenko , Cezary Rojewski , Puyou Lu , Mark Brown , Josh Poimboeuf , Peter Zijlstra , Brendan Higgins , David Gow , Andrew Morton , Nathan Chancellor , Alexander Potapenko , Zhaoyang Huang , Randy Dunlap , Geert Uytterhoeven , Miguel Ojeda , Nick Desaulniers , Liam Howlett , Vlastimil Babka , Dan Williams , Rasmus Villemoes , Yury Norov , "Jason A. Donenfeld" , Sander Vanheule , Eric Biggers , "Masami Hiramatsu (Google)" , Andrey Konovalov , Linus Walleij , Daniel Latypov , =?utf-8?b?Sm9zw6kgRXhww7NzaXRv?= , linux-kernel@vger.kernel.org, kunit-dev@googlegroups.com Subject: [PATCH 6/9] fortify: Split reporting and avoid passing string pointer Date: Wed, 5 Apr 2023 17:02:05 -0700 Message-Id: <20230406000212.3442647-6-keescook@chromium.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230405235832.never.487-kees@kernel.org> References: <20230405235832.never.487-kees@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=11820; h=from:subject; bh=unK9/F7S4FUxqEzGNDbeCYLXq18RsKeeVFU9xRkUXsI=; b=owEBbQKS/ZANAwAKAYly9N/cbcAmAcsmYgBkLgv/Wwi9CD4BEpJoI75TveBPXRcut2QdfsP7sq0t vflFcsmJAjMEAAEKAB0WIQSlw/aPIp3WD3I+bhOJcvTf3G3AJgUCZC4L/wAKCRCJcvTf3G3AJhDAD/ 9+VFjHhYUtmkAtvm/ml4DQSaa6P/0Y+N6+4FhTbbGHVKigx+qRFJV4RRq6kasXh3ZzA8EHhUq7fbTp Iec2D1Nlyex5HIwNr+118srvlS2SZUOnEQxpyu9IBzmPdX7fMiwJ38qypqUkcuRNwapFb7Ppy4nCyX 0o+0bqQRv3cX5txcZXrJL0lNw6xn4Ci142qhSQNAhJ8Fuu3ITrrXSVtxDc53J42BoBpEYGEz4f9klT s4kjKEbhdcefB3fkY1S6s/b7pfcbGDzQYoWyERPI7u3dMGVW7Tw7qn/yeDbX0uJPpXAztjQdFlKwln wm2twRnu5aSFU082MWwjMvy+5Ld7f8ZJmsUfYGTTSbft17ac4Qi+Gqy0gyOkktm57sNpZ/tlGauNzG TkFSzIFmnpQyyM4aRjRHpPF7LgCdoC6shVaF1JkTuqUhJrJMjYtKPAB2QcDm86lXypAl9TWjyj8/tO 8r8a9Ob782ODDAiOlGHlrHzQV0/UxbDRz1hlOpiwsqew89XDt2D6w0eEdd1Bq5MHXBWWjBnc7n7roV v+aD1CE5viiZHAWgjCsRQYHTFDvkxBRblO5zW7VcsnkimaRSd8/g8f9kSqUXnm/ScbKAS6RVcPzhRG R81/JwTKZanUtzfC5kSl/oR43vWw9l9GoMc9K5LmNzgGs4FM2hVXxrcTbV8w== X-Developer-Key: i=keescook@chromium.org; a=openpgp; fpr=A5C3F68F229DD60F723E6E138972F4DFDC6DC026 X-Spam-Status: No, score=-0.2 required=5.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1762383033470988329?= X-GMAIL-MSGID: =?utf-8?q?1762383033470988329?= In preparation for KUnit testing and further improvements in fortify failure reporting, split out the report and encode the function and access failure (read or write overflow) into a single int argument. This mainly ends up saving some space in the data segment. For a defconfig with FORTIFY_SOURCE enabled: $ size gcc/vmlinux.before gcc/vmlinux.after text data bss dec hex filename 26132309 9760658 2195460 38088427 2452eeb gcc/vmlinux.before 26132386 9748382 2195460 38076228 244ff44 gcc/vmlinux.after Cc: Andy Shevchenko Cc: Cezary Rojewski Cc: Puyou Lu Cc: Mark Brown Cc: linux-hardening@vger.kernel.org Signed-off-by: Kees Cook --- include/linux/fortify-string.h | 72 +++++++++++++++++++++++----------- lib/string_helpers.c | 70 +++++++++++++++++++++++++++++++-- tools/objtool/check.c | 2 +- 3 files changed, 118 insertions(+), 26 deletions(-) diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h index 41dbd641f55c..6db4052db459 100644 --- a/include/linux/fortify-string.h +++ b/include/linux/fortify-string.h @@ -9,7 +9,34 @@ #define __FORTIFY_INLINE extern __always_inline __gnu_inline __overloadable #define __RENAME(x) __asm__(#x) -void fortify_panic(const char *name) __noreturn __cold; +#define fortify_reason(func, write) (((func) << 1) | !!(write)) + +#define fortify_panic(func, write) \ + __fortify_panic(fortify_reason(func, write)) + +#define FORTIFY_READ 0 +#define FORTIFY_WRITE 1 + +#define FORTIFY_FUNC_strncpy 0 +#define FORTIFY_FUNC_strnlen 1 +#define FORTIFY_FUNC_strlen 2 +#define FORTIFY_FUNC_strlcpy 3 +#define FORTIFY_FUNC_strscpy 4 +#define FORTIFY_FUNC_strlcat 5 +#define FORTIFY_FUNC_strcat 6 +#define FORTIFY_FUNC_strncat 7 +#define FORTIFY_FUNC_memset 8 +#define FORTIFY_FUNC_memcpy 9 +#define FORTIFY_FUNC_memmove 10 +#define FORTIFY_FUNC_memscan 11 +#define FORTIFY_FUNC_memcmp 12 +#define FORTIFY_FUNC_memchr 13 +#define FORTIFY_FUNC_memchr_inv 14 +#define FORTIFY_FUNC_kmemdup 15 +#define FORTIFY_FUNC_strcpy 16 + +void __fortify_report(u8 reason); +void __fortify_panic(u8 reason) __cold __noreturn; void __read_overflow(void) __compiletime_error("detected read beyond size of object (1st parameter)"); void __read_overflow2(void) __compiletime_error("detected read beyond size of object (2nd parameter)"); void __read_overflow2_field(size_t avail, size_t wanted) __compiletime_warning("detected read beyond size of field (2nd parameter); maybe use struct_group()?"); @@ -147,7 +174,7 @@ char *strncpy(char * const POS p, const char *q, __kernel_size_t size) if (__compiletime_lessthan(p_size, size)) __write_overflow(); if (p_size < size) - fortify_panic(__func__); + fortify_panic(FORTIFY_FUNC_strncpy, FORTIFY_WRITE); return __underlying_strncpy(p, q, size); } @@ -178,7 +205,7 @@ __FORTIFY_INLINE __kernel_size_t strnlen(const char * const POS p, __kernel_size /* Do not check characters beyond the end of p. */ ret = __real_strnlen(p, maxlen < p_size ? maxlen : p_size); if (p_size <= ret && maxlen != ret) - fortify_panic(__func__); + fortify_panic(FORTIFY_FUNC_strnlen, FORTIFY_READ); return ret; } @@ -214,7 +241,7 @@ __kernel_size_t __fortify_strlen(const char * const POS p) return __underlying_strlen(p); ret = strnlen(p, p_size); if (p_size <= ret) - fortify_panic(__func__); + fortify_panic(FORTIFY_FUNC_strlen, FORTIFY_READ); return ret; } @@ -256,7 +283,7 @@ __FORTIFY_INLINE size_t strlcpy(char * const POS p, const char * const POS q, si } if (size) { if (len >= p_size) - fortify_panic(__func__); + fortify_panic(FORTIFY_FUNC_strlcpy, FORTIFY_WRITE); __underlying_memcpy(p, q, len); p[len] = '\0'; } @@ -334,7 +361,7 @@ __FORTIFY_INLINE ssize_t strscpy(char * const POS p, const char * const POS q, s * p_size. */ if (len > p_size) - fortify_panic(__func__); + fortify_panic(FORTIFY_FUNC_strscpy, FORTIFY_WRITE); /* * We can now safely call vanilla strscpy because we are protected from: @@ -392,7 +419,7 @@ size_t strlcat(char * const POS p, const char * const POS q, size_t avail) /* Give up if string is already overflowed. */ if (p_size <= p_len) - fortify_panic(__func__); + fortify_panic(FORTIFY_FUNC_strlcat, FORTIFY_READ); if (actual >= avail) { copy_len = avail - p_len - 1; @@ -401,7 +428,7 @@ size_t strlcat(char * const POS p, const char * const POS q, size_t avail) /* Give up if copy will overflow. */ if (p_size <= actual) - fortify_panic(__func__); + fortify_panic(FORTIFY_FUNC_strlcat, FORTIFY_WRITE); __underlying_memcpy(p + p_len, q, copy_len); p[actual] = '\0'; @@ -430,7 +457,7 @@ char *strcat(char * const POS p, const char *q) size_t p_size = __member_size(p); if (strlcat(p, q, p_size) >= p_size) - fortify_panic(__func__); + fortify_panic(FORTIFY_FUNC_strcat, FORTIFY_WRITE); return p; } @@ -466,7 +493,7 @@ char *strncat(char * const POS p, const char * const POS q, __kernel_size_t coun p_len = strlen(p); copy_len = strnlen(q, count); if (p_size < p_len + copy_len + 1) - fortify_panic(__func__); + fortify_panic(FORTIFY_FUNC_strncat, FORTIFY_WRITE); __underlying_memcpy(p + p_len, q, copy_len); p[p_len + copy_len] = '\0'; return p; @@ -507,7 +534,7 @@ __FORTIFY_INLINE void fortify_memset_chk(__kernel_size_t size, * lengths are unknown.) */ if (p_size != SIZE_MAX && p_size < size) - fortify_panic("memset"); + fortify_panic(FORTIFY_FUNC_memset, FORTIFY_WRITE); } #define __fortify_memset_chk(p, c, size, p_size, p_size_field) ({ \ @@ -561,7 +588,7 @@ __FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size, const size_t q_size, const size_t p_size_field, const size_t q_size_field, - const char *func) + const u8 func) { if (__builtin_constant_p(size)) { /* @@ -605,9 +632,10 @@ __FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size, * (The SIZE_MAX test is to optimize away checks where the buffer * lengths are unknown.) */ - if ((p_size != SIZE_MAX && p_size < size) || - (q_size != SIZE_MAX && q_size < size)) - fortify_panic(func); + if (p_size != SIZE_MAX && p_size < size) + fortify_panic(func, FORTIFY_WRITE); + else if (q_size != SIZE_MAX && q_size < size) + fortify_panic(func, FORTIFY_READ); /* * Warn when writing beyond destination field size. @@ -640,7 +668,7 @@ __FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size, const size_t __q_size_field = (q_size_field); \ WARN_ONCE(fortify_memcpy_chk(__fortify_size, __p_size, \ __q_size, __p_size_field, \ - __q_size_field, #op), \ + __q_size_field, FORTIFY_FUNC_ ##op), \ #op ": detected field-spanning write (size %zu) of single %s (size %zu)\n", \ __fortify_size, \ "field \"" #p "\" at " __FILE__ ":" __stringify(__LINE__), \ @@ -707,7 +735,7 @@ __FORTIFY_INLINE void *memscan(void * const POS0 p, int c, __kernel_size_t size) if (__compiletime_lessthan(p_size, size)) __read_overflow(); if (p_size < size) - fortify_panic(__func__); + fortify_panic(FORTIFY_FUNC_memscan, FORTIFY_READ); return __real_memscan(p, c, size); } @@ -724,7 +752,7 @@ int memcmp(const void * const POS0 p, const void * const POS0 q, __kernel_size_t __read_overflow2(); } if (p_size < size || q_size < size) - fortify_panic(__func__); + fortify_panic(FORTIFY_FUNC_memcmp, FORTIFY_READ); return __underlying_memcmp(p, q, size); } @@ -736,7 +764,7 @@ void *memchr(const void * const POS0 p, int c, __kernel_size_t size) if (__compiletime_lessthan(p_size, size)) __read_overflow(); if (p_size < size) - fortify_panic(__func__); + fortify_panic(FORTIFY_FUNC_memchr, FORTIFY_READ); return __underlying_memchr(p, c, size); } @@ -748,7 +776,7 @@ __FORTIFY_INLINE void *memchr_inv(const void * const POS0 p, int c, size_t size) if (__compiletime_lessthan(p_size, size)) __read_overflow(); if (p_size < size) - fortify_panic(__func__); + fortify_panic(FORTIFY_FUNC_memchr_inv, FORTIFY_READ); return __real_memchr_inv(p, c, size); } @@ -761,7 +789,7 @@ __FORTIFY_INLINE void *kmemdup(const void * const POS0 p, size_t size, gfp_t gfp if (__compiletime_lessthan(p_size, size)) __read_overflow(); if (p_size < size) - fortify_panic(__func__); + fortify_panic(FORTIFY_FUNC_kmemdup, FORTIFY_READ); return __real_kmemdup(p, size, gfp); } @@ -798,7 +826,7 @@ char *strcpy(char * const POS p, const char * const POS q) __write_overflow(); /* Run-time check for dynamic size overflow. */ if (p_size < size) - fortify_panic(__func__); + fortify_panic(FORTIFY_FUNC_strcpy, FORTIFY_WRITE); __underlying_memcpy(p, q, size); return p; } diff --git a/lib/string_helpers.c b/lib/string_helpers.c index 230020a2e076..631c50657096 100644 --- a/lib/string_helpers.c +++ b/lib/string_helpers.c @@ -1021,10 +1021,74 @@ EXPORT_SYMBOL(__read_overflow2_field); void __write_overflow_field(size_t avail, size_t wanted) { } EXPORT_SYMBOL(__write_overflow_field); -void fortify_panic(const char *name) +void __fortify_report(u8 reason) { - pr_emerg("detected buffer overflow in %s\n", name); + const char *name; + const bool write = !!(reason & 0x1); + + switch (reason >> 1) { + case FORTIFY_FUNC_strncpy: + name = "strncpy"; + break; + case FORTIFY_FUNC_strnlen: + name = "strnlen"; + break; + case FORTIFY_FUNC_strlen: + name = "strlen"; + break; + case FORTIFY_FUNC_strlcpy: + name = "strlcpy"; + break; + case FORTIFY_FUNC_strscpy: + name = "strscpy"; + break; + case FORTIFY_FUNC_strlcat: + name = "strlcat"; + break; + case FORTIFY_FUNC_strcat: + name = "strcat"; + break; + case FORTIFY_FUNC_strncat: + name = "strncat"; + break; + case FORTIFY_FUNC_memset: + name = "memset"; + break; + case FORTIFY_FUNC_memcpy: + name = "memcpy"; + break; + case FORTIFY_FUNC_memmove: + name = "memmove"; + break; + case FORTIFY_FUNC_memscan: + name = "memscan"; + break; + case FORTIFY_FUNC_memcmp: + name = "memcmp"; + break; + case FORTIFY_FUNC_memchr: + name = "memchr"; + break; + case FORTIFY_FUNC_memchr_inv: + name = "memchr_inv"; + break; + case FORTIFY_FUNC_kmemdup: + name = "kmemdup"; + break; + case FORTIFY_FUNC_strcpy: + name = "strcpy"; + break; + default: + name = "unknown"; + } + WARN(1, "%s: detected buffer %s overflow\n", name, write ? "write" : "read"); +} +EXPORT_SYMBOL(__fortify_report); + +void __fortify_panic(const u8 reason) +{ + __fortify_report(reason); BUG(); } -EXPORT_SYMBOL(fortify_panic); +EXPORT_SYMBOL(__fortify_panic); #endif /* CONFIG_FORTIFY_SOURCE */ diff --git a/tools/objtool/check.c b/tools/objtool/check.c index f937be1afe65..2d0a67ce1c51 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -197,6 +197,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func, * attribute isn't provided in ELF data. Keep 'em sorted. */ static const char * const global_noreturns[] = { + "__fortify_panic", "__invalid_creds", "__module_put_and_kthread_exit", "__reiserfs_panic", @@ -208,7 +209,6 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func, "do_group_exit", "do_task_dead", "ex_handler_msr_mce", - "fortify_panic", "kthread_complete_and_exit", "kthread_exit", "kunit_try_catch_throw", From patchwork Thu Apr 6 00:02:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 79989 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp670797vqo; Wed, 5 Apr 2023 17:13:37 -0700 (PDT) X-Google-Smtp-Source: AKy350bH+I+EKQW/1BnfblRNIKVg2+WTJw9yocWv5gXr0H2vSWfKqOlpF3NJKVTYvvFqZpfbPs6E X-Received: by 2002:a17:906:13c9:b0:932:5f7d:db33 with SMTP id g9-20020a17090613c900b009325f7ddb33mr4824402ejc.34.1680740017374; Wed, 05 Apr 2023 17:13:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1680740017; cv=none; d=google.com; s=arc-20160816; b=AT5kSLWXYbdHrSqtmC8uh1+JZyfwFAoPUeA7PfHSTWCDAcB2ay63jE+Ma4KGef14hb et7keoqTce0S+gD7zYnQ+jCdInyLrNOIy6w1q+P4rDWujukbMzN0VNjgj1Yx3v7KPstN YARQsHAqgg3Wsyx6VCrRDIW9KTQbb9wSue0g15kHC7Go30dW14KVe7hoZdk0yoCHEevy GhY1Ca2nAG4oeQwLbBYCEy2kwHoPgz6MsI8HBW1eZZVc0jSr+nK8iC0N6efpDLeJErTh oJ6tVnRoP2nMFUqjdbGCl2R9PXM/YfbBbOMA+lEArFzPyH1RXqfZoxffPE4XEHaWjiXG 01yw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=fe5ivn1TRo1YQZGpjtcwb12k/6+IjegXd9dcvsAQqpo=; b=vWALRSPmh0mY2bBFKZ/NOomBJ3GY0b2b1tqhDBheWX/4NWJp7xYeQQwv5F4/HsZA29 i6k+FZLd2E1glirC2f/WvrFMVMrrLLDPik1ZseMZt2zkqWxmdO4PdOBnXqglk1pjHaPR +EIFLmvELk3oy+Gn/A23FCTVtcuWvwogXqzh6DnIWzzXaYWYBTLAu8crh8aPmcUJxcah mPDzzwAo/QnBScmFnbQuWkNBFfVNhi8a/MXTKPFgw2vdlIgbtlPjgvW8X5DoIc/rhdW4 lwcojFoX24l0vRlQRLklwwyAJyUQP/w1/bnvHmRj704G1bm7dZLH6FB2v22zWyxiDdK2 FQGQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=Eieac6hs; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id v3-20020a1709061dc300b00931b174e776si49682ejh.705.2023.04.05.17.13.13; Wed, 05 Apr 2023 17:13:37 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=Eieac6hs; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234129AbjDFACe (ORCPT + 99 others); Wed, 5 Apr 2023 20:02:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47880 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232832AbjDFACV (ORCPT ); Wed, 5 Apr 2023 20:02:21 -0400 Received: from mail-pl1-x634.google.com (mail-pl1-x634.google.com [IPv6:2607:f8b0:4864:20::634]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EEBB67683 for ; Wed, 5 Apr 2023 17:02:18 -0700 (PDT) Received: by mail-pl1-x634.google.com with SMTP id f22so31833624plr.0 for ; Wed, 05 Apr 2023 17:02:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1680739338; 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=fe5ivn1TRo1YQZGpjtcwb12k/6+IjegXd9dcvsAQqpo=; b=Eieac6hsjf/ZtZ6plrcl1dl/HZP04XmleXkBFTI8obqP7vSWmG64v4kacbMCs8dpWt go4DkRkXiLIgYWKgo9aqhUljI7kk5PM9t65E4/tHOpurAAv4no0mFm6pa3zp6QANyXKf Ua3KKUxFXnPibYqx9V1JXt7QQvw0ItwgQNNB0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680739338; 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=fe5ivn1TRo1YQZGpjtcwb12k/6+IjegXd9dcvsAQqpo=; b=kngLNoq1snSHFWdhn7iVhjc9AhfI4JYKmnZnsuvpCnIUd2icP+CT7WACnTlE64TTSX NUqJ3CUMpEdtzeAJRnjG4AyC+t2qcMSBfE1Zt1Y64kHSsZ5k9KW03YJsrmxzyc7dFXXP AEvZSAYkAlNaBxnyP4Z5FGmETXS04kujaZxt77jJFDdEAbWKjuie3KMPQXczYaSTNEju PDCBt5R1l2kfozS7aFlU+MQ1MjrPJJjjfpU9f46w6IHZ+8SL8LBOSMNn8RqzwmbWWAAU QH1rgnpZPrnu8/uHhgaaBwlEGv07Ic8FZDVPKI4CV7CSTTmP0o9LHwWnPHdimkB9D5k0 vkJg== X-Gm-Message-State: AAQBX9dFXYfqBDogsivKZve4xc2EMoyc4Lw1nRmweiEVM8j7m0N3q3xC lnuE3yCjUUx5Xn9KoPG6ytDiMA== X-Received: by 2002:a17:903:2306:b0:1a0:4046:23f2 with SMTP id d6-20020a170903230600b001a0404623f2mr9242650plh.56.1680739338311; Wed, 05 Apr 2023 17:02:18 -0700 (PDT) Received: from www.outflux.net (198-0-35-241-static.hfc.comcastbusiness.net. [198.0.35.241]) by smtp.gmail.com with ESMTPSA id a18-20020a170902b59200b0019f1264c7d7sm94897pls.103.2023.04.05.17.02.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Apr 2023 17:02:17 -0700 (PDT) From: Kees Cook To: linux-hardening@vger.kernel.org Cc: Kees Cook , Kees Cook , Andy Shevchenko , Cezary Rojewski , Puyou Lu , Mark Brown , Josh Poimboeuf , Peter Zijlstra , Brendan Higgins , David Gow , Andrew Morton , Nathan Chancellor , Alexander Potapenko , Zhaoyang Huang , Randy Dunlap , Geert Uytterhoeven , Miguel Ojeda , Nick Desaulniers , Liam Howlett , Vlastimil Babka , Dan Williams , Rasmus Villemoes , Yury Norov , "Jason A. Donenfeld" , Sander Vanheule , Eric Biggers , "Masami Hiramatsu (Google)" , Andrey Konovalov , Linus Walleij , Daniel Latypov , =?utf-8?b?Sm9zw6kgRXhww7NzaXRv?= , linux-kernel@vger.kernel.org, kunit-dev@googlegroups.com Subject: [PATCH 7/9] fortify: Provide KUnit counters for failure testing Date: Wed, 5 Apr 2023 17:02:06 -0700 Message-Id: <20230406000212.3442647-7-keescook@chromium.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230405235832.never.487-kees@kernel.org> References: <20230405235832.never.487-kees@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=10804; i=keescook@chromium.org; h=from:subject; bh=sfFlPo/mYV5VxdWixlpvcwAc+CtRK0pyQL7GL4KflJE=; b=owEBbQKS/ZANAwAKAYly9N/cbcAmAcsmYgBkLgv/qRZxzYzlqXt/wBRNW5IQR7wBwCY6ToiHUJ3z CNBFVL+JAjMEAAEKAB0WIQSlw/aPIp3WD3I+bhOJcvTf3G3AJgUCZC4L/wAKCRCJcvTf3G3AJrLzEA CzZ2FJuTA4dSd+rwj+KZD5cCIco6tJp5KYGB1dXhNiIWkEElDOF1wuQdwEiexK9jwUJZoD6YmdRSU8 TMtyStxj/IF6hySQyYpNkxeNyRDZjdWxWj7ABcr+5FfY3xQxPBuKizXW13+QGrBLDju6jSAay/CleP fvXvsDLWKCGgN/Hwy1D6va8eSbDV1I4w9hkKOyOLXp8OyxSQ0RZPVijwC2eCr+EV5oeLKWKq8IL1mq eQq9nCvh1wx3IEBpSilz2776YQ7iAe1TiAWUID4L0xxgh02Nx4aakR6YAh4vq+7/5KmW5UVMJ3BvBI WB3RTHOeMpwNGAgHkAlLRN7SsQ13raE7svGvgWDAOvEkXvtIYx/BSib6r/5SmsaRg2gPB6SGluJS94 6lYilIjUMchmfbcFQqqbX4ze2LFzE4fsm/mxTNkyfu2z3EjbRjJp5xsdUpgl9YM6FxvL6/P6oU8JVF tV10AlH83wkqVa3N54CRjBmIKZrMxNtmNpN4I83Lgh0buZDlYs85JGDsyDKiPxUasoVSedJxIpcZ5u 1Qvq3JQMetSjq+GFrMr/L+ax8uG8rmcl6Ro39BPGplzrR+/2oTIE8/cBeyPLLgOqZDFI1nJYytd89j RP74yoh1iJxniMF6OM0iAqm73tnaArMMeuFt61Nf2lHa5jOeFcIp5l0enxFg== X-Developer-Key: i=keescook@chromium.org; a=openpgp; fpr=A5C3F68F229DD60F723E6E138972F4DFDC6DC026 X-Spam-Status: No, score=-0.2 required=5.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1762383644719049485?= X-GMAIL-MSGID: =?utf-8?q?1762383644719049485?= From: Kees Cook The standard C string APIs were not designed to have a failure mode; they were expected to always succeed without memory safety issues. Normally, CONFIG_FORTIFY_SOURCE will use fortify_panic() to stop processing, as truncating a read or write may provide an even worse system state. However, this creates a problem for testing under things like KUnit, which needs a way to survive failures. When building with CONFIG_KUNIT, provide a failure path for all users for fortify_panic, and track whether the failure was a read overflow or a write overflow, for KUnit tests to examine. Inspired by similar logic in the slab tests. Signed-off-by: Kees Cook --- include/linux/fortify-string.h | 45 +++++++++++++++++--------------- lib/fortify_kunit.c | 47 ++++++++++++++++++++++++++++++++++ lib/string_helpers.c | 3 +++ 3 files changed, 75 insertions(+), 20 deletions(-) diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h index 6db4052db459..2bbee7b28e71 100644 --- a/include/linux/fortify-string.h +++ b/include/linux/fortify-string.h @@ -11,8 +11,12 @@ #define fortify_reason(func, write) (((func) << 1) | !!(write)) -#define fortify_panic(func, write) \ +#ifdef FORTIFY_KUNIT_OVERRIDE +# define fortify_panic kunit_fortify_panic +#else +# define fortify_panic(func, write, retfail) \ __fortify_panic(fortify_reason(func, write)) +#endif #define FORTIFY_READ 0 #define FORTIFY_WRITE 1 @@ -174,7 +178,7 @@ char *strncpy(char * const POS p, const char *q, __kernel_size_t size) if (__compiletime_lessthan(p_size, size)) __write_overflow(); if (p_size < size) - fortify_panic(FORTIFY_FUNC_strncpy, FORTIFY_WRITE); + fortify_panic(FORTIFY_FUNC_strncpy, FORTIFY_WRITE, p); return __underlying_strncpy(p, q, size); } @@ -205,7 +209,7 @@ __FORTIFY_INLINE __kernel_size_t strnlen(const char * const POS p, __kernel_size /* Do not check characters beyond the end of p. */ ret = __real_strnlen(p, maxlen < p_size ? maxlen : p_size); if (p_size <= ret && maxlen != ret) - fortify_panic(FORTIFY_FUNC_strnlen, FORTIFY_READ); + fortify_panic(FORTIFY_FUNC_strnlen, FORTIFY_READ, ret); return ret; } @@ -241,7 +245,7 @@ __kernel_size_t __fortify_strlen(const char * const POS p) return __underlying_strlen(p); ret = strnlen(p, p_size); if (p_size <= ret) - fortify_panic(FORTIFY_FUNC_strlen, FORTIFY_READ); + fortify_panic(FORTIFY_FUNC_strlen, FORTIFY_READ, ret); return ret; } @@ -283,7 +287,7 @@ __FORTIFY_INLINE size_t strlcpy(char * const POS p, const char * const POS q, si } if (size) { if (len >= p_size) - fortify_panic(FORTIFY_FUNC_strlcpy, FORTIFY_WRITE); + fortify_panic(FORTIFY_FUNC_strlcpy, FORTIFY_WRITE, q_len); __underlying_memcpy(p, q, len); p[len] = '\0'; } @@ -361,7 +365,7 @@ __FORTIFY_INLINE ssize_t strscpy(char * const POS p, const char * const POS q, s * p_size. */ if (len > p_size) - fortify_panic(FORTIFY_FUNC_strscpy, FORTIFY_WRITE); + fortify_panic(FORTIFY_FUNC_strscpy, FORTIFY_WRITE, -E2BIG); /* * We can now safely call vanilla strscpy because we are protected from: @@ -419,7 +423,7 @@ size_t strlcat(char * const POS p, const char * const POS q, size_t avail) /* Give up if string is already overflowed. */ if (p_size <= p_len) - fortify_panic(FORTIFY_FUNC_strlcat, FORTIFY_READ); + fortify_panic(FORTIFY_FUNC_strlcat, FORTIFY_READ, wanted); if (actual >= avail) { copy_len = avail - p_len - 1; @@ -428,7 +432,7 @@ size_t strlcat(char * const POS p, const char * const POS q, size_t avail) /* Give up if copy will overflow. */ if (p_size <= actual) - fortify_panic(FORTIFY_FUNC_strlcat, FORTIFY_WRITE); + fortify_panic(FORTIFY_FUNC_strlcat, FORTIFY_WRITE, wanted); __underlying_memcpy(p + p_len, q, copy_len); p[actual] = '\0'; @@ -457,7 +461,7 @@ char *strcat(char * const POS p, const char *q) size_t p_size = __member_size(p); if (strlcat(p, q, p_size) >= p_size) - fortify_panic(FORTIFY_FUNC_strcat, FORTIFY_WRITE); + fortify_panic(FORTIFY_FUNC_strcat, FORTIFY_WRITE, p); return p; } @@ -493,13 +497,13 @@ char *strncat(char * const POS p, const char * const POS q, __kernel_size_t coun p_len = strlen(p); copy_len = strnlen(q, count); if (p_size < p_len + copy_len + 1) - fortify_panic(FORTIFY_FUNC_strncat, FORTIFY_WRITE); + fortify_panic(FORTIFY_FUNC_strncat, FORTIFY_WRITE, p); __underlying_memcpy(p + p_len, q, copy_len); p[p_len + copy_len] = '\0'; return p; } -__FORTIFY_INLINE void fortify_memset_chk(__kernel_size_t size, +__FORTIFY_INLINE bool fortify_memset_chk(__kernel_size_t size, const size_t p_size, const size_t p_size_field) { @@ -534,7 +538,8 @@ __FORTIFY_INLINE void fortify_memset_chk(__kernel_size_t size, * lengths are unknown.) */ if (p_size != SIZE_MAX && p_size < size) - fortify_panic(FORTIFY_FUNC_memset, FORTIFY_WRITE); + fortify_panic(FORTIFY_FUNC_memset, FORTIFY_WRITE, true); + return false; } #define __fortify_memset_chk(p, c, size, p_size, p_size_field) ({ \ @@ -633,9 +638,9 @@ __FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size, * lengths are unknown.) */ if (p_size != SIZE_MAX && p_size < size) - fortify_panic(func, FORTIFY_WRITE); + fortify_panic(func, FORTIFY_WRITE, true); else if (q_size != SIZE_MAX && q_size < size) - fortify_panic(func, FORTIFY_READ); + fortify_panic(func, FORTIFY_READ, true); /* * Warn when writing beyond destination field size. @@ -735,7 +740,7 @@ __FORTIFY_INLINE void *memscan(void * const POS0 p, int c, __kernel_size_t size) if (__compiletime_lessthan(p_size, size)) __read_overflow(); if (p_size < size) - fortify_panic(FORTIFY_FUNC_memscan, FORTIFY_READ); + fortify_panic(FORTIFY_FUNC_memscan, FORTIFY_READ, NULL); return __real_memscan(p, c, size); } @@ -752,7 +757,7 @@ int memcmp(const void * const POS0 p, const void * const POS0 q, __kernel_size_t __read_overflow2(); } if (p_size < size || q_size < size) - fortify_panic(FORTIFY_FUNC_memcmp, FORTIFY_READ); + fortify_panic(FORTIFY_FUNC_memcmp, FORTIFY_READ, INT_MIN); return __underlying_memcmp(p, q, size); } @@ -764,7 +769,7 @@ void *memchr(const void * const POS0 p, int c, __kernel_size_t size) if (__compiletime_lessthan(p_size, size)) __read_overflow(); if (p_size < size) - fortify_panic(FORTIFY_FUNC_memchr, FORTIFY_READ); + fortify_panic(FORTIFY_FUNC_memchr, FORTIFY_READ, NULL); return __underlying_memchr(p, c, size); } @@ -776,7 +781,7 @@ __FORTIFY_INLINE void *memchr_inv(const void * const POS0 p, int c, size_t size) if (__compiletime_lessthan(p_size, size)) __read_overflow(); if (p_size < size) - fortify_panic(FORTIFY_FUNC_memchr_inv, FORTIFY_READ); + fortify_panic(FORTIFY_FUNC_memchr_inv, FORTIFY_READ, NULL); return __real_memchr_inv(p, c, size); } @@ -789,7 +794,7 @@ __FORTIFY_INLINE void *kmemdup(const void * const POS0 p, size_t size, gfp_t gfp if (__compiletime_lessthan(p_size, size)) __read_overflow(); if (p_size < size) - fortify_panic(FORTIFY_FUNC_kmemdup, FORTIFY_READ); + fortify_panic(FORTIFY_FUNC_kmemdup, FORTIFY_READ, NULL); return __real_kmemdup(p, size, gfp); } @@ -826,7 +831,7 @@ char *strcpy(char * const POS p, const char * const POS q) __write_overflow(); /* Run-time check for dynamic size overflow. */ if (p_size < size) - fortify_panic(FORTIFY_FUNC_strcpy, FORTIFY_WRITE); + fortify_panic(FORTIFY_FUNC_strcpy, FORTIFY_WRITE, p); __underlying_memcpy(p, q, size); return p; } diff --git a/lib/fortify_kunit.c b/lib/fortify_kunit.c index d054fc20a7d5..f7523c25d341 100644 --- a/lib/fortify_kunit.c +++ b/lib/fortify_kunit.c @@ -15,12 +15,28 @@ */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +/* Call kunit_fortify_panic() instead of fortify_panic() */ +#define FORTIFY_KUNIT_OVERRIDE +void fortify_add_kunit_error(int write); +#define kunit_fortify_panic(func, write, retfail) \ + do { \ + __fortify_report(fortify_reason(func, write)); \ + fortify_add_kunit_error(write); \ + return (retfail); \ + } while (0) + #include +#include #include #include #include #include +static struct kunit_resource read_resource; +static struct kunit_resource write_resource; +static int fortify_read_overflows; +static int fortify_write_overflows; + static const char array_of_10[] = "this is 10"; static const char *ptr_of_11 = "this is 11!"; static char array_unknown[] = "compiler thinks I might change"; @@ -36,6 +52,25 @@ do { \ kunit_skip(test, "Not built with CONFIG_FORTIFY_SOURCE=y"); \ } while (0) +void fortify_add_kunit_error(int write) +{ + struct kunit_resource *resource; + struct kunit *current_test; + + current_test = kunit_get_current_test(); + if (!current_test) + return; + + resource = kunit_find_named_resource(current_test, + write ? "fortify_write_overflows" + : "fortify_read_overflows"); + if (!resource) + return; + + (*(int *)resource->data)++; + kunit_put_resource(resource); +} + static void known_sizes_test(struct kunit *test) { skip_without_fortify(); @@ -322,6 +357,17 @@ DEFINE_ALLOC_SIZE_TEST_PAIR(kvmalloc) } while (0) DEFINE_ALLOC_SIZE_TEST_PAIR(devm_kmalloc) +static int fortify_test_init(struct kunit *test) +{ + kunit_add_named_resource(test, NULL, NULL, &read_resource, + "fortify_read_overflows", + &fortify_read_overflows); + kunit_add_named_resource(test, NULL, NULL, &write_resource, + "fortify_write_overflows", + &fortify_write_overflows); + return 0; +} + static struct kunit_case fortify_test_cases[] = { KUNIT_CASE(known_sizes_test), KUNIT_CASE(control_flow_split_test), @@ -338,6 +384,7 @@ static struct kunit_case fortify_test_cases[] = { static struct kunit_suite fortify_test_suite = { .name = "fortify", + .init = fortify_test_init, .test_cases = fortify_test_cases, }; diff --git a/lib/string_helpers.c b/lib/string_helpers.c index 631c50657096..5bb65f623e40 100644 --- a/lib/string_helpers.c +++ b/lib/string_helpers.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include /** * string_get_size - get the size in the specified units @@ -1091,4 +1093,5 @@ void __fortify_panic(const u8 reason) BUG(); } EXPORT_SYMBOL(__fortify_panic); + #endif /* CONFIG_FORTIFY_SOURCE */ From patchwork Thu Apr 6 00:02:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 79993 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp671317vqo; Wed, 5 Apr 2023 17:14:44 -0700 (PDT) X-Google-Smtp-Source: AKy350bkeNeqZxePiPFEgCmjbWFTdgIAeB8CFw0rj3OfB7gFlLtlDU0y69edauQvkaVseWQOVYfo X-Received: by 2002:a17:906:d10c:b0:8b1:7b10:61d5 with SMTP id b12-20020a170906d10c00b008b17b1061d5mr4882228ejz.33.1680740084349; Wed, 05 Apr 2023 17:14:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1680740084; cv=none; d=google.com; s=arc-20160816; b=odqxz2fqFY4y4PJ9pst32Y8cQ29/EjNNjlR1ly5OfksU15StkwR79TsScD7kBv49cu F17eTPvutZ76H7UCM6DrG3FdW1cpruyJs9QVyP5r0upW3/cHUowuJC/x6i5yf/axGxJB NNsryssmpZwCf/Ht8eLvp0fQKIOmXuQBD2euR+EM6+OIkjYG+8GfqG0Q11GXI5yuAbcG UMNO+Uf0cUllZndtjshBaqbQcO8OAwA4O/9wz8W8mQ1nhYlmGea/hfXd6Lm6PqamYLX9 o3tWL+R3BhnUNu7NGAwu/rAHz5Y/oxHmV8qrI6cktv3CJb2iC0Q5MBns7vKFZKLy7b9N aC2w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=aGVmFbO1Y3SrBAnAifK0ihmdOIjmdFYZw8LCIDp6wGM=; b=n8WxLsHj/vemlChtjP0p6yIoUL4rI8iTNOZ5jy7tpfI50roXY4L/JWK8hKnm8+JB3p G0poP5WGnHB8dFtRWCTgCecbyz0iMhK47doAh76/7fn2tam3m56ta3w2esMhck3aHAZY sInGgcYkPieNfpgZkVb/e52OhaLrsZYxQ7UBd08FFcv2PCYajVytZxOmVDU+nLs2O+xV V7ORJrGdI3gEtuRanwlb5FcbTLpUJgTlJQ7Vhq120d+s10ef629E/NJZOUVoJNLQQSBD ovwkWAS6s6elQseMGgvbLV9kdisgnJ+ibFDUjiu0o5XBCIVVGODBm9pFqcUIv5h7s2H3 wRQw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b="LxuIX9/u"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id gn27-20020a1709070d1b00b0093e0b659bc3si78391ejc.493.2023.04.05.17.14.20; Wed, 05 Apr 2023 17:14:44 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b="LxuIX9/u"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234296AbjDFACz (ORCPT + 99 others); Wed, 5 Apr 2023 20:02:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48002 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233603AbjDFACY (ORCPT ); Wed, 5 Apr 2023 20:02:24 -0400 Received: from mail-pj1-x1035.google.com (mail-pj1-x1035.google.com [IPv6:2607:f8b0:4864:20::1035]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E7FB17A89 for ; Wed, 5 Apr 2023 17:02:20 -0700 (PDT) Received: by mail-pj1-x1035.google.com with SMTP id x15so35676507pjk.2 for ; Wed, 05 Apr 2023 17:02:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1680739340; 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=aGVmFbO1Y3SrBAnAifK0ihmdOIjmdFYZw8LCIDp6wGM=; b=LxuIX9/ul4iLS8S1aSht29ovUoxEWtGqAQzkZBAuM1aqCB5+3YSKswbAGoEOIAFZHU 5+ZEOX44gt7UQ/6UDEk2oYWZHiuiZJCSUgfTLAzMP7qUKPaD9+iZvbO+rCCFfPu902DU yKxO2jiNZJkpWIJ/VwUKDp+AP65jBVlINGOLs= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680739340; 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=aGVmFbO1Y3SrBAnAifK0ihmdOIjmdFYZw8LCIDp6wGM=; b=fnWXt8G2WtdHw3JVa4m5sORadXdnaJxYfLxKCNAF3R6xzGqgOCSfu+F4mnpCCvEWhO LSUjTg0hn4ooCy91MOfrQQRGilRDOLRWqhYYIoMeo4owsCq9hixxCoXT8/epPV/9LoJa UZBikgXXYLN6SFbzl5pmR6h4+sjj6WzKcDmLbLcXM9bpqBwnJ7uHZVk5/V74qr/0MAIP sS3nDB7N5zSZ3c7uRxzkHHjapPs2QCbhQBxP4hIeFMrQrDEYEmmc1RRSTRzS7d27cyVd FoTpJTEw7DrGkzouD4YO2XEMlu5VRuPd5fYzEyZlCMp932TJFFM05wNjA0HurGktqLh5 Berw== X-Gm-Message-State: AAQBX9fH3ny+yCgcGTC3ZZUdH/7QmBn5zNpP9kjDnh9pcMLWj5kLgDKB HDHFZwcFeD2r6rWO8RGZD82oFA== X-Received: by 2002:a17:902:d2ce:b0:1a2:1a5b:cc69 with SMTP id n14-20020a170902d2ce00b001a21a5bcc69mr9937827plc.32.1680739339837; Wed, 05 Apr 2023 17:02:19 -0700 (PDT) Received: from www.outflux.net (198-0-35-241-static.hfc.comcastbusiness.net. [198.0.35.241]) by smtp.gmail.com with ESMTPSA id p10-20020a170902b08a00b0019cbd37a335sm93665plr.93.2023.04.05.17.02.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Apr 2023 17:02:17 -0700 (PDT) From: Kees Cook To: linux-hardening@vger.kernel.org Cc: Kees Cook , Kees Cook , Andy Shevchenko , Cezary Rojewski , Puyou Lu , Mark Brown , Josh Poimboeuf , Peter Zijlstra , Brendan Higgins , David Gow , Andrew Morton , Nathan Chancellor , Alexander Potapenko , Zhaoyang Huang , Randy Dunlap , Geert Uytterhoeven , Miguel Ojeda , Nick Desaulniers , Liam Howlett , Vlastimil Babka , Dan Williams , Rasmus Villemoes , Yury Norov , "Jason A. Donenfeld" , Sander Vanheule , Eric Biggers , "Masami Hiramatsu (Google)" , Andrey Konovalov , Linus Walleij , Daniel Latypov , =?utf-8?b?Sm9zw6kgRXhww7NzaXRv?= , linux-kernel@vger.kernel.org, kunit-dev@googlegroups.com Subject: [PATCH 8/9] fortify: Add KUnit tests for runtime overflows Date: Wed, 5 Apr 2023 17:02:07 -0700 Message-Id: <20230406000212.3442647-8-keescook@chromium.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230405235832.never.487-kees@kernel.org> References: <20230405235832.never.487-kees@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=29256; i=keescook@chromium.org; h=from:subject; bh=93uSHieIIEjRUuw59HxOto+9Z0ygPJhGlaPpgK8yUi0=; b=owEBbQKS/ZANAwAKAYly9N/cbcAmAcsmYgBkLgv/Eee2x9D/oTNO8DmEDkp1d4E7VwNznal84U3D Z5T/FeaJAjMEAAEKAB0WIQSlw/aPIp3WD3I+bhOJcvTf3G3AJgUCZC4L/wAKCRCJcvTf3G3AJuQnD/ 9HcOyFb96Sg7V/6cPe30hGahUjaFGv1GJfhTo1eskyLJvf490QordO1B8ZxUJ37i4l7HNDFoBD7gbU k+V3dnqQuks53s7OPhS51I38yshsdhmdHmoHtXIYfc3SrbbmPG2cgWRGo8xtqSK9Kva2myh2nFax6y tbcRrFiKQxBcM0M/V3fuw4Mmd1M2yp3diPAEnlzdTx8OoKsMedFtr0IG9azL8xTx8z9rb9kfIkaw52 UXeFOXOHo/aiZhe/n2X5rWhbywBQ06NVg4HN9pSFtHCWW41y2FbQmfdMZvA6rgSrG2fyLrVKf0Y+Qt hwRvjEmAjmQXowe0K/zJ2NUFDmaCyey3jnrf+V2nqK2gk0qdaZxCcArh7tPail+7pDkS4BdNlbEHNP JaKkLIFa1vz3MXuBXLBWNJZXeIYnBk9g4620cJU25/tpaGtCs6dFFMLrp8oWa8orSkMnRxFG+01yX8 dUMGsEA2wF2LIqJZgnQ9orDYUk+fYxHowQ/h67qjTqqjBW1fEtRVFcIUTFMR6WBzvNy7DrtjBO5mZY AypftjP2RcG3FS1fucjbxIt37jlDlR67LRUa/xShcHMBtMtNgMUVeLu25sDGt2ZNUz1UlGarFdLMtH 3MEXbzgAEBC/+yUST0x/69+evQL2UvyD/WBQ6oDdw/kuLYC7PlXJLkcwVnuQ== X-Developer-Key: i=keescook@chromium.org; a=openpgp; fpr=A5C3F68F229DD60F723E6E138972F4DFDC6DC026 X-Spam-Status: No, score=-0.2 required=5.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1762383662378714098?= X-GMAIL-MSGID: =?utf-8?q?1762383714593264901?= From: Kees Cook With fortify overflows able to be redirected, we can use KUnit to exercise the overflow conditions. Add tests for every API covered by CONFIG_FORTIFY_SOURCE. Signed-off-by: Kees Cook --- lib/fortify_kunit.c | 733 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 733 insertions(+) diff --git a/lib/fortify_kunit.c b/lib/fortify_kunit.c index f7523c25d341..b7c884037629 100644 --- a/lib/fortify_kunit.c +++ b/lib/fortify_kunit.c @@ -357,6 +357,723 @@ DEFINE_ALLOC_SIZE_TEST_PAIR(kvmalloc) } while (0) DEFINE_ALLOC_SIZE_TEST_PAIR(devm_kmalloc) +/* + * We can't have an array at the end of a structure or else + * builds without -fstrict-flex-arrays=3 will report them as + * being an unknown length. Additionally, add bytes before + * and after the string to catch over/underflows if tests + * fail. + */ +struct fortify_padding { + unsigned long bytes_before; + char buf[32]; + unsigned long bytes_after; +}; +/* Force compiler into not being able to resolve size at compile-time. */ +static volatile int unconst = 0; + +static void strlen_test(struct kunit *test) +{ + struct fortify_padding pad = { }; + int i, end = sizeof(pad.buf) - 1; + + skip_without_fortify(); + + fortify_read_overflows = 0; + + /* Fill 31 bytes with valid characters. */ + for (i = 0; i < sizeof(pad.buf) - 1; i++) + pad.buf[i] = i + '0'; + /* Trailing bytes are still %NUL. */ + KUNIT_EXPECT_EQ(test, pad.buf[end], '\0'); + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* String is terminated, so strlen() is valid. */ + KUNIT_EXPECT_EQ(test, strlen(pad.buf), end); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + + /* Make string unterminated, and recount. */ + pad.buf[end] = 'A'; + end = sizeof(pad.buf); + KUNIT_EXPECT_EQ(test, strlen(pad.buf), end); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 1); +} + +static void strnlen_test(struct kunit *test) +{ + struct fortify_padding pad = { }; + int i, end = sizeof(pad.buf) - 1; + + skip_without_fortify(); + + fortify_read_overflows = 0; + + /* Fill 31 bytes with valid characters. */ + for (i = 0; i < sizeof(pad.buf) - 1; i++) + pad.buf[i] = i + '0'; + /* Trailing bytes are still %NUL. */ + KUNIT_EXPECT_EQ(test, pad.buf[end], '\0'); + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* String is terminated, so strnlen() is valid. */ + KUNIT_EXPECT_EQ(test, strnlen(pad.buf, sizeof(pad.buf)), end); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + /* A truncated strnlen() will be safe, too. */ + KUNIT_EXPECT_EQ(test, strnlen(pad.buf, sizeof(pad.buf) / 2), + sizeof(pad.buf) / 2); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + + /* Make string unterminated, and recount. */ + pad.buf[end] = 'A'; + end = sizeof(pad.buf); + /* Reading beyond with strncpy() will fail. */ + KUNIT_EXPECT_EQ(test, strnlen(pad.buf, end + 1), end); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 1); + KUNIT_EXPECT_EQ(test, strnlen(pad.buf, end + 2), end); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 2); + + /* Early-truncated is safe still, though. */ + KUNIT_EXPECT_EQ(test, strnlen(pad.buf, end), end); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 2); + + end = sizeof(pad.buf) / 2; + KUNIT_EXPECT_EQ(test, strnlen(pad.buf, end), end); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 2); +} + +static void strcpy_test(struct kunit *test) +{ + struct fortify_padding pad = { }; + char src[sizeof(pad.buf) + 1] = { }; + int i; + + skip_without_fortify(); + + /* Fill 31 bytes with valid characters. */ + for (i = 0; i < sizeof(src) - 2; i++) + src[i] = i + '0'; + + fortify_read_overflows = 0; + fortify_write_overflows = 0; + + /* Destination is %NUL-filled to start with. */ + KUNIT_EXPECT_EQ(test, pad.bytes_before, 0); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* Legitimate strcpy() 1 less than of max size. */ + KUNIT_ASSERT_TRUE(test, strcpy(pad.buf, src) + == pad.buf); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); + /* Only last byte should be %NUL */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + + src[sizeof(src) - 2] = 'A'; + /* But now we trip the overflow checking. */ + KUNIT_ASSERT_TRUE(test, strcpy(pad.buf, src) + == pad.buf); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1); + /* Trailing %NUL -- thanks to FORTIFY. */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + /* And we will not have gone beyond. */ + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + src[sizeof(src) - 1] = 'A'; + /* And for sure now, two bytes past. */ + KUNIT_ASSERT_TRUE(test, strcpy(pad.buf, src) + == pad.buf); + /* + * Which trips both the strlen() on the unterminated src, + * and the resulting copy attempt. + */ + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 1); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2); + /* Trailing %NUL -- thanks to FORTIFY. */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + /* And we will not have gone beyond. */ + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); +} + +static void strncpy_test(struct kunit *test) +{ + struct fortify_padding pad = { }; + char src[] = "Copy me fully into a small buffer and I will overflow!"; + + skip_without_fortify(); + + fortify_write_overflows = 0; + + /* Destination is %NUL-filled to start with. */ + KUNIT_EXPECT_EQ(test, pad.bytes_before, 0); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* Legitimate strncpy() 1 less than of max size. */ + KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, + sizeof(pad.buf) + unconst - 1) + == pad.buf); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); + /* Only last byte should be %NUL */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + + /* Legitimate (though unterminated) max-size strncpy. */ + KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, + sizeof(pad.buf) + unconst) + == pad.buf); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); + /* No trailing %NUL -- thanks strncpy API. */ + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + /* But we will not have gone beyond. */ + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* Now verify that FORTIFY is working... */ + KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, + sizeof(pad.buf) + unconst + 1) + == pad.buf); + /* Should catch the overflow. */ + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + /* And we will not have gone beyond. */ + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* And further... */ + KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, + sizeof(pad.buf) + unconst + 2) + == pad.buf); + /* Should catch the overflow. */ + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + /* And we will not have gone beyond. */ + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); +} + +static void strlcpy_test(struct kunit *test) +{ + struct fortify_padding pad = { }; + char src[] = "Copy me fully into a small buffer and I will overflow!"; + char tiny[4] = "abcd"; + + skip_without_fortify(); + + fortify_read_overflows = 0; + fortify_write_overflows = 0; + + /* Destination is %NUL-filled to start with. */ + KUNIT_EXPECT_EQ(test, pad.bytes_before, 0); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* Legitimate strlcpy() 1 less than of max size. */ + KUNIT_ASSERT_EQ(test, strlcpy(pad.buf, src, + sizeof(pad.buf) + unconst - 1), + sizeof(src) - 1); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); + /* Keeping space for %NUL, last two bytes should be %NUL */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + + /* Legitimate max-size strlcpy. */ + KUNIT_ASSERT_EQ(test, strlcpy(pad.buf, src, + sizeof(pad.buf) + unconst), + sizeof(src) - 1); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); + /* A trailing %NUL will exist. */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + + /* Now verify that FORTIFY is working... */ + KUNIT_ASSERT_EQ(test, strlcpy(pad.buf, src, + sizeof(pad.buf) + unconst + 1), + sizeof(src) - 1); + /* Should catch the overflow. */ + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + /* And we will not have gone beyond. */ + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* And much further... */ + KUNIT_ASSERT_EQ(test, strlcpy(pad.buf, src, + sizeof(src) * 2 + unconst), + sizeof(src) - 1); + /* Should catch the overflow. */ + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + /* And we will not have gone beyond. */ + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* Catch over-read. */ + KUNIT_ASSERT_EQ(test, strlcpy(pad.buf, tiny, + sizeof(pad.buf) + unconst), + sizeof(tiny)); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 1); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2); +} + +static void strscpy_test(struct kunit *test) +{ + struct fortify_padding pad = { }; + char src[] = "Copy me fully into a small buffer and I will overflow!"; + + skip_without_fortify(); + + fortify_write_overflows = 0; + + /* Destination is %NUL-filled to start with. */ + KUNIT_EXPECT_EQ(test, pad.bytes_before, 0); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* Legitimate strscpy() 1 less than of max size. */ + KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src, + sizeof(pad.buf) + unconst - 1), + -E2BIG); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); + /* Keeping space for %NUL, last two bytes should be %NUL */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + + /* Legitimate max-size strscpy. */ + KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src, + sizeof(pad.buf) + unconst), + -E2BIG); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); + /* A trailing %NUL will exist. */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + + /* Now verify that FORTIFY is working... */ + KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src, + sizeof(pad.buf) + unconst + 1), + -E2BIG); + /* Should catch the overflow. */ + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + /* And we will not have gone beyond. */ + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* And much further... */ + KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src, + sizeof(src) * 2 + unconst), + -E2BIG); + /* Should catch the overflow. */ + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + /* And we will not have gone beyond. */ + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); +} + +static void strcat_test(struct kunit *test) +{ + struct fortify_padding pad = { }; + char src[sizeof(pad.buf) / 2] = { }; + char one[] = "A"; + char two[] = "BC"; + int i; + + skip_without_fortify(); + + fortify_write_overflows = 0; + + /* Fill 15 bytes with valid characters. */ + for (i = 0; i < sizeof(src) - 1; i++) + src[i] = i + 'A'; + + /* Destination is %NUL-filled to start with. */ + KUNIT_EXPECT_EQ(test, pad.bytes_before, 0); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* Legitimate strcat() using less than half max size. */ + KUNIT_ASSERT_TRUE(test, strcat(pad.buf, src) == pad.buf); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); + /* Legitimate strcat() now 2 bytes shy of end. */ + KUNIT_ASSERT_TRUE(test, strcat(pad.buf, src) == pad.buf); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); + /* Last two bytes should be %NUL */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + + /* Add one more character to the end. */ + KUNIT_ASSERT_TRUE(test, strcat(pad.buf, one) == pad.buf); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); + /* Last byte should be %NUL */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + + /* And this one char will overflow. */ + KUNIT_ASSERT_TRUE(test, strcat(pad.buf, one) == pad.buf); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1); + /* Last byte should be %NUL thanks to FORTIFY. */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* And adding two will overflow more. */ + KUNIT_ASSERT_TRUE(test, strcat(pad.buf, two) == pad.buf); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2); + /* Last byte should be %NUL thanks to FORTIFY. */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); +} + +static void strncat_test(struct kunit *test) +{ + struct fortify_padding pad = { }; + char src[sizeof(pad.buf)] = { }; + int i, partial; + + skip_without_fortify(); + + fortify_read_overflows = 0; + fortify_write_overflows = 0; + + /* Fill 31 bytes with valid characters. */ + partial = sizeof(src) / 2 - 1; + for (i = 0; i < partial; i++) + src[i] = i + 'A'; + + /* Destination is %NUL-filled to start with. */ + KUNIT_EXPECT_EQ(test, pad.bytes_before, 0); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* Legitimate strncat() using less than half max size. */ + KUNIT_ASSERT_TRUE(test, strncat(pad.buf, src, partial) == pad.buf); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); + /* Legitimate strncat() now 2 bytes shy of end. */ + KUNIT_ASSERT_TRUE(test, strncat(pad.buf, src, partial) == pad.buf); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); + /* Last two bytes should be %NUL */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + + /* Add one more character to the end. */ + KUNIT_ASSERT_TRUE(test, strncat(pad.buf, src, 1) == pad.buf); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); + /* Last byte should be %NUL */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + + /* And this one char will overflow. */ + KUNIT_ASSERT_TRUE(test, strncat(pad.buf, src, 1) == pad.buf); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1); + /* Last byte should be %NUL thanks to FORTIFY. */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* And adding two will overflow more. */ + KUNIT_ASSERT_TRUE(test, strncat(pad.buf, src, 2) == pad.buf); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2); + /* Last byte should be %NUL thanks to FORTIFY. */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* Force an unterminated destination, and overflow. */ + pad.buf[sizeof(pad.buf) - 1] = 'A'; + KUNIT_ASSERT_TRUE(test, strncat(pad.buf, src, 1) == pad.buf); + /* This will have tripped both strlen() and strcat(). */ + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 1); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 3); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + /* But we should not go beyond the end. */ + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); +} + +static void strlcat_test(struct kunit *test) +{ + struct fortify_padding pad = { }; + char src[sizeof(pad.buf)] = { }; + int i, partial; + int len = sizeof(pad.buf) + unconst; + + skip_without_fortify(); + + fortify_read_overflows = 0; + fortify_write_overflows = 0; + + /* Fill 15 bytes with valid characters. */ + partial = sizeof(src) / 2 - 1; + for (i = 0; i < partial; i++) + src[i] = i + 'A'; + + /* Destination is %NUL-filled to start with. */ + KUNIT_EXPECT_EQ(test, pad.bytes_before, 0); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* Legitimate strlcat() using less than half max size. */ + KUNIT_ASSERT_EQ(test, strlcat(pad.buf, src, len), partial); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); + /* Legitimate strlcat() now 2 bytes shy of end. */ + KUNIT_ASSERT_EQ(test, strlcat(pad.buf, src, len), partial * 2); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); + /* Last two bytes should be %NUL */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + + /* Add one more character to the end. */ + KUNIT_ASSERT_EQ(test, strlcat(pad.buf, "Q", len), partial * 2 + 1); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); + /* Last byte should be %NUL */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + + /* And this one char will overflow. */ + KUNIT_ASSERT_EQ(test, strlcat(pad.buf, "V", len * 2), len); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1); + /* Last byte should be %NUL thanks to FORTIFY. */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* And adding two will overflow more. */ + KUNIT_ASSERT_EQ(test, strlcat(pad.buf, "QQ", len * 2), len + 1); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2); + /* Last byte should be %NUL thanks to FORTIFY. */ + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* Force an unterminated destination, and overflow. */ + pad.buf[sizeof(pad.buf) - 1] = 'A'; + KUNIT_ASSERT_EQ(test, strlcat(pad.buf, "TT", len * 2), len + 2); + /* This will have tripped both strlen() and strlcat(). */ + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 2); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + /* But we should not go beyond the end. */ + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); + + /* Force an unterminated source, and overflow. */ + memset(src, 'B', sizeof(src)); + pad.buf[sizeof(pad.buf) - 1] = '\0'; + KUNIT_ASSERT_EQ(test, strlcat(pad.buf, src, len * 3), len - 1 + sizeof(src)); + /* This will have tripped both strlen() and strlcat(). */ + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 3); + KUNIT_EXPECT_EQ(test, fortify_write_overflows, 3); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); + /* But we should not go beyond the end. */ + KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); +} + +static void memscan_test(struct kunit *test) +{ + char haystack[] = "Where oh where is my memory range?"; + char *mem = haystack + strlen("Where oh where is "); + char needle = 'm'; + size_t len = sizeof(haystack) + unconst; + + skip_without_fortify(); + + fortify_read_overflows = 0; + + KUNIT_ASSERT_PTR_EQ(test, memscan(haystack, needle, len), + mem); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + /* Catch too-large range. */ + KUNIT_ASSERT_PTR_EQ(test, memscan(haystack, needle, len + 1), + NULL); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 1); + KUNIT_ASSERT_PTR_EQ(test, memscan(haystack, needle, len * 2), + NULL); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 2); +} + +static void memchr_test(struct kunit *test) +{ + char haystack[] = "Where oh where is my memory range?"; + char *mem = haystack + strlen("Where oh where is "); + char needle = 'm'; + size_t len = sizeof(haystack) + unconst; + + skip_without_fortify(); + + fortify_read_overflows = 0; + + KUNIT_ASSERT_PTR_EQ(test, memchr(haystack, needle, len), + mem); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + /* Catch too-large range. */ + KUNIT_ASSERT_PTR_EQ(test, memchr(haystack, needle, len + 1), + NULL); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 1); + KUNIT_ASSERT_PTR_EQ(test, memchr(haystack, needle, len * 2), + NULL); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 2); +} + +static void memchr_inv_test(struct kunit *test) +{ + char haystack[] = "Where oh where is my memory range?"; + char *mem = haystack + 1; + char needle = 'W'; + size_t len = sizeof(haystack) + unconst; + + skip_without_fortify(); + + fortify_read_overflows = 0; + + /* Normal search is okay. */ + KUNIT_ASSERT_PTR_EQ(test, memchr_inv(haystack, needle, len), + mem); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + /* Catch too-large range. */ + KUNIT_ASSERT_PTR_EQ(test, memchr_inv(haystack, needle, len + 1), + NULL); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 1); + KUNIT_ASSERT_PTR_EQ(test, memchr_inv(haystack, needle, len * 2), + NULL); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 2); +} + +static void memcmp_test(struct kunit *test) +{ + char one[] = "My mind is going ..."; + char two[] = "My mind is going ... I can feel it."; + size_t one_len = sizeof(one) + unconst - 1; + size_t two_len = sizeof(two) + unconst - 1; + + skip_without_fortify(); + + fortify_read_overflows = 0; + + /* We match the first string (ignoring the %NUL). */ + KUNIT_ASSERT_EQ(test, memcmp(one, two, one_len), 0); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + /* Still in bounds, but no longer matching. */ + KUNIT_ASSERT_EQ(test, memcmp(one, two, one_len + 1), -32); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + + /* Catch too-large ranges. */ + KUNIT_ASSERT_EQ(test, memcmp(one, two, one_len + 2), INT_MIN); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 1); + + KUNIT_ASSERT_EQ(test, memcmp(two, one, two_len + 2), INT_MIN); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 2); +} + +static void kmemdup_test(struct kunit *test) +{ + char src[] = "I got Doom running on it!"; + char *copy; + size_t len = sizeof(src) + unconst; + + skip_without_fortify(); + + fortify_read_overflows = 0; + + /* Copy is within bounds. */ + copy = kmemdup(src, len, GFP_KERNEL); + KUNIT_EXPECT_NOT_NULL(test, copy); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + kfree(copy); + + /* Without %NUL. */ + copy = kmemdup(src, len - 1, GFP_KERNEL); + KUNIT_EXPECT_NOT_NULL(test, copy); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + kfree(copy); + + /* Tiny bounds. */ + copy = kmemdup(src, 1, GFP_KERNEL); + KUNIT_EXPECT_NOT_NULL(test, copy); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); + kfree(copy); + + /* Out of bounds by 1 byte. */ + copy = kmemdup(src, len + 1, GFP_KERNEL); + KUNIT_EXPECT_NULL(test, copy); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 1); + kfree(copy); + + /* Way out of bounds. */ + copy = kmemdup(src, len * 2, GFP_KERNEL); + KUNIT_EXPECT_NULL(test, copy); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 2); + kfree(copy); + + /* Starting offset causing out of bounds. */ + copy = kmemdup(src + 1, len, GFP_KERNEL); + KUNIT_EXPECT_NULL(test, copy); + KUNIT_EXPECT_EQ(test, fortify_read_overflows, 3); + kfree(copy); +} + static int fortify_test_init(struct kunit *test) { kunit_add_named_resource(test, NULL, NULL, &read_resource, @@ -379,6 +1096,22 @@ static struct kunit_case fortify_test_cases[] = { KUNIT_CASE(alloc_size_kvmalloc_dynamic_test), KUNIT_CASE(alloc_size_devm_kmalloc_const_test), KUNIT_CASE(alloc_size_devm_kmalloc_dynamic_test), + KUNIT_CASE(strlen_test), + KUNIT_CASE(strnlen_test), + KUNIT_CASE(strcpy_test), + KUNIT_CASE(strncpy_test), + KUNIT_CASE(strlcpy_test), + KUNIT_CASE(strscpy_test), + KUNIT_CASE(strcat_test), + KUNIT_CASE(strncat_test), + KUNIT_CASE(strlcat_test), + /* skip memset: performs bounds checking on whole structs */ + /* skip memcpy: still using warn-and-clobber instead of hard-fail */ + KUNIT_CASE(memscan_test), + KUNIT_CASE(memchr_test), + KUNIT_CASE(memchr_inv_test), + KUNIT_CASE(memcmp_test), + KUNIT_CASE(kmemdup_test), {} }; From patchwork Thu Apr 6 00:02:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 79987 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp670319vqo; Wed, 5 Apr 2023 17:12:25 -0700 (PDT) X-Google-Smtp-Source: AKy350ZqgM7ztm4fGL/mgAbgVhrgNQor0VfTAG8ouq+1ygSokeOh2vugzOYSIxfr0riPIXIh1rVz X-Received: by 2002:a17:906:b755:b0:933:130e:e81a with SMTP id fx21-20020a170906b75500b00933130ee81amr3707425ejb.32.1680739945706; Wed, 05 Apr 2023 17:12:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1680739945; cv=none; d=google.com; s=arc-20160816; b=adYAS4DyTzKbw0xoJGO70916Jiq5JbAuPNUmroWYXyIZV/uTcP69Pok6YPAsj2GmSG QskGg+IUlL+x27e23nh5qr/NrEAFfa5TBL8xxxEr+6c3fsXTELqnkAY6JB3QVbqbjTdb eW7q/39Lw7Wzm6AV6RHtaKEGIhdXbMyNjWoimn6vJuhSsbEKqZNMJQT/C1h90RtnzqwO wuk8XGu09X//q+lFTTN8XpwM41GnXbqrdGM6KmaSwl1AhTi99RdgcO1zC76mW5AywxZ4 rc1ad3Wq1oiT494ZIA6avukQ3uUjqQwNWMRYySTxh9rtxByivqLZgQLcVGYEMSsojMup +Hcw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=TMkBWw2BkDKd0w5gBkiKI3BqJHl3IJqXN2BQevcFbNE=; b=J8ax1cPsx3vyiHZcePfhsN1fvx90Sq/m+BXcgrkTAPyjIpABh4W9JaYWIysrTOWkpD 93P0pyQW5QNgD4Wc3la6TyKU/9vuOG+3dgxSFfxC5A1TxPLE1x80YbK8PTyte8T6Kc+E xVZ7T3YsHF22Bed9zwdpBu3z49ye0GGVlDEdW5UjBoK3XdfA0galBigVcLr+6oAhIvMv avV6fpoTXYAm0lL8BOh7BSzQf9Q6uj5VCyIK1/r5Xh+7/ppLkTQIpzgy/xBetiVpUVgp y+adFAC/BrtuSG/PKRTZqyJsuTwRCprtiUWdcU/wnxMnv/0I2Wuxqks4Aa41HGeEKgiu fuBg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=fFL2rtSq; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id o7-20020a17090611c700b00930a3df8e79si59953eja.558.2023.04.05.17.12.01; Wed, 05 Apr 2023 17:12:25 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=fFL2rtSq; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233998AbjDFACv (ORCPT + 99 others); Wed, 5 Apr 2023 20:02:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47880 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233384AbjDFACX (ORCPT ); Wed, 5 Apr 2023 20:02:23 -0400 Received: from mail-pj1-x1029.google.com (mail-pj1-x1029.google.com [IPv6:2607:f8b0:4864:20::1029]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4D87C76BD for ; Wed, 5 Apr 2023 17:02:20 -0700 (PDT) Received: by mail-pj1-x1029.google.com with SMTP id mp3-20020a17090b190300b0023fcc8ce113so41183687pjb.4 for ; Wed, 05 Apr 2023 17:02:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1680739339; 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=TMkBWw2BkDKd0w5gBkiKI3BqJHl3IJqXN2BQevcFbNE=; b=fFL2rtSqkSU6Bt+5odQRtTqVNA9TuWc9jO+VTD4Yl8/W8fT4IdqxL+4K74Hwv+5XqE rz0aomwvMjXdOe6kM+YcxrMO2Md7V+uVUFwwpbRoB39+t5Hxtqg2T0GZDYD2qot0e48t JiZkOttLyLyYjk791fN7F3Pe6ZTRSLSGhHaR4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680739339; 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=TMkBWw2BkDKd0w5gBkiKI3BqJHl3IJqXN2BQevcFbNE=; b=r2A3yAmb9DLSpH8YpNveJX9/v0T22+z0lt2U1+w/HXKE8c9lVl3i20NwARQWC2JkCW hGoVwnms4r/dVoQBR1ToVacDebwg1rPXxjbXnyVjURDe/+cl6KWV2c79V/Dl1+K07rP7 xoZEb2OmjXEtSyV6+7VV9koQk/7XRt9YWSEa1KZ2aRKiUJHxZrhu/QFJZDx8PCxfej0g 8PS584w6WI0vUVPtOmdtp3uYA31ENJH5+I5QnLenJrj5xie+PuGccFoA2WW/2O7T9M7s RcKSfugLqFfJKNnCMabCJVk2iYLShGVxvkyWe1H2inKQ0rPEDcsl9QIxTAc9nopbcHo8 oi7A== X-Gm-Message-State: AAQBX9e1peoVa9lmxWTCkzOxyirYZO4ZtavMmRsidaFLSwgqZxs+jJdG NrSvtDUsdoXwXfK6U3MAH44plQ== X-Received: by 2002:a17:902:d2c9:b0:19d:7a4:4063 with SMTP id n9-20020a170902d2c900b0019d07a44063mr10558907plc.46.1680739339380; Wed, 05 Apr 2023 17:02:19 -0700 (PDT) Received: from www.outflux.net (198-0-35-241-static.hfc.comcastbusiness.net. [198.0.35.241]) by smtp.gmail.com with ESMTPSA id v3-20020a170902b7c300b001a240f053aasm82939plz.180.2023.04.05.17.02.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Apr 2023 17:02:17 -0700 (PDT) From: Kees Cook To: linux-hardening@vger.kernel.org Cc: Kees Cook , Kees Cook , Andy Shevchenko , Cezary Rojewski , Puyou Lu , Mark Brown , Josh Poimboeuf , Peter Zijlstra , Brendan Higgins , David Gow , Andrew Morton , Nathan Chancellor , Alexander Potapenko , Zhaoyang Huang , Randy Dunlap , Geert Uytterhoeven , Miguel Ojeda , Nick Desaulniers , Liam Howlett , Vlastimil Babka , Dan Williams , Rasmus Villemoes , Yury Norov , "Jason A. Donenfeld" , Sander Vanheule , Eric Biggers , "Masami Hiramatsu (Google)" , Andrey Konovalov , Linus Walleij , Daniel Latypov , =?utf-8?b?Sm9zw6kgRXhww7NzaXRv?= , linux-kernel@vger.kernel.org, kunit-dev@googlegroups.com Subject: [PATCH 9/9] fortify: Improve buffer overflow reporting Date: Wed, 5 Apr 2023 17:02:08 -0700 Message-Id: <20230406000212.3442647-9-keescook@chromium.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230405235832.never.487-kees@kernel.org> References: <20230405235832.never.487-kees@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=10763; i=keescook@chromium.org; h=from:subject; bh=sUo3OusVEyTd1TzMe089/10RvDWd1ECiLD0iA7jbIMo=; b=owEBbQKS/ZANAwAKAYly9N/cbcAmAcsmYgBkLgv/K75AFXHO/hOzjfREHpqcERlLV3XfGhVps4a5 3V4CDYyJAjMEAAEKAB0WIQSlw/aPIp3WD3I+bhOJcvTf3G3AJgUCZC4L/wAKCRCJcvTf3G3AJmK6D/ 9gmGPNETiVsquqPmXbjRCt8fY5qeKhaICBkEOkHuWRQ/LJ+rMGE6UpqebohA5cRkOzG8G1yT0Zzyta y1uChVwx8YTE627K52ry9bJRzyeDiCx/JxElBaqBeYo870Osw66SI+uL0CpEfCCyp328woQHGN/PeC AQ7sn3YG8R8jSkMaBy5jeskTNErnZjw+cc67ltaYlYLh6qA1fN+h7NzjEEGH2VIGVE2JBV+Uap6Cse xUoDTRiAchaiSlEhp+CReYFqsEXgQNezLntzmsGkjYSRowJhTOlYZzHsJTGp0yna5vpW4To1w7nQEl aXDoYn86ZH538WKLkX/lxmpPnTSS9ERMAatG8B3BtLpZgYpQu7InTzfwIjYypT7f3baF8M2m13pVhi CEw3cDwUmHb/nyRc+xBCC6YtT16dHfH+kJ05PEHRXXkgTSCSf7fJEyr98MOraI+M/lCoP28BYBeoDE h2bhM2bjKCUJcyJ0Y6lyCiNbcwe4TF/Vus9/2cvmvMwlr77AaoFvPei2PXoOobkr1nfCX5qBemSJDP CMbvgY524ktnbIrz7bcvVCTVyEESAMjaVGftjndxhF7eUVbvhS0PHiQcLhXJ98AGWOAL1TUjdkCKiw cfK3c11il/LI7k00NfS0hPI/oLPvPiPBPRoAOMngD9FgUwTp/EGUyyH2ZeoQ== X-Developer-Key: i=keescook@chromium.org; a=openpgp; fpr=A5C3F68F229DD60F723E6E138972F4DFDC6DC026 X-Spam-Status: No, score=-0.2 required=5.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1762383569231923975?= X-GMAIL-MSGID: =?utf-8?q?1762383569231923975?= From: Kees Cook Improve the reporting of buffer overflows under CONFIG_FORTIFY_SOURCE to help accelerate debugging efforts. The calculations are all just sitting in registers anyway, so pass them along to the function to be reported. For example, before: detected buffer overflow in memcpy and after: memcpy: detected buffer overflow: 4096 byte read from buffer of size 1 Signed-off-by: Kees Cook --- include/linux/fortify-string.h | 60 +++++++++++++++++++--------------- lib/fortify_kunit.c | 4 +-- lib/string_helpers.c | 9 ++--- 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h index 2bbee7b28e71..d37f4597cf68 100644 --- a/include/linux/fortify-string.h +++ b/include/linux/fortify-string.h @@ -14,8 +14,8 @@ #ifdef FORTIFY_KUNIT_OVERRIDE # define fortify_panic kunit_fortify_panic #else -# define fortify_panic(func, write, retfail) \ - __fortify_panic(fortify_reason(func, write)) +# define fortify_panic(func, write, avail, size, retfail) \ + __fortify_panic(fortify_reason(func, write), avail, size) #endif #define FORTIFY_READ 0 @@ -39,8 +39,8 @@ #define FORTIFY_FUNC_kmemdup 15 #define FORTIFY_FUNC_strcpy 16 -void __fortify_report(u8 reason); -void __fortify_panic(u8 reason) __cold __noreturn; +void __fortify_report(const u8 reason, const size_t avail, const size_t size); +void __fortify_panic(const u8 reason, const size_t avail, const size_t size) __cold __noreturn; void __read_overflow(void) __compiletime_error("detected read beyond size of object (1st parameter)"); void __read_overflow2(void) __compiletime_error("detected read beyond size of object (2nd parameter)"); void __read_overflow2_field(size_t avail, size_t wanted) __compiletime_warning("detected read beyond size of field (2nd parameter); maybe use struct_group()?"); @@ -178,7 +178,7 @@ char *strncpy(char * const POS p, const char *q, __kernel_size_t size) if (__compiletime_lessthan(p_size, size)) __write_overflow(); if (p_size < size) - fortify_panic(FORTIFY_FUNC_strncpy, FORTIFY_WRITE, p); + fortify_panic(FORTIFY_FUNC_strncpy, FORTIFY_WRITE, p_size, size, p); return __underlying_strncpy(p, q, size); } @@ -209,7 +209,7 @@ __FORTIFY_INLINE __kernel_size_t strnlen(const char * const POS p, __kernel_size /* Do not check characters beyond the end of p. */ ret = __real_strnlen(p, maxlen < p_size ? maxlen : p_size); if (p_size <= ret && maxlen != ret) - fortify_panic(FORTIFY_FUNC_strnlen, FORTIFY_READ, ret); + fortify_panic(FORTIFY_FUNC_strnlen, FORTIFY_READ, p_size, ret + 1, ret); return ret; } @@ -245,7 +245,7 @@ __kernel_size_t __fortify_strlen(const char * const POS p) return __underlying_strlen(p); ret = strnlen(p, p_size); if (p_size <= ret) - fortify_panic(FORTIFY_FUNC_strlen, FORTIFY_READ, ret); + fortify_panic(FORTIFY_FUNC_strlen, FORTIFY_READ, p_size, ret + 1, ret); return ret; } @@ -286,8 +286,8 @@ __FORTIFY_INLINE size_t strlcpy(char * const POS p, const char * const POS q, si __write_overflow(); } if (size) { - if (len >= p_size) - fortify_panic(FORTIFY_FUNC_strlcpy, FORTIFY_WRITE, q_len); + if (p_size <= len) + fortify_panic(FORTIFY_FUNC_strlcpy, FORTIFY_WRITE, p_size, len + 1, q_len); __underlying_memcpy(p, q, len); p[len] = '\0'; } @@ -364,8 +364,8 @@ __FORTIFY_INLINE ssize_t strscpy(char * const POS p, const char * const POS q, s * Generate a runtime write overflow error if len is greater than * p_size. */ - if (len > p_size) - fortify_panic(FORTIFY_FUNC_strscpy, FORTIFY_WRITE, -E2BIG); + if (p_size < len) + fortify_panic(FORTIFY_FUNC_strscpy, FORTIFY_WRITE, p_size, len, -E2BIG); /* * We can now safely call vanilla strscpy because we are protected from: @@ -423,7 +423,7 @@ size_t strlcat(char * const POS p, const char * const POS q, size_t avail) /* Give up if string is already overflowed. */ if (p_size <= p_len) - fortify_panic(FORTIFY_FUNC_strlcat, FORTIFY_READ, wanted); + fortify_panic(FORTIFY_FUNC_strlcat, FORTIFY_READ, p_size, p_len + 1, wanted); if (actual >= avail) { copy_len = avail - p_len - 1; @@ -432,7 +432,7 @@ size_t strlcat(char * const POS p, const char * const POS q, size_t avail) /* Give up if copy will overflow. */ if (p_size <= actual) - fortify_panic(FORTIFY_FUNC_strlcat, FORTIFY_WRITE, wanted); + fortify_panic(FORTIFY_FUNC_strlcat, FORTIFY_WRITE, p_size, actual + 1, wanted); __underlying_memcpy(p + p_len, q, copy_len); p[actual] = '\0'; @@ -459,9 +459,11 @@ __FORTIFY_INLINE __diagnose_as(__builtin_strcat, 1, 2) char *strcat(char * const POS p, const char *q) { size_t p_size = __member_size(p); + size_t wanted; - if (strlcat(p, q, p_size) >= p_size) - fortify_panic(FORTIFY_FUNC_strcat, FORTIFY_WRITE, p); + wanted = strlcat(p, q, p_size); + if (p_size <= wanted) + fortify_panic(FORTIFY_FUNC_strcat, FORTIFY_WRITE, p_size, wanted + 1, p); return p; } @@ -491,13 +493,15 @@ char *strncat(char * const POS p, const char * const POS q, __kernel_size_t coun size_t p_len, copy_len; size_t p_size = __member_size(p); size_t q_size = __member_size(q); + size_t total; if (p_size == SIZE_MAX && q_size == SIZE_MAX) 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(FORTIFY_FUNC_strncat, FORTIFY_WRITE, p); + total = p_len + copy_len + 1; + if (p_size < total) + fortify_panic(FORTIFY_FUNC_strncat, FORTIFY_WRITE, p_size, total, p); __underlying_memcpy(p + p_len, q, copy_len); p[p_len + copy_len] = '\0'; return p; @@ -538,7 +542,7 @@ __FORTIFY_INLINE bool fortify_memset_chk(__kernel_size_t size, * lengths are unknown.) */ if (p_size != SIZE_MAX && p_size < size) - fortify_panic(FORTIFY_FUNC_memset, FORTIFY_WRITE, true); + fortify_panic(FORTIFY_FUNC_memset, FORTIFY_WRITE, p_size, size, true); return false; } @@ -638,9 +642,9 @@ __FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size, * lengths are unknown.) */ if (p_size != SIZE_MAX && p_size < size) - fortify_panic(func, FORTIFY_WRITE, true); + fortify_panic(func, FORTIFY_WRITE, p_size, size, true); else if (q_size != SIZE_MAX && q_size < size) - fortify_panic(func, FORTIFY_READ, true); + fortify_panic(func, FORTIFY_READ, p_size, size, true); /* * Warn when writing beyond destination field size. @@ -740,7 +744,7 @@ __FORTIFY_INLINE void *memscan(void * const POS0 p, int c, __kernel_size_t size) if (__compiletime_lessthan(p_size, size)) __read_overflow(); if (p_size < size) - fortify_panic(FORTIFY_FUNC_memscan, FORTIFY_READ, NULL); + fortify_panic(FORTIFY_FUNC_memscan, FORTIFY_READ, p_size, size, NULL); return __real_memscan(p, c, size); } @@ -756,8 +760,10 @@ int memcmp(const void * const POS0 p, const void * const POS0 q, __kernel_size_t if (__compiletime_lessthan(q_size, size)) __read_overflow2(); } - if (p_size < size || q_size < size) - fortify_panic(FORTIFY_FUNC_memcmp, FORTIFY_READ, INT_MIN); + if (p_size < size) + fortify_panic(FORTIFY_FUNC_memcmp, FORTIFY_READ, p_size, size, INT_MIN); + else if (q_size < size) + fortify_panic(FORTIFY_FUNC_memcmp, FORTIFY_READ, q_size, size, INT_MIN); return __underlying_memcmp(p, q, size); } @@ -769,7 +775,7 @@ void *memchr(const void * const POS0 p, int c, __kernel_size_t size) if (__compiletime_lessthan(p_size, size)) __read_overflow(); if (p_size < size) - fortify_panic(FORTIFY_FUNC_memchr, FORTIFY_READ, NULL); + fortify_panic(FORTIFY_FUNC_memchr, FORTIFY_READ, p_size, size, NULL); return __underlying_memchr(p, c, size); } @@ -781,7 +787,7 @@ __FORTIFY_INLINE void *memchr_inv(const void * const POS0 p, int c, size_t size) if (__compiletime_lessthan(p_size, size)) __read_overflow(); if (p_size < size) - fortify_panic(FORTIFY_FUNC_memchr_inv, FORTIFY_READ, NULL); + fortify_panic(FORTIFY_FUNC_memchr_inv, FORTIFY_READ, p_size, size, NULL); return __real_memchr_inv(p, c, size); } @@ -794,7 +800,7 @@ __FORTIFY_INLINE void *kmemdup(const void * const POS0 p, size_t size, gfp_t gfp if (__compiletime_lessthan(p_size, size)) __read_overflow(); if (p_size < size) - fortify_panic(FORTIFY_FUNC_kmemdup, FORTIFY_READ, NULL); + fortify_panic(FORTIFY_FUNC_kmemdup, FORTIFY_READ, p_size, size, NULL); return __real_kmemdup(p, size, gfp); } @@ -831,7 +837,7 @@ char *strcpy(char * const POS p, const char * const POS q) __write_overflow(); /* Run-time check for dynamic size overflow. */ if (p_size < size) - fortify_panic(FORTIFY_FUNC_strcpy, FORTIFY_WRITE, p); + fortify_panic(FORTIFY_FUNC_strcpy, FORTIFY_WRITE, p_size, size, p); __underlying_memcpy(p, q, size); return p; } diff --git a/lib/fortify_kunit.c b/lib/fortify_kunit.c index b7c884037629..b022797c9fe6 100644 --- a/lib/fortify_kunit.c +++ b/lib/fortify_kunit.c @@ -18,9 +18,9 @@ /* Call kunit_fortify_panic() instead of fortify_panic() */ #define FORTIFY_KUNIT_OVERRIDE void fortify_add_kunit_error(int write); -#define kunit_fortify_panic(func, write, retfail) \ +#define kunit_fortify_panic(func, write, avail, size, retfail) \ do { \ - __fortify_report(fortify_reason(func, write)); \ + __fortify_report(fortify_reason(func, write), avail, size); \ fortify_add_kunit_error(write); \ return (retfail); \ } while (0) diff --git a/lib/string_helpers.c b/lib/string_helpers.c index 5bb65f623e40..cc15a25556fb 100644 --- a/lib/string_helpers.c +++ b/lib/string_helpers.c @@ -1023,7 +1023,7 @@ EXPORT_SYMBOL(__read_overflow2_field); void __write_overflow_field(size_t avail, size_t wanted) { } EXPORT_SYMBOL(__write_overflow_field); -void __fortify_report(u8 reason) +void __fortify_report(const u8 reason, const size_t avail, const size_t size) { const char *name; const bool write = !!(reason & 0x1); @@ -1083,13 +1083,14 @@ void __fortify_report(u8 reason) default: name = "unknown"; } - WARN(1, "%s: detected buffer %s overflow\n", name, write ? "write" : "read"); + WARN(1, "%s: detected buffer overflow: %zu byte %s buffer of size %zu\n", + name, size, write ? "write to" : "read from", avail); } EXPORT_SYMBOL(__fortify_report); -void __fortify_panic(const u8 reason) +void __fortify_panic(const u8 reason, const size_t avail, const size_t size) { - __fortify_report(reason); + __fortify_report(reason, avail, size); BUG(); } EXPORT_SYMBOL(__fortify_panic);