From nobody Sun Dec 14 21:52:57 2025 Received: from mail-wr1-f47.google.com (mail-wr1-f47.google.com [209.85.221.47]) (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 7BEAC341ACB for ; Thu, 4 Dec 2025 14:13:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764857591; cv=none; b=G27CWmcbQnbR41mS3d5vBdXd1UXR4Gtje/oi/HDem+bvFwlbYK+mBhIwR3CslQ5DwsLsNil15eFZXsAyOGk5CbKCQZrhL6x3thfEhklYlAO99MKNeFdHV/IfCEZdJjOSthGxYUGU35/GQWrmjnbDHdeP538YfaQN0DfpCQX0Xfk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764857591; c=relaxed/simple; bh=gGOyyVjVMhMF3sDm6WRBw0+IQtrWF8GPAGIMRplta2c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=vFcI059wuj1B/MMyh/JLqero4rF7oNlhUu2PsEUwGby+fIYztHeaK6ApZdJRqn1oCJ9WIRqyN0d8cudATqSnxbT4c3ruptXmt16AcShrGCEjCwM1nnhRPltqNCbCw2IqOdZPE3uzROstlLvcDlLX/AvyegkxHMaJccVSJP+th00= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=DnNEoFkd; arc=none smtp.client-ip=209.85.221.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="DnNEoFkd" Received: by mail-wr1-f47.google.com with SMTP id ffacd0b85a97d-42b32ff5d10so1398679f8f.1 for ; Thu, 04 Dec 2025 06:13:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1764857587; x=1765462387; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=isyNyNcz2cmNMZXUIhi196/Z7TRsBZBkmSpv3VPEYmw=; b=DnNEoFkdX816PUig11YRbjWEMG+GnW0Id+UzFswX/dQVsxjcLb2oj1hi/gyoo6CFIe Sxcwpsu8r42jbEcaw2ZXmcNjhoT4aXlQ9xrtRyYPdieL8c0lKStznZPmFfZPkKR/h2jX E4qEJDayNpRExtVEHItSRQ3ft9evBrb1Kx1Dx8T8gY0ApX0Pp38eTu4KifrEtF+12N5F FAsjtMGbE42JIJJimCh8DBA7mjDVjUBn/SJV1NkTWSkg19JzvZWFIfZH9k5UaaU1U95W qDy+lc5BiS1dPjwnFlr/FHFm8DmdhETuC+FfoiZxO3gLjWfzuLn0mtuL3l0dFpCbCarS kwTw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764857587; x=1765462387; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=isyNyNcz2cmNMZXUIhi196/Z7TRsBZBkmSpv3VPEYmw=; b=bBVq/WlQ4fpGuXZx6zaHu4eFVdIbPhS7ekk09YJVePKhaRzb9fAhBSWyaa0hYtl6jF FAlPPN0gGj2sOqNlhQ+TgEXpuhN1dnF59VqKtp+1kwOqslF/cQwEIzX5miIsFzDU9+zy QuIrOkH8Y1oGBjx1a6uAmPes6131zKeJvxZQzdBnD4hYAVbQPLWNUenFeiwWBUkDsjkx 1dVfqTxwMBGIUkw1MHt5d3uByqX1f1JknYr5nM4sstStQTwyqz4uUpoX63cuo+qkwYhA lzZ3QEkqo0HlBfs8FFnUlSe2EyiWdkt73RsM29Xa7KCmoPNRTEViniRRtmPRBzRiar75 vODQ== X-Forwarded-Encrypted: i=1; AJvYcCW8AcnXkgP/E8MRKxgJ+Mj77eKxEeQ5Cx9zzVPCQ5Ud+wZm6HqSO9/VBGFiD6XTPW8r77MoYBh7nmeXlz0=@vger.kernel.org X-Gm-Message-State: AOJu0YwkfF5OvLZSW+0HaXm6x8bwhCyWlSPAYOh/+DQpi9fnxTV99M7I dqHCieejdzhfMvidAJbLDl4Xbw6XmUs9wIvL6Jn6QX63CE+RBlvyKe12 X-Gm-Gg: ASbGncvpfEf29k5lvM3Ao7pUBpkYIyEeODVmOcuTdnEKnFkr7fjFXXzwCchZJsydkma UxuC+LwqYxErTvOqLiEoHDgpKZDuzgepUbEnKq17bDl2tzYp1aFAmReTkZIZT6pwkOtTs5kMvcn 81hpXlSQCme3yowsJKx7sA7SBnZZSXgVTuwuKsv/eYxp1hQQIPo3W59NqByv6ndikEh3vMRkJcD NxKjCDDGKutHu9yvxJSxE9ZphlEZPK4QE50iB6lajEYtrhbOrs+/1+tVUlN6ngM3qUjXueC3bMC URkw2SuMpRVpp+hYsLS9Rc5QvbwM7cLHn1GJpSKJ8DuI3QleeCr/2OHUz6L+C/A+zbWhfDRTcsT XeMaJnYFWnsERS5o1Hj1Kvvnl2hFjJ7/YaPe70wv/0B0HYUrrpbboaIBHOrm9qbsGGO8xre4kv8 26aya5xQYJkqwzjWLbfev7mj9tiU8y+JjEgZ9baA1vrcxUWsmfQTu+G4721DgEN/yQZg== X-Google-Smtp-Source: AGHT+IHzNmWdyGZHlpy0d/ld4zER7YnP7X7/VxSK89F6ur9TtLx9dRwcFdqJB8Vqqm6xuvTuLO1sQw== X-Received: by 2002:a05:6000:290c:b0:42b:3661:304e with SMTP id ffacd0b85a97d-42f78874e61mr3830533f8f.16.1764857586521; Thu, 04 Dec 2025 06:13:06 -0800 (PST) Received: from ethan-tp.d.ethz.ch (2001-67c-10ec-5744-8000--626.net6.ethz.ch. [2001:67c:10ec:5744:8000::626]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-42f7cbfeae9sm3605808f8f.13.2025.12.04.06.13.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Dec 2025 06:13:06 -0800 (PST) From: Ethan Graham To: ethan.w.s.graham@gmail.com, glider@google.com Cc: andreyknvl@gmail.com, andy@kernel.org, andy.shevchenko@gmail.com, brauner@kernel.org, brendan.higgins@linux.dev, davem@davemloft.net, davidgow@google.com, dhowells@redhat.com, dvyukov@google.com, elver@google.com, herbert@gondor.apana.org.au, ignat@cloudflare.com, jack@suse.cz, jannh@google.com, johannes@sipsolutions.net, kasan-dev@googlegroups.com, kees@kernel.org, kunit-dev@googlegroups.com, linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, lukas@wunner.de, rmoar@google.com, shuah@kernel.org, sj@kernel.org, tarasmadan@google.com Subject: [PATCH 03/10] kfuzztest: introduce the FUZZ_TEST_SIMPLE macro Date: Thu, 4 Dec 2025 15:12:42 +0100 Message-ID: <20251204141250.21114-4-ethan.w.s.graham@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20251204141250.21114-1-ethan.w.s.graham@gmail.com> References: <20251204141250.21114-1-ethan.w.s.graham@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The serialization format required by a KFuzzTest target defined with the FUZZ_TEST macro is overkill for simpler cases, in particular the very common pattern of kernel interfaces taking a (data, datalen) pair. Introduce the FUZZ_TEST_SIMPLE for defining simple targets that accept a simpler binary interface without any required serialization. The aim is to make simple targets compatible with a wide variety of userspace fuzzing engines out of the box. A FUZZ_TEST_SIMPLE target also defines an equivalent FUZZ_TEST macro in its expansion maintaining compatibility with the default KFuzzTest interface, using a shared `struct kfuzztest_simple_arg` as input type. In essence, the following equivalence holds: FUZZ_TEST_SIMPLE(test) =3D=3D=3D FUZZ_TEST(test, struct kfuzztest_simple_ar= g) Constraints and annotation metadata for `struct kfuzztest_simple_arg` is defined statically in the header file to avoid duplicate definitions in the compiled vmlinux image. Signed-off-by: Ethan Graham --- include/asm-generic/vmlinux.lds.h | 4 ++ include/linux/kfuzztest.h | 87 +++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinu= x.lds.h index 9afe569d013b..2736dd41fba0 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -974,6 +974,10 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPEL= LER_CLANG) KEEP(*(.kfuzztest_target)); \ __kfuzztest_targets_end =3D .; \ . =3D ALIGN(PAGE_SIZE); \ + __kfuzztest_simple_targets_start =3D .; \ + KEEP(*(.kfuzztest_simple_target)); \ + __kfuzztest_simple_targets_end =3D .; \ + . =3D ALIGN(PAGE_SIZE); \ __kfuzztest_constraints_start =3D .; \ KEEP(*(.kfuzztest_constraint)); \ __kfuzztest_constraints_end =3D .; \ diff --git a/include/linux/kfuzztest.h b/include/linux/kfuzztest.h index 1839fcfeabf5..284142fa4300 100644 --- a/include/linux/kfuzztest.h +++ b/include/linux/kfuzztest.h @@ -483,4 +483,91 @@ fail_early: \ } \ static void kfuzztest_logic_##test_name(test_arg_type *arg) =20 +struct kfuzztest_simple_target { + const char *name; + ssize_t (*write_input_cb)(struct file *filp, const char __user *buf, size= _t len, loff_t *off); +} __aligned(32); + +struct kfuzztest_simple_arg { + char *data; + size_t datalen; +}; + +/* Define constraint and annotation metadata for reused kfuzztest_simple_a= rg. */ +__KFUZZTEST_CONSTRAINT(kfuzztest_simple_arg, data, NULL, 0x0, EXPECT_NE); +__KFUZZTEST_ANNOTATE(kfuzztest_simple_arg, data, NULL, ATTRIBUTE_ARRAY); +__KFUZZTEST_ANNOTATE(kfuzztest_simple_arg, datalen, data, ATTRIBUTE_LEN); + +/** + * FUZZ_TEST_SIMPLE - defines a simple KFuzzTest target + * + * @test_name: the unique identifier for the fuzz test, which is used to n= ame + * the debugfs entry. + * + * This macro function nearly identically to the standard FUZZ_TEST target= , the + * key difference being that a simple fuzz target is constrained to inputs= of + * the form `(char *data, size_t datalen)` - a common pattern in kernel AP= Is. + * + * The FUZZ_TEST_SIMPLE macro expands to define an equivalent FUZZ_TEST, + * effectively creating two debugfs input files for the fuzz target. In es= sence, + * on top of creating an input file under kfuzztest/@test_name/input, a new + * simple input file is created under kfuzztest/@test_name/input_simple. T= his + * debugfs file takes raw byte buffers as input and doesn't require any sp= ecial + * serialization. + * + * User-provided Logic: + * The developer must provide the body of the fuzz test logic within the c= urly + * braces following the macro invocation. Within this scope, the framework + * provides the `data` and `datalen` variables, where `datalen =3D=3D len(= data)`. + * + * Example Usage: + * + * // 1. The kernel function that we wnat to fuzz. + * int process_data(const char *data, size_t datalen); + * + * // 2. Define a fuzz target using the FUZZ_TEST_SIMPLE macro. + * FUZZ_TEST_SIMPLE(test_process_data) + * { + * // Call the function under test using the `data` and `datalen` + * // variables. + * process_data(data, datalen); + * } + * + */ +#define FUZZ_TEST_SIMPLE(test_name) \ + static ssize_t kfuzztest_simple_write_cb_##test_name(struct file *filp, c= onst char __user *buf, size_t len, \ + loff_t *off); \ + static void kfuzztest_simple_logic_##test_name(char *data, size_t datalen= ); \ + static const struct kfuzztest_simple_target __fuzz_test_simple__##test_na= me __section( \ + ".kfuzztest_simple_target") __used =3D { \ + .name =3D #test_name, \ + .write_input_cb =3D kfuzztest_simple_write_cb_##test_name, \ + }; \ + FUZZ_TEST(test_name, struct kfuzztest_simple_arg) \ + { \ + /* We don't use the KFUZZTEST_EXPECT macro to define the + * non-null constraint on `arg->data` as we only want metadata + * to be emitted once, so we enforce it here manually. */ \ + if (arg->data =3D=3D NULL) \ + return; \ + kfuzztest_simple_logic_##test_name(arg->data, arg->datalen); \ + } \ + static ssize_t kfuzztest_simple_write_cb_##test_name(struct file *filp, c= onst char __user *buf, size_t len, \ + loff_t *off) \ + { \ + void *buffer; \ + int ret; \ + \ + ret =3D kfuzztest_write_cb_common(filp, buf, len, off, &buffer); \ + if (ret < 0) \ + goto out; \ + kfuzztest_simple_logic_##test_name(buffer, len); \ + record_invocation(); \ + ret =3D len; \ + kfree(buffer); \ +out: \ + return ret; \ + } \ + static void kfuzztest_simple_logic_##test_name(char *data, size_t datalen) + #endif /* KFUZZTEST_H */ --=20 2.51.0