Skip to content

Commit 6db074a

Browse files
committed
Add symbol prefixing feature for BoringSSL
1 parent e628aeb commit 6db074a

6 files changed

Lines changed: 219 additions & 0 deletions

File tree

.github/workflows/prefix.yml

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

60+
# Add a prefix to all symbols in libcrypto and libssl to prevent conflicts
61+
# with other OpenSSL or BoringSSL versions that might be linked in the same process.
62+
prefix-symbols = []
63+
6064
[build-dependencies]
6165
bindgen = { workspace = true }
6266
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 {
@@ -544,6 +547,10 @@ fn built_boring_source_path(config: &Config) -> &PathBuf {
544547
.define("FIPS", "1");
545548
}
546549

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

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

683+
if config.features.prefix_symbols {
684+
builder = builder.parse_callbacks(Box::new(PrefixCallback));
685+
}
686+
668687
let headers = [
669688
"aes.h",
670689
"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
@@ -32,6 +32,10 @@ legacy-compat-deprecated = []
3232
# `BORING_BSSL{,_FIPS}_ASSUME_PATCHED`.
3333
underscore-wildcards = ["boring-sys/underscore-wildcards"]
3434

35+
# Add a prefix to all symbols in libcrypto and libssl to prevent conflicts
36+
# with other OpenSSL or BoringSSL versions that might be linked in the same process.
37+
prefix-symbols = ["boring-sys/prefix-symbols"]
38+
3539
[dependencies]
3640
bitflags = { workspace = true }
3741
foreign-types = { workspace = true }

0 commit comments

Comments
 (0)