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 December 6, 2023 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 platform. 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