Skip to content

Commit e263110

Browse files
committed
Add initial support for DataFlowSanitizer
Adds initial support for DataFlowSanitizer to the Rust compiler. It currenctly supports `-Zsanitizer-dataflow-abilist` and other options can be specified using `-C llvm-args=`.
1 parent 5ad7454 commit e263110

File tree

17 files changed

+90
-9
lines changed

17 files changed

+90
-9
lines changed

compiler/rustc_codegen_llvm/src/back/write.rs

+10
Original file line numberDiff line numberDiff line change
@@ -519,12 +519,22 @@ pub(crate) unsafe fn llvm_optimize(
519519
let pgo_sample_use_path = get_pgo_sample_use_path(config);
520520
let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO;
521521
let instr_profile_output_path = get_instr_profile_output_path(config);
522+
let sanitize_dataflow_abilist: Vec<_> = config
523+
.sanitizer_dataflow_abilist
524+
.iter()
525+
.map(|file| CString::new(file.as_str()).unwrap())
526+
.collect();
527+
let sanitize_dataflow_abilist1: Vec<_> =
528+
sanitize_dataflow_abilist.iter().map(|file| file.as_ptr()).collect();
522529
// Sanitizer instrumentation is only inserted during the pre-link optimization stage.
523530
let sanitizer_options = if !is_lto {
524531
Some(llvm::SanitizerOptions {
525532
sanitize_address: config.sanitizer.contains(SanitizerSet::ADDRESS),
526533
sanitize_address_recover: config.sanitizer_recover.contains(SanitizerSet::ADDRESS),
527534
sanitize_cfi: config.sanitizer.contains(SanitizerSet::CFI),
535+
sanitize_dataflow: config.sanitizer.contains(SanitizerSet::DATAFLOW),
536+
sanitize_dataflow_abilist: sanitize_dataflow_abilist1.as_ptr(),
537+
sanitize_dataflow_abilist_len: sanitize_dataflow_abilist1.len(),
528538
sanitize_kcfi: config.sanitizer.contains(SanitizerSet::KCFI),
529539
sanitize_memory: config.sanitizer.contains(SanitizerSet::MEMORY),
530540
sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+3
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,9 @@ pub struct SanitizerOptions {
482482
pub sanitize_address: bool,
483483
pub sanitize_address_recover: bool,
484484
pub sanitize_cfi: bool,
485+
pub sanitize_dataflow: bool,
486+
pub sanitize_dataflow_abilist: *const *const c_char,
487+
pub sanitize_dataflow_abilist_len: size_t,
485488
pub sanitize_kcfi: bool,
486489
pub sanitize_memory: bool,
487490
pub sanitize_memory_recover: bool,

compiler/rustc_codegen_ssa/src/back/link.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,9 @@ fn add_sanitizer_libraries(
12221222
if sanitizer.contains(SanitizerSet::ADDRESS) {
12231223
link_sanitizer_runtime(sess, flavor, linker, "asan");
12241224
}
1225+
if sanitizer.contains(SanitizerSet::DATAFLOW) {
1226+
link_sanitizer_runtime(sess, flavor, linker, "dfsan");
1227+
}
12251228
if sanitizer.contains(SanitizerSet::LEAK) {
12261229
link_sanitizer_runtime(sess, flavor, linker, "lsan");
12271230
}

compiler/rustc_codegen_ssa/src/back/write.rs

+5
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ pub struct ModuleConfig {
9696

9797
pub sanitizer: SanitizerSet,
9898
pub sanitizer_recover: SanitizerSet,
99+
pub sanitizer_dataflow_abilist: Vec<String>,
99100
pub sanitizer_memory_track_origins: usize,
100101

101102
// Flags indicating which outputs to produce.
@@ -198,6 +199,10 @@ impl ModuleConfig {
198199
),
199200

200201
sanitizer: if_regular!(sess.opts.unstable_opts.sanitizer, SanitizerSet::empty()),
202+
sanitizer_dataflow_abilist: if_regular!(
203+
sess.opts.unstable_opts.sanitizer_dataflow_abilist.clone(),
204+
Vec::new()
205+
),
201206
sanitizer_recover: if_regular!(
202207
sess.opts.unstable_opts.sanitizer_recover,
203208
SanitizerSet::empty()

compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,7 @@ fn test_unstable_options_tracking_hash() {
810810
tracked!(sanitizer_cfi_canonical_jump_tables, None);
811811
tracked!(sanitizer_cfi_generalize_pointers, Some(true));
812812
tracked!(sanitizer_cfi_normalize_integers, Some(true));
813+
tracked!(sanitizer_dataflow_abilist, None);
813814
tracked!(sanitizer_memory_track_origins, 2);
814815
tracked!(sanitizer_recover, SanitizerSet::ADDRESS);
815816
tracked!(saturating_float_casts, Some(true));

compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#endif
4343
#include "llvm/Transforms/Instrumentation.h"
4444
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
45+
#include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h"
4546
#include "llvm/Support/TimeProfiler.h"
4647
#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
4748
#include "llvm/Transforms/Instrumentation/InstrProfiling.h"
@@ -683,6 +684,9 @@ struct LLVMRustSanitizerOptions {
683684
bool SanitizeAddress;
684685
bool SanitizeAddressRecover;
685686
bool SanitizeCFI;
687+
bool SanitizeDataFlow;
688+
char** SanitizeDataFlowABIList;
689+
size_t SanitizeDataFlowABIListLen;
686690
bool SanitizeKCFI;
687691
bool SanitizeMemory;
688692
bool SanitizeMemoryRecover;
@@ -868,6 +872,18 @@ LLVMRustOptimize(
868872
}
869873

870874
if (SanitizerOptions) {
875+
if (SanitizerOptions->SanitizeDataFlow) {
876+
std::vector<std::string> ABIListFiles(
877+
SanitizerOptions->SanitizeDataFlowABIList,
878+
SanitizerOptions->SanitizeDataFlowABIList +
879+
SanitizerOptions->SanitizeDataFlowABIListLen);
880+
OptimizerLastEPCallbacks.push_back(
881+
[ABIListFiles](ModulePassManager &MPM, OptimizationLevel Level) {
882+
MPM.addPass(DataFlowSanitizerPass(ABIListFiles));
883+
}
884+
);
885+
}
886+
871887
if (SanitizerOptions->SanitizeMemory) {
872888
MemorySanitizerOptions Options(
873889
SanitizerOptions->SanitizeMemoryTrackOrigins,

compiler/rustc_session/src/options.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ mod desc {
381381
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
382382
pub const parse_oom_strategy: &str = "either `panic` or `abort`";
383383
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
384-
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`";
384+
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`";
385385
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
386386
pub const parse_cfguard: &str =
387387
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
@@ -718,6 +718,7 @@ mod parse {
718718
*slot |= match s {
719719
"address" => SanitizerSet::ADDRESS,
720720
"cfi" => SanitizerSet::CFI,
721+
"dataflow" => SanitizerSet::DATAFLOW,
721722
"kcfi" => SanitizerSet::KCFI,
722723
"kernel-address" => SanitizerSet::KERNELADDRESS,
723724
"leak" => SanitizerSet::LEAK,
@@ -1841,6 +1842,8 @@ written to standard error output)"),
18411842
"enable generalizing pointer types (default: no)"),
18421843
sanitizer_cfi_normalize_integers: Option<bool> = (None, parse_opt_bool, [TRACKED],
18431844
"enable normalizing integer types (default: no)"),
1845+
sanitizer_dataflow_abilist: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
1846+
"additional ABI list files that control how shadow parameters are passed (space separated)"),
18441847
sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
18451848
"enable origins tracking in MemorySanitizer"),
18461849
sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],

compiler/rustc_target/src/spec/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1221,6 +1221,7 @@ bitflags::bitflags! {
12211221
const KCFI = 1 << 8;
12221222
const KERNELADDRESS = 1 << 9;
12231223
const SAFESTACK = 1 << 10;
1224+
const DATAFLOW = 1 << 11;
12241225
}
12251226
}
12261227
rustc_data_structures::external_bitflags_debug! { SanitizerSet }
@@ -1233,6 +1234,7 @@ impl SanitizerSet {
12331234
Some(match self {
12341235
SanitizerSet::ADDRESS => "address",
12351236
SanitizerSet::CFI => "cfi",
1237+
SanitizerSet::DATAFLOW => "dataflow",
12361238
SanitizerSet::KCFI => "kcfi",
12371239
SanitizerSet::KERNELADDRESS => "kernel-address",
12381240
SanitizerSet::LEAK => "leak",
@@ -2782,6 +2784,7 @@ impl Target {
27822784
base.$key_name |= match s.as_str() {
27832785
Some("address") => SanitizerSet::ADDRESS,
27842786
Some("cfi") => SanitizerSet::CFI,
2787+
Some("dataflow") => SanitizerSet::DATAFLOW,
27852788
Some("kcfi") => SanitizerSet::KCFI,
27862789
Some("kernel-address") => SanitizerSet::KERNELADDRESS,
27872790
Some("leak") => SanitizerSet::LEAK,

compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub fn target() -> Target {
1010
base.static_position_independent_executables = true;
1111
base.supported_sanitizers = SanitizerSet::ADDRESS
1212
| SanitizerSet::CFI
13+
| SanitizerSet::DATAFLOW
1314
| SanitizerSet::LEAK
1415
| SanitizerSet::MEMORY
1516
| SanitizerSet::SAFESTACK

src/bootstrap/configure.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def v(*args):
4848
o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)")
4949
o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date")
5050
o("vendor", "build.vendor", "enable usage of vendored Rust crates")
51-
o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan, hwasan)")
51+
o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, dfsan, lsan, msan, tsan, hwasan)")
5252
o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball")
5353
o("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo")
5454
o("profiler", "build.profiler", "build the profiler runtime")

src/bootstrap/src/core/build_steps/llvm.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1093,7 +1093,7 @@ fn supported_sanitizers(
10931093
"x86_64-unknown-illumos" => common_libs("illumos", "x86_64", &["asan"]),
10941094
"x86_64-pc-solaris" => common_libs("solaris", "x86_64", &["asan"]),
10951095
"x86_64-unknown-linux-gnu" => {
1096-
common_libs("linux", "x86_64", &["asan", "lsan", "msan", "safestack", "tsan"])
1096+
common_libs("linux", "x86_64", &["asan", "dfsan", "lsan", "msan", "safestack", "tsan"])
10971097
}
10981098
"x86_64-unknown-linux-musl" => {
10991099
common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])

src/doc/unstable-book/src/compiler-flags/sanitizer.md

+24-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ This feature allows for use of one of following sanitizers:
1212
* [AddressSanitizer](#addresssanitizer) a fast memory error detector.
1313
* [ControlFlowIntegrity](#controlflowintegrity) LLVM Control Flow Integrity (CFI) provides
1414
forward-edge control flow protection.
15+
* [DataFlowSanitizer](#dataflowsanitizer) a generic dynamic data flow analysis framework.
1516
* [HWAddressSanitizer](#hwaddresssanitizer) a memory error detector similar to
1617
AddressSanitizer, but based on partial hardware assistance.
1718
* [KernelControlFlowIntegrity](#kernelcontrolflowintegrity) LLVM Kernel Control
@@ -25,10 +26,12 @@ This feature allows for use of one of following sanitizers:
2526
* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow protection (aarch64 only).
2627
* [ThreadSanitizer](#threadsanitizer) a fast data race detector.
2728

28-
To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
29-
`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`,
30-
`-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or `-Zsanitizer=thread`.
31-
You might also need the `--target` and `build-std` flags. Example:
29+
To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=cfi`,
30+
`-Zsanitizer=dataflow`,`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`,
31+
`-Zsanitizer=memory`, `-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or
32+
`-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags.
33+
34+
Example:
3235
```shell
3336
$ RUSTFLAGS=-Zsanitizer=address cargo build -Zbuild-std --target x86_64-unknown-linux-gnu
3437
```
@@ -625,6 +628,21 @@ LLVM KCFI is supported on the following targets:
625628
See the [Clang KernelControlFlowIntegrity documentation][clang-kcfi] for more
626629
details.
627630
631+
# DataFlowSanitizer
632+
633+
DataFlowSanitizer is a generalised dynamic data flow analysis.
634+
635+
Unlike other Sanitizer tools, this tool is not designed to detect a specific
636+
class of bugs on its own. Instead, it provides a generic dynamic data flow
637+
analysis framework to be used by clients to help detect application-specific
638+
issues within their own code.
639+
640+
DataFlowSanitizer is supported on the following targets:
641+
642+
* `x86_64-unknown-linux-gnu`
643+
644+
See the [Clang DataFlowSanitizer documentation][clang-dataflow] for more details.
645+
628646
# KernelAddressSanitizer
629647
630648
KernelAddressSanitizer (KASAN) is a freestanding version of AddressSanitizer
@@ -835,6 +853,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
835853
* [Sanitizers project page](https://github.com./google/sanitizers/wiki/)
836854
* [AddressSanitizer in Clang][clang-asan]
837855
* [ControlFlowIntegrity in Clang][clang-cfi]
856+
* [DataFlowSanitizer in Clang][clang-dataflow]
838857
* [HWAddressSanitizer in Clang][clang-hwasan]
839858
* [Linux Kernel's KernelAddressSanitizer documentation][linux-kasan]
840859
* [LeakSanitizer in Clang][clang-lsan]
@@ -844,6 +863,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
844863
845864
[clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
846865
[clang-cfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html
866+
[clang-dataflow]: https://clang.llvm.org/docs/DataFlowSanitizer.html
847867
[clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
848868
[clang-kcfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-kcfi
849869
[clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html

src/tools/compiletest/src/common.rs

+1
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ impl PanicStrategy {
156156
pub enum Sanitizer {
157157
Address,
158158
Cfi,
159+
Dataflow,
159160
Kcfi,
160161
KernelAddress,
161162
Leak,

src/tools/compiletest/src/header/needs.rs

+7
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ pub(super) fn handle_needs(
2929
condition: cache.sanitizer_cfi,
3030
ignore_reason: "ignored on targets without CFI sanitizer",
3131
},
32+
Need {
33+
name: "needs-sanitizer-dataflow",
34+
condition: cache.sanitizer_dataflow,
35+
ignore_reason: "ignored on targets without dataflow sanitizer",
36+
},
3237
Need {
3338
name: "needs-sanitizer-kcfi",
3439
condition: cache.sanitizer_kcfi,
@@ -190,6 +195,7 @@ pub(super) struct CachedNeedsConditions {
190195
sanitizer_support: bool,
191196
sanitizer_address: bool,
192197
sanitizer_cfi: bool,
198+
sanitizer_dataflow: bool,
193199
sanitizer_kcfi: bool,
194200
sanitizer_kasan: bool,
195201
sanitizer_leak: bool,
@@ -229,6 +235,7 @@ impl CachedNeedsConditions {
229235
sanitizer_support: std::env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(),
230236
sanitizer_address: sanitizers.contains(&Sanitizer::Address),
231237
sanitizer_cfi: sanitizers.contains(&Sanitizer::Cfi),
238+
sanitizer_dataflow: sanitizers.contains(&Sanitizer::Dataflow),
232239
sanitizer_kcfi: sanitizers.contains(&Sanitizer::Kcfi),
233240
sanitizer_kasan: sanitizers.contains(&Sanitizer::KernelAddress),
234241
sanitizer_leak: sanitizers.contains(&Sanitizer::Leak),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Verifies that functions are instrumented.
2+
//
3+
// needs-sanitizer-dataflow
4+
// compile-flags: -Copt-level=0 -Zsanitizer=dataflow
5+
6+
#![crate_type="lib"]
7+
8+
pub fn foo() {
9+
}
10+
// CHECK: define{{.*}}foo{{.*}}.dfsan

tests/ui/check-cfg/well-known-values.stderr

-1
Original file line numberDiff line numberDiff line change
@@ -256,4 +256,3 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux`
256256
= note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
257257

258258
warning: 26 warnings emitted
259-

tests/ui/invalid/invalid-no-sanitize.stderr

-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,3 @@ LL | #[no_sanitize(brontosaurus)]
77
= note: expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
88

99
error: aborting due to 1 previous error
10-

0 commit comments

Comments
 (0)