From nobody Sun Oct 5 17:56:34 2025 Received: from mail-wr1-f73.google.com (mail-wr1-f73.google.com [209.85.221.73]) (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 509DC236431 for ; Thu, 31 Jul 2025 11:51:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962711; cv=none; b=HbDjs4uEzbShLUfZZVzFsfwBQUPftPzo7NZTYmbgxgRxYNr2z2D1z9qwEmcTDzOANJgD8dPA6bOzh31KMBBK9pRIpkZDNlRphMWL5pNNAY3F2myj2IXhZkMvq7vztMp9JW6IS057X9S9ZpdeK8/zAOjoPbv1UA5dgm7B0VEXzt4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962711; c=relaxed/simple; bh=/YaqQbmjAyDLMKNqMblfPKHKB8Pubt0iKCZQ2aM+B5M=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=q0WQO5YLW74a7JwPGa3UZHrBNVOT10nQv+LmAR8dky6R4tQ6deqoGjveHM8+2HyY1R5097d+3LlJsCO37kgOeU2SC9YMJW3OzPGBUXv98OK9RIaLLrN9fmvMBO8jCudsT5Ahsfsiqqxz1ZDc/dHDqs3ZvK2qA6U9HgEXQi/UDxc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--glider.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=b+Wz1vfP; arc=none smtp.client-ip=209.85.221.73 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=flex--glider.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="b+Wz1vfP" Received: by mail-wr1-f73.google.com with SMTP id ffacd0b85a97d-3b7851a096fso294598f8f.1 for ; Thu, 31 Jul 2025 04:51:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753962706; x=1754567506; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=CXQg+XdaYsLX77wN5kdKJjw9/5umyLhAylJtIjXw9j0=; b=b+Wz1vfPIsWWOiHB/Xjdkh1qiXxo5thlpVxzxWiJDaZKTQLFbJU80BpCAuF6WKlnSV YqQ9iwlLTXxbamOXTLSk/rDhw/kPQnhFXY88b/ezdLZMRoZTOvCWmgh7FPDrSAaL2DI4 F3afeLXyZcMNLB16JM9KANAFLZ/yawj8xKaSaEekF0NUyDmF0kUFm/S0+D3cLm5BSTjD GJ1fVLFjAe/yc8J7H4X4oq7F00dy7hMN+pxhVDu5AiaXpKkymbBomKZ71FWGYBgcBnUh 256C3dHG6zrm3KvXWHcmr6F0dfLS9dYwzJbUcUVsFNvU50RfSYhJ+ipPYfRKjHCHCU7m DyJw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753962706; x=1754567506; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=CXQg+XdaYsLX77wN5kdKJjw9/5umyLhAylJtIjXw9j0=; b=mjDX4MK+3mRdzqwnDyLy0VTvUhiIGwODNJpckiUvjMNjM+PIz3lDbWwoD+RnvZkNJ5 zbErr345XW8MDjCPHvoU9ismdN+I0erIEnYwzyySbWV17j9i1uYTKNkGWM+zGQgK0qAg 2hI0yexArf8Z0j94RTu0gAXLa0pg+o0SOIBjl5kigwHHBuu4aJDWtfo4LvAV3GN1fxGy 2y8aQYy2DO4cg0jR0nUTQwwhnyxDoFgrTsETsbHT1EVqk1gPG7nvnMuLdPEh6F22qc4x MULA2J2L4JTOOAwgzp31PgJQ0UkHPp8sDEQ2v6CcWwVzOhevWZ2nktv84nIhm+aExzaB gNOQ== X-Forwarded-Encrypted: i=1; AJvYcCXTmIDjTe9bQqrw4zM9KQMZKIl1daQqzJDgIN8UZ6jNYvmSSn+YaeyNQ19wg3qNWx24NzEVx5bHvJPHQec=@vger.kernel.org X-Gm-Message-State: AOJu0YzsSJa8uKOE39VaFUv4+AN3HD6ZTjmx25LbFbBX9D1fWooXvAb6 YPQucOotsWfq106G3KUsu6LLlysuTLAr4YnrXBgaw3DjGVUZFd5Zsn5CXzcwGSFY2g7L/TPqy3G 9DJWYDg== X-Google-Smtp-Source: AGHT+IHpZ5VlJorp1XLdO4xxLYlKlSsb2LC7QkiWpuKlb/RDNKu1odUVhKBJq6tTFUk49mJkrqOta4tjDK4= X-Received: from wrbfy8.prod.google.com ([2002:a05:6000:2d88:b0:3b7:8d84:e97]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:3101:b0:3a4:dfc2:bb60 with SMTP id ffacd0b85a97d-3b794fd3f6cmr5156251f8f.26.1753962706607; Thu, 31 Jul 2025 04:51:46 -0700 (PDT) Date: Thu, 31 Jul 2025 13:51:30 +0200 In-Reply-To: <20250731115139.3035888-1-glider@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250731115139.3035888-1-glider@google.com> X-Mailer: git-send-email 2.50.1.552.g942d659e1b-goog Message-ID: <20250731115139.3035888-2-glider@google.com> Subject: [PATCH v4 01/10] x86: kcov: disable instrumentation of arch/x86/kernel/tsc.c From: Alexander Potapenko To: glider@google.com Cc: quic_jiangenj@quicinc.com, linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, Aleksandr Nogikh , Andrey Konovalov , Borislav Petkov , Dave Hansen , Dmitry Vyukov , Ingo Molnar , Josh Poimboeuf , Marco Elver , Peter Zijlstra , Thomas Gleixner Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" sched_clock() appears to be called from interrupts, producing spurious coverage, as reported by CONFIG_KCOV_SELFTEST: RIP: 0010:__sanitizer_cov_trace_pc_guard+0x66/0xe0 kernel/kcov.c:288 ... fault_in_kernel_space+0x17/0x70 arch/x86/mm/fault.c:1119 handle_page_fault arch/x86/mm/fault.c:1477 exc_page_fault+0x56/0x110 arch/x86/mm/fault.c:1538 asm_exc_page_fault+0x26/0x30 ./arch/x86/include/asm/idtentry.h:623 RIP: 0010:__sanitizer_cov_trace_pc_guard+0x66/0xe0 kernel/kcov.c:288 ... sched_clock+0x12/0x70 arch/x86/kernel/tsc.c:284 __lock_pin_lock kernel/locking/lockdep.c:5628 lock_pin_lock+0xd7/0x180 kernel/locking/lockdep.c:5959 rq_pin_lock kernel/sched/sched.h:1761 rq_lock kernel/sched/sched.h:1838 __schedule+0x3a8/0x4b70 kernel/sched/core.c:6691 preempt_schedule_irq+0xbf/0x160 kernel/sched/core.c:7090 irqentry_exit+0x6f/0x90 kernel/entry/common.c:354 asm_sysvec_reschedule_ipi+0x1a/0x20 ./arch/x86/include/asm/idtentry.h:707 RIP: 0010:selftest+0x26/0x60 kernel/kcov.c:1223 ... kcov_init+0x81/0xa0 kernel/kcov.c:1252 do_one_initcall+0x2e1/0x910 do_initcall_level+0xff/0x160 init/main.c:1319 do_initcalls+0x4a/0xa0 init/main.c:1335 kernel_init_freeable+0x448/0x610 init/main.c:1567 kernel_init+0x24/0x230 init/main.c:1457 ret_from_fork+0x60/0x90 arch/x86/kernel/process.c:153 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 Signed-off-by: Alexander Potapenko --- Change-Id: Ica191d73bf5601b31e893d6e517b91be983e986a --- arch/x86/kernel/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 0d2a6d953be91..ca134ce03eea9 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -43,6 +43,8 @@ KCOV_INSTRUMENT_dumpstack_$(BITS).o :=3D n KCOV_INSTRUMENT_unwind_orc.o :=3D n KCOV_INSTRUMENT_unwind_frame.o :=3D n KCOV_INSTRUMENT_unwind_guess.o :=3D n +# Avoid instrumenting code that produces spurious coverage in interrupts. +KCOV_INSTRUMENT_tsc.o :=3D n =20 CFLAGS_head32.o :=3D -fno-stack-protector CFLAGS_head64.o :=3D -fno-stack-protector --=20 2.50.1.552.g942d659e1b-goog From nobody Sun Oct 5 17:56:34 2025 Received: from mail-wm1-f73.google.com (mail-wm1-f73.google.com [209.85.128.73]) (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 06A332C08C1 for ; Thu, 31 Jul 2025 11:51:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962712; cv=none; b=p6B0PX9qOHCzW/QNK/MHzzeFbPMy2nRpMi8RzjoWDfmllY1KbhJj9D7NidPJlv0EJgpHDrhZ73UGjLPyc+Hfe//henT0wxfFl6N5vUBOOH1IZnwCBi8/jtoyTwYipdE+wwQRe1G23yzSILEcAu+1EH05DqGJWGGLT0wjGXoWce8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962712; c=relaxed/simple; bh=C0sm9IXEXO6Tm8UTYt3LMTFM7Ou7qy/wmj90Uarc8XQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Uhf15jVZFHUfOG/6E63zSpKtpLoVOhK6yFpshkNTryBCvi6RmOnhZ9h2de6gbSP4Gmgp0ijE3DbkP9Yg8gXarRkd1vkKKnUi7wwuw423DlXAdh2+NM6wXgPru27VyTDbkLEqOPTU7tzakSEF3WWaf9SKeqtCUooX9jjPg2/UiKk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--glider.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=TAypsaFf; arc=none smtp.client-ip=209.85.128.73 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=flex--glider.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="TAypsaFf" Received: by mail-wm1-f73.google.com with SMTP id 5b1f17b1804b1-4561611dc2aso8318145e9.0 for ; Thu, 31 Jul 2025 04:51:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753962709; x=1754567509; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=CQvXhi+JRNfdVXUC3A+PGrkf/DlYZ6BztZDrEED0HWA=; b=TAypsaFf36NGxh8qzfpDtyArDpTrIZHugnO3zOVdEjQ48upLkEwOG6kRbxndMmoNVM 9Q48msfCuLKr43esYly5zoG+sZjOX4N5jqcAmfnG2PPICTUF0T2XTC1JEwrAMChMl2vp 1S7vlp8Af279IrtVoiiJ+J5yYMG/CxXIpNiktgIdXOuTGo4CcX30DBzPaBCCr6JSHrK3 M5Nsrob9gwbtX/AOaDEBl4sPLMVVIMoUuaWSxHayZOQUBG4OOjdzZSc1zQ2f+J+9x9zv S0RZF5GB7/n4VE9PyL3tieRG9CZa6m7WTY1Az8Uv96WJSKln4X/N65l2V47ddFUrPoj0 69Xg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753962709; x=1754567509; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=CQvXhi+JRNfdVXUC3A+PGrkf/DlYZ6BztZDrEED0HWA=; b=mDvCcnTmHV1Ng+XiPPhpAq5RPs5oKiP+5vK6jAcjgkq20A8BUZUxI1YzZNB9j+tbRf A4kk+jb3rTLrmPuLwI5Gt1wqFvxkWX9E10jXo8lUNSTQ45sNjDzJ95ggs/6w0r9iNMsY jcAfGQvDDOV2LeI2rPDQP2aAHXJsFSHZoqcCKsgGmuTjFwsHs+UQZUs4YFRggg+LoRhY +Qj1ydkS4WLMbnWGIKUPxiGSjfJ85T+fULvLkEf4UDz0Litp/6hfDPKbgA4oQ45gM22C 0hyVmdFLsb4Ln4ciVfv3Syerles+NfIqZfDwp1mQPCd1xXvqJYJD16HXCcatSBvv0ank cMsQ== X-Forwarded-Encrypted: i=1; AJvYcCV1YNNl/8TJG73w7d+wsjzNGkZ9eiphl67/wqwjrfXBzb2iCHT5R8nQstqL3Fq3+ieEtmpGpkzclRuOYGw=@vger.kernel.org X-Gm-Message-State: AOJu0Yyc5Fl4XaPMy3qClEqZNvJz7YjQLMML+bKazTFbQdGtSE96mawY p9DWyXlOynKhlapSYcrAZKj8iz6Lv66bxIYf3A2dk0rjPZFfkFbtgpV4TY/SsGOpq/bs+mYxLFp wC/8aew== X-Google-Smtp-Source: AGHT+IF3aDST1Gm4tiVNl+bsKkQtjhouu0IeNJsrxrczaDXlohR9f6qhG5KcqvqJsrj+SFS6mHGvh5BmEqg= X-Received: from wmsp27.prod.google.com ([2002:a05:600c:1d9b:b0:456:1ba0:c8ac]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:1388:b0:456:25e7:bed with SMTP id 5b1f17b1804b1-4589af5ba2fmr58419925e9.14.1753962709498; Thu, 31 Jul 2025 04:51:49 -0700 (PDT) Date: Thu, 31 Jul 2025 13:51:31 +0200 In-Reply-To: <20250731115139.3035888-1-glider@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250731115139.3035888-1-glider@google.com> X-Mailer: git-send-email 2.50.1.552.g942d659e1b-goog Message-ID: <20250731115139.3035888-3-glider@google.com> Subject: [PATCH v4 02/10] kcov: elaborate on using the shared buffer From: Alexander Potapenko To: glider@google.com Cc: quic_jiangenj@quicinc.com, linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, Dmitry Vyukov , Aleksandr Nogikh , Andrey Konovalov , Borislav Petkov , Dave Hansen , Ingo Molnar , Josh Poimboeuf , Marco Elver , Peter Zijlstra , Thomas Gleixner Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a paragraph about the shared buffer usage to kcov.rst. Signed-off-by: Alexander Potapenko Reviewed-by: Dmitry Vyukov --- v3: - add Reviewed-by: Dmitry Vyukov Change-Id: Ia47ef7c3fcc74789fe57a6e1d93e29a42dbc0a97 --- Documentation/dev-tools/kcov.rst | 55 ++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/Documentation/dev-tools/kcov.rst b/Documentation/dev-tools/kco= v.rst index 6611434e2dd24..abf3ad2e784e8 100644 --- a/Documentation/dev-tools/kcov.rst +++ b/Documentation/dev-tools/kcov.rst @@ -137,6 +137,61 @@ mmaps coverage buffer, and then forks child processes = in a loop. The child processes only need to enable coverage (it gets disabled automatically when a thread exits). =20 +Shared buffer for coverage collection +------------------------------------- +KCOV employs a shared memory buffer as a central mechanism for efficient a= nd +direct transfer of code coverage information between the kernel and usersp= ace +applications. + +Calling ``ioctl(fd, KCOV_INIT_TRACE, size)`` initializes coverage collecti= on for +the current thread associated with the file descriptor ``fd``. The buffer +allocated will hold ``size`` unsigned long values, as interpreted by the k= ernel. +Notably, even in a 32-bit userspace program on a 64-bit kernel, each entry= will +occupy 64 bits. + +Following initialization, the actual shared memory buffer is created using= :: + + mmap(NULL, size * sizeof(unsigned long), PROT_READ | PROT_WRITE, MAP_S= HARED, fd, 0) + +The size of this memory mapping, calculated as ``size * sizeof(unsigned lo= ng)``, +must be a multiple of ``PAGE_SIZE``. + +This buffer is then shared between the kernel and the userspace. The first +element of the buffer contains the number of PCs stored in it. +Both the userspace and the kernel may write to the shared buffer, so to av= oid +race conditions each userspace thread should only update its own buffer. + +Normally the shared buffer is used as follows:: + + Userspace Kernel + -----------------------------------------+----------------------------= --------------- + ioctl(fd, KCOV_INIT_TRACE, size) | + | Initialize coverage for = current thread + mmap(..., MAP_SHARED, fd, 0) | + | Allocate the buffer, ini= tialize it + | with zeroes + ioctl(fd, KCOV_ENABLE, KCOV_TRACE_PC) | + | Enable PC collection for= current thread + | starting at buffer[1] (K= COV_ENABLE will + | already write some cover= age) + Atomically write 0 to buffer[0] to | + reset the coverage | + | + Execute some syscall(s) | + | Write new coverage start= ing at + | buffer[1] + Atomically read buffer[0] to get the | + total coverage size at this point in | + time | + | + ioctl(fd, KCOV_DISABLE, 0) | + | Write some more coverage= for ioctl(), + | then disable PC collecti= on for current + | thread + Safely read and process the coverage | + up to the buffer[0] value saved above | + + Comparison operands collection ------------------------------ =20 --=20 2.50.1.552.g942d659e1b-goog From nobody Sun Oct 5 17:56:34 2025 Received: from mail-ej1-f74.google.com (mail-ej1-f74.google.com [209.85.218.74]) (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 C2F502C15B9 for ; Thu, 31 Jul 2025 11:51:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962715; cv=none; b=POUXwec+fMTRU26JwSa+di+4Dr5htVyqq4gNgibfiGGEjioHfDsBXAS8mr7HCqtr0N5YqlxXMfEeviWMh+4p/pBX5Or+FLATqKlXWmG88/YS9ElCl38my16pau88lf4nSSTBVaUK14vaV/uR8oD/VTEaTevO3x+r/AbAeqRlio8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962715; c=relaxed/simple; bh=72TTR0RUXLLmYjXf/Z0q8ilDDC2a8g5aDq0nln3D2lU=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=U8CIo/7ksN7zGPigY6NJAjkEo9Qw9WeekWFp9qY8J2jQxbEXqRjG0bEv31AIvsdkKkN6s4C51MoNS3koGvfkZ1b/fPLftX9E+4oxOijT9kF36N6uJe0gyiG4SO055Nv6eVTMmh9Zf/63nC/Tz6c8QW2DV3WPPe5bXh+1w7Rd57w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--glider.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=ExvKti5D; arc=none smtp.client-ip=209.85.218.74 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=flex--glider.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="ExvKti5D" Received: by mail-ej1-f74.google.com with SMTP id a640c23a62f3a-af658355147so72445766b.2 for ; Thu, 31 Jul 2025 04:51:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753962712; x=1754567512; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=DzEkgpRCnk/Bq1twXrDYYtTyuJB3TyxcrLIFIKrRv4o=; b=ExvKti5DvjINwYrvzTBXTWWaYwg48vBqxLtk4VpWwwLRimcoesXdKSoIzeiedWZAxb 5UvsVXLKY8O246r/ES0ohZrdop7qGzbwq8gzgKcSINMKC6z1JjcCQI4USg5uDUv5gvPO efjPkiSYlXO1C34n8eb7b4wY0id9DxkFHTEvkW8u2LIhei7RMwQfDZH/a74D8FY6zDAR fZnF33zO76aCyLzG48Mhnsy7qFzWpvrNimpWNMBru/plu4dHmAnDzGtDspv75rmi36Q3 Nzmd/bvaXz+B3wAfz0FK+USqPnIQed6zLEyq4w8A1IiVeieLoLYuyRf0VnA31319TgoE s93g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753962712; x=1754567512; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=DzEkgpRCnk/Bq1twXrDYYtTyuJB3TyxcrLIFIKrRv4o=; b=VHAXYPMnlB1GzdHSutAjxBlwsOvAh2NLgF7RYhCK6a2R4IceY3X4K/LFMyamGPXdLp YODR8m02AGZGv8+FKiLKkKelGBR8+aL7RJdntlzWYTVWkDsLmnXABSMjmN8RSIzzXqv+ SjLkTlrxDhqOFdY6c8aviduhCF0pHV4rXm4nqM8tk2U7znri7U+k6pi2nK70U67uwb5j X0Z82qXloBAIzBtD5iu2vVmUZi4t8iZs6aa5+IX9+nSVupzJFFr/MygzUXZTfzhx1cqQ YSxhnjsd2zo7nob5pOSbVHTuO1r1o/9copqB4iAXkHT7aEO44RYn9OPZqtlPze4g4uOa dHYA== X-Forwarded-Encrypted: i=1; AJvYcCUDnWYYkvBjaKBDKP5310gQuDHOqq9YWf+3a5G/VbRX+NlweuD5vCkZC5MFVphlO8L2ggsBQrZ3NyCNhs4=@vger.kernel.org X-Gm-Message-State: AOJu0YyrnuMcs+X7ITp+49xhy8Bti7SLESzW/F+zB8Lo28SvgYgk9bRA s6Ns0TLXRLJzHcMMSYpff6M22PayDV9Jhky0uG0fGE0LHcr7cvHPQaX4VofJ9DjCtmgr/vuIAdO YwnViZQ== X-Google-Smtp-Source: AGHT+IEyVPLUOYmer2m28FP5XC/20+U99rnhjL4y4I8h0rQ5jZsUEJbVCCEwdTT5ov7ImX/d+XIysFJNPaY= X-Received: from ejcss8.prod.google.com ([2002:a17:907:c008:b0:ae3:64a9:78cd]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a17:907:728c:b0:ad8:85df:865b with SMTP id a640c23a62f3a-af8fd978528mr766051066b.33.1753962712055; Thu, 31 Jul 2025 04:51:52 -0700 (PDT) Date: Thu, 31 Jul 2025 13:51:32 +0200 In-Reply-To: <20250731115139.3035888-1-glider@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250731115139.3035888-1-glider@google.com> X-Mailer: git-send-email 2.50.1.552.g942d659e1b-goog Message-ID: <20250731115139.3035888-4-glider@google.com> Subject: [PATCH v4 03/10] kcov: factor out struct kcov_state From: Alexander Potapenko To: glider@google.com Cc: quic_jiangenj@quicinc.com, linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, Dmitry Vyukov , Aleksandr Nogikh , Andrey Konovalov , Borislav Petkov , Dave Hansen , Ingo Molnar , Josh Poimboeuf , Marco Elver , Peter Zijlstra , Thomas Gleixner Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Group several kcov-related fields (area, size, sequence) that are stored in various structures, into `struct kcov_state`, so that these fields can be easily passed around and manipulated. Note that now the spinlock in struct kcov applies to every member of struct kcov_state, including the sequence number. This prepares us for the upcoming change that will introduce more kcov state. Also update the MAINTAINERS entry: add include/linux/kcov_types.h, add myself as kcov reviewer. Signed-off-by: Alexander Potapenko Reviewed-by: Dmitry Vyukov --- v4: - add Reviewed-by: Dmitry Vyukov v3: - fix comments by Dmitry Vyukov: - adjust a comment in sched.h - fix incorrect parameters passed to kcov_start() v2: - add myself to kcov MAINTAINERS - rename kcov-state.h to kcov_types.h - update the description - do not move mode into struct kcov_state - use '{ }' instead of '{ 0 }' Change-Id: If225682ea2f6e91245381b3270de16e7ea40df39 --- MAINTAINERS | 2 + include/linux/kcov.h | 2 +- include/linux/kcov_types.h | 22 ++++++++ include/linux/sched.h | 13 +---- kernel/kcov.c | 112 ++++++++++++++++--------------------- 5 files changed, 77 insertions(+), 74 deletions(-) create mode 100644 include/linux/kcov_types.h diff --git a/MAINTAINERS b/MAINTAINERS index c0b444e5fd5ad..6906eb9d88dae 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13008,11 +13008,13 @@ F: include/linux/kcore.h KCOV R: Dmitry Vyukov R: Andrey Konovalov +R: Alexander Potapenko L: kasan-dev@googlegroups.com S: Maintained B: https://bugzilla.kernel.org/buglist.cgi?component=3DSanitizers&product= =3DMemory%20Management F: Documentation/dev-tools/kcov.rst F: include/linux/kcov.h +F: include/linux/kcov_types.h F: include/uapi/linux/kcov.h F: kernel/kcov.c F: scripts/Makefile.kcov diff --git a/include/linux/kcov.h b/include/linux/kcov.h index 75a2fb8b16c32..2b3655c0f2278 100644 --- a/include/linux/kcov.h +++ b/include/linux/kcov.h @@ -2,7 +2,7 @@ #ifndef _LINUX_KCOV_H #define _LINUX_KCOV_H =20 -#include +#include #include =20 struct task_struct; diff --git a/include/linux/kcov_types.h b/include/linux/kcov_types.h new file mode 100644 index 0000000000000..53b25b6f0addd --- /dev/null +++ b/include/linux/kcov_types.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_KCOV_STATE_H +#define _LINUX_KCOV_STATE_H + +#ifdef CONFIG_KCOV +/* See kernel/kcov.c for more details. */ +struct kcov_state { + /* Size of the area (in long's). */ + unsigned int size; + + /* Buffer for coverage collection, shared with the userspace. */ + void *area; + + /* + * KCOV sequence number: incremented each time kcov is reenabled, used + * by kcov_remote_stop(), see the comment there. + */ + int sequence; +}; +#endif /* CONFIG_KCOV */ + +#endif /* _LINUX_KCOV_STATE_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index aa9c5be7a6325..7901fece5aba3 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -1516,16 +1517,11 @@ struct task_struct { #endif /* CONFIG_TRACING */ =20 #ifdef CONFIG_KCOV - /* See kernel/kcov.c for more details. */ - /* Coverage collection mode enabled for this task (0 if disabled): */ unsigned int kcov_mode; =20 - /* Size of the kcov_area: */ - unsigned int kcov_size; - - /* Buffer for coverage collection: */ - void *kcov_area; + /* KCOV buffer state for this task. */ + struct kcov_state kcov_state; =20 /* KCOV descriptor wired with this task or NULL: */ struct kcov *kcov; @@ -1533,9 +1529,6 @@ struct task_struct { /* KCOV common handle for remote coverage collection: */ u64 kcov_handle; =20 - /* KCOV sequence number: */ - int kcov_sequence; - /* Collect coverage from softirq context: */ unsigned int kcov_softirq; #endif diff --git a/kernel/kcov.c b/kernel/kcov.c index 187ba1b80bda1..5170f367c8a1b 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -53,24 +54,17 @@ struct kcov { * - each code section for remote coverage collection */ refcount_t refcount; - /* The lock protects mode, size, area and t. */ + /* The lock protects mode, state and t. */ spinlock_t lock; enum kcov_mode mode; - /* Size of arena (in long's). */ - unsigned int size; - /* Coverage buffer shared with user space. */ - void *area; + struct kcov_state state; + /* Task for which we collect coverage, or NULL. */ struct task_struct *t; /* Collecting coverage from remote (background) threads. */ bool remote; /* Size of remote area (in long's). */ unsigned int remote_size; - /* - * Sequence is incremented each time kcov is reenabled, used by - * kcov_remote_stop(), see the comment there. - */ - int sequence; }; =20 struct kcov_remote_area { @@ -92,11 +86,9 @@ struct kcov_percpu_data { void *irq_area; local_lock_t lock; =20 - unsigned int saved_mode; - unsigned int saved_size; - void *saved_area; + enum kcov_mode saved_mode; struct kcov *saved_kcov; - int saved_sequence; + struct kcov_state saved_state; }; =20 static DEFINE_PER_CPU(struct kcov_percpu_data, kcov_percpu_data) =3D { @@ -217,10 +209,10 @@ void notrace __sanitizer_cov_trace_pc(void) if (!check_kcov_mode(KCOV_MODE_TRACE_PC, t)) return; =20 - area =3D t->kcov_area; + area =3D t->kcov_state.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 < t->kcov_state.size)) { /* Previously we write pc before updating pos. However, some * early interrupt code could bypass check_kcov_mode() check * and invoke __sanitizer_cov_trace_pc(). If such interrupt is @@ -250,10 +242,10 @@ static void notrace write_comp_data(u64 type, u64 arg= 1, u64 arg2, u64 ip) =20 /* * We write all comparison arguments and types as u64. - * The buffer was allocated for t->kcov_size unsigned longs. + * The buffer was allocated for t->kcov_state.size unsigned longs. */ - area =3D (u64 *)t->kcov_area; - max_pos =3D t->kcov_size * sizeof(unsigned long); + area =3D (u64 *)t->kcov_state.area; + max_pos =3D t->kcov_state.size * sizeof(unsigned long); =20 count =3D READ_ONCE(area[0]); =20 @@ -354,15 +346,13 @@ 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, - int sequence) + enum kcov_mode mode, struct kcov_state *state) { - kcov_debug("t =3D %px, size =3D %u, area =3D %px\n", t, size, area); + kcov_debug("t =3D %px, size =3D %u, area =3D %px\n", t, state->size, + state->area); t->kcov =3D kcov; /* Cache in task struct for performance. */ - t->kcov_size =3D size; - t->kcov_area =3D area; - t->kcov_sequence =3D sequence; + t->kcov_state =3D *state; /* See comment in check_kcov_mode(). */ barrier(); WRITE_ONCE(t->kcov_mode, mode); @@ -373,14 +363,14 @@ static void kcov_stop(struct task_struct *t) WRITE_ONCE(t->kcov_mode, KCOV_MODE_DISABLED); barrier(); t->kcov =3D NULL; - t->kcov_size =3D 0; - t->kcov_area =3D NULL; + t->kcov_state.size =3D 0; + t->kcov_state.area =3D NULL; } =20 static void kcov_task_reset(struct task_struct *t) { kcov_stop(t); - t->kcov_sequence =3D 0; + t->kcov_state.sequence =3D 0; t->kcov_handle =3D 0; } =20 @@ -396,7 +386,7 @@ static void kcov_reset(struct kcov *kcov) kcov->mode =3D KCOV_MODE_INIT; kcov->remote =3D false; kcov->remote_size =3D 0; - kcov->sequence++; + kcov->state.sequence++; } =20 static void kcov_remote_reset(struct kcov *kcov) @@ -436,7 +426,7 @@ static void kcov_put(struct kcov *kcov) { if (refcount_dec_and_test(&kcov->refcount)) { kcov_remote_reset(kcov); - vfree(kcov->area); + vfree(kcov->state.area); kfree(kcov); } } @@ -493,8 +483,8 @@ static int kcov_mmap(struct file *filep, struct vm_area= _struct *vma) unsigned long flags; =20 spin_lock_irqsave(&kcov->lock, flags); - size =3D kcov->size * sizeof(unsigned long); - if (kcov->area =3D=3D NULL || vma->vm_pgoff !=3D 0 || + size =3D kcov->state.size * sizeof(unsigned long); + if (kcov->state.area =3D=3D NULL || vma->vm_pgoff !=3D 0 || vma->vm_end - vma->vm_start !=3D size) { res =3D -EINVAL; goto exit; @@ -502,7 +492,7 @@ static int kcov_mmap(struct file *filep, struct vm_area= _struct *vma) spin_unlock_irqrestore(&kcov->lock, flags); vm_flags_set(vma, VM_DONTEXPAND); for (off =3D 0; off < size; off +=3D PAGE_SIZE) { - page =3D vmalloc_to_page(kcov->area + off); + page =3D vmalloc_to_page(kcov->state.area + off); res =3D vm_insert_page(vma, vma->vm_start + off, page); if (res) { pr_warn_once("kcov: vm_insert_page() failed\n"); @@ -523,7 +513,7 @@ static int kcov_open(struct inode *inode, struct file *= filep) if (!kcov) return -ENOMEM; kcov->mode =3D KCOV_MODE_DISABLED; - kcov->sequence =3D 1; + kcov->state.sequence =3D 1; refcount_set(&kcov->refcount, 1); spin_lock_init(&kcov->lock); filep->private_data =3D kcov; @@ -558,10 +548,10 @@ static int kcov_get_mode(unsigned long arg) static void kcov_fault_in_area(struct kcov *kcov) { unsigned long stride =3D PAGE_SIZE / sizeof(unsigned long); - unsigned long *area =3D kcov->area; + unsigned long *area =3D kcov->state.area; unsigned long offset; =20 - for (offset =3D 0; offset < kcov->size; offset +=3D stride) + for (offset =3D 0; offset < kcov->state.size; offset +=3D stride) READ_ONCE(area[offset]); } =20 @@ -600,7 +590,7 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigne= d int cmd, * at task exit or voluntary by KCOV_DISABLE. After that it can * be enabled for another task. */ - if (kcov->mode !=3D KCOV_MODE_INIT || !kcov->area) + if (kcov->mode !=3D KCOV_MODE_INIT || !kcov->state.area) return -EINVAL; t =3D current; if (kcov->t !=3D NULL || t->kcov !=3D NULL) @@ -610,8 +600,7 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigne= d int cmd, return mode; kcov_fault_in_area(kcov); kcov->mode =3D mode; - kcov_start(t, kcov, kcov->size, kcov->area, kcov->mode, - kcov->sequence); + kcov_start(t, kcov, mode, &kcov->state); kcov->t =3D t; /* Put either in kcov_task_exit() or in KCOV_DISABLE. */ kcov_get(kcov); @@ -628,7 +617,7 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigne= d int cmd, kcov_put(kcov); return 0; case KCOV_REMOTE_ENABLE: - if (kcov->mode !=3D KCOV_MODE_INIT || !kcov->area) + if (kcov->mode !=3D KCOV_MODE_INIT || !kcov->state.area) return -EINVAL; t =3D current; if (kcov->t !=3D NULL || t->kcov !=3D NULL) @@ -722,8 +711,8 @@ static long kcov_ioctl(struct file *filep, unsigned int= cmd, unsigned long arg) vfree(area); return -EBUSY; } - kcov->area =3D area; - kcov->size =3D size; + kcov->state.area =3D area; + kcov->state.size =3D size; kcov->mode =3D KCOV_MODE_INIT; spin_unlock_irqrestore(&kcov->lock, flags); return 0; @@ -821,10 +810,8 @@ static void kcov_remote_softirq_start(struct task_stru= ct *t) mode =3D READ_ONCE(t->kcov_mode); barrier(); if (kcov_mode_enabled(mode)) { + data->saved_state =3D t->kcov_state; data->saved_mode =3D mode; - data->saved_size =3D t->kcov_size; - data->saved_area =3D t->kcov_area; - data->saved_sequence =3D t->kcov_sequence; data->saved_kcov =3D t->kcov; kcov_stop(t); } @@ -835,13 +822,9 @@ static void kcov_remote_softirq_stop(struct task_struc= t *t) struct kcov_percpu_data *data =3D this_cpu_ptr(&kcov_percpu_data); =20 if (data->saved_kcov) { - kcov_start(t, data->saved_kcov, data->saved_size, - data->saved_area, data->saved_mode, - data->saved_sequence); - data->saved_mode =3D 0; - data->saved_size =3D 0; - data->saved_area =3D NULL; - data->saved_sequence =3D 0; + kcov_start(t, data->saved_kcov, data->saved_mode, + &data->saved_state); + data->saved_state =3D (struct kcov_state){}; data->saved_kcov =3D NULL; } } @@ -850,12 +833,12 @@ void kcov_remote_start(u64 handle) { struct task_struct *t =3D current; struct kcov_remote *remote; + struct kcov_state state; + enum kcov_mode mode; + unsigned long flags; + unsigned int size; struct kcov *kcov; - unsigned int mode; void *area; - unsigned int size; - int sequence; - unsigned long flags; =20 if (WARN_ON(!kcov_check_handle(handle, true, true, true))) return; @@ -900,7 +883,7 @@ void kcov_remote_start(u64 handle) * KCOV_DISABLE / kcov_remote_reset(). */ mode =3D kcov->mode; - sequence =3D kcov->sequence; + state.sequence =3D kcov->state.sequence; if (in_task()) { size =3D kcov->remote_size; area =3D kcov_remote_area_get(size); @@ -923,12 +906,14 @@ void kcov_remote_start(u64 handle) =20 /* Reset coverage size. */ *(u64 *)area =3D 0; + state.area =3D area; + state.size =3D size; =20 if (in_serving_softirq()) { kcov_remote_softirq_start(t); t->kcov_softirq =3D 1; } - kcov_start(t, kcov, size, area, mode, sequence); + kcov_start(t, kcov, mode, &state); =20 local_unlock_irqrestore(&kcov_percpu_data.lock, flags); =20 @@ -1027,9 +1012,9 @@ void kcov_remote_stop(void) } =20 kcov =3D t->kcov; - area =3D t->kcov_area; - size =3D t->kcov_size; - sequence =3D t->kcov_sequence; + area =3D t->kcov_state.area; + size =3D t->kcov_state.size; + sequence =3D t->kcov_state.sequence; =20 kcov_stop(t); if (in_serving_softirq()) { @@ -1042,8 +1027,9 @@ void kcov_remote_stop(void) * KCOV_DISABLE could have been called between kcov_remote_start() * 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); + if (sequence =3D=3D kcov->state.sequence && kcov->remote) + kcov_move_area(kcov->mode, kcov->state.area, kcov->state.size, + area); spin_unlock(&kcov->lock); =20 if (in_task()) { --=20 2.50.1.552.g942d659e1b-goog From nobody Sun Oct 5 17:56:34 2025 Received: from mail-wr1-f73.google.com (mail-wr1-f73.google.com [209.85.221.73]) (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 42A192C3242 for ; Thu, 31 Jul 2025 11:51:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962717; cv=none; b=KwIJKPdK0qezG7vVhcPufHI25VX8cFKDpxew2EXZ03p7gQkFrKdvXoR7tKTaZLgsg95zR2pO3OkVCsiAgeDbpk860v9DoC76m0WYl5yrK9r6YJ49cjPWk1iMeL2t+lBdDirGAq16QMUAI2S4r2voP4RrV5dIKdGZSshMcnWMHHE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962717; c=relaxed/simple; bh=jag1r1U9xtFWGzbHHaOAoGJUilJf+3MCA7L1ZTkpTb8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=nI7PKGP6/nR2PK6DZ+japFvKAQ6HIPWSwz2gwiNlqVlUX3F0XMWC1TisgcUXIeYl1CcRXE6pBw4U0V21MuOldXLm+7weG+NJaRHcHWwv4/aTL20KJzp+q/iQAWjn6XAA/EIAfIGWHHy3GejEXmKI3NOmubdQuGsoK12NeOPGqSc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--glider.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=HvsyRSJ6; arc=none smtp.client-ip=209.85.221.73 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=flex--glider.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="HvsyRSJ6" Received: by mail-wr1-f73.google.com with SMTP id ffacd0b85a97d-3b780da0ab6so435191f8f.0 for ; Thu, 31 Jul 2025 04:51:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753962714; x=1754567514; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Gx/82C9/LmdN6I5VG5zleKCD5AaUcYE9gaKc5zZKlEM=; b=HvsyRSJ613s8bUdj2QgOqxlxGSOnOP66NnH1oXSapnhKjCGPJRu/We+UNiTw1+9G2h G4fgI5g/ubMjQfZDE7JNRON66DzZ5R0Obqq3MoKcwqab6XbdbmRleRLQw8VkT+YkPBqx ApGTTQh46rf/OdEsLr4lF4r6Uz3gSYoMglzte/5XxEM1OGjIm23Ml0VtV0sS0/SM847e WPUwHhRaBpjV/LGSwRuavIynS1zdIKpNKnEioj5WkWOXkj5hovdKq0Ouk5t8ixomQd2P 9SsAxt+/FeUJjMIancGliXzfxjhH2xmgzYPbWlnQaICTdoS0dHfe9W2uZ8ozgi97GzLX cexw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753962714; x=1754567514; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Gx/82C9/LmdN6I5VG5zleKCD5AaUcYE9gaKc5zZKlEM=; b=wZX00F/6/7DtfzsEk6z51HbqmEQk5WH23gLy75RK/bm2AETrxlWHmI6SjQME/Qvcgj Wheu7EeZzwmQvckGQ38sy6GN87cg2E2xanKmqdGNKqssifqgWdFGM0RqVNTWX/j8IV7P HtTbyM0xStf7eB7ONKb7YPtANb+qXR0jN1ndkou+Qq9R6Hxxaw/jzkQEeMTW2T+dSrWR ZubTN7Ke3B0p5sRCM3uzsGZ98R2wfxPG0Zkb4BKexRZruG4ZKfw58CnOTPn0TG+KLCiW DDbbicEXI+kX2ro2DWC7EQan4F+DR7TtJD0iTs14+SUCdjdYl9VB8aHrK8+gJ1fXQ5o5 fYRw== X-Forwarded-Encrypted: i=1; AJvYcCW2XSoyl8wVVeroxVVSMsF4RmOIwo8JxVGF3ZD3BBJ0YwDHKg1QoASCwvvKYV/oYXIu7CPPrh2nsSDe0m0=@vger.kernel.org X-Gm-Message-State: AOJu0YyhhCBEOOlCt/aAemU6wgzeYXP3e/pp5R0tXtnyRUYzhLDrtUnG loC9wanG+m/qM5KXV9vw7F05XYXFul5MpoS9+JHwinuPK9nEKh7K/JKvEWX4mJXaGH/3aEiXRSb V9vWoew== X-Google-Smtp-Source: AGHT+IGToFaqhJLe0IGbNpc4OT696IWRhQioLybjZJauCKgYvo/uamB7Vtqa+4ymvZ9o8FsYzUyGdVvEMkA= X-Received: from wrta8.prod.google.com ([2002:a5d:5088:0:b0:3b7:89f0:5c26]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:401f:b0:3b7:8832:fde6 with SMTP id ffacd0b85a97d-3b794fb6807mr4958295f8f.13.1753962714695; Thu, 31 Jul 2025 04:51:54 -0700 (PDT) Date: Thu, 31 Jul 2025 13:51:33 +0200 In-Reply-To: <20250731115139.3035888-1-glider@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250731115139.3035888-1-glider@google.com> X-Mailer: git-send-email 2.50.1.552.g942d659e1b-goog Message-ID: <20250731115139.3035888-5-glider@google.com> Subject: [PATCH v4 04/10] mm/kasan: define __asan_before_dynamic_init, __asan_after_dynamic_init From: Alexander Potapenko To: glider@google.com Cc: quic_jiangenj@quicinc.com, linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, Dmitry Vyukov , Aleksandr Nogikh , Andrey Konovalov , Borislav Petkov , Dave Hansen , Ingo Molnar , Josh Poimboeuf , Marco Elver , Peter Zijlstra , Thomas Gleixner Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Calls to __asan_before_dynamic_init() and __asan_after_dynamic_init() are inserted by Clang when building with coverage guards. These functions can be used to detect initialization order fiasco bugs in the userspace, but it is fine for them to be no-ops in the kernel. Signed-off-by: Alexander Potapenko Reviewed-by: Dmitry Vyukov --- v4: - Fix a compilation error reported by the kernel test robot v3: - add Reviewed-by: Dmitry Vyukov v2: - Address comments by Dmitry Vyukov: - rename CONFIG_KCOV_ENABLE_GUARDS to CONFIG_KCOV_UNIQUE - Move this patch before the one introducing CONFIG_KCOV_UNIQUE, per Marco Elver's request. Change-Id: I7f8eb690a3d96f7d122205e8f1cba8039f6a68eb fixup asan_before Change-Id: If653ba4f160414cafe65eee530b6b67e5b5b547c --- mm/kasan/generic.c | 24 ++++++++++++++++++++++++ mm/kasan/kasan.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index d54e89f8c3e76..b43ac17b7c926 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -238,6 +238,30 @@ void __asan_unregister_globals(void *ptr, ssize_t size) } EXPORT_SYMBOL(__asan_unregister_globals); =20 +#if defined(CONFIG_KCOV_UNIQUE) +/* + * __asan_before_dynamic_init() and __asan_after_dynamic_init() are insert= ed + * when the user requests building with coverage guards. In the userspace,= these + * two functions can be used to detect initialization order fiasco bugs, b= ut in + * the kernel they can be no-ops. + * + * There is an inconsistency between how Clang and GCC emit calls to this + * function, with Clang expecting the parameter to be i64, whereas GCC wan= ts it + * to be const void *. + * We pick the latter option, because Clang does not care, and GCC prints a + * warning with -Wbuiltin-declaration-mismatch. + */ +void __asan_before_dynamic_init(const void *module_name) +{ +} +EXPORT_SYMBOL(__asan_before_dynamic_init); + +void __asan_after_dynamic_init(void) +{ +} +EXPORT_SYMBOL(__asan_after_dynamic_init); +#endif + #define DEFINE_ASAN_LOAD_STORE(size) \ void __asan_load##size(void *addr) \ { \ diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index 129178be5e649..d23fcac9e0c12 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -582,6 +582,8 @@ void kasan_restore_multi_shot(bool enabled); =20 void __asan_register_globals(void *globals, ssize_t size); void __asan_unregister_globals(void *globals, ssize_t size); +void __asan_before_dynamic_init(const void *module_name); +void __asan_after_dynamic_init(void); void __asan_handle_no_return(void); void __asan_alloca_poison(void *, ssize_t size); void __asan_allocas_unpoison(void *stack_top, ssize_t stack_bottom); --=20 2.50.1.552.g942d659e1b-goog From nobody Sun Oct 5 17:56:34 2025 Received: from mail-ej1-f74.google.com (mail-ej1-f74.google.com [209.85.218.74]) (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 B71042C3263 for ; Thu, 31 Jul 2025 11:51:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962721; cv=none; b=h5RchybX52CDfcxN92emdltslYhsMhW2GanqdqvmuKqRIZdV4L6WGmsffKOThDAJC/OUoOjRcyrBVp+H181ukDJkZm2P0vOaJduTqLndNRIcrp+iIEYX0Jrw6nQcmZVmT3o0qx/4nBhAzkqjRLFrrUJyf0K/22UeCy2JlcGpWo0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962721; c=relaxed/simple; bh=Tci+SKMZ8RMMxche64nX1uWNAaVUFUvasDdgUwYtAgw=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=oNrJkmk0Bp/kXJcoq9r2Me3idopY3nVSgvrhpjjYmFm15dGTZLhlLl+49qKYvDH7krOk9MolfsaGoyE8mKTNmdUhdXcHdHG5+wzUfwaSxqtp0iqknRsL1bUN63GRlqwTRdo/qT1cbpFSAGkQeSQKQ5ehqWC2iFGhcTHTjtFx8VY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--glider.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=zH+cchL2; arc=none smtp.client-ip=209.85.218.74 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=flex--glider.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="zH+cchL2" Received: by mail-ej1-f74.google.com with SMTP id a640c23a62f3a-af91e018025so50553466b.1 for ; Thu, 31 Jul 2025 04:51:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753962718; x=1754567518; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=fr3wdyxx9nf1qL2KhZS1xwKvuRnArjYIvI1lmTgg9P0=; b=zH+cchL2HS3OsTWRawLRRt/YHvlpof/dDfdI5qZXpXo/SKybSpwphhCpgJQLgpM+KI vGQEq4YWBtVrRdp5MADXB/rQpMG08X7hxwRdCeac1KucE/zFwih4lG9pth9s6kIzedkA Wg39RSOmBGqm1UDRiPTP5S2ABMv+7xN9veuK1rJpW3voIfx/8D+flwzdoOlfG3zW9bat huit7i2yki96UUxtf9sYx/shrvh+Uh0IKYlK8xb/SxrO7sSD2fzIlxQ2knolb57WP5Nd l7oBsztIbC7ZUEPEjeiUQBx6+MTBCNnqP5WeDrFZNaX/5kxiYdHyCjLOAHMgxLTOSdnh 6JHw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753962718; x=1754567518; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=fr3wdyxx9nf1qL2KhZS1xwKvuRnArjYIvI1lmTgg9P0=; b=FGqLtmyZucwLVIRnhjYQHEPPf8mA2gBXpPlaIpT09Ay6KHOCwwrkpQHcigRNaf8Opa EEngPUz+4qZh9Hij3ZrpjKat2L83Xa5nj3Js6qhZkWirVxTK1KTaMh7nLhs2N0iWlyG2 PYMM3RDhsAzMlYbg+uL/Sg3QO31CwBN/0ufx7sqGvMIxzp3F1fnaT1CbWhCsqFgYkGTU IsBrYJEGGkCt6eq7L49nrgmP4VyKtr67LG3syUHKge0JPQiN0rPN8fZDj+cuC2lwMaLs qlcnQk4nIML5lZ3bu8w8RbkRLCPRCmgyRmcP/pNZroxriamuzv+y75r+p4el7MicZt9y 72lQ== X-Forwarded-Encrypted: i=1; AJvYcCXBxk2uWWdRUMBaIyRrVNEDO40B0SqSavx9ja1qd06AYAHVPrQiGPEJvf210X7VuuvMoQy+9eutYkYJcR4=@vger.kernel.org X-Gm-Message-State: AOJu0YyS011Lm9O8JjlFflGjEMQzRJBoQmMteQ2PXiXZkYY1ENaIIQiB 8lRYZOBAzorwoRMDpF8khQsBkHGyyXd+wOcdzjO5eMQQQcnvGP5pq4qXYROsAO+gNwvdc4T8vjg LMUTnmA== X-Google-Smtp-Source: AGHT+IHv1NYaLHKrEG2v2miqIOvqmDFdLaIEDvxbQ9I1X2gPSxT9NeaOugPde5/hee0pii+5iI9CNX7vL/I= X-Received: from edj19.prod.google.com ([2002:a05:6402:3253:b0:615:979:8d80]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a17:907:2689:b0:ae3:6cc8:e431 with SMTP id a640c23a62f3a-af8fda6fb17mr960236966b.57.1753962717188; Thu, 31 Jul 2025 04:51:57 -0700 (PDT) Date: Thu, 31 Jul 2025 13:51:34 +0200 In-Reply-To: <20250731115139.3035888-1-glider@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250731115139.3035888-1-glider@google.com> X-Mailer: git-send-email 2.50.1.552.g942d659e1b-goog Message-ID: <20250731115139.3035888-6-glider@google.com> Subject: [PATCH v4 05/10] kcov: x86: introduce CONFIG_KCOV_UNIQUE From: Alexander Potapenko To: glider@google.com Cc: quic_jiangenj@quicinc.com, linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, x86@kernel.org, Dmitry Vyukov , Aleksandr Nogikh , Andrey Konovalov , Borislav Petkov , Dave Hansen , Ingo Molnar , Josh Poimboeuf , Marco Elver , Peter Zijlstra , Thomas Gleixner Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The new config switches coverage instrumentation to using __sanitizer_cov_trace_pc_guard(u32 *guard) instead of __sanitizer_cov_trace_pc(void) This relies on Clang's -fsanitize-coverage=3Dtrace-pc-guard flag [1]. Each callback receives a unique 32-bit guard variable residing in .bss. Those guards can be used by kcov to deduplicate the coverage on the fly. As a first step, we make the new instrumentation mode 1:1 compatible with the old one. [1] https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-gua= rds Cc: x86@kernel.org Signed-off-by: Alexander Potapenko Reviewed-by: Dmitry Vyukov --- v4: - add Reviewed-by: Dmitry Vyukov v3: - per Dmitry Vyukov's request, add better comments in scripts/module.lds.S and lib/Kconfig.debug - add -sanitizer-coverage-drop-ctors to scripts/Makefile.kcov to drop the unwanted constructors emitting unsupported relocations - merge the __sancov_guards section into .bss v2: - Address comments by Dmitry Vyukov - rename CONFIG_KCOV_ENABLE_GUARDS to CONFIG_KCOV_UNIQUE - update commit description and config description - Address comments by Marco Elver - rename sanitizer_cov_write_subsequent() to kcov_append_to_buffer() - make config depend on X86_64 (via ARCH_HAS_KCOV_UNIQUE) - swap #ifdef branches - tweak config description - remove redundant check for CONFIG_CC_HAS_SANCOV_TRACE_PC_GUARD Change-Id: Iacb1e71fd061a82c2acadf2347bba4863b9aec39 --- arch/x86/Kconfig | 1 + arch/x86/kernel/vmlinux.lds.S | 1 + include/asm-generic/vmlinux.lds.h | 13 ++++++- include/linux/kcov.h | 2 + kernel/kcov.c | 61 +++++++++++++++++++++---------- lib/Kconfig.debug | 26 +++++++++++++ scripts/Makefile.kcov | 7 ++++ scripts/module.lds.S | 35 ++++++++++++++++++ tools/objtool/check.c | 1 + 9 files changed, 126 insertions(+), 21 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 8bed9030ad473..0533070d24fe7 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -94,6 +94,7 @@ config X86 select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_KCOV if X86_64 + select ARCH_HAS_KCOV_UNIQUE if X86_64 select ARCH_HAS_KERNEL_FPU_SUPPORT select ARCH_HAS_MEM_ENCRYPT select ARCH_HAS_MEMBARRIER_SYNC_CORE diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 4fa0be732af10..52fe6539b9c91 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -372,6 +372,7 @@ SECTIONS . =3D ALIGN(PAGE_SIZE); *(BSS_MAIN) BSS_DECRYPTED + BSS_SANCOV_GUARDS . =3D ALIGN(PAGE_SIZE); __bss_stop =3D .; } diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinu= x.lds.h index fa5f19b8d53a0..ee78328eecade 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -102,7 +102,8 @@ * sections to be brought in with rodata. */ #if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || defined(CONFIG_LTO_CL= ANG) || \ -defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG) + defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG) || \ + defined(CONFIG_KCOV_UNIQUE) #define TEXT_MAIN .text .text.[0-9a-zA-Z_]* #else #define TEXT_MAIN .text @@ -121,6 +122,16 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPEL= LER_CLANG) #define SBSS_MAIN .sbss #endif =20 +#if defined(CONFIG_KCOV_UNIQUE) +/* BSS_SANCOV_GUARDS must be part of the .bss section so that it is zero-i= nitialized. */ +#define BSS_SANCOV_GUARDS \ + __start___sancov_guards =3D .; \ + *(__sancov_guards); \ + __stop___sancov_guards =3D .; +#else +#define BSS_SANCOV_GUARDS +#endif + /* * GCC 4.5 and later have a 32 bytes section alignment for structures. * Except GCC 4.9, that feels the need to align on 64 bytes. diff --git a/include/linux/kcov.h b/include/linux/kcov.h index 2b3655c0f2278..2acccfa5ae9af 100644 --- a/include/linux/kcov.h +++ b/include/linux/kcov.h @@ -107,6 +107,8 @@ typedef unsigned long long kcov_u64; #endif =20 void __sanitizer_cov_trace_pc(void); +void __sanitizer_cov_trace_pc_guard(u32 *guard); +void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop); 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 5170f367c8a1b..8154ac1c1622e 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -194,27 +194,15 @@ 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 notrace void kcov_append_to_buffer(unsigned long *area, int size, + unsigned long ip) { - struct task_struct *t; - unsigned long *area; - unsigned long ip =3D canonicalize_ip(_RET_IP_); - unsigned long pos; - - t =3D current; - if (!check_kcov_mode(KCOV_MODE_TRACE_PC, t)) - return; - - area =3D t->kcov_state.area; /* The first 64-bit word is the number of subsequent PCs. */ - pos =3D READ_ONCE(area[0]) + 1; - if (likely(pos < t->kcov_state.size)) { - /* Previously we write pc before updating pos. However, some - * early interrupt code could bypass check_kcov_mode() check + unsigned long pos =3D READ_ONCE(area[0]) + 1; + + if (likely(pos < size)) { + /* + * Some early interrupt code could bypass check_kcov_mode() 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(). @@ -225,7 +213,40 @@ void notrace __sanitizer_cov_trace_pc(void) area[pos] =3D ip; } } + +/* + * Entry point from instrumented code. + * This is called once per basic-block/edge. + */ +#ifdef CONFIG_KCOV_UNIQUE +void notrace __sanitizer_cov_trace_pc_guard(u32 *guard) +{ + if (!check_kcov_mode(KCOV_MODE_TRACE_PC, current)) + return; + + kcov_append_to_buffer(current->kcov_state.area, + current->kcov_state.size, + canonicalize_ip(_RET_IP_)); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_pc_guard); + +void notrace __sanitizer_cov_trace_pc_guard_init(uint32_t *start, + uint32_t *stop) +{ +} +EXPORT_SYMBOL(__sanitizer_cov_trace_pc_guard_init); +#else /* !CONFIG_KCOV_UNIQUE */ +void notrace __sanitizer_cov_trace_pc(void) +{ + if (!check_kcov_mode(KCOV_MODE_TRACE_PC, current)) + return; + + kcov_append_to_buffer(current->kcov_state.area, + current->kcov_state.size, + canonicalize_ip(_RET_IP_)); +} EXPORT_SYMBOL(__sanitizer_cov_trace_pc); +#endif =20 #ifdef CONFIG_KCOV_ENABLE_COMPARISONS static void notrace write_comp_data(u64 type, u64 arg1, u64 arg2, u64 ip) @@ -253,7 +274,7 @@ static void notrace write_comp_data(u64 type, u64 arg1,= u64 arg2, u64 ip) start_index =3D 1 + count * KCOV_WORDS_PER_CMP; end_pos =3D (start_index + KCOV_WORDS_PER_CMP) * sizeof(u64); if (likely(end_pos <=3D max_pos)) { - /* See comment in __sanitizer_cov_trace_pc(). */ + /* See comment in kcov_append_to_buffer(). */ WRITE_ONCE(area[0], count + 1); barrier(); area[start_index] =3D type; diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index ebe33181b6e6e..a7441f89465f3 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2153,6 +2153,12 @@ config ARCH_HAS_KCOV build and run with CONFIG_KCOV. This typically requires disabling instrumentation for some early boot code. =20 +config CC_HAS_SANCOV_TRACE_PC + def_bool $(cc-option,-fsanitize-coverage=3Dtrace-pc) + +config CC_HAS_SANCOV_TRACE_PC_GUARD + def_bool $(cc-option,-fsanitize-coverage=3Dtrace-pc-guard) + config KCOV bool "Code coverage for fuzzing" depends on ARCH_HAS_KCOV @@ -2166,6 +2172,26 @@ config KCOV =20 For more details, see Documentation/dev-tools/kcov.rst. =20 +config ARCH_HAS_KCOV_UNIQUE + bool + help + An architecture should select this when it can successfully + build and run with CONFIG_KCOV_UNIQUE. + +config KCOV_UNIQUE + depends on KCOV + depends on CC_HAS_SANCOV_TRACE_PC_GUARD && ARCH_HAS_KCOV_UNIQUE + bool "Enable unique program counter collection mode for KCOV" + help + This option enables KCOV's unique program counter (PC) collection mode, + which deduplicates PCs on the fly when the KCOV_UNIQUE_ENABLE ioctl is + used. + + This significantly reduces the memory footprint for coverage data + collection compared to trace mode, as it prevents the kernel from + storing the same PC multiple times. + Enabling this mode incurs a slight increase in kernel binary size. + 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 78305a84ba9d2..c3ad5504f5600 100644 --- a/scripts/Makefile.kcov +++ b/scripts/Makefile.kcov @@ -1,5 +1,12 @@ # SPDX-License-Identifier: GPL-2.0-only +ifeq ($(CONFIG_KCOV_UNIQUE),y) +kcov-flags-y +=3D -fsanitize-coverage=3Dtrace-pc-guard +# Drop per-file constructors that -fsanitize-coverage=3Dtrace-pc-guard ins= erts by default. +# Kernel does not need them, and they may produce unknown relocations. +kcov-flags-y +=3D -mllvm -sanitizer-coverage-drop-ctors +else kcov-flags-y +=3D -fsanitize-coverage=3Dtrace-pc +endif kcov-flags-$(CONFIG_KCOV_ENABLE_COMPARISONS) +=3D -fsanitize-coverage=3Dtr= ace-cmp =20 kcov-rflags-y +=3D -Cpasses=3Dsancov-module diff --git a/scripts/module.lds.S b/scripts/module.lds.S index 450f1088d5fd3..17f36d5112c5d 100644 --- a/scripts/module.lds.S +++ b/scripts/module.lds.S @@ -47,6 +47,7 @@ SECTIONS { .bss : { *(.bss .bss.[0-9a-zA-Z_]*) *(.bss..L*) + *(__sancov_guards) } =20 .data : { @@ -64,6 +65,40 @@ SECTIONS { MOD_CODETAG_SECTIONS() } #endif + +#ifdef CONFIG_KCOV_UNIQUE + /* + * CONFIG_KCOV_UNIQUE creates COMDAT groups for instrumented functions, + * which has the following consequences in the presence of + * -ffunction-sections: + * - Separate .init.text and .exit.text sections in the modules are not + * merged together, which results in errors trying to create + * duplicate entries in /sys/module/MODNAME/sections/ at module load + * time. + * - Each function is placed in a separate .text.funcname section, so + * there is no .text section anymore. Collecting them together here + * has mostly aesthetic purpose, although some tools may be expecting + * it to be present. + */ + .text : { + *(.text .text.[0-9a-zA-Z_]*) + *(.text..L*) + } + .init.text : { + *(.init.text .init.text.[0-9a-zA-Z_]*) + *(.init.text..L*) + } + .exit.text : { + *(.exit.text .exit.text.[0-9a-zA-Z_]*) + *(.exit.text..L*) + } + .bss : { + *(.bss .bss.[0-9a-zA-Z_]*) + *(.bss..L*) + *(__sancov_guards) + } +#endif + MOD_SEPARATE_CODETAG_SECTIONS() } =20 diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 67d76f3a1dce5..60eb5faa27d28 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1156,6 +1156,7 @@ static const char *uaccess_safe_builtin[] =3D { "write_comp_data", "check_kcov_mode", "__sanitizer_cov_trace_pc", + "__sanitizer_cov_trace_pc_guard", "__sanitizer_cov_trace_const_cmp1", "__sanitizer_cov_trace_const_cmp2", "__sanitizer_cov_trace_const_cmp4", --=20 2.50.1.552.g942d659e1b-goog From nobody Sun Oct 5 17:56:34 2025 Received: from mail-wr1-f73.google.com (mail-wr1-f73.google.com [209.85.221.73]) (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 2989A2C1581 for ; Thu, 31 Jul 2025 11:52:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962724; cv=none; b=N/OYA77ZeoaYPt46qibrfOdZs8W8NL9pIhoqKmiNNP1gmrIuT2O8rJwtT+c8ENziFyUln9F/sj+WXmyfEsqHbzjH3VjiKD0oKzWefPLtkt57VW1wzYXKgWjs/b1ZN4zRUjGzsaFBkEqrqMQ221wBVaBGuQz612rC3wZ6AXUlJKU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962724; c=relaxed/simple; bh=DKlgttxOJoNYs2L2yFu65c8RnXZJeaUFXB1cyr4OjR0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=q4nXFuOWr3RToOZ64Brn1vH7edO1E3kQ60d2Jmhg7C6ONikVva5vMzGUwoWv8R/t2yW0fbDbSg3SfS4UI6UhDefFs2ak5UDnqNp0ShKd3h+vK0t6FKwq0IWKWfqmYu+SeDb4WnrtRa8LCXg69aPMEpsan8lHxKvuBNZ09KPcLIQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--glider.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=SYIXO5vQ; arc=none smtp.client-ip=209.85.221.73 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=flex--glider.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="SYIXO5vQ" Received: by mail-wr1-f73.google.com with SMTP id ffacd0b85a97d-3b78c983014so437682f8f.0 for ; Thu, 31 Jul 2025 04:52:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753962720; x=1754567520; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=PPuLl+jotf/eLqBsrdKJtiuGUESLMuKQyj/jfXbQ+ZY=; b=SYIXO5vQ/EEkAwwUb4t0gHY1nIO8BdGYDnrZ2MKb8J6e/gD60ruxX9cSxzLOvbP55c FrbKHmDLzKuXdCGVD6n7tkWL/3YbfflW9Vvg1eJbZcw/L1Wmn0Y+O3As5uxtjSvFTwYf PU0QbpAwGU69+A+/H4BRxm+j7iou+l8wVj827MoBgmtJPbOGcxqCKGNv/hL7b6g+o2YO 6RT7kZ12uEQtLEduzpaYZjPodnBNY0Ll0gRjaDksGGawV4oypdlidwFqGhlSe9WWc6b4 YmZhAR9nIfSqffEwWenK6aBKcAW+VUVyzTNjBUpzrpPERBPWfPiUWj+zqRvXzsG0CHHX UtJQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753962720; x=1754567520; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=PPuLl+jotf/eLqBsrdKJtiuGUESLMuKQyj/jfXbQ+ZY=; b=WowtMGMmd3/klPi6S3ViPDlg6JYF3BnZ8VzZTNnSUdz2ulAkKgiB9s0NqIvNPVIW+q AeZrZr1Ewi8UA9/Bg6/gW/pwHqlbMQcExP0b+btz1NH7bhdAJTI29c7YnkAjlsDBMhWc G0Dyd+WhqTFAh1koaHflY0m9XVvAnkzXCKC1dZm/ca7xsTAS4zEcSDzcSA9OfYrnX+WU LQLR+p1KIxA/ZAl6HCLdLgwPweL97Ca5aG2rOFwoCTv3Is0weAAfFszGjgGuxCyo+d8s NdpUuXC5f/Co8zGXpMqFejGrLbYfwcr9c715mW+TtYdoO4BZXnbitqwHU1rYpR09tZKh k38Q== X-Forwarded-Encrypted: i=1; AJvYcCVobosBp/D6Q1FYLbCjvsZxodg7dEHwCrkaKdn+rBO6xOkkVpnlgL45vjJVeJxlr2CQRCKDEaSW6f00qxs=@vger.kernel.org X-Gm-Message-State: AOJu0YzlI5N4aRWVbpUjho1JZx5YG0QWS9yLSTCcTeZ2eWAg7ps6wXh0 nZD/748LSjzMu8Q1Blh5lxVygrpkZMDSxAShWoF/S56BewSKV6QdW0tLtQgXln8NEk0a+0L6QrY LKYqbjw== X-Google-Smtp-Source: AGHT+IF/sgG0v6dTdYZQ8u2DEGmxrI/1eJJ5Ir2nQ2ymjDVQDFeR79V0Pwb1remmYjUDjxnIelFypZQ5+tU= X-Received: from wrbfx3.prod.google.com ([2002:a05:6000:2d03:b0:3b7:8216:2015]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:2c04:b0:3a5:27ba:47c7 with SMTP id ffacd0b85a97d-3b79500950cmr5811629f8f.48.1753962720502; Thu, 31 Jul 2025 04:52:00 -0700 (PDT) Date: Thu, 31 Jul 2025 13:51:35 +0200 In-Reply-To: <20250731115139.3035888-1-glider@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250731115139.3035888-1-glider@google.com> X-Mailer: git-send-email 2.50.1.552.g942d659e1b-goog Message-ID: <20250731115139.3035888-7-glider@google.com> Subject: [PATCH v4 06/10] kcov: add trace and trace_size to struct kcov_state From: Alexander Potapenko To: glider@google.com Cc: quic_jiangenj@quicinc.com, linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, Dmitry Vyukov , Aleksandr Nogikh , Andrey Konovalov , Borislav Petkov , Dave Hansen , Ingo Molnar , Josh Poimboeuf , Marco Elver , Peter Zijlstra , Thomas Gleixner Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Keep kcov_state.area as the pointer to the memory buffer used by kcov and shared with the userspace. Store the pointer to the trace (part of the buffer holding sequential events) separately, as we will be splitting that buffer in multiple parts. No functional changes so far. Signed-off-by: Alexander Potapenko Reviewed-by: Dmitry Vyukov --- v4: - add Reviewed-by: Dmitry Vyukov v3: - Fix a warning detected by the kernel test robot - Address comments by Dmitry Vyukov: - s/kcov/KCOV/ - fix struct initialization style v2: - Address comments by Dmitry Vyukov: - tweak commit description - Address comments by Marco Elver: - rename sanitizer_cov_write_subsequent() to kcov_append_to_buffer() - Update code to match the new description of struct kcov_state Change-Id: I50b5589ef0e0b6726aa0579334093c648f76790a --- include/linux/kcov_types.h | 9 ++++++- kernel/kcov.c | 48 +++++++++++++++++++++----------------- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/include/linux/kcov_types.h b/include/linux/kcov_types.h index 53b25b6f0addd..9d38a2020b099 100644 --- a/include/linux/kcov_types.h +++ b/include/linux/kcov_types.h @@ -7,9 +7,16 @@ struct kcov_state { /* Size of the area (in long's). */ unsigned int size; + /* + * Pointer to user-provided memory used by KCOV. This memory may + * contain multiple buffers. + */ + void *area; =20 + /* Size of the trace (in long's). */ + unsigned int trace_size; /* Buffer for coverage collection, shared with the userspace. */ - void *area; + unsigned long *trace; =20 /* * KCOV sequence number: incremented each time kcov is reenabled, used diff --git a/kernel/kcov.c b/kernel/kcov.c index 8154ac1c1622e..2005fc7f578ee 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -194,11 +194,11 @@ static notrace unsigned long canonicalize_ip(unsigned= long ip) return ip; } =20 -static notrace void kcov_append_to_buffer(unsigned long *area, int size, +static notrace void kcov_append_to_buffer(unsigned long *trace, int size, unsigned long ip) { /* The first 64-bit word is the number of subsequent PCs. */ - unsigned long pos =3D READ_ONCE(area[0]) + 1; + unsigned long pos =3D READ_ONCE(trace[0]) + 1; =20 if (likely(pos < size)) { /* @@ -208,9 +208,9 @@ static notrace void kcov_append_to_buffer(unsigned long= *area, int size, * overitten by the recursive __sanitizer_cov_trace_pc(). * Update pos before writing pc to avoid such interleaving. */ - WRITE_ONCE(area[0], pos); + WRITE_ONCE(trace[0], pos); barrier(); - area[pos] =3D ip; + trace[pos] =3D ip; } } =20 @@ -224,8 +224,8 @@ void notrace __sanitizer_cov_trace_pc_guard(u32 *guard) if (!check_kcov_mode(KCOV_MODE_TRACE_PC, current)) return; =20 - kcov_append_to_buffer(current->kcov_state.area, - current->kcov_state.size, + kcov_append_to_buffer(current->kcov_state.trace, + current->kcov_state.trace_size, canonicalize_ip(_RET_IP_)); } EXPORT_SYMBOL(__sanitizer_cov_trace_pc_guard); @@ -241,8 +241,8 @@ void notrace __sanitizer_cov_trace_pc(void) if (!check_kcov_mode(KCOV_MODE_TRACE_PC, current)) return; =20 - kcov_append_to_buffer(current->kcov_state.area, - current->kcov_state.size, + kcov_append_to_buffer(current->kcov_state.trace, + current->kcov_state.trace_size, canonicalize_ip(_RET_IP_)); } EXPORT_SYMBOL(__sanitizer_cov_trace_pc); @@ -251,9 +251,9 @@ EXPORT_SYMBOL(__sanitizer_cov_trace_pc); #ifdef CONFIG_KCOV_ENABLE_COMPARISONS static void notrace write_comp_data(u64 type, u64 arg1, u64 arg2, u64 ip) { - struct task_struct *t; - u64 *area; u64 count, start_index, end_pos, max_pos; + struct task_struct *t; + u64 *trace; =20 t =3D current; if (!check_kcov_mode(KCOV_MODE_TRACE_CMP, t)) @@ -265,22 +265,22 @@ static void notrace write_comp_data(u64 type, u64 arg= 1, u64 arg2, u64 ip) * We write all comparison arguments and types as u64. * The buffer was allocated for t->kcov_state.size unsigned longs. */ - area =3D (u64 *)t->kcov_state.area; + trace =3D (u64 *)t->kcov_state.trace; max_pos =3D t->kcov_state.size * sizeof(unsigned long); =20 - count =3D READ_ONCE(area[0]); + count =3D READ_ONCE(trace[0]); =20 /* Every record is KCOV_WORDS_PER_CMP 64-bit words. */ start_index =3D 1 + count * KCOV_WORDS_PER_CMP; end_pos =3D (start_index + KCOV_WORDS_PER_CMP) * sizeof(u64); if (likely(end_pos <=3D max_pos)) { /* See comment in kcov_append_to_buffer(). */ - WRITE_ONCE(area[0], count + 1); + WRITE_ONCE(trace[0], count + 1); barrier(); - area[start_index] =3D type; - area[start_index + 1] =3D arg1; - area[start_index + 2] =3D arg2; - area[start_index + 3] =3D ip; + trace[start_index] =3D type; + trace[start_index + 1] =3D arg1; + trace[start_index + 2] =3D arg2; + trace[start_index + 3] =3D ip; } } =20 @@ -381,11 +381,13 @@ static void kcov_start(struct task_struct *t, struct = kcov *kcov, =20 static void kcov_stop(struct task_struct *t) { + int saved_sequence =3D t->kcov_state.sequence; + WRITE_ONCE(t->kcov_mode, KCOV_MODE_DISABLED); barrier(); t->kcov =3D NULL; - t->kcov_state.size =3D 0; - t->kcov_state.area =3D NULL; + t->kcov_state =3D (typeof(t->kcov_state)){}; + t->kcov_state.sequence =3D saved_sequence; } =20 static void kcov_task_reset(struct task_struct *t) @@ -734,6 +736,8 @@ static long kcov_ioctl(struct file *filep, unsigned int= cmd, unsigned long arg) } kcov->state.area =3D area; kcov->state.size =3D size; + kcov->state.trace =3D area; + kcov->state.trace_size =3D size; kcov->mode =3D KCOV_MODE_INIT; spin_unlock_irqrestore(&kcov->lock, flags); return 0; @@ -925,10 +929,12 @@ void kcov_remote_start(u64 handle) local_lock_irqsave(&kcov_percpu_data.lock, flags); } =20 - /* Reset coverage size. */ - *(u64 *)area =3D 0; state.area =3D area; state.size =3D size; + state.trace =3D area; + state.trace_size =3D size; + /* Reset coverage size. */ + state.trace[0] =3D 0; =20 if (in_serving_softirq()) { kcov_remote_softirq_start(t); --=20 2.50.1.552.g942d659e1b-goog From nobody Sun Oct 5 17:56:34 2025 Received: from mail-wm1-f74.google.com (mail-wm1-f74.google.com [209.85.128.74]) (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 E5A382D0275 for ; Thu, 31 Jul 2025 11:52:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962727; cv=none; b=im1Y3WDCjUfd5UmLDJaGlgsfBlPMf6IB75cbD9nSx659VgmpOOguserT1g2rgoMLXYarj2fmgtMIsqkkwc/us7/suY0YxnCqtnnx5tvcuxPxMnDQIq22ImeEhokMF+kTIe4nUq4QBRbBVPH1uJEc0Bl7ybYRePMy/QgKDsVXmcE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962727; c=relaxed/simple; bh=QFA8j7SQOVxFc/i0AuPkiRtB7FNb/J7gKEV/pzhSERM=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=DsEFaZYynpVBgbqcjPTm+P01JIhMD7O1qlRa72Y0TQF4DXtSFqdiMD9hAfXwvC6UB/f9hNjD+nr+J0JaS9UlNvfn/hPRIS9ba99vxXrd8TaVm82nvib1oE+9djlNRked2q32Db4ZlaUXtmwjHQn05Ee5to6QgvRlgfkzSzfJtTU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--glider.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=YpP3S1rS; arc=none smtp.client-ip=209.85.128.74 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=flex--glider.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="YpP3S1rS" Received: by mail-wm1-f74.google.com with SMTP id 5b1f17b1804b1-451d30992bcso5545505e9.2 for ; Thu, 31 Jul 2025 04:52:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753962723; x=1754567523; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Wxltob97dGGsyXvDSMkg1S6ftRZJNYows0FnYbt40l0=; b=YpP3S1rSzHDGLXxBaP2LBJCsgwmoWZQcXGZ91KK9oAlt6Dp0iCWiKXKnhkFDQsolyQ /ZWHdcMOVQf5risY7NV6VqQI+4gqoB1DQgE0xhzx4zoiXzJ6JfXTncrTjdxe5Ms+Idly 1Jg3MZl5tSK9gpe2h492TZRahwyeHUtcgau9MwCWlIdtJF1hcCuBm5NrV83mNVjK9kFR zzOuisPJG4vnvnMQFXbQ3LDG4+Yk8F7hln/1gzglcQUckzweBHHLkQOEZBjhdYGDjTqi jcOjfh1WflHwVrD3H3OzldOPZnAURFTp2LJ6QqCy4rXh+nfbLSnh1xTJWif46+CqV98f OTwQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753962723; x=1754567523; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Wxltob97dGGsyXvDSMkg1S6ftRZJNYows0FnYbt40l0=; b=a47bdY7B0uN9Yy9PkoMhhgBEmoOrtA/zyilOH/M6EMbjp4xhPhKXeRb5Bk/6OJgHLs r9fXgSJVFXHZ7TDXNnVv3oAYOynsT7E3ZhBuzubz8JAeGmJEA+3mJnL7KI1KeZMyRSLp kGwO7ynFMaqpHxhrWVAM3vxlbfZzotdryzKIAM5D7tqlps3VLSiJdR0eYqSoD/EgBg1d vL0yuQi5Ya9MND0wL1s1HQQCt60Ztd3cWeMUbarzxdZoZzJspJ5S/G3ORjNWsmby+Koc WqviFONVBq3uTIABjTUwnAwP/Os3DUDBQovO0A0GWqvnNb2wxl8dFBufdN40bJndtPL7 q6lg== X-Forwarded-Encrypted: i=1; AJvYcCWaKczTCX/RxEf3JWxKaqoIj/TVTlg8/0Y1Rq145E9aPtPoYL03WmPdXrLXZMwbh0S0bioIpE6zhGn/Av4=@vger.kernel.org X-Gm-Message-State: AOJu0Yz8Uc/bPjrGrMk2qM5GlGSCAGCnN/knsaNK5eqa8I7I3jt0HJx1 cXjtlF3UL/VVaLvP6e8cXS7K/E8JHEAspzzpU6qMYZft8EwUP8yO83Iv1W0KlDizLJqTNTIhNjE +ERk5nQ== X-Google-Smtp-Source: AGHT+IFczRzgbAWMCrFR+KuaSw8jlM2FhbJ4UCMBla1L68NW1HL1ZxJDw+kXgA8OIQOhdu+rFoC0wF435Fo= X-Received: from wmbet6.prod.google.com ([2002:a05:600c:8186:b0:454:d702:f3c2]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:1f92:b0:43c:f44c:72a6 with SMTP id 5b1f17b1804b1-45892b9341emr73441445e9.2.1753962723337; Thu, 31 Jul 2025 04:52:03 -0700 (PDT) Date: Thu, 31 Jul 2025 13:51:36 +0200 In-Reply-To: <20250731115139.3035888-1-glider@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250731115139.3035888-1-glider@google.com> X-Mailer: git-send-email 2.50.1.552.g942d659e1b-goog Message-ID: <20250731115139.3035888-8-glider@google.com> Subject: [PATCH v4 07/10] kcov: add ioctl(KCOV_UNIQUE_ENABLE) From: Alexander Potapenko To: glider@google.com Cc: quic_jiangenj@quicinc.com, linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, Dmitry Vyukov , Aleksandr Nogikh , Andrey Konovalov , Borislav Petkov , Dave Hansen , Ingo Molnar , Josh Poimboeuf , Marco Elver , Peter Zijlstra , Thomas Gleixner Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" ioctl(KCOV_UNIQUE_ENABLE) enables collection of deduplicated coverage in the presence of CONFIG_KCOV_ENABLE_GUARDS. The buffer shared with the userspace is divided in two parts, one holding a bitmap, and the other one being the trace. The single parameter of ioctl(KCOV_UNIQUE_ENABLE) determines the number of words used for the bitmap. Each __sanitizer_cov_trace_pc_guard() instrumentation hook receives a pointer to a unique guard variable. Upon the first call of each hook, the guard variable is initialized with a unique integer, which is used to map those hooks to bits in the bitmap. In the new coverage collection mode, the kernel first checks whether the bit corresponding to a particular hook is set, and then, if it is not, the PC is written into the trace buffer, and the bit is set. Note: when CONFIG_KCOV_ENABLE_GUARDS is disabled, ioctl(KCOV_UNIQUE_ENABLE) returns -ENOTSUPP, which is consistent with the existing kcov code. Measuring the exact performance impact of this mode directly can be challenging. However, based on fuzzing experiments (50 instances x 24h with and without deduplication), we observe the following: - When normalized by pure fuzzing time, total executions decreased by 2.1% (p=3D0.01). - When normalized by fuzzer uptime, the reduction in total executions was statistically insignificant (-1.0% with p=3D0.20). Despite a potential slight slowdown in execution count, the new mode positively impacts fuzzing effectiveness: - Statistically significant increase in corpus size (+0.6%, p<0.01). - Statistically significant increase in coverage (+0.6%, p<0.01). - A 99.8% reduction in coverage overflows. Also update the documentation. Signed-off-by: Alexander Potapenko Reviewed-by: Dmitry Vyukov --- v4: Add Reviewed-by: Dmitry Vyukov v3: - s/check_kcov_mode/get_kcov_mode in objtool v2: - Address comments by Dmitry Vyukov: - rename CONFIG_KCOV_ENABLE_GUARDS to CONFIG_KCOV_UNIQUE - rename KCOV_MODE_TRACE_UNIQUE_PC to KCOV_MODE_UNIQUE_PC - simplify index allocation - update documentation and comments - Address comments by Marco Elver: - change _IOR to _IOW in KCOV_UNIQUE_ENABLE definition - rename sanitizer_cov_write_subsequent() to kcov_append_to_buffer() - Use __test_and_set_bit() to avoid the lock prefix on the bit operation - Update code to match the new description of struct kcov_state - Rename kcov_get_mode() to kcov_arg_to_mode() to avoid confusion with get_kcov_mode(). Also make it use `enum kcov_mode`. Change-Id: I9805e7b22619a50e05cc7c7d794dacf6f7de2f03 --- Documentation/dev-tools/kcov.rst | 43 ++++++++ include/linux/kcov.h | 2 + include/linux/kcov_types.h | 8 ++ include/uapi/linux/kcov.h | 1 + kernel/kcov.c | 164 ++++++++++++++++++++++++++----- tools/objtool/check.c | 2 +- 6 files changed, 193 insertions(+), 27 deletions(-) diff --git a/Documentation/dev-tools/kcov.rst b/Documentation/dev-tools/kco= v.rst index abf3ad2e784e8..6446887cd1c92 100644 --- a/Documentation/dev-tools/kcov.rst +++ b/Documentation/dev-tools/kcov.rst @@ -192,6 +192,49 @@ Normally the shared buffer is used as follows:: up to the buffer[0] value saved above | =20 =20 +Unique coverage collection +--------------------------- + +Instead of collecting a trace of PCs, KCOV can deduplicate them on the fly. +This mode is enabled by the ``KCOV_UNIQUE_ENABLE`` ioctl (only available if +``CONFIG_KCOV_UNIQUE`` is on). + +.. code-block:: c + + /* Same includes and defines as above. */ + #define KCOV_UNIQUE_ENABLE _IOW('c', 103, unsigned long) + #define BITMAP_SIZE (4<<10) + + /* Instead of KCOV_ENABLE, enable unique coverage collection. */ + if (ioctl(fd, KCOV_UNIQUE_ENABLE, BITMAP_SIZE)) + perror("ioctl"), exit(1); + /* Reset the coverage from the tail of the ioctl() call. */ + __atomic_store_n(&cover[BITMAP_SIZE], 0, __ATOMIC_RELAXED); + memset(cover, 0, BITMAP_SIZE * sizeof(unsigned long)); + + /* Call the target syscall call. */ + /* ... */ + + /* Read the number of collected PCs. */ + n =3D __atomic_load_n(&cover[BITMAP_SIZE], __ATOMIC_RELAXED); + /* Disable the coverage collection. */ + if (ioctl(fd, KCOV_DISABLE, 0)) + perror("ioctl"), exit(1); + +Calling ``ioctl(fd, KCOV_UNIQUE_ENABLE, bitmap_size)`` carves out ``bitmap= _size`` +unsigned long's from those allocated by ``KCOV_INIT_TRACE`` to keep an opa= que +bitmap that prevents the kernel from storing the same PC twice. The remain= ing +part of the buffer is used to collect PCs, like in other modes (this part = must +contain at least two unsigned long's, like when collecting non-unique PCs). + +The mapping between a PC and its position in the bitmap is persistent duri= ng the +kernel lifetime, so it is possible for the callers to directly use the bit= map +contents as a coverage signal (like when fuzzing userspace with AFL). + +In order to reset the coverage between the runs, the user needs to rewind = the +trace (by writing 0 into the first buffer element past ``bitmap_size``) an= d zero +the whole bitmap. + Comparison operands collection ------------------------------ =20 diff --git a/include/linux/kcov.h b/include/linux/kcov.h index 2acccfa5ae9af..cea2e62723ef9 100644 --- a/include/linux/kcov.h +++ b/include/linux/kcov.h @@ -10,6 +10,7 @@ struct task_struct; #ifdef CONFIG_KCOV =20 enum kcov_mode { + KCOV_MODE_INVALID =3D -1, /* Coverage collection is not enabled yet. */ KCOV_MODE_DISABLED =3D 0, /* KCOV was initialized, but tracing mode hasn't been chosen yet. */ @@ -23,6 +24,7 @@ enum kcov_mode { KCOV_MODE_TRACE_CMP =3D 3, /* The process owns a KCOV remote reference. */ KCOV_MODE_REMOTE =3D 4, + KCOV_MODE_UNIQUE_PC =3D 5, }; =20 #define KCOV_IN_CTXSW (1 << 30) diff --git a/include/linux/kcov_types.h b/include/linux/kcov_types.h index 9d38a2020b099..8be930f47cd78 100644 --- a/include/linux/kcov_types.h +++ b/include/linux/kcov_types.h @@ -18,6 +18,14 @@ struct kcov_state { /* Buffer for coverage collection, shared with the userspace. */ unsigned long *trace; =20 + /* Size of the bitmap (in bits). */ + unsigned int bitmap_size; + /* + * Bitmap for coverage deduplication, shared with the + * userspace. + */ + unsigned long *bitmap; + /* * KCOV sequence number: incremented each time kcov is reenabled, used * by kcov_remote_stop(), see the comment there. diff --git a/include/uapi/linux/kcov.h b/include/uapi/linux/kcov.h index ed95dba9fa37e..e743ee011eeca 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_UNIQUE_ENABLE _IOW('c', 103, unsigned long) =20 enum { /* diff --git a/kernel/kcov.c b/kernel/kcov.c index 2005fc7f578ee..a92c848d17bce 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -28,6 +28,10 @@ #include #include =20 +#ifdef CONFIG_KCOV_UNIQUE +atomic_t kcov_guard_max_index =3D ATOMIC_INIT(0); +#endif + #define kcov_debug(fmt, ...) pr_debug("%s: " fmt, __func__, ##__VA_ARGS__) =20 /* Number of 64-bit words written per one comparison: */ @@ -163,9 +167,9 @@ 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 enum kcov_mode get_kcov_mode(struct task_struct *t) { - unsigned int mode; + enum kcov_mode mode; =20 /* * We are interested in code coverage as a function of a syscall inputs, @@ -173,7 +177,7 @@ static notrace bool check_kcov_mode(enum kcov_mode need= ed_mode, struct task_stru * coverage collection section in a softirq. */ if (!in_task() && !(in_softirq_really() && t->kcov_softirq)) - return false; + return KCOV_MODE_INVALID; mode =3D READ_ONCE(t->kcov_mode); /* * There is some code that runs in interrupts but for which @@ -183,7 +187,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 mode; } =20 static notrace unsigned long canonicalize_ip(unsigned long ip) @@ -202,7 +206,7 @@ static notrace void kcov_append_to_buffer(unsigned long= *trace, int size, =20 if (likely(pos < size)) { /* - * Some early interrupt code could bypass check_kcov_mode() check + * Some early interrupt code could bypass get_kcov_mode() 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(). @@ -219,14 +223,76 @@ static notrace void kcov_append_to_buffer(unsigned lo= ng *trace, int size, * This is called once per basic-block/edge. */ #ifdef CONFIG_KCOV_UNIQUE +DEFINE_PER_CPU(u32, saved_index); +/* + * Assign an index to a guard variable that does not have one yet. + * For an unlikely case of a race with another task executing the same bas= ic + * block for the first time with kcov enabled, we store the unused index i= n a + * per-cpu variable. + * In an even less likely case of the current task losing the race and get= ting + * rescheduled onto a CPU that already has a saved index, the index is + * discarded. This will result in an unused hole in the bitmap, but such e= vents + * should have minor impact on the overall memory consumption. + */ +static __always_inline u32 init_pc_guard(u32 *guard) +{ + /* If the current CPU has a saved free index, use it. */ + u32 index =3D this_cpu_xchg(saved_index, 0); + u32 old_guard; + + if (likely(!index)) + /* + * Allocate a new index. No overflow is possible, because 2**32 + * unique basic blocks will take more space than the max size + * of the kernel text segment. + */ + index =3D atomic_inc_return(&kcov_guard_max_index); + + /* + * Make sure another task is not initializing the same guard + * concurrently. + */ + old_guard =3D cmpxchg(guard, 0, index); + if (unlikely(old_guard)) { + /* We lost the race, save the index for future use. */ + this_cpu_write(saved_index, index); + return old_guard; + } + return index; +} + void notrace __sanitizer_cov_trace_pc_guard(u32 *guard) { - if (!check_kcov_mode(KCOV_MODE_TRACE_PC, current)) - return; + enum kcov_mode mode =3D get_kcov_mode(current); + u32 pc_index; =20 - kcov_append_to_buffer(current->kcov_state.trace, - current->kcov_state.trace_size, - canonicalize_ip(_RET_IP_)); + switch (mode) { + case KCOV_MODE_UNIQUE_PC: + pc_index =3D READ_ONCE(*guard); + if (unlikely(!pc_index)) + pc_index =3D init_pc_guard(guard); + + /* + * Use the bitmap for coverage deduplication. We assume both + * s.bitmap and s.trace are non-NULL. + */ + if (likely(pc_index < current->kcov_state.bitmap_size)) + if (__test_and_set_bit(pc_index, + current->kcov_state.bitmap)) + return; + /* + * If the PC is new, or the bitmap is too small, write PC to the + * trace. + */ + fallthrough; + case KCOV_MODE_TRACE_PC: + kcov_append_to_buffer(current->kcov_state.trace, + current->kcov_state.trace_size, + canonicalize_ip(_RET_IP_)); + break; + default: + return; + } } EXPORT_SYMBOL(__sanitizer_cov_trace_pc_guard); =20 @@ -238,7 +304,7 @@ EXPORT_SYMBOL(__sanitizer_cov_trace_pc_guard_init); #else /* !CONFIG_KCOV_UNIQUE */ void notrace __sanitizer_cov_trace_pc(void) { - if (!check_kcov_mode(KCOV_MODE_TRACE_PC, current)) + if (get_kcov_mode(current) !=3D KCOV_MODE_TRACE_PC) return; =20 kcov_append_to_buffer(current->kcov_state.trace, @@ -256,7 +322,7 @@ static void notrace write_comp_data(u64 type, u64 arg1,= u64 arg2, u64 ip) u64 *trace; =20 t =3D current; - if (!check_kcov_mode(KCOV_MODE_TRACE_CMP, t)) + if (get_kcov_mode(t) !=3D KCOV_MODE_TRACE_CMP) return; =20 ip =3D canonicalize_ip(ip); @@ -374,7 +440,7 @@ static void kcov_start(struct task_struct *t, struct kc= ov *kcov, t->kcov =3D kcov; /* Cache in task struct for performance. */ t->kcov_state =3D *state; - /* See comment in check_kcov_mode(). */ + /* See comment in get_kcov_mode(). */ barrier(); WRITE_ONCE(t->kcov_mode, mode); } @@ -409,6 +475,10 @@ static void kcov_reset(struct kcov *kcov) kcov->mode =3D KCOV_MODE_INIT; kcov->remote =3D false; kcov->remote_size =3D 0; + kcov->state.trace =3D kcov->state.area; + kcov->state.trace_size =3D kcov->state.size; + kcov->state.bitmap =3D NULL; + kcov->state.bitmap_size =3D 0; kcov->state.sequence++; } =20 @@ -549,18 +619,23 @@ static int kcov_close(struct inode *inode, struct fil= e *filep) return 0; } =20 -static int kcov_get_mode(unsigned long arg) +static enum kcov_mode kcov_arg_to_mode(unsigned long arg, int *error) { - if (arg =3D=3D KCOV_TRACE_PC) + if (arg =3D=3D KCOV_TRACE_PC) { return KCOV_MODE_TRACE_PC; - else if (arg =3D=3D KCOV_TRACE_CMP) + } else if (arg =3D=3D KCOV_TRACE_CMP) { #ifdef CONFIG_KCOV_ENABLE_COMPARISONS return KCOV_MODE_TRACE_CMP; #else - return -ENOTSUPP; + if (error) + *error =3D -ENOTSUPP; + return KCOV_MODE_INVALID; #endif - else - return -EINVAL; + } else { + if (error) + *error =3D -EINVAL; + return KCOV_MODE_INVALID; + } } =20 /* @@ -595,12 +670,47 @@ static inline bool kcov_check_handle(u64 handle, bool= common_valid, return false; } =20 +static long kcov_handle_unique_enable(struct kcov *kcov, + unsigned long bitmap_words) +{ + struct task_struct *t =3D current; + + if (!IS_ENABLED(CONFIG_KCOV_UNIQUE)) + return -ENOTSUPP; + if (kcov->mode !=3D KCOV_MODE_INIT || !kcov->state.area) + return -EINVAL; + if (kcov->t !=3D NULL || t->kcov !=3D NULL) + return -EBUSY; + + /* + * Cannot use zero-sized bitmap, also the bitmap must leave at least two + * words for the trace. + */ + if ((!bitmap_words) || (bitmap_words >=3D (kcov->state.size - 1))) + return -EINVAL; + + kcov->state.bitmap_size =3D bitmap_words * sizeof(unsigned long) * 8; + kcov->state.bitmap =3D kcov->state.area; + kcov->state.trace_size =3D kcov->state.size - bitmap_words; + kcov->state.trace =3D ((unsigned long *)kcov->state.area + bitmap_words); + + kcov_fault_in_area(kcov); + kcov->mode =3D KCOV_MODE_UNIQUE_PC; + kcov_start(t, kcov, kcov->mode, &kcov->state); + kcov->t =3D t; + /* Put either in kcov_task_exit() or in KCOV_DISABLE. */ + kcov_get(kcov); + + return 0; +} + static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd, unsigned long arg) { struct task_struct *t; unsigned long flags, unused; - int mode, i; + enum kcov_mode mode; + int error =3D 0, i; struct kcov_remote_arg *remote_arg; struct kcov_remote *remote; =20 @@ -618,9 +728,9 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigne= d int cmd, t =3D current; if (kcov->t !=3D NULL || t->kcov !=3D NULL) return -EBUSY; - mode =3D kcov_get_mode(arg); - if (mode < 0) - return mode; + mode =3D kcov_arg_to_mode(arg, &error); + if (mode =3D=3D KCOV_MODE_INVALID) + return error; kcov_fault_in_area(kcov); kcov->mode =3D mode; kcov_start(t, kcov, mode, &kcov->state); @@ -628,6 +738,8 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigne= d int cmd, /* Put either in kcov_task_exit() or in KCOV_DISABLE. */ kcov_get(kcov); return 0; + case KCOV_UNIQUE_ENABLE: + return kcov_handle_unique_enable(kcov, arg); case KCOV_DISABLE: /* Disable coverage for the current task. */ unused =3D arg; @@ -646,9 +758,9 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigne= d int cmd, if (kcov->t !=3D NULL || t->kcov !=3D NULL) return -EBUSY; remote_arg =3D (struct kcov_remote_arg *)arg; - mode =3D kcov_get_mode(remote_arg->trace_mode); - if (mode < 0) - return mode; + mode =3D kcov_arg_to_mode(remote_arg->trace_mode, &error); + if (mode =3D=3D KCOV_MODE_INVALID) + return error; if ((unsigned long)remote_arg->area_size > LONG_MAX / sizeof(unsigned long)) return -EINVAL; diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 60eb5faa27d28..f4ec041de0224 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1154,7 +1154,7 @@ static const char *uaccess_safe_builtin[] =3D { "__tsan_unaligned_write16", /* KCOV */ "write_comp_data", - "check_kcov_mode", + "get_kcov_mode", "__sanitizer_cov_trace_pc", "__sanitizer_cov_trace_pc_guard", "__sanitizer_cov_trace_const_cmp1", --=20 2.50.1.552.g942d659e1b-goog From nobody Sun Oct 5 17:56:34 2025 Received: from mail-wr1-f74.google.com (mail-wr1-f74.google.com [209.85.221.74]) (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 DD2D2221720 for ; Thu, 31 Jul 2025 11:52:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962737; cv=none; b=akRKUtV++f9DvYyk53EMqAjQFlqqVdR0iuk6QxCYU2aU9W9PwNr2IzvHyh/C/FCOt58+bL6amgQySRvLgW7Se+/mEGNLveX0gOc3JlmfMaHtkV04Ft8CPWzaJOZX6H+yLIEDnhgcQVSu06KE4Dl5Bhg4YPyrSOUNqlI6MEATpn4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962737; c=relaxed/simple; bh=DA5Wdj0iE1bl4c20loy2DajEXRDOZaZO/CNEtIe+YJA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=GKdBV+qR9rueJZG2Lci31O56Lkc/VpoHj72YjChS8FWRwuCr+Z4SHgLjTzcVIRYmaYweV0TYEpys1Zj34sdBHYjBAdCbesyCMsAdoCSnXJLmeI0WvCMwrsJSytnpwwowBntLd4kYsNGNB9rAJkfMPbSyZGW4ZgPTIjPrzOsgjuY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--glider.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=udvCQz1A; arc=none smtp.client-ip=209.85.221.74 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=flex--glider.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="udvCQz1A" Received: by mail-wr1-f74.google.com with SMTP id ffacd0b85a97d-3b78aa2a113so385756f8f.2 for ; Thu, 31 Jul 2025 04:52:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753962734; x=1754567534; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=TiC3uM7/D8NzErdvh0SxeDfKJcSB6iSbAQ3laEPvArs=; b=udvCQz1A2Ri/5WPeSNaPOdI+UukQeQyZBoHSTDfLlGptFZTlEyAaqiLqbXutwdQIp7 LxH1Tu9CUfGN0ZtfGKmUaoAP/lxc4DaKdNUuJJdxcfu5Hj2H2MeVPYkq6wsHl6bfAyeY BTHQVsfhb2qGWCxAsJzMn4BgC6glzI+PmhjBBk6FESfrcS3x9dmcgxgpR4XplC9nR7Nx PSFvYWCAiFrRxq5/86YLNgpnaJf3JNzFI7GyouR7QyCsnDClqMiZF8HxfrLZF/xgCmpY ymb/6vPBs8kM6kK/gxP8Ag4Yz6TX+HvzsnlmMqV4xCCHlbXzjHE2jUcOznVSywUlptL5 3p7Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753962734; x=1754567534; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=TiC3uM7/D8NzErdvh0SxeDfKJcSB6iSbAQ3laEPvArs=; b=L6xjsH1cgFEtu1uaEXVNeHzB0aiPDA9mLuzN8EiQjADkwwnZ3GYMYMAzFjyRgBEkR9 G4powBqjbsHXXPBXqlbUBtXeBb8ky6fVHbLtOoXLCK34b8M/0nSlOy6suOZGQezM60GK Ys6cmdKvaYkOiQX476T54NigHFhFfHyKRdFc5sE/Wf0F3WFOKVSZ7iinYr22o0zniMsA dgYL+G/F7LhBKAwSq4V/BXKVi17eZr5TNl3bz06NRtk2VHRKHj9OYyn5Ww6y5Uto+aCX z//C7DCBq2SLa8qsfUIlSK86GB4fHv5DJNvQrygbkrWzrAGZ1B0kvbeFZrqrTkBV2vwA mDNQ== X-Forwarded-Encrypted: i=1; AJvYcCU/hbddLiiDCl1obEtiva6WvOe7Rsu1AOTtY/ncbOApPGV17PqNQUv6LPFjvV+OhvpKlE3GBuUtf+ElDNk=@vger.kernel.org X-Gm-Message-State: AOJu0YxFLDe5v/UfdsAw4nUK1VNOozsDcy4hIKf8ibs4ulpigOLO7Rli wVo81JU1blXw3jY001qpQ6msT/0zjhzSisAxK4i7UD3g593jGwqaJHJttmHDTTUW7dlx4zMFYQT e48y5VA== X-Google-Smtp-Source: AGHT+IE50+USTAaUlkTKFrYYFo7vGLTpJlsac/PeWm8p7/FHjOX1FZHvjV8SGAr24cM4epEeIUAvKRsDjs4= X-Received: from wrbfm13.prod.google.com ([2002:a05:6000:280d:b0:3a4:eef1:dbc7]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:26ca:b0:3a4:ee40:715c with SMTP id ffacd0b85a97d-3b794fb67fbmr6412932f8f.14.1753962734272; Thu, 31 Jul 2025 04:52:14 -0700 (PDT) Date: Thu, 31 Jul 2025 13:51:37 +0200 In-Reply-To: <20250731115139.3035888-1-glider@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250731115139.3035888-1-glider@google.com> X-Mailer: git-send-email 2.50.1.552.g942d659e1b-goog Message-ID: <20250731115139.3035888-9-glider@google.com> Subject: [PATCH v4 08/10] kcov: add ioctl(KCOV_RESET_TRACE) From: Alexander Potapenko To: glider@google.com Cc: quic_jiangenj@quicinc.com, linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, Dmitry Vyukov , Aleksandr Nogikh , Andrey Konovalov , Borislav Petkov , Dave Hansen , Ingo Molnar , Josh Poimboeuf , Marco Elver , Peter Zijlstra , Thomas Gleixner Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Provide a mechanism to reset the coverage for the current task without writing directly to the coverage buffer. This is slower, but allows the fuzzers to map the coverage buffer as read-only, making it harder to corrupt. Signed-off-by: Alexander Potapenko Reviewed-by: Dmitry Vyukov --- v4: - Add Reviewed-by: Dmitry Vyukov v2: - Update code to match the new description of struct kcov_state Change-Id: I8f9e6c179d93ccbfe0296b14764e88fa837cfffe --- Documentation/dev-tools/kcov.rst | 26 ++++++++++++++++++++++++++ include/uapi/linux/kcov.h | 1 + kernel/kcov.c | 15 +++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/Documentation/dev-tools/kcov.rst b/Documentation/dev-tools/kco= v.rst index 6446887cd1c92..e215c0651e16d 100644 --- a/Documentation/dev-tools/kcov.rst +++ b/Documentation/dev-tools/kcov.rst @@ -470,3 +470,29 @@ local tasks spawned by the process and the global task= that handles USB bus #1: perror("close"), exit(1); return 0; } + + +Resetting coverage with an KCOV_RESET_TRACE +------------------------------------------- + +The ``KCOV_RESET_TRACE`` ioctl provides a mechanism to clear collected cov= erage +data for the current task. It resets the program counter (PC) trace and, if +``KCOV_UNIQUE_ENABLE`` mode is active, also zeroes the associated bitmap. + +The primary use case for this ioctl is to enhance safety during fuzzing. +Normally, a user could map the kcov buffer with ``PROT_READ | PROT_WRITE``= and +reset the trace from the user-space program. However, when fuzzing system = calls, +the kernel itself might inadvertently write to this shared buffer, corrupt= ing +the coverage data. + +To prevent this, a fuzzer can map the buffer with ``PROT_READ`` and use +``ioctl(fd, KCOV_RESET_TRACE, 0)`` to safely clear the buffer from the ker= nel +side before each fuzzing iteration. + +Note that: + +* This ioctl is safer but slower than directly writing to the shared memory + buffer due to the overhead of a system call. +* ``KCOV_RESET_TRACE`` is itself a system call, and its execution will be = traced + by kcov. Consequently, immediately after the ioctl returns, cover[0] wil= l be + greater than 0. diff --git a/include/uapi/linux/kcov.h b/include/uapi/linux/kcov.h index e743ee011eeca..8ab77cc3afa76 100644 --- a/include/uapi/linux/kcov.h +++ b/include/uapi/linux/kcov.h @@ -23,6 +23,7 @@ struct kcov_remote_arg { #define KCOV_DISABLE _IO('c', 101) #define KCOV_REMOTE_ENABLE _IOW('c', 102, struct kcov_remote_arg) #define KCOV_UNIQUE_ENABLE _IOW('c', 103, unsigned long) +#define KCOV_RESET_TRACE _IO('c', 104) =20 enum { /* diff --git a/kernel/kcov.c b/kernel/kcov.c index a92c848d17bce..82ed4c6150c54 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -740,6 +740,21 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsign= ed int cmd, return 0; case KCOV_UNIQUE_ENABLE: return kcov_handle_unique_enable(kcov, arg); + case KCOV_RESET_TRACE: + unused =3D arg; + if (unused !=3D 0 || current->kcov !=3D kcov) + return -EINVAL; + t =3D current; + if (WARN_ON(kcov->t !=3D t)) + return -EINVAL; + mode =3D kcov->mode; + if (mode < KCOV_MODE_TRACE_PC) + return -EINVAL; + if (kcov->state.bitmap) + bitmap_zero(kcov->state.bitmap, + kcov->state.bitmap_size); + WRITE_ONCE(kcov->state.trace[0], 0); + return 0; case KCOV_DISABLE: /* Disable coverage for the current task. */ unused =3D arg; --=20 2.50.1.552.g942d659e1b-goog From nobody Sun Oct 5 17:56:34 2025 Received: from mail-wm1-f74.google.com (mail-wm1-f74.google.com [209.85.128.74]) (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 6AFBE2C15BC for ; Thu, 31 Jul 2025 11:52:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962740; cv=none; b=puHAoMc6T9p4AbMtuYpPF+MwR+sM9ZJGM9LpBRHqr5FP37cwsBEwgSbaVWb4n85dTPnaFOfLP3lwZV9pt2nm4E4r9DysPaoyrmIAVcBIFXkIw9F/ugvMPh9CDw+JuglCkSaAhNSjFxN15yhixrH9Jml2C60xAvXasAoNG7mxq8s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962740; c=relaxed/simple; bh=8s1lFStlYqBNb80I1bimebpW/X9YENeLEuBPuYPSvg8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=h9BibzIsuXl+phIN4GUs9t8siG85q1RHF3y42OrGZMcqxbrFHT2/XYCx5UZUlDXJkw4JG1vJEoSd5HE7a3tR7/QJAFuVa6jOMQp8j0eKHfOSiExw85QeoItmmEfmCkGmZsHkVMSr9m/jrIFfxq3wBYmlSu+HYqjPUhuTmu8jbjk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--glider.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=qY+Vli6W; arc=none smtp.client-ip=209.85.128.74 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=flex--glider.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="qY+Vli6W" Received: by mail-wm1-f74.google.com with SMTP id 5b1f17b1804b1-45867ac308dso4073435e9.2 for ; Thu, 31 Jul 2025 04:52:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753962737; x=1754567537; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=h3x7t3g1azUi3Bhe5e/NuO4vXpKA7reEhObrUhymgs0=; b=qY+Vli6WzSRuHGCrJ52RA5kTJLQHCdel/oy2z4m5LFwpvtW0BznvsnuQucMzTRicwp zINfvcKx7BKiVE7nHJVcxtmq2OJ17AhdRnEnGhHGr+kJ4321rHWDjNxFFw9VVlpZ+w+U UhgGUNzAX99qKszaeWrf0uNP91WoZxlQVyUYXTgHZN6jfw6fhXW02PBQ6SuP2K0o7EmR 2oBzn+SoB3fb+XLkpdL+yhTym41Gi3TPT5Sxq42qQSuelYl+xV30qMaW0iRXMwA30atR xR9YtWc0WXLzcBfxmDNoJZQtTPPv+b/YvdqkfJfsQ5nhOHd/b7MvggUsT1Yv/yIbl7Yd Sy3A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753962737; x=1754567537; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=h3x7t3g1azUi3Bhe5e/NuO4vXpKA7reEhObrUhymgs0=; b=Lr6Ftmux9q8gcwwpQ0qyHrZzRUwkc7f+WhStHJ3S/gxb+9CgJWpLGO/S7TTX25uQNt iUCFUGiRtuv2ygEAid3kiNGjOkPTwJ0rK3+nFMLxRJn2q4mNiaCpD2fOmhiyNwP1gboG BqQwqNjOhugPP18AEZCVyXXVWfA/jBl2kPI1Ooz6iEc7PQPPdJqjyeDG7Tw+lUy1NPOh I1xhX1Kmkzden2uVwbiQKJImsv/0WrLF1iE1MOu1y46Lo4sBuTqrNYgDpQyA0WZKxm7T ROes978kHmBBiaGsZERcf7+E2+FcfrXClagHYvBWxmyY14JLWa/erlHzF0okJ6YKA05N Y6Bg== X-Forwarded-Encrypted: i=1; AJvYcCV6TVNZFVyVRsrjYbIIhaCiloTB5gFFc5R0+2GgQ+2gaRT7jy6LM/gmzyBJZe4NdUtlLpeGNAhEabOKueY=@vger.kernel.org X-Gm-Message-State: AOJu0YxfGCySOFQXq09xWO37SjX2GGA2SDOmsZKUfoqSTaASx8IplIvS V/fNotpdXN5CXqpzvYaWN9BVA46mD63pPPjNC8TwGkk+mdbjIH4taH3aWNHYwfUgIftGaU23xtY YdbNIkg== X-Google-Smtp-Source: AGHT+IExHF1OViXisfAJMuA5wloCcYI2HYLmUzRgw6/gntLBPE9zL+3/cH0aWSPIIgcd2egwFV35D5XJkfY= X-Received: from wmbet10.prod.google.com ([2002:a05:600c:818a:b0:458:8d91:62dd]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:8b6e:b0:456:27a4:50ad with SMTP id 5b1f17b1804b1-45892be4bf9mr54021785e9.33.1753962736912; Thu, 31 Jul 2025 04:52:16 -0700 (PDT) Date: Thu, 31 Jul 2025 13:51:38 +0200 In-Reply-To: <20250731115139.3035888-1-glider@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250731115139.3035888-1-glider@google.com> X-Mailer: git-send-email 2.50.1.552.g942d659e1b-goog Message-ID: <20250731115139.3035888-10-glider@google.com> Subject: [PATCH v4 09/10] kcov: selftests: add kcov_test From: Alexander Potapenko To: glider@google.com Cc: quic_jiangenj@quicinc.com, linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, Aleksandr Nogikh , Andrey Konovalov , Borislav Petkov , Dave Hansen , Dmitry Vyukov , Ingo Molnar , Josh Poimboeuf , Marco Elver , Peter Zijlstra , Thomas Gleixner Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Implement test fixtures for testing different combinations of coverage collection modes: - unique and non-unique coverage; - collecting PCs and comparison arguments; - mapping the buffer as RO and RW. To build: $ make -C tools/testing/selftests/kcov kcov_test Signed-off-by: Alexander Potapenko Reviewed-by: Dmitry Vyukov --- v4: - Per Dmitry Vyukov's request, add CONFIG_KCOV_UNIQUE=3Dy to the list of required configs v3: - Address comments by Dmitry Vyukov: - add tools/testing/selftests/kcov/config - add ifdefs to KCOV_UNIQUE_ENABLE and KCOV_RESET_TRACE - Properly handle/reset the coverage buffer when collecting unique coverage Change-Id: I0793f1b91685873c77bcb222a03f64321244df8f --- MAINTAINERS | 1 + tools/testing/selftests/kcov/Makefile | 6 + tools/testing/selftests/kcov/config | 2 + tools/testing/selftests/kcov/kcov_test.c | 401 +++++++++++++++++++++++ 4 files changed, 410 insertions(+) create mode 100644 tools/testing/selftests/kcov/Makefile create mode 100644 tools/testing/selftests/kcov/config create mode 100644 tools/testing/selftests/kcov/kcov_test.c diff --git a/MAINTAINERS b/MAINTAINERS index 6906eb9d88dae..c1d64cef693b9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13018,6 +13018,7 @@ F: include/linux/kcov_types.h F: include/uapi/linux/kcov.h F: kernel/kcov.c F: scripts/Makefile.kcov +F: tools/testing/selftests/kcov/ =20 KCSAN M: Marco Elver diff --git a/tools/testing/selftests/kcov/Makefile b/tools/testing/selftest= s/kcov/Makefile new file mode 100644 index 0000000000000..08abf8b60bcf9 --- /dev/null +++ b/tools/testing/selftests/kcov/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +LDFLAGS +=3D -static + +TEST_GEN_PROGS :=3D kcov_test + +include ../lib.mk diff --git a/tools/testing/selftests/kcov/config b/tools/testing/selftests/= kcov/config new file mode 100644 index 0000000000000..ba0c1a0bc8bf2 --- /dev/null +++ b/tools/testing/selftests/kcov/config @@ -0,0 +1,2 @@ +CONFIG_KCOV=3Dy +CONFIG_KCOV_UNIQUE=3Dy diff --git a/tools/testing/selftests/kcov/kcov_test.c b/tools/testing/selft= ests/kcov/kcov_test.c new file mode 100644 index 0000000000000..daf12aeb374b5 --- /dev/null +++ b/tools/testing/selftests/kcov/kcov_test.c @@ -0,0 +1,401 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test the kernel coverage (/sys/kernel/debug/kcov). + * + * Copyright 2025 Google LLC. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../kselftest_harness.h" + +/* Normally these defines should be provided by linux/kcov.h, but they are= n't there yet. */ +#ifndef KCOV_UNIQUE_ENABLE +#define KCOV_UNIQUE_ENABLE _IOW('c', 103, unsigned long) +#endif +#ifndef KCOV_RESET_TRACE +#define KCOV_RESET_TRACE _IO('c', 104) +#endif + +#define COVER_SIZE (64 << 10) +#define BITMAP_SIZE (4 << 10) + +#define DEBUG_COVER_PCS 0 + +FIXTURE(kcov) +{ + int fd; + unsigned long *mapping; + size_t mapping_size; +}; + +FIXTURE_VARIANT(kcov) +{ + int mode; + bool fast_reset; + bool map_readonly; +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(kcov, mode_trace_pc) +{ + /* clang-format on */ + .mode =3D KCOV_TRACE_PC, + .fast_reset =3D true, + .map_readonly =3D false, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(kcov, mode_trace_cmp) +{ + /* clang-format on */ + .mode =3D KCOV_TRACE_CMP, + .fast_reset =3D true, + .map_readonly =3D false, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(kcov, reset_ioctl_rw) +{ + /* clang-format on */ + .mode =3D KCOV_TRACE_PC, + .fast_reset =3D false, + .map_readonly =3D false, +}; + +FIXTURE_VARIANT_ADD(kcov, reset_ioctl_ro) +/* clang-format off */ +{ + /* clang-format on */ + .mode =3D KCOV_TRACE_PC, + .fast_reset =3D false, + .map_readonly =3D true, +}; + +int kcov_open_init(struct __test_metadata *_metadata, unsigned long size, + int prot, unsigned long **out_mapping) +{ + unsigned long *mapping; + + /* A single fd descriptor allows coverage collection on a single thread. = */ + int fd =3D open("/sys/kernel/debug/kcov", O_RDWR); + + ASSERT_NE(fd, -1) + { + perror("open"); + } + + EXPECT_EQ(ioctl(fd, KCOV_INIT_TRACE, size), 0) + { + perror("ioctl KCOV_INIT_TRACE"); + close(fd); + } + + /* Mmap buffer shared between kernel- and user-space. */ + mapping =3D (unsigned long *)mmap(NULL, size * sizeof(unsigned long), + prot, MAP_SHARED, fd, 0); + ASSERT_NE((void *)mapping, MAP_FAILED) + { + perror("mmap"); + close(fd); + } + *out_mapping =3D mapping; + + return fd; +} + +FIXTURE_SETUP(kcov) +{ + int prot =3D variant->map_readonly ? PROT_READ : (PROT_READ | PROT_WRITE); + + /* Read-only mapping is incompatible with fast reset. */ + ASSERT_FALSE(variant->map_readonly && variant->fast_reset); + + self->mapping_size =3D COVER_SIZE; + self->fd =3D kcov_open_init(_metadata, self->mapping_size, prot, + &(self->mapping)); + + /* Enable coverage collection on the current thread. */ + EXPECT_EQ(ioctl(self->fd, KCOV_ENABLE, variant->mode), 0) + { + perror("ioctl KCOV_ENABLE"); + /* Cleanup will be handled by FIXTURE_TEARDOWN. */ + return; + } +} + +void kcov_uninit_close(struct __test_metadata *_metadata, int fd, + unsigned long *mapping, size_t size) +{ + /* Disable coverage collection for the current thread. */ + EXPECT_EQ(ioctl(fd, KCOV_DISABLE, 0), 0) + { + perror("ioctl KCOV_DISABLE"); + } + + /* Free resources. */ + EXPECT_EQ(munmap(mapping, size * sizeof(unsigned long)), 0) + { + perror("munmap"); + } + + EXPECT_EQ(close(fd), 0) + { + perror("close"); + } +} + +FIXTURE_TEARDOWN(kcov) +{ + kcov_uninit_close(_metadata, self->fd, self->mapping, + self->mapping_size); +} + +void dump_collected_pcs(struct __test_metadata *_metadata, unsigned long *= cover, + size_t start, size_t end) +{ + int i =3D 0; + + TH_LOG("Collected %lu PCs", end - start); +#if DEBUG_COVER_PCS + for (i =3D start; i < end; i++) + TH_LOG("0x%lx", cover[i + 1]); +#endif +} + +/* Coverage collection helper without assertions. */ +unsigned long collect_coverage_unchecked(struct __test_metadata *_metadata, + unsigned long *cover, bool dump) +{ + unsigned long before, after; + + before =3D __atomic_load_n(&cover[0], __ATOMIC_RELAXED); + /* + * Call the target syscall call. Here we use read(-1, NULL, 0) as an exam= ple. + * This will likely return an error (-EFAULT or -EBADF), but the goal is = to + * collect coverage for the syscall's entry/exit paths. + */ + read(-1, NULL, 0); + + after =3D __atomic_load_n(&cover[0], __ATOMIC_RELAXED); + + if (dump) + dump_collected_pcs(_metadata, cover, before, after); + return after - before; +} + +unsigned long collect_coverage_once(struct __test_metadata *_metadata, + unsigned long *cover) +{ + unsigned long collected =3D + collect_coverage_unchecked(_metadata, cover, /*dump*/ true); + + /* Coverage must be non-zero. */ + EXPECT_GT(collected, 0); + return collected; +} + +void reset_coverage(struct __test_metadata *_metadata, bool fast, int fd, + unsigned long *mapping) +{ + unsigned long count; + + if (fast) { + __atomic_store_n(&mapping[0], 0, __ATOMIC_RELAXED); + } else { + EXPECT_EQ(ioctl(fd, KCOV_RESET_TRACE, 0), 0) + { + perror("ioctl KCOV_RESET_TRACE"); + } + count =3D __atomic_load_n(&mapping[0], __ATOMIC_RELAXED); + EXPECT_NE(count, 0); + } +} + +TEST_F(kcov, kcov_basic_syscall_coverage) +{ + unsigned long first, second, before, after, i; + + /* Reset coverage that may be left over from the fixture setup. */ + reset_coverage(_metadata, variant->fast_reset, self->fd, self->mapping); + + /* Collect the coverage for a single syscall two times in a row. */ + first =3D collect_coverage_once(_metadata, self->mapping); + second =3D collect_coverage_once(_metadata, self->mapping); + /* Collected coverage should not differ too much. */ + EXPECT_GT(first * 10, second); + EXPECT_GT(second * 10, first); + + /* Now reset the buffer and collect the coverage again. */ + reset_coverage(_metadata, variant->fast_reset, self->fd, self->mapping); + collect_coverage_once(_metadata, self->mapping); + + /* Now try many times to fill up the buffer. */ + reset_coverage(_metadata, variant->fast_reset, self->fd, self->mapping); + while (collect_coverage_unchecked(_metadata, self->mapping, + /*dump*/ false)) { + /* Do nothing. */ + } + before =3D __atomic_load_n(&(self->mapping[0]), __ATOMIC_RELAXED); + /* + * Resetting with ioctl may still generate some coverage, but much less + * than there was before. + */ + reset_coverage(_metadata, variant->fast_reset, self->fd, self->mapping); + after =3D __atomic_load_n(&(self->mapping[0]), __ATOMIC_RELAXED); + EXPECT_GT(before, after); + /* Collecting coverage after reset will now succeed. */ + collect_coverage_once(_metadata, self->mapping); +} + +FIXTURE(kcov_uniq) +{ + int fd; + unsigned long *mapping; + size_t mapping_size; + unsigned long *bitmap; + size_t bitmap_size; + unsigned long *cover; + size_t cover_size; +}; + +FIXTURE_VARIANT(kcov_uniq) +{ + bool fast_reset; + bool map_readonly; +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(kcov_uniq, fast_rw) +{ + /* clang-format on */ + .fast_reset =3D true, + .map_readonly =3D false, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(kcov_uniq, slow_rw) +{ + /* clang-format on */ + .fast_reset =3D false, + .map_readonly =3D false, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(kcov_uniq, slow_ro) +{ + /* clang-format on */ + .fast_reset =3D false, + .map_readonly =3D true, +}; + +FIXTURE_SETUP(kcov_uniq) +{ + int prot =3D variant->map_readonly ? PROT_READ : (PROT_READ | PROT_WRITE); + + /* Read-only mapping is incompatible with fast reset. */ + ASSERT_FALSE(variant->map_readonly && variant->fast_reset); + + self->mapping_size =3D COVER_SIZE; + self->fd =3D kcov_open_init(_metadata, self->mapping_size, prot, + &(self->mapping)); + + self->bitmap =3D self->mapping; + self->bitmap_size =3D BITMAP_SIZE; + /* + * Enable unique coverage collection on the current thread. Carve out + * self->bitmap_size unsigned long's for the bitmap. + */ + EXPECT_EQ(ioctl(self->fd, KCOV_UNIQUE_ENABLE, self->bitmap_size), 0) + { + perror("ioctl KCOV_ENABLE"); + /* Cleanup will be handled by FIXTURE_TEARDOWN. */ + return; + } + self->cover =3D self->mapping + BITMAP_SIZE; + self->cover_size =3D self->mapping_size - BITMAP_SIZE; +} + +FIXTURE_TEARDOWN(kcov_uniq) +{ + kcov_uninit_close(_metadata, self->fd, self->mapping, + self->mapping_size); +} + +void reset_uniq_coverage(struct __test_metadata *_metadata, bool fast, int= fd, + unsigned long *bitmap, unsigned long *cover) +{ + unsigned long count; + + if (fast) { + /* + * Resetting the buffer for unique coverage collection requires + * zeroing out the bitmap and cover[0]. We are assuming that + * the coverage buffer immediately follows the bitmap, as they + * belong to the same memory mapping. + */ + if (cover > bitmap) + memset(bitmap, 0, sizeof(unsigned long) * (cover - bitmap)); + __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED); + } else { + EXPECT_EQ(ioctl(fd, KCOV_RESET_TRACE, 0), 0) + { + perror("ioctl KCOV_RESET_TRACE"); + } + count =3D __atomic_load_n(&cover[0], __ATOMIC_RELAXED); + EXPECT_NE(count, 0); + } +} + +TEST_F(kcov_uniq, kcov_uniq_coverage) +{ + unsigned long first, second, before, after, i; + + /* Reset coverage that may be left over from the fixture setup. */ + reset_uniq_coverage(_metadata, variant->fast_reset, self->fd, self->bitma= p, self->cover); + + /* + * Collect the coverage for a single syscall two times in a row. + * Use collect_coverage_unchecked(), because it may return zero coverage. + */ + first =3D collect_coverage_unchecked(_metadata, self->cover, + /*dump*/ true); + second =3D collect_coverage_unchecked(_metadata, self->cover, + /*dump*/ true); + + /* Now reset the buffer and collect the coverage again. */ + reset_uniq_coverage(_metadata, variant->fast_reset, self->fd, self->bitma= p, self->cover); + collect_coverage_once(_metadata, self->cover); + + /* Now try many times to saturate the unique coverage bitmap. */ + reset_uniq_coverage(_metadata, variant->fast_reset, self->fd, self->bitma= p, self->cover); + for (i =3D 0; i < 1000; i++) + collect_coverage_unchecked(_metadata, self->cover, + /*dump*/ false); + + /* Another invocation of collect_coverage_unchecked() should not produce = new coverage. */ + EXPECT_EQ(collect_coverage_unchecked(_metadata, self->cover, + /*dump*/ false), + 0); + + before =3D __atomic_load_n(&(self->cover[0]), __ATOMIC_RELAXED); + /* + * Resetting with ioctl may still generate some coverage, but much less + * than there was before. + */ + reset_uniq_coverage(_metadata, variant->fast_reset, self->fd, self->bitma= p, self->cover); + after =3D __atomic_load_n(&(self->cover[0]), __ATOMIC_RELAXED); + EXPECT_GT(before, after); + /* Collecting coverage after reset will now succeed. */ + collect_coverage_once(_metadata, self->cover); +} + +TEST_HARNESS_MAIN --=20 2.50.1.552.g942d659e1b-goog From nobody Sun Oct 5 17:56:34 2025 Received: from mail-wr1-f74.google.com (mail-wr1-f74.google.com [209.85.221.74]) (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 05E962D1F45 for ; Thu, 31 Jul 2025 11:52:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962742; cv=none; b=LLqLN65OCVPaJDb4dMZLNyMseFpHSi0jOZ5GFgYt9cC8ejBEZy1/sV0aoYfeTi4jvqMsSSlNrTA4a7NdaCZk5wubKeK8R6xzWY54sBb4k/p4PagnhWzmhOWXEU5ThERgckOJHwq0jOVuZXwmqIxfIiabLKIIhbvAywFUDYKOK3E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753962742; c=relaxed/simple; bh=ex7aFGh63rGWYKE0ZLNtL5d8gBsPWNlimliemfap3Gw=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=eKb4UYJOxtoWIyoyBptKsqbmUPO2C91Xj/zSkIHnlKwROR+crUYtYK76Gu6qpBimeUPrAJXhE/LawHPkH6kX47fGETzvr8Xl7vQp31ovQRBF73jhw7xOxtrXoVSUz2uhUhOn5QzCVefabdNbTJy6pehFqxtY7HyX4zmqFjN9Udc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--glider.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=kwopOJKd; arc=none smtp.client-ip=209.85.221.74 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=flex--glider.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="kwopOJKd" Received: by mail-wr1-f74.google.com with SMTP id ffacd0b85a97d-3b78329f180so540856f8f.3 for ; Thu, 31 Jul 2025 04:52:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753962739; x=1754567539; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=3GI7pfDzbEZpzy7S8dcB3cJkLd1K2BcoBH+xtJGm4Rs=; b=kwopOJKdzIeU8Jd4lyJaAiVJLm9+09OVCn6aYrLsqOyBjJp9tddlNcFXoSAV/j7OqX iei5zsNUAbbujbR+w2g9CWfSLwof8mlbmtmCgtqftDcDjszGGbHvV14AxnbSGNGDGOKI fBnrpKdpxrfF7fi0v2yd0yFDMWKY5N43vYRKxGkcmGmTP2U7KGWFE76GFTearRQ65P/9 0tbqs5hNw8L+sf616ham7M0Uk+zJ6kxO0HDAJxZV8brvJAgS6bIq/lMP3UQpYM/iLEtv wfdqBGY/kdQV0c+RB+NmavNeuteuQ0sGU5D4dMk7AIx/K3LxN2sV/ajHfsWZM58zhHSw 80Yw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753962739; x=1754567539; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=3GI7pfDzbEZpzy7S8dcB3cJkLd1K2BcoBH+xtJGm4Rs=; b=Jlk/E+nqWz+XLhTOdJ/oOSYkK7o06E2omQivj9bT0QRGQ6xLKD0Gh6mGnoO9XJ3azF 9MB4ECECHpaiAoEQ+QZS03s+323wg3OztNc96uJI2ZXU3Ta1c3vHBtGK5JJeOlPCDLP4 m4RpmfsAE8gzKKz1ndPSPQup+O14mmF4tHq3A2rXC3xkVsvIMAu+JccR1YXGO8xYMEO7 92syqjSJunuIvJjxaHgAVxWWnpOpCPzTowXAII18Z7gRACU2iwruU2ea0H7fLHDVt3Li tlKx/+h70muq6kAj/ZipqkHyMVX/FYPpudPW+k8b9XaKEWv9avLG2w71EPHmaeTAmRWC FpUQ== X-Forwarded-Encrypted: i=1; AJvYcCXmkjKiuGsLqkZiYtdxCBiBg1WOtsVFvSPLuTUv0A2HzzIiAm0T49u1ZQ2aw0yNkTQF3nRBxOXu2zhLco0=@vger.kernel.org X-Gm-Message-State: AOJu0YyJPmr2WNVwKe1SSabxrzWxKUsWXWwZkjp4PgZw29PAy3vOzdz8 1b2G3L/EYjgJv/OAh/iidyE9+fS0Q5Pq3vhzZafJHyGHZMxuaxACUFB+mVFkY+q+GSrl+CatfNT xmHqRog== X-Google-Smtp-Source: AGHT+IFxNdx6ot8g09Y+M8mgdTgi7og9gyB3PqBmK8AEtcJUb3tDZZzVDcF7OxHvGDSE1S7lhA5lxiojGaU= X-Received: from wmbgv7.prod.google.com ([2002:a05:600c:80c7:b0:458:a7ae:4acf]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:2912:b0:3b3:9ca4:ac8e with SMTP id ffacd0b85a97d-3b794ff878amr5465479f8f.44.1753962739364; Thu, 31 Jul 2025 04:52:19 -0700 (PDT) Date: Thu, 31 Jul 2025 13:51:39 +0200 In-Reply-To: <20250731115139.3035888-1-glider@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250731115139.3035888-1-glider@google.com> X-Mailer: git-send-email 2.50.1.552.g942d659e1b-goog Message-ID: <20250731115139.3035888-11-glider@google.com> Subject: [PATCH v4 10/10] kcov: use enum kcov_mode in kcov_mode_enabled() From: Alexander Potapenko To: glider@google.com Cc: quic_jiangenj@quicinc.com, linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, Dmitry Vyukov , Aleksandr Nogikh , Andrey Konovalov , Borislav Petkov , Dave Hansen , Ingo Molnar , Josh Poimboeuf , Marco Elver , Peter Zijlstra , Thomas Gleixner Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Replace the remaining declarations of `unsigned int mode` with `enum kcov_mode mode`. No functional change. Signed-off-by: Alexander Potapenko Reviewed-by: Dmitry Vyukov --- v4: - Add Reviewed-by: Dmitry Vyukov Change-Id: I739b293c1f689cc99ef4adbe38bdac5813802efe --- kernel/kcov.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/kcov.c b/kernel/kcov.c index 82ed4c6150c54..6b7c21280fcd5 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -949,7 +949,7 @@ static const struct file_operations kcov_fops =3D { * collecting coverage and copies all collected coverage into the kcov are= a. */ =20 -static inline bool kcov_mode_enabled(unsigned int mode) +static inline bool kcov_mode_enabled(enum kcov_mode mode) { return (mode & ~KCOV_IN_CTXSW) !=3D KCOV_MODE_DISABLED; } @@ -957,7 +957,7 @@ static inline bool kcov_mode_enabled(unsigned int mode) static void kcov_remote_softirq_start(struct task_struct *t) { struct kcov_percpu_data *data =3D this_cpu_ptr(&kcov_percpu_data); - unsigned int mode; + enum kcov_mode mode; =20 mode =3D READ_ONCE(t->kcov_mode); barrier(); @@ -1134,7 +1134,7 @@ void kcov_remote_stop(void) { struct task_struct *t =3D current; struct kcov *kcov; - unsigned int mode; + enum kcov_mode mode; void *area; unsigned int size; int sequence; --=20 2.50.1.552.g942d659e1b-goog