xref: /freebsd/share/man/man9/kmsan.9 (revision a8089ea5aee578e08acab2438e82fc9a9ae50ed8)
1.\"-
2.\" Copyright (c) 2021 The FreeBSD Foundation
3.\"
4.\" This documentation was written by Mark Johnston under sponsorship from
5.\" the FreeBSD Foundation.
6.\"
7.\" Redistribution and use in source and binary forms, with or without
8.\" modification, are permitted provided that the following conditions
9.\" are met:
10.\" 1. Redistributions of source code must retain the above copyright
11.\"    notice, this list of conditions and the following disclaimer.
12.\" 2. Redistributions in binary form must reproduce the above copyright
13.\"    notice, this list of conditions and the following disclaimer in the
14.\"    documentation and/or other materials provided with the distribution.
15.\"
16.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26.\" SUCH DAMAGE.
27.\"
28.Dd January 11, 2024
29.Dt KMSAN 9
30.Os
31.Sh NAME
32.Nm KMSAN
33.Nd Kernel Memory SANitizer
34.Sh SYNOPSIS
35The
36.Pa GENERIC-KMSAN
37kernel configuration can be used to compile a KMSAN-enabled kernel using
38.Pa GENERIC
39as a base configuration.
40Alternately, to compile KMSAN into the kernel, place the following line in your
41kernel configuration file:
42.Bd -ragged -offset indent
43.Cd "options KMSAN"
44.Ed
45.Pp
46.In sys/msan.h
47.Ft void
48.Fn kmsan_mark "const void *addr" "size_t size" "uint8_t code"
49.Ft void
50.Fn kmsan_orig "const void *addr" "size_t size" "int type" "uintptr_t pc"
51.Ft void
52.Fn kmsan_check "const void *addr" "size_t size" "const char *descr"
53.Ft void
54.Fn kmsan_check_bio "const struct bio *" "const char *descr"
55.Ft void
56.Fn kmsan_check_ccb "const union ccb *" "const char *descr"
57.Ft void
58.Fn kmsan_check_mbuf "const struct mbuf *" "const char *descr"
59.Ft void
60.Fn kmsan_check_uio "const struct uio *" "const char *descr"
61.Sh DESCRIPTION
62.Nm
63is a subsystem which leverages compiler instrumentation to detect uses of
64uninitialized memory in the kernel.
65Currently it is implemented only on the amd64 and arm64 platforms.
66.Pp
67When
68.Nm
69is compiled into the kernel, the compiler is configured to emit function
70calls preceding memory accesses.
71The functions are implemented by the
72.Nm
73runtime component and use hidden, byte-granular shadow state to determine
74whether the source operand has been initialized.
75When uninitialized memory is used as a source operand in certain operations,
76such as control flow expressions or memory accesses, the runtime reports
77an error.
78Otherwise, the shadow state is propagated to destination operand.
79For example, a
80variable assignment or a
81.Fn memcpy
82call which copies uninitialized memory will cause the destination buffer or
83variable to be marked uninitialized.
84.Pp
85To report an error, the
86.Nm
87runtime will either trigger a kernel panic or print a message to the console,
88depending on the value of the
89.Sy debug.kmsan.panic_on_violation
90sysctl.
91In both cases, a stack trace and information about the origin of the
92uninitialized memory is included.
93.Pp
94In addition to compiler-detected uses of uninitialized memory,
95various kernel I/O
96.Dq exit points ,
97such as
98.Xr copyout 9 ,
99perform validation of the input's shadow state and will raise an error if
100any uninitialized bytes are detected.
101.Pp
102The
103.Nm
104option imposes a significant performance penalty.
105Kernel code typically runs two or three times slower, and each byte mapped in
106the kernel map requires two bytes of shadow state.
107As a result,
108.Nm
109should be used only for kernel testing and development.
110It is not recommended to enable
111.Nm
112in systems with less than 8GB of physical RAM.
113.Pp
114The sanitizer in a KMSAN-configured kernel can be disabled by setting the loader
115tunable
116.Sy debug.kmsan.disable=1 .
117.Sh FUNCTIONS
118The
119.Fn kmsan_mark
120and
121.Fn kmsan_orig
122functions update
123.Nm
124shadow state.
125.Fn kmsan_mark
126marks an address range as valid or invalid according to the value of the
127.Va code
128parameter.
129The valid values for this parameter are
130.Dv KMSAN_STATE_INITED
131and
132.Dv KMSAN_STATE_UNINIT ,
133which mark the range as initialized and uninitialized, respectively.
134For example, when a piece of memory is freed to a kernel allocator, it will
135typically have been marked initialized; before the memory is reused for a new
136allocation, the allocator should mark it as uninitialized.
137As another example, writes to host memory performed by devices, e.g., via DMA,
138are not intercepted by the sanitizer; to avoid false positives, drivers should
139mark device-written memory as initialized.
140For many drivers this is handled internally by the
141.Xr busdma 9
142subsystem.
143.Pp
144The
145.Fn kmsan_orig
146function updates
147.Dq origin
148shadow state.
149In particular, it associates a given uninitialized buffer with a memory type
150and code address.
151This is used by the
152.Nm
153runtime to track the source of uninitialized memory and is only for debugging
154purposes.
155See
156.Sx IMPLEMENTATION NOTES
157for more details.
158.Pp
159The
160.Fn kmsan_check
161function and its sub-typed siblings validate the shadow state of the region(s)
162of kernel memory passed as input parameters.
163If any byte of the input is marked as uninitialized, the runtime will generate
164a report.
165These functions are useful during debugging, as they can be strategically
166inserted into code paths to narrow down the source of uninitialized memory.
167They are also used to perform validation in various kernel I/O paths, helping
168ensure that, for example, packets transmitted over a network do not contain
169uninitialized kernel memory.
170.Fn kmsan_check
171and related functions also take a
172.Fa descr
173parameter which is inserted into any reports raised by the check.
174.Sh IMPLEMENTATION NOTES
175.Ss Shadow Maps
176The
177.Nm
178runtime makes use of two shadows of the kernel map.
179Each address in the kernel map has a linear mapping to addresses in the
180two shadows.
181The first, simply called the shadow map, tracks the state of the corresponding
182kernel memory.
183A non-zero byte in the shadow map indicates that the corresponding byte of
184kernel memory is uninitialized.
185The
186.Nm
187instrumentation automatically propagates shadow state as the contents of kernel
188memory are transformed and copied.
189.Pp
190The second shadow is called the origin map, and exists only to help debug
191reports from the sanitizer.
192To avoid false positives,
193.Nm
194does not raise reports for certain operations on uninitialized memory, such
195as copying or arithmetic.
196Thus, operations on uninitialized state which raise a report may be far removed
197from the source of the bug, complicating debugging.
198The origin map contains information which can help pinpoint the root cause of
199a particular
200.Nm
201report; when generating a report, the runtime uses state from the origin map
202to provide extra details.
203.Pp
204Unlike the shadow map, the origin map is not byte-granular, but consists of 4-byte
205.Dq cells .
206Each cell describes the corresponding four bytes of mapped kernel memory and
207holds a type and compressed code address.
208When kernel memory is allocated for some purpose, its origin is initialized
209either by the compiler instrumentation or by runtime hooks in the allocator.
210The type indicates the specific allocator, e.g.,
211.Xr uma 9 ,
212and the address provides the location in the kernel code where the memory was
213allocated.
214.Ss Assembly Code
215When
216.Nm
217is configured, the compiler will only emit instrumentation for C code.
218Files containing assembly code are left un-instrumented.
219In some cases this is handled by the sanitizer runtime, which defines
220wrappers for subroutines implemented in assembly.
221These wrappers are referred to as interceptors and handle updating
222shadow state to reflect the operations performed by the original
223subroutines.
224In other cases, C code which calls assembly code or is called from
225assembly code may need to use
226.Fn kmsan_mark
227to manually update shadow state.
228This is typically only necessary in machine-dependent code.
229.Pp
230Inline assembly is instrumented by the compiler to update shadow state
231based on the output operands of the code, and thus does not usually
232require any special handling to avoid false positives.
233.Ss Interrupts and Exceptions
234In addition to the shadow maps, the sanitizer requires some thread-local
235storage (TLS) to track initialization and origin state for function
236parameters and return values.
237The sanitizer instrumentation will automatically fetch, update and
238verify this state.
239In particular, this storage block has a layout defined by the sanitizer
240ABI.
241.Pp
242Most kernel code runs in a context where interrupts or exceptions may
243redirect the CPU to begin execution of unrelated code.
244To ensure that thread-local sanitizer state remains consistent, the
245runtime maintains a stack of TLS blocks for each thread.
246When machine-dependent interrupt and exception handlers begin execution,
247they push a new entry onto the stack before calling into any C code, and
248pop the stack before resuming execution of the interrupted code.
249These operations are performed by the
250.Fn kmsan_intr_enter
251and
252.Fn kmsan_intr_leave
253functions in the sanitizer runtime.
254.Sh EXAMPLES
255The following contrived example demonstrates some of the types of bugs
256that are automatically detected by
257.Nm :
258.Bd -literal -offset indent
259int
260f(size_t osz)
261{
262	struct {
263		uint32_t bar;
264		uint16_t baz;
265		/* A 2-byte hole is here. */
266	} foo;
267	char *buf;
268	size_t sz;
269	int error;
270
271	/*
272	 * This will raise a report since "sz" is uninitialized
273	 * here.  If it is initialized, and "osz" was left uninitialized
274	 * by the caller, a report would also be raised.
275	 */
276	if (sz < osz)
277		return (1);
278
279	buf = malloc(32, M_TEMP, M_WAITOK);
280
281	/*
282	 * This will raise a report since "buf" has not been
283	 * initialized and contains whatever data is left over from the
284	 * previous use of that memory.
285	 */
286	for (i = 0; i < 32; i++)
287		if (buf[i] != '\0')
288			foo.bar++;
289	foo.baz = 0;
290
291	/*
292	 * This will raise a report since the pad bytes in "foo" have
293	 * not been initialized, e.g., by memset(), and this call will
294	 * thus copy uninitialized kernel stack memory into userspace.
295	 */
296	copyout(&foo, uaddr, sizeof(foo));
297
298	/*
299	 * This line itself will not raise a report, but may trigger
300	 * a report in the caller depending on how the return value is
301	 * used.
302	 */
303	return (error);
304}
305.Ed
306.Sh SEE ALSO
307.Xr build 7 ,
308.Xr busdma 9 ,
309.Xr copyout 9 ,
310.Xr KASAN 9 ,
311.Xr uio 9 ,
312.Xr uma 9
313.Rs
314.%A Evgeniy Stepanov
315.%A Konstantin Serebryany
316.%T MemorySanitizer: fast detector of uninitialized memory use in C++
317.%J 2015 IEEE/ACM International Symposium on Code Generation and Optimization (CGO)
318.%D 2015
319.Re
320.Sh HISTORY
321.Nm
322was ported from
323.Nx
324and first appeared in
325.Fx 14.0 .
326.Sh BUGS
327Accesses to kernel memory outside of the kernel map are ignored by the
328.Nm
329runtime.
330In particular, memory accesses via the direct map are not validated.
331When memory is copied from outside the kernel map into the kernel map,
332that region of the kernel map is marked as initialized.
333When
334.Nm
335is configured, kernel memory allocators are configured to use the kernel map,
336and filesystems are configured to always map data buffers into the kernel map,
337so usage of the direct map is minimized.
338However, some uses of the direct map remain.
339This is a conservative policy which aims to avoid false positives, but it will
340mask bug in some kernel subsystems.
341.Pp
342On amd64, global variables and the physical page array
343.Va vm_page_array
344are not sanitized.
345This is intentional, as it reduces memory usage by avoiding creating
346shadows of large regions of the kernel map.
347However, this can allow bugs to go undetected by
348.Nm .
349.Pp
350Some kernel memory allocators provide type-stable objects, and code which uses
351them frequently depends on object data being preserved across allocations.
352Such allocations cannot be sanitized by
353.Nm .
354However, in some cases it may be possible to use
355.Fn kmsan_mark
356to manually annotate fields which are known to contain invalid data upon
357allocation.
358