ztong0001 created this revision. Herald added subscribers: ormris, dexonsmith, jdoerfert, steven_wu, hiraditya. ztong0001 requested review of this revision. Herald added projects: clang, LLVM. Herald added subscribers: llvm-commits, cfe-commits.
Adding __attribute__((no_sanitize("bounds"))) is not really disabling bounds checking, i.e. disable -fsanitize=array-bounds -fsanitize=local-bounds. or -fsanitize=bounds. We have a potential user in Linux kennel which is currently affected by -fsanitize=local-bounds. Linux kernel(5.17) has a function pskb_expand_head (net/core/skbuff.c) currently experiencing false positive when CONFIG_UBSAN_LOCAL_BOUNDS is enabled (i.e. supply -fsanitize=array-bounds -fsanitize=local-bounds). The aforementioned function does the following which will create a false positive. char* p = kmalloc(M); // allocate buffer, size is M int actual_size = ksize(p); // return actual allocated size in the slab allocator, this will guaranteed to be larger than M + N p[actual_size - N+1] = 0; //Out of bound access LLVM assume the size of the buffer is M, thus the later p[actual_size-N+1] access will be treated as out of bound access. However, this function deliberately use the actual allocated size instead of M. Kernel will be unhappy as bounds check fail and it crash hard with the following message: [ 0.060423] PTP clock support registered [ 0.060820] invalid opcode: 0000 [#1] PREEMPT SMP NOPTI [ 0.061232] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.17.0-rc3-00247-g83e396641110-dirty #102 [ 0.061418] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-1ubuntu1.1 04/01/2014 [ 0.061418] RIP: 0010:pskb_expand_head+0x38b/0x3b0 [ 0.061418] Code: 84 fc fd ff ff be 01 00 00 00 b8 01 00 00 00 3e 0f c1 47 18 85 c0 74 14 8d 48 01 0 9 c1 0f 89 de fd ff ff eb 0c 67 0f b9 40 12 <0f> 0b be 02 00 00 00 48 83 c7 18 e8 25 b7 cc ff e9 c2 fd ff ff 0f [ 0.061418] RSP: 0018:ffffc9000000bb60 EFLAGS: 00010287 [ 0.061418] RAX: 00000000000006c0 RBX: ffff888002e92000 RCX: 000000000000ffff [ 0.061418] RDX: 00000000000006c0 RSI: ffff888002cebef0 RDI: 000000000002c800 [ 0.061418] RBP: ffff888002cebec0 R08: ffff888002ceb000 R09: ffffffff8174ed1f [ 0.061418] R10 <https://reviews.llvm.org/source/svn-test-suite/>: ffffea00000b3a00 R11 <https://reviews.llvm.org/source/libunwind/>: 0000000000000000 R12 <https://reviews.llvm.org/source/lldb/>: ffff888002ceb000 [ 0.061418] R13 <https://reviews.llvm.org/source/pstl/>: 0000000000000000 R14 <https://reviews.llvm.org/source/llvm-github/>: 0000000000012a20 R15 <https://reviews.llvm.org/source/zorg/>: ffff888002e0f000 [ 0.061418] FS: 0000000000000000(0000) GS:ffff88803ec00000(0000) knlGS:0000000000000000 [ 0.061418] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 0.061418] CR2: ffff888002a01000 CR3: 000000000220c000 CR4: 0000000000350ef0 [ 0.061418] Call Trace: [ 0.061418] <TASK> [ 0.061418] netlink_trim+0x83/0xa0 [ 0.061418] netlink_broadcast+0x2a/0x5a0 [ 0.061418] ? nla_put+0x72/0x90 [ 0.061418] genlmsg_multicast_allns+0xcc/0x120 [ 0.061418] genl_ctrl_event+0x219/0x370 [ 0.061418] genl_register_family+0x5b8/0x660 [ 0.061418] ? rtnl_register_internal+0x14d/0x180 [ 0.061418] ? tca_get_fill+0x120/0x120 [ 0.061418] ? tc_ctl_action+0x5b0/0x5b0 [ 0.061418] ? genl_init+0x31/0x31 [ 0.061418] ethnl_init+0xd/0x50 [ 0.061418] do_one_initcall+0xa5/0x290 [ 0.061418] ? alloc_page_interleave+0x5e/0x80 [ 0.061418] ? preempt_count_add+0x5e/0xa0 [ 0.061418] ? ida_alloc_range+0x3fc/0x440 [ 0.061418] ? parse_args+0x254/0x390 [ 0.061418] do_initcall_level+0xb4/0x131 [ 0.061418] do_initcalls+0x44/0x6b [ 0.061418] kernel_init_freeable+0xd8/0x138 [ 0.061418] ? rest_init+0xc0/0xc0 [ 0.061418] kernel_init+0x11/0x1a0 [ 0.061418] ret_from_fork+0x1f/0x30 The solution here is to add __attribute__((no_sanitize("bounds"))) to this function to avoid local bounds checking altogether. This patch adds __attribute__((no_sanitize("bounds"))) support to LLVM, and in linux kernel, we will add this attribute to the function definition. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D119816 Files: clang/lib/CodeGen/CodeGenFunction.cpp clang/test/CodeGen/sanitize-coverage.c llvm/include/llvm/AsmParser/LLToken.h llvm/include/llvm/Bitcode/LLVMBitCodes.h llvm/include/llvm/IR/Attributes.td llvm/lib/Bitcode/Reader/BitcodeReader.cpp llvm/lib/Bitcode/Writer/BitcodeWriter.cpp llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp llvm/lib/Transforms/Utils/CodeExtractor.cpp
Index: llvm/lib/Transforms/Utils/CodeExtractor.cpp =================================================================== --- llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -938,6 +938,7 @@ case Attribute::NonLazyBind: case Attribute::NoRedZone: case Attribute::NoUnwind: + case Attribute::NoSanitizeBounds: case Attribute::NoSanitizeCoverage: case Attribute::NullPointerIsValid: case Attribute::OptForFuzzing: Index: llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp +++ llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp @@ -142,6 +142,9 @@ static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI, ScalarEvolution &SE) { + if (F.hasFnAttribute(Attribute::NoSanitizeBounds)) + return false; + const DataLayout &DL = F.getParent()->getDataLayout(); ObjectSizeOpts EvalOpts; EvalOpts.RoundToAlign = true; Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -690,6 +690,8 @@ return bitc::ATTR_KIND_NO_UNWIND; case Attribute::NoSanitizeCoverage: return bitc::ATTR_KIND_NO_SANITIZE_COVERAGE; + case Attribute::NoSanitizeBounds: + return bitc::ATTR_KIND_NO_SANITIZE_BOUNDS; case Attribute::NullPointerIsValid: return bitc::ATTR_KIND_NULL_POINTER_IS_VALID; case Attribute::OptForFuzzing: Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1453,6 +1453,8 @@ return Attribute::NoUnwind; case bitc::ATTR_KIND_NO_SANITIZE_COVERAGE: return Attribute::NoSanitizeCoverage; + case bitc::ATTR_KIND_NO_SANITIZE_BOUNDS: + return Attribute::NoSanitizeBounds; case bitc::ATTR_KIND_NULL_POINTER_IS_VALID: return Attribute::NullPointerIsValid; case bitc::ATTR_KIND_OPT_FOR_FUZZING: Index: llvm/include/llvm/IR/Attributes.td =================================================================== --- llvm/include/llvm/IR/Attributes.td +++ llvm/include/llvm/IR/Attributes.td @@ -178,6 +178,9 @@ /// No SanitizeCoverage instrumentation. def NoSanitizeCoverage : EnumAttr<"nosanitize_coverage", [FnAttr]>; +/// No SanitizeBounds instrumentation. +def NoSanitizeBounds : EnumAttr<"nosanitize_bounds", [FnAttr]>; + /// Null pointer in address space zero is valid. def NullPointerIsValid : EnumAttr<"null_pointer_is_valid", [FnAttr]>; Index: llvm/include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -677,6 +677,7 @@ ATTR_KIND_NO_SANITIZE_COVERAGE = 76, ATTR_KIND_ELEMENTTYPE = 77, ATTR_KIND_DISABLE_SANITIZER_INSTRUMENTATION = 78, + ATTR_KIND_NO_SANITIZE_BOUNDS = 79, }; enum ComdatSelectionKindCodes { Index: llvm/include/llvm/AsmParser/LLToken.h =================================================================== --- llvm/include/llvm/AsmParser/LLToken.h +++ llvm/include/llvm/AsmParser/LLToken.h @@ -219,6 +219,7 @@ kw_nosync, kw_nocf_check, kw_nounwind, + kw_nosanitize_bounds, kw_nosanitize_coverage, kw_null_pointer_is_valid, kw_optforfuzzing, Index: clang/test/CodeGen/sanitize-coverage.c =================================================================== --- clang/test/CodeGen/sanitize-coverage.c +++ clang/test/CodeGen/sanitize-coverage.c @@ -53,6 +53,7 @@ // ASAN-NOT: call void @__asan_report_store // MSAN-NOT: call void @__msan_warning // BOUNDS-NOT: call void @__ubsan_handle_out_of_bounds + // BOUNDS-NOT: call void @llvm.trap() // TSAN-NOT: call void @__tsan_func_entry // UBSAN-NOT: call void @__ubsan_handle if (n) @@ -72,6 +73,7 @@ // ASAN-NOT: call void @__asan_report_store // MSAN-NOT: call void @__msan_warning // BOUNDS-NOT: call void @__ubsan_handle_out_of_bounds + // BOUNDS-NOT: call void @llvm.trap() // TSAN-NOT: call void @__tsan_func_entry // UBSAN-NOT: call void @__ubsan_handle if (n) Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ clang/lib/CodeGen/CodeGenFunction.cpp @@ -757,6 +757,10 @@ SanOpts.set(SanitizerKind::KernelHWAddress, false); if (mask & SanitizerKind::KernelHWAddress) SanOpts.set(SanitizerKind::HWAddress, false); + if (mask & SanitizerKind::LocalBounds) + Fn->addFnAttr(llvm::Attribute::NoSanitizeBounds); + if (mask & SanitizerKind::ArrayBounds) + Fn->addFnAttr(llvm::Attribute::NoSanitizeBounds); // SanitizeCoverage is not handled by SanOpts. if (Attr->hasCoverage())
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits