Skip to content

Commit 8e547f4

Browse files
committed
Windows: Load DLLs from system32
1 parent 7e22426 commit 8e547f4

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

build.rs

+32
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,36 @@ fn main() {
2727
}
2828
let target = env::var("TARGET").unwrap();
2929
println!("cargo:rustc-env=TARGET={target}");
30+
31+
let target_os = env::var("CARGO_CFG_TARGET_OS");
32+
let target_env = env::var("CARGO_CFG_TARGET_ENV");
33+
if Ok("windows") == target_os.as_deref() && Ok("msvc") == target_env.as_deref() {
34+
// # Only search system32 for DLLs
35+
//
36+
// This applies to DLLs loaded at load time. However, this setting is ignored
37+
// before Windows 10 RS1.
38+
println!("cargo:cargo:rustc-link-arg-bin=rustup-init=/DEPENDENTLOADFLAG:0x800");
39+
40+
// # Delay load
41+
//
42+
// Delay load dlls that are not "known DLLs".
43+
// Known DLLs are always loaded from the system directory whereas other DLLs
44+
// are loaded from the application directory. By delay loading the latter
45+
// we can ensure they are instead loaded from the system directory.
46+
//
47+
// This will work on all supported Windows versions but it relies on
48+
// using `SetDefaultDllDirectories` before any libraries are loaded.
49+
let delay_load_dlls = ["bcrypt", "powrprof", "secur32"];
50+
for dll in delay_load_dlls {
51+
println!("cargo:rustc-link-arg-bin=rustup-init=/delayload:{dll}.dll");
52+
}
53+
println!("cargo:rustc-link-arg-bin=rustup-init=delayimp.lib");
54+
55+
// # Turn linker warnings into errors
56+
//
57+
// Rust hides linker warnings meaning mistakes may go unnoticed.
58+
// Turning them into errors forces them to be displayed (and the build to fail).
59+
// If we do want to ignore specific warnings then `/IGNORE:` should be used.
60+
println!("cargo:cargo:rustc-link-arg-bin=rustup-init=/WX");
61+
}
3062
}

src/bin/rustup-init.rs

+19
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ use rustup::is_proxyable_tools;
2929
use rustup::utils::utils;
3030

3131
fn main() {
32+
#[cfg(windows)]
33+
pre_rustup_main_init();
34+
3235
let process = OSProcess::default();
3336
with(process.into(), || match maybe_trace_rustup() {
3437
Err(e) => {
@@ -163,3 +166,19 @@ fn do_recursion_guard() -> Result<()> {
163166

164167
Ok(())
165168
}
169+
170+
/// Windows pre-main security mitigations.
171+
///
172+
/// This is attempts to defend against malicious DLLs that may sit alongside
173+
/// rustup-init in the user's download folder.
174+
#[cfg(windows)]
175+
pub fn pre_rustup_main_init() {
176+
use winapi::um::libloaderapi::{SetDefaultDllDirectories, LOAD_LIBRARY_SEARCH_SYSTEM32};
177+
// Default to loading delay loaded DLLs from the system directory.
178+
unsafe {
179+
let result = SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32);
180+
// SetDefaultDllDirectories should never fail if given valid arguments.
181+
// But just to be safe and to catch mistakes, assert that it succeeded.
182+
assert_ne!(result, 0);
183+
}
184+
}

0 commit comments

Comments
 (0)