This patch adds initial support for the -fsanitize=kernel-address flag to Clang.
Right now it's quite restricted: only out-of-line instrumentation is supported, globals are not instrumented, some GCC kasan flags are not supported.
Using this patch I am able to build and boot the KASan tree with LLVMLinux patches from github.com/ramosian-glider/kasan/tree/kasan_llvmlinux.
To disable KASan instrumentation for a certain function attribute((no_sanitize("kernel-address"))) can be used.
Details
Diff Detail
Event Timeline
Cool, happy to see it coming. I would also add tests for:
a) presence of sanitize_address function attribute b) actual KASan instrumentation with correct shadow offset/scale. c) missing module ctors/callbacks in KASan mode.
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
1362 | Wait a second.... Do you do *anything* in AddressSanitizerModule pass in CompileKernel mode? You don't add module constructor, and you don't instrument globals. Maybe, we should just avoid creating this pass in the first place? | |
1419 | Hm... So you don't have __asan_memset() in the kernel. Maybe, we shouldn't instrument mem intrinsics in this case at all, not replace intrinisics with call to plain memset()? | |
1455 | You will access uninitialized memory in AddressSanitizer::runOnFunction (potentially in AddressSanitizer::maybeInsertAsanInitAtFunctionEntry as well, but the latter is relevant only for Mac). | |
1542–1543 | bool UseCalls = CompileKernel || (ClInstrumentationWithCallsThreshold >= 0 && ...); | |
tools/clang/include/clang/Basic/Sanitizers.def | ||
44 | What is the "correct" way to capitalize it? KASAN? KASan? | |
tools/clang/lib/AST/Decl.cpp | ||
3684–3685 | Wow, that's hard to parse. I'd vote for adding a method to SanitizerSet if (!Context.getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address, SanitizerKind::KernelAddress) ... That would also be useful in several places below. | |
tools/clang/lib/CodeGen/BackendUtil.cpp | ||
217 | See note above - I'm not sure we need a module pass for that. |
Addressed Alexey's comments.
Regarding the missing tests, I think it's best to add them at opt level, but I can't do that now because there's no command line switch that enables KASan (this mode only depends on the bool passed to the pass factory). I can add such a switch, but then it can be used to work around the "ASan xor KASan" restriction. WDYT?
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
1362 |
Exactly, my intention was to add it soon. | |
1390 | Looks like I've been comparing to the wrong gcc version, 4.9 didn't have the 'noabort' suffixes. Fixed. | |
1419 | mm/kasan/kasan.c redefines memset() et al. making them call __asan_{load,store}N (see https://github.com/ramosian-glider/kasan/blob/kasan_llvmlinux/mm/kasan/kasan.c#L263), so we just replace the intrinsics with calls to memset(). | |
1455 | In fact I didn't fully understand this piece before. I've looked std::tie up and it's more clear to me now. | |
1542–1543 | Done. | |
tools/clang/include/clang/Basic/Sanitizers.def | ||
44 | It hasn't been established yet, but Dima says we prefer "KASan" (which surprised me). Fixed here and in tools/clang/lib/CodeGen/CodeGenModule.cpp | |
tools/clang/lib/AST/Decl.cpp | ||
3684–3685 | I've added SanitizerSet::hasAsanOrKasan() -- did you mean that? | |
tools/clang/lib/CodeGen/BackendUtil.cpp | ||
217 | Can we keep it provided that we'll have module-level instrumentation soon? | |
tools/clang/lib/CodeGen/CodeGenFunction.cpp | ||
619 | Note I'm using the same attribute for both userspace and kernel instrumentation. I think we don't need to distinguish between them. |
I think it's fine to add whatever commandline flags are needed for testing - they are not user-visible anyway, and we should have *some* means to test KASan instrumentation without a frontend.
Looks mostly good.
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
1455 | I would actually prefer a null initialization, as it's weird to create functions that would never be called in KASan mode. | |
tools/clang/include/clang/Basic/Sanitizers.h | ||
56 | Um, no, I mean to add hasOneOf method that would take ArrayRef of sanitizer kinds and return true iff at least one of them is enabled. Then you could call it as... | |
tools/clang/lib/AST/Decl.cpp | ||
3684–3685 | Context.getLangOpts().Sanitize.hasOneOf({SanitizerKind::Address, SanitizerKind::KernelAddress}) | |
tools/clang/lib/CodeGen/BackendUtil.cpp | ||
203–204 | Pass false here. |
I've added the tests for -fsanitize=kernel-address
- check that it instruments memory accesses
- check that the sanitize_address attributes are emitted
Regarding the offset/scale, these aren't emitted now, as I've only implemented the out-of-line instrumentation.
Regarding the missing module ctors, these will be added once we've globals instrumentation - not sure we need to test that they're absent now.
I've also added the -enable-kasan flag, but the existing tests do not use it yet.
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
1455 | Done. | |
tools/clang/include/clang/Basic/Sanitizers.h | ||
56 | This is basically the has() method without the llvm::countPopulation(K) == 1 check. | |
tools/clang/lib/CodeGen/BackendUtil.cpp | ||
203–204 | Done |
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
1391 | we also need to make them actually noabort |
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
120 | Um, asan-kernel? Looks like most of the flags in this file start with asan-, it makes sense to keep it. | |
394 | nullptr | |
tools/clang/include/clang/Basic/Sanitizers.h | ||
56 | Yeah, using the mask is also ok. But let's make the name different, so that has() method would still always accept a single sanitizer. |
tools/clang/test/Driver/kasan.c | ||
---|---|---|
1 ↗ | (On Diff #27761) | Please use linux as a target (http://reviews.llvm.org/D10467). You can also merge it into asan.c to keep a single test case (I'm fine either way). |
Addressed comments by Alexey and Dmitry
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
120 | Done | |
394 | Added them for the ctor/init functions. What's the policy regarding those in the code? | |
1391 | Removed the noabort suffixes for error reporting functions. | |
tools/clang/test/Driver/kasan.c | ||
1 ↗ | (On Diff #27761) | Done, united the tests. |
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
1366 | Wait, this is dead code, right? CompileKernel is known to be false here, as you've checked it in the outer if. | |
tools/clang/lib/CodeGen/CGDeclCXX.cpp | ||
270 | hasOneOf | |
tools/clang/lib/CodeGen/SanitizerMetadata.cpp | ||
28 | (here and below) | |
tools/clang/test/CodeGen/address-safety-attr-kasan.cpp | ||
4 | Please specify triple (or merge this into address-safety-attr.cpp somehow) | |
10 | Function Attrs: nounwind sanitize_address |
Addressed Alexey's comments
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
1366 | Removed the dead code for now. This block will be added back once we enable globals instrumentation. | |
tools/clang/lib/CodeGen/CGDeclCXX.cpp | ||
270 | Done | |
tools/clang/lib/CodeGen/SanitizerMetadata.cpp | ||
28 | Yes, I'm about to add globals support soon, it's just not working properly yet. | |
tools/clang/test/CodeGen/address-safety-attr-kasan.cpp | ||
4 | Done. | |
10 | Added a $ after "nounwind" |
LGTM
tools/clang/lib/AST/Decl.cpp | ||
---|---|---|
3684–3685 | remove extra parens around hasOneOf call | |
tools/clang/test/CodeGen/address-safety-attr-kasan.cpp | ||
11 | Please check this syntax. I thought that [[]] is used to define FileCheck variables, while {{}} are used for regular expressions. | |
tools/clang/test/Driver/asan.c | ||
1–9 | while you're here, please add linux to original RUN-lines as well. |
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
1394 | Do you mean to add noabort variants to compiler-rt? That would be nice, especially if you could add -fsanitize-recover to enable those in userspace as well. |
Addressed the comments by Alexey and Yury
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
1394 | No, I meant just emitting _noabort calls under KASan. I've updated the comment to reflect that. | |
tools/clang/lib/AST/Decl.cpp | ||
3684–3685 | Indeed. | |
tools/clang/test/CodeGen/address-safety-attr-kasan.cpp | ||
11 | Yeah, that's right. | |
tools/clang/test/Driver/asan.c | ||
1–9 | Done |
Now there's a problem with handleNoSanitizeSpecificAttr() - looks like attribute((no_sanitize_address)) can only works with either ASan or KASan.
Looking.
Updated the test to use attribute((no_sanitize("kernel-address"))) as a workaround. We'll still need to decide which of the three attributes:
- attribute((no_sanitize_address))
- attribute((no_sanitize("address")))
- attribute((no_sanitize("kernel-address")))
shall affect KASan instrumentation.
Um, asan-kernel? Looks like most of the flags in this file start with asan-, it makes sense to keep it.