diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 08aab84986800..031bbd6336116 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -519,12 +519,22 @@ pub(crate) unsafe fn llvm_optimize( let pgo_sample_use_path = get_pgo_sample_use_path(config); let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO; let instr_profile_output_path = get_instr_profile_output_path(config); + let sanitize_dataflow_abilist: Vec<_> = config + .sanitizer_dataflow_abilist + .iter() + .map(|file| CString::new(file.as_str()).unwrap()) + .collect(); + let sanitize_dataflow_abilist_ptrs: Vec<_> = + sanitize_dataflow_abilist.iter().map(|file| file.as_ptr()).collect(); // Sanitizer instrumentation is only inserted during the pre-link optimization stage. let sanitizer_options = if !is_lto { Some(llvm::SanitizerOptions { sanitize_address: config.sanitizer.contains(SanitizerSet::ADDRESS), sanitize_address_recover: config.sanitizer_recover.contains(SanitizerSet::ADDRESS), sanitize_cfi: config.sanitizer.contains(SanitizerSet::CFI), + sanitize_dataflow: config.sanitizer.contains(SanitizerSet::DATAFLOW), + sanitize_dataflow_abilist: sanitize_dataflow_abilist_ptrs.as_ptr(), + sanitize_dataflow_abilist_len: sanitize_dataflow_abilist_ptrs.len(), sanitize_kcfi: config.sanitizer.contains(SanitizerSet::KCFI), sanitize_memory: config.sanitizer.contains(SanitizerSet::MEMORY), sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY), diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 70fc7a66bcdc7..0d7337fc97671 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -480,6 +480,9 @@ pub struct SanitizerOptions { pub sanitize_address: bool, pub sanitize_address_recover: bool, pub sanitize_cfi: bool, + pub sanitize_dataflow: bool, + pub sanitize_dataflow_abilist: *const *const c_char, + pub sanitize_dataflow_abilist_len: size_t, pub sanitize_kcfi: bool, pub sanitize_memory: bool, pub sanitize_memory_recover: bool, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 1ad0dec064006..83cb2246c1e4c 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1218,6 +1218,9 @@ fn add_sanitizer_libraries( if sanitizer.contains(SanitizerSet::ADDRESS) { link_sanitizer_runtime(sess, flavor, linker, "asan"); } + if sanitizer.contains(SanitizerSet::DATAFLOW) { + link_sanitizer_runtime(sess, flavor, linker, "dfsan"); + } if sanitizer.contains(SanitizerSet::LEAK) { link_sanitizer_runtime(sess, flavor, linker, "lsan"); } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index c2fc32130ea00..1690654b82d2d 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -95,6 +95,7 @@ pub struct ModuleConfig { pub sanitizer: SanitizerSet, pub sanitizer_recover: SanitizerSet, + pub sanitizer_dataflow_abilist: Vec, pub sanitizer_memory_track_origins: usize, // Flags indicating which outputs to produce. @@ -197,6 +198,10 @@ impl ModuleConfig { ), sanitizer: if_regular!(sess.opts.unstable_opts.sanitizer, SanitizerSet::empty()), + sanitizer_dataflow_abilist: if_regular!( + sess.opts.unstable_opts.sanitizer_dataflow_abilist.clone(), + Vec::new() + ), sanitizer_recover: if_regular!( sess.opts.unstable_opts.sanitizer_recover, SanitizerSet::empty() diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 112553b2f7031..5e1fc248b801c 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -811,6 +811,7 @@ fn test_unstable_options_tracking_hash() { tracked!(sanitizer_cfi_canonical_jump_tables, None); tracked!(sanitizer_cfi_generalize_pointers, Some(true)); tracked!(sanitizer_cfi_normalize_integers, Some(true)); + tracked!(sanitizer_dataflow_abilist, vec![String::from("/rustc/abc")]); tracked!(sanitizer_memory_track_origins, 2); tracked!(sanitizer_recover, SanitizerSet::ADDRESS); tracked!(saturating_float_casts, Some(true)); diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 5b1cc52f1f63b..4ec784e259058 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -42,6 +42,7 @@ #endif #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Instrumentation/AddressSanitizer.h" +#include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h" #include "llvm/Support/TimeProfiler.h" #if LLVM_VERSION_GE(19, 0) #include "llvm/Support/PGOOptions.h" @@ -686,6 +687,9 @@ struct LLVMRustSanitizerOptions { bool SanitizeAddress; bool SanitizeAddressRecover; bool SanitizeCFI; + bool SanitizeDataFlow; + char **SanitizeDataFlowABIList; + size_t SanitizeDataFlowABIListLen; bool SanitizeKCFI; bool SanitizeMemory; bool SanitizeMemoryRecover; @@ -883,6 +887,18 @@ LLVMRustOptimize( } if (SanitizerOptions) { + if (SanitizerOptions->SanitizeDataFlow) { + std::vector ABIListFiles( + SanitizerOptions->SanitizeDataFlowABIList, + SanitizerOptions->SanitizeDataFlowABIList + + SanitizerOptions->SanitizeDataFlowABIListLen); + OptimizerLastEPCallbacks.push_back( + [ABIListFiles](ModulePassManager &MPM, OptimizationLevel Level) { + MPM.addPass(DataFlowSanitizerPass(ABIListFiles)); + } + ); + } + if (SanitizerOptions->SanitizeMemory) { MemorySanitizerOptions Options( SanitizerOptions->SanitizeMemoryTrackOrigins, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 743f476033935..42c9d5e10eba1 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -371,7 +371,8 @@ mod desc { pub const parse_list: &str = "a space-separated list of strings"; pub const parse_list_with_polarity: &str = "a comma-separated list of strings, with elements beginning with + or -"; - pub const parse_opt_comma_list: &str = "a comma-separated list of strings"; + pub const parse_comma_list: &str = "a comma-separated list of strings"; + pub const parse_opt_comma_list: &str = parse_comma_list; pub const parse_number: &str = "a number"; pub const parse_opt_number: &str = parse_number; pub const parse_threads: &str = parse_number; @@ -381,7 +382,7 @@ mod desc { pub const parse_opt_panic_strategy: &str = parse_panic_strategy; pub const parse_oom_strategy: &str = "either `panic` or `abort`"; pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; - pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, or `thread`"; + pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, or `thread`"; pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2"; pub const parse_cfguard: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; @@ -602,6 +603,18 @@ mod parse { } } + pub(crate) fn parse_comma_list(slot: &mut Vec, v: Option<&str>) -> bool { + match v { + Some(s) => { + let mut v: Vec<_> = s.split(',').map(|s| s.to_string()).collect(); + v.sort_unstable(); + *slot = v; + true + } + None => false, + } + } + pub(crate) fn parse_opt_comma_list(slot: &mut Option>, v: Option<&str>) -> bool { match v { Some(s) => { @@ -718,6 +731,7 @@ mod parse { *slot |= match s { "address" => SanitizerSet::ADDRESS, "cfi" => SanitizerSet::CFI, + "dataflow" => SanitizerSet::DATAFLOW, "kcfi" => SanitizerSet::KCFI, "kernel-address" => SanitizerSet::KERNELADDRESS, "leak" => SanitizerSet::LEAK, @@ -1846,6 +1860,8 @@ written to standard error output)"), "enable generalizing pointer types (default: no)"), sanitizer_cfi_normalize_integers: Option = (None, parse_opt_bool, [TRACKED], "enable normalizing integer types (default: no)"), + sanitizer_dataflow_abilist: Vec = (Vec::new(), parse_comma_list, [TRACKED], + "additional ABI list files that control how shadow parameters are passed (comma separated)"), sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED], "enable origins tracking in MemorySanitizer"), sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED], diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index d04bcb2d78aac..f981dd92dfc42 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1221,6 +1221,7 @@ bitflags::bitflags! { const KCFI = 1 << 8; const KERNELADDRESS = 1 << 9; const SAFESTACK = 1 << 10; + const DATAFLOW = 1 << 11; } } rustc_data_structures::external_bitflags_debug! { SanitizerSet } @@ -1233,6 +1234,7 @@ impl SanitizerSet { Some(match self { SanitizerSet::ADDRESS => "address", SanitizerSet::CFI => "cfi", + SanitizerSet::DATAFLOW => "dataflow", SanitizerSet::KCFI => "kcfi", SanitizerSet::KERNELADDRESS => "kernel-address", SanitizerSet::LEAK => "leak", @@ -2790,6 +2792,7 @@ impl Target { base.$key_name |= match s.as_str() { Some("address") => SanitizerSet::ADDRESS, Some("cfi") => SanitizerSet::CFI, + Some("dataflow") => SanitizerSet::DATAFLOW, Some("kcfi") => SanitizerSet::KCFI, Some("kernel-address") => SanitizerSet::KERNELADDRESS, Some("leak") => SanitizerSet::LEAK, diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs index 2296b58f45dc0..1510f3b390cd2 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs @@ -10,6 +10,7 @@ pub fn target() -> Target { base.static_position_independent_executables = true; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI + | SanitizerSet::DATAFLOW | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::SAFESTACK diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index d34c19a47e3fb..8b65e8ff9c3e1 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -48,7 +48,7 @@ def v(*args): o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)") o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date") o("vendor", "build.vendor", "enable usage of vendored Rust crates") -o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan, hwasan)") +o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, dfsan, lsan, msan, tsan, hwasan)") o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball") o("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo") o("profiler", "build.profiler", "build the profiler runtime") diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index 9998fe2f5db8f..bd1f9699c3c82 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/116881 +Last change is for: https://github.com/rust-lang/rust/pull/120761 diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 4a92acfa3d90d..8e7430bd819bc 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -1091,7 +1091,7 @@ fn supported_sanitizers( "x86_64-unknown-illumos" => common_libs("illumos", "x86_64", &["asan"]), "x86_64-pc-solaris" => common_libs("solaris", "x86_64", &["asan"]), "x86_64-unknown-linux-gnu" => { - common_libs("linux", "x86_64", &["asan", "lsan", "msan", "safestack", "tsan"]) + common_libs("linux", "x86_64", &["asan", "dfsan", "lsan", "msan", "safestack", "tsan"]) } "x86_64-unknown-linux-musl" => { common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"]) diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index 523617eb3e15f..c8fd154a00ec9 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -29,6 +29,8 @@ This feature allows for use of one of following sanitizers: * Those that apart from testing, may be used in production: * [ControlFlowIntegrity](#controlflowintegrity) LLVM Control Flow Integrity (CFI) provides forward-edge control flow protection. + * [DataFlowSanitizer](#dataflowsanitizer) a generic dynamic data flow analysis + framework. * [KernelControlFlowIntegrity](#kernelcontrolflowintegrity) LLVM Kernel Control Flow Integrity (KCFI) provides forward-edge control flow protection for operating systems kernels. @@ -39,14 +41,21 @@ This feature allows for use of one of following sanitizers: * [ShadowCallStack](#shadowcallstack) provides backward-edge control flow protection (aarch64 only). -To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`, -`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`, -`-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or `-Zsanitizer=thread`. -You might also need the `--target` and `build-std` flags. Example: +To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=cfi`, +`-Zsanitizer=dataflow`,`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, +`-Zsanitizer=memory`, `-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or +`-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags. + +Example: ```shell $ RUSTFLAGS=-Zsanitizer=address cargo build -Zbuild-std --target x86_64-unknown-linux-gnu ``` +Additional options for sanitizers can be passed to LLVM command line argument +processor via LLVM arguments using `llvm-args` codegen option (e.g., +`-Cllvm-args=-dfsan-combine-pointer-labels-on-load=false`). See the sanitizer +documentation for more information about additional options. + # AddressSanitizer AddressSanitizer is a memory error detector. It can detect the following types @@ -639,6 +648,21 @@ LLVM KCFI is supported on the following targets: See the [Clang KernelControlFlowIntegrity documentation][clang-kcfi] for more details. +# DataFlowSanitizer + +DataFlowSanitizer is a generalised dynamic data flow analysis. + +Unlike other Sanitizer tools, this tool is not designed to detect a specific +class of bugs on its own. Instead, it provides a generic dynamic data flow +analysis framework to be used by clients to help detect application-specific +issues within their own code. + +DataFlowSanitizer is supported on the following targets: + +* `x86_64-unknown-linux-gnu` + +See the [Clang DataFlowSanitizer documentation][clang-dataflow] for more details. + # KernelAddressSanitizer KernelAddressSanitizer (KASAN) is a freestanding version of AddressSanitizer @@ -849,6 +873,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT * [Sanitizers project page](https://github.com/google/sanitizers/wiki/) * [AddressSanitizer in Clang][clang-asan] * [ControlFlowIntegrity in Clang][clang-cfi] +* [DataFlowSanitizer in Clang][clang-dataflow] * [HWAddressSanitizer in Clang][clang-hwasan] * [Linux Kernel's KernelAddressSanitizer documentation][linux-kasan] * [LeakSanitizer in Clang][clang-lsan] @@ -858,6 +883,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT [clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html [clang-cfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html +[clang-dataflow]: https://clang.llvm.org/docs/DataFlowSanitizer.html [clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html [clang-kcfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-kcfi [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 49f1226e2cc38..bfe6c959e7ce5 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -156,6 +156,7 @@ impl PanicStrategy { pub enum Sanitizer { Address, Cfi, + Dataflow, Kcfi, KernelAddress, Leak, diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs index 9b22b2112a8c0..3978658815053 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/header/needs.rs @@ -29,6 +29,11 @@ pub(super) fn handle_needs( condition: cache.sanitizer_cfi, ignore_reason: "ignored on targets without CFI sanitizer", }, + Need { + name: "needs-sanitizer-dataflow", + condition: cache.sanitizer_dataflow, + ignore_reason: "ignored on targets without dataflow sanitizer", + }, Need { name: "needs-sanitizer-kcfi", condition: cache.sanitizer_kcfi, @@ -190,6 +195,7 @@ pub(super) struct CachedNeedsConditions { sanitizer_support: bool, sanitizer_address: bool, sanitizer_cfi: bool, + sanitizer_dataflow: bool, sanitizer_kcfi: bool, sanitizer_kasan: bool, sanitizer_leak: bool, @@ -229,6 +235,7 @@ impl CachedNeedsConditions { sanitizer_support: std::env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(), sanitizer_address: sanitizers.contains(&Sanitizer::Address), sanitizer_cfi: sanitizers.contains(&Sanitizer::Cfi), + sanitizer_dataflow: sanitizers.contains(&Sanitizer::Dataflow), sanitizer_kcfi: sanitizers.contains(&Sanitizer::Kcfi), sanitizer_kasan: sanitizers.contains(&Sanitizer::KernelAddress), sanitizer_leak: sanitizers.contains(&Sanitizer::Leak), diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 920fe16a9fcb4..ec863299e4866 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -43,6 +43,7 @@ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[ "tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment", // more include "tests/ui/proc-macro/auxiliary/included-file.txt", // more include "tests/ui/invalid/foo.natvis.xml", // sample debugger visualizer + "tests/ui/sanitize/sanitizer-dataflow-abilist.txt", // dataflow sanitizer ABI list file "tests/ui/shell-argfiles/shell-argfiles.args", // passing args via a file "tests/ui/shell-argfiles/shell-argfiles-badquotes.args", // passing args via a file "tests/ui/shell-argfiles/shell-argfiles-via-argfile-shell.args", // passing args via a file diff --git a/tests/codegen/sanitizer/dataflow-instrument-functions.rs b/tests/codegen/sanitizer/dataflow-instrument-functions.rs new file mode 100644 index 0000000000000..69c3560882c18 --- /dev/null +++ b/tests/codegen/sanitizer/dataflow-instrument-functions.rs @@ -0,0 +1,10 @@ +// Verifies that functions are instrumented. +// +//@ needs-sanitizer-dataflow +//@ compile-flags: -Copt-level=0 -Zsanitizer=dataflow + +#![crate_type="lib"] + +pub fn foo() { +} +// CHECK: define{{.*}}foo{{.*}}.dfsan diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 5f52421fef5b2..8184eb8554c14 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -100,7 +100,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | sanitize = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `sanitize` are: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread` + = note: expected values for `sanitize` are: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/sanitize/sanitizer-dataflow-abilist.txt b/tests/ui/sanitize/sanitizer-dataflow-abilist.txt new file mode 100644 index 0000000000000..fe04838f5493e --- /dev/null +++ b/tests/ui/sanitize/sanitizer-dataflow-abilist.txt @@ -0,0 +1,505 @@ +fun:main=uninstrumented +fun:main=discard + +############################################################################### +# DFSan interface functions +############################################################################### +fun:dfsan_union=uninstrumented +fun:dfsan_union=discard +fun:dfsan_create_label=uninstrumented +fun:dfsan_create_label=discard +fun:dfsan_set_label=uninstrumented +fun:dfsan_set_label=discard +fun:dfsan_add_label=uninstrumented +fun:dfsan_add_label=discard +fun:dfsan_get_label=uninstrumented +fun:dfsan_get_label=custom +fun:dfsan_read_label=uninstrumented +fun:dfsan_read_label=discard +fun:dfsan_get_label_count=uninstrumented +fun:dfsan_get_label_count=discard +fun:dfsan_get_label_info=uninstrumented +fun:dfsan_get_label_info=discard +fun:dfsan_has_label=uninstrumented +fun:dfsan_has_label=discard +fun:dfsan_has_label_with_desc=uninstrumented +fun:dfsan_has_label_with_desc=discard +fun:dfsan_set_write_callback=uninstrumented +fun:dfsan_set_write_callback=custom +fun:dfsan_flush=uninstrumented +fun:dfsan_flush=discard +fun:dfsan_print_origin_trace=uninstrumented +fun:dfsan_print_origin_trace=discard +fun:dfsan_print_origin_id_trace=uninstrumented +fun:dfsan_print_origin_id_trace=discard +fun:dfsan_sprint_origin_trace=uninstrumented +fun:dfsan_sprint_origin_trace=discard +fun:dfsan_sprint_origin_id_trace=uninstrumented +fun:dfsan_sprint_origin_id_trace=discard +fun:dfsan_sprint_stack_trace=uninstrumented +fun:dfsan_sprint_stack_trace=discard +fun:dfsan_get_origin=uninstrumented +fun:dfsan_get_origin=custom +fun:dfsan_read_origin_of_first_taint=uninstrumented +fun:dfsan_read_origin_of_first_taint=discard +fun:dfsan_get_init_origin=uninstrumented +fun:dfsan_get_init_origin=discard +fun:dfsan_get_track_origins=uninstrumented +fun:dfsan_get_track_origins=discard +fun:dfsan_set_conditional_callback=uninstrumented +fun:dfsan_set_conditional_callback=discard +fun:dfsan_get_labels_in_signal_conditional=uninstrumented +fun:dfsan_get_labels_in_signal_conditional=discard +fun:dfsan_set_reaches_function_callback=uninstrumented +fun:dfsan_set_reaches_function_callback=discard +fun:dfsan_get_labels_in_signal_reaches_function=uninstrumented +fun:dfsan_get_labels_in_signal_reaches_function=discard +fun:dfsan_reaches_function_callback=uninstrumented +fun:dfsan_reaches_function_callback=discard + +############################################################################### +# glibc +############################################################################### +# Functions of memory allocators +fun:__libc_memalign=discard +fun:aligned_alloc=discard +fun:calloc=discard +fun:cfree=discard +fun:mallinfo=discard +fun:malloc=discard +fun:free=discard +fun:malloc_stats=discard +fun:malloc_usable_size=discard +fun:mallopt=discard +fun:memalign=discard +fun:posix_memalign=discard +fun:pvalloc=discard +fun:realloc=discard +fun:reallocarray=discard +fun:valloc=discard + +# Functions that return a value that depends on the input, but the output might +# not be necessarily data-dependent on the input. +fun:isalpha=functional +fun:isdigit=functional +fun:isprint=functional +fun:isxdigit=functional +fun:isalnum=functional +fun:ispunct=functional +fun:isspace=functional +fun:tolower=functional +fun:_tolower=functional +fun:toupper=functional + +# Functions that return a value that is data-dependent on the input. +fun:__isinf=functional +fun:__isinff=functional +fun:__signbit=functional +fun:__signbitf=functional +fun:__signbitl=functional +fun:btowc=functional +fun:exp=functional +fun:exp2=functional +fun:expf=functional +fun:expl=functional +fun:fabs=functional +fun:finite=functional +fun:finitef=functional +fun:finitel=functional +fun:floor=functional +fun:fmod=functional +fun:isinf=functional +fun:isinff=functional +fun:isinfl=functional +fun:isnan=functional +fun:isnanf=functional +fun:isnanl=functional +fun:log=functional +fun:log1p=functional +fun:log1pf=functional +fun:log1pl=functional +fun:log2=functional +fun:log2f=functional +fun:log2l=functional +fun:modf=functional +fun:nextafter=functional +fun:nextafterf=functional +fun:nextafterl=functional +fun:nexttoward=functional +fun:nexttowardf=functional +fun:nexttowardl=functional +fun:pow=functional +fun:powf=functional +fun:powl=functional +fun:round=functional +fun:sqrt=functional +fun:sqrtf=functional +fun:sqrtl=functional +fun:wctob=functional + +# Functions that produce an output that does not depend on the input (shadow is +# zeroed automatically). +fun:__assert_fail=discard +fun:__cmsg_nxthdr=discard +fun:__ctype_b_loc=discard +fun:__cxa_atexit=discard +fun:__errno_location=discard +fun:__newlocale=discard +fun:__sbrk=discard +fun:__sigsetjmp=discard +fun:__uselocale=discard +fun:__wctype_l=discard +fun:access=discard +fun:alarm=discard +fun:atexit=discard +fun:bind=discard +fun:chdir=discard +fun:close=discard +fun:closedir=discard +fun:connect=discard +fun:creat=discard +fun:dladdr=discard +fun:dlclose=discard +fun:epoll_create=discard +fun:epoll_create1=discard +fun:epoll_ctl=discard +fun:fclose=discard +fun:feof=discard +fun:ferror=discard +fun:fflush=discard +fun:fileno=discard +fun:fopen=discard +fun:fprintf=discard +fun:fputc=discard +fun:fputc=discard +fun:fputs=discard +fun:fputs=discard +fun:fseek=discard +fun:ftell=discard +fun:fwrite=discard +fun:getenv=discard +fun:getuid=discard +fun:geteuid=discard +fun:getpagesize=discard +fun:getpid=discard +fun:kill=discard +fun:listen=discard +fun:lseek=discard +fun:mkdir=discard +fun:mmap=discard +fun:munmap=discard +fun:open=discard +fun:openat=discard +fun:pipe=discard +fun:posix_fadvise=discard +fun:prctl=discard +fun:printf=discard +fun:pthread_sigmask=discard +fun:putc=discard +fun:putchar=discard +fun:puts=discard +fun:rand=discard +fun:random=discard +fun:remove=discard +fun:sched_getcpu=discard +fun:sched_get_priority_max=discard +fun:sched_setaffinity=discard +fun:sched_yield=discard +fun:sem_destroy=discard +fun:sem_init=discard +fun:sem_post=discard +fun:sem_wait=discard +fun:send=discard +fun:sendmsg=discard +fun:sendto=discard +fun:setsockopt=discard +fun:shutdown=discard +fun:sleep=discard +fun:socket=discard +fun:strerror=discard +fun:strspn=discard +fun:strcspn=discard +fun:symlink=discard +fun:syscall=discard +fun:unlink=discard +fun:uselocale=discard +fun:vfprintf=discard + +# Functions that produce output does not depend on the input (need to zero the +# shadow manually). +fun:_dl_get_tls_static_info=custom +fun:clock_gettime=custom +fun:dlopen=custom +fun:epoll_wait=custom +fun:fgets=custom +fun:fstat=custom +fun:getcwd=custom +fun:get_current_dir_name=custom +fun:getentropy=custom +fun:gethostname=custom +fun:getpeername=custom +fun:getrlimit=custom +fun:getrusage=custom +fun:getsockname=custom +fun:getsockopt=custom +fun:nanosleep=custom +fun:pread=custom +fun:read=custom +fun:recvmmsg=custom +fun:recvmsg=custom +fun:sigaltstack=custom +fun:socketpair=custom +fun:stat=custom +fun:time=custom + +# Functions that produce an output that depend on the input (propagate the +# shadow manually). +fun:ctime_r=custom +fun:inet_pton=custom +fun:localtime_r=custom +fun:memcpy=custom +fun:memmove=custom +fun:memset=custom +fun:strcpy=custom +fun:strdup=custom +fun:strncpy=custom +fun:strtod=custom +fun:strtol=custom +fun:strtoll=custom +fun:strtoul=custom +fun:strtoull=custom +fun:strcat=custom +fun:strncat=custom +fun:__isoc23_strtod=custom +fun:__isoc23_strtol=custom +fun:__isoc23_strtoll=custom +fun:__isoc23_strtoul=custom +fun:__isoc23_strtoull=custom + +# Functions that produce an output that is computed from the input, but is not +# necessarily data dependent. +fun:bcmp=custom +fun:memchr=custom +fun:memcmp=custom +fun:strcasecmp=custom +fun:strchr=custom +fun:strcmp=custom +fun:strlen=custom +fun:strnlen=custom +fun:strncasecmp=custom +fun:strncmp=custom +fun:strpbrk=custom +fun:strrchr=custom +fun:strstr=custom +fun:strsep=custom + +# Functions which take action based on global state, such as running a callback +# set by a separate function. +fun:write=custom + +# Functions that take a callback (wrap the callback manually). +fun:dl_iterate_phdr=custom + +fun:getpwuid_r=custom +fun:poll=custom +fun:sched_getaffinity=custom +fun:select=custom +fun:sigemptyset=custom +fun:sigaction=custom +fun:signal=custom +fun:gettimeofday=custom + +# sprintf-like +fun:sprintf=custom +fun:snprintf=custom + +# scanf-like +fun:sscanf=custom +fun:__isoc99_sscanf=custom +fun:__isoc23_sscanf=custom + +# TODO: custom +fun:asprintf=discard +fun:qsort=discard + +# fork +fun:fork=custom + +############################################################################### +# pthread +############################################################################### +fun:__pthread_register_cancel=discard +fun:__pthread_unregister_cancel=discard +fun:pthread_attr_destroy=discard +fun:pthread_attr_getaffinity_np=discard +fun:pthread_attr_getdetachstate=discard +fun:pthread_attr_getguardsize=discard +fun:pthread_attr_getinheritsched=discard +fun:pthread_attr_getschedparam=discard +fun:pthread_attr_getschedpolicy=discard +fun:pthread_attr_getscope=discard +fun:pthread_attr_getstack=discard +fun:pthread_attr_getstackaddr=disacrd +fun:pthread_attr_getstacksize=discard +fun:pthread_attr_init=discard +fun:pthread_attr_setaffinity_np=discard +fun:pthread_attr_setdetachstate=discard +fun:pthread_attr_setguardsize=discard +fun:pthread_attr_setinheritsched=discard +fun:pthread_attr_setschedparam=discard +fun:pthread_attr_setschedpolicy=discard +fun:pthread_attr_setscope=discard +fun:pthread_attr_setstack=discard +fun:pthread_attr_setstackaddr=discard +fun:pthread_attr_setstacksize=discard +fun:pthread_equal=discard +fun:pthread_getschedparam=discard +fun:pthread_getspecific=discard +fun:pthread_key_create=discard +fun:pthread_key_delete=discard +fun:pthread_mutex_destroy=discard +fun:pthread_mutex_init=discard +fun:pthread_mutex_lock=discard +fun:pthread_mutex_trylock=discard +fun:pthread_mutex_unlock=discard +fun:pthread_mutexattr_destroy=discard +fun:pthread_mutexattr_init=discard +fun:pthread_mutexattr_settype=discard +fun:pthread_rwlock_destroy=discard +fun:pthread_rwlock_init=discard +fun:pthread_rwlock_rdlock=discard +fun:pthread_rwlock_timedrdlock=discard +fun:pthread_rwlock_timedwrlock=discard +fun:pthread_rwlock_tryrdlock=discard +fun:pthread_rwlock_trywrlock=discard +fun:pthread_rwlock_wrlock=discard +fun:pthread_rwlock_unlock=discard +fun:pthread_setschedparam=discard +fun:pthread_setname_np=discard +fun:pthread_once=discard +fun:pthread_self=discard +fun:pthread_setspecific=discard + +# Functions that take a callback (wrap the callback manually). +fun:pthread_create=custom + +# Functions that produce output does not depend on the input (need to zero the +# shadow manually). +fun:pthread_join=custom + +############################################################################### +# libffi/libgo +############################################################################### +# Functions that are written in asm or are called from asm. +fun:ffi_call_unix64=uninstrumented +fun:ffi_call_unix64=discard +fun:ffi_closure_unix64_inner=uninstrumented +fun:ffi_closure_unix64_inner=discard +fun:ffi_closure_unix64=uninstrumented +fun:ffi_closure_unix64=discard +fun:__go_get_closure=uninstrumented +fun:__go_get_closure=discard +fun:__go_makefunc_can_recover=uninstrumented +fun:__go_makefunc_can_recover=discard +fun:__go_makefunc_returning=uninstrumented +fun:__go_makefunc_returning=discard +fun:reflect.MakeFuncStubGo=uninstrumented +fun:reflect.MakeFuncStubGo=discard +fun:reflect.makeFuncStub=uninstrumented +fun:reflect.makeFuncStub=discard + + +############################################################################### +# lib/Fuzzer +############################################################################### +# Replaces __sanitizer_cov_trace_cmp with __dfsw___sanitizer_cov_trace_cmp +fun:__sanitizer_cov_trace_cmp1=custom +fun:__sanitizer_cov_trace_cmp1=uninstrumented +fun:__sanitizer_cov_trace_cmp2=custom +fun:__sanitizer_cov_trace_cmp2=uninstrumented +fun:__sanitizer_cov_trace_cmp4=custom +fun:__sanitizer_cov_trace_cmp4=uninstrumented +fun:__sanitizer_cov_trace_cmp8=custom +fun:__sanitizer_cov_trace_cmp8=uninstrumented +fun:__sanitizer_cov_trace_const_cmp1=custom +fun:__sanitizer_cov_trace_const_cmp1=uninstrumented +fun:__sanitizer_cov_trace_const_cmp2=custom +fun:__sanitizer_cov_trace_const_cmp2=uninstrumented +fun:__sanitizer_cov_trace_const_cmp4=custom +fun:__sanitizer_cov_trace_const_cmp4=uninstrumented +fun:__sanitizer_cov_trace_const_cmp8=custom +fun:__sanitizer_cov_trace_const_cmp8=uninstrumented +# Similar for __sanitizer_cov_trace_switch +fun:__sanitizer_cov_trace_switch=custom +fun:__sanitizer_cov_trace_switch=uninstrumented + +# Ignores all other __sanitizer callbacks. +fun:__sanitizer_cov=uninstrumented +fun:__sanitizer_cov=discard +fun:__sanitizer_cov_module_init=uninstrumented +fun:__sanitizer_cov_module_init=discard +fun:__sanitizer_cov_with_check=uninstrumented +fun:__sanitizer_cov_with_check=discard +fun:__sanitizer_set_death_callback=uninstrumented +fun:__sanitizer_set_death_callback=discard +fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented +fun:__sanitizer_update_counter_bitset_and_clear_counters=discard +fun:__sanitizer_cov_trace_pc*=uninstrumented +fun:__sanitizer_cov_trace_pc*=discard +fun:__sanitizer_cov_pcs_init=uninstrumented +fun:__sanitizer_cov_pcs_init=discard + +fun:__sanitizer_get_current_allocated_bytes=uninstrumented +fun:__sanitizer_get_current_allocated_bytes=discard +fun:__sanitizer_get_heap_size=uninstrumented +fun:__sanitizer_get_heap_size=discard +fun:__sanitizer_get_free_bytes=uninstrumented +fun:__sanitizer_get_free_bytes=discard +fun:__sanitizer_get_unmapped_bytes=uninstrumented +fun:__sanitizer_get_unmapped_bytes=discard +fun:__sanitizer_get_estimated_allocated_size=uninstrumented +fun:__sanitizer_get_estimated_allocated_size=discard +fun:__sanitizer_get_ownership=uninstrumented +fun:__sanitizer_get_ownership=discard +fun:__sanitizer_get_allocated_begin=uninstrumented +fun:__sanitizer_get_allocated_begin=discard +fun:__sanitizer_get_allocated_size=uninstrumented +fun:__sanitizer_get_allocated_size=discard +fun:__sanitizer_get_allocated_size_fast=uninstrumented +fun:__sanitizer_get_allocated_size_fast=discard +fun:__sanitizer_print_stack_trace=uninstrumented +fun:__sanitizer_print_stack_trace=discard + +fun:TcmallocSlab_Internal_PushBatch_FixedShift=uninstrumented +fun:TcmallocSlab_Internal_PushBatch_FixedShift=discard +fun:TcmallocSlab_Internal_PushBatch_FixedShift_VCPU=uninstrumented +fun:TcmallocSlab_Internal_PushBatch_FixedShift_VCPU=discard +fun:TcmallocSlab_Internal_PerCpuCmpxchg64=uninstrumented +fun:TcmallocSlab_Internal_PerCpuCmpxchg64=discard +fun:TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU=uninstrumented +fun:TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU=discard +fun:TcmallocSlab_Internal_PopBatch_FixedShift=uninstrumented +fun:TcmallocSlab_Internal_PopBatch_FixedShift=discard +fun:TcmallocSlab_Internal_PopBatch_FixedShift_VCPU=uninstrumented +fun:TcmallocSlab_Internal_PopBatch_FixedShift_VCPU=discard + +# Ignores the dfsan wrappers. +fun:__dfsw_*=uninstrumented +fun:__dfsw_*=discard +fun:__dfso_*=uninstrumented +fun:__dfso_*=discard + +# Rust functions. +fun:__rdl_alloc=uninstrumented +fun:__rdl_alloc_zeroed=uninstrumented +fun:__rdl_dealloc=uninstrumented +fun:__rdl_realloc=uninstrumented +fun:__rg_oom=uninstrumented +fun:__rust_alloc=uninstrumented +fun:__rust_alloc_error_handler=uninstrumented +fun:__rust_alloc_zeroed=uninstrumented +fun:__rust_dealloc=uninstrumented +fun:__rust_realloc=uninstrumented +fun:_ZN4core*=uninstrumented +fun:_ZN3std*=uninstrumented +fun:rust_eh_personality=uninstrumented diff --git a/tests/ui/sanitize/sanitizer-dataflow-basic.rs b/tests/ui/sanitize/sanitizer-dataflow-basic.rs new file mode 100644 index 0000000000000..8194c6ca3cecd --- /dev/null +++ b/tests/ui/sanitize/sanitizer-dataflow-basic.rs @@ -0,0 +1,59 @@ +#![allow(non_camel_case_types)] +// Verifies that labels are propagated through loads and stores. +// +//@ needs-sanitizer-dataflow +//@ run-pass +//@ compile-flags: -Zsanitizer=dataflow -Zsanitizer-dataflow-abilist={{src-base}}/sanitize/sanitizer-dataflow-abilist.txt + +use std::mem::size_of; +use std::os::raw::{c_int, c_long, c_void}; + +type dfsan_label = u8; + +extern "C" { + fn dfsan_add_label(label: dfsan_label, addr: *mut c_void, size: usize); + fn dfsan_get_label(data: c_long) -> dfsan_label; + fn dfsan_has_label(label: dfsan_label, elem: dfsan_label) -> c_int; + fn dfsan_read_label(addr: *const c_void, size: usize) -> dfsan_label; + fn dfsan_set_label(label: dfsan_label, addr: *mut c_void, size: usize); +} + +fn propagate2(i: &i64) -> i64 { + i.clone() +} + +fn propagate(i: i64) -> i64 { + let v = vec!(i, 1, 2, 3); + let j = v.iter().sum(); + propagate2(&j) +} + +pub fn main() { + let mut i = 1i64; + let i_ptr = &mut i as *mut i64; + let i_label: dfsan_label = 1; + unsafe { + dfsan_set_label(i_label, i_ptr as *mut c_void, size_of::()); + } + + let new_label = unsafe { dfsan_get_label(i) }; + assert_eq!(i_label, new_label); + + let read_label = unsafe { dfsan_read_label(i_ptr as *const c_void, size_of::()) }; + assert_eq!(i_label, read_label); + + let j_label: dfsan_label = 2; + unsafe { + dfsan_add_label(j_label, i_ptr as *mut c_void, size_of::()); + } + + let read_label = unsafe { dfsan_read_label(i_ptr as *const c_void, size_of::()) }; + assert_eq!(unsafe { dfsan_has_label(read_label, i_label) }, 1); + assert_eq!(unsafe { dfsan_has_label(read_label, j_label) }, 1); + + let mut new_i = propagate(i); + let new_i_ptr = &mut new_i as *mut i64; + let read_label = unsafe { dfsan_read_label(new_i_ptr as *const c_void, size_of::()) }; + assert_eq!(unsafe { dfsan_has_label(read_label, i_label) }, 1); + assert_eq!(unsafe { dfsan_has_label(read_label, j_label) }, 1); +}