diff --git a/boring-sys/Cargo.toml b/boring-sys/Cargo.toml index 15e6025e..34e8df21 100644 --- a/boring-sys/Cargo.toml +++ b/boring-sys/Cargo.toml @@ -57,6 +57,10 @@ fips = [] # `BORING_BSSL{,_FIPS}_SOURCE_PATH`. underscore-wildcards = [] +# Add a prefix to all symbols in libcrypto and libssl to prevent conflicts +# with other OpenSSL or BoringSSL versions that might be linked in the same process. +prefix-symbols = [] + [build-dependencies] bindgen = { workspace = true } cmake = { workspace = true } diff --git a/boring-sys/build/config.rs b/boring-sys/build/config.rs index 25aaabf4..a8aaed62 100644 --- a/boring-sys/build/config.rs +++ b/boring-sys/build/config.rs @@ -18,6 +18,7 @@ pub(crate) struct Features { pub(crate) fips: bool, pub(crate) rpk: bool, pub(crate) underscore_wildcards: bool, + pub(crate) prefix_symbols: bool, } pub(crate) struct Env { @@ -105,11 +106,13 @@ impl Features { let fips = env::var_os("CARGO_FEATURE_FIPS").is_some(); let rpk = env::var_os("CARGO_FEATURE_RPK").is_some(); let underscore_wildcards = env::var_os("CARGO_FEATURE_UNDERSCORE_WILDCARDS").is_some(); + let prefix_symbols = env::var_os("CARGO_FEATURE_PREFIX_SYMBOLS").is_some(); Self { fips, rpk, underscore_wildcards, + prefix_symbols, } } diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index c995a580..76bb6bec 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -9,8 +9,10 @@ use std::process::{Command, Output}; use std::sync::OnceLock; use crate::config::Config; +use crate::prefix::{prefix_symbols, PrefixCallback}; mod config; +mod prefix; fn should_use_cmake_cross_compilation(config: &Config) -> bool { if config.host == config.target { @@ -544,6 +546,10 @@ fn built_boring_source_path(config: &Config) -> &PathBuf { .define("FIPS", "1"); } + if config.features.prefix_symbols { + cfg.define("CMAKE_POSITION_INDEPENDENT_CODE", "ON"); + } + cfg.build_target("ssl").build(); cfg.build_target("crypto").build() }) @@ -571,6 +577,9 @@ fn main() { if !config.env.docs_rs { emit_link_directives(&config); } + if config.features.prefix_symbols { + prefix_symbols(&config); + } generate_bindings(&config); } @@ -665,6 +674,10 @@ fn generate_bindings(config: &Config) { .clang_arg(sysroot.display().to_string()); } + if config.features.prefix_symbols { + builder = builder.parse_callbacks(Box::new(PrefixCallback)); + } + let headers = [ "aes.h", "asn1_mac.h", diff --git a/boring-sys/build/prefix.rs b/boring-sys/build/prefix.rs new file mode 100644 index 00000000..01dd8510 --- /dev/null +++ b/boring-sys/build/prefix.rs @@ -0,0 +1,81 @@ +use crate::{config::Config, pick_best_android_ndk_toolchain, run_command}; +use std::{fs, io::Write, path::PathBuf, process::Command}; +// The prefix to add to all symbols +// RBSSL = Rust BoringSSL, chosen arbitrarily to avoid collisions with other projects +const PREFIX: &str = "RBSSL"; +// Callback to add a `link_name` macro with the prefix to all generated bindings +#[derive(Debug)] +pub struct PrefixCallback; +impl bindgen::callbacks::ParseCallbacks for PrefixCallback { + fn generated_link_name_override( + &self, + item_info: bindgen::callbacks::ItemInfo<'_>, + ) -> Option { + Some(format!("{PREFIX}_{}", item_info.name)) + } +} +fn android_toolchain(config: &Config) -> PathBuf { + let mut android_bin_path = config + .env + .android_ndk_home + .clone() + .expect("Please set ANDROID_NDK_HOME for Android build"); + android_bin_path.extend(["toolchains", "llvm", "prebuilt"]); + android_bin_path.push(pick_best_android_ndk_toolchain(&android_bin_path).unwrap()); + android_bin_path.push("bin"); + android_bin_path +} +pub fn prefix_symbols(config: &Config) { + // List static libraries to prefix symbols in + let static_libs: Vec = [ + config.out_dir.join("build"), + config.out_dir.join("build").join("ssl"), + config.out_dir.join("build").join("crypto"), + ] + .iter() + .flat_map(|dir| { + ["libssl.a", "libcrypto.a"] + .into_iter() + .map(move |file| PathBuf::from(dir).join(file)) + }) + .filter(|p| p.exists()) + .collect(); + // Use `nm` to list symbols in these static libraries + let nm = match &*config.target_os { + "android" => android_toolchain(config).join("llvm-nm"), + _ => PathBuf::from("nm"), + }; + let out = run_command(Command::new(nm).args(&static_libs)).unwrap(); + let mut redefine_syms: Vec = String::from_utf8_lossy(&out.stdout) + .lines() + .filter(|l| { + [" T ", " D ", " B ", " C ", " R ", " W "] + .iter() + .any(|s| l.contains(s)) + }) + .filter_map(|l| l.split_whitespace().nth(2).map(|s| s.to_string())) + .filter(|l| !l.starts_with("_")) + .map(|l| format!("{l} {PREFIX}_{l}")) + .collect(); + redefine_syms.sort(); + redefine_syms.dedup(); + let redefine_syms_path = config.out_dir.join("redefine_syms.txt"); + let mut f = fs::File::create(&redefine_syms_path).unwrap(); + for sym in &redefine_syms { + writeln!(f, "{sym}").unwrap(); + } + f.flush().unwrap(); + // Use `objcopy` to prefix symbols in these static libraries + let objcopy = match &*config.target_os { + "android" => android_toolchain(config).join("llvm-objcopy"), + _ => PathBuf::from("objcopy"), + }; + for static_lib in &static_libs { + run_command( + Command::new(&objcopy) + .arg(format!("--redefine-syms={}", redefine_syms_path.display())) + .arg(static_lib), + ) + .unwrap(); + } +} diff --git a/boring/Cargo.toml b/boring/Cargo.toml index 227ff998..51dd8ec8 100644 --- a/boring/Cargo.toml +++ b/boring/Cargo.toml @@ -32,6 +32,10 @@ legacy-compat-deprecated = [] # `BORING_BSSL{,_FIPS}_ASSUME_PATCHED`. underscore-wildcards = ["boring-sys/underscore-wildcards"] +# Add a prefix to all symbols in libcrypto and libssl to prevent conflicts +# with other OpenSSL or BoringSSL versions that might be linked in the same process. +prefix-symbols = ["boring-sys/prefix-symbols"] + [dependencies] bitflags = { workspace = true } foreign-types = { workspace = true }