Skip to content
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
47 changes: 43 additions & 4 deletions cargo-auditable/src/rustc_arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ use std::{ffi::OsString, path::PathBuf};
/// Includes only the rustc arguments we care about
#[derive(Debug)]
pub struct RustcArgs {
pub crate_name: String,
pub crate_name: Option<String>,
pub crate_types: Vec<String>,
pub cfg: Vec<String>,
pub emit: Vec<String>,
pub out_dir: PathBuf,
pub out_dir: Option<PathBuf>,
pub target: Option<String>,
pub print: Vec<String>,
}
Expand Down Expand Up @@ -52,12 +52,12 @@ impl RustcArgs {
}

Ok(RustcArgs {
crate_name: parser.value_from_str("--crate-name")?,
crate_name: parser.opt_value_from_str("--crate-name")?,
crate_types: parser.values_from_str("--crate-type")?,
cfg: parser.values_from_str("--cfg")?,
emit,
out_dir: parser
.value_from_os_str::<&str, PathBuf, pico_args::Error>("--out-dir", |s| {
.opt_value_from_os_str::<&str, PathBuf, pico_args::Error>("--out-dir", |s| {
Ok(PathBuf::from(s))
})?,
target: parser.opt_value_from_str("--target")?,
Expand Down Expand Up @@ -98,6 +98,22 @@ pub fn should_embed_audit_data(args: &RustcArgs) -> bool {
mod tests {
use super::*;

#[test]
fn rustc_vv() {
let raw_rustc_args = vec!["-vV"];
let raw_rustc_args: Vec<OsString> = raw_rustc_args.into_iter().map(|s| s.into()).collect();
let args = RustcArgs::from_vec(raw_rustc_args).unwrap();
assert!(!should_embed_audit_data(&args));
}

#[test]
fn rustc_version_verbose() {
let raw_rustc_args = vec!["--version", "--verbose"];
let raw_rustc_args: Vec<OsString> = raw_rustc_args.into_iter().map(|s| s.into()).collect();
let args = RustcArgs::from_vec(raw_rustc_args).unwrap();
assert!(!should_embed_audit_data(&args));
}

#[test]
fn cargo_c_compatibility() {
let raw_rustc_args = vec!["--crate-name", "rustls", "--edition=2021", "src/lib.rs", "--error-format=json", "--json=diagnostic-rendered-ansi,artifacts,future-incompat", "--crate-type", "staticlib", "--crate-type", "cdylib", "--emit=dep-info,link", "-C", "embed-bitcode=no", "-C", "debuginfo=2", "-C", "link-arg=-Wl,-soname,librustls.so.0.14.0", "-Cmetadata=rustls-ffi", "--cfg", "cargo_c", "--print", "native-static-libs", "--cfg", "feature=\"aws-lc-rs\"", "--cfg", "feature=\"capi\"", "--cfg", "feature=\"default\"", "--check-cfg", "cfg(docsrs)", "--check-cfg", "cfg(feature, values(\"aws-lc-rs\", \"capi\", \"cert_compression\", \"default\", \"no_log_capture\", \"read_buf\", \"ring\"))", "-C", "metadata=b6a43041f637feb8", "--out-dir", "/home/user/Code/rustls-ffi/target/x86_64-unknown-linux-gnu/debug/deps", "--target", "x86_64-unknown-linux-gnu", "-C", "linker=clang", "-C", "incremental=/home/user/Code/rustls-ffi/target/x86_64-unknown-linux-gnu/debug/incremental", "-L", "dependency=/home/user/Code/rustls-ffi/target/x86_64-unknown-linux-gnu/debug/deps", "-L", "dependency=/home/user/Code/rustls-ffi/target/debug/deps", "--extern", "libc=/home/user/Code/rustls-ffi/target/x86_64-unknown-linux-gnu/debug/deps/liblibc-4fc7c9f82dda33ee.rlib", "--extern", "log=/home/user/Code/rustls-ffi/target/x86_64-unknown-linux-gnu/debug/deps/liblog-6f7c8f4d1d5ec422.rlib", "--extern", "rustls=/home/user/Code/rustls-ffi/target/x86_64-unknown-linux-gnu/debug/deps/librustls-a93cda0ba0380929.rlib", "--extern", "pki_types=/home/user/Code/rustls-ffi/target/x86_64-unknown-linux-gnu/debug/deps/librustls_pki_types-27749859644f0979.rlib", "--extern", "rustls_platform_verifier=/home/user/Code/rustls-ffi/target/x86_64-unknown-linux-gnu/debug/deps/librustls_platform_verifier-bceca5cf09f3d7ba.rlib", "--extern", "webpki=/home/user/Code/rustls-ffi/target/x86_64-unknown-linux-gnu/debug/deps/libwebpki-bc4a16dd84e0b062.rlib", "-C", "link-arg=-fuse-ld=/home/user/mold-2.32.0-x86_64-linux/bin/mold", "-L", "native=/home/user/Code/rustls-ffi/target/x86_64-unknown-linux-gnu/debug/build/aws-lc-sys-d52f8990d9ede41d/out"];
Expand All @@ -106,6 +122,29 @@ mod tests {
assert!(should_embed_audit_data(&args));
}

#[test]
fn embed_licensing_compatibility() {
// https://github.com/rust-secure-code/cargo-auditable/issues/198
let raw_rustc_args = vec![
"-",
"--crate-name ___",
"--print=file-names",
"--crate-type bin",
"--crate-type rlib",
"--crate-type dylib",
"--crate-type cdylib",
"--crate-type staticlib",
"--crate-type proc-macro",
"--print=sysroot",
"--print=split-debuginfo",
"--print=crate-name",
"--print=cfg",
];
let raw_rustc_args: Vec<OsString> = raw_rustc_args.into_iter().map(|s| s.into()).collect();
let args = RustcArgs::from_vec(raw_rustc_args).unwrap();
assert!(!should_embed_audit_data(&args));
}

#[test]
fn multiple_emit_values() {
let raw_rustc_args = vec![
Expand Down
111 changes: 48 additions & 63 deletions cargo-auditable/src/rustc_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,74 +19,59 @@ pub fn main(rustc_path: &OsStr) {
// Binaries and C dynamic libraries are not built as non-primary packages,
// so this should not cause issues with Cargo caches.
if env::var_os("CARGO_PRIMARY_PACKAGE").is_some() {
let arg_parsing_result = rustc_arguments::parse_args();
if let Ok(args) = rustc_arguments::parse_args() {
if should_embed_audit_data(&args) {
// Get the audit data to embed
let target_triple = args
.target
.clone()
.unwrap_or_else(|| rustc_host_target_triple(rustc_path));
let contents: Vec<u8> =
collect_audit_data::compressed_dependency_list(&args, &target_triple);
// write the audit info to an object file
let target_info = target_info::rustc_target_info(rustc_path, &target_triple);
let binfile = binary_file::create_binary_file(
&target_info,
&target_triple,
&contents,
"AUDITABLE_VERSION_INFO",
let args = rustc_arguments::parse_args().unwrap(); // descriptive enough message
if should_embed_audit_data(&args) {
// Get the audit data to embed
let target_triple = args
.target
.clone()
.unwrap_or_else(|| rustc_host_target_triple(rustc_path));
let contents: Vec<u8> =
collect_audit_data::compressed_dependency_list(&args, &target_triple);
// write the audit info to an object file
let target_info = target_info::rustc_target_info(rustc_path, &target_triple);
let binfile = binary_file::create_binary_file(
&target_info,
&target_triple,
&contents,
"AUDITABLE_VERSION_INFO",
);
if let Some(file) = binfile {
// Place the audit data in the output dir.
// We can place it anywhere really, the only concern is clutter and name collisions,
// and the target dir is locked so we're probably good
let filename = format!(
"{}_audit_data.o",
args.crate_name
.expect("rustc command is missing --crate-name")
);
if let Some(file) = binfile {
// Place the audit data in the output dir.
// We can place it anywhere really, the only concern is clutter and name collisions,
// and the target dir is locked so we're probably good
let filename = format!("{}_audit_data.o", args.crate_name);
let path = args.out_dir.join(filename);
std::fs::write(&path, file).expect("Unable to write output file");
let path = args
.out_dir
.expect("rustc command is missing --out-dir")
.join(filename);
std::fs::write(&path, file).expect("Unable to write output file");

// Modify the rustc command to link the object file with audit data
let mut linker_command = OsString::from("-Clink-arg=");
linker_command.push(&path);
command.arg(linker_command);
// Prevent the symbol from being removed as unused by the linker
if is_apple(&target_info) {
command.arg("-Clink-arg=-Wl,-u,_AUDITABLE_VERSION_INFO");
} else if is_msvc(&target_info) {
command.arg("-Clink-arg=/INCLUDE:AUDITABLE_VERSION_INFO");
} else if is_wasm(&target_info) {
// We don't emit the symbol name in WASM, so nothing to do
} else {
command.arg("-Clink-arg=-Wl,--undefined=AUDITABLE_VERSION_INFO");
}
// Modify the rustc command to link the object file with audit data
let mut linker_command = OsString::from("-Clink-arg=");
linker_command.push(&path);
command.arg(linker_command);
// Prevent the symbol from being removed as unused by the linker
if is_apple(&target_info) {
command.arg("-Clink-arg=-Wl,-u,_AUDITABLE_VERSION_INFO");
} else if is_msvc(&target_info) {
command.arg("-Clink-arg=/INCLUDE:AUDITABLE_VERSION_INFO");
} else if is_wasm(&target_info) {
// We don't emit the symbol name in WASM, so nothing to do
} else {
// create_binary_file() returned None, indicating an unsupported architecture
eprintln!("WARNING: target '{target_triple}' is not supported by 'cargo auditable'!\n\
The build will continue, but no audit data will be injected into the binary.");
command.arg("-Clink-arg=-Wl,--undefined=AUDITABLE_VERSION_INFO");
}
} else {
// create_binary_file() returned None, indicating an unsupported architecture
eprintln!(
"WARNING: target '{target_triple}' is not supported by 'cargo auditable'!\n\
The build will continue, but no audit data will be injected into the binary."
);
}
} else {
// Failed to parse rustc arguments.

// This may be due to a `rustc -vV` call, or similar non-compilation command.
// This never happens with Cargo - it does call `rustc -vV`,
// but either bypasses the wrapper or doesn't set CARGO_PRIMARY_PACKAGE=true.
// However it does happen with `sccache`:
// https://github.com/rust-secure-code/cargo-auditable/issues/87
// This is probably a bug in `sccache`, but it's easier to fix here.

// There are many non-compilation flags (and they can be compound),
// so parsing them properly adds a lot of complexity.
// So we just check if `--crate-name` is passed and if not,
// assume that it's a non-compilation command.
if env::args_os()
.skip(2)
.any(|arg| arg == OsStr::new("--crate-name"))
{
// this was a compilation command, bail
arg_parsing_result.unwrap();
}
// for commands like `rustc --version` we just pass on the arguments without changes
}
}

Expand Down
Loading