From nobody Sun Oct 5 23:45:01 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 AB5C6273808 for ; Mon, 28 Jul 2025 15:26: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=1753716363; cv=none; b=aC3YOWcs6jo96WpkUn6apBiDkRcKa5LjHs5wnJJaF0w/X2OGxrM1W6Oy5+HvmdpW/5ezXne6VtQH8okTWqzup7xocuvuAJvhdivnjJfAZ/MRSlUawe8p1Bqqu4TEmT4qr0Zwc5OS1/CFojFciCXl0QQ0W3wyrT/Km7zxpSVXMJs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753716363; c=relaxed/simple; bh=gVNBX5v1fHfBF+/rvqTg/Zf4VYqZlUkchmACzkZ+K8k=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=gdB7UDqYkEq3DDRvlA5TLHzh2wrexT9FXiROo8QcoQU8rcSBMtKviuWSG0TvRrfc0X993bz5L0GFVA9s5TO0FC8RW3BWxLLfoQFaiFTpUqme5dKLwU3V7vSa00O+DuG6tyeevVzykmEh0FaRZc1V5Mv3DKViDiGDb/OihLITEfs= 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=bhL4Q0op; 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="bhL4Q0op" Received: by mail-wr1-f73.google.com with SMTP id ffacd0b85a97d-3a6d1394b07so2713929f8f.3 for ; Mon, 28 Jul 2025 08:26:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753716360; x=1754321160; 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=hA2z1o4ZKLpPx/4s7kZhiOi+XbhOvD8L3886s5YuSNo=; b=bhL4Q0opoJ/IKJx/b2RNy+2CFvGgbJKGlZyZTUNmaKzu5F6ChN0kL+piBenWBWQvQ0 uJbBrYgUsd32cFd2RvHWajRVON25UWfxfCVpGOUZOA8HMp/RZSrUGP6ZAriH2KMmWJpl dMEopspM6qZoDi+dmpv5bpGqdNOSr5/GSMRSEM3/b+SMMs4vKKxJL/a1oQ12phT8SKlD giZqTzhl6Cf954O3Lbi49bEO4aYMiCMoeeT8dIPeifv57CXiAt1yf1UrL/S5E2o3cP9I zuS77w2p/PDQmxpGCXYx37ov6HZjQPzmmfniaWrhA/bletbc0gk8jPizm97j3yZs2AQH WwCQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753716360; x=1754321160; 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=hA2z1o4ZKLpPx/4s7kZhiOi+XbhOvD8L3886s5YuSNo=; b=Hj5Uh3jjAUURtVYzOfP5fyxSXRdAw4PYH0IwPwGUc67RXMUSOgUTOgcTLQaw1TEAP/ N3vGUDmYHp2FzolJe9VpVd3WsBftIQzHOX29BBrzvwsbcFGtJohFiAJtu58hzKLTwflw ho+XVVe+9Jm9pBm1F0LTDPsJsqg1q5Wt7OCFf9GuVucnDVPXOxp4XR/1nuuZ/+bOrIN8 Ycdtapbp8qvCv6fOXdChMvcAsrBAjF1Ruh/qr5EQKUtbIPOiczbF8XloZSSbSYNfr1p4 LZ3uB1YsUGUfXOqUsySQpKG7oH/l0HzyYVLHIEEJSArbmEq0C/Dt9ha01xfGZdSl2UDn mdFQ== X-Forwarded-Encrypted: i=1; AJvYcCVnVIJgqsyqqRM5qS23bDzCzwZQoKfcliy1Lfm3PoyjrMPraHvap/VDaBnZ+3Gj8L+6NcUhr6g3CqVVYTc=@vger.kernel.org X-Gm-Message-State: AOJu0YwVa09aHQaeYEWrLRi2FN5R/Jga/QJIrT1Q9OjKphLsLGhECSVA Dd6L0NP6P14Bna8Nu9UER6MuVmdVoBexwiM1EUTcCItvF0wjrxDliScSr9T91kQotQBMHEvhFDI SC5uwVQ== X-Google-Smtp-Source: AGHT+IEdqY6eTeVAU3TB+2kdhYBC38PQ/sxXzD1PRV8zVs8UyJbuGs3uNpUw75OIdLQLrdfOizU1DybRo6I= X-Received: from wrur18.prod.google.com ([2002:a05:6000:1b92:b0:3a3:6eeb:2a27]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:230d:b0:3b7:8d71:9657 with SMTP id ffacd0b85a97d-3b78d71968amr446780f8f.28.1753716359829; Mon, 28 Jul 2025 08:25:59 -0700 (PDT) Date: Mon, 28 Jul 2025 17:25:39 +0200 In-Reply-To: <20250728152548.3969143-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: <20250728152548.3969143-1-glider@google.com> X-Mailer: git-send-email 2.50.1.470.g6ba607880d-goog Message-ID: <20250728152548.3969143-2-glider@google.com> Subject: [PATCH v3 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.470.g6ba607880d-goog From nobody Sun Oct 5 23:45:01 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 5CC66273D8C for ; Mon, 28 Jul 2025 15:26:04 +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=1753716366; cv=none; b=C20GOQOCgZKS+YEXyvdllz1WhZUbzjDpYiCVkrGGPNIZh8MpCmPAgFO2K3LFoUrXWPCZ/rFPtv4m7IIH1oxjLu9dxeqgVXmSuDewwhVjWmkQwRW4yYDwF45e+gCAPw5RJJ7wAakju1V3rDU4m7+G/Lh93KtOctjr31xCijBkAAE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753716366; c=relaxed/simple; bh=B2+rh0rOGraQ7q8XhKBNzeZFAeXpJupBpVJeEQFtmt4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=lj1NYBl+oVoiIZlhtfEreaFriGOiMe8aiTpto8aPoheG7Y9Womy/pWffOOcxd+RP4/WJthv5OIn22LXN/fSw8+IzXCGoltCsaQrh37B2pgaZ+dHgm0hKPLrpkPLbHZn+oB+6ksJKPuCofuGpX+v2PCu2tQNYNBE+5CR8O2cFoeE= 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=gQPkzr0L; 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="gQPkzr0L" Received: by mail-wm1-f73.google.com with SMTP id 5b1f17b1804b1-45626532e27so25518095e9.1 for ; Mon, 28 Jul 2025 08:26:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753716362; x=1754321162; 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=85Dq+0aWzQbqxgpA60NbQvRp1U2h0O13hIt4+o13Fas=; b=gQPkzr0Lpm/ejv0M8aSx1wm3/0s7+EaHVIozE9tD9unsy0yzmqqrZYfw1oBEomPMdQ 59CJiaNqsSy50go2PXBvRQVaTZo13Ydbe6j8dBHeYN5P6+HtGUkbnp8y5sGGHHRVOaxB t30voSe2TY7fuNJlHgrPdCd/kLtleG/liyBWq6dnYmrLT+jLZnJFJ7Kb4ZdiS4itRBZ6 /WfWcQeJG1w3fhJhRggTVWRmCVC7ySOwzhg5g+CDhOvYZFzVDVCnMnsVhDtGYLHZ0dBZ aT82Qw2hviXspFRdPAyXxlDGyeodNLFlWmNUSMk6UqeG3BAy9g8tUAx5FZVrlrTxoJZd ze9w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753716363; x=1754321163; 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=85Dq+0aWzQbqxgpA60NbQvRp1U2h0O13hIt4+o13Fas=; b=b0JUZ3DFr0RgA9pRmmvCWYU3sf4phDTaMfKf1p9g0A+HF8rFVavYdhh3w5qXXsHJOv 4S3XAucgOFTtLqtAetdMr8tTXb2PsRsMoU6zRccb3ie2hk4cyJmDOtR8NEj21U8cZa4/ O9BY3j8lRtLJsNYNic8U2OXdRxLX0r74bbbg2uaRcqL/IT65mvzU+lEIB6O0LAP3usld fdYaUssZN5m5c3QYT27pEl+KBSSYTwfdGwMUgOAnYqaeE3urB+LvTrG3imVF3akqnCYH gvSFus7u/w8Zpvzgh++DVlCKP3sgvG55kIaEQBxwFDc2Tw5P8lCeOtluDgeY9tUPTSH/ 5dyQ== X-Forwarded-Encrypted: i=1; AJvYcCWcYo4i9dBBSsGAscamhzBHTyOTpQKt9RArfUW/MeZCyJeXrBLHIQqC+tU3p+nm71YcEjMrMUaeovUEcrI=@vger.kernel.org X-Gm-Message-State: AOJu0YxCGg4Dh+5InBDNoGc5dTmv7wBaUAQpURRv6WwgozCpBmis1ZKM lYTflF7lQnfIWf2GS6NWV+y6iWeCC/lPUl62gWImim5+PyXx5KJrDVgH7VtrupYVGrN09VggN+M Igd8e9Q== X-Google-Smtp-Source: AGHT+IF7iuHEqTYX6R6hFk+4Mr2nordQpQph6sAYq6uxKRUPLUn4yemzwfL/jq5aN++p+IChmzkvToBdX1o= X-Received: from wrbeh10.prod.google.com ([2002:a05:6000:410a:b0:3b7:76ea:26cd]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:4009:b0:3b7:8d47:6f82 with SMTP id ffacd0b85a97d-3b78d476ff0mr666355f8f.57.1753716362501; Mon, 28 Jul 2025 08:26:02 -0700 (PDT) Date: Mon, 28 Jul 2025 17:25:40 +0200 In-Reply-To: <20250728152548.3969143-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: <20250728152548.3969143-1-glider@google.com> X-Mailer: git-send-email 2.50.1.470.g6ba607880d-goog Message-ID: <20250728152548.3969143-3-glider@google.com> Subject: [PATCH v3 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.470.g6ba607880d-goog From nobody Sun Oct 5 23:45:01 2025 Received: from mail-ed1-f73.google.com (mail-ed1-f73.google.com [209.85.208.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 86DD82741CE for ; Mon, 28 Jul 2025 15:26:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753716370; cv=none; b=TjLGOo2ICIbIPFOZYD1KpTZ+NmKzkYu//5BcevhCnsZXC8mx88oMYLhzy4jEifnbdzDBHtKnrwKZ4kQKxv2xnRF2K2+1LggEoD+szmB+cL7/AWkjTL3tCnm6VXqfXsxgeXbg1pPgnZQ0+Obxk9ORs1D5vNHnCiYBKfl3mmGPRrc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753716370; c=relaxed/simple; bh=MaLiA46sivEF5ovv9hlz50NlHkSs2YRFbyGnO20cyTI=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=agF0bGgXMNaYAbMuBXphfe/veugO/eWDQkDpbAZHsaC248G5w6PF6PM3yLojFnL7WTG/Gd/u5YNjIJbBCR793L41+x+LX/dEhw0QHdtLAb0LWUszxUCl6eHqRqGq15jruZn87Tvl2fkj6tQowBIhjMoMuEYJN9oVm8ILHo1AVzk= 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=aY0Gmr0Q; arc=none smtp.client-ip=209.85.208.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="aY0Gmr0Q" Received: by mail-ed1-f73.google.com with SMTP id 4fb4d7f45d1cf-615293aeea9so1546621a12.3 for ; Mon, 28 Jul 2025 08:26:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753716367; x=1754321167; 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=x81fL8jUmjkAzRsxHSSAhVNkBiMxf9fqzVJGZhSQsxk=; b=aY0Gmr0QMCWBWoe4chYMFDrzd+2iMt+luiFoZ1biiUWDYkAtRN4qRCRUZtJ6gjXkQj C659wwcmYjB3hxiT60GJv/l/RpZp+VogawmOIFrE90AW/vG1Lxc5GaDDiUiSSAkgyMWW Iy6/byL5mUPmRQpS9KQnifJHqRLZr/Y5ODtNsJjGnUYG8DZL7Lidkut1YQEJ+Koc84N1 KZEGJrO9MXvHZ5nmpkPRxpYyE5BsRV8/CNnu0ZSALrXgZwQ4a6RZL5lR99v50eB6KgCs 9I7P0SF/w5//1i781g11icfhA9CrirdPB7C2PoMGDcmlGn16FwlZVcvjbIwuZt9RTYmz Z6WA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753716367; x=1754321167; 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=x81fL8jUmjkAzRsxHSSAhVNkBiMxf9fqzVJGZhSQsxk=; b=tCNnqukoSKLDvp8sDwkdBqSj+2tfFaLmlHWKw302cHt6NKdCMbwDyLSU/0ZfOQ/EAE vb9W+cumRHQHxY55kP/b9Q8scgkfdIEDm0NEud7dUCN2fVXw90C0MRK/uMuRdtsIdyom wz0GO87KdFWLroA2ClVNDPR81L+t8m6n0ZrcmdJ5i8sFaJIuGYbseqxxo5q2UkLb4d8m 8IKo2p11P0pJzHxn+JAxfhwGkB//3xVGCTL/UTFIM8oVuMmWayw/3XJPWZvFr2xoFY1T UyPjBYh7cDKFr6Cc1PbJfh8PbWrbUgcqa8ST5KVskAhNmsPn5bcuxCAvyZRi3XNT2j4k drRg== X-Forwarded-Encrypted: i=1; AJvYcCUxQHUsuJ3FwR9OzWP7vK/N16xCZAORanhdggBVTxmlalZDTrixmbJ5Q9XOKF4dLb+NXEkfPGcG719EI0Y=@vger.kernel.org X-Gm-Message-State: AOJu0YxVve9/o/D4cNa3wkzNRvIoli5mlsBJh0YPQzT+Ym1L17R0NqVt 53I6YwNrSHksfYzJ63mDG9z5EkVZjW2ruqCytxp79VcrRwmeCbWrVuHBe0utNW1Ok2Bn+DE/gnx ApYLtYw== X-Google-Smtp-Source: AGHT+IFLHmGdalewYQBnVMF3u/DjpqVqoFNJ15U8QZHFyuIahsV/7khrSovKQnnZRcEg8mde3IOLLcPioDU= X-Received: from edbdn24.prod.google.com ([2002:a05:6402:22f8:b0:608:89ec:59b3]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:84c:b0:614:f982:6335 with SMTP id 4fb4d7f45d1cf-614f98266b1mr10815929a12.22.1753716365086; Mon, 28 Jul 2025 08:26:05 -0700 (PDT) Date: Mon, 28 Jul 2025 17:25:41 +0200 In-Reply-To: <20250728152548.3969143-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: <20250728152548.3969143-1-glider@google.com> X-Mailer: git-send-email 2.50.1.470.g6ba607880d-goog Message-ID: <20250728152548.3969143-4-glider@google.com> Subject: [PATCH v3 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, 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" 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 --- 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.470.g6ba607880d-goog From nobody Sun Oct 5 23:45:01 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 6F2AD2741DF for ; Mon, 28 Jul 2025 15:26:09 +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=1753716371; cv=none; b=pSi/GyvzgJLY1MlLNdBP1/maQZstYcoMqrejG5+SRYkRteyVDRaQQX8EWppHZ3svZ/fekVwl5cPnG9EmjjumkrtnvuqUPWPTpVcTXZIlCPUP1wElWjvV2Cvw1Cz0Z0eLZ/22LZL+rBJ9yrh5Yvz3UWPENM/6MLU5VucXX5Y2+Kg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753716371; c=relaxed/simple; bh=MllcQEuHiBTsDJxE3qurrwpUzMzU/Y6EBnsPVAZdFD4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=DUcLQi2hCaH8vNJAdoJ/goz9ReGoUMJa15AQtn2JAov/1RBleldJWBhyH0/bKodkpgUguMc1tTSOcTBSr72p7BqvMt4xyELb/2qtOL7MC2PPBEs+NjbmE44yJnVVeaOblGesmRSrF3ufP5tr1aiH52FN+f79Y6jn6RReiYLy7GA= 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=oaKFz5tV; 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="oaKFz5tV" Received: by mail-wm1-f73.google.com with SMTP id 5b1f17b1804b1-451d3f03b74so22996015e9.3 for ; Mon, 28 Jul 2025 08:26:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753716367; x=1754321167; 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=LxbX5YL9Hd7g/YslttSYNXM3pBZCa2EzwplzrqOsm+s=; b=oaKFz5tVBPhBx4n69yFoR2Fzq+Ae6ikXy9+bw/V3SECM2vQVwgcG5O0j6CNamgdned M1E4c8xpdi3H5OA3E5hPc8DvlSCq0O6PC/BxHaT5O6B+v08TVNRBow45Kcdmtyi5daTa 61xlHem5oo0ZiLyNDuQHXVWjM+1PAoDsujEpAxxoZHNzbcU6O+ZyvsMqqHCSd8XtfPJU ATgGEgZ2x1Kv6kyMTFKTwprmkeRYHkycZ4qI4PmW8el5hVoV3yBhBBaSy8exqcefQwOZ i6EzqaxCgm+ROiOtlX0j+84FUML5vceFMcJyGaQcUFZxi1OSsfZ77biI9KepQ5amBuPz GomQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753716367; x=1754321167; 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=LxbX5YL9Hd7g/YslttSYNXM3pBZCa2EzwplzrqOsm+s=; b=XVogG5eT6udxFysopFcv0ikZtRMfuYcMJbvUVQ5BFyWhcRlPhK6BFrDO9fHqoc5D+x evicDBayWpp7t1zxQ+b18ELluZCUH84i2c5RQ3wf/1M/nTlUp+TZbcQDHXJoKp+DbGq9 8/XkyisjCRogMooRRpjjRpU3Z18/PyCBl/mph5bssw3sCIiL2aPlI99aXEaRfv6Z3d08 U0yIXvb5pNKhvc1B3GP8WAtnHDU+Zy3mHs7TDduNH5ZLAhcEERdE4Qprj9x91hBAUGny KUzjUzwn9JLiF8G3ckcvzMqMrpersZ9ts/owG9HznpjqvGrXPt/ZmCVYv5H2ZLX+nMHx Tsfw== X-Forwarded-Encrypted: i=1; AJvYcCUfOgJ7KOCzWkLDpO70D++dKsJQ8bKR48ZlmyYy0BCK+XRSn4IPcmx/1/rJo5F70etgC8pT0EY44bETtxY=@vger.kernel.org X-Gm-Message-State: AOJu0Yze418fIBVZo6fqmlV0jjb+cmwJDxoN3ICzzYDQr8IiifE+hQnY ELQywwbZXIlHGCCIrOG9pPYmxFYJkPQXBWagfjikVhs29M9ZpVzod8I5iz6j0CJ79v6/GoGvmca BUBaNeA== X-Google-Smtp-Source: AGHT+IG2V0ZWWxxszP1ey1jI3Sk0wfKbI+mMNaZLQ1rs2Nl6fNN8FRwGu+cbt173QwILw+7KVPRP6sUI7BI= X-Received: from wmtf6.prod.google.com ([2002:a05:600c:8b46:b0:456:365f:428b]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:8b6d:b0:456:1514:5b04 with SMTP id 5b1f17b1804b1-4587643aed4mr91132245e9.21.1753716367733; Mon, 28 Jul 2025 08:26:07 -0700 (PDT) Date: Mon, 28 Jul 2025 17:25:42 +0200 In-Reply-To: <20250728152548.3969143-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: <20250728152548.3969143-1-glider@google.com> X-Mailer: git-send-email 2.50.1.470.g6ba607880d-goog Message-ID: <20250728152548.3969143-5-glider@google.com> Subject: [PATCH v3 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 --- 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 --- mm/kasan/generic.c | 18 ++++++++++++++++++ mm/kasan/kasan.h | 2 ++ 2 files changed, 20 insertions(+) diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index d54e89f8c3e76..b0b7781524348 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -238,6 +238,24 @@ 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. + */ +void __asan_before_dynamic_init(const char *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..c817c46b4fcd2 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 char *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.470.g6ba607880d-goog From nobody Sun Oct 5 23:45:01 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 B542427281C for ; Mon, 28 Jul 2025 15:26:11 +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=1753716373; cv=none; b=gA4S+t/iEHEnrosr1rYb1ChhByL0If69BQ+1mi57vWe1NpWdPlqx6zp6dA0DxUbu24xJSnk2x1sJi0ghK8xobV0N+BkH4rNG0r40koI6olo0k9ge87X5pJ3sdBA6sSY/BS8gCckA//jnZZlR31vfpMxjSxfJSn8jCIj7+sU7hg8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753716373; c=relaxed/simple; bh=YSOAtuT/thF1ayPHuMRpF1qsC4ljCMx/1GfBaNJ180U=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=tWOtCcb+zaDkxb3vJ48M9qWIEg12nc96rZbbV7ka7tx2lAkWez1Tumvx1G3y0ZruDzWk2p3Up0SE6sypHZpaMGwCs7Kls9O3ZdiePzA5SA9c+mmM8KxEGjb0l/ZB5IZwFpdxEeMyTnDSZsvhOiC9lx3ntloEoiki19FfqkZO6+0= 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=Syt4227j; 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="Syt4227j" Received: by mail-wm1-f74.google.com with SMTP id 5b1f17b1804b1-4561dfd07bcso23301285e9.1 for ; Mon, 28 Jul 2025 08:26:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753716370; x=1754321170; 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=OKqMQFpHzUCDFRnRabqvw1Gefpd/rsbhAybeGDXo5FM=; b=Syt4227jNbpMIoOa1GH/3pNkvZ8S2CM7a0sLqhtfqFxbzAAuJ4w2MOryERPaq+0nHA iV9uOnxZXxWAWsvMJzwa85W1ll1gJLka4CBU9L9VTCAt3vJAWx1fwhSSn5cNxFsJ5YHy gFh5AxeWfWIkUewhahzgj60ufOY16rHdAwz5no1R432zkbNq74aWFljV7lcIJsKRotJA gspLQTd+lD2o0ndezldiMmsPtFTP/0c65Pa6Lfxv3XgVbrsUDqTsOqC3S+i3bVukBfWs GHzvR+/fv+lHmS7lig7fWwBDFD+TsKYAL6CbBXY2vS4pvEvv+KGUrQIMdYdKPq8YmvrC 67/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753716370; x=1754321170; 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=OKqMQFpHzUCDFRnRabqvw1Gefpd/rsbhAybeGDXo5FM=; b=pAvJEfvvEpRhCkQLHvmMv8dfCrWEEc7Rdq2JGtYDNoq75z32GbmO2/ykkkjGzSpPz8 EODHwY8vm2QZf9Uyt7IigLwj4Iiq9T9PJ3Rv+fttyyo1zU5ltkmxUuVUqiK868Rg1aDw lOGgkMBiMQAAfAhBK6ekr9K4s2icN/vBU2PY1TfS2Glxkyc2tHnuuZnuHFLgL7CObWzd 2+11rd3YXqE6mVVbd1Z457JArzw6ucHbM7QT6m6yjGbJSSEN2E7RAIc5kP3CxebedIz+ 40LmMeOWNr5trlekZOOmO8Sae0iMj9bUJcUkdRQc3/zk1eBnp/elkKTqq51JJdMIA8bO pq9Q== X-Forwarded-Encrypted: i=1; AJvYcCXUURIeYcUpRf7giX1BlcCKasE4Hg2bOeK1WymUt9nawVqFBWR3nJ9XTNqxNAvEldQS4Rvzs8Jt/bDVLOM=@vger.kernel.org X-Gm-Message-State: AOJu0YyNOUjXi3s2KAqMVqTHPHjQQzqsGpzzpEyVA4TR9UTjs8UJxHjt mmo1bCdKdwM5JAg5KzWYi+GSshcWV0ZBSuHm3NHQRxobLpYB2IarQPId8o0pQntfFN0UcQ2ilBZ 33xqUYA== X-Google-Smtp-Source: AGHT+IGAioPglZ7osQQufZb/9tEyIG1NMfgO6mIRNlC3zdzw5786xpBYB8aTLr1ZOKPonUiouNmI4htewu4= X-Received: from wmbei27.prod.google.com ([2002:a05:600c:3f1b:b0:456:1b6f:c878]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:6592:b0:456:76c:84f2 with SMTP id 5b1f17b1804b1-45876e70183mr119044925e9.30.1753716370100; Mon, 28 Jul 2025 08:26:10 -0700 (PDT) Date: Mon, 28 Jul 2025 17:25:43 +0200 In-Reply-To: <20250728152548.3969143-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: <20250728152548.3969143-1-glider@google.com> X-Mailer: git-send-email 2.50.1.470.g6ba607880d-goog Message-ID: <20250728152548.3969143-6-glider@google.com> Subject: [PATCH v3 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, 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" 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 --- 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.470.g6ba607880d-goog From nobody Sun Oct 5 23:45:01 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 2A42C27467B for ; Mon, 28 Jul 2025 15:26:14 +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=1753716376; cv=none; b=MOiIbvz0nyHcXRxsSmcO86ixKQkMPx3NVYf9KCGseya5PZZvs6Zf0zvBMr9ST8Wpfvvsn7+yRQ27HEv8I49IwDzdWSV2OT1ylcYoIQbtjvkBTpdnsjC6GkQv8L2LY8IOk4c+IzEQQHB1wI+TNmdX9iQ9gYs+IcOq35ynTsZFUFk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753716376; c=relaxed/simple; bh=r/tZXEP+8eEdZLTTr+icWX3GRDcf5HowPMVmT2pS6NA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=hfRk6ZFeysV5lV0X7hwNIwnbf0fBVI9suEVuPSjsJZDF+nwh3sQC8w0Gra2ete7jqD28EnecnXlBBl0gwiq+qPr8DzCT505tJFoabqxJfRUsfR3BzbHGtetkSYWaYUtqddSe/XfROuUuSxJsx8vuBJXdqQYBtLCQIe0nwBevuvU= 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=OnptUpVX; 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="OnptUpVX" Received: by mail-wr1-f74.google.com with SMTP id ffacd0b85a97d-3a4f7f1b932so2597763f8f.2 for ; Mon, 28 Jul 2025 08:26:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753716372; x=1754321172; 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=PWggRk8hyLpW4/M6UT4TQt+tg1m7K6txrnQvGMUPVFM=; b=OnptUpVX4VyrrFQ7kFjGwAic2HlmsvaW4oz+0jO3DDaOZALyv83sS5ABpwzHKYWyup K6zLeAoMouIbLbJe/J/+u05RoncOb8J45AwSAhYyZY8FPmlJ6azTOeJFMvVMRT8CLvPv rintW0d0jNT9ldD2l8MOq8pHwwSuXKcZaNagC0GH9F7oUfyjLp7uyZngEX0dzJbeTjIk 2kCido1nd8YOSE5DD0P0jTav7/YO8nURmeEmr6XymAl/ch9ws6dca/2cPS3ltbp2kafi ETnZ778XnNWzYIkSczZ1kqzfqPczvvvgrUudId6F3J18AkgzNJPXdiAXLFfAOWQKZzXD VkgA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753716372; x=1754321172; 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=PWggRk8hyLpW4/M6UT4TQt+tg1m7K6txrnQvGMUPVFM=; b=Xf90pVgYpYYe4BoeIvvYv3VKm8bALfoJyWBGP1OYGHZNopmSpuIMWLh5BpiCeu8691 OobezZz23/85zj7ayA2+S32tELBjXZIrkh0ZIfqEByIRNB13sap8YrkHsV5k2u+eRIFG sOH8ZK3sCe8T5vE5+FOBlbLHcPern7quT0/nA6RrDys76tjRdxydghnk9NaBCwiOtQ90 MdI++Z2HelbWIS7P+VvfVCYO1nAcE95h+KQpRQLrf5mQ82jNDCy0Qf0lBroT7dUJFuvn pBqxNp+UdQCBNPzgxN2F0U77B5MEXIPUTGUoJ+QvwO8UvXHpCMnA70xVbU7UmAcFRm3K osXQ== X-Forwarded-Encrypted: i=1; AJvYcCUTlJZuELaQNmdyN+X7Bo4UwQuHUkCnerBLsB8QTH+2z09nR6Sm1N+HLOfjTGAYwCGjyu1BjNmOeZbW3vU=@vger.kernel.org X-Gm-Message-State: AOJu0Yx9wxseiIeHqpNOtf5LR590tPG+HB0IlAuHKgI3f5J+/TjkpFAV UZaU9G4eGRdeYPRS0RQB/mtfJgPdAXmQycn4tMEcWAXV8VtCftWj8fpJvC4D/a2PcTTeWd7591y H1S3YVQ== X-Google-Smtp-Source: AGHT+IGkE7Uuj1VenFYjF3LuEj8c5sOe2muKlKtZ9FwxWlnSIZKVPmai6ALZHafTifUSOHbrJOaZIExUuiE= X-Received: from wrod15.prod.google.com ([2002:adf:ef8f:0:b0:3b7:7e20:4466]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:adf:a11c:0:b0:3b7:76e8:b9f7 with SMTP id ffacd0b85a97d-3b776e8bcb3mr7141293f8f.10.1753716372699; Mon, 28 Jul 2025 08:26:12 -0700 (PDT) Date: Mon, 28 Jul 2025 17:25:44 +0200 In-Reply-To: <20250728152548.3969143-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: <20250728152548.3969143-1-glider@google.com> X-Mailer: git-send-email 2.50.1.470.g6ba607880d-goog Message-ID: <20250728152548.3969143-7-glider@google.com> Subject: [PATCH v3 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, 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" 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 --- 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.470.g6ba607880d-goog From nobody Sun Oct 5 23:45:01 2025 Received: from mail-ej1-f73.google.com (mail-ej1-f73.google.com [209.85.218.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 0527E274B42 for ; Mon, 28 Jul 2025 15:26:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753716379; cv=none; b=VsmtVSjglizxk+GW5RBy1W5OyarRGvevA+dlmS+5Yio7+OyurK/DxWMNVEamJ/q3su/jMaiJbxdq3X4dBAPV2pqzYc3kwO+NMUQIfjAk407ptxAE4V25MJyQWEp7uE4FmcePCjMVY7ycWm3Gmekb5nH4UHo1jNqVYs1xrcUH0Eg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753716379; c=relaxed/simple; bh=3b9Y0aaO/Wh/wrBm87/5EmphlezqUYvYps0/u9myhAY=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=m4NoDILbRpUPt+My1Scnl5xMLpqSPwehq5Qr/YlgKiDVi996Fso0H3YQ72zw21z5t2WGWtbul8y0OrQqV+5XT98x7hYO4U4Jwyy9MUQ6UzKp8NueVsgILxP3mdHp3cbPqQt0vabYItq5tvbYbJEqbOW/tP5FEza+gVdcqJUg+Ps= 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=VgPb88XK; arc=none smtp.client-ip=209.85.218.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="VgPb88XK" Received: by mail-ej1-f73.google.com with SMTP id a640c23a62f3a-ade5b98537dso492531266b.2 for ; Mon, 28 Jul 2025 08:26:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753716375; x=1754321175; 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=CU5RXN+7NuwbklsjRQ1PV1YDDJdsiMox+OyYa2UMKaQ=; b=VgPb88XKcH6NROz/Iw591L72DA9uPArV8y06Y/8fq45MkgJBAjC3hJxHmnNEtmWjoJ SwOcEDT5Kp8Qs6RyJ9rqvU6MEHPjCjYbyNL7sb+z9uN2ZeQh7pzd3eYj+jjHY7XgTfMR lRSC6n/N7iZHIh7pzYM//y/pa0itdREHvvhZ+rv7J5O6mz/GTuNTVCKiCCW/Yhq7bVzp MV2K548NtZs9ZrIMf1+JYuo7XWUvkuV9PCGWi4Wz/FriXeKGVrH79LsHVN39WrFrOjzo 8xzjrluewI4WkiNHDvi8OVq36ylOFZn9APrieeNtE8ohwIpCC+LIpHwBeDrMtOImogg3 hICA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753716375; x=1754321175; 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=CU5RXN+7NuwbklsjRQ1PV1YDDJdsiMox+OyYa2UMKaQ=; b=JhLq9UWrfO+VhTNLSphZqpp14VQO8ACHWpPXRJVfd83Gx1sQGPl/ASWq1dKmvbsX7Z 3Oe1ltgPImiwna992RB9hYUYKF+aAL6Fs9+lOc06CRPHYMXMyYDqPxwSeTwsJCC/sBaw oBrmBZOZU4PlsNxKrt+yzUu5eyTkmH1CrKTBAqnl4ozIIEDG/mgw0c4QTkoit/RtlFFN sWjUik+g8QH6wbHLXRCSmghvcnw/wtNX0qZQo4BXuVeBJOpTErQzpGPtKZCgNHBgNfTz LCJSHbYU4wRiC3vpBJ7O8HPVS44ZTSjTG28k48YmDuCHs7TS4xfz1OVRdptyITnSeIy5 cUfA== X-Forwarded-Encrypted: i=1; AJvYcCX9qSt1Z+r0lc3oxKNl3Cm9If2msR3XrSKlzLRORzwkVvFgfEXa+DvYVCZWBV/YzQIwKObWXH4cbsfIrGM=@vger.kernel.org X-Gm-Message-State: AOJu0YyAkA+WSesSoMZpyIEWna4tpQJIczLyXMP+IcmDaWG8WrUpEFtn xJN7eF7Z2Yka2h1xvDdPeTY9AN4ki8MdNeLAwW1x0CdpSKhq2kSTLGzV1kuepUXA4fxbT+PpuRf KFt3zXA== X-Google-Smtp-Source: AGHT+IEHV49EfH/lu/WNh5052loChk8CyHdLMnQl1qck8Tv2E6cZj6i5E+s28Hcd8gkUyV2XiXYLua3DkoU= X-Received: from ejckt23.prod.google.com ([2002:a17:907:9d17:b0:ae9:204c:581]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a17:906:f5a3:b0:ade:42a7:dad2 with SMTP id a640c23a62f3a-af618bd84c0mr1381216166b.33.1753716375187; Mon, 28 Jul 2025 08:26:15 -0700 (PDT) Date: Mon, 28 Jul 2025 17:25:45 +0200 In-Reply-To: <20250728152548.3969143-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: <20250728152548.3969143-1-glider@google.com> X-Mailer: git-send-email 2.50.1.470.g6ba607880d-goog Message-ID: <20250728152548.3969143-8-glider@google.com> Subject: [PATCH v3 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, 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" 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 --- 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.470.g6ba607880d-goog From nobody Sun Oct 5 23:45:01 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 9B89C27281C for ; Mon, 28 Jul 2025 15:26:19 +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=1753716381; cv=none; b=qCJKZeOkqoL7VgKRKsSYq7U64ZM1gJpvVpzf90szQbR4a2ztmwNluwlX6KLezPi8g02WKqR3RIDwhBPjXbd9MNuEmj/UrMRb9keOkQlOb5e+l2bPa263g97Pbrf4mQb/xmwQaIXISrIpmNm2JamdOhTYJbcVrL5af8aQlXDc0l4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753716381; c=relaxed/simple; bh=XPi5UctYPQ6iqqxChHrb+I2GOcd/h2cPlC/uujMzXF4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=s1s7zZv8h80hQa/dMedl6DSIJhr9d01IBNdKQO/IKqRM1QpBf+UUUj6lFcQ+hot6hgd37nCMKs37NLliqg4ApA0ERJt9CC6hlV8V/Q9Tx5jyi4w6Wz5e3aMC/+RVrmqdTZgDMB5IpIYHiNGIiNSo70XaR0R/qFuEoobQQVf1FBM= 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=NbbOjAEP; 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="NbbOjAEP" Received: by mail-wr1-f74.google.com with SMTP id ffacd0b85a97d-3b780da0ab6so1100997f8f.0 for ; Mon, 28 Jul 2025 08:26:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753716378; x=1754321178; 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=uFjnsgZ8ZjgFIrgBqo3fRpKhi5jRt02tyhhsiWaGr2M=; b=NbbOjAEPeEI6Rp6i5Mb2FOLLykoJD9mMPEgrg4SdKtE0Wgyiz8PPC0cjDB1tpdLcbb jMqfgg9zH0GMrr3CSQMI1LdmqsrvG2D2cfRn9Nt0/I0S3gDAlqHa59Eppz5meI2zq6kQ 1jjmDbIi0PeSlhx4K+aEhbaB3MEO77qS815mZwGsGkhFVJlv2zHAPVcT9q3h+PfHjGXM FM5gmoBYtOkuKvb9qqJTphzHb+CAAgcLaQb4ls5D1JFXTgnyuhKSVzS1ggAB0g596cVp SrSUMMFzdBAZGTC9bl1otDLMYdUqXl/FChaTGYGdEmv1kdmFU4H+VUY4YQc0fzzz/Pdm tg4A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753716378; x=1754321178; 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=uFjnsgZ8ZjgFIrgBqo3fRpKhi5jRt02tyhhsiWaGr2M=; b=vq+GHeOrEHrOZiNpRmNdh8AiURl0P8t0PSK6FoHXLsAN2NH0MFsp16gJxSlw5/8Cw/ Wd4B4koiyHrEQVP/R+wAMulxdNGm8TaQeUpMJgu8Piz6Y6t66uus/SCyU/PohJ9yT5RT w6ioDoEcCerEfoYJuV8bC9JU8k2JmMTCDHSB4ID9N4F2ILblc4P4UL6RXUm3n/rZ5Mai +KKCCp1mNLfvrC9TQrrgR1nt88EFy/PmlUXwNPADksio1kij6XEfLnPAJ4ALlDJR6Vy4 kKg0jeseQrUaZnzH1t1oFOS8dYSeahqMjDcXbNJ2S7GvOwd7lVjMjyd6fKqyBIGPn3LE oG7w== X-Forwarded-Encrypted: i=1; AJvYcCUYxh3uMhXulknrPPM9fELU85S4itWcAf5Pm14+Ur1khAmAw28aOlLmeoILdszVyYivL7JZiYXp+OWbS58=@vger.kernel.org X-Gm-Message-State: AOJu0Yxpe4lQs4UBtND9cWUOWw13Rmy/tWtWxAsmOJxThaw2xzZdC8G8 E7bOlqewq1EHIagHOopuhB7LKJ2P6mh+Q1epnfPVGJkDf+9phvzMrHdbVtvjlDOnHf6sAlprmy5 bgANqxA== X-Google-Smtp-Source: AGHT+IGq4PQHv8VDaJwxvJyLtWnkDr4Bb+g+30J9ik9jr47G58ggPtO0o8e9h7qgGXHBI52CNU+CGkItrv4= X-Received: from wrbfk2.prod.google.com ([2002:a05:6000:2702:b0:3b7:844b:17ae]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:2083:b0:3b7:662a:b835 with SMTP id ffacd0b85a97d-3b77671d144mr8757417f8f.6.1753716377790; Mon, 28 Jul 2025 08:26:17 -0700 (PDT) Date: Mon, 28 Jul 2025 17:25:46 +0200 In-Reply-To: <20250728152548.3969143-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: <20250728152548.3969143-1-glider@google.com> X-Mailer: git-send-email 2.50.1.470.g6ba607880d-goog Message-ID: <20250728152548.3969143-9-glider@google.com> Subject: [PATCH v3 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, 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" 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 --- 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.470.g6ba607880d-goog From nobody Sun Oct 5 23:45:01 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 F3C10275110 for ; Mon, 28 Jul 2025 15:26:21 +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=1753716384; cv=none; b=RMy6s/aA/rjabNIKzS9flO2HcCBoPQuspof5JXI4DEOl5xp92FlE1uYwCubpxYMbcdgENd4wbIwuwMr0K1qjvlyRXMFsEhZSvGF/Dcxo6CG7XWiVRhDgri9N2VTdCOhH0VkMnftGqOvSz9Z0zZfU1DGAnLXjAZ+3FIIJUDkS3WE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753716384; c=relaxed/simple; bh=oHEHQI2Km0t4tE8MDoNKRGZsz2Pa0IaBV64EzSKIXhE=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=sjwTadBwieAYzW5zHIUUoUQK/zMNBVi9wa+P73odwbfpJok22crH2mJLrRKHlfkFH/UjjWTewWRJ6g/8l3lY7uuTfs9TjS+f/Qzbl42s6vZ+G4PBjJdKBrnnrUrKMdVyDuFQOoLiioyGBrj5GRj5dcXrDF0QCQkuHa0o5KrQ1E4= 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=atRBkrGG; 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="atRBkrGG" Received: by mail-wr1-f74.google.com with SMTP id ffacd0b85a97d-3b7886bfc16so708491f8f.1 for ; Mon, 28 Jul 2025 08:26:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753716380; x=1754321180; 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=RM3rYcVJaPkMmvCtgqhtUuIHqeUyU5KTFhX1F5xwLi8=; b=atRBkrGGNaZTXsWeZ3QxmIxv6eKypIScn4CIAvBl0akBlX3oeFZOnsoUTZr1yKUIIu k0FOe2m427KuLMLtkyInnPLMilcbu1dBlX/fEpM64bgR/93r7Au6nkfgcZfm576S0WVs e+qp0E1o8Sv0l0fBdojuWnP84n0QLmhUiY3USdHwY9Qv/6xWLhFf/rzAFSXafdR9Do91 WAKzAonzRM9La1e+MidGq+eGB/tM4Qe316Gi5/0rxAH1Gk77cOG3qyHSSMRMpuQ8VAeH 6Xl2sp1iyUtWalqbNaSAZF5tPqXUUnjOOP2yMJWGrOIIvfc/I6iKmXt/G6pqnYEtS0g/ uh+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753716380; x=1754321180; 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=RM3rYcVJaPkMmvCtgqhtUuIHqeUyU5KTFhX1F5xwLi8=; b=PNfYr59zmfPvcMT59LdEeWe8BT5mjWWswtEjK1hCWRU5ki7VLqxnbM+FXGOKRQQS10 HYIR0Q1SXMARR28Sp5VfkoI1hXeqyrF6r1iMa6ZPjc0u9SWUYSVowGm55fzkAAnLcgbl kjCeK/yDTXM89Oc6mw3ZSH1Sxvt/e6Yf3rR8Pwyv+tNqYPtrHzRjhKfX9cvdjkK79Muh o7I/ynji2LDHGL5prKBtlqHCgEVJr+ie+HQzp9eCdask11t6rckb7715zo8oktxuKYf1 kPAR/uJ9pNYt024EBEImF+WG2crbMpFKkzHRWhZfgK7NJvezuqnP01eT6B32SvlfEOpp Frbw== X-Forwarded-Encrypted: i=1; AJvYcCWXGM4GG/rLSl0KKEl9epnTXbW+395rh1OgqdJ691JACPg9od4GBwFO5ivET5KCA0V8ffgd5/Fg97Cg9MM=@vger.kernel.org X-Gm-Message-State: AOJu0YwRlMipr66vdDy/D7wywS3mRuj0EfsKEseWwcG9JATMvh8SiKRK HHEoOhN8Dismn/MXLSdCWNNfVudmMOsm0BYNTH698PZKhsx7dsUWocC48jFuKxY22XVj/bDQI6A gEwnxvg== X-Google-Smtp-Source: AGHT+IHUCNbr51JQqwUCi3muVJ1RbQXkO5iU5ZjMpw/FpHYsNBwRad9q0Gv6T6yMJ8thDgb01Sr1heviZRA= X-Received: from wrf6-n1.prod.google.com ([2002:a05:6000:43c6:10b0:3b7:887e:816]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:2582:b0:3b7:868d:435e with SMTP id ffacd0b85a97d-3b7868d4705mr3391930f8f.41.1753716380342; Mon, 28 Jul 2025 08:26:20 -0700 (PDT) Date: Mon, 28 Jul 2025 17:25:47 +0200 In-Reply-To: <20250728152548.3969143-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: <20250728152548.3969143-1-glider@google.com> X-Mailer: git-send-email 2.50.1.470.g6ba607880d-goog Message-ID: <20250728152548.3969143-10-glider@google.com> Subject: [PATCH v3 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 --- 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 | 1 + tools/testing/selftests/kcov/kcov_test.c | 401 +++++++++++++++++++++++ 4 files changed, 409 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..75726b2aa9979 --- /dev/null +++ b/tools/testing/selftests/kcov/config @@ -0,0 +1 @@ +CONFIG_KCOV=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.470.g6ba607880d-goog From nobody Sun Oct 5 23:45:01 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 A37B327586E for ; Mon, 28 Jul 2025 15:26:24 +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=1753716386; cv=none; b=olajJWwPA6VEiITM8tywu6+Io78rkY64bsFU5dEgzyM+wS218+KOeG/+KDXYXvjob0zuOhog8wPjVc8WjlnxPcB/hA06FvkSB4gqv64G6SNY47ahh1tKoDnSLXoU0ZPVNwPgw+trUxIiPUS51Tut60xKOV4Wb4j+k3aOLWDyFCs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753716386; c=relaxed/simple; bh=gcFdg60wQIJoUwDRf0ghpUkI0GsFS2FwORXI/aIkLP4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=m98NVsyMgP8TdGELRqx2J+yS8EgVf1FuTji0KtJm8d3waDSU3N2Bi/ImQDFFPspOk4LJ3LlFE21SuvZMAWC5BPEA5c9ZLxUe0+T/WGd9MPRa8rbx2V+DBqgAMeheQ8mxkwygl0O5L781LIs8sOC9AI1vR0br7+87KL0g+QsjhIs= 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=CtbHK615; 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="CtbHK615" Received: by mail-wr1-f73.google.com with SMTP id ffacd0b85a97d-3b7865dc367so905519f8f.2 for ; Mon, 28 Jul 2025 08:26:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753716383; x=1754321183; 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=hykQKzruNCv5r2lQ9UgjaMRVHwcJ9+lJEhAaVBLVSIs=; b=CtbHK615St/W1JOJpINMPK80a6JABoYa21wx933OQyxh5Zj6w+m93LADxlW+aR14OD WFoj/oTHTj7pPW/Xbw2ETrR4HsN5kbMxEfHI/etAu1SI+jdNtNrwAZ+mi7ynUoVH57Nk Y8I0Dar+z7wrieYU/ev6nq2Qq8PcpQOApGuYUfPMgTq2p5dWYoeu7i0V8v5QQRMDHbap 6GGuNi+5zVPKhyYY4A7Sbd5bT6GNFsvL0GQDR2lhnVZJSGiiq8TTa11XpjG8JOEyl8KT 4apiJqkVzVtztClB+8OCt6bdmIhWSLLxcXrhinmjYvoaF5+Hw/9tBSm0hSVR/9ACFEc4 ZCuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753716383; x=1754321183; 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=hykQKzruNCv5r2lQ9UgjaMRVHwcJ9+lJEhAaVBLVSIs=; b=mau6kpx8WpYq7eBiuToyLbpjt1Y7G4w+b86qxPO04dKQGQAL83Nzk8p5ff3m27BCXq cPM9zAxpoGr94J0mgNCV5HnArZiep5n6slPT/5olJXi2Y5a7nJJPAgzi3Wqy73sqjclQ 1A749Ql4Yboo01hCjjJkO27hYnyKxobeLHeGgtuQNA5J2NbawDcc5ywBxoiZflSsLVRl EcITEcalQLA+2njj4unGn5FJl/0STUpbPSpB3liUzNAy1Nr63A4AVJNfDP6g2uf531pm JkQrClHPo9JQPZl+kdlvwQZt2thRFW7/fkbeauyAoZA2Kh3mwJLQLGyDfH01xi5zOWHq fOzw== X-Forwarded-Encrypted: i=1; AJvYcCVrcBF2H3NfuiQdJa2+Ut3BzhrvPM2AQJBziGB3sAgtSmRUhRjwKSifhvI/KdNqajTaWBhscX0j8T+4XGM=@vger.kernel.org X-Gm-Message-State: AOJu0YwPKJEw/u+RYoIFobpOInqjO1lVpQ1H3NxjMn2XHariKLYL4tfA WfP/EpslmAv4QzCFbAu7Y1OEu4QJQT1aPLbtUJG4ojjGsiTOOBacba3mlus2GsQA1wLONGk90DW zWMhw0A== X-Google-Smtp-Source: AGHT+IHQIsWJFSACJdbsfEOnTkjKDpo0gsN3yoE4tAbV8g2x7pI85GfO9OZIH4sQMnQLtn9vJ1p105jcddA= X-Received: from wrmc6.prod.google.com ([2002:adf:e706:0:b0:3b7:828a:15fa]) (user=glider job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:3110:b0:3a4:d4cd:b06 with SMTP id ffacd0b85a97d-3b776776423mr8151840f8f.34.1753716382935; Mon, 28 Jul 2025 08:26:22 -0700 (PDT) Date: Mon, 28 Jul 2025 17:25:48 +0200 In-Reply-To: <20250728152548.3969143-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: <20250728152548.3969143-1-glider@google.com> X-Mailer: git-send-email 2.50.1.470.g6ba607880d-goog Message-ID: <20250728152548.3969143-11-glider@google.com> Subject: [PATCH v3 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, 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" 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 --- 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.470.g6ba607880d-goog