Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
1e0587e
Add simple configuration for kftf module that is built with kernel
Jun 18, 2025
43dc893
kftf: Add init and exit functions to module
Jun 18, 2025
42d6acc
kftf: simple sysfs that accepts a struct for a single function and the
Jun 18, 2025
4a35a64
kftf: allow tests with macro definitions in .kftf section of binary.
Jun 20, 2025
e8992cb
kftf: fixx sizeof check so that it checks against the provided type.
Jun 23, 2025
d7adb90
kftf: add metadata file per fuzzed function - this contains the name of
Jun 23, 2025
ca5ba48
move int_sqrt test out of kftf_tests file and into the math source
Jun 23, 2025
96ae8d5
kftf: address PR comments and make the FUZZ_TEST interface a lot more
Jun 23, 2025
ece3042
kftf: update include block so that the relative include (kftf_tests.h)
Jun 23, 2025
07bfafa
delete unused file kftf_simple_fuzzer
Jun 23, 2025
0c5cd7e
kftf: per test-case input buffer with mutex
Jun 23, 2025
a4bb002
kftf: update kftf_fuzzable test
Jun 23, 2025
0bddc3f
kftf: add some comments to module main file and kftf header file
Jun 25, 2025
5971467
kftf: replace static test cases buffer with kmalloc'd one.
Jun 25, 2025
d799f5c
kftf: replace input buffers for callback with dynamically allocated
Jul 1, 2025
aae72ff
kftf: replace heap allocated input buffer with function-local stack
Jul 1, 2025
72e3dec
kftf: fix bug in input reading logic.
Jul 1, 2025
6673d6f
kftf: work in progress on domain constraints. Need to see about exposing
Jul 3, 2025
95a0a01
kftf: allow for range constraints by expanding constraint struct.
Jul 6, 2025
581f240
kftf: move some stuff around and enforce 64 byte alignment of KFuzzTest
Jul 6, 2025
a83dee7
kftf: add annotations macros to express field types (for example
Jul 8, 2025
8e1f787
kfuzztest: add array annotation
Jul 18, 2025
c74d33a
kftf: remove int_sqrt test which is no longer really needed, added
Jul 9, 2025
6b03486
kftf: remove some prints from write_input_callback, update test case to
Jul 11, 2025
ba24eb3
kftf: introduce new buffer for payload that provides alignment
Jul 14, 2025
799cdcd
kftf: harden binary input parsing
Jul 15, 2025
51cadf2
kfuzztest: update naming from "kftf" to "kfuzztest"
Jul 25, 2025
e328953
kfuzztest: cleanup code and update documentation
Jul 25, 2025
8cb9faa
kfuzztest: remove dummy test file
Jul 25, 2025
aeeb29f
kfuzztest: update header comment in kfuzztest_main.c
Jul 25, 2025
57fddce
kfuzztest: update macros to fix naming
Jul 25, 2025
4ebed5f
kfuzztest: align targets to 32-byte boundary
Jul 25, 2025
fd61eeb
linux/kfuzztest: update serialization format for KFuzzTest inputs
Aug 1, 2025
c14dbe8
kfuzztest: reduce sizes of fields to 32-bit to reduce wastage
Aug 4, 2025
e763e70
kfuzztest: refactor code, introduce distinct and poisoned modes.
Aug 4, 2025
76c3b85
kfuzztest: extract relocations logic into separate .c file.
Aug 5, 2025
f0bd54a
kfuzztest: refactoring functions into separate .c files, modify kasan
Aug 5, 2025
624a566
kfuzztest: add toy example
Aug 5, 2025
0ccd3a3
kfuzztest: backup before only supporting poisoned mode
Aug 5, 2025
614ce92
kfuzztest: relocate in poison mode - the new only mode
Aug 5, 2025
62053d4
kfuzztest: update poisoning to use kasan_poison_last_granule
Aug 5, 2025
5116dcc
kfuzztest: cleanups WIP
Aug 6, 2025
83dfd18
kfuzztest: remove unnecessary padding from kfuzztest.h structs
Aug 6, 2025
60f56f6
kfuzztest: add SPDX headers to all new files
Aug 6, 2025
3e9815e
kfuzztest: add help section to KConfig.kfuzztest
Aug 6, 2025
cc985fe
kfuzztest: update comments and one code block refactored
Aug 6, 2025
4ad76d0
kfuzztest: move examples to .c file
Aug 6, 2025
14f3851
kfuzztest: wrap KFUZZTEST_TABLE def in an ifdef block
Aug 6, 2025
bd5d833
kfuzztest: start documentation
Aug 6, 2025
f39fd77
kfuzztest: add Google copyright notice, remove ifdefs in .c file
Aug 7, 2025
af9d76f
kfuzztest: fix parsing logic that didn't account for padding
Aug 7, 2025
1a286cb
kfuzztest: update examples file
Aug 7, 2025
b25969f
kfuzztest: update state name from st to state
Aug 7, 2025
3f96f02
kfuzztest: remove extraneous braces, prints, and add a check in poison
Aug 7, 2025
1cba6b1
kfuzztest: add a debug helper function
Aug 7, 2025
c85f16b
kfuzztest: poison region preceding payload to catch underflows
Aug 7, 2025
4820368
kfuzztest: update overflow example, add underflow example
Aug 7, 2025
366d8bb
kfuzztest: define macros for granule size and slab redzone
Aug 7, 2025
1f0ea22
kfuzztest: fix example so that it actually overflows
Aug 7, 2025
7b6ff73
kfuzztest: add stricter input parsing and validation, fix nits
Aug 7, 2025
f1cd01f
kfuzztest: more validation.
Aug 7, 2025
be3ba18
kfuzztest: assume at 8 bytes of padding before payload
Aug 7, 2025
eab275f
kfuzztest: add GE and LT domain constraints for completeness
Aug 7, 2025
c223a37
kfuzztest: remove __kfuzztest_write_cb_common as we no longer need it.
Aug 8, 2025
55f9fe6
kfuzztest: documentation updates
Aug 8, 2025
5ba009f
kfuzztest: updates doc comments for consistency
Aug 8, 2025
c22f0fc
kfuzztest: update allocation / error handling for debufs_state
Aug 8, 2025
1eee647
kfuzztest: file header comments
Aug 8, 2025
fd8b6ec
kfuzztest: update some kasan poison logic and comments
Aug 8, 2025
f7ee465
kfuzztest: update test case comments
Aug 8, 2025
5411510
kfuzztest: remove no longer needed CONFIG_KASAN check
Aug 8, 2025
7ed2876
kfuzztest: update KConfig dependencies and help description
Aug 8, 2025
496ceef
kfuzztest: move period out of a quoted region
Aug 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 181 additions & 0 deletions Documentation/dev-tools/kfuzztest.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
.. SPDX-License-Identifier: GPL-2.0
.. Copyright 2025 Google LLC

Kernel Fuzz Testing Framework (KFuzzTest)
=========================================

Overview
--------

The Kernel Fuzz Testing Framework (KFuzzTest) is a framework designed to expose
internal kernel functions to a userspace fuzzing engine.

It is intended for testing stateless or low-state functions that are difficult
to reach from the system call interface, such as routines involved in file
format parsing or complex data transformations. This provides a method for
in-situ fuzzing of kernel code without requiring that it be built as a separate
userspace library or that its dependencies be stubbed out.

The framework consists of four main components:

1. An API, based on the ``FUZZ_TEST`` macro, for defining test targets
directly in the kernel tree.
2. A binary serialization format for passing complex, pointer-rich data
structures from userspace to the kernel.
3. A ``debugfs`` interface through which a userspace fuzzer submits
serialized test inputs.
4. Metadata embedded in dedicated ELF sections of the ``vmlinux`` binary to
allow for the discovery of available fuzz targets by external tooling.

Supported Architectures
-----------------------

KFuzzTest is currently only supported for x86_64.

Usage
-----

To enable KFuzzTest, configure the kernel with::

CONFIG_KFUZZTEST=y

which depends on ``CONFIG_DEBUGFS`` for receiving userspace inputs.

Declaring a KFuzzTest target
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

A fuzz target is defined directly in a .c file, typically alongside the function
being tested. This process involves three main parts: defining an input
structure, writing the test body using the ``FUZZ_TEST`` macro, and optionally
adding metadata for the fuzzer.

The following example illustrates how to create a fuzz target for a function
``int process_data(const char *data, size_t len)``.

.. code-block:: c

// 1. Define a struct to model the inputs for the function under test.
// Each field corresponds to an argument needed by the function.
struct process_data_inputs {
const char *data;
size_t len;
};

// 2. Define the fuzz target using the FUZZ_TEST macro.
// The first parameter is a unique name for the target.
// The second parameter is the input struct defined above.
FUZZ_TEST(test_process_data, struct process_data_inputs)
{
// Within this body, the 'arg' variable is a pointer to a
// fully initialized 'struct process_data_inputs'.

// 3. (Optional) Add constraints to define preconditions.
// This check ensures 'arg->data' is not NULL. If the condition
// is not met, the test exits early. This also creates metadata
// to inform the fuzzer.
KFUZZTEST_EXPECT_NOT_NULL(process_data_inputs, data);

// 4. (Optional) Add annotations to provide semantic hints.
// This annotation informs the fuzzer that the 'len' field
// is the length of the buffer pointed to by 'data'.
// Annotations do not add any runtime checks.
KFUZZTEST_ANNOTATE_LEN(process_data_inputs, len, data);

// 5. Call the kernel function with the provided inputs.
// Memory errors like out-of-bounds accesses on 'arg->data' will
// be detected by KASAN or other memory error detection tools.
process_data(arg->data, arg->len);
}

KFuzzTest provides two families of macros to improve the quality of fuzzing:

- ``KFUZZTEST_EXPECT_*``: These macros define constraints, which are
preconditions that must be true for the test to proceed. They are enforced
with a runtime check in the kernel. If a check fails, the current test run is
aborted. This metadata helps the userspace fuzzer avoid generating invalid
inputs.

- ``KFUZZTEST_ANNOTATE_*``: These macros define annotations, which are purely
semantic hints for the fuzzer. They do not add any runtime checks and exist
only to help the fuzzer generate more intelligent and structurally correct
inputs. For example, KFUZZTEST_ANNOTATE_LEN links a size field to a pointer
field, which is a common pattern in C APIs.

Input Format
------------

KFuzzTest targets receive their inputs from userspace via a write to a dedicated
debugfs ``/sys/kernel/debug/kfuzztest/<test-name>/input``.

The data written to this file must be a single binary blob that follows a
specific serialization format. This format is designed to allow complex,
pointer-rich C structures to be represented in a flat buffer, requiring only a
single kernel allocation and copy from userspace.

The format consists of three main parts laid out sequentially: a region array,
a relocation table, and the payload.::

+----------------+---------------------+-----------+----------------+
| region array | relocation table | padding | payload |
+----------------+---------------------+-----------+----------------+

Region Array
~~~~~~~~~~~~

This component is a header that describes how the raw data in the Payload is
partitioned into logical memory regions. It consists of a count of regions
followed by an array of ``struct reloc_region``, where each entry defines a
single region with its size and offset from the start of the payload.

.. code-block:: c

struct reloc_region {
uint32_t offset;
uint32_t size;
};

struct reloc_region_array {
uint32_t num_regions;
struct reloc_region regions[];
};

By convention, region 0 represents the top-level input struct that is passed
as the arg variable to the FUZZ_TEST body. Subsequent regions typically
represent data buffers pointed to by fields within that struct. Region array
entries must be ordered by offset ascending, and must not overlap with one
another.

Relocation Table
~~~~~~~~~~~~~~~~

The relocation table provides the instructions for the kernel to "hydrate" the
payload by patching pointer fields. It contains an array of
``struct reloc_entry`` items. Each entry acts as a linking instruction,
specifying:

- The location of a pointer that needs to be patched (identified by a region
ID and an offset within that region).

- The target region that the pointer should point to (identified by the
target's region ID) or ``KFUZZTEST_REGIONID_NULL`` if the pointer is ``NULL``.

This table also specifies the amount of padding between its end and the start
of the payload, which should be at least 8 bytes.

Payload
~~~~~~~

The payload contains the raw binary data for all regions, concatenated together
according to their specified offsets.

- Alignment: The start of the payload must be aligned to the most restrictive
alignment requirement of all its constituent regions. The framework ensures
that each region within the payload is then placed at an offset that respects
its own type's alignment.

- Padding and Poisoning: The space between the end of one region's data and the
beginning of the next must be sufficient for padding. In KASAN builds,
KFuzzTest poisons this unused padding, allowing for precise detection of
out-of-bounds memory accesses between adjacent buffers. This padding should
be at least ``KFUZZTEST_POISON_SIZE`` bytes as defined in
`include/linux/kfuzztest.h``.
22 changes: 22 additions & 0 deletions arch/x86/kernel/vmlinux.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,26 @@ ASSERT(__relocate_kernel_end - __relocate_kernel_start <= KEXEC_CONTROL_CODE_MAX
#else
#define KEXEC_RELOCATE_KERNEL
#endif

#ifdef CONFIG_KFUZZTEST
#define KFUZZTEST_TABLE \
. = ALIGN(PAGE_SIZE); \
__kfuzztest_targets_start = .; \
KEEP(*(.kfuzztest_target)); \
__kfuzztest_targets_end = .; \
. = ALIGN(PAGE_SIZE); \
__kfuzztest_constraints_start = .; \
KEEP(*(.kfuzztest_constraint)); \
__kfuzztest_constraints_end = .; \
. = ALIGN(PAGE_SIZE); \
__kfuzztest_annotations_start = .; \
KEEP(*(.kfuzztest_annotation)); \
__kfuzztest_annotations_end = .;

#else /* CONFIG_KFUZZTEST */
#define KFUZZTEST_TABLE
#endif /* CONFIG_KFUZZTEST */

PHDRS {
text PT_LOAD FLAGS(5); /* R_E */
data PT_LOAD FLAGS(6); /* RW_ */
Expand Down Expand Up @@ -199,6 +219,8 @@ SECTIONS
CONSTRUCTORS
KEXEC_RELOCATE_KERNEL

KFUZZTEST_TABLE

/* rarely changed data like cpu maps */
READ_MOSTLY_DATA(INTERNODE_CACHE_BYTES)

Expand Down
23 changes: 23 additions & 0 deletions include/linux/kasan.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,29 @@ static __always_inline bool kasan_unpoison_pages(struct page *page,
return false;
}

#ifdef CONFIG_KASAN_GENERIC

/**
* kasan_poison_last_granule - mark the last granule of the memory range as
* inaccessible
* @address: range start address, must be aligned to KASAN_GRANULE_SIZE
* @size: range size
*
* This function is only available for the generic mode, as it's the only mode
* that has partially poisoned memory granules.
*/
void kasan_poison_last_granule(const void *address, size_t size);

#else /* CONFIG_KASAN_GENERIC */

static inline void kasan_poison_last_granule(const void *address, size_t size)
{
}

#endif /* CONFIG_KASAN_GENERIC */

void kasan_poison(const void *addr, size_t size, u8 value, bool init);

void __kasan_poison_slab(struct slab *slab);
static __always_inline void kasan_poison_slab(struct slab *slab)
{
Expand Down
Loading