From nobody Fri Sep 25 20:47:43 2026 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5BA4358E2C0 for ; Tue, 8 Sep 2026 16:55:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886505; cv=none; b=gkeUwH0L0JmP3MRp+Zx99S8g+s10+mLzJVNbKcwIxr9vuss09O7l/RbG3zwZ2yPXsCMh5fUbAfFJpOg4umzmuKDuQPkxn6woFys6BvepM7adBLJ2V4nzddkd/nV8Nxe/MTwDrCQ0WWELcStsd0WKu2w3LQ043yY4FO1v/KLrweY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886505; c=relaxed/simple; bh=fbhmEJLe+fv6wmnOQ+SkOQQ7U1O9RdjLzXOBxFO1BRs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=TRDF62WqOg4xmGUILlu0zm1l2Ir717ZlyszwOwYbjf8X8Q0jy7Lsi+Dj966jB2m9sIWoNwkB8e07JOSu1e8DQHkWpDgT+dRK/2yvqH63aqnRfvbhJVv65zplVUSlRRkx6P5x6JAOuYsmmb+Y54wE2geADU3/7KGrqoLtCW9Abhc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=DkPr01mJ; arc=none smtp.client-ip=74.125.225.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="DkPr01mJ" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-49cff3b3b92so96905e9.1 for ; Tue, 08 Sep 2026 09:55:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788886502; x=1789491302; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=FysVnPArrErIx2WaY61CSIH8v7xlwTnQSJCtiIE9LJg=; b=DkPr01mJEujKeCoXpA2hOz1Uy6qqbEvusb4HIAgZo4Hqk3e54ztY5WPSHN+7jeXGvS PtkYFsR9Rwz+SxWmmkFf7nidT9BqRGexQJyf+gTSoKhw1Zd5Cuaq/tGQ0eOUV28oECvy BUg5TyH0oXDHdHHxHSALvAiI4f30tGA7EFjx9+Vq0YGGcsszZaq3Wq9Nh9pCiA0cmO69 sJeAnsYUpgv6xwTqesWB/Btvrnrn0VLfiTrF3cqghAPpPk7OXlbgn20HNP+zlUUm+ucV EpStczgsRdrxiT0WlbQosP9iSq9Ar5Z14daJPQh7vbGa6gQEFOXi8cGhXa3QmT9ZuFc+ QHYQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788886502; x=1789491302; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=FysVnPArrErIx2WaY61CSIH8v7xlwTnQSJCtiIE9LJg=; b=U6tGMkEC+F1x/K2YJiTqW4nGcJiHM+BIqCMtkt9z3YL2TR31koQatA9S+IJc07V2eJ hKR7TslCO9A+cBpCcIVGPowopQnt3iP/S6SOO7tjSwmHDZptrhRoh1BJ2XQsPXxv5w4I pvLPbFKWZQ+pt+9Ib4M7O70o5R+5DPyo+Iu7WbxXFjVQhIrnwzV6e+H0cHd9KaIQg/VF pt7hlb/KpLoGAs6afKhXaKtvMi0FTjxa7diE0OLfO2EQbHuZKe5MM60z8G4DFC5XhtFR nbSpFM2ueS+VOcfGdQ5ZE2Z97HAjK/D+c+zDWEMVSPdHNRWXwX04Y+92v5E/u7W3Hiuv IKgw== X-Forwarded-Encrypted: i=1; AKwUvBy0F7FIEv3GI6uFsxQSIgbugKHZqmseAdNprzy7dkI9DE0/K3ZH8afkqObhWYMcxh+QlzrKkBJjdGphYHA=@vger.kernel.org X-Gm-Message-State: AFuF++klNCJqNJ85XR/0PTKB/u59bQIOAEobnO/FB3uKkOr9PjiVqNyW QLy3CKmgNnWjTTclRiMRR4x0W+9TNL/682L3E4yRuY4sn0ydUZrRM+n/DFINMYRicA== X-Gm-Gg: AYBFou1RBIG9lX0IiqwPHypUfE/nzfu6AHEnqmQcxHIkgD61Lw+epz3R0MBvzjwUDzR 0HvAVX993VsU4gw8Bvz/8fZHEzJhcVJhNCahqwtvi1iJlt2xWk2ck2aK14hqZXZ9D8DIWw8+jC7 l//mdt0hdEDitFI5m77rNJ9W30ZMhjUpWnlfdovmcv5OfEjeilI520XEzUkQid0I4KQCVgmae7B ILsKbLFbWdqSvw4Xb7st9CAYKbzcvTYeuWBybIbEsjGJqboxaKZJn3CwiqXKjU8O/IXdXBbKJiW fy2m5jnoZtGJ9AKfr7AdNZqcvejNS4IKIbGLTrZRgTWvHHLyNsy/L/ylEU36nzumfobOclVZsff cKn1zVan+42WMsMsofEAt453sPV0iXyCUTuQRlh/BUeZeUtOfDPjQ6TpUP1qJk1fZBI5fLZZpFa cfdMijdFL1z5RqvvFTztoCxBFKpwPdWLm1DyL4Uaexj/uquen1OxYwR55zfZh9zzxnJeoDV2WKq FDaWv9yOCTtaNzNxnLFn/hheU66dkCYLpt7Vd73Ms3tU+4sGw== X-Received: by 2002:a05:600c:321a:b0:499:c5f8:6773 with SMTP id 5b1f17b1804b1-49d1f3c671cmr43385e9.1.1788886501174; Tue, 08 Sep 2026 09:55:01 -0700 (PDT) Received: from localhost ([2a00:79e0:288a:8:ac21:220d:3908:7e61]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-48588135600sm32881768f8f.2.2026.09.08.09.55.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 09:55:00 -0700 (PDT) From: Jann Horn Date: Tue, 08 Sep 2026 18:54:41 +0200 Subject: [PATCH RFC v3 01/12] kcov: wire up compiler instrumentation for CONFIG_KCOV_EXT_RECORDS Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260908-kcov-extrecord-v3-1-dcbc11593e88@google.com> References: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> In-Reply-To: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> To: Dmitry Vyukov , Andrey Konovalov , Alexander Potapenko Cc: Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, llvm@lists.linux.dev, Jann Horn X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788886494; l=5490; i=jannh@google.com; s=20240730; h=from:subject:message-id; bh=fbhmEJLe+fv6wmnOQ+SkOQQ7U1O9RdjLzXOBxFO1BRs=; b=xC0J7K86WvjhjpkFg4np6v4fDVR4B9bGKONZpAv7YX+g0Q4BMzsypH3bF+lvko3zB+SJG4naq 0QBEJWkWnhcAUTR7X5fNCJbZg5/mVmI9SSPppgASzA+IrR+Ibrh4ll5 X-Developer-Key: i=jannh@google.com; a=ed25519; pk=AljNtGOzXeF6khBXDJVVvwSEkVDGnnZZYqfWhP1V+C8= This is the first half of CONFIG_KCOV_EXT_RECORDS. Set the appropriate compiler flags to call separate hooks for function entry/exit, and provide these hooks, but don't make it visible in the KCOV UAPI yet. With -fsanitize-coverage=3Dtrace-pc-entry-exit, the compiler behavior chang= es as follows: - The __sanitizer_cov_trace_pc() call on function entry is replaced with a call to __sanitizer_cov_trace_pc_entry(); so for now, __sanitizer_cov_trace_pc_entry() must be treated the same way as __sanitizer_cov_trace_pc(). - On function exit, an extra call to __sanitizer_cov_trace_pc_exit() happens; since function exit produced no coverage in the old UAPI, __sanitizer_cov_trace_pc_exit() should do nothing for now. This feature was added to LLVM in commit: https://github.com/llvm/llvm-project/commit/dc5c6d008f487eea8f5d646011f9b3d= ca6caebd7 Reviewed-by: Dmitry Vyukov Signed-off-by: Jann Horn --- include/linux/kcov.h | 2 ++ kernel/kcov.c | 34 +++++++++++++++++++++++++++------- lib/Kconfig.debug | 12 ++++++++++++ scripts/Makefile.kcov | 2 ++ tools/objtool/check.c | 2 ++ 5 files changed, 45 insertions(+), 7 deletions(-) diff --git a/include/linux/kcov.h b/include/linux/kcov.h index 895b761b2db1..cd79715db241 100644 --- a/include/linux/kcov.h +++ b/include/linux/kcov.h @@ -79,6 +79,8 @@ typedef unsigned long long kcov_u64; #endif =20 void __sanitizer_cov_trace_pc(void); +void __sanitizer_cov_trace_pc_entry(void); +void __sanitizer_cov_trace_pc_exit(void); void __sanitizer_cov_trace_cmp1(u8 arg1, u8 arg2); void __sanitizer_cov_trace_cmp2(u16 arg1, u16 arg2); void __sanitizer_cov_trace_cmp4(u32 arg1, u32 arg2); diff --git a/kernel/kcov.c b/kernel/kcov.c index 35420f0ac524..5d9686c8b3ec 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -198,15 +198,10 @@ static notrace unsigned long canonicalize_ip(unsigned= long ip) return ip; } =20 -/* - * Entry point from instrumented code. - * This is called once per basic-block/edge. - */ -void notrace __sanitizer_cov_trace_pc(void) +static __always_inline void notrace kcov_add_pc_record(unsigned long recor= d) { struct task_struct *t; unsigned long *area; - unsigned long ip =3D canonicalize_ip(_RET_IP_); unsigned long pos; =20 t =3D current; @@ -226,11 +221,36 @@ void notrace __sanitizer_cov_trace_pc(void) */ WRITE_ONCE(area[0], pos); barrier(); - area[pos] =3D ip; + area[pos] =3D record; } } + +/* + * Entry point from instrumented code. + * This is called once per basic-block/edge. + */ +void notrace __sanitizer_cov_trace_pc(void) +{ + kcov_add_pc_record(canonicalize_ip(_RET_IP_)); +} EXPORT_SYMBOL(__sanitizer_cov_trace_pc); =20 +#ifdef CONFIG_KCOV_EXT_RECORDS +void notrace __sanitizer_cov_trace_pc_entry(void) +{ + unsigned long record =3D canonicalize_ip(_RET_IP_); + + /* + * This hook replaces __sanitizer_cov_trace_pc() for the function entry + * basic block; it should still emit a record even in classic kcov mode. + */ + kcov_add_pc_record(record); +} +void notrace __sanitizer_cov_trace_pc_exit(void) +{ +} +#endif + #ifdef CONFIG_KCOV_ENABLE_COMPARISONS static void notrace write_comp_data(u64 type, u64 arg1, u64 arg2, u64 ip) { diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index a2f0d3e97889..6ddf58692b09 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2195,6 +2195,18 @@ config KCOV =20 For more details, see Documentation/dev-tools/kcov.rst. =20 +config KCOV_EXT_RECORDS + bool "Support extended KCOV records with function entry/exit records" + depends on KCOV + depends on 64BIT + depends on $(cc-option,-fsanitize-coverage=3Dtrace-pc-entry-exit) + help + Extended KCOV records allow distinguishing between multiple types of + records: Normal edge coverage, function entry, and function exit. + + This will likely cause a small additional slowdown compared to normal + KCOV. + config KCOV_ENABLE_COMPARISONS bool "Enable comparison operands collection by KCOV" depends on KCOV diff --git a/scripts/Makefile.kcov b/scripts/Makefile.kcov index 78305a84ba9d..aa0be904268f 100644 --- a/scripts/Makefile.kcov +++ b/scripts/Makefile.kcov @@ -1,10 +1,12 @@ # SPDX-License-Identifier: GPL-2.0-only kcov-flags-y +=3D -fsanitize-coverage=3Dtrace-pc +kcov-flags-$(CONFIG_KCOV_EXT_RECORDS) +=3D -fsanitize-coverage=3Dtrace-pc= -entry-exit kcov-flags-$(CONFIG_KCOV_ENABLE_COMPARISONS) +=3D -fsanitize-coverage=3Dtr= ace-cmp =20 kcov-rflags-y +=3D -Cpasses=3Dsancov-module kcov-rflags-y +=3D -Cllvm-args=3D-sanitizer-coverage-level=3D3 kcov-rflags-y +=3D -Cllvm-args=3D-sanitizer-coverage-trace-pc +kcov-rflags-$(CONFIG_KCOV_EXT_RECORDS) +=3D -Cllvm-args=3D-sanitizer-cove= rage-trace-pc-entry-exit kcov-rflags-$(CONFIG_KCOV_ENABLE_COMPARISONS) +=3D -Cllvm-args=3D-sanitize= r-coverage-trace-compares =20 export CFLAGS_KCOV :=3D $(kcov-flags-y) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index df04e6be2f66..d70cb640e2ec 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1220,6 +1220,8 @@ static const char *uaccess_safe_builtin[] =3D { "write_comp_data", "check_kcov_mode", "__sanitizer_cov_trace_pc", + "__sanitizer_cov_trace_pc_entry", + "__sanitizer_cov_trace_pc_exit", "__sanitizer_cov_trace_const_cmp1", "__sanitizer_cov_trace_const_cmp2", "__sanitizer_cov_trace_const_cmp4", --=20 2.55.0.979.g7e5102b832-goog From nobody Fri Sep 25 20:47:43 2026 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2D4BD58F068 for ; Tue, 8 Sep 2026 16:55:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886507; cv=none; b=cC5ErZE7MwGnU4KlKfGVLWJZogzz1C/qBH8qM3mLAFXgBPhsImWN9hcH8HKYu+UUhrm4+HJU6gc4+zW6R30jWgl/7C/u26OmqWWHzXxgvFB80XGVkLTTXzST2GQxa9lBHjA5kuFPV8DCSSTg0dZjYDMA6xEflehDggyhW9OJjzQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886507; c=relaxed/simple; bh=zMSdv79W/28vOlNus87Hr0NP1H4bhJbv+hYzEQlIBho=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=to0ao2YsCtmeIzZ9qqPr++85ejiutlA5e8w6olNmXzEjk6k7SD+9DbcbedrTOc2kk8P2naCKAy9CmqziqmfohYG+/NDhtctMAYaCVkb6YkcA0RtN72TD5OgMPqOxw8QmjlPkSTKkZDqr7Jnn0DdW/juEsM+olbIA6mStTrtSzeE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=h5L5LCUT; arc=none smtp.client-ip=74.125.225.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="h5L5LCUT" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-49ccf3bc34cso140755e9.0 for ; Tue, 08 Sep 2026 09:55:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788886503; x=1789491303; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=0RnG64ZBEYmtca9ZKg3SGvzKLOcbOD+eKnvKZpxSN+E=; b=h5L5LCUTJ8+sgQIq8Z+Hs7sTN/aCB2n3BtV7MaOjP0TcXCveZY/T4wQ/fX9j3svQkl e4HVnr2xw3lDkpEjuiffo4rwiFdi1efL/7eyGC5o3K9PRefwK1DEiLiPB3zfHfUhTQvK G92WqWee9eRuZBdoXgotmiDrAjzBhuU/XcpjtbwvAOpu8jkoeUc7Xqls47kbUk4ZEtNn OmhpxTBk2lwB8XEeli96Xo0Htel2ubZSweKNZcIrpPmkQjMQ0SJcb1TLY5MSdRRYqz0/ 6zq91D7/TlkDFibQEqw7peggqBZ24WRwJZb2rJOyseogTVRhlkQgaeJNchtLJ6AtrsiO 5YMg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788886503; x=1789491303; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=0RnG64ZBEYmtca9ZKg3SGvzKLOcbOD+eKnvKZpxSN+E=; b=cIcTPOXWiIECoZvTy0bS2wzsQGyvSOXK4y7JwA8iGQ4FqE+dNQD8mmrYpBT7oua4G4 x/SieBdoPHEDKKzeEGJRv+HjSrNap+RZHpA1D9Zs/YEKzmSu0JueRIXISsPa+jnk+Iw4 ecNVcIqz82FzaHV041N7i3CfnjdXWHYxHnB7Lhe5YhOc3xtJwy7PubfSJ2wGoeFaW0l6 kSVwpkOmCY/+Mw2Udn5ODvJQV/XemdKp/0ysQUR+nox/54Hsj4VghxZm434eM0cC6FUA jVsyYZ+gc4bMuO8lnBCkpMjTH8DcZwU/xRVRm1XfhSxnSbY4hqvI+5ui92OEtZeX5Lmv 3Z9w== X-Forwarded-Encrypted: i=1; AKwUvBwOMBQLr2FZmUAsiMtsX3Ym1LmjYEVywLwaAeh2VkRwx357uaMGVvv9fBKaSKTIgdEi2gBZyExIWdABJUg=@vger.kernel.org X-Gm-Message-State: AFuF++nZqgVMp5z1+ra3SAnVx+ejD1dPeei96W2V4TwXtXxxV9sFqQSc wVbQ5+ucIsVNQogaAiIQ6blgSWPtKmLvX/eshVmekZjk1jJ2WSKNyDKFWl4qR0499A== X-Gm-Gg: AYBFou2CWFv09Tr25ZuneVo8Hem9wQeObD6U2Rd2fPcj7XIBuAha799laVgqBZNn76L NKED48LgeefaYfAEx51WKOc11IxpaC9UZWOJSoWlfNPdwbnFbuIMKZMx+wgIPmP2Eq8mlYoInml rMNoQn7BNX/dw9WPXv3k9b+9+fPpAQOqGkY4VHUQFOyvgCEr4wxpSR6ZhBiIvItlcujADrzQp1w 0aPUb1pQ3UZVWDM36C48l9V43WFbZ2DEE4V3ourvOuPk9nkisE2n996100QZ0bNelozpo80oUJe vmqbPCVt51IO7fIeq6qJTVYGIhCncEd3xMmXEs8LWUFnD9mkGIYb6v9XROTHxOG5ylq9WoKKukI PFYhtY9JBE7VfrP8pLVSXsbgwAc4re2wpb7YF+j8Lo61syFuPzdi/BTwy9svxNATs6Jg03uwzBo +Id9aqWJu/GsRGMYKZSS6nXyM0vAgwcjMiUjy/IjKHxAhpwbOACKuY77jzSsNTvMpgUd0ISOvON 30i28/GAuCk3eA6XBZfJIzQQ9f6Y2Mz5fU3MX6VP7mYWutw X-Received: by 2002:a05:600d:8498:20b0:49b:c90:e1ee with SMTP id 5b1f17b1804b1-49d1f6edc70mr25955e9.11.1788886502918; Tue, 08 Sep 2026 09:55:02 -0700 (PDT) Received: from localhost ([2a00:79e0:288a:8:ac21:220d:3908:7e61]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-48588392b3esm42560497f8f.12.2026.09.08.09.55.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 09:55:02 -0700 (PDT) From: Jann Horn Date: Tue, 08 Sep 2026 18:54:42 +0200 Subject: [PATCH RFC v3 02/12] kcov: refactor mode check out of check_kcov_mode() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260908-kcov-extrecord-v3-2-dcbc11593e88@google.com> References: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> In-Reply-To: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> To: Dmitry Vyukov , Andrey Konovalov , Alexander Potapenko Cc: Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, llvm@lists.linux.dev, Jann Horn X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788886494; l=4314; i=jannh@google.com; s=20240730; h=from:subject:message-id; bh=zMSdv79W/28vOlNus87Hr0NP1H4bhJbv+hYzEQlIBho=; b=dc+rBp1W+qTZPJAb2xVJwbP8NlsZyRFXM4Sx2H+OrYfUbG/leu3BWxB4V4UE2C9jlKusRh70p pgZDfOg+3/aBNHPOcsYwX4To6jVbLUPym3MCTzTQ3ybFpAbQtTc89Ns X-Developer-Key: i=jannh@google.com; a=ed25519; pk=AljNtGOzXeF6khBXDJVVvwSEkVDGnnZZYqfWhP1V+C8= The following patch will need to check t->kcov_mode in different ways at different check_kcov_mode() call sites. In preparation for that, move the mode check up the call hierarchy. Signed-off-by: Jann Horn --- kernel/kcov.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/kernel/kcov.c b/kernel/kcov.c index 5d9686c8b3ec..26baccaaefa9 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -167,10 +167,8 @@ static __always_inline bool in_softirq_really(void) return in_serving_softirq() && !in_hardirq() && !in_nmi(); } =20 -static notrace bool check_kcov_mode(enum kcov_mode needed_mode, struct tas= k_struct *t) +static notrace bool check_kcov_context(struct task_struct *t) { - unsigned int mode; - /* * We are interested in code coverage as a function of a syscall inputs, * so we ignore code executed in interrupts, unless we are in a remote @@ -178,7 +176,6 @@ static notrace bool check_kcov_mode(enum kcov_mode need= ed_mode, struct task_stru */ if (!in_task() && !(in_softirq_really() && t->kcov_softirq)) return false; - mode =3D READ_ONCE(t->kcov_mode); /* * There is some code that runs in interrupts but for which * in_interrupt() returns false (e.g. preempt_schedule_irq()). @@ -187,7 +184,7 @@ static notrace bool check_kcov_mode(enum kcov_mode need= ed_mode, struct task_stru * kcov_start(). */ barrier(); - return mode =3D=3D needed_mode; + return true; } =20 static notrace unsigned long canonicalize_ip(unsigned long ip) @@ -198,14 +195,12 @@ static notrace unsigned long canonicalize_ip(unsigned= long ip) return ip; } =20 -static __always_inline void notrace kcov_add_pc_record(unsigned long recor= d) +static __always_inline void notrace kcov_add_pc_record(struct task_struct = *t, unsigned long record) { - struct task_struct *t; unsigned long *area; unsigned long pos; =20 - t =3D current; - if (!check_kcov_mode(KCOV_MODE_TRACE_PC, t)) + if (!check_kcov_context(t)) return; =20 area =3D t->kcov_area; @@ -213,7 +208,7 @@ static __always_inline void notrace kcov_add_pc_record(= unsigned long record) pos =3D READ_ONCE(area[0]) + 1; if (likely(pos < t->kcov_size)) { /* Previously we write pc before updating pos. However, some - * early interrupt code could bypass check_kcov_mode() check + * early interrupt code could bypass check_kcov_context() check * and invoke __sanitizer_cov_trace_pc(). If such interrupt is * raised between writing pc and updating pos, the pc could be * overitten by the recursive __sanitizer_cov_trace_pc(). @@ -231,20 +226,28 @@ static __always_inline void notrace kcov_add_pc_recor= d(unsigned long record) */ void notrace __sanitizer_cov_trace_pc(void) { - kcov_add_pc_record(canonicalize_ip(_RET_IP_)); + struct task_struct *cur =3D current; + + if (READ_ONCE(cur->kcov_mode) !=3D KCOV_MODE_TRACE_PC) + return; + kcov_add_pc_record(cur, canonicalize_ip(_RET_IP_)); } EXPORT_SYMBOL(__sanitizer_cov_trace_pc); =20 #ifdef CONFIG_KCOV_EXT_RECORDS void notrace __sanitizer_cov_trace_pc_entry(void) { + struct task_struct *cur =3D current; unsigned long record =3D canonicalize_ip(_RET_IP_); + unsigned int kcov_mode =3D READ_ONCE(cur->kcov_mode); =20 /* * This hook replaces __sanitizer_cov_trace_pc() for the function entry * basic block; it should still emit a record even in classic kcov mode. */ - kcov_add_pc_record(record); + if (kcov_mode !=3D KCOV_MODE_TRACE_PC) + return; + kcov_add_pc_record(cur, record); } void notrace __sanitizer_cov_trace_pc_exit(void) { @@ -259,7 +262,7 @@ static void notrace write_comp_data(u64 type, u64 arg1,= u64 arg2, u64 ip) u64 count, start_index, end_pos, max_pos; =20 t =3D current; - if (!check_kcov_mode(KCOV_MODE_TRACE_CMP, t)) + if (READ_ONCE(t->kcov_mode) !=3D KCOV_MODE_TRACE_CMP || !check_kcov_conte= xt(t)) return; =20 ip =3D canonicalize_ip(ip); @@ -379,7 +382,7 @@ static void kcov_start(struct task_struct *t, struct kc= ov *kcov, t->kcov_size =3D size; t->kcov_area =3D area; t->kcov_sequence =3D sequence; - /* See comment in check_kcov_mode(). */ + /* See comment in check_kcov_context(). */ barrier(); WRITE_ONCE(t->kcov_mode, mode); } --=20 2.55.0.979.g7e5102b832-goog From nobody Fri Sep 25 20:47:43 2026 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C24AD58F080 for ; Tue, 8 Sep 2026 16:55:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886509; cv=none; b=daI6kI8bxc2AwUk9VxDw99XjQVh5hlcYKbc4e4zxgEPhtzQaDdJjnAIGvzpn0qDtun/4Os9D95/x3hJo5VkJEYWGuQhiWBF5yYfAskCuiWV9tov5yxbgZ25whKCltfvywHZy1nWcD59Y8vJ7yCEwUIeHwjkZvtcko4TOrnOzoHQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886509; c=relaxed/simple; bh=vkxeQ7PpkZnIrliC5/UORrRPv5LIO5nBtwshLbwdaTk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=SqIAkMv6MyI1ddA5R+WuLSgWLVpyrp5eJWswQNVysjYjLjU8BDxijRNDjlIdCkLSRJYgdK98gsjnbtd1WRYVdj0RNYEji14/FzGoso7NUG4rm4rMS8q5qTjvlAaoWeWr9QdGig7GL5/L1VtlREMGvEySp3W3vIvWg6NCp5DLagM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=lzATzC7P; arc=none smtp.client-ip=74.125.225.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="lzATzC7P" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-49cda5e048fso145365e9.0 for ; Tue, 08 Sep 2026 09:55:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788886506; x=1789491306; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=qiIZFjtrQa9YVC8NnwzXWfF3N1VkZxLZmC07XgW9jKw=; b=lzATzC7PbReH6C/5QSIOVAbiinFbw+MnB/TABS6/qTtFpXD9wIPhYBMpU2kfH5XbHK 2OED7ksjtq8xy3KHy5YHAp3ngTvohEmef7vvJB4zgcs33CdlTLKIpgegVQ0iBn11kmGi Zn8/usIXIFlwTY2WRuhHuP8BiKo+Zsavz8cFV9p7YiutehyGGH0mOJsMY3L7Vn7zFcHu HX1S5jk7FENmaJOuVzUJR5ZLo82JYUmI7vmHdLdj9Ae59LMGCs6YGZ5ZBSkpFSes1Mw8 e/paAhVnKBKerZZz4Lrc6Coyrnq7RgkJiXY9cKSoEUzg4h+gqWAHat2csUTw/YsU/MDF EMvQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788886506; x=1789491306; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=qiIZFjtrQa9YVC8NnwzXWfF3N1VkZxLZmC07XgW9jKw=; b=pAqdOcJ+qZwfKUja/CGIY8Idz1pAlIsuv+ku8R/BbMB1H7VJaqNdIGzBqjlJxfMr3Q JjjPedY3J2rQmWZOTb9XJ+K/sV1dz5qzPqDtJPX0M2ALmtv+XyfPM4+z1GzF0itWozqv VT1LA5v/k5wtAF1XXUgwET+VGYFWs/91jRhdSkkZueO76Qygkg8djHgFL7CXCnjV+64f VuRIm2DuCRBj62e93KrH2COq/L1q8UsOtDUl/00dildCyJulAlbD+S2yC6QZjzdRuB+Y OaKTXNgdRKGtT6eCq3V9+3AmU1NHHo1Xzc9rH9d/ssFDDcBBZNl+fJuabb/7MzCXSPJv KWTQ== X-Forwarded-Encrypted: i=1; AKwUvBy7t6BMS+O51OkiMZymug+gdI8R2s1zWwdZyvOaN1GqtlWwZiuKEnarMsXJgEoJ6Nmgis4NGZp0/s+dBOI=@vger.kernel.org X-Gm-Message-State: AFuF++lmIL2dbOV/W4vMYj7JjUQQz0Plaqx0jvYTyAJmQwvP3J1PSm02 /Hou1iVLoVSDVJCmgVf44kpygZfWhR2iaIQsjY13yLZ4Z80gxQuZb5vPXxgWDByCxg== X-Gm-Gg: AYBFou3e2jq6yL0bK2f2+qvLmSL5l/YZq3nFPX+ZZjKo8MOOTBvGtS3l4qVsvVyEw3G r/2i7dBCIfbg1XdPNzRIojGv6FIWaj+D6dFdWCsTIu6JYPn9gsEvEBYSu+/FjDXp5oDZHgzWYW5 MQXZB5G2aeT0OPWyI0sSvDVlLwVJNt7cTgey5yLtsaxDQe+WovxCTzqhcprrD5btRASOh2kMfWi 6pB93yb+HQYPyq1ioLH6CDlO3lIw7jX5T9dtNJh+ngdhlHs9uJht6wU1RJX6H+sz3EP/vbpy4+s ayOSpagWuwZKznzd60PPYit8qsMx/sJsI++5ENZ1z904tnuF7W1GHit+ACP1KWZTxkON+/f7PSK 6B8dZW3MTqTQsm0CInha2oKxe1HcJKbOccV/108BhH4PcCjeIbgM6Us4wWeK6ycZRlM5DsCZfUm EOIKwRDndLzLSoCAeySe6zyzXMhyUQZYZkCxJ2X3YYGyicpJbmNZAvMRKr5KoyS93FzzUJfwZRo wpUSLAhQsywc90ep+vs3Oda3JrQ80lY1MfJBjJsTHPU1X4B X-Received: by 2002:a05:600c:6a97:b0:49c:e41a:4c70 with SMTP id 5b1f17b1804b1-49d0918770cmr2097565e9.6.1788886505314; Tue, 08 Sep 2026 09:55:05 -0700 (PDT) Received: from localhost ([2a00:79e0:288a:8:ac21:220d:3908:7e61]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49d1fd5959fsm120175e9.1.2026.09.08.09.55.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 09:55:04 -0700 (PDT) From: Jann Horn Date: Tue, 08 Sep 2026 18:54:43 +0200 Subject: [PATCH RFC v3 03/12] kcov: introduce extended PC coverage collection mode Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260908-kcov-extrecord-v3-3-dcbc11593e88@google.com> References: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> In-Reply-To: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> To: Dmitry Vyukov , Andrey Konovalov , Alexander Potapenko Cc: Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, llvm@lists.linux.dev, Jann Horn X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788886494; l=5697; i=jannh@google.com; s=20240730; h=from:subject:message-id; bh=vkxeQ7PpkZnIrliC5/UORrRPv5LIO5nBtwshLbwdaTk=; b=gEpbf8x0BgtqSFhOstHU4jG4bB7vlFxCbBJc1ogoMSuZFEjT6kvAgF5YwRXxop60QwmVplyyS xB3JTB88r9ACi20cnFlyo7Xqa/+iuhVLeaiMuWq8EIobrGG7rivZKdF X-Developer-Key: i=jannh@google.com; a=ed25519; pk=AljNtGOzXeF6khBXDJVVvwSEkVDGnnZZYqfWhP1V+C8= This is the second half of CONFIG_KCOV_EXT_RECORDS. Introduce a new KCOV mode KCOV_TRACE_PC_EXT which replaces the upper 8 bits of recorded instruction pointers with metadata. For now, userspace can use this metadata to distinguish three types of records: - function entry - function exit - normal basic block inside the function Internally, this new mode is represented as a variant of KCOV_MODE_TRACE_PC, distinguished with the flag KCOV_EXT_FORMAT. Store this flag as part of the mode in task_struct::kcov_mode and in kcov::mode to avoid having to pass it around separately everywhere. Signed-off-by: Jann Horn --- include/linux/kcov.h | 7 +++++++ include/uapi/linux/kcov.h | 12 ++++++++++++ kernel/kcov.c | 39 ++++++++++++++++++++++++++++++++++----- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/include/linux/kcov.h b/include/linux/kcov.h index cd79715db241..6c9f0373022f 100644 --- a/include/linux/kcov.h +++ b/include/linux/kcov.h @@ -23,8 +23,15 @@ enum kcov_mode { KCOV_MODE_TRACE_CMP =3D 3, }; =20 +/* + * Modifier for KCOV_MODE_TRACE_PC to record function entry/exit marked wi= th + * metadata bits. + */ +#define KCOV_EXT_FORMAT (1 << 29) #define KCOV_IN_CTXSW (1 << 30) =20 +#define KCOV_MODE_TRACE_PC_EXT (KCOV_MODE_TRACE_PC | KCOV_EXT_FORMAT) + void kcov_task_init(struct task_struct *t); void kcov_task_exit(struct task_struct *t); =20 diff --git a/include/uapi/linux/kcov.h b/include/uapi/linux/kcov.h index ed95dba9fa37..8d8a233bd61f 100644 --- a/include/uapi/linux/kcov.h +++ b/include/uapi/linux/kcov.h @@ -35,8 +35,20 @@ enum { KCOV_TRACE_PC =3D 0, /* Collecting comparison operands mode. */ KCOV_TRACE_CMP =3D 1, + /* + * Extended PC coverage collection mode. + * In this mode, the top byte of the PC is replaced with flag bits + * (KCOV_RECORDFLAG_*). + */ + KCOV_TRACE_PC_EXT =3D 2, }; =20 +#define KCOV_RECORD_IP_MASK 0x00ffffffffffffff +#define KCOV_RECORDFLAG_TYPEMASK 0xf000000000000000 +#define KCOV_RECORDFLAG_TYPE_NORMAL 0xf000000000000000 +#define KCOV_RECORDFLAG_TYPE_ENTRY 0x0000000000000000 +#define KCOV_RECORDFLAG_TYPE_EXIT 0x1000000000000000 + /* * The format for the types of collected comparisons. * diff --git a/kernel/kcov.c b/kernel/kcov.c index 26baccaaefa9..701ad69493bf 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -55,7 +55,12 @@ struct kcov { refcount_t refcount; /* The lock protects mode, size, area and t. */ spinlock_t lock; - enum kcov_mode mode __guarded_by(&lock); + /* + * Mode, consists of: + * - enum kcov_mode + * - flag KCOV_EXT_FORMAT + */ + unsigned int mode __guarded_by(&lock); /* Size of arena (in long's). */ unsigned int size __guarded_by(&lock); /* Coverage buffer shared with user space. */ @@ -228,8 +233,14 @@ void notrace __sanitizer_cov_trace_pc(void) { struct task_struct *cur =3D current; =20 - if (READ_ONCE(cur->kcov_mode) !=3D KCOV_MODE_TRACE_PC) + if ((READ_ONCE(cur->kcov_mode) & ~KCOV_EXT_FORMAT) !=3D KCOV_MODE_TRACE_P= C) return; + /* + * No bitops are needed here for setting the record type because + * KCOV_RECORDFLAG_TYPE_NORMAL has the high bits set. + * This relies on userspace not caring about the rest of the top byte + * for KCOV_RECORDFLAG_TYPE_NORMAL records. + */ kcov_add_pc_record(cur, canonicalize_ip(_RET_IP_)); } EXPORT_SYMBOL(__sanitizer_cov_trace_pc); @@ -245,12 +256,28 @@ void notrace __sanitizer_cov_trace_pc_entry(void) * This hook replaces __sanitizer_cov_trace_pc() for the function entry * basic block; it should still emit a record even in classic kcov mode. */ - if (kcov_mode !=3D KCOV_MODE_TRACE_PC) + if ((kcov_mode & ~KCOV_EXT_FORMAT) !=3D KCOV_MODE_TRACE_PC) return; + if ((kcov_mode & KCOV_EXT_FORMAT) !=3D 0) + record =3D (record & KCOV_RECORD_IP_MASK) | KCOV_RECORDFLAG_TYPE_ENTRY; kcov_add_pc_record(cur, record); } void notrace __sanitizer_cov_trace_pc_exit(void) { + struct task_struct *cur =3D current; + unsigned long record; + + /* + * This hook is not called at the beginning of a basic block; the basic + * block from which the hook was invoked is already covered by a + * preceding hook call. + * So unlike __sanitizer_cov_trace_pc_entry(), this PC should only be + * reported in extended mode, where function exit events are recorded. + */ + if (READ_ONCE(cur->kcov_mode) !=3D KCOV_MODE_TRACE_PC_EXT) + return; + record =3D (canonicalize_ip(_RET_IP_) & KCOV_RECORD_IP_MASK) | KCOV_RECOR= DFLAG_TYPE_EXIT; + kcov_add_pc_record(cur, record); } #endif =20 @@ -373,7 +400,7 @@ EXPORT_SYMBOL(__sanitizer_cov_trace_switch); #endif /* ifdef CONFIG_KCOV_ENABLE_COMPARISONS */ =20 static void kcov_start(struct task_struct *t, struct kcov *kcov, - unsigned int size, void *area, enum kcov_mode mode, + unsigned int size, void *area, unsigned int mode, int sequence) { kcov_debug("t =3D %px, size =3D %u, area =3D %px\n", t, size, area); @@ -590,6 +617,8 @@ static int kcov_get_mode(unsigned long arg) #else return -ENOTSUPP; #endif + else if (arg =3D=3D KCOV_TRACE_PC_EXT) + return IS_ENABLED(CONFIG_KCOV_EXT_RECORDS) ? KCOV_MODE_TRACE_PC_EXT : -E= NOTSUPP; else return -EINVAL; } @@ -1098,7 +1127,7 @@ void kcov_remote_stop(void) * and kcov_remote_stop(), hence the sequence check. */ if (sequence =3D=3D kcov->sequence && kcov->remote) - kcov_move_area(kcov->mode, kcov->area, kcov->size, area); + kcov_move_area(kcov->mode & ~KCOV_EXT_FORMAT, kcov->area, kcov->size, ar= ea); spin_unlock(&kcov->lock); =20 spin_lock(&kcov_remote_lock); --=20 2.55.0.979.g7e5102b832-goog From nobody Fri Sep 25 20:47:43 2026 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C62AE58FD08 for ; Tue, 8 Sep 2026 16:55:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886513; cv=none; b=piGbTNuAWW7BNjSqmEj/MyRfv6AR40YiMNC21tTtyzWfgVkc6lSqOfNHZV/BK2X3rtFnimnJB+GDPA7jhsrTt92Jw5RH1cWMzm1q6Ch01n4iKTXHODvlWQa6THM0t055/VPYynHiZd/3G9ta+KxvCJSBfngNhkS3p/ertMFcEck= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886513; c=relaxed/simple; bh=3ehJaQwH2cLaqFIB9pK0qax4lQLljQfavu2Lu9R+/sE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=WSWpHoR/Jwn4blSnGsJk9toPr9h+z9BRSfo4g1JYwSrwHJ0YGiH8RKlOu7i1CZsu6z7Fyip+ohMYH4GGnmVCxMQJ98QPd8PquvOWScIwHAz1iR/shqzyWHORYipL7FojMY9pn5jwT8DeWBfMf1XaYj5Hf0uMua9WXh/FXB29YXM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=KfJndTWx; arc=none smtp.client-ip=74.125.225.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="KfJndTWx" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-49b5e50eb70so101935e9.1 for ; Tue, 08 Sep 2026 09:55:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788886508; x=1789491308; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=gAVsSzOIvfCvCjIHusXiixu/0awvwiM/FetAo9sODI8=; b=KfJndTWxyRqcOBbr5Sc25h0n/rI9U8fopYdYk7EXoCpdiaKI2obtg761NPDLgHL/al /BuJ628SrR7jUaQ79m7A8XWy+kMz/FYItphXmwYq8f5Jf9Bczwhy6L3w9WF6sUOPOg6j MsfaUZbCiR62T7IOeagHb4d/FkPMuTj8pu0aAYeM0AXzt66uA8vYggym+/Xgg6YGiHEr 3jvItBwuH1Y7ts3EzCaEyJkGXjvnhwWsXyHRIIsaqKjFYU3nA2blJlb3V0eOzxHmdiID R6JkUsH9FA/OuBpZQZT/E9rRfrVgnlaOV/CgdmIb1feuTsta6yMd6V3gni8GBZwtBOcW RuOg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788886508; x=1789491308; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=gAVsSzOIvfCvCjIHusXiixu/0awvwiM/FetAo9sODI8=; b=UYDAGPouy06s2dEXs2J2+1aE5Prk6kpVUzH9xaUcPhMsajQQmx+BFGhZ/55/8ov9sM wWF6afDdyn8g91tSoURLHdhCAk/aEByw6j/OiqBRO/70ewhBuPvREThAuXY6KoLeNkzR 1C8E2dToBGOoaxuwftVLgcYi0HXMNkX8xVuIIBVTVbbSUmfZHpWpV5IZv32dvnOzkIfk qJ2WHxIRXYcWzb59MXoxaQNwN7DGEY3IGqs9gVp8rghZ7v39bV0B0R6WsrcjAfIFVCwC AYQzlaD1mnt7ao3PXsh4mSWFwh+jp+TPSNtQTD2t/LStSut262Y4TIea4Jz9WBb3rLng QCkQ== X-Forwarded-Encrypted: i=1; AKwUvBy8m1BNbmkYupkEZQaoVk18AExL8a+OBdvdG2ERlhcgsdrFlUkLRFfDP5jdp2lb5HOw19L7apU8cxRWoq0=@vger.kernel.org X-Gm-Message-State: AFuF++nci1P4GxDBk5m95BkI7ubzKfdDsvORtpuStiChM/37CNlDDSHy /a46S0C7u8zka3JVpcjcu6EcVsIf2i+2/wf6Z5kQidkG2uiU9svdJDQGUM4e6kOJMg== X-Gm-Gg: AYBFou2BP+1v6ogX0WULNRnLNTt4LLfVuuXB9HdwVSdJ/OcNR6h3GTIvoGitmnutzm0 crO44SQdnVzkx9DoEI/htI8WKnwP/QanW373PMfrCVgVMv60CrQfn2gs4nxpYUu2E6EuIZwMdgI s+uZZ9K4McBd/o5iM06DKcJIl48pbaV6UvHOe5hJFgJv8jesbQdD++g7zays31Ir65z80wF1h7O F8GLKkSQLnCZFW4xu3owsZw7GzflWu6t/ab9zqx5M1iccRXfqgCTWyefExMJGaFxADAYLFGLIav 5Mfgqc4j381s9Vg6VXh1ST9zlnJUYixvrLx+7OK+dJfheQydGtkWO3pSewHMULeL+HLD108ElNJ DYq9ibPkI+cPahZMkL2qaXcLXs0qNUsqOereYLr06S4CErtbPo0xSXxRwNKW1Fyayqav4IhnNX+ S5IDNZq4W/U9Z9g/+GlqKUCVeBt6izeROsqpabfIgEFJ5D7WZP0h6bpXQINoo+i4bYvO99oinoG h0YXof0e2Ll5kdrILxfsUpJSfzhBcRe4Si88I7PurPsRksA X-Received: by 2002:a05:600c:6c4e:b0:49d:3:4a29 with SMTP id 5b1f17b1804b1-49d1f6e324cmr36965e9.7.1788886507196; Tue, 08 Sep 2026 09:55:07 -0700 (PDT) Received: from localhost ([2a00:79e0:288a:8:ac21:220d:3908:7e61]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4858e239862sm31989701f8f.9.2026.09.08.09.55.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 09:55:06 -0700 (PDT) From: Jann Horn Date: Tue, 08 Sep 2026 18:54:44 +0200 Subject: [PATCH RFC v3 04/12] kcov: summarize entry/exit while disabled Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260908-kcov-extrecord-v3-4-dcbc11593e88@google.com> References: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> In-Reply-To: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> To: Dmitry Vyukov , Andrey Konovalov , Alexander Potapenko Cc: Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, llvm@lists.linux.dev, Jann Horn X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788886494; l=4851; i=jannh@google.com; s=20240730; h=from:subject:message-id; bh=3ehJaQwH2cLaqFIB9pK0qax4lQLljQfavu2Lu9R+/sE=; b=1PtG4EdUagp4gP5iDk3jLQFUBtzlXenzTz6y7/KiV9cSp2fcNYAro0JWEvHlVJnfsXgirf9U0 IcCeVUrYXqfDNWwOh9DTjLf2X9zmbo4yY91FXs59zXa/7XuQH/ggPJ3 X-Developer-Key: i=jannh@google.com; a=ed25519; pk=AljNtGOzXeF6khBXDJVVvwSEkVDGnnZZYqfWhP1V+C8= In case kcov is re-enabled with a different call stack than the one it was disabled with, emit events that summarize changes to the call stack so that userspace can continue tracking the call stack across context switches. Signed-off-by: Jann Horn --- include/linux/kcov.h | 11 ++--------- include/uapi/linux/kcov.h | 2 ++ kernel/kcov.c | 48 +++++++++++++++++++++++++++++++++++++++++++= ++-- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/include/linux/kcov.h b/include/linux/kcov.h index 6c9f0373022f..357f4de8790a 100644 --- a/include/linux/kcov.h +++ b/include/linux/kcov.h @@ -35,15 +35,8 @@ enum kcov_mode { void kcov_task_init(struct task_struct *t); void kcov_task_exit(struct task_struct *t); =20 -#define kcov_prepare_switch(t) \ -do { \ - (t)->kcov_mode |=3D KCOV_IN_CTXSW; \ -} while (0) - -#define kcov_finish_switch(t) \ -do { \ - (t)->kcov_mode &=3D ~KCOV_IN_CTXSW; \ -} while (0) +void kcov_prepare_switch(struct task_struct *cur); +void kcov_finish_switch(struct task_struct *cur); =20 /* See Documentation/dev-tools/kcov.rst for usage details. */ void kcov_remote_start(u64 handle); diff --git a/include/uapi/linux/kcov.h b/include/uapi/linux/kcov.h index 8d8a233bd61f..75c582784055 100644 --- a/include/uapi/linux/kcov.h +++ b/include/uapi/linux/kcov.h @@ -48,6 +48,8 @@ enum { #define KCOV_RECORDFLAG_TYPE_NORMAL 0xf000000000000000 #define KCOV_RECORDFLAG_TYPE_ENTRY 0x0000000000000000 #define KCOV_RECORDFLAG_TYPE_EXIT 0x1000000000000000 +/* Summarized entry/exit events that occurred in an untraced region. */ +#define KCOV_RECORDFLAG_TYPE_EESUM 0x2000000000000000 =20 /* * The format for the types of collected comparisons. diff --git a/kernel/kcov.c b/kernel/kcov.c index 701ad69493bf..712f0f744ec5 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -76,6 +76,8 @@ struct kcov { * kcov_remote_stop(), see the comment there. */ int sequence; + int suppressed_stack_delta; + int suppressed_stack_mindelta; }; =20 struct kcov_remote_area { @@ -256,8 +258,12 @@ void notrace __sanitizer_cov_trace_pc_entry(void) * This hook replaces __sanitizer_cov_trace_pc() for the function entry * basic block; it should still emit a record even in classic kcov mode. */ - if ((kcov_mode & ~KCOV_EXT_FORMAT) !=3D KCOV_MODE_TRACE_PC) + if ((kcov_mode & ~(KCOV_EXT_FORMAT|KCOV_IN_CTXSW)) !=3D KCOV_MODE_TRACE_P= C) return; + if (kcov_mode & KCOV_IN_CTXSW) { + cur->kcov->suppressed_stack_delta++; + return; + } if ((kcov_mode & KCOV_EXT_FORMAT) !=3D 0) record =3D (record & KCOV_RECORD_IP_MASK) | KCOV_RECORDFLAG_TYPE_ENTRY; kcov_add_pc_record(cur, record); @@ -266,6 +272,7 @@ void notrace __sanitizer_cov_trace_pc_exit(void) { struct task_struct *cur =3D current; unsigned long record; + unsigned int kcov_mode =3D READ_ONCE(cur->kcov_mode); =20 /* * This hook is not called at the beginning of a basic block; the basic @@ -274,8 +281,16 @@ void notrace __sanitizer_cov_trace_pc_exit(void) * So unlike __sanitizer_cov_trace_pc_entry(), this PC should only be * reported in extended mode, where function exit events are recorded. */ - if (READ_ONCE(cur->kcov_mode) !=3D KCOV_MODE_TRACE_PC_EXT) + if ((kcov_mode & ~KCOV_IN_CTXSW) !=3D KCOV_MODE_TRACE_PC_EXT) return; + if (kcov_mode & KCOV_IN_CTXSW) { + struct kcov *kcov =3D cur->kcov; + + if (kcov->suppressed_stack_mindelta =3D=3D kcov->suppressed_stack_delta) + kcov->suppressed_stack_mindelta--; + kcov->suppressed_stack_delta--; + return; + } record =3D (canonicalize_ip(_RET_IP_) & KCOV_RECORD_IP_MASK) | KCOV_RECOR= DFLAG_TYPE_EXIT; kcov_add_pc_record(cur, record); } @@ -399,6 +414,35 @@ void notrace __sanitizer_cov_trace_switch(kcov_u64 val= , void *arg) EXPORT_SYMBOL(__sanitizer_cov_trace_switch); #endif /* ifdef CONFIG_KCOV_ENABLE_COMPARISONS */ =20 +void kcov_prepare_switch(struct task_struct *cur) +{ +#ifdef CONFIG_KCOV_EXT_RECORDS + struct kcov *kcov =3D cur->kcov; + + if (kcov) { + kcov->suppressed_stack_mindelta =3D 0; + kcov->suppressed_stack_delta =3D 0; + } +#endif + cur->kcov_mode |=3D KCOV_IN_CTXSW; +} + +void kcov_finish_switch(struct task_struct *cur) +{ + struct kcov *kcov =3D cur->kcov; + unsigned long record; + + cur->kcov_mode &=3D ~KCOV_IN_CTXSW; + if (!IS_ENABLED(CONFIG_KCOV_EXT_RECORDS)) + return; + if ((cur->kcov_mode & KCOV_EXT_FORMAT) =3D=3D 0) + return; + record =3D KCOV_RECORDFLAG_TYPE_EESUM | + (((u16)(s16)kcov->suppressed_stack_mindelta)<<16) | + (((u16)(s16)kcov->suppressed_stack_delta)<<16); + kcov_add_pc_record(cur, record); +} + static void kcov_start(struct task_struct *t, struct kcov *kcov, unsigned int size, void *area, unsigned int mode, int sequence) --=20 2.55.0.979.g7e5102b832-goog From nobody Fri Sep 25 20:47:43 2026 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0B18C58F071 for ; Tue, 8 Sep 2026 16:55:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886515; cv=none; b=CzlLyT8y21xiqKJ/OCKM8tk0jdIGvQ6P3wNA7Pf2M65hciVwRQHJWk612OuTNhtOeVrz+HvGY9qZtY1OvWGXDtsrvQejfEgICojctSeu9lZ3Lh5r+/yIhr5U1kix/OPkFt8ckX8DaDE4t78eTGabgTzPNpdB22ahXC6AHzMmB68= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886515; c=relaxed/simple; bh=swnHzCzPIsazYNrb6Gr29KC3lToHtlhY/NVfFI7DlP0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=JM1295YJgGh1Y6vc+QXzl+8xuLprUQGARAeBWj1x21gVTFdZ7lj3zVqQ3gmneYC/4finqleBJ5N2ArxxyYOidRzjjo8x2LxABVN7a3rphihoeWUs8+iKQcD+hvupwswivRUaPtEx+/m+BvtvQviau54L9jHTnUkPCk69FnNDkjE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=wHZULxHS; arc=none smtp.client-ip=74.125.225.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="wHZULxHS" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-49b5e50eb70so101945e9.1 for ; Tue, 08 Sep 2026 09:55:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788886510; x=1789491310; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Nw8yIRTtoZrCknqrua36GQ/CxjoMx8x/uJ+stBHvubA=; b=wHZULxHSLAeUHoT38N8qRrghQrfbbThMybyN2UV0ChtGOdoFi9zZEhHnP2cPDHtc81 C3n9KVDBV6ibjNYZnXXohG8v3zqov45lq2qA4x9nv8iWc4Qw12RZVN2xcNYohtdQK9UC IABM+/eD7JU+rbDpR4OQQd1sxbmp4o2/sw1/63KROz7iJ1wgnJ8swntaBr1hJSkL1lAj ssgDRvPxc19zIvhCGFOz0s43ju7FvmlMqtmksfOWkqKEkvphFjmVKjIVagIZm1NTqCbL IUGCbCgs2sDqv+6h/7DA2qVEiXEfGNIrZ5Zp/sKEs7uIHfQD21WgqrdD56BbReDOM0UE lR/A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788886510; x=1789491310; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=Nw8yIRTtoZrCknqrua36GQ/CxjoMx8x/uJ+stBHvubA=; b=V9bUD+GeQT3tGG3CvL0AePaJ51EMZA6sE52heq0u4ZGtH5OeYpWh44Sn1J+Qk3HZdA 0zirxDmqIIlfWnW6iHlEde2Kt0dYmv0R9zJK736rZvRTRWC0EsJWBFtOIbbOk+CsTy2F VELBYG0EGuPzV+Yb8mVGc5ERD7fOtOo0K4nnXc58Ka/GUrFNIuvnczDpWW7HCd1/1ggz pOd8bR5Sq+isGLD2KA1K/lYUEKzK7br015mb0Xgo/ZS2k4K+QlgJqvrgWyGRv5s3N4c4 OuSs5pK0O2whwlly8F9VQI5mUrD9J3SVZQWdiEHab1jrKG4NM/g0It796PV2GyYE8Fkc 23/Q== X-Forwarded-Encrypted: i=1; AKwUvBy3uUSggnZWLgmmCb11844k9jn+yCU/hLpbNR4cQnQlJNnvUuVQe4YQrcNUuf80nEqhbbyWjF2qJOIHUb8=@vger.kernel.org X-Gm-Message-State: AFuF++nRFmT2bnrSdTsp0E50W9ewPIYezjKI6a2ee1JiIh7kfw+eVqM1 vUjUdUdlxReik42sR3Ub8w8k04aMhW7E48WQQRe5BY6+eFXVBfahJ9dZJGwdp4s4aQ== X-Gm-Gg: AYBFou1o+ymo2ernwvGVB1vD1ge4FibQM2r8nwgxZHL9xgtDGdbpyk2lphWT6GWeeqI LePkxOV/MFO7W+l0j76Jt/NtirYNhn0DNR2x6KsQP2ymW9lyBnS3bLjg3Hnd0mdkWWorEYmEj1U TJx3jaiFu4+y1xMkTSXfcbvYa1p6nSdMUWuVp2dtMyM1cMc9n6PotpINhtnXPp8KfgvFHvs98u9 rtVmliuMuK3RoKGDnpVNTMvk0GLo0pYiy6olnIuj2YLfrEm+EffhfyY+D/ov2hhvQgl5AU0wsfG ga66bRzkP0fKLHaDcMXqKV56P1zk5ngX04IokUCXXP3l2KYr+sxzhwPjkvsaPTZMWpZmhelyOpC p67rcqZXol2Dn05itNP1f6PWtQcLcg7uIWFZmVL75bBvWmmIhiVdMbCnEcfnaQVYrm8eC448CdP YTJwz2HiNz83VqFXVc9xiDOzCFa9qJw59LooyTRBtWQ4qW0fQEcx4F8Y3bskPrTJTERgsV9tHMg u1PTxV5K6zVCa1drO3XaQ2W0/NM1YbQtb2nQe61pfGFlchM X-Received: by 2002:a05:600c:3221:b0:499:c46c:adc7 with SMTP id 5b1f17b1804b1-49d1bcfc063mr550665e9.2.1788886509269; Tue, 08 Sep 2026 09:55:09 -0700 (PDT) Received: from localhost ([2a00:79e0:288a:8:ac21:220d:3908:7e61]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49cfd3f815bsm304098545e9.4.2026.09.08.09.55.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 09:55:08 -0700 (PDT) From: Jann Horn Date: Tue, 08 Sep 2026 18:54:45 +0200 Subject: [PATCH RFC v3 05/12] kasan: refactor write/is_write arguments to flags Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260908-kcov-extrecord-v3-5-dcbc11593e88@google.com> References: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> In-Reply-To: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> To: Dmitry Vyukov , Andrey Konovalov , Alexander Potapenko Cc: Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, llvm@lists.linux.dev, Jann Horn X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788886494; l=15697; i=jannh@google.com; s=20240730; h=from:subject:message-id; bh=swnHzCzPIsazYNrb6Gr29KC3lToHtlhY/NVfFI7DlP0=; b=xSzSXAvjgloPp+rdyeXvT+Khwp4gZ7hk1qn/SwJIRaO9bgCTg1ThG0i+7Wc6CCj4nbVGx9DCW PD+R63Jx4+VDiDlkxVhpY0o2eyGnufGo+9ITtw81h/TnsGTXLamz5CV X-Developer-Key: i=jannh@google.com; a=ed25519; pk=AljNtGOzXeF6khBXDJVVvwSEkVDGnnZZYqfWhP1V+C8= Refactor the "write"/"is_write" arguments of kasan_check_range() and kasan_report() into "flags" arguments that can contain the flag KASAN_TYPE_WRITE. This prepares for a following patch that introduces a second flag. This should hopefully not change the machine code in hotpaths - both before and after this change, the argument is either 0 or 1 at the assembly level depending on whether the access is a write. Only kasan_report() should have to do a tiny bit of extra work to do a bittest. Signed-off-by: Jann Horn --- arch/arm64/kernel/traps.c | 2 +- arch/arm64/mm/fault.c | 2 +- include/linux/kasan.h | 6 ++++-- mm/kasan/common.c | 2 +- mm/kasan/generic.c | 20 ++++++++++---------- mm/kasan/kasan.h | 6 +++--- mm/kasan/report.c | 3 ++- mm/kasan/report_generic.c | 8 ++++---- mm/kasan/shadow.c | 24 ++++++++++++------------ mm/kasan/sw_tags.c | 20 ++++++++++---------- 10 files changed, 48 insertions(+), 45 deletions(-) diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 914282016069..9f31fe3f1660 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -1069,7 +1069,7 @@ int kasan_brk_handler(struct pt_regs *regs, unsigned = long esr) void *addr =3D (void *)regs->regs[0]; u64 pc =3D regs->pc; =20 - kasan_report(addr, size, write, pc); + kasan_report(addr, size, write ? KASAN_TYPE_WRITE : 0, pc); =20 /* * The instrumentation allows to control whether we can proceed after diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 0b52557652be..221e39869ae6 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -365,7 +365,7 @@ static void report_tag_fault(unsigned long addr, unsign= ed long esr, * find out access size. */ bool is_write =3D !!(esr & ESR_ELx_WNR); - kasan_report((void *)addr, 0, is_write, regs->pc); + kasan_report((void *)addr, 0, is_write ? KASAN_TYPE_WRITE : 0, regs->pc); } #else /* Tag faults aren't enabled without CONFIG_KASAN_HW_TAGS. */ diff --git a/include/linux/kasan.h b/include/linux/kasan.h index bf233bde68c7..03c7ac79345d 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -33,6 +33,8 @@ typedef unsigned int __bitwise kasan_vmalloc_flags_t; #define KASAN_VMALLOC_PAGE_RANGE 0x1 /* Apply exsiting page range */ #define KASAN_VMALLOC_TLB_FLUSH 0x2 /* TLB flush */ =20 +#define KASAN_TYPE_WRITE 0x1 + #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS) =20 #include @@ -526,11 +528,11 @@ static inline void *kasan_reset_tag(const void *addr) * kasan_report - print a report about a bad memory access detected by KAS= AN * @addr: address of the bad access * @size: size of the bad access - * @is_write: whether the bad access is a write or a read + * @flags: bitmask, can contain KASAN_TYPE_* flags * @ip: instruction pointer for the accessibility check or the bad access = itself */ bool kasan_report(const void *addr, size_t size, - bool is_write, unsigned long ip); + unsigned int flags, unsigned long ip); =20 #else /* CONFIG_KASAN_SW_TAGS || CONFIG_KASAN_HW_TAGS */ =20 diff --git a/mm/kasan/common.c b/mm/kasan/common.c index b7d05c2a6d93..1ab77ac9719c 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -571,7 +571,7 @@ void __kasan_mempool_unpoison_object(void *ptr, size_t = size, unsigned long ip) bool __kasan_check_byte(const void *address, unsigned long ip) { if (!kasan_byte_accessible(address)) { - kasan_report(address, 1, false, ip); + kasan_report(address, 1, 0, ip); return false; } return true; diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 2b8e73f5f6a7..9efd6fbbb7c3 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -173,7 +173,7 @@ static __always_inline bool memory_is_poisoned(const vo= id *addr, size_t size) } =20 static __always_inline bool check_region_inline(const void *addr, - size_t size, bool write, + size_t size, unsigned int flags, unsigned long ret_ip) { if (!kasan_enabled()) @@ -183,21 +183,21 @@ static __always_inline bool check_region_inline(const= void *addr, return true; =20 if (unlikely(addr + size < addr)) - return !kasan_report(addr, size, write, ret_ip); + return !kasan_report(addr, size, flags, ret_ip); =20 if (unlikely(!addr_has_metadata(addr))) - return !kasan_report(addr, size, write, ret_ip); + return !kasan_report(addr, size, flags, ret_ip); =20 if (likely(!memory_is_poisoned(addr, size))) return true; =20 - return !kasan_report(addr, size, write, ret_ip); + return !kasan_report(addr, size, flags, ret_ip); } =20 -bool kasan_check_range(const void *addr, size_t size, bool write, +bool kasan_check_range(const void *addr, size_t size, unsigned int flags, unsigned long ret_ip) { - return check_region_inline(addr, size, write, ret_ip); + return check_region_inline(addr, size, flags, ret_ip); } =20 bool kasan_byte_accessible(const void *addr) @@ -252,7 +252,7 @@ EXPORT_SYMBOL(__asan_unregister_globals); #define DEFINE_ASAN_LOAD_STORE(size) \ void __asan_load##size(void *addr) \ { \ - check_region_inline(addr, size, false, _RET_IP_); \ + check_region_inline(addr, size, 0, _RET_IP_); \ } \ EXPORT_SYMBOL(__asan_load##size); \ __alias(__asan_load##size) \ @@ -260,7 +260,7 @@ EXPORT_SYMBOL(__asan_unregister_globals); EXPORT_SYMBOL(__asan_load##size##_noabort); \ void __asan_store##size(void *addr) \ { \ - check_region_inline(addr, size, true, _RET_IP_); \ + check_region_inline(addr, size, KASAN_TYPE_WRITE, _RET_IP_); \ } \ EXPORT_SYMBOL(__asan_store##size); \ __alias(__asan_store##size) \ @@ -275,7 +275,7 @@ DEFINE_ASAN_LOAD_STORE(16); =20 void __asan_loadN(void *addr, ssize_t size) { - kasan_check_range(addr, size, false, _RET_IP_); + kasan_check_range(addr, size, 0, _RET_IP_); } EXPORT_SYMBOL(__asan_loadN); =20 @@ -285,7 +285,7 @@ EXPORT_SYMBOL(__asan_loadN_noabort); =20 void __asan_storeN(void *addr, ssize_t size) { - kasan_check_range(addr, size, true, _RET_IP_); + kasan_check_range(addr, size, KASAN_TYPE_WRITE, _RET_IP_); } EXPORT_SYMBOL(__asan_storeN); =20 diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index fc9169a54766..c833bd44e3cc 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -339,11 +339,11 @@ static __always_inline bool addr_has_metadata(const v= oid *addr) * kasan_check_range - Check memory region, and report if invalid access. * @addr: the accessed address * @size: the accessed size - * @write: true if access is a write access + * @flags: bitmask, can contain KASAN_TYPE_* flags * @ret_ip: return address * @return: true if access was valid, false if invalid */ -bool kasan_check_range(const void *addr, size_t size, bool write, +bool kasan_check_range(const void *addr, size_t size, unsigned int flags, unsigned long ret_ip); =20 #else /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */ @@ -379,7 +379,7 @@ static inline void kasan_print_aux_stacks(struct kmem_c= ache *cache, const void * #endif =20 bool kasan_report(const void *addr, size_t size, - bool is_write, unsigned long ip); + unsigned int flags, unsigned long ip); void kasan_report_invalid_free(void *object, unsigned long ip, enum kasan_= report_type type); =20 struct slab *kasan_addr_to_slab(const void *addr); diff --git a/mm/kasan/report.c b/mm/kasan/report.c index e804b1e1f886..cfe00ebb98ec 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c @@ -568,13 +568,14 @@ void kasan_report_invalid_free(void *ptr, unsigned lo= ng ip, enum kasan_report_ty * user_access_save/restore(): kasan_report_invalid_free() cannot be called * from a UACCESS region, and kasan_report_async() is not used on x86. */ -bool kasan_report(const void *addr, size_t size, bool is_write, +bool kasan_report(const void *addr, size_t size, unsigned int flags, unsigned long ip) { bool ret =3D true; unsigned long ua_flags =3D user_access_save(); unsigned long irq_flags; struct kasan_report_info info; + bool is_write =3D (flags & KASAN_TYPE_WRITE); =20 if (unlikely(report_suppressed_sw()) || unlikely(!report_enabled())) { ret =3D false; diff --git a/mm/kasan/report_generic.c b/mm/kasan/report_generic.c index f5b8e37b3805..445183e2f4d3 100644 --- a/mm/kasan/report_generic.c +++ b/mm/kasan/report_generic.c @@ -364,14 +364,14 @@ void kasan_print_address_stack_frame(const void *addr) #define DEFINE_ASAN_REPORT_LOAD(size) \ void __asan_report_load##size##_noabort(void *addr) \ { \ - kasan_report(addr, size, false, _RET_IP_); \ + kasan_report(addr, size, 0, _RET_IP_); \ } \ EXPORT_SYMBOL(__asan_report_load##size##_noabort) =20 #define DEFINE_ASAN_REPORT_STORE(size) \ void __asan_report_store##size##_noabort(void *addr) \ { \ - kasan_report(addr, size, true, _RET_IP_); \ + kasan_report(addr, size, KASAN_TYPE_WRITE, _RET_IP_); \ } \ EXPORT_SYMBOL(__asan_report_store##size##_noabort) =20 @@ -388,12 +388,12 @@ DEFINE_ASAN_REPORT_STORE(16); =20 void __asan_report_load_n_noabort(void *addr, ssize_t size) { - kasan_report(addr, size, false, _RET_IP_); + kasan_report(addr, size, 0, _RET_IP_); } EXPORT_SYMBOL(__asan_report_load_n_noabort); =20 void __asan_report_store_n_noabort(void *addr, ssize_t size) { - kasan_report(addr, size, true, _RET_IP_); + kasan_report(addr, size, KASAN_TYPE_WRITE, _RET_IP_); } EXPORT_SYMBOL(__asan_report_store_n_noabort); diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c index d286e0a04543..a24f1225dd88 100644 --- a/mm/kasan/shadow.c +++ b/mm/kasan/shadow.c @@ -28,13 +28,13 @@ =20 bool __kasan_check_read(const volatile void *p, unsigned int size) { - return kasan_check_range((void *)p, size, false, _RET_IP_); + return kasan_check_range((void *)p, size, 0, _RET_IP_); } EXPORT_SYMBOL(__kasan_check_read); =20 bool __kasan_check_write(const volatile void *p, unsigned int size) { - return kasan_check_range((void *)p, size, true, _RET_IP_); + return kasan_check_range((void *)p, size, KASAN_TYPE_WRITE, _RET_IP_); } EXPORT_SYMBOL(__kasan_check_write); =20 @@ -50,7 +50,7 @@ EXPORT_SYMBOL(__kasan_check_write); #undef memset void *memset(void *addr, int c, size_t len) { - if (!kasan_check_range(addr, len, true, _RET_IP_)) + if (!kasan_check_range(addr, len, KASAN_TYPE_WRITE, _RET_IP_)) return NULL; =20 return __memset(addr, c, len); @@ -60,8 +60,8 @@ void *memset(void *addr, int c, size_t len) #undef memmove void *memmove(void *dest, const void *src, size_t len) { - if (!kasan_check_range(src, len, false, _RET_IP_) || - !kasan_check_range(dest, len, true, _RET_IP_)) + if (!kasan_check_range(src, len, 0, _RET_IP_) || + !kasan_check_range(dest, len, KASAN_TYPE_WRITE, _RET_IP_)) return NULL; =20 return __memmove(dest, src, len); @@ -71,8 +71,8 @@ void *memmove(void *dest, const void *src, size_t len) #undef memcpy void *memcpy(void *dest, const void *src, size_t len) { - if (!kasan_check_range(src, len, false, _RET_IP_) || - !kasan_check_range(dest, len, true, _RET_IP_)) + if (!kasan_check_range(src, len, 0, _RET_IP_) || + !kasan_check_range(dest, len, KASAN_TYPE_WRITE, _RET_IP_)) return NULL; =20 return __memcpy(dest, src, len); @@ -81,7 +81,7 @@ void *memcpy(void *dest, const void *src, size_t len) =20 void *__asan_memset(void *addr, int c, ssize_t len) { - if (!kasan_check_range(addr, len, true, _RET_IP_)) + if (!kasan_check_range(addr, len, KASAN_TYPE_WRITE, _RET_IP_)) return NULL; =20 return __memset(addr, c, len); @@ -91,8 +91,8 @@ EXPORT_SYMBOL(__asan_memset); #ifdef __HAVE_ARCH_MEMMOVE void *__asan_memmove(void *dest, const void *src, ssize_t len) { - if (!kasan_check_range(src, len, false, _RET_IP_) || - !kasan_check_range(dest, len, true, _RET_IP_)) + if (!kasan_check_range(src, len, 0, _RET_IP_) || + !kasan_check_range(dest, len, KASAN_TYPE_WRITE, _RET_IP_)) return NULL; =20 return __memmove(dest, src, len); @@ -102,8 +102,8 @@ EXPORT_SYMBOL(__asan_memmove); =20 void *__asan_memcpy(void *dest, const void *src, ssize_t len) { - if (!kasan_check_range(src, len, false, _RET_IP_) || - !kasan_check_range(dest, len, true, _RET_IP_)) + if (!kasan_check_range(src, len, 0, _RET_IP_) || + !kasan_check_range(dest, len, KASAN_TYPE_WRITE, _RET_IP_)) return NULL; =20 return __memcpy(dest, src, len); diff --git a/mm/kasan/sw_tags.c b/mm/kasan/sw_tags.c index c75741a74602..af77b642ede7 100644 --- a/mm/kasan/sw_tags.c +++ b/mm/kasan/sw_tags.c @@ -72,7 +72,7 @@ u8 kasan_random_tag(void) return (u8)(state % (KASAN_TAG_MAX + 1)); } =20 -bool kasan_check_range(const void *addr, size_t size, bool write, +bool kasan_check_range(const void *addr, size_t size, unsigned int flags, unsigned long ret_ip) { u8 tag; @@ -83,7 +83,7 @@ bool kasan_check_range(const void *addr, size_t size, boo= l write, return true; =20 if (unlikely(addr + size < addr)) - return !kasan_report(addr, size, write, ret_ip); + return !kasan_report(addr, size, flags, ret_ip); =20 tag =3D get_tag((const void *)addr); =20 @@ -109,12 +109,12 @@ bool kasan_check_range(const void *addr, size_t size,= bool write, =20 untagged_addr =3D kasan_reset_tag((const void *)addr); if (unlikely(!addr_has_metadata(untagged_addr))) - return !kasan_report(addr, size, write, ret_ip); + return !kasan_report(addr, size, flags, ret_ip); shadow_first =3D kasan_mem_to_shadow(untagged_addr); shadow_last =3D kasan_mem_to_shadow(untagged_addr + size - 1); for (shadow =3D shadow_first; shadow <=3D shadow_last; shadow++) { if (*shadow !=3D tag) { - return !kasan_report(addr, size, write, ret_ip); + return !kasan_report(addr, size, flags, ret_ip); } } =20 @@ -137,12 +137,12 @@ bool kasan_byte_accessible(const void *addr) #define DEFINE_HWASAN_LOAD_STORE(size) \ void __hwasan_load##size##_noabort(void *addr) \ { \ - kasan_check_range(addr, size, false, _RET_IP_); \ + kasan_check_range(addr, size, 0, _RET_IP_); \ } \ EXPORT_SYMBOL(__hwasan_load##size##_noabort); \ void __hwasan_store##size##_noabort(void *addr) \ { \ - kasan_check_range(addr, size, true, _RET_IP_); \ + kasan_check_range(addr, size, KASAN_TYPE_WRITE, _RET_IP_); \ } \ EXPORT_SYMBOL(__hwasan_store##size##_noabort) =20 @@ -154,13 +154,13 @@ DEFINE_HWASAN_LOAD_STORE(16); =20 void __hwasan_loadN_noabort(void *addr, ssize_t size) { - kasan_check_range(addr, size, false, _RET_IP_); + kasan_check_range(addr, size, 0, _RET_IP_); } EXPORT_SYMBOL(__hwasan_loadN_noabort); =20 void __hwasan_storeN_noabort(void *addr, ssize_t size) { - kasan_check_range(addr, size, true, _RET_IP_); + kasan_check_range(addr, size, KASAN_TYPE_WRITE, _RET_IP_); } EXPORT_SYMBOL(__hwasan_storeN_noabort); =20 @@ -173,6 +173,6 @@ EXPORT_SYMBOL(__hwasan_tag_memory); void kasan_tag_mismatch(void *addr, unsigned long access_info, unsigned long ret_ip) { - kasan_report(addr, 1 << (access_info & 0xf), access_info & 0x10, - ret_ip); + kasan_report(addr, 1 << (access_info & 0xf), + (access_info & 0x10) ? KASAN_TYPE_WRITE : 0, ret_ip); } --=20 2.55.0.979.g7e5102b832-goog From nobody Fri Sep 25 20:47:43 2026 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7B72658F085 for ; Tue, 8 Sep 2026 16:55:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886516; cv=none; b=QTVd8fTrdCGrZ8mVwh1/9vu+foZZ4DuL0QxtoElUPmNBUAHMVe+FSnU4cNMDJ0INrxSAtA69u+iwpixXe0q8daRwVDXs9qhJNcHHSzdERRMvY6zCFGYyeqLJIRtMJ6dv2hWiKhvk40vr0WwChLFf5ENgD4XUmabCWMxOAzmOEtw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886516; c=relaxed/simple; bh=KM3J1uqaAuVEtjhIrPm3dpl77//Er2qflRT9ZFIQO/A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=O/e/zpMJXsCmMcnBzVstlKfK6qlLEyOEWHBJjnOdZp3HBUYAJS81YUWNKUzTtBzOFi7qiP0JKvKalMSKlStDp/vYd4mYT4V0FSEjRk8AFkrHzPZ4iI1R+eMlz5gzvUi10ts+5cWeYkHOJ6FMN5SoPKTiokZw1II7FGWteiSZT4U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=LHm1PAeG; arc=none smtp.client-ip=74.125.225.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="LHm1PAeG" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-49cff3b3b92so96935e9.1 for ; Tue, 08 Sep 2026 09:55:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788886512; x=1789491312; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=bFBHubYFY/k3KdYk9Gk7CjyW2NbP8onxJg8FRcfS+Jk=; b=LHm1PAeGtKJ0zeCbTmlV1agSAi3FkbPT9AiA5KkGzXbMOKdw2jTtL05zs9sMZG5+tg VD/1FPqS1OHlpCN5o8zKmzxRMPfYQllMMF3tjtRXJ7eoS8AO4apBjEYFpukryfZKjgaZ LQNx2DBCvrlmruu34JbpyIjhYHsFgYCsE793j7d+RVuctm70eugQTEiMZoV2iLMU2xT6 vJrL23mD5DdECPp/oSI1ndDWsjzobvOvHsl2T/I85Bu7P5BpTqFbpKxXmqAEd6Cz29zv 4lBsOu26UWymBqz+RoOBjzXwIS3GcQtQLwCjtxjwFdX0f8jJ/n2aM3Q/d9Ce0ucu00Do O/Mw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788886512; x=1789491312; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=bFBHubYFY/k3KdYk9Gk7CjyW2NbP8onxJg8FRcfS+Jk=; b=LJFq/vgutMSZEC54d3z5Ag0sJYoJ7HDhEj5t55LvSZM2MbXaZFojZFfCkH4MsNN00f uUfKX/txOF2M8IXvAsoqjbq9zL/ndlemUYl/htvEKTGJOXq1NbvGq64hP0gtqlZOTJdL 6Tj+x7y92XK+NmWYD4IKor40V5GIQQz3+KuwKXyPptalXgVRt3sKGnR5RFEioWf0PVMh S2To184GlVh4IPdHfhYMMzTxbjp4vp2AzKBe0mD8vAv6M6qdECigdxTBwmk8hFehcvFF mHDlCVSaMbsYi7ulHqR6ByypmOiInBAGXosqvkQMoWb1jbIT1N7NPMA9RRQupQGB7oZD 5nUg== X-Forwarded-Encrypted: i=1; AKwUvByNl8hOjdCf2cuFbRZYBTf/eEQIL+gI9Yiph+1uRN52gC6mBQ1P9G99QMFqnHCNIKHJX0mfe5kJyhjP8ww=@vger.kernel.org X-Gm-Message-State: AFuF++l94SnZCfxj796AFonWByMP/QdCfZUVoOQ4y96OtIoUJ2icin8H WaMhWdveRoqJvvx24rjPnrL3lS9X3Y1Gh9qQQ5H982cDkEe70/MIXS/GpGKQmLmM4g== X-Gm-Gg: AYBFou1NPI+i3tEgLLm1PU3YD1MJ1IcTU/IcEx3RwIv6X1qnEEM9oOZWJxup3w2ZXws PIvdGIsrq820ncbiRXSr25cDQ/aQy17uRCbSwQJwe53GCToeaL4Rr2oPiqBcyeFIS4NDl6jbSRX gnm5XyyzSSFt+/x6CY2RmMjDdU5IQBUybulAm9ywVnIzVgA74keZTIgiUvTct5LpV/ttCJaTbmt Lxou4+ssqO2d6oMpSp06y1wWrehALZ8aP+KnVbzU2NFNZftRdQ8ZZ4tv8e0cV5TwwSyO89cq4gx juttAcnSrAf0c5Z5SN5XjsiNplqNebVwuoSjC1z3URu575S5v36qwDK1s2oicec5A0i5YvEHdR3 2a8OgTDFZRA8Oocp/KfIjl7Zbi8PFrBTMP3Xqg7KLZ8+1P7jjMuyU7OguTfZD/Th7yb3F78s9Uy y7P4YgR3R7nd0CefayUY7VomXebx6RJtZCK4g1enWxlEMnmxoecOMeXYyZFZwAyyK/UqvIh/ewF CsfHcFdw+jF8Ei19U8qiEZuCNHhCiRW1+9pKV2CrJVziwLL X-Received: by 2002:a05:600c:5919:b0:499:cfeb:4f17 with SMTP id 5b1f17b1804b1-49d1f6e6e8bmr41005e9.5.1788886511111; Tue, 08 Sep 2026 09:55:11 -0700 (PDT) Received: from localhost ([2a00:79e0:288a:8:ac21:220d:3908:7e61]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-485883be709sm37649438f8f.21.2026.09.08.09.55.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 09:55:10 -0700 (PDT) From: Jann Horn Date: Tue, 08 Sep 2026 18:54:46 +0200 Subject: [PATCH RFC v3 06/12] kcov: introduce memory access tracing Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260908-kcov-extrecord-v3-6-dcbc11593e88@google.com> References: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> In-Reply-To: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> To: Dmitry Vyukov , Andrey Konovalov , Alexander Potapenko Cc: Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, llvm@lists.linux.dev, Jann Horn X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788886494; l=14092; i=jannh@google.com; s=20240730; h=from:subject:message-id; bh=KM3J1uqaAuVEtjhIrPm3dpl77//Er2qflRT9ZFIQO/A=; b=Me1BYaxa3UcH4uDWhaWlZ/p3BX9q54yIRRaeL+npmLeJNRcwA2GBISemLGmz+DgO08c4fxxTI WjJj57RshWJDTn4dreOozqBq5DmfNjwXiwIhFS4Vomjg5zHL+ph+9CI X-Developer-Key: i=jannh@google.com; a=ed25519; pk=AljNtGOzXeF6khBXDJVVvwSEkVDGnnZZYqfWhP1V+C8= This commit only introduces tracing of memory accesses that are instrumented at the source level with instrument_*(); a followup commit will additionally provide data based on ASAN compiler instrumentation. I am adding the instrumentation hook definitions directly in include/linux/instrumented.h instead of adding separate headers; this way the compiler won't have to read yet another header file for almost every compilation unit. To avoid instrumenting files that shouldn't be instrumented, reuse KASAN's __SANITIZE_ADDRESS__. Signed-off-by: Jann Horn --- include/linux/instrumented.h | 30 +++++++++++++++++ include/linux/kcov.h | 11 ++++++ include/uapi/linux/kcov.h | 24 +++++++++++++ kernel/kcov.c | 80 ++++++++++++++++++++++++++++++++++++++++= +--- lib/Kconfig.debug | 11 ++++++ 5 files changed, 152 insertions(+), 4 deletions(-) diff --git a/include/linux/instrumented.h b/include/linux/instrumented.h index a1b4cf81adc2..940776dff616 100644 --- a/include/linux/instrumented.h +++ b/include/linux/instrumented.h @@ -13,6 +13,26 @@ #include #include #include +#ifdef CONFIG_KCOV_MEMORY +/* For build speed, only include this header in builds that actually need = it. */ +#include +#endif + +#ifdef CONFIG_KCOV_MEMORY +void _kcov_handle_memaccess(const volatile void *p, size_t size, unsigned = int type); +#else +static __always_inline void _kcov_handle_memaccess(const volatile void *p, + size_t size, unsigned int type) {} +/* Discard type argument to avoid depending on kcov header. */ +#define _kcov_handle_memaccess(p, size, type) _kcov_handle_memaccess((p), = (size), 0) +#endif + +#if defined(__SANITIZE_ADDRESS__) || !defined(CONFIG_KCOV_MEMORY) +#define kcov_handle_memaccess _kcov_handle_memaccess +#else +static __always_inline void kcov_handle_memaccess(const volatile void *p, + size_t size, unsigned int type) {} +#endif =20 /** * instrument_read - instrument regular read access @@ -24,6 +44,7 @@ */ static __always_inline void instrument_read(const volatile void *v, size_t= size) { + kcov_handle_memaccess(v, size, 0); kasan_check_read(v, size); kcsan_check_read(v, size); } @@ -38,6 +59,7 @@ static __always_inline void instrument_read(const volatil= e void *v, size_t size) */ static __always_inline void instrument_write(const volatile void *v, size_= t size) { + kcov_handle_memaccess(v, size, MEMORY_ACCESS_RECORD_WRITE); kasan_check_write(v, size); kcsan_check_write(v, size); } @@ -52,6 +74,7 @@ static __always_inline void instrument_write(const volati= le void *v, size_t size */ static __always_inline void instrument_read_write(const volatile void *v, = size_t size) { + kcov_handle_memaccess(v, size, MEMORY_ACCESS_RECORD_RMW); kasan_check_write(v, size); kcsan_check_read_write(v, size); } @@ -79,6 +102,7 @@ static __always_inline void instrument_atomic_check_alig= nment(const volatile voi */ static __always_inline void instrument_atomic_read(const volatile void *v,= size_t size) { + kcov_handle_memaccess(v, size, MEMORY_ACCESS_RECORD_ATOMIC); kasan_check_read(v, size); kcsan_check_atomic_read(v, size); instrument_atomic_check_alignment(v, size); @@ -94,6 +118,7 @@ static __always_inline void instrument_atomic_read(const= volatile void *v, size_ */ static __always_inline void instrument_atomic_write(const volatile void *v= , size_t size) { + kcov_handle_memaccess(v, size, MEMORY_ACCESS_RECORD_WRITE|MEMORY_ACCESS_R= ECORD_ATOMIC); kasan_check_write(v, size); kcsan_check_atomic_write(v, size); instrument_atomic_check_alignment(v, size); @@ -109,6 +134,7 @@ static __always_inline void instrument_atomic_write(con= st volatile void *v, size */ static __always_inline void instrument_atomic_read_write(const volatile vo= id *v, size_t size) { + kcov_handle_memaccess(v, size, MEMORY_ACCESS_RECORD_RMW|MEMORY_ACCESS_REC= ORD_ATOMIC); kasan_check_write(v, size); kcsan_check_atomic_read_write(v, size); instrument_atomic_check_alignment(v, size); @@ -126,6 +152,7 @@ static __always_inline void instrument_atomic_read_writ= e(const volatile void *v, static __always_inline void instrument_copy_to_user(void __user *to, const void *from, unsigned long n) { + kcov_handle_memaccess(from, n, 0); kasan_check_read(from, n); kcsan_check_read(from, n); kmsan_copy_to_user(to, from, n, 0); @@ -143,6 +170,7 @@ instrument_copy_to_user(void __user *to, const void *fr= om, unsigned long n) static __always_inline void instrument_copy_from_user_before(const void *to, const void __user *from, = unsigned long n) { + kcov_handle_memaccess(to, n, MEMORY_ACCESS_RECORD_WRITE); kasan_check_write(to, n); kcsan_check_write(to, n); } @@ -176,6 +204,8 @@ instrument_copy_from_user_after(const void *to, const v= oid __user *from, static __always_inline void instrument_memcpy_before(void *to, const void = *from, unsigned long n) { + kcov_handle_memaccess(from, n, 0); + kcov_handle_memaccess(to, n, MEMORY_ACCESS_RECORD_WRITE); kasan_check_write(to, n); kasan_check_read(from, n); kcsan_check_write(to, n); diff --git a/include/linux/kcov.h b/include/linux/kcov.h index 357f4de8790a..e4b818df189e 100644 --- a/include/linux/kcov.h +++ b/include/linux/kcov.h @@ -23,6 +23,7 @@ enum kcov_mode { KCOV_MODE_TRACE_CMP =3D 3, }; =20 +#define KCOV_ENABLE_MEMORY (1 << 28) /* * Modifier for KCOV_MODE_TRACE_PC to record function entry/exit marked wi= th * metadata bits. @@ -31,6 +32,7 @@ enum kcov_mode { #define KCOV_IN_CTXSW (1 << 30) =20 #define KCOV_MODE_TRACE_PC_EXT (KCOV_MODE_TRACE_PC | KCOV_EXT_FORMAT) +#define KCOV_MODE_TRACE_PC_AND_MEM (KCOV_MODE_TRACE_PC_EXT | KCOV_ENABLE_M= EMORY) =20 void kcov_task_init(struct task_struct *t); void kcov_task_exit(struct task_struct *t); @@ -109,4 +111,13 @@ static inline void kcov_remote_start_usb_softirq(u64 i= d) {} static inline void kcov_remote_stop_softirq(void) {} =20 #endif /* CONFIG_KCOV */ + +#ifdef CONFIG_KCOV_MEMORY +void __kcov_handle_memaccess(const volatile void *p, size_t size, unsigned= int type, + unsigned long ret_ip); +#else /* CONFIG_KCOV_MEMORY */ +static inline void __kcov_handle_memaccess(const volatile void *p, size_t = size, + unsigned int type, unsigned long ret_ip) {} +#endif /* CONFIG_KCOV_MEMORY */ + #endif /* _LINUX_KCOV_H */ diff --git a/include/uapi/linux/kcov.h b/include/uapi/linux/kcov.h index 75c582784055..7d7147e7b427 100644 --- a/include/uapi/linux/kcov.h +++ b/include/uapi/linux/kcov.h @@ -22,6 +22,7 @@ struct kcov_remote_arg { #define KCOV_ENABLE _IO('c', 100) #define KCOV_DISABLE _IO('c', 101) #define KCOV_REMOTE_ENABLE _IOW('c', 102, struct kcov_remote_arg) +#define KCOV_GET_MEMORY_RECORD_SIZE _IO('c', 103) =20 enum { /* @@ -41,6 +42,8 @@ enum { * (KCOV_RECORDFLAG_*). */ KCOV_TRACE_PC_EXT =3D 2, + /* Extended PC coverage mode with tracing of memory accesses. */ + KCOV_TRACE_MEMORY_ACCESS =3D 3, }; =20 #define KCOV_RECORD_IP_MASK 0x00ffffffffffffff @@ -50,6 +53,7 @@ enum { #define KCOV_RECORDFLAG_TYPE_EXIT 0x1000000000000000 /* Summarized entry/exit events that occurred in an untraced region. */ #define KCOV_RECORDFLAG_TYPE_EESUM 0x2000000000000000 +#define KCOV_RECORDFLAG_TYPE_MEMORY 0x3000000000000000 =20 /* * The format for the types of collected comparisons. @@ -74,4 +78,24 @@ static inline __u64 kcov_remote_handle(__u64 subsys, __u= 64 inst) return subsys | inst; } =20 +/* + * Data format for memory access tracing mode. + * This is an extensible struct (it can be extended by appending elements); + * userspace can query the struct size used by the running kernel with + * KCOV_GET_MEMORY_ACCESS_RECORD_SIZE. + */ +#define MEMORY_ACCESS_RECORD_TYPE_MASK 0xf +#define MEMORY_ACCESS_RECORD_TYPE_ACCESS 0x0 +/* flags for MEMORY_ACCESS_RECORD_TYPE_ACCESS */ +#define MEMORY_ACCESS_RECORD_WRITE 0x10 +#define MEMORY_ACCESS_RECORD_RMW 0x20 +#define MEMORY_ACCESS_RECORD_ATOMIC 0x40 +struct memory_access_record { + __aligned_u64 ip_address_and_kcov_flags; + __aligned_u64 data_address; + __u32 size; + __u32 flags; /* MEMORY_ACCESS_RECORD_* */ + __aligned_u64 time; +} __attribute__((aligned(8))); + #endif /* _LINUX_KCOV_IOCTLS_H */ diff --git a/kernel/kcov.c b/kernel/kcov.c index 712f0f744ec5..83e05aa61728 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -235,7 +235,8 @@ void notrace __sanitizer_cov_trace_pc(void) { struct task_struct *cur =3D current; =20 - if ((READ_ONCE(cur->kcov_mode) & ~KCOV_EXT_FORMAT) !=3D KCOV_MODE_TRACE_P= C) + if ((READ_ONCE(cur->kcov_mode) & ~(KCOV_ENABLE_MEMORY|KCOV_EXT_FORMAT)) + !=3D KCOV_MODE_TRACE_PC) return; /* * No bitops are needed here for setting the record type because @@ -258,7 +259,7 @@ void notrace __sanitizer_cov_trace_pc_entry(void) * This hook replaces __sanitizer_cov_trace_pc() for the function entry * basic block; it should still emit a record even in classic kcov mode. */ - if ((kcov_mode & ~(KCOV_EXT_FORMAT|KCOV_IN_CTXSW)) !=3D KCOV_MODE_TRACE_P= C) + if ((kcov_mode & ~(KCOV_ENABLE_MEMORY|KCOV_EXT_FORMAT|KCOV_IN_CTXSW)) != =3D KCOV_MODE_TRACE_PC) return; if (kcov_mode & KCOV_IN_CTXSW) { cur->kcov->suppressed_stack_delta++; @@ -281,7 +282,7 @@ void notrace __sanitizer_cov_trace_pc_exit(void) * So unlike __sanitizer_cov_trace_pc_entry(), this PC should only be * reported in extended mode, where function exit events are recorded. */ - if ((kcov_mode & ~KCOV_IN_CTXSW) !=3D KCOV_MODE_TRACE_PC_EXT) + if ((kcov_mode & ~(KCOV_ENABLE_MEMORY|KCOV_IN_CTXSW)) !=3D KCOV_MODE_TRAC= E_PC_EXT) return; if (kcov_mode & KCOV_IN_CTXSW) { struct kcov *kcov =3D cur->kcov; @@ -663,6 +664,8 @@ static int kcov_get_mode(unsigned long arg) #endif else if (arg =3D=3D KCOV_TRACE_PC_EXT) return IS_ENABLED(CONFIG_KCOV_EXT_RECORDS) ? KCOV_MODE_TRACE_PC_EXT : -E= NOTSUPP; + else if (arg =3D=3D KCOV_TRACE_MEMORY_ACCESS) + return IS_ENABLED(CONFIG_KCOV_MEMORY) ? KCOV_MODE_TRACE_PC_AND_MEM : -EN= OTSUPP; else return -EINVAL; } @@ -803,6 +806,10 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsign= ed int cmd, /* Put either in kcov_task_exit() or in KCOV_DISABLE. */ kcov_get(kcov); return 0; + case KCOV_GET_MEMORY_RECORD_SIZE: + if (!IS_ENABLED(CONFIG_KCOV_MEMORY)) + return -ENOTSUPP; + return sizeof(struct memory_access_record); default: return -ENOTTY; } @@ -1171,7 +1178,8 @@ void kcov_remote_stop(void) * and kcov_remote_stop(), hence the sequence check. */ if (sequence =3D=3D kcov->sequence && kcov->remote) - kcov_move_area(kcov->mode & ~KCOV_EXT_FORMAT, kcov->area, kcov->size, ar= ea); + kcov_move_area(kcov->mode & ~(KCOV_ENABLE_MEMORY|KCOV_EXT_FORMAT), + kcov->area, kcov->size, area); spin_unlock(&kcov->lock); =20 spin_lock(&kcov_remote_lock); @@ -1194,6 +1202,70 @@ struct kcov_common_handle_id kcov_common_handle(void) } EXPORT_SYMBOL(kcov_common_handle); =20 +#ifdef CONFIG_KCOV_MEMORY +static notrace bool kcov_get_memaccess_record(struct task_struct *t, + struct memory_access_record **recordp) +{ + u64 *area =3D (u64 *)t->kcov_area; + /* The buffer was allocated for t->kcov_size unsigned longs. */ + u64 max_pos =3D t->kcov_size * sizeof(unsigned long); + u64 count =3D READ_ONCE(area[0]); + u64 start_pos =3D sizeof(unsigned long) + count * sizeof(unsigned long); + u64 end_pos =3D start_pos + sizeof(struct memory_access_record); + + if (unlikely(end_pos > max_pos)) + return false; + + /* See comment in kcov_add_pc_record(). */ + WRITE_ONCE(area[0], count + sizeof(struct memory_access_record)/sizeof(un= signed long)); + barrier(); + *recordp =3D (void *)area + start_pos; + return true; +} + +/* + * Memory ordering doesn't matter a lot here because timestamps aren't + * collected atomically with memory accesses anyway. + * The important things are that the clock access has to be uaccess-safe, + * notrace, and have high granularity. + */ +static notrace __always_inline u64 kcov_get_time(void) +{ +#ifdef CONFIG_X86 + return rdtsc_ordered(); +#else + return 0; +#endif +} + +void notrace __kcov_handle_memaccess(const volatile void *p, size_t size, = unsigned int type, + unsigned long ret_ip) +{ + struct task_struct *t =3D current; + struct memory_access_record *record; + unsigned int kcov_mode =3D READ_ONCE(t->kcov_mode); + + if (kcov_mode !=3D KCOV_MODE_TRACE_PC_AND_MEM || !check_kcov_context(t)) + return; + if (!kcov_get_memaccess_record(t, &record)) + return; + *record =3D (struct memory_access_record) { + .ip_address_and_kcov_flags =3D + (ret_ip & KCOV_RECORD_IP_MASK) | KCOV_RECORDFLAG_TYPE_MEMORY, + .data_address =3D (u64)p, + .size =3D size, + .flags =3D type, + .time =3D kcov_get_time() + }; +} + +void notrace _kcov_handle_memaccess(const volatile void *p, size_t size, u= nsigned int type) +{ + __kcov_handle_memaccess(p, size, type, _RET_IP_); +} +EXPORT_SYMBOL(_kcov_handle_memaccess); +#endif /* CONFIG_KCOV_MEMORY */ + #ifdef CONFIG_KCOV_SELFTEST static void __init selftest(void) { diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 6ddf58692b09..5de427ccc42d 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2217,6 +2217,17 @@ config KCOV_ENABLE_COMPARISONS These operands can be used by fuzzing engines to improve the quality of fuzzing coverage. =20 +config KCOV_MEMORY + bool "Enable memory access trace collection by KCOV" + depends on KCOV + depends on KCOV_EXT_RECORDS + help + Provide a KCOV mode which records memory access operations and allows + userspace to inject execution delays to impose constraints on the + order in which multithreaded execution happens. + + This is mainly useful for testing race condition bugs. + config KCOV_INSTRUMENT_ALL bool "Instrument all code by default" depends on KCOV --=20 2.55.0.979.g7e5102b832-goog From nobody Fri Sep 25 20:47:43 2026 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5C5B858F088 for ; Tue, 8 Sep 2026 16:55:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886517; cv=none; b=RlOXw6OdTZkVLmbixpI3XiSW9Mxx0jiiRYXYtI3pZwZQ62F8eIdfy8Z8HD+HV43H9EhuoeIR0S2FxThmFm4sA8Qys29ZghoCngMOYTlgEHkWJSyBz5ulsoSxuWBqAWgZu1Kc/9aFbSJd8FZeEPvKRJQtf/N813H9XwNfEucIPtA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886517; c=relaxed/simple; bh=jWrqAHnqkILFV1YH9xYKa130B7ghMaQXLo+ayiQ9UN8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=pw0yimN3/XcxF4qJV4PVVGkAyhUs2Mo9WEQVV3n2cB+pG12iizQ/q1Mq6Tb4q3gZSUo6631wDEW+Om6uoNldyYBRuM/Td8L0g+t3wE4nBrH4438NwPYspNc+sp92cQyKKTI7oimpkbS6aDpV7gyA9jP8CZ9012J5ASnNzAhCEZI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=asal/egh; arc=none smtp.client-ip=74.125.225.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="asal/egh" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-49ccf3bc34cso140875e9.0 for ; Tue, 08 Sep 2026 09:55:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788886514; x=1789491314; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=R3DzdAFO70KwGDjJHYL4MMa9eTii8Dfq+RaBQI260U8=; b=asal/eghnRhaDgyws+BsMurzQ5LKja7MJpT9NMC3m4X7wnnZfPMVssZrcHXEdDGMWw 8Bx1nmYSh3uH7ZJAprBeeGJ50FvLAdlLNt0duxYM5ZFZfg1R3ir082dgKTm4x49udNkB Es180eI+PtKJwdpRb34dB/NVYw3pAG0pe/Cf9u1cnZlLJGUAssk61qwA7/EmE6xJ54PK HJJEEPiE2PPbrK8phgDn7NCwIcN192vBZtjDm7tKykKGYB0mFhtygaMlHWd9uEL6v9Jk f9O1No5sktZ4rG5CkJ2qGWwdh7hj+M/41oqFZ87pmg96gKGmsRwi+FPQd77pAGWrecAE MACg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788886514; x=1789491314; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=R3DzdAFO70KwGDjJHYL4MMa9eTii8Dfq+RaBQI260U8=; b=lNWvFz8onEe7Gv0L0NB1QPJodVvYTaAvP8C8SC38tIZsERIrMntZiXddx/f3ZT5+XZ ae/WYqWRedY1a5pWuJIzJOC2nRq39zr+WRfkLTDTPHcHAiXuVg16sHnu97mRTd6PAeDW 7gFgGHnH4GQnvmOjIvjxoNOMj1dGQ0/2W4zjD5Gj7fQTjLYEQwyqSsrzlj+vHUsHuJBk Jc2QJS1gyBE5dxEXEONKW2deyBybiC0/GhFuI1J4A4DUVQQqmOAws+RqDZlKGPF+mlW+ 0xLBy2xytEHrS2fRkUfjrh3dh1nXGFsEJIhRKIuaHKIB482CT5PScgew3LcdOR/mWWvs LA1A== X-Forwarded-Encrypted: i=1; AKwUvBwdiKcb9PDfYd1PYQNZFUMx6YydD+xMQDgtMcucN25/Vf2JrU3rwY/PH2AIcc6P6P77bDmFD7V12S6eHGI=@vger.kernel.org X-Gm-Message-State: AFuF++mlxTdX0xDHsx2BQwr7ZHS/r7i5IiGvpmEDiydqPOhOKR/CmSF3 kjyTRmcW4vqs3Ejq2YHlfaztCh1wvj168m2pAq/dnJ2oe6ykIFJqtXljxC3QypwKVg== X-Gm-Gg: AYBFou2kGtvf7cd9bBlznFhVd/s0r8ZmMBluLFUAs2+jupcyjj/pbYgKjNtboOk+b4l snPu2JlPqvbCpFKo+kP/BPQ0fPQa47zgFmE3M2+4MyKBJkhch0S8iKcw9ogz7NoH9oSo0L6RcKw a9sfBH9cxvsf9bVZkAPMMzOcR81lju7GqiqjLY2NbA4Xg40+YsNSoYWbsTipwzX+tzg4+NMUjHZ CwZzucu6WWKmKaWCgu0qJzwY4n0lXLzM19gL9CS8L+2WJrfmt9ZcJlzDgWwAHQgJHCo0tUkJxAh 6/gwGJ0OYgBw6vM7uJs6E0ZQv3kcgeWUO+ZSR5Qd/Vw2xV+UtIoR6a/rI8FjJgdYzJzzb6utcrQ rYecumqt3VXxQG70tdP6SgNwwuqhjqFcx51LYJbVBy5aYyRTWurjfsBpiexNQHdR4p+ADFyJfYJ Ut4YlH6GHrQnof+8o8K7MlUb4DlbhI1umtTE5l9UXDlSTe1dgbBTQL4L+pZIwjL9PPacojj6dkl AuqFC6YFfM78s9GN2unXKfBbKc7kP9hJ3G/QCBS2C/MlTMc X-Received: by 2002:a05:600c:a418:b0:499:7da3:dd0c with SMTP id 5b1f17b1804b1-49d00ab4237mr2533115e9.0.1788886513189; Tue, 08 Sep 2026 09:55:13 -0700 (PDT) Received: from localhost ([2a00:79e0:288a:8:ac21:220d:3908:7e61]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-48591eb3d3bsm24137110f8f.0.2026.09.08.09.55.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 09:55:12 -0700 (PDT) From: Jann Horn Date: Tue, 08 Sep 2026 18:54:47 +0200 Subject: [PATCH RFC v3 07/12] kasan: provide memory access information to KCOV Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260908-kcov-extrecord-v3-7-dcbc11593e88@google.com> References: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> In-Reply-To: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> To: Dmitry Vyukov , Andrey Konovalov , Alexander Potapenko Cc: Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, llvm@lists.linux.dev, Jann Horn X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788886494; l=6000; i=jannh@google.com; s=20240730; h=from:subject:message-id; bh=jWrqAHnqkILFV1YH9xYKa130B7ghMaQXLo+ayiQ9UN8=; b=XDDNcY0FkeFwasVBghiWsijYmlXi6Ml7BF/P9dZjWRpo+jfqVHsfEoOKHFmZBCIoyrxi6gMmF LHYJw90WPRKD7HDpuhMEaNyizksoKFaOWz41Njq17MJoqgWECkQiIti X-Developer-Key: i=jannh@google.com; a=ed25519; pk=AljNtGOzXeF6khBXDJVVvwSEkVDGnnZZYqfWhP1V+C8= In CONFIG_KCOV_MEMORY builds, let KASAN provide information about memory accesses to KCOV. Since KCOV already receives information from instrument_*() directly, filter out those accesses by introducing KASAN_TYPE_EXPLICIT. Because the KCOV usecase requires seeing ~every memory access (including accesses to globals and repeated accesses to the same memory location within a basic block), gate this on CC_IS_CLANG and let it flip some hidden LLVM flags that disable ASAN optimizations. Signed-off-by: Jann Horn --- include/linux/kasan.h | 1 + lib/Kconfig.debug | 2 ++ lib/Kconfig.kasan | 9 +++++++++ mm/kasan/generic.c | 15 +++++++++++++++ mm/kasan/shadow.c | 5 +++-- scripts/Makefile.kasan | 17 +++++++++++++++++ tools/objtool/check.c | 1 + 7 files changed, 48 insertions(+), 2 deletions(-) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 03c7ac79345d..4b915e0c51bc 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -34,6 +34,7 @@ typedef unsigned int __bitwise kasan_vmalloc_flags_t; #define KASAN_VMALLOC_TLB_FLUSH 0x2 /* TLB flush */ =20 #define KASAN_TYPE_WRITE 0x1 +#define KASAN_TYPE_EXPLICIT 0x2 =20 #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS) =20 diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 5de427ccc42d..f763f0504f62 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2221,6 +2221,8 @@ config KCOV_MEMORY bool "Enable memory access trace collection by KCOV" depends on KCOV depends on KCOV_EXT_RECORDS + depends on HAVE_KASAN_REPORT_EVERY_ACCESS + select KASAN_REPORT_EVERY_ACCESS help Provide a KCOV mode which records memory access operations and allows userspace to inject execution delays to impose constraints on the diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan index a4bb610a7a6f..9a43f6269c5c 100644 --- a/lib/Kconfig.kasan +++ b/lib/Kconfig.kasan @@ -228,4 +228,13 @@ config KASAN_EXTRA_INFO boot parameter, it will add 8 * stack_ring_size bytes of additional memory consumption. =20 +# Is KASAN_REPORT_EVERY_ACCESS allowed? +config HAVE_KASAN_REPORT_EVERY_ACCESS + def_bool y + depends on KASAN_OUTLINE + depends on CC_IS_CLANG + +config KASAN_REPORT_EVERY_ACCESS + bool + endif # KASAN diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 9efd6fbbb7c3..6cf88f569e64 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include =20 #include "kasan.h" #include "../slab.h" @@ -182,6 +184,19 @@ static __always_inline bool check_region_inline(const = void *addr, if (unlikely(size =3D=3D 0)) return true; =20 + /* + * Do not route information about an access to KCOV if we got called + * through the instrument_*() path - KCOV can get those accesses + * directly from instrument_*(), and get a bit more metadata about the + * access that way. + */ + if (likely((flags & KASAN_TYPE_EXPLICIT) =3D=3D 0)) { + unsigned int kcov_flags =3D + (flags & KASAN_TYPE_WRITE) ? MEMORY_ACCESS_RECORD_WRITE : 0; + + __kcov_handle_memaccess(addr, size, kcov_flags, ret_ip); + } + if (unlikely(addr + size < addr)) return !kasan_report(addr, size, flags, ret_ip); =20 diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c index a24f1225dd88..84f8567d4f2c 100644 --- a/mm/kasan/shadow.c +++ b/mm/kasan/shadow.c @@ -28,13 +28,14 @@ =20 bool __kasan_check_read(const volatile void *p, unsigned int size) { - return kasan_check_range((void *)p, size, 0, _RET_IP_); + return kasan_check_range((void *)p, size, KASAN_TYPE_EXPLICIT, _RET_IP_); } EXPORT_SYMBOL(__kasan_check_read); =20 bool __kasan_check_write(const volatile void *p, unsigned int size) { - return kasan_check_range((void *)p, size, KASAN_TYPE_WRITE, _RET_IP_); + return kasan_check_range((void *)p, size, + KASAN_TYPE_WRITE|KASAN_TYPE_EXPLICIT, _RET_IP_); } EXPORT_SYMBOL(__kasan_check_write); =20 diff --git a/scripts/Makefile.kasan b/scripts/Makefile.kasan index 91504e81247a..82e88c5fb9bc 100644 --- a/scripts/Makefile.kasan +++ b/scripts/Makefile.kasan @@ -60,6 +60,23 @@ kasan_params +=3D asan-instrumentation-with-call-thresho= ld=3D$(call_threshold) \ asan-instrument-allocas=3D1 \ asan-globals=3D1 =20 +# When we piggyback tracing of memory accesses for race condition testing = on top +# of KASAN, we want the compiler to report memory accesses even when KASAN= can +# prove that no UAF/OOB can occur; in particular, these optimizations must= be +# inhibited: +# +# - suppression of ASAN hook calls for global variables +# - merging of multiple accesses in a basic block into a single ASAN hook= call +# +# For now, known stack variable accesses are still ignored as a performance +# tradeoff, though that will probably make a small number of races (where +# another task concurrently accesses stuff on our stack) invisible to the +# instrumentation. (Stack access instrumentation is gated on +# asan-use-stack-safety and asan-skip-promotable-allocas.) +ifdef CONFIG_KASAN_REPORT_EVERY_ACCESS +kasan_params +=3D asan-opt-globals=3D0 asan-opt-same-temp=3D0 +endif # CONFIG_KASAN_REPORT_EVERY_ACCESS + # Instrument memcpy/memset/memmove calls by using instrumented __asan_mem*= () # instead. With compilers that don't support this option, compiler-inserted # memintrinsics won't be checked by KASAN on GENERIC_ENTRY architectures. diff --git a/tools/objtool/check.c b/tools/objtool/check.c index d70cb640e2ec..08ebfe1f3fac 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1219,6 +1219,7 @@ static const char *uaccess_safe_builtin[] =3D { /* KCOV */ "write_comp_data", "check_kcov_mode", + "__kcov_handle_memaccess", "__sanitizer_cov_trace_pc", "__sanitizer_cov_trace_pc_entry", "__sanitizer_cov_trace_pc_exit", --=20 2.55.0.979.g7e5102b832-goog From nobody Fri Sep 25 20:47:43 2026 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E90DE58FD35 for ; Tue, 8 Sep 2026 16:55:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886519; cv=none; b=CY+twduD+PpeWJA6+UaN8h3xExwRrENxbxvPA0kFoRpsGeQBQYRngvhrNLrYERsANJs/9henLx2uu+tKxrbBYnLpxCEZAbCPBsnLnvkW30lrsIGZqb7O68fnVc4qzmFEnBhTQTP0DtwG5w3c9ymEhAuT9QAuIdmFRtmMQhoO7M4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886519; c=relaxed/simple; bh=ns2JDtylu0ZVx4C7znMm+Qun0k8Uo9dIcle/pG/Boc0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=AyCs+BGk8GypXOrFWitrg1NFwPBHuuMoyZCUhCEromZdStuLZIW/s2WWGLejJJEkx1hWx6BcggVGA0m7FWYtpGJHFh+q4HyBUzJwMHykmpoq3KObFo8BMlHmNFJa2r4DcxnWz1JUdrOJATMvmlspZRJY5A9tVd4mcSJD+LUJdks= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=bjR8M65r; arc=none smtp.client-ip=74.125.225.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="bjR8M65r" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-49cff3b3b92so96945e9.1 for ; Tue, 08 Sep 2026 09:55:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788886515; x=1789491315; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=QT2LgRp+eFl8LbhRKic90r+4pTm4Z+44dh2+IjeCBi0=; b=bjR8M65ru5tLPo2MxxbXzwAM14fvxusFcKtnjFfyr3w4lDHT2b44EJCF+H7H9OnTBA YL3HbBv0v70ald/VRTgHSMqh53VlXSPrRAOJrbVc3TdBJr7nwvQ1WWSYG1kJsL680Awo xbDCsVK/35gKGa49vZv4D1EeQ/vrvKt9Y9CJHnvq0du89UFOLNgaEXlSHz7fY7om41tw //RUjCB7v3Nkhv6RBgGFgx8A4L8VyL0pDjVphEam5/sy4MMUL2nZwy5v4ZMFPwsVK1O1 wSji7i/t8/laLhGl+2ESsADYgygPaZrfbEHOrqPPYGiGgbqAjNAbZ2ZenP47L8mVY8xJ eZNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788886515; x=1789491315; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=QT2LgRp+eFl8LbhRKic90r+4pTm4Z+44dh2+IjeCBi0=; b=Nd1FK5isqvCK35TRq3C+GodXssfuRFczn0aMpOGcOB9mjuuuUAcwAG4sAw5RlLOe/p c9nD1xbyVy9K4l/m6I29IH5q+oxBOX7U7gcu+TXvsXRM91UM7o/p63LyTsmY0SLaz0tc DZVkp+7hLYJ4S05d9A7DUSK7Gl/OhyKbHILK2dGvYkCuRziVNANJsK5hgLDv6HHARCyd moRhChZt6B4XVHxU0lTckwgCeJ5yQVaQExvk9dzHB7XSi+u0Qa/S9C53VDnztS90kvB5 cjOXLdOn+9norBMjcbngK7cJV7m0/b41q7yv4pBC+F166Nb3K6+ZMOhJAO1UdsF6AjTT O5yg== X-Forwarded-Encrypted: i=1; AKwUvBzzBa3RG+f6HH0uHcma0zu5LhIx9aKiIiL4emsDdhZ7cGPTUciH65eaBqFA1BBLJUGTjMADHErSAvsBroM=@vger.kernel.org X-Gm-Message-State: AFuF++m4r7zmUFwOlMbAoe8yXY3hirAyeeDYuFG7QdjkQWSsw2rjLu8y LbKVk3Ua2Wd4VyRSGdNOemzCv+nANLOTKAInwOMyopLDu7IzIp7U+86W1T5C6ngQ5A== X-Gm-Gg: AYBFou3b/yhKYlElJmKMpGkRRY5v3FVDv2ACQdBBh+f1ppGDxthcZH+vIFYVwh4wzvF U9w7sXqUEISXjrxpo5NFauf97jbwEaIMuEjl3Rh4g2DeHlbUpi4zV5r3MzxVpg+dOBWAcbAePRN yYWqzDSUSB64pTx7pAttJkjDU9KLNKvfy5w/mGhGdPmjcDRSmS87KJEzK2M12+zevK8ZPEbM00l hZs4PAScRcFxo7SYJWUhlAVdRIv+RM42t9uqDaSYEgLjnQsRuCNx+ffRxFyauadCaXp2EsMF/fJ PI/biNCxoLSDGs3AQgcbJ8JtRvb+yNAvd/uIo5zlwXfsW3eiGVhZgpgVMQYQMKwWFwrnd5jC12I cns3vnDj2DvHotq0fxdoa8oY8OJVzi1vbQjdUKT3MRWGwJbX0fwAmxXohD1htT2COFi/UYMM9jY +OgLAzYZsmOx1H/DsUiDeeXoIegDDQh0BYIWSloOK8IBA9xuunbzRhK35CPEYNtJXvn9VFmoxsn 7ILiTOEGHIf3OiYQK75/LwzTyxmKv7Zx8XLaUM3l9vXeJcU X-Received: by 2002:a05:600d:650d:10b0:49b:dec:ae63 with SMTP id 5b1f17b1804b1-49d05898d9emr2153525e9.12.1788886514775; Tue, 08 Sep 2026 09:55:14 -0700 (PDT) Received: from localhost ([2a00:79e0:288a:8:ac21:220d:3908:7e61]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49d1fd845absm148015e9.3.2026.09.08.09.55.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 09:55:13 -0700 (PDT) From: Jann Horn Date: Tue, 08 Sep 2026 18:54:48 +0200 Subject: [PATCH RFC v3 08/12] kcov: log freeing of SLUB objects and pages Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260908-kcov-extrecord-v3-8-dcbc11593e88@google.com> References: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> In-Reply-To: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> To: Dmitry Vyukov , Andrey Konovalov , Alexander Potapenko Cc: Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, llvm@lists.linux.dev, Jann Horn X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788886494; l=2117; i=jannh@google.com; s=20240730; h=from:subject:message-id; bh=ns2JDtylu0ZVx4C7znMm+Qun0k8Uo9dIcle/pG/Boc0=; b=K3J6yFPU21oXDkqAqu5zOxsYibb4xdpPLHoKvLH5qNom7vL+ErrS4AoAGUJwJmK4uGxq1QNWd vkAM0pi7NY4DuxZuPSpmrXCMiJD//apE3zJ+yZqkc1NisNYpRgSRl/C X-Developer-Key: i=jannh@google.com; a=ed25519; pk=AljNtGOzXeF6khBXDJVVvwSEkVDGnnZZYqfWhP1V+C8= To help with using CONFIG_KCOV_MEMORY for detecting use-after-free issues, log when memory (SLUB objects or page allocations) is being freed. This should happen after KASAN has already marked the memory as freed; this will become important if we allow driving delay injection off this in the future. Signed-off-by: Jann Horn --- include/uapi/linux/kcov.h | 1 + mm/kasan/common.c | 2 ++ mm/page_alloc.c | 3 +++ 3 files changed, 6 insertions(+) diff --git a/include/uapi/linux/kcov.h b/include/uapi/linux/kcov.h index 7d7147e7b427..76822d1c119a 100644 --- a/include/uapi/linux/kcov.h +++ b/include/uapi/linux/kcov.h @@ -90,6 +90,7 @@ static inline __u64 kcov_remote_handle(__u64 subsys, __u6= 4 inst) #define MEMORY_ACCESS_RECORD_WRITE 0x10 #define MEMORY_ACCESS_RECORD_RMW 0x20 #define MEMORY_ACCESS_RECORD_ATOMIC 0x40 +#define MEMORY_ACCESS_RECORD_FREE 0x80 struct memory_access_record { __aligned_u64 ip_address_and_kcov_flags; __aligned_u64 data_address; diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 1ab77ac9719c..3a648eaad024 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -283,6 +283,8 @@ bool __kasan_slab_free(struct kmem_cache *cache, void *= object, bool init, return false; =20 poison_slab_object(cache, object, init); + _kcov_handle_memaccess(object, cache->object_size, + MEMORY_ACCESS_RECORD_WRITE|MEMORY_ACCESS_RECORD_FREE); =20 if (no_quarantine) return false; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 083cbcb5bdde..910d14925b84 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1446,6 +1446,9 @@ static __always_inline bool __free_pages_prepare(stru= ct page *page, if (init) clear_highpages_kasan_tagged(page, 1 << order); =20 + _kcov_handle_memaccess(page_address(page), (1 << order)*PAGE_SIZE, + MEMORY_ACCESS_RECORD_WRITE|MEMORY_ACCESS_RECORD_FREE); + /* * arch_free_page() can make the page's contents inaccessible. s390 * does this. So nothing which can access the page's contents should --=20 2.55.0.979.g7e5102b832-goog From nobody Fri Sep 25 20:47:43 2026 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1FF0758F093 for ; Tue, 8 Sep 2026 16:55:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886521; cv=none; b=ak2HHPlcL1QkA7Qr6LI0TpzR2g3hkACHVeRFy0yx148qL1cQ8sTKjlWeUxAfsAkOTs7qnH6pmvUnIZmRnNNLHR3o9Uw5dyw1qXVdB3Tjfvx48LCz6h4SnYakwpWRHPqNlEHh85NPjZdupGg46bzW0Qlr/Uz3x+JUntUV1EW3TmE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886521; c=relaxed/simple; bh=D7dJVybwPKSlApecBF+pMS/ZKTr29P6+H87h9M038Z0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=YxBp62isHcZTavXrYpifAU4QW2hvJZpyPPVeDrUvr8pnQqEyAQjvjqIhuT1K/vLXbB1QtBgKaiy5n9hkfcSfkZStZMxlLph7n0ia07S13fRdRLX7zfF9P2BAm7k2n7XmnumTTGBqdd1Pkq7bPz3D+8/sNdzVh1jvNBvoLkeR8VQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Tyk/ogiH; arc=none smtp.client-ip=74.125.225.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Tyk/ogiH" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-49cda5e048fso145435e9.0 for ; Tue, 08 Sep 2026 09:55:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788886517; x=1789491317; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=4I7/tk4AzeXA19kVEngNjvzyfvBO6TVzR+9+9eypgrU=; b=Tyk/ogiHJOa7N4cFUkShyTwLu6OIUuRujP8KI1hMdyjTIzEmwjANVm9SVh5uj6Fcjt HDc4/AQIWgx4lAa/vDomNvsyc5/n77BJu51tprkt+pEYF48+4Q18s+NAQBUVaTrzKfiI Ppty6uzNGfdY/4n19EfvZHrUD45bMnqiKDdcJFkgb4j/YOCS2LQ7FqYbC+5msAhLTJhv pLJJZeY8Ac7VT9edIE0j4f+PjEm4FdPhGDaOCqleDjPoEMrdvzJWnvOzbwlKjS3RzeQf ihI2Kk5guyrsWOUuS9KgSb2IyMdl6AumbSGBHAHvvY1y2+U5CFR4lUScqnaebeHpismM 2HNw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788886517; x=1789491317; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=4I7/tk4AzeXA19kVEngNjvzyfvBO6TVzR+9+9eypgrU=; b=E9eEyP/agHAUVdggMxWoHGTs69af7eiqws1QiXKzSHAM523b0GhXDEAiOtyHQ/g4eT L+4F9MRMT2/xXUZfww707WpF2bVjAREyD7MP2EI+65aN6hKGXcfMbQiEyqL4w+07qBmY +Ep8yDK41sTZxCRzzs37/p6CleU0rZL5gt+nBcADjo18AN2KzCt7+4mSHrZtYptjjnFd OSm6EHNxQJJx0uCgz4Rxzk2zSC1L2+v01g4Agz7hmIm02xdjjuJGilCFwD8UwaoQIeT6 qsgQvB+s1/55xWPeyAIKNhwaEEqWVPgfHOKiBrCagwYDiKpI2gy+JStvN+/x2o24LDSz dorQ== X-Forwarded-Encrypted: i=1; AKwUvBytA0Sb2NiXKaTPshP0gwW2vAAzsNXOQjz8TxWPboS61K3x94nX+CWA+CYsRdH9rW7DiZUFi0VDiK8SUOA=@vger.kernel.org X-Gm-Message-State: AFuF++mTHLQLO6HMUsgc6CRPvniRtE1e1YGHKaVg5u0sqWbyXbhJeoVw Jvn73O1jFKMOM6Ftl6yuoF7XCAbzRU4A2pF5qs/JYrC6gbYuPyMVJ8j7A8tRQzdRPQ== X-Gm-Gg: AYBFou34b/Xus9qGQq/mgL+I4GobEx3nhyMWA/TndRxLH/H9xXAzDV8IwAJKOCLV6hz dGJAQg4OF+ahmC9fbkZOJkRlaPk6IW4UvdBidarrYgtg1Sbc8nv4GajmVDCxW/tymP5pX29Lv/g AX1ltsRfibrjPO7rzgHMm8PzsXRYnsw4mjz4CmRGXF5ld924dqBFmfFY0ci8EKkQwGTeK/umOpK FeNQI37T8dJ/U9n8nF1dkHy/HM5P7L1+WIZivOIs4NMcbJcSGv27BYbuNnyfrIbhGeM9GHkOso3 kQIyJw7cqA5YPnVpiLVFZmAkv/mAKk0Vc+9vZeAKz19Vw0EBA+K4C7yClBAlXbp4RIIeYzDj/eK kTdcvPyaUu2tL0olU43wDdWgjPCY8VgfA9PWrUfsjfCCXO8Q+8fpAeb1SGPYbQmm8Mx95JE4lZp uGJAfK5yarU3Rp7s/aP01qddzfamAbAPofur2dWSWSWy4+OQg/3YTkXedIA5MT/HBlYwiYgVg3Q v8inhC6Cta9rqYJhBCPVFaGrrFF+W5+m7onIYwGN8jCFRiC X-Received: by 2002:a05:600c:35d0:b0:499:fa56:f542 with SMTP id 5b1f17b1804b1-49d01d85e40mr4018175e9.8.1788886516560; Tue, 08 Sep 2026 09:55:16 -0700 (PDT) Received: from localhost ([2a00:79e0:288a:8:ac21:220d:3908:7e61]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49cee5f912esm504671695e9.4.2026.09.08.09.55.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 09:55:15 -0700 (PDT) From: Jann Horn Date: Tue, 08 Sep 2026 18:54:49 +0200 Subject: [PATCH RFC v3 09/12] kcov: record return address on function entry Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260908-kcov-extrecord-v3-9-dcbc11593e88@google.com> References: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> In-Reply-To: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> To: Dmitry Vyukov , Andrey Konovalov , Alexander Potapenko Cc: Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, llvm@lists.linux.dev, Jann Horn X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788886494; l=4458; i=jannh@google.com; s=20240730; h=from:subject:message-id; bh=D7dJVybwPKSlApecBF+pMS/ZKTr29P6+H87h9M038Z0=; b=blRTwufZNn3PfEU4TTbSRB/U9sQkxGpHTJbhKcJ7EX8g+GufzihLPqn2ue1NeTqRQ7qpfVzNg 1CypQf5tHhwAz9R/7Rz71PqldPRjeK/IEXvpu5jzzedr5uZCGzZvQgo X-Developer-Key: i=jannh@google.com; a=ed25519; pk=AljNtGOzXeF6khBXDJVVvwSEkVDGnnZZYqfWhP1V+C8= It is helpful to know which code location a function was called from for: - attributing calls to source locations in the callee - attributing calls to inlined functions For this purpose, make function entry records bigger, and record the caller instruction address in them. Signed-off-by: Jann Horn --- kernel/kcov.c | 26 ++++++++++++++++++-------- lib/Kconfig.debug | 2 ++ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/kernel/kcov.c b/kernel/kcov.c index 83e05aa61728..88aedaf41a9e 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -202,7 +202,8 @@ static notrace unsigned long canonicalize_ip(unsigned l= ong ip) return ip; } =20 -static __always_inline void notrace kcov_add_pc_record(struct task_struct = *t, unsigned long record) +static __always_inline notrace +void kcov_add_pc_record(struct task_struct *t, unsigned long record, bool = hasext, unsigned long ext) { unsigned long *area; unsigned long pos; @@ -213,7 +214,7 @@ static __always_inline void notrace kcov_add_pc_record(= struct task_struct *t, un area =3D t->kcov_area; /* The first 64-bit word is the number of subsequent PCs. */ pos =3D READ_ONCE(area[0]) + 1; - if (likely(pos < t->kcov_size)) { + if (likely(pos + (hasext?1:0) < t->kcov_size)) { /* Previously we write pc before updating pos. However, some * early interrupt code could bypass check_kcov_context() check * and invoke __sanitizer_cov_trace_pc(). If such interrupt is @@ -221,9 +222,11 @@ static __always_inline void notrace kcov_add_pc_record= (struct task_struct *t, un * overitten by the recursive __sanitizer_cov_trace_pc(). * Update pos before writing pc to avoid such interleaving. */ - WRITE_ONCE(area[0], pos); + WRITE_ONCE(area[0], pos + (hasext?1:0)); barrier(); area[pos] =3D record; + if (hasext) + area[pos+1] =3D ext; } } =20 @@ -244,7 +247,7 @@ void notrace __sanitizer_cov_trace_pc(void) * This relies on userspace not caring about the rest of the top byte * for KCOV_RECORDFLAG_TYPE_NORMAL records. */ - kcov_add_pc_record(cur, canonicalize_ip(_RET_IP_)); + kcov_add_pc_record(cur, canonicalize_ip(_RET_IP_), false, 0); } EXPORT_SYMBOL(__sanitizer_cov_trace_pc); =20 @@ -254,6 +257,7 @@ void notrace __sanitizer_cov_trace_pc_entry(void) struct task_struct *cur =3D current; unsigned long record =3D canonicalize_ip(_RET_IP_); unsigned int kcov_mode =3D READ_ONCE(cur->kcov_mode); + bool ext_format; =20 /* * This hook replaces __sanitizer_cov_trace_pc() for the function entry @@ -265,9 +269,15 @@ void notrace __sanitizer_cov_trace_pc_entry(void) cur->kcov->suppressed_stack_delta++; return; } - if ((kcov_mode & KCOV_EXT_FORMAT) !=3D 0) + ext_format =3D (kcov_mode & KCOV_EXT_FORMAT) !=3D 0; + if (ext_format) record =3D (record & KCOV_RECORD_IP_MASK) | KCOV_RECORDFLAG_TYPE_ENTRY; - kcov_add_pc_record(cur, record); + /* + * __builtin_return_address(1) is safe because this function is only + * called from C functions, which are compiled with frame pointers + * enabled + */ + kcov_add_pc_record(cur, record, ext_format, (unsigned long)__builtin_retu= rn_address(1)); } void notrace __sanitizer_cov_trace_pc_exit(void) { @@ -293,7 +303,7 @@ void notrace __sanitizer_cov_trace_pc_exit(void) return; } record =3D (canonicalize_ip(_RET_IP_) & KCOV_RECORD_IP_MASK) | KCOV_RECOR= DFLAG_TYPE_EXIT; - kcov_add_pc_record(cur, record); + kcov_add_pc_record(cur, record, false, 0); } #endif =20 @@ -441,7 +451,7 @@ void kcov_finish_switch(struct task_struct *cur) record =3D KCOV_RECORDFLAG_TYPE_EESUM | (((u16)(s16)kcov->suppressed_stack_mindelta)<<16) | (((u16)(s16)kcov->suppressed_stack_delta)<<16); - kcov_add_pc_record(cur, record); + kcov_add_pc_record(cur, record, false, 0); } =20 static void kcov_start(struct task_struct *t, struct kcov *kcov, diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index f763f0504f62..55c786a373b5 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2200,6 +2200,8 @@ config KCOV_EXT_RECORDS depends on KCOV depends on 64BIT depends on $(cc-option,-fsanitize-coverage=3Dtrace-pc-entry-exit) + select ARCH_WANT_FRAME_POINTERS + select FRAME_POINTER help Extended KCOV records allow distinguishing between multiple types of records: Normal edge coverage, function entry, and function exit. --=20 2.55.0.979.g7e5102b832-goog From nobody Fri Sep 25 20:47:43 2026 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CA35B58F096 for ; Tue, 8 Sep 2026 16:55:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886522; cv=none; b=fbmDf9VgYYRuKCkB0XQ4ihmHaZHwUFbp9O3cmEkilbrXuMgn8/DeQSUW6phwZDJnwXYehT1Y8iTxftnUghyfnCSzoS3RlD5zb8SuMDauV9rMLLRSBaofxhF6WJ6DuKFIMV7AMr6V95mE92fDIKvZEyJfFK+u27WopiasvC1+sLk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886522; c=relaxed/simple; bh=nI7UZDHKHLOeR8gHis7kZKBzbvddfeV62d7kRLq8zjs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=GGPOCVcK1YVvKA3DBH1lCYZOKpeg6UO2lmoqE/sihEsREkCyhrKreSiZXDGPyeyNzKknQbDwSa+Fg+UbbMfqZ9KWoZKXLj9oQaXm/3+dgFD80s3WjkaFMDRwomCU5M5r7OEIECVTEpYRV3iOXSLDQTdZbPhbz3VtcYI5MaGTo9w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=vPFjOiAh; arc=none smtp.client-ip=74.125.225.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="vPFjOiAh" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-49ccf3bc34cso140915e9.0 for ; Tue, 08 Sep 2026 09:55:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788886519; x=1789491319; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=RaUxdToouQ436sBgssARKpnXWAtos5uuXm7i5Fmx0oI=; b=vPFjOiAh3PIhjxKpyCuEVEVzbKmOT85FVCeym/wCyTNOL3qS/ISPnrbIn4wqiDbMdI e9VlrcvB2M9S8fnBlUTceBA/vHasI1fzZIRhIpBxkLwn+3UQPWNHaZTahaUTrQFWT2h+ h6kEgCTlIcHb0XG18LLCsyhTDR++O2sKYoY2TH0fIvg3cLD/WuUMbkRreT1rUjZfbfDO ujhPQF7Z0cXBkZex90iW91OhZGQOztVvQ17lnP8mccLai2ixYpp+Yhja60w2kqKRXwk4 ONruhpScJDwpcF6xbgYTafUW5tkRZ9TdHGp1RxUWbcxBT6uKbqEAKafpXjZ9Phte4NUH 0BgA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788886519; x=1789491319; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=RaUxdToouQ436sBgssARKpnXWAtos5uuXm7i5Fmx0oI=; b=sVlu9/LunqWBDa9X1oN9MmveQ1IWhOL0+dOJUZZlbAgZaR0tyHrc38qqkkrh29jHI9 zGezq0dS3FcWFAoyUL1wvN4spto6/YdvCQfk/jS6wsOo0A6B4Kt5g4VXktGbZjEgH4V2 xhZLjaMsUlNVVy5MhwhEeW0P9SnCwT8hX8ElyeeiXOE5gGRioZep4GoyzoHTmIzMcD4I 60aPwOwh23w2VyUhR69iLG+/vHC+W0wrbOjZEoh5ki4mLAMVnr8Rv/sbuhUtXwBb/HQT hDM3287eu2iGVjkgd40fb6jSbRTK5/z666Vx65sh/t7bWCxfc0FYDduKvIpnLl/qL4r7 U9Fg== X-Forwarded-Encrypted: i=1; AKwUvByr9N7KYyai3ZSwEeSdSWgdjM4CgrkQLtIRodLhxuBljS7iLfNN+9RYvJIn9cyMQYhlX+2uVjLb0Cn+UTQ=@vger.kernel.org X-Gm-Message-State: AFuF++n3Ul7h3UxuCQrLCfgngUBmkAcEBoBZZO40pQVEoduSp3LuX4/O yyxcyt9CPGpJAkMoT576qg4WwqIInXo7XuXU3JyZsWhUB037rI4Tta7IvuKiXnRX4w== X-Gm-Gg: AYBFou2nz2urtUTOdd3XV7cTktg74imZr6um8p8ruOVnztZtzgO2DRiS9A1lFTLr2am Q1z+XBe1gwRr/tR2cCjZaB9iQ8e1c57E8Wj/+FkfxiOPZUlte7XhaSsbVG7+PKzDgGElEW9a86s k02RCrtOBsvwxy258AX+D47TIbedRkHALPve66h44/TeuX09nUKZbDiOUaob57ZfSUBEwx+JPh4 pCOCqji70ItF94dKQXXebvsjyX5AU4IPSRFIF6CFUcWj/MhMr12ce3NWJ+JZmDVYFGaUTn1EKdI FfXtdxft2+S4znFj31VQwVpffPHd7aftGTmYJzES0W75KyBRTJGCZcpCkhWJbLoes1RKvr09Oif auyme/o+0aMxHRvq8Iym1RK4lqFyRlOVJvFau6Y7n3Y9jBWlR1PYJRajTX6dlvamYKMj6THee2v PUpybaXAqxQq1+DhRLIwXLgZYd0Si+DYXQAuwEv+fRp4E1YmA+cEVc2Kxm9xUkaKjsBAoPgv4kR wfL7RE5rFTGq4T/tYSIn+oTLEFNmkW/roYAuuldv20Wl7Rx X-Received: by 2002:a05:600d:10e:b0:495:4593:616c with SMTP id 5b1f17b1804b1-49d1f3bc3bbmr19965e9.1.1788886518456; Tue, 08 Sep 2026 09:55:18 -0700 (PDT) Received: from localhost ([2a00:79e0:288a:8:ac21:220d:3908:7e61]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4858ac2b4cdsm36061757f8f.16.2026.09.08.09.55.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 09:55:17 -0700 (PDT) From: Jann Horn Date: Tue, 08 Sep 2026 18:54:50 +0200 Subject: [PATCH RFC v3 10/12] kcov: log old value Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260908-kcov-extrecord-v3-10-dcbc11593e88@google.com> References: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> In-Reply-To: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> To: Dmitry Vyukov , Andrey Konovalov , Alexander Potapenko Cc: Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, llvm@lists.linux.dev, Jann Horn X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788886494; l=2312; i=jannh@google.com; s=20240730; h=from:subject:message-id; bh=nI7UZDHKHLOeR8gHis7kZKBzbvddfeV62d7kRLq8zjs=; b=Lkb5Mmm5ypM1UlMzH2etDVDhjeF5GU8tDa7HVHPAceBtEplvzPo1Dw5v/cbOiOulRWKt0hmfK 2WnKTrkqFwQBC+8ppvbSQgDl2Y5GEsO75520U6hPrKQqxpU6Q/iJXtN X-Developer-Key: i=jannh@google.com; a=ed25519; pk=AljNtGOzXeF6khBXDJVVvwSEkVDGnnZZYqfWhP1V+C8= For manual analysis of traces, log the old value at the memory location as part of the memory_access_record. This is best-effort; in particular: - the value may not be recorded if it has an unusual size - the recorded value may not match the value observed by the instrumented memory operation in cases where the value is modified concurrently Signed-off-by: Jann Horn --- include/uapi/linux/kcov.h | 2 ++ kernel/kcov.c | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/uapi/linux/kcov.h b/include/uapi/linux/kcov.h index 76822d1c119a..235f73e11d59 100644 --- a/include/uapi/linux/kcov.h +++ b/include/uapi/linux/kcov.h @@ -91,12 +91,14 @@ static inline __u64 kcov_remote_handle(__u64 subsys, __= u64 inst) #define MEMORY_ACCESS_RECORD_RMW 0x20 #define MEMORY_ACCESS_RECORD_ATOMIC 0x40 #define MEMORY_ACCESS_RECORD_FREE 0x80 +#define MEMORY_ACCESS_RECORD_VALUE 0x100 /* value field is valid */ struct memory_access_record { __aligned_u64 ip_address_and_kcov_flags; __aligned_u64 data_address; __u32 size; __u32 flags; /* MEMORY_ACCESS_RECORD_* */ __aligned_u64 time; + __aligned_u64 value; } __attribute__((aligned(8))); =20 #endif /* _LINUX_KCOV_IOCTLS_H */ diff --git a/kernel/kcov.c b/kernel/kcov.c index 88aedaf41a9e..ef405940a2cb 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -1267,6 +1267,26 @@ void notrace __kcov_handle_memaccess(const volatile = void *p, size_t size, unsign .flags =3D type, .time =3D kcov_get_time() }; + + switch (size) { + case 1: + __get_kernel_nofault((u8 *)&record->value, p, u8, handle_fault); + record->flags |=3D MEMORY_ACCESS_RECORD_VALUE; + break; + case 2: + __get_kernel_nofault((u16 *)&record->value, p, u16, handle_fault); + record->flags |=3D MEMORY_ACCESS_RECORD_VALUE; + break; + case 4: + __get_kernel_nofault((u32 *)&record->value, p, u32, handle_fault); + record->flags |=3D MEMORY_ACCESS_RECORD_VALUE; + break; + case 8: + __get_kernel_nofault((u64 *)&record->value, p, u64, handle_fault); + record->flags |=3D MEMORY_ACCESS_RECORD_VALUE; + break; + } +handle_fault:; } =20 void notrace _kcov_handle_memaccess(const volatile void *p, size_t size, u= nsigned int type) --=20 2.55.0.979.g7e5102b832-goog From nobody Fri Sep 25 20:47:43 2026 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 222C15921E8 for ; Tue, 8 Sep 2026 16:55:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886527; cv=none; b=ms2gpzr/tbSSaS8uJfZf1q+l0hhSX+Vpct9k1wfiK3VwJhUe37W3cmEisdPYnrOEo8VNS6fdDjmflmiPLqHVQ4n25spv7hlUzF7f5N9KMA3w6BperE7EBQctTBGyUDCESayRGnZCrejFkroHFFa3FK8lsly4Vn5cppNdRYxiKiw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886527; c=relaxed/simple; bh=fiAhh6XY7S2/oKBgtInnYdJWgrkgs/QDWJDpJKTlPnY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=AuumqaRZBJsuMHU4u/3WuERg7ZIUvfgocZ64hQ7K5oB/2dtFV2U9sFdHWN97U4jhggLom2vWFNstGDKLLuSE6CIfj3MSpFFieE8ruxg79cA+0QbetArBuwfuesuOq7I6Z1Wj83D8QGFT/nHplJcgnrJyxqpi5f2OKRK4RJXC32Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=gkhWspeA; arc=none smtp.client-ip=74.125.225.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="gkhWspeA" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-49cda5e048fso145465e9.0 for ; Tue, 08 Sep 2026 09:55:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788886521; x=1789491321; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=hfWxGqDuvLc58Bbxh+QJEjR9j2F/HWUPaBW7tT0fnEk=; b=gkhWspeAgB8lrClO+P6U0Y8dtlcaVYhkHBSV5fXVekQui2rE9L4dCc0xmt5GAuk7Ev wdaxRmABogdgKyiL6/R4PniJQcY2adHyiAPTpYuHwqqRqfgYEc6CKlNj9EYF3cqjoKo5 3e0/nOnAPOx61c6HzrotW5CNhaScbC/f/DELlFQKJ6pw0N25SqCOv0jGQQADVxsODPeg 5FNfhCL2zWR1+cu8AEsGpqde5lvdt4xXBN0HReF39L64cMlRQyY2jmSyC5yOr8mD4dbj EWufRueTxikuUnRzR3GNdXaRrivXHUV6l/pDjFPmYDRQdqBFQNOgQV5172+a6rDSwgck +J9A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788886521; x=1789491321; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=hfWxGqDuvLc58Bbxh+QJEjR9j2F/HWUPaBW7tT0fnEk=; b=mNG+RqiWB8IilC2jpe/03byLo5S2xO+4l/4wQk52LdE3t91t2nnNPsgTimyDv8DWii 07qgdu2UXXNqcZIIwgbokXhZT4fi5YgZZaUD2OTh5Tkqw0q80a9HjkjapFody+4WXc4j 4KGAOr48zAiAVCt9POABSwV+IotS8prMnCsZkeswGOp83sGPODgCPLmhnSYdu64tj+D6 wt9UU1N+pe9T11Blb/BYSvdFSZL+qx8f+039seVmHhou7XvktICc46RUjWnX234+KRFy Jbey7kWDBo7b4mxltyO/BNNLP4ucT0fSC+25B6qBRIj/sIh2KHSTbfoYX7PgcjLvaplN 2qdw== X-Forwarded-Encrypted: i=1; AKwUvBzGjAC9EnGJsd9a5hZwir7/7HKCsuO4HA6MjpW5EiWay/xPW7TOOu3HFHP8aD5uwXKRPcCYCl3UY1wqr1I=@vger.kernel.org X-Gm-Message-State: AFuF++nTOcRuUeq8296IuwVRAkslROHmBOonsoeU9wzu26MNXo+AhwP8 1+Pz2g/7aDv/JeF095lCDIlbofC2zEoOB9AkO5ow1qzddw0gi6GjpD753mTr6BwzHw== X-Gm-Gg: AYBFou3cTQ1B0qmDN/l7XwYY73P66gyKaD8twF6msdepPdYmJCsxpfTcGtyBzUW+qNF m8EH38lrVTw9Xj0nkMd6GNUyPzJWV3CUlJoJm9tQLwOI+XSi53JpgIC8ilH69sYHVsdMVEEUios RvSG1lKN3CZo0uo/PWQsrl+Mt0M2qd0dwvEMRxHjBr8qEY/QLwNc2x6Oc0v72hNsJNA2NNjnNhB LstHYiwSi0uHVB4SenFen7lyo48cTFxYwNsOkIeKJ/s33ZVF/JsmDuepkyv6VuCiEjlps4bytaM 2094z+ye2HzXHUELI8lcP4Mloa5I60mQPyWy7vPaGN4cBpmLw3umvaSZCqjMvmKySER2YC46n03 ccBxFOKY0wkVCsfJXsTyKAnlxW3N0wXsSD/ivqQ0CHzeh93lOgK/3Y/RjphYP3XUJajXkgOXCDr wp+rzOZxBG84odMXfzmJpKApgNzw+b6VDujMDV6amXCh378dz52b7/QA0pP1YQK8tbSrH9D/OeG EhZ+WgnW3SAqjJJS7Vkh0hL5LzHQnYlTNTo8LNOzScRi3OJrrSmPjjS7l4= X-Received: by 2002:a05:600c:2d82:b0:49c:ff18:79bd with SMTP id 5b1f17b1804b1-49d1f6f4369mr42055e9.9.1788886520243; Tue, 08 Sep 2026 09:55:20 -0700 (PDT) Received: from localhost ([2a00:79e0:288a:8:ac21:220d:3908:7e61]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-48591eb3d3bsm24137705f8f.0.2026.09.08.09.55.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 09:55:19 -0700 (PDT) From: Jann Horn Date: Tue, 08 Sep 2026 18:54:51 +0200 Subject: [PATCH RFC v3 11/12] kcov: introduce delay injection Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260908-kcov-extrecord-v3-11-dcbc11593e88@google.com> References: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> In-Reply-To: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> To: Dmitry Vyukov , Andrey Konovalov , Alexander Potapenko Cc: Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, llvm@lists.linux.dev, Jann Horn X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788886494; l=18966; i=jannh@google.com; s=20240730; h=from:subject:message-id; bh=fiAhh6XY7S2/oKBgtInnYdJWgrkgs/QDWJDpJKTlPnY=; b=9NUnaVZzE20SqkvtMF2xIxZX/9C+a0Usm4XRFtN4DW2f9/WocMCXrx32DK8J9dLHg1Ab418Sn c7wrHpU29zqCRTWquSMnrY7cR+s/jjhqNTQYB+qwTbeckDyGDyROmY2 X-Developer-Key: i=jannh@google.com; a=ed25519; pk=AljNtGOzXeF6khBXDJVVvwSEkVDGnnZZYqfWhP1V+C8= Introduce KCOV-based delay injection, which is intended for deterministically testing race condition bugs. Preceding patches allow userspace to record a trace of function entry/exit events and memory access events in a multi-threaded test case. After userspace identifies kernel memory accesses that could be part of a race condition, userspace can use KCOV_SET_DI on the participating threads to instruct KCOV to ensure that pairs of memory accesses execute in the desired order. A kcov_di_stack with type DI_STACK_WAIT instructs KCOV to spin-wait for another kcov_di_stack (normally installed on another thread) with type DI_STACK_WAKE and with the same flagidx. Signed-off-by: Jann Horn --- include/uapi/linux/kcov.h | 45 ++++++ kernel/kcov.c | 380 ++++++++++++++++++++++++++++++++++++++++++= +++- tools/objtool/check.c | 1 + 3 files changed, 422 insertions(+), 4 deletions(-) diff --git a/include/uapi/linux/kcov.h b/include/uapi/linux/kcov.h index 235f73e11d59..88bd11d7d108 100644 --- a/include/uapi/linux/kcov.h +++ b/include/uapi/linux/kcov.h @@ -3,6 +3,7 @@ #define _LINUX_KCOV_IOCTLS_H =20 #include +#include =20 /* * Argument for KCOV_REMOTE_ENABLE ioctl, see Documentation/dev-tools/kcov= .rst @@ -23,6 +24,10 @@ struct kcov_remote_arg { #define KCOV_DISABLE _IO('c', 101) #define KCOV_REMOTE_ENABLE _IOW('c', 102, struct kcov_remote_arg) #define KCOV_GET_MEMORY_RECORD_SIZE _IO('c', 103) +#define KCOV_SET_DI _IOW('c', 104, struct kcov_set_di_arg) +#define KCOV_RESET_DI_FLAGS _IO('c', 105) +#define KCOV_WAKE_DI_FLAG _IO('c', 106) +#define KCOV_SPINWAIT_DI_FLAG _IO('c', 107) =20 enum { /* @@ -54,6 +59,11 @@ enum { /* Summarized entry/exit events that occurred in an untraced region. */ #define KCOV_RECORDFLAG_TYPE_EESUM 0x2000000000000000 #define KCOV_RECORDFLAG_TYPE_MEMORY 0x3000000000000000 +/* these two record types have a flag index in the low bits */ +#define KCOV_RECORDFLAG_TYPE_WAIT 0x4000000000000000 +#define KCOV_RECORDFLAG_TYPE_WAKE 0x5000000000000000 +/* set in KCOV_RECORDFLAG_TYPE_WAIT record to mark that the wait timed out= */ +#define KCOV_WAIT_TIMEOUT 0x0010000000000000 =20 /* * The format for the types of collected comparisons. @@ -101,4 +111,39 @@ struct memory_access_record { __aligned_u64 value; } __attribute__((aligned(8))); =20 + +/* + * Delay Injection API + */ +struct kcov_di_stack_elem { + __aligned_u64 ip; + __aligned_u64 parent_idx; +}; +enum di_stack_type { + DI_STACK_WAIT =3D 0, + DI_STACK_WAKE_PRE, + DI_STACK_WAKE_POST +}; +struct kcov_di_stack { + __aligned_u64 elems; + __u32 num_elems; + enum di_stack_type type; + __u32 flagidx; +}; +struct kcov_set_di_arg { + /* + * Pointer to array of struct kcov_di_stack. + * The array consists of function entry instruction addresses, with a + * memory access instruction address at the end. + * These must be addresses as reported in KCOV_RECORDFLAG_TYPE_ENTRY and + * KCOV_RECORDFLAG_TYPE_MEMORY events (so they are not the addresses + * where functions begin). + */ + __aligned_u64 stacks; + __u32 num_stacks; + + int sync_bits_fd; + __aligned_u64 spin_limit; +}; + #endif /* _LINUX_KCOV_IOCTLS_H */ diff --git a/kernel/kcov.c b/kernel/kcov.c index ef405940a2cb..318ae2c89891 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -32,6 +32,22 @@ /* Number of 64-bit words written per one comparison: */ #define KCOV_WORDS_PER_CMP 4 =20 +#define NUM_SYNC_BITS 64 + +struct di_stack_elem { + unsigned long ip; + unsigned long parent_idx; + unsigned long cur_parent_idx; +}; + +struct di_stack { + struct di_stack_elem *elems; + unsigned int num_elems; + enum di_stack_type type; + unsigned int flagidx; + unsigned int nomatch_depth; +}; + /* * kcov descriptor (one per opened debugfs file). * State transitions of the descriptor: @@ -78,6 +94,18 @@ struct kcov { int sequence; int suppressed_stack_delta; int suppressed_stack_mindelta; + + /* delay injection */ + struct { + DECLARE_BITMAP(sync_bits, NUM_SYNC_BITS); + struct di_stack *match_stacks; + unsigned int num_match_stacks; + u64 spin_limit; + unsigned int stack_used; + unsigned int shared_nomatch_depth; + unsigned int pending_sync_bit; + struct kcov *syncbits_owner; + } di; }; =20 struct kcov_remote_area { @@ -252,12 +280,53 @@ void notrace __sanitizer_cov_trace_pc(void) EXPORT_SYMBOL(__sanitizer_cov_trace_pc); =20 #ifdef CONFIG_KCOV_EXT_RECORDS +static void notrace kcov_di_enter_slowpath(struct kcov *kcov, unsigned lon= g ip) +{ + unsigned int i; + bool no_matches =3D true; + + for (int need_increments =3D 0; need_increments < 2; need_increments++) { + for (i =3D 0; i < kcov->di.num_match_stacks; i++) { + struct di_stack *dis =3D &kcov->di.match_stacks[i]; + struct di_stack_elem *next_elem; + + if (dis->nomatch_depth || kcov->di.stack_used >=3D dis->num_elems-1) { +no_match: + if (need_increments) + dis->nomatch_depth++; + continue; + } + next_elem =3D &dis->elems[kcov->di.stack_used]; + if (next_elem->ip !=3D ip) + goto no_match; + if (need_increments =3D=3D 0) + next_elem->cur_parent_idx++; + if (next_elem->parent_idx !=3D next_elem->cur_parent_idx-1) + goto no_match; + + /* going a step down in the di_stack */ + no_matches =3D false; + next_elem[1].cur_parent_idx =3D 0; + } + + if (likely(need_increments =3D=3D 0 && no_matches)) { + kcov->di.shared_nomatch_depth++; + return; + } + /* do second pass and increment individual nomatch counters */ + } + + kcov->di.stack_used++; +} + void notrace __sanitizer_cov_trace_pc_entry(void) { struct task_struct *cur =3D current; - unsigned long record =3D canonicalize_ip(_RET_IP_); + unsigned long ip =3D canonicalize_ip(_RET_IP_); + unsigned long record =3D ip; unsigned int kcov_mode =3D READ_ONCE(cur->kcov_mode); bool ext_format; + struct kcov *kcov; =20 /* * This hook replaces __sanitizer_cov_trace_pc() for the function entry @@ -267,7 +336,7 @@ void notrace __sanitizer_cov_trace_pc_entry(void) return; if (kcov_mode & KCOV_IN_CTXSW) { cur->kcov->suppressed_stack_delta++; - return; + goto handle_distack; } ext_format =3D (kcov_mode & KCOV_EXT_FORMAT) !=3D 0; if (ext_format) @@ -278,12 +347,25 @@ void notrace __sanitizer_cov_trace_pc_entry(void) * enabled */ kcov_add_pc_record(cur, record, ext_format, (unsigned long)__builtin_retu= rn_address(1)); + +handle_distack: + if (IS_ENABLED(CONFIG_KCOV_MEMORY)) { + kcov =3D cur->kcov; + if (unlikely(kcov->di.num_match_stacks)) { + if (likely(kcov->di.shared_nomatch_depth > 0)) { + kcov->di.shared_nomatch_depth++; + } else { + kcov_di_enter_slowpath(kcov, ip); + } + } + } } void notrace __sanitizer_cov_trace_pc_exit(void) { struct task_struct *cur =3D current; unsigned long record; unsigned int kcov_mode =3D READ_ONCE(cur->kcov_mode); + struct kcov *kcov; =20 /* * This hook is not called at the beginning of a basic block; the basic @@ -300,10 +382,31 @@ void notrace __sanitizer_cov_trace_pc_exit(void) if (kcov->suppressed_stack_mindelta =3D=3D kcov->suppressed_stack_delta) kcov->suppressed_stack_mindelta--; kcov->suppressed_stack_delta--; - return; + goto handle_distack; } record =3D (canonicalize_ip(_RET_IP_) & KCOV_RECORD_IP_MASK) | KCOV_RECOR= DFLAG_TYPE_EXIT; kcov_add_pc_record(cur, record, false, 0); + +handle_distack: + if (IS_ENABLED(CONFIG_KCOV_MEMORY)) { + kcov =3D cur->kcov; + if (unlikely(kcov->di.num_match_stacks)) { + if (likely(kcov->di.shared_nomatch_depth > 0)) { + kcov->di.shared_nomatch_depth--; + } else { + unsigned int i; + + if (kcov->di.stack_used) + kcov->di.stack_used--; + for (i =3D 0; i < kcov->di.num_match_stacks; i++) { + struct di_stack *dis =3D &kcov->di.match_stacks[i]; + + if (dis->nomatch_depth > 0) + dis->nomatch_depth--; + } + } + } + } } #endif =20 @@ -458,6 +561,17 @@ static void kcov_start(struct task_struct *t, struct k= cov *kcov, unsigned int size, void *area, unsigned int mode, int sequence) { + int i; + + if (IS_ENABLED(CONFIG_KCOV_MEMORY)) { + /* delay injection */ + kcov->di.stack_used =3D 0; + kcov->di.shared_nomatch_depth =3D 0; + kcov->di.pending_sync_bit =3D UINT_MAX; + for (i =3D 0; i < kcov->di.num_match_stacks; i++) + kcov->di.match_stacks[i].elems[0].cur_parent_idx =3D 0; + } + kcov_debug("t =3D %px, size =3D %u, area =3D %px\n", t, size, area); t->kcov =3D kcov; /* Cache in task struct for performance. */ @@ -547,6 +661,15 @@ static void kcov_get(struct kcov *kcov) refcount_inc(&kcov->refcount); } =20 +static void free_di_stacks(struct di_stack *di_stacks, unsigned int num_st= acks) +{ + unsigned int i; + + for (i =3D 0; i < num_stacks; i++) + kfree(di_stacks[i].elems); + kfree(di_stacks); +} + static void kcov_put(struct kcov *kcov) { if (refcount_dec_and_test(&kcov->refcount)) { @@ -555,6 +678,11 @@ static void kcov_put(struct kcov *kcov) kcov_remote_reset(kcov); vfree(kcov->area); ); + if (IS_ENABLED(CONFIG_KCOV_MEMORY)) { + free_di_stacks(kcov->di.match_stacks, kcov->di.num_match_stacks); + if (kcov->di.syncbits_owner && kcov->di.syncbits_owner !=3D kcov) + kcov_put(kcov->di.syncbits_owner); + } kfree(kcov); } } @@ -825,9 +953,180 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsig= ned int cmd, } } =20 +static const struct file_operations kcov_fops; + +static int kcov_set_delay_injection(struct kcov *kcov, unsigned long arg_u= addr) +{ + struct kcov_set_di_arg arg; + struct di_stack *di_stacks; + int i, j; + int ret; + unsigned long flags; + struct file *syncbits_owner_file; + struct kcov *syncbits_owner; + + if (!IS_ENABLED(CONFIG_KCOV_MEMORY)) + return -ENOTSUPP; + if (copy_from_user(&arg, (void __user *)arg_uaddr, sizeof(arg))) + return -EFAULT; + if (arg.num_stacks > 128) + return -ERANGE; + + /* + * This feature *intentionally* allows forcing the kernel to spinloop + * for a long time, including in contexts in which that would normally + * be a terrible idea. + * To prevent the user from causing a persistent system hang with this, + * cap the number of spinloop iterations. + */ + if (arg.spin_limit > 10000000000) + return -ERANGE; + + di_stacks =3D kmalloc_array(arg.num_stacks, sizeof(struct di_stack), GFP_= KERNEL|__GFP_ZERO); + if (!di_stacks) + return -ENOMEM; + + if (arg.sync_bits_fd !=3D -1) { + syncbits_owner_file =3D fget(arg.sync_bits_fd); + if (!syncbits_owner_file) { + ret =3D -EBADF; + goto out_freestacks; + } + if (syncbits_owner_file->f_op !=3D &kcov_fops || + syncbits_owner_file->private_data =3D=3D kcov) { + ret =3D -EBADF; + fput(syncbits_owner_file); + goto out_freestacks; + } + syncbits_owner =3D syncbits_owner_file->private_data; + kcov_get(syncbits_owner); + fput(syncbits_owner_file); + + /* + * Ensure that the syncbits_owner does not, and can never, + * point to yet another KCOV instance. + */ + spin_lock_irqsave(&syncbits_owner->lock, flags); + if (syncbits_owner->di.syncbits_owner && + syncbits_owner->di.syncbits_owner !=3D syncbits_owner) { + spin_unlock_irqrestore(&syncbits_owner->lock, flags); + ret =3D -ELOOP; + goto out_put_syncbits_owner; + } + if (!syncbits_owner->di.syncbits_owner) + syncbits_owner->di.syncbits_owner =3D syncbits_owner; + spin_unlock_irqrestore(&syncbits_owner->lock, flags); + } else { + syncbits_owner =3D kcov; + kcov_get(syncbits_owner); + } + + for (i =3D 0; i < arg.num_stacks; i++) { + struct kcov_di_stack __user *user_stackp =3D + ((struct kcov_di_stack __user *)u64_to_user_ptr(arg.stacks)) + i; + struct kcov_di_stack u_di_stack; + + if (copy_from_user(&u_di_stack, user_stackp, sizeof(struct kcov_di_stack= ))) { + ret =3D -EFAULT; + goto out_put_syncbits_owner; + } + if (u_di_stack.num_elems < 2 || u_di_stack.num_elems > 32 || + u_di_stack.flagidx >=3D NUM_SYNC_BITS) { + ret =3D -ERANGE; + goto out_put_syncbits_owner; + } + if (u_di_stack.type !=3D DI_STACK_WAIT && u_di_stack.type !=3D DI_STACK_= WAKE_PRE && + u_di_stack.type !=3D DI_STACK_WAKE_POST) { + ret =3D -EINVAL; + goto out_put_syncbits_owner; + } + di_stacks[i] =3D (struct di_stack) { + .elems =3D kmalloc_array(u_di_stack.num_elems, sizeof(struct di_stack_e= lem), + GFP_KERNEL), + .num_elems =3D u_di_stack.num_elems, + .type =3D u_di_stack.type, + .flagidx =3D u_di_stack.flagidx + }; + if (!di_stacks[i].elems) { + ret =3D -ENOMEM; + goto out_put_syncbits_owner; + } + for (j =3D 0; j < u_di_stack.num_elems; j++) { + struct kcov_di_stack_elem __user *user_elemp =3D + ((struct kcov_di_stack_elem __user *)u_di_stack.elems) + j; + struct kcov_di_stack_elem user_elem; + + if (copy_from_user(&user_elem, user_elemp, sizeof(user_elem))) { + ret =3D -EFAULT; + goto out_put_syncbits_owner; + } + di_stacks[i].elems[j] =3D (struct di_stack_elem) { + .ip =3D user_elem.ip, + .parent_idx =3D user_elem.parent_idx + }; + } + } + + spin_lock_irqsave(&kcov->lock, flags); + if (kcov->t) { + ret =3D -EBUSY; + } else if (kcov->di.syncbits_owner && kcov->di.syncbits_owner !=3D syncbi= ts_owner) { + ret =3D -EBADFD; + } else { + /* load config */ + free_di_stacks(kcov->di.match_stacks, kcov->di.num_match_stacks); + kcov->di.match_stacks =3D di_stacks; + kcov->di.num_match_stacks =3D arg.num_stacks; + kcov->di.spin_limit =3D arg.spin_limit; + if (!kcov->di.syncbits_owner) { + /* Avoid reference loop. */ + if (syncbits_owner !=3D kcov) + kcov_get(syncbits_owner); + kcov->di.syncbits_owner =3D syncbits_owner; + } + + ret =3D 0; + } + spin_unlock_irqrestore(&kcov->lock, flags); + +out_put_syncbits_owner: + kcov_put(syncbits_owner); +out_freestacks: + if (ret) + free_di_stacks(di_stacks, arg.num_stacks); + return ret; +} + +static int notrace __kcov_spin_wait(struct kcov *kcov, unsigned int flagid= x) +{ + while (!test_bit(flagidx, kcov->di.syncbits_owner->di.sync_bits)) { + u64 spin_limit =3D READ_ONCE(kcov->di.spin_limit); + + if (spin_limit =3D=3D 0) /* spin timeout */ + return -ETIMEDOUT; + WRITE_ONCE(kcov->di.spin_limit, spin_limit - 1); + cpu_relax(); + } + return 0; +} + +/* + * Look up kcov->syncbits_owner in a way that is safe is @kcov is not acti= ve on + * the current task. + */ +static struct kcov *get_syncbits_owner(struct kcov *kcov) +{ + guard(spinlock_irqsave)(&kcov->lock); + + if (!kcov->di.syncbits_owner) + return NULL; + kcov_get(kcov->di.syncbits_owner); + return kcov->di.syncbits_owner; +} + static long kcov_ioctl(struct file *filep, unsigned int cmd, unsigned long= arg) { - struct kcov *kcov; + struct kcov *kcov, *syncbits_owner; int res; struct kcov_remote_arg *remote_arg =3D NULL; unsigned int remote_num_handles; @@ -862,6 +1161,29 @@ static long kcov_ioctl(struct file *filep, unsigned i= nt cmd, unsigned long arg) kcov->mode =3D KCOV_MODE_INIT; spin_unlock_irqrestore(&kcov->lock, flags); return 0; + case KCOV_SET_DI: + return kcov_set_delay_injection(kcov, arg); + case KCOV_RESET_DI_FLAGS: + case KCOV_WAKE_DI_FLAG: + case KCOV_SPINWAIT_DI_FLAG: + if (!IS_ENABLED(CONFIG_KCOV_MEMORY)) + return -ENOTSUPP; + if (arg >=3D NUM_SYNC_BITS) + return -EINVAL; + syncbits_owner =3D get_syncbits_owner(kcov); + if (!syncbits_owner) + return -EINVAL; + if (cmd =3D=3D KCOV_RESET_DI_FLAGS) { + bitmap_clear(syncbits_owner->di.sync_bits, 0, NUM_SYNC_BITS); + res =3D 0; + } else if (cmd =3D=3D KCOV_WAKE_DI_FLAG) { + set_bit(arg, syncbits_owner->di.sync_bits); + res =3D 0; + } else { + res =3D __kcov_spin_wait(syncbits_owner, arg); + } + kcov_put(syncbits_owner); + return res; case KCOV_REMOTE_ENABLE: if (get_user(remote_num_handles, (unsigned __user *)(arg + offsetof(struct kcov_remote_arg, num_handles)))) @@ -1254,9 +1576,56 @@ void notrace __kcov_handle_memaccess(const volatile = void *p, size_t size, unsign struct task_struct *t =3D current; struct memory_access_record *record; unsigned int kcov_mode =3D READ_ONCE(t->kcov_mode); + struct kcov *kcov; + int di_wake_idx =3D -1; =20 if (kcov_mode !=3D KCOV_MODE_TRACE_PC_AND_MEM || !check_kcov_context(t)) return; + + kcov =3D t->kcov; + if (IS_ENABLED(CONFIG_KCOV_MEMORY) && unlikely(kcov->di.num_match_stacks)= ) { + if (unlikely(kcov->di.pending_sync_bit !=3D UINT_MAX)) { + set_bit(kcov->di.pending_sync_bit, kcov->di.syncbits_owner->di.sync_bit= s); + kcov->di.pending_sync_bit =3D UINT_MAX; + } + + if (unlikely(kcov->di.shared_nomatch_depth =3D=3D 0)) { + /* similar to kcov_di_enter_slowpath */ + unsigned int i; + + for (i =3D 0; i < kcov->di.num_match_stacks; i++) { + struct di_stack *dis =3D &kcov->di.match_stacks[i]; + struct di_stack_elem *elem; + + if (dis->nomatch_depth || kcov->di.stack_used !=3D dis->num_elems-1) + continue; + elem =3D &dis->elems[kcov->di.stack_used]; + if (elem->ip !=3D ret_ip) + continue; + if (elem->parent_idx !=3D elem->cur_parent_idx++) + continue; + if (dis->type =3D=3D DI_STACK_WAIT) { + unsigned long wait_record =3D KCOV_RECORDFLAG_TYPE_WAIT; + + wait_record |=3D dis->flagidx; + if (__kcov_spin_wait(kcov->di.syncbits_owner, dis->flagidx)) + wait_record |=3D KCOV_WAIT_TIMEOUT; + kcov_add_pc_record(t, wait_record, false, 0); + } else if (dis->type =3D=3D DI_STACK_WAKE_PRE) { + kcov_add_pc_record(t, + KCOV_RECORDFLAG_TYPE_WAKE | dis->flagidx, + false, 0); + set_bit(dis->flagidx, + kcov->di.syncbits_owner->di.sync_bits); + } else { + /* DI_STACK_WAKE_POST */ + di_wake_idx =3D dis->flagidx; + kcov->di.pending_sync_bit =3D dis->flagidx; + } + } + } + } + if (!kcov_get_memaccess_record(t, &record)) return; *record =3D (struct memory_access_record) { @@ -1287,6 +1656,9 @@ void notrace __kcov_handle_memaccess(const volatile v= oid *p, size_t size, unsign break; } handle_fault:; + + if (unlikely(di_wake_idx !=3D -1)) + kcov_add_pc_record(t, KCOV_RECORDFLAG_TYPE_WAKE | di_wake_idx, false, 0); } =20 void notrace _kcov_handle_memaccess(const volatile void *p, size_t size, u= nsigned int type) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 08ebfe1f3fac..30d748249b1c 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1222,6 +1222,7 @@ static const char *uaccess_safe_builtin[] =3D { "__kcov_handle_memaccess", "__sanitizer_cov_trace_pc", "__sanitizer_cov_trace_pc_entry", + "kcov_di_enter_slowpath", "__sanitizer_cov_trace_pc_exit", "__sanitizer_cov_trace_const_cmp1", "__sanitizer_cov_trace_const_cmp2", --=20 2.55.0.979.g7e5102b832-goog From nobody Fri Sep 25 20:47:43 2026 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 248585908CE for ; Tue, 8 Sep 2026 16:55:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886526; cv=none; b=hAqv4lPRcDrCtc414m8KbWhr8jDpQc/oQAr/VOBmtknAkCy5fWKrZfO5yTRJbbnIeEZsVGG/nnZR1r+o8O5olSQkt2QLPyxE6zdAEmSmMFHdQYZ2hnEvlWDc5kRhkrD/jCrzl5y+POei/9yVA0lK259KMojCTWPufNgbRy6i7iM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788886526; c=relaxed/simple; bh=YCFdNceXAmFoeYaaoZilFisOt8nfet1SAE5gqKxRIb8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kDOu2PZr3sPH+fGVOTasMGEggfmCYOO+79sTlgwZ58/LW4ZsfYjo04t+bamwZF8Cd6/NAs+4ZpPsrATSsLxyavG8kmUrnN6eYc9LMigchJVHKUJNezRdHtyK9QJdQ8pAkb4iM2/FCk0Q9BpE6xuVThoBBV75+cX8oJ5NMJBXBbU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Yq/7VgMx; arc=none smtp.client-ip=74.125.225.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Yq/7VgMx" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-49cda5e048fso145555e9.0 for ; Tue, 08 Sep 2026 09:55:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788886522; x=1789491322; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=70pm1sR81UgF7K4xKYYgzlq1/hkKMl0juN2wWiFyYyI=; b=Yq/7VgMxzKj2sSIPWaUal6Gp2dwf/ASkBKDBCxLBdSKdfc77BkQYljL1YZKVC2Cv7m /5IJ4LhVcmtlmZZV6v3jZ6UAdfYkJ8QOr+Ukyrq+cguvCE1IMmT5UNNeYb6MdTz0mkom wz7sGbbO1DISi4tGrEt7fNaoGs3TgG5Vf/UJU4cFa07Nd/OQaJ9qfaFGCNzdT9oQ8Y+g At8HurIR4Roly9prnzFxA9mCvzkim2jvBzjpLCNMTUIih66xGj6yhYCt3/urvAzxcUzN zUEoX6p1iHWcrYjR9v677OYzRH5/LR6SrctdUyaZk61PIcTKApJIZWzFedMQPNoOu0xF dmAA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788886522; x=1789491322; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=70pm1sR81UgF7K4xKYYgzlq1/hkKMl0juN2wWiFyYyI=; b=dtpLZ9u8xnvZYV3Es2KxgB6GFDiybopN+xzcQR9YgLxOYPPz5KQKFR4xiY2prsZIue O4hJcKHMNeKQT89+sti5h5iV3bT+eMs5cKjJOR1tRd+5xC7rRFPrqWJwfKKx4p6ierWH h5pgF4krb0uOmhTOS9DTt02OxcCYa7s6gvBQgAOPtPxObB2223eScnk32LfrfZq9ptEQ Sbm7zqaRmyPYDJEhVGVLJy3MKB6jYdB61CrBCR0jzeM/J4qa58+Yain3yE4+zPCdYcRP 65JnekkQhRInnGSN+j4c6eELbzLP59T/cqhXHQ0gEzGRUnir17bSAC5q6UjF/HNo9Rm3 l5Zg== X-Forwarded-Encrypted: i=1; AKwUvBx0t+Z7d1gJmzfCEIC6Z8ICrCzKdqRHOeTFA5VyPIOBAXIcz05PumL+M3mqrWXgQZnJ79nRv8fohsN6Zl0=@vger.kernel.org X-Gm-Message-State: AFuF++lOvRLdKNiZV8eRN2jqdNoJNwNhMsGU6HqFPRrXp6j9v+fO4BPb 3uenomFvRD06I9vQCJza39XmTXh8KLiOhJdTkXAt/48iiguJp20hD/5xrJlv62xvAg== X-Gm-Gg: AYBFou2DVOtf5rIQvvf0vKGE6Wqq1FVcLO8njWe9md7i3Bqq29UfkNIyZmpeYMuIZJe ZfFncBYym6cnZu+vI+ws03NUR7XDYo+HGCsxrTQHwIKfUSPgfrGNGrxe9GDxkDlQ2OzW8NOP3+L 4GL2S7Is4p5LeXGhQvSdZo2B4LAx2+eAERsW26FVJO3KjtMOwJ3A76Q0FY3OcRhPtVT8J3dKHwN 1G5iiNKGu41Raq0iwlLh3cyHcXhBdGMzQxUd7VrCI0Ekxuvjniy8g4ClQBlprtt5t/LxY1bEe8p P1Bv9gKNa/HOxbNN/reYxlLiyjd1qEPtXg/GM3Yj0fMx9JU2eACjlyng3mPoJpGt91MyY642Gmk ATjtAm7cbu5BGibFySOkWROwomQlkXhBpGeyFRBtgIw/4zhKKdC1YPKILBhfufDpHpGxkO/Xj+N PVFHLx35h9cDQgEslc3dKyTZCwy95nF2mfF9J2Fg3xPvP0k+1CyLb4ooH9sfLNxuoNI6DUX8mpA 7pp6DTO7Y0IIiLd7Hxj3f6SfGaezCgJF1O05hrJjaEiPtzk X-Received: by 2002:a05:600c:c088:b0:49c:fee1:5095 with SMTP id 5b1f17b1804b1-49d05a2110amr2862085e9.16.1788886522045; Tue, 08 Sep 2026 09:55:22 -0700 (PDT) Received: from localhost ([2a00:79e0:288a:8:ac21:220d:3908:7e61]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-485883c6ba4sm42193292f8f.25.2026.09.08.09.55.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 09:55:21 -0700 (PDT) From: Jann Horn Date: Tue, 08 Sep 2026 18:54:52 +0200 Subject: [PATCH RFC v3 12/12] Documentation/kcov: add documentation for EXT_RECORDS and KCOV_MEMORY Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260908-kcov-extrecord-v3-12-dcbc11593e88@google.com> References: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> In-Reply-To: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com> To: Dmitry Vyukov , Andrey Konovalov , Alexander Potapenko Cc: Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, llvm@lists.linux.dev, Jann Horn X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788886494; l=3853; i=jannh@google.com; s=20240730; h=from:subject:message-id; bh=YCFdNceXAmFoeYaaoZilFisOt8nfet1SAE5gqKxRIb8=; b=aSllr6z4j5ZxQFN1J4mtvDyw4zIh2DzHMu0rf2hZN2Vk9RDxRq5UJb5pLt39tiRv6TbjlJMFn p1/1QLFNZ2ACxGm/+aK3WHNWaEbF1RiMPvLuwTx3hkv8nAjV+J0f3xl X-Developer-Key: i=jannh@google.com; a=ed25519; pk=AljNtGOzXeF6khBXDJVVvwSEkVDGnnZZYqfWhP1V+C8= Document the new KCOV features CONFIG_KCOV_EXT_RECORDS and CONFIG_KCOV_MEMORY. Signed-off-by: Jann Horn --- Documentation/dev-tools/kcov.rst | 70 ++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 70 insertions(+) diff --git a/Documentation/dev-tools/kcov.rst b/Documentation/dev-tools/kco= v.rst index 1a739290c8ec..41eef656ed90 100644 --- a/Documentation/dev-tools/kcov.rst +++ b/Documentation/dev-tools/kcov.rst @@ -383,3 +383,73 @@ local tasks spawned by the process and the global task= that handles USB bus #1: perror("close"), exit(1); return 0; } + +Extended trace format +--------------------- + +If the kernel is built with ``CONFIG_KCOV_EXT_RECORDS=3Dy`` (which require= s LLVM +>=3D23.1.0), the ``KCOV_TRACE_PC_EXT`` mode can be used instead of +``KCOV_TRACE_PC``. + +``KCOV_TRACE_PC_EXT`` uses the top byte of recorded PCs to store a record = type. +The function entry block is recorded with type ``KCOV_RECORDFLAG_TYPE_ENTR= Y``, +and an additional record with ``KCOV_RECORDFLAG_TYPE_EXIT`` is generated on +function exit. + +``KCOV_RECORDFLAG_TYPE_ENTRY`` records are immediately followed by the PC = from +which the call occurred. + +After code sections which have to temporarily stop emitting KCOV trace eve= nts, +a ``KCOV_RECORDFLAG_TYPE_EESUM`` record summarizes the entry/exit events t= hat +happened. + +Together, these record types allow keeping track of the current stack trac= e. + +Memory access tracing +--------------------- + +If the kernel is built with ``CONFIG_KCOV_MEMORY=3Dy`` (which depends on +``CONFIG_KCOV_EXT_RECORDS=3Dy``), the ``KCOV_TRACE_MEMORY_ACCESS`` mode ca= n be +used to produce a trace similar to ``KCOV_TRACE_PC_EXT``, but with additio= nal +``KCOV_RECORDFLAG_TYPE_MEMORY`` records that are emitted for every memory +access. + +In such a trace, when a record with type ``KCOV_RECORDFLAG_TYPE_MEMORY`` is +encountered, the trace element is a ``struct memory_access_record`` with a +size returned by the ioctl ``KCOV_GET_MEMORY_RECORD_SIZE``. + +Delay injection +--------------- + +If the kernel is built with ``CONFIG_KCOV_MEMORY=3Dy``, userspace can conf= igure +soft ordering constraints (like "this load on thread A should happen befor= e that +write happens on thread B") through the ioctl ``KCOV_SET_DI``, with an arg= ument +pointing to a ``struct kcov_set_di_arg``. +The kernel will attempt to fulfill these ordering constraints by spin-wait= ing, +with a configurable timeout ``spin_limit`` after which the kernel gives up= on +forcing the specified ordering. + +For each thread, userspace supplies an array of ``struct kcov_di_stack`` +elements, each of which describes an action to take at a specific call sta= ck +ending at an instrumented memory access. +An action is one of: + + - ``DI_STACK_WAKE_PRE``: "set synchronization bit N before this memory ac= cess" + - ``DI_STACK_WAKE_POST``: "set synchronization bit N after this memory ac= cess" + - ``DI_STACK_WAIT``: "spin-wait for synchronization bit N" + +These are normally paired between two threads: One thread sets synchroniza= tion +bit N after the access at call stack A, another thread spin-waits for +synchronization bit N before the access at call stack B, and this establis= hes an +A-happens-before-B ordering. + +Since this involves multiple threads (and therefore multiple KCOV instance= s), +the member ``sync_bits_fd`` in ``struct kcov_set_di_arg`` informs the kern= el +which KCOV instance holds the shared synchronization bits (where -1 means = the +current instance). + +Userspace can also directly interact with these synchronization bits using: + + - ``KCOV_RESET_DI_FLAGS`` for zeroing all bits + - ``KCOV_WAKE_DI_FLAG`` for setting a specific bit + - ``KCOV_SPINWAIT_DI_FLAG`` for spin-waiting on a specific bit --=20 2.55.0.979.g7e5102b832-goog