code sanitizer
{{Short description|Tool to detect memory-related bugs}}
{{refimprove|date=July 2014}}
A code sanitizer is a programming tool that detects bugs in the form of undefined or suspicious behavior by a compiler inserting instrumentation code at runtime. The class of tools was first introduced by Google's AddressSanitizer (or ASan) of 2012, which uses directly mapped shadow memory to detect memory corruption such as buffer overflows or accesses to a dangling pointer (use-after-free).
AddressSanitizer
Google's ASan, introduced in 2012, uses a shadow memory scheme to detect memory bugs. It is available in:
- Clang (starting from version 3.1{{cite web |url=http://llvm.org/releases/3.1/docs/ReleaseNotes.html#whatsnew |title=LLVM 3.1 Release Notes |publisher=LLVM |accessdate=8 February 2014}})
- GCC (starting from version 4.8{{cite web |url=https://gcc.gnu.org/gcc-4.8/changes.html |title=GCC 4.8 Release Notes |publisher=GCC |accessdate=8 February 2014}})
- Xcode (starting from version 7.0{{cite web | url=https://developer.apple.com/documentation/code_diagnostics/address_sanitizer | title=Address Sanitizer | Apple Developer Documentation}})
- MSVC (widely available starting from version 16.9{{cite web | url=https://docs.microsoft.com/en-us/visualstudio/releases/2019/release-notes#16.9.0 | title=Visual Studio 2019 version 16.9 Release Notes |publisher=Microsoft |accessdate=5 March 2021}}).
On average, the instrumentation increases processing time by about 73% and memory usage by 240%.{{cite web | title = AddressSanitizer: a fast address sanity checker |author1=Konstantin Serebryany |author2=Derek Bruening |author3=Alexander Potapenko |author4=Dmitry Vyukov | work = Proceedings of the 2012 USENIX conference on Annual Technical Conference | url = https://www.usenix.org/system/files/conference/atc12/atc12-final39.pdf }} There is a hardware-accelerated ASan called HWAsan available for AArch64 and (in a limited fashion) x86_64.{{cite web |title=Hardware-assisted AddressSanitizer Design Documentation — Clang 17.0.0git documentation |url=https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html |website=clang.llvm.org}}
AddressSanitizer does not detect any uninitialized memory reads (but this is detected by MemorySanitizer{{cite web|url=https://github.com/google/sanitizers/wiki/MemorySanitizer|title=MemorySanitizer|website=GitHub }}), and only detects some use-after-return bugs.{{cite web |url=https://github.com/google/sanitizers/wiki/AddressSanitizerComparisonOfMemoryTools |title=ComparisonOfMemoryTools |publisher=AddressSanitizer Wiki|accessdate=1 December 2017}} It is also not capable of detecting all arbitrary memory corruption bugs, nor all arbitrary write bugs due to integer underflow/overflows (when the integer with undefined behavior is used to calculate memory address offsets). Adjacent buffers in structs and classes are not protected from overflow, in part to prevent breaking backwards compatibility.{{cite web |url=http://dl.packetstormsecurity.net/papers/general/BreakingAddressSanitizer.pdf |title=Bypassing AddressSanitizer|publisher=Eric Wimberley|accessdate=1 July 2014}}
= {{Anchor|KASAN}}KernelAddressSanitizer =
The KernelAddressSanitizer (KASan) detects dynamic memory errors in the Linux kernel.{{cite web | title = KernelAddressSanitizer (KASAN) | author = | url = http://lxr.free-electrons.com/source/Documentation/kasan.txt | archive-url = https://web.archive.org/web/20150915180313/http://lxr.free-electrons.com/source/Documentation/kasan.txt | archive-date = 2015-09-15}} Kernel instrumentation requires a special feature in the compiler supplying the -fsanitize=kernel-address command line option, since kernels do not use the same address space as normal programs.{{cite web | title = The kernel address sanitizer | author = Jake Edge| url = https://lwn.net/Articles/612153/ }}{{cite web | title = 3.20 merge window part 2 | author = Jonathan Corbet | url = https://lwn.net/Articles/633096/ }}
KASan is also available for use with Windows kernel drivers beginning in Windows 11 22H2 and above.{{cite web | title = Kernel Address Sanitizer (KASAN) | author = | url = https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/kasan | archive-url = https://web.archive.org/web/20241104171917/https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/kasan | archive-date = 2024-11-04}} Similarly to Linux, compiling a Windows driver with KASAN requires passing the /fsanitize=kernel-address command line option to the MSVC compiler.
Other sanitizers
Google also produced LeakSanitizer (LSan, memory leaks), ThreadSanitizer (TSan, data races and deadlocks), MemorySanitizer (MSan, uninitialized memory), and UndefinedBehaviorSanitizer (UBSan, undefined behaviors, with fine-grained control).{{cite web |last1=Google |title=sanitizers: This project is the home for Sanitizers: AddressSanitizer, MemorySanitizer, ThreadSanitizer, LeakSanitizer, and more. |url=https://github.com/google/sanitizers |website=GitHub |publisher=Google |date=2 March 2023}} These tools are generally available in Clang/LLVM and GCC.{{cite web |title=sanitizer - The Rust Unstable Book |url=https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html |website=doc.rust-lang.org |quote=This feature allows for use of one of following sanitizers: [...] ControlFlowIntegrity LLVM Control Flow Integrity}}{{cite web |title=Clang Compiler User's Manual — Clang 17.0.0git documentation |url=https://clang.llvm.org/docs/UsersManual.html#cmdoption-f-no-sanitize |website=clang.llvm.org |quote=-f[no-]sanitize=check1,check2,... Turn on runtime checks for various forms of undefined or suspicious behavior}}{{cite web |title=Instrumentation Options (Using the GNU Compiler Collection (GCC)) |url=https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html |website=gcc.gnu.org}} Similar to KASan, there are kernel-specific versions of LSan, MSan, TSan, as well as completely original kernel sanitizers such as KFENCE and KCSan.{{cite web |title=Linux Kernel Sanitizers |url=https://github.com/google/kernel-sanitizers |publisher=Google |date=2 March 2023}}
Additional sanitizer tools (grouped by compilers under {{tt|-fsanitize}} or a similar flag) include:
- LLVM control-flow integrity and its kernel counterpart, which checks virtual tables and type casts for forward-edge CFI
- MemTagSanitizer, an ASan-like tool that uses Armv8.5-A features for very low overhead
- ShadowCallStack, an AArch64 tool that provides a shadow stack protection
- Scudo Hardened Allocator, an alternative memory allocator that includes GWP-ASan, a probabilistic ASan analogue with low overhead{{cite web |title=GWP-ASan — LLVM 17.0.0git documentation |url=https://llvm.org/docs/GwpAsan.html |website=llvm.org}}
- libFuzzer, an LLVM tool that adds code coverage to fuzzing{{cite web |title=libFuzzer – a library for coverage-guided fuzz testing. — LLVM 17.0.0git documentation |url=https://llvm.org/docs/LibFuzzer.html?highlight=fsanitize |website=llvm.org}}
Usage
A code sanitizer detects suspicious behavior as the program runs. One common way to use a sanitizer is to combine it with fuzzing, which generates inputs likely to trigger bugs.
Users
{{missing information|section|2=the other San's; Google keeps score for [https://github.com/google/sanitizers/wiki/MemorySanitizerFoundBugs MSan] and [https://github.com/google/sanitizers/wiki/ThreadSanitizerFoundBugs TSan]. Nongnu search for [http://savannah.nongnu.org/search/?type_of_search=bugs&words=Sanitizer Sanitizer] turns up leaks found by LSan in nano, man, etc|date=March 2023}}
Chromium and Firefox developers are active users of AddressSanitizer;{{cite web | title = Fuzzing for Security |author1=Abhishek Arya |author2=Cris Neckar |author3=Chrome Security Team | url =https://blog.chromium.org/2012/04/fuzzing-for-security.html }}{{cite web | title = Securing Firefox: Trying new code analysis techniques | url = https://blog.mozilla.org/decoder/2012/01/27/trying-new-code-analysis-techniques/#more-14 | access-date = 2018-06-18 | archive-url = https://web.archive.org/web/20160307095743/https://blog.mozilla.org/decoder/2012/01/27/trying-new-code-analysis-techniques/#more-14 | archive-date = 2016-03-07 | url-status = dead }} the tool has found hundreds of bugs in these web browsers.{{cite web | title = Some of the bugs found by AddressSanitizer | website =GitHub | url =https://github.com/google/sanitizers/wiki/AddressSanitizerFoundBugs }} A number of bugs were found in FFmpeg{{cite news | title = FFmpeg and a thousand fixes |author1=Mateusz Jurczyk |author2=Gynvael Coldwind |newspaper=J00Ru-Vx Tech Blog | url =http://j00ru.vexillium.org/?p=2211 |date=2014-01-10 }} and FreeType.{{cite web | title = Search results for AddressSanitizer in FreeType Bugs
| url =http://savannah.nongnu.org/search/?words=AddressSanitizer&type_of_search=bugs&Search=Search&exact=1#options }} The Linux kernel has enabled the AddressSanitizer for the x86-64 architecture as of Linux version 4.0.
Examples
= ASan: Heap-use-after-free =
// To compile: g++ -O -g -fsanitize=address heap-use-after-free.cc
int main(int argc, char **argv) {
int *array = new int[100];
delete [] array;
return array[argc]; // BOOM
}
$ ./a.out
==5587==ERROR: AddressSanitizer: heap-use-after-free on address 0x61400000fe44 at pc 0x47b55f bp 0x7ffc36b28200 sp 0x7ffc36b281f8
READ of size 4 at 0x61400000fe44 thread T0
#0 0x47b55e in main /home/test/example_UseAfterFree.cc:5
#1 0x7f15cfe71b14 in __libc_start_main (/lib64/libc.so.6+0x21b14)
#2 0x47b44c in _start (/root/a.out+0x47b44c)
0x61400000fe44 is located 4 bytes inside of 400-byte region [0x61400000fe40,0x61400000ffd0)
freed by thread T0 here:
#0 0x465da9 in operator delete[](void*) (/root/a.out+0x465da9)
#1 0x47b529 in main /home/test/example_UseAfterFree.cc:4
previously allocated by thread T0 here:
#0 0x465aa9 in operator new[](unsigned long) (/root/a.out+0x465aa9)
#1 0x47b51e in main /home/test/example_UseAfterFree.cc:3
SUMMARY: AddressSanitizer: heap-use-after-free /home/test/example_UseAfterFree.cc:5 main
Shadow bytes around the buggy address:
[...]
0x0c287fff9fb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c287fff9fc0: fa fa fa fa fa fa fa fa[fd]fd fd fd fd fd fd fd
0x0c287fff9fd0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
[...]
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
ASan internal: fe
==5587==ABORTING
= ASan: Heap-buffer-overflow =
// RUN: clang++ -O -g -fsanitize=address heap-buf-of.cc && ./a.out
int main(int argc, char **argv) {
int *array = new int[100];
array[0] = 0;
int res = array[argc + 100]; // BOOM
delete [] array;
return res;
}
==25372==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61400000ffd4 at pc 0x0000004ddb59 bp 0x7fffea6005a0 sp 0x7fffea600598
READ of size 4 at 0x61400000ffd4 thread T0
#0 0x46bfee in main /tmp/main.cpp:4:13
0x61400000ffd4 is located 4 bytes to the right of 400-byte region [0x61400000fe40,0x61400000ffd0)
allocated by thread T0 here:
#0 0x4536e1 in operator delete[](void*)
#1 0x46bfb9 in main /tmp/main.cpp:2:16
= ASan: Stack-buffer-overflow =
// RUN: clang -O -g -fsanitize=address stack-buf-of.cc && ./a.out
int main(int argc, char **argv) {
int stack_array[100];
stack_array[1] = 0;
return stack_array[argc + 100]; // BOOM
}
==7405==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff64740634 at pc 0x46c103 bp 0x7fff64740470 sp 0x7fff64740468
READ of size 4 at 0x7fff64740634 thread T0
#0 0x46c102 in main /tmp/example_StackOutOfBounds.cc:5
Address 0x7fff64740634 is located in stack of thread T0 at offset 436 in frame
#0 0x46bfaf in main /tmp/example_StackOutOfBounds.cc:2
This frame has 1 object(s):
[32, 432) 'stack_array' <== Memory access at offset 436 overflows this variable
= ASan: Global-buffer-overflow =
// RUN: clang -O -g -fsanitize=address global-buf-of.cc && ./a.out
int global_array[100] = {-1};
int main(int argc, char **argv) {
return global_array[argc + 100]; // BOOM
}
==7455==ERROR: AddressSanitizer: global-buffer-overflow on address 0x000000689b54 at pc 0x46bfd8 bp 0x7fff515e5ba0 sp 0x7fff515e5b98
READ of size 4 at 0x000000689b54 thread T0
#0 0x46bfd7 in main /tmp/example_GlobalOutOfBounds.cc:4
0x000000689b54 is located 4 bytes to the right of
global variable 'global_array' from 'example_GlobalOutOfBounds.cc' (0x6899c0) of size 400
= UBSan: nullptr-dereference =
// RUN: g++ -O -g -fsanitize=null null-dereference.c && ./a.out
int main(int argc, char **argv) {
const char * ptr = nullptr;
return *ptr; // BOOM
}
null-dereference.c:4:10: runtime error: load of null pointer of type 'const char'
Segmentation fault (core dumped)
See also
- Intel MPX
- The Application Verifier (AppVerif.exe) in Microsoft Windows SDK
- Valgrind, a memory debugging tool
References
{{Reflist|30em}}
External links
- [https://groups.google.com/g/address-sanitizer AddressSanitizer Google Group] (no mailing list)
- [https://github.com/google/sanitizers AddressSanitizer project page]
- [http://clang.llvm.org/docs/AddressSanitizer.html AddressSanitizer documentation (Clang)]
Category:Security testing tools
Category:Computer security procedures