Skip to content

Commit a8cd92f

Browse files
committed
Add symbol prefixing feature for BoringSSL
1 parent 76f47a7 commit a8cd92f

File tree

6 files changed

+221
-0
lines changed

6 files changed

+221
-0
lines changed

.github/workflows/prefix.yml

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
name: prefix
2+
3+
on:
4+
push:
5+
paths:
6+
- .github/workflows/prefix.yml
7+
- boring-sys/build/main.rs
8+
- boring-sys/build/prefix.rs
9+
10+
jobs:
11+
prefix-symbols:
12+
runs-on: ${{ matrix.os }}
13+
strategy:
14+
matrix:
15+
include:
16+
- target: x86_64-unknown-linux-gnu
17+
os: ubuntu-latest
18+
bin: ""
19+
test: true
20+
custom_env: {}
21+
- target: aarch64-unknown-linux-gnu
22+
os: ubuntu-latest
23+
bin: ""
24+
test: false
25+
apt_packages: crossbuild-essential-arm64 binutils-multiarch
26+
custom_env:
27+
CC_aarch64_unknown_linux_gnu: aarch64-linux-gnu-gcc
28+
CXX_aarch64_unknown_linux_gnu: aarch64-linux-gnu-g++
29+
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-g++
30+
- target: armv7-linux-androideabi
31+
os: ubuntu-latest
32+
bin: ndk
33+
test: false
34+
custom_env: {}
35+
- target: aarch64-linux-android
36+
os: ubuntu-latest
37+
bin: ndk
38+
test: false
39+
custom_env: {}
40+
- target: x86_64-linux-android
41+
os: ubuntu-latest
42+
bin: ndk
43+
test: false
44+
custom_env: {}
45+
- target: i686-linux-android
46+
os: ubuntu-latest
47+
bin: ndk
48+
test: false
49+
custom_env: {}
50+
defaults:
51+
run:
52+
working-directory: test-project
53+
steps:
54+
- name: Checkout repository
55+
uses: actions/checkout@v5
56+
- name: Create test project
57+
working-directory: .
58+
run: |
59+
cargo init test-project
60+
cd test-project
61+
cargo add boring-sys --path ../boring-sys/
62+
cargo add openssl-sys -F vendored
63+
echo "fn main() {boring_sys::init(); openssl_sys::init();}" > src/main.rs
64+
- name: Install Rust toolchain
65+
shell: bash
66+
run: rustup target add ${{ matrix.target }}
67+
- name: Install target-specific APT dependencies
68+
if: matrix.apt_packages != ''
69+
run: sudo apt update && sudo apt install -y ${{ matrix.apt_packages }}
70+
- name: Install cargo-ndk
71+
if: contains(matrix.target, 'android')
72+
run: |
73+
cargo install cargo-ndk
74+
# Openssl fix for i686: https://github.com/rust-openssl/rust-openssl/issues/2163#issuecomment-2692363343
75+
echo "ANDROID_NDK=$ANDROID_NDK_LATEST_HOME" >> $GITHUB_ENV
76+
echo "ANDROID_NDK_HOME=$ANDROID_NDK_LATEST_HOME" >> $GITHUB_ENV
77+
echo "ANDROID_NDK_ROOT=$ANDROID_NDK_LATEST_HOME" >> $GITHUB_ENV
78+
echo "CARGO_TARGET_I686_LINUX_ANDROID_RUSTFLAGS=-C link-arg=-lclang_rt.builtins-i686-android -C link-arg=-L${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/21/lib/linux/" >> $GITHUB_ENV
79+
- name: Build without prefixing
80+
env: ${{ matrix.custom_env }}
81+
shell: bash
82+
run: |
83+
RC=0
84+
cargo ${{ matrix.bin }} build --target ${{ matrix.target }} >logs 2>&1 || RC=$?
85+
if [[ $RC == 0 || (! $(cat logs | grep "lld: error: duplicate symbol") && ! $(cat logs | grep "multiple definition of")) ]]; then
86+
cat logs
87+
echo "Build finished without duplicate symbols: $RC"
88+
exit 1
89+
fi
90+
cat logs
91+
echo "Failed as expected: $RC"
92+
- name: Add prefix-symbols feature
93+
shell: bash
94+
run: cargo add boring-sys --path ../boring-sys/ -F prefix-symbols
95+
- name: Build with prefixing
96+
env: ${{ matrix.custom_env }}
97+
shell: bash
98+
run: cargo ${{ matrix.bin }} build --target ${{ matrix.target }}
99+
- name: Check if the is no runtime failures
100+
if: matrix.test == true
101+
shell: bash
102+
run: cargo ${{ matrix.bin }} run --target ${{ matrix.target }}

boring-sys/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ rpk = []
6464
# `BORING_BSSL{,_FIPS}_SOURCE_PATH`.
6565
underscore-wildcards = []
6666

67+
# Add a prefix to all symbols in libcrypto and libssl to prevent conflicts
68+
# with other OpenSSL or BoringSSL versions that might be linked in the same process.
69+
prefix-symbols = []
70+
6771
[build-dependencies]
6872
bindgen = { workspace = true }
6973
cmake = { workspace = true }

boring-sys/build/config.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub(crate) struct Features {
1818
pub(crate) fips: bool,
1919
pub(crate) rpk: bool,
2020
pub(crate) underscore_wildcards: bool,
21+
pub(crate) prefix_symbols: bool,
2122
}
2223

2324
pub(crate) struct Env {
@@ -105,11 +106,13 @@ impl Features {
105106
let fips = env::var_os("CARGO_FEATURE_FIPS").is_some();
106107
let rpk = env::var_os("CARGO_FEATURE_RPK").is_some();
107108
let underscore_wildcards = env::var_os("CARGO_FEATURE_UNDERSCORE_WILDCARDS").is_some();
109+
let prefix_symbols = env::var_os("CARGO_FEATURE_PREFIX_SYMBOLS").is_some();
108110

109111
Self {
110112
fips,
111113
rpk,
112114
underscore_wildcards,
115+
prefix_symbols,
113116
}
114117
}
115118

boring-sys/build/main.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use core::panic;
12
use fslock::LockFile;
23
use std::env;
34
use std::ffi::OsString;
@@ -9,8 +10,10 @@ use std::process::{Command, Output};
910
use std::sync::OnceLock;
1011

1112
use crate::config::Config;
13+
use crate::prefix::{prefix_symbols, PrefixCallback};
1214

1315
mod config;
16+
mod prefix;
1417

1518
fn should_use_cmake_cross_compilation(config: &Config) -> bool {
1619
if config.host == config.target {
@@ -543,6 +546,10 @@ fn built_boring_source_path(config: &Config) -> &PathBuf {
543546
.define("FIPS", "1");
544547
}
545548

549+
if config.features.prefix_symbols {
550+
cfg.define("CMAKE_POSITION_INDEPENDENT_CODE", "ON");
551+
}
552+
546553
cfg.build_target("ssl").build();
547554
cfg.build_target("crypto").build()
548555
})
@@ -570,6 +577,14 @@ fn main() {
570577
if !config.env.docs_rs {
571578
emit_link_directives(&config);
572579
}
580+
if config.features.prefix_symbols
581+
&& ["macos", "ios", "windows"].contains(&config.target_os.as_str())
582+
{
583+
panic!("The `prefix_symbols` feature is not supported on macOS/iOS or windows targets.");
584+
}
585+
if config.features.prefix_symbols {
586+
prefix_symbols(&config);
587+
}
573588
generate_bindings(&config);
574589
}
575590

@@ -664,6 +679,10 @@ fn generate_bindings(config: &Config) {
664679
.clang_arg(sysroot.display().to_string());
665680
}
666681

682+
if config.features.prefix_symbols {
683+
builder = builder.parse_callbacks(Box::new(PrefixCallback));
684+
}
685+
667686
let headers = [
668687
"aes.h",
669688
"asn1_mac.h",

boring-sys/build/prefix.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use crate::{config::Config, pick_best_android_ndk_toolchain, run_command};
2+
use std::{fs, io::Write, path::PathBuf, process::Command};
3+
4+
// The prefix to add to all symbols
5+
// Using crate name to avoid collisions with other projects
6+
const PREFIX: &str = env!("CARGO_CRATE_NAME");
7+
8+
// Callback to add a `link_name` macro with the prefix to all generated bindings
9+
#[derive(Debug)]
10+
pub struct PrefixCallback;
11+
12+
impl bindgen::callbacks::ParseCallbacks for PrefixCallback {
13+
fn generated_link_name_override(
14+
&self,
15+
item_info: bindgen::callbacks::ItemInfo<'_>,
16+
) -> Option<String> {
17+
Some(format!("{PREFIX}_{}", item_info.name))
18+
}
19+
}
20+
21+
fn android_toolchain(config: &Config) -> PathBuf {
22+
let mut android_bin_path = config
23+
.env
24+
.android_ndk_home
25+
.clone()
26+
.expect("Please set ANDROID_NDK_HOME for Android build");
27+
android_bin_path.extend(["toolchains", "llvm", "prebuilt"]);
28+
android_bin_path.push(pick_best_android_ndk_toolchain(&android_bin_path).unwrap());
29+
android_bin_path.push("bin");
30+
android_bin_path
31+
}
32+
33+
pub fn prefix_symbols(config: &Config) {
34+
// List static libraries to prefix symbols in
35+
let static_libs: Vec<PathBuf> = [
36+
config.out_dir.join("build"),
37+
config.out_dir.join("build").join("ssl"),
38+
config.out_dir.join("build").join("crypto"),
39+
]
40+
.iter()
41+
.flat_map(|dir| {
42+
["libssl.a", "libcrypto.a"]
43+
.into_iter()
44+
.map(move |file| PathBuf::from(dir).join(file))
45+
})
46+
.filter(|p| p.exists())
47+
.collect();
48+
49+
// Use `nm` to list symbols in these static libraries
50+
let nm = match &*config.target_os {
51+
"android" => android_toolchain(config).join("llvm-nm"),
52+
_ => PathBuf::from("nm"),
53+
};
54+
let out = run_command(Command::new(nm).args(&static_libs)).unwrap();
55+
let mut redefine_syms: Vec<String> = String::from_utf8_lossy(&out.stdout)
56+
.lines()
57+
.filter(|l| {
58+
[" T ", " D ", " B ", " C ", " R ", " W "]
59+
.iter()
60+
.any(|s| l.contains(s))
61+
})
62+
.filter_map(|l| l.split_whitespace().nth(2).map(|s| s.to_string()))
63+
.filter(|l| !l.starts_with("_"))
64+
.map(|l| format!("{l} {PREFIX}_{l}"))
65+
.collect();
66+
redefine_syms.sort();
67+
redefine_syms.dedup();
68+
69+
let redefine_syms_path = config.out_dir.join("redefine_syms.txt");
70+
let mut f = fs::File::create(&redefine_syms_path).unwrap();
71+
for sym in &redefine_syms {
72+
writeln!(f, "{sym}").unwrap();
73+
}
74+
f.flush().unwrap();
75+
76+
// Use `objcopy` to prefix symbols in these static libraries
77+
let objcopy = match &*config.target_os {
78+
"android" => android_toolchain(config).join("llvm-objcopy"),
79+
_ => PathBuf::from("objcopy"),
80+
};
81+
for static_lib in &static_libs {
82+
run_command(
83+
Command::new(&objcopy)
84+
.arg(format!("--redefine-syms={}", redefine_syms_path.display()))
85+
.arg(static_lib),
86+
)
87+
.unwrap();
88+
}
89+
}

boring/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ rpk = ["boring-sys/rpk"]
3939
# `BORING_BSSL{,_FIPS}_ASSUME_PATCHED`.
4040
underscore-wildcards = ["boring-sys/underscore-wildcards"]
4141

42+
# Add a prefix to all symbols in libcrypto and libssl to prevent conflicts
43+
# with other OpenSSL or BoringSSL versions that might be linked in the same process.
44+
prefix-symbols = ["boring-sys/prefix-symbols"]
45+
4246
[dependencies]
4347
bitflags = { workspace = true }
4448
foreign-types = { workspace = true }

0 commit comments

Comments
 (0)