Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a prefix to the library names and to every global symbol #115

Merged
merged 5 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ name: Continuous Integration
on: [push, pull_request]

jobs:
build-1-58-1:
name: "All tests: rustc 1.58.1"
build-1-60-0:
name: "All tests: rustc 1.60.0"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Rust 1.58.1
- name: Install Rust 1.60.0
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.58.1
toolchain: 1.60.0
rustflags: ""
- name: Set up Python
uses: actions/setup-python@v4
Expand Down
12 changes: 6 additions & 6 deletions psa-crypto-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@ keywords = ["psa", "crypto", "cryptography"]
categories = ["api-bindings", "external-ffi-bindings", "cryptography"]
license = "Apache-2.0"
repository = "https://github.com/parallaxsecond/rust-psa-crypto"
links = "mbedcrypto"
rust-version = "1.58.1"
rust-version = "1.60.0"

[build-dependencies]
bindgen = { version = "0.63.0", optional = true }
bindgen = { version = "0.66.1", optional = true }
cc = "1.0.59"
cmake = "0.1.44"
# Without this line we get the following error:
# `regex-syntax v0.7.2` cannot be built because it requires rustc 1.60.0 or newer
regex = "1.7.3"
regex = "1.9.1"
walkdir = "2.3.1"
# Later versions of "memchr" and "which" (indirectly) need rustc >1.60.0:
memchr = "=2.6.2"
which = "=4.4.0"

[features]
default = ["operations"]
Expand Down
8 changes: 8 additions & 0 deletions psa-crypto-sys/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ makes no difference and there is no way to allow dynamic linking. The
requirements for configuring and building MbedTLS can be found
[on their repository homepage](https://github.com/ARMmbed/mbedtls#tool-versions).

When the crate builds the library, both the `mbedcrypto` library
itself and the `shim` library (which is needed for inline functions)
are renamed by adding a prefix of the form `psa_crypto_X_Y_Z_`. Also
every globally defined symbol in those libraries has that prefix
added. This is to avoid link-time collisions with other crates that
might use the same library, including other versions of this crate.
The renaming of symbols uses the `nm` and `objcopy` commands.

Linking and generating implementation-specific APIs is controlled by the
`operations` feature that is enabled by default. Therefore, if you
require only the specification-defined bits of the API (namely the constants and types)
Expand Down
145 changes: 112 additions & 33 deletions psa-crypto-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ fn main() -> std::io::Result<()> {

#[cfg(any(feature = "interface", feature = "operations"))]
mod common {
use bindgen::callbacks::{ItemInfo, ParseCallbacks};
use std::env;
use std::io::{Error, ErrorKind, Result};
use std::path::{Path, PathBuf};
Expand Down Expand Up @@ -81,6 +82,23 @@ mod common {
Ok(())
}

// Cargo provides the crate version from Cargo.toml in the environment.
const VERSION: &str = env!("CARGO_PKG_VERSION");

// Return a prefix that we hope is globally unique.
pub fn prefix() -> String {
format!("psa_crypto_{}_", VERSION.replace('.', "_"))
}

#[derive(Debug)]
struct RenameCallbacks {}

impl ParseCallbacks for RenameCallbacks {
fn generated_link_name_override(&self, info: ItemInfo<'_>) -> Option<String> {
Some(prefix() + info.name)
}
}

pub fn generate_mbed_crypto_bindings(mbed_include_dir: String) -> Result<()> {
let header = mbed_include_dir.clone() + "/psa/crypto.h";

Expand All @@ -92,11 +110,11 @@ mod common {
.clang_arg(format!("-I{}", out_dir))
.clang_arg("-DMBEDTLS_CONFIG_FILE=<config.h>")
.clang_arg(format!("-I{}", mbed_include_dir))
.rustfmt_bindings(true)
.header("src/c/shim.h")
.blocklist_type("max_align_t")
.generate_comments(false)
.size_t_is_usize(true)
.parse_callbacks(Box::new(RenameCallbacks {}))
.generate()
.map_err(|_| {
Error::new(
Expand All @@ -110,8 +128,8 @@ mod common {
Ok(())
}

pub fn compile_shim_library(include_dir: String) -> Result<()> {
let out_dir = env::var("OUT_DIR").unwrap();
pub fn compile_shim_library(include_dir: String, metadata: bool) -> Result<PathBuf> {
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());

// Compile and package the shim library
cc::Build::new()
Expand All @@ -122,14 +140,11 @@ mod common {
.warnings(true)
.flag("-Werror")
.opt_level(2)
.try_compile("libshim.a")
.cargo_metadata(metadata)
.try_compile("libmbedcryptoshim.a")
.map_err(|_| Error::new(ErrorKind::Other, "compiling shim.c failed"))?;

// Also link shim library
println!("cargo:rustc-link-search=native={}", out_dir);
println!("cargo:rustc-link-lib=static=shim");

Ok(())
Ok(out_dir.join("libmbedcryptoshim.a"))
}
}

Expand All @@ -144,7 +159,8 @@ mod interface {
if let Ok(include_dir) = env::var("MBEDTLS_INCLUDE_DIR") {
common::configure_mbed_crypto()?;
common::generate_mbed_crypto_bindings(include_dir.clone())?;
common::compile_shim_library(include_dir)
let _ = common::compile_shim_library(include_dir, true)?;
Ok(())
} else {
Err(Error::new(
ErrorKind::Other,
Expand All @@ -157,9 +173,10 @@ mod interface {
#[cfg(feature = "operations")]
mod operations {
use super::common;
use super::common::prefix;
use cmake::Config;
use std::env;
use std::io::{Error, ErrorKind, Result};
use std::io::{Error, ErrorKind, Result, Write};
use std::path::PathBuf;
use walkdir::WalkDir;

Expand Down Expand Up @@ -190,20 +207,8 @@ mod operations {
Ok(mbed_build_path)
}

fn link_to_lib(lib_path: String, link_statically: bool) {
let link_type = if link_statically { "static" } else { "dylib" };

// Request rustc to link the Mbed Crypto library
println!("cargo:rustc-link-search=native={}", lib_path,);
println!("cargo:rustc-link-lib={}=mbedcrypto", link_type);
}

// Build script when the operations feature is on
pub fn script_operations() -> Result<()> {
let lib;
let statically;
let include;

if env::var("MBEDTLS_LIB_DIR").is_err() ^ env::var("MBEDTLS_INCLUDE_DIR").is_err() {
return Err(Error::new(
ErrorKind::Other,
Expand All @@ -216,24 +221,98 @@ mod operations {
if let (Ok(lib_dir), Ok(include_dir)) =
(env::var("MBEDTLS_LIB_DIR"), env::var("MBEDTLS_INCLUDE_DIR"))
{
lib = lib_dir;
include = include_dir;
statically = cfg!(feature = "static") || env::var("MBEDCRYPTO_STATIC").is_ok();
// Request rustc to link the Mbed Crypto library
let link_type = if cfg!(feature = "static") || env::var("MBEDCRYPTO_STATIC").is_ok() {
"static"
} else {
"dylib"
};
println!("cargo:rustc-link-search=native={}", lib_dir);
println!("cargo:rustc-link-lib={}=mbedcrypto", link_type);

common::generate_mbed_crypto_bindings(include_dir.clone())?;
let _ = common::compile_shim_library(include_dir, true)?;
} else {
println!("Did not find environment variables, building MbedTLS!");
let mut mbed_lib_dir = compile_mbed_crypto()?;
let mut mbed_include_dir = mbed_lib_dir.clone();
mbed_lib_dir.push("lib");
mbed_include_dir.push("include");
let main_lib = mbed_lib_dir.join("libmbedcrypto.a");

let include = mbed_include_dir.to_str().unwrap().to_owned();
common::generate_mbed_crypto_bindings(include.clone())?;
let shim_lib = common::compile_shim_library(include, false)?;

// Modify and copy the libraries into a new directory.
let llib_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("llib");
let main_lib_name = prefix() + "mbedcrypto";
let shim_lib_name = prefix() + "shim";
objcopy(vec![
(main_lib, llib_path.join(format!("lib{}.a", main_lib_name))),
(shim_lib, llib_path.join(format!("lib{}.a", shim_lib_name))),
])?;
println!("cargo:rustc-link-search=native={}", llib_path.display());
println!("cargo:rustc-link-lib=static={}", main_lib_name);
println!("cargo:rustc-link-lib=static={}", shim_lib_name);
}

Ok(())
}

pub fn objcopy(liblist: Vec<(PathBuf, PathBuf)>) -> Result<()> {
// Run nm on the source libraries.
let mut args = vec![];
for lib in &liblist {
let (from, _) = &lib;
args.push(from.as_os_str());
}
let output = std::process::Command::new("nm")
.args(args)
.output()
.expect("failed to run nm");
if !output.status.success() {
panic!("nm failed");
}

// Extract globally defined symbols.
let mut syms = vec![];
let re = regex::Regex::new(r"(?m) +[A-TV-Z] +(.+)$").unwrap();
let stdout = String::from_utf8(output.stdout).unwrap();
for (_, [sym]) in re.captures_iter(&stdout).map(|c| c.extract()) {
syms.push(sym);
}

// Generate a file for objcopy containing "old new" in each line.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let prefix = prefix();
let symfile = out_path.join("objcopy_syms");
{
let mut file = std::fs::File::create(&symfile).unwrap();
for sym in syms.iter() {
file.write_all(format!("{} {}{}\n", sym, prefix, sym).as_bytes())
.unwrap();
}
}

lib = mbed_lib_dir.to_str().unwrap().to_owned();
include = mbed_include_dir.to_str().unwrap().to_owned();
statically = true;
for (from, to) in liblist.into_iter() {
std::fs::create_dir_all(to.parent().unwrap())?;

// Run objcopy to copy library and rename symbols.
let status = std::process::Command::new("objcopy")
.args([
"--redefine-syms",
symfile.to_str().unwrap(),
from.to_str().unwrap(),
to.to_str().unwrap(),
])
.status()
.expect("failed to execute process");
if !status.success() {
panic!("objcopy failed");
}
}

// Linking to PSA Crypto library is only needed for the operations.
link_to_lib(lib, statically);
common::generate_mbed_crypto_bindings(include.clone())?;
common::compile_shim_library(include)
Ok(())
}
}
5 changes: 2 additions & 3 deletions psa-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ keywords = ["psa", "crypto", "cryptography", "no_std"]
categories = ["api-bindings", "external-ffi-bindings", "cryptography"]
license = "Apache-2.0"
repository = "https://github.com/parallaxsecond/rust-psa-crypto"
rust-version = "1.58.1"
rust-version = "1.60.0"

[dependencies]
psa-crypto-sys = { path = "../psa-crypto-sys", version = "0.10.0", default-features = false }
# log v0.4.19 requires rustc 1.60.0 or newer
log = ">=0.4.11, <0.4.19"
log = "0.4.20"
serde = { version = "1.0.115", features = ["derive"], default-features = false }
zeroize = { version = "1.4.3", features = ["zeroize_derive"] }

Expand Down