Skip to content

Commit 2a3901c

Browse files
authored
Merge pull request #228 from rust-secure-code/no-cli-assumptions
Do not assume --crate-name and --out-dir are present in the rustc com…
2 parents 1506544 + ddb6551 commit 2a3901c

File tree

1 file changed

+100
-72
lines changed

1 file changed

+100
-72
lines changed

cargo-auditable/src/rustc_wrapper.rs

Lines changed: 100 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -14,78 +14,10 @@ use crate::{
1414
use std::io::BufRead;
1515

1616
pub fn main(rustc_path: &OsStr) {
17-
let mut command = rustc_command(rustc_path);
18-
19-
// Binaries and C dynamic libraries are not built as non-primary packages,
20-
// so this should not cause issues with Cargo caches.
21-
if env::var_os("CARGO_PRIMARY_PACKAGE").is_some() {
22-
let args = rustc_arguments::parse_args().unwrap(); // descriptive enough message
23-
if should_embed_audit_data(&args) {
24-
// Get the audit data to embed
25-
let target_triple = args
26-
.target
27-
.clone()
28-
.unwrap_or_else(|| rustc_host_target_triple(rustc_path));
29-
let contents: Vec<u8> =
30-
collect_audit_data::compressed_dependency_list(&args, &target_triple);
31-
// write the audit info to an object file
32-
let target_info = target_info::rustc_target_info(rustc_path, &target_triple);
33-
let binfile = binary_file::create_binary_file(
34-
&target_info,
35-
&target_triple,
36-
&contents,
37-
"AUDITABLE_VERSION_INFO",
38-
);
39-
if let Some(file) = binfile {
40-
// Place the audit data in the output dir.
41-
// We can place it anywhere really, the only concern is clutter and name collisions,
42-
// and the target dir is locked so we're probably good
43-
let filename = format!(
44-
"{}_audit_data.o",
45-
args.crate_name
46-
.as_ref()
47-
.expect("rustc command is missing --crate-name")
48-
);
49-
let path = args
50-
.out_dir
51-
.as_ref()
52-
.expect("rustc command is missing --out-dir")
53-
.join(filename);
54-
std::fs::write(&path, file).expect("Unable to write output file");
55-
56-
// Modify the rustc command to link the object file with audit data
57-
let mut linker_command = OsString::from("-Clink-arg=");
58-
linker_command.push(&path);
59-
command.arg(linker_command);
60-
// Prevent the symbol from being removed as unused by the linker
61-
if is_apple(&target_info) {
62-
if args.bare_linker() {
63-
command.arg("-Clink-arg=-u,_AUDITABLE_VERSION_INFO");
64-
} else {
65-
command.arg("-Clink-arg=-Wl,-u,_AUDITABLE_VERSION_INFO");
66-
}
67-
} else if is_msvc(&target_info) {
68-
command.arg("-Clink-arg=/INCLUDE:AUDITABLE_VERSION_INFO");
69-
} else if is_wasm(&target_info) {
70-
// We don't emit the symbol name in WASM, so nothing to do
71-
} else {
72-
// Unrecognized platform, assume it to be unix-like
73-
#[allow(clippy::collapsible_else_if)]
74-
if args.bare_linker() {
75-
command.arg("-Clink-arg=--undefined=AUDITABLE_VERSION_INFO");
76-
} else {
77-
command.arg("-Clink-arg=-Wl,--undefined=AUDITABLE_VERSION_INFO");
78-
}
79-
}
80-
} else {
81-
// create_binary_file() returned None, indicating an unsupported architecture
82-
eprintln!(
83-
"WARNING: target '{target_triple}' is not supported by 'cargo auditable'!\n\
84-
The build will continue, but no audit data will be injected into the binary."
85-
);
86-
}
87-
}
88-
}
17+
let mut command = match rustc_command_with_audit_data(rustc_path) {
18+
Some(cmd) => cmd,
19+
None => rustc_command(rustc_path), // could not construct command that injects audit data, skip it
20+
};
8921

9022
// Invoke rustc
9123
let results = command.status().unwrap_or_else(|err| {
@@ -127,3 +59,99 @@ fn rustc_host_target_triple(rustc_path: &OsStr) -> String {
12759
.map(|l| l[6..].to_string())
12860
.expect("Failed to parse rustc output to determine the current platform. Please report this bug!")
12961
}
62+
63+
fn rustc_command_with_audit_data(rustc_path: &OsStr) -> Option<Command> {
64+
let mut command = rustc_command(rustc_path);
65+
66+
// Only inject audit data if CARGO_PRIMARY_PACKAGE is set.
67+
// This allows linking audit data only in toplevel binaries, not intermediate artifacts.
68+
//
69+
// Binaries and C dynamic libraries are not built as non-primary packages,
70+
// so this should not cause issues with Cargo caches.
71+
#[allow(clippy::question_mark)]
72+
if env::var_os("CARGO_PRIMARY_PACKAGE").is_none() {
73+
return None;
74+
}
75+
let args = rustc_arguments::parse_args().unwrap(); // descriptive enough message
76+
if !should_embed_audit_data(&args) {
77+
return None;
78+
}
79+
// Get the audit data to embed
80+
let target_triple = args
81+
.target
82+
.clone()
83+
.unwrap_or_else(|| rustc_host_target_triple(rustc_path));
84+
let contents: Vec<u8> = collect_audit_data::compressed_dependency_list(&args, &target_triple);
85+
86+
// write the audit info to an object file
87+
let target_info = target_info::rustc_target_info(rustc_path, &target_triple);
88+
let binfile = binary_file::create_binary_file(
89+
&target_info,
90+
&target_triple,
91+
&contents,
92+
"AUDITABLE_VERSION_INFO",
93+
);
94+
if let Some(file) = binfile {
95+
// Place the audit data in the output dir.
96+
// We can place it anywhere really, the only concern is clutter and name collisions,
97+
// and the target dir is locked so we're probably good
98+
let crate_name = match args.crate_name.as_deref() {
99+
Some(name) => name,
100+
None => {
101+
eprintln!(
102+
"WARNING: cargo-auditable: rustc command is missing --crate-name\n\
103+
Please double-check that the audit data was injected into the binary.\n\
104+
If it wasn't, please report a bug."
105+
);
106+
return None;
107+
}
108+
};
109+
let out_dir = match args.out_dir.as_deref() {
110+
Some(name) => name,
111+
None => {
112+
eprintln!(
113+
"WARNING: cargo-auditable: rustc command is missing --out-dir\n\
114+
Please double-check that the audit data was injected into the binary.\n\
115+
If it wasn't, please report a bug."
116+
);
117+
return None;
118+
}
119+
};
120+
let filename = format!("{crate_name}_audit_data.o");
121+
let path = out_dir.join(filename);
122+
std::fs::write(&path, file).expect("Unable to write output file");
123+
124+
// Modify the rustc command to link the object file with audit data
125+
let mut linker_command = OsString::from("-Clink-arg=");
126+
linker_command.push(&path);
127+
command.arg(linker_command);
128+
// Prevent the symbol from being removed as unused by the linker
129+
if is_apple(&target_info) {
130+
if args.bare_linker() {
131+
command.arg("-Clink-arg=-u,_AUDITABLE_VERSION_INFO");
132+
} else {
133+
command.arg("-Clink-arg=-Wl,-u,_AUDITABLE_VERSION_INFO");
134+
}
135+
} else if is_msvc(&target_info) {
136+
command.arg("-Clink-arg=/INCLUDE:AUDITABLE_VERSION_INFO");
137+
} else if is_wasm(&target_info) {
138+
// We don't emit the symbol name in WASM, so nothing to do
139+
} else {
140+
// Unrecognized platform, assume it to be unix-like
141+
#[allow(clippy::collapsible_else_if)]
142+
if args.bare_linker() {
143+
command.arg("-Clink-arg=--undefined=AUDITABLE_VERSION_INFO");
144+
} else {
145+
command.arg("-Clink-arg=-Wl,--undefined=AUDITABLE_VERSION_INFO");
146+
}
147+
}
148+
Some(command)
149+
} else {
150+
// create_binary_file() returned None, indicating an unsupported architecture
151+
eprintln!(
152+
"WARNING: cargo-auditable: target '{target_triple}' is not supported!\n\
153+
The build will continue, but no audit data will be injected into the binary."
154+
);
155+
None
156+
}
157+
}

0 commit comments

Comments
 (0)