Skip to content
498 changes: 290 additions & 208 deletions Cargo.lock

Large diffs are not rendered by default.

40 changes: 20 additions & 20 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
[package]
name = "cargo-acl"
version = "0.8.0"
edition = "2021"
rust-version = "1.74"
edition = "2024"
rust-version = "1.95"
license = "MIT OR Apache-2.0"
description = "A Rust code ACL checker"
readme = "README.md"
repository = "https://github.com/cackle-rs/cackle"
keywords = ["cargo", "plugin", "security", "supply-chain"]

[dependencies]
anyhow = "1.0.33"
clap = { version = "4.2.1", features = [ "derive" ] }
serde = { version = "1.0.136", features = [ "derive", "rc" ] }
toml = "0.8.0"
serde_json = "1.0.95"
cargo_metadata = "0.18.0"
object = "0.32.0"
anyhow = "1.0.102"
clap = { version = "4.6.1", features = [ "derive" ] }
serde = { version = "1.0.228", features = [ "derive", "rc" ] }
toml = "0.8.23"
serde_json = "1.0.149"
cargo_metadata = "0.18.1"
object = "0.32.2"
ar = "0.9.0"
gimli = { version = "0.28.0", default-features = false, features = ["read"] }
rustc-demangle = "0.1.22"
once_cell = "1.17.1"
is-terminal = "0.4.8"
colored = "2.0.0"
rustc-ap-rustc_lexer = "727.0.0"
indoc = "2.0.1"
log = { version = "0.4.19", features = [ "std" ] }
gimli = { version = "0.28.1", default-features = false, features = ["read"] }
rustc-demangle = "0.1.27"
once_cell = "1.21.4"
is-terminal = "0.4.17"
colored = "2.2.0"
ra-ap-rustc_lexer = "0.162.0"
indoc = "2.0.7"
log = { version = "0.4.29", features = [ "std" ] }
addr2line = { version = "0.21.0", default-features = false, features = [ "std" ] }
tempfile = "3.6.0"
fxhash = "0.2.1"
tempfile = "3.27.0"
rustc-hash = "2.1.2"
tui-input = "0.8.0"
toml_edit = { version = "0.20.0" }
toml_edit = { version = "0.20.7" }

ratatui = { version = "0.24.0", optional = true }
diff = { version = "0.1.13", optional = true }
Expand Down
19 changes: 13 additions & 6 deletions cackle.toml
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,6 @@ allow_unsafe = true
[pkg.clap_lex]
allow_unsafe = true

[pkg.ryu]
allow_unsafe = true

[pkg.itoa]
allow_unsafe = true

Expand Down Expand Up @@ -267,6 +264,7 @@ test.sandbox.make_writable = [
"test_crates/custom_target_dir",
]
test.sandbox.allow_network = true
test.allow_unsafe = true

[pkg.clap_builder]
allow_apis = [
Expand Down Expand Up @@ -326,9 +324,6 @@ allow_unsafe = true

[pkg.getrandom]
allow_unsafe = true
build.allow_apis = [
"process",
]

[pkg.serde_core]
allow_unsafe = true
Expand All @@ -346,3 +341,15 @@ build.allow_apis = [

[pkg.simd-adler32]
allow_unsafe = true

[pkg.wit-bindgen-rust-macro]
allow_proc_macro = true

[pkg.zmij]
build.allow_apis = [
"process",
]
allow_unsafe = true

[pkg.errno]
allow_unsafe = true
12 changes: 6 additions & 6 deletions src/build_script_checker.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::config::permissions::PermSel;
use crate::config::Config;
use crate::config::permissions::PermSel;
use crate::crate_index::PackageId;
use crate::problem::DisallowedBuildInstruction;
use crate::problem::Problem;
Expand Down Expand Up @@ -41,10 +41,10 @@ impl BuildScriptReport {
allow_build_instructions,
));
}
if let Some(rest) = line.strip_prefix("cargo:rustc-env=") {
if let Some((var_name, _value)) = rest.split_once('=') {
report.env_vars.push(var_name.to_owned());
}
if let Some(rest) = line.strip_prefix("cargo:rustc-env=")
&& let Some((var_name, _value)) = rest.split_once('=')
{
report.env_vars.push(var_name.to_owned());
}
}
Ok(report)
Expand Down Expand Up @@ -96,8 +96,8 @@ fn matches(instruction: &str, rule: &str) -> bool {
mod tests {
use crate::config;
use crate::config::SandboxConfig;
use crate::crate_index::testing::pkg_id;
use crate::crate_index::CrateSel;
use crate::crate_index::testing::pkg_id;
use crate::problem::DisallowedBuildInstruction;
use crate::problem::Problem;
use crate::problem::ProblemList;
Expand Down
76 changes: 37 additions & 39 deletions src/checker.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::Args;
use crate::CheckState;
use crate::build_script_checker;
use crate::config::permissions::PermSel;
use crate::config::permissions::PermissionScope;
use crate::config::ApiName;
use crate::config::Config;
use crate::config::permissions::PermSel;
use crate::config::permissions::PermissionScope;
use crate::crate_index::CrateIndex;
use crate::crate_index::CrateKind;
use crate::crate_index::PackageId;
Expand All @@ -20,20 +22,18 @@ use crate::proxy::cargo::profile_name;
use crate::proxy::rpc;
use crate::proxy::rpc::UnsafeUsage;
use crate::proxy::subprocess::SubprocessConfig;
use crate::symbol_graph::backtrace::Backtracer;
use crate::symbol_graph::NameSource;
use crate::symbol_graph::UsageDebugData;
use crate::symbol_graph::backtrace::Backtracer;
use crate::timing::TimingCollector;
use crate::tmpdir::TempDir;
use crate::Args;
use crate::CheckState;
use anyhow::anyhow;
use anyhow::bail;
use anyhow::Context;
use anyhow::Result;
use fxhash::FxHashMap;
use fxhash::FxHashSet;
use anyhow::anyhow;
use anyhow::bail;
use log::info;
use rustc_hash::FxHashMap;
use rustc_hash::FxHashSet;
use std::borrow::Cow;
use std::path::Path;
use std::path::PathBuf;
Expand Down Expand Up @@ -413,12 +413,12 @@ impl Checker {
) -> Result<()> {
let api = &api_usage.api_name;
let perm_sel = api_usage.perm_sel();
if let Some(crate_info) = self.crate_infos.get_mut(&perm_sel) {
if crate_info.allowed_apis.contains(api) {
crate_info.unused_allowed_apis.remove(api);
self.mark_parent_allow_apis_used(api, &perm_sel);
return Ok(());
}
if let Some(crate_info) = self.crate_infos.get_mut(&perm_sel)
&& crate_info.allowed_apis.contains(api)
{
crate_info.unused_allowed_apis.remove(api);
self.mark_parent_allow_apis_used(api, &perm_sel);
return Ok(());
}

// Partition all usages into on-tree and off-tree usages. On-tree are those usages that are
Expand All @@ -430,25 +430,24 @@ impl Checker {
let all_deps = self.crate_index.name_prefix_to_pkg_id();
if let Some(crate_deps) = self.crate_index.transitive_deps(&api_usage.pkg_id) {
for usage in &api_usage.usages {
if let Some(first_name_part) = usage.to_name.parts.first() {
if !crate_deps.contains(first_name_part) {
if let Some(pkg_id) = all_deps.get(first_name_part) {
// If we detect an off-tree usage where the outer function/variable is
// defined by crate that also defined the restricted API that's being
// accessed, then we ignore it completely.
//
// This can happen if for example a macro defines a variable that is
// then referenced by an inlined function. The macro and the inlined
// function can both be from leaf crates, while the code calling the
// macro is from a higher level crate that provides a restricted API.
// The end effect is that it looks like the inlined function is
// referencing the restricted API.
if !self.is_to_name_from_outer_location(usage)? {
off_tree.entry(pkg_id).or_default().push(usage.clone());
}
continue;
}
if let Some(first_name_part) = usage.to_name.parts.first()
&& !crate_deps.contains(first_name_part)
&& let Some(pkg_id) = all_deps.get(first_name_part)
{
// If we detect an off-tree usage where the outer function/variable is
// defined by crate that also defined the restricted API that's being
// accessed, then we ignore it completely.
//
// This can happen if for example a macro defines a variable that is
// then referenced by an inlined function. The macro and the inlined
// function can both be from leaf crates, while the code calling the
// macro is from a higher level crate that provides a restricted API.
// The end effect is that it looks like the inlined function is
// referencing the restricted API.
if !self.is_to_name_from_outer_location(usage)? {
off_tree.entry(pkg_id).or_default().push(usage.clone());
}
continue;
}
on_tree.push(usage.clone());
}
Expand Down Expand Up @@ -566,12 +565,11 @@ impl Checker {
continue;
}
}
if let Some(api_config) = self.config.raw.apis.get(&p.api) {
if api_config.no_auto_detect.contains(&perm_sel.package_name)
|| api_config.include.contains(&p.api_path())
{
continue;
}
if let Some(api_config) = self.config.raw.apis.get(&p.api)
&& (api_config.no_auto_detect.contains(&perm_sel.package_name)
|| api_config.include.contains(&p.api_path()))
{
continue;
}
problems.push(Problem::PossibleExportedApi(p.clone()));
}
Expand Down
4 changes: 2 additions & 2 deletions src/checker/api_map.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::config::ApiName;
use fxhash::FxHashMap;
use fxhash::FxHashSet;
use rustc_hash::FxHashMap;
use rustc_hash::FxHashSet;

/// A map from a path prefix to a set of APIs. Stored as a tree where each level of the tree does
/// lookup for the next part of the name. e.g. `std::path::PathBuf` would be stored as a tree with 4
Expand Down
2 changes: 1 addition & 1 deletion src/checker/common_prefix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::demangle::DemangleToken;
use crate::names::NamesIterator;
use crate::names::SymbolOrDebugName;
use anyhow::Result;
use fxhash::FxHashSet;
use rustc_hash::FxHashSet;

/// Returns a list of name prefixes that are common to all of the from-names in the supplied API
/// usages. These are candidates for names that are missing from an API when an off-tree usage is
Expand Down
16 changes: 9 additions & 7 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use crate::crate_index::PackageId;
use crate::problem::AvailableApi;
use crate::problem::Problem;
use crate::problem::ProblemList;
use anyhow::anyhow;
use anyhow::bail;
use anyhow::Context;
use anyhow::Result;
use anyhow::anyhow;
use anyhow::bail;
use serde::Deserialize;
use serde::Serialize;
use std::collections::BTreeMap;
Expand Down Expand Up @@ -465,8 +465,8 @@ pub(crate) mod testing {
#[cfg(test)]
mod tests {
use super::testing::parse;
use crate::config::permissions::PermSel;
use crate::config::SandboxKind;
use crate::config::permissions::PermSel;

#[test]
fn empty() {
Expand Down Expand Up @@ -533,10 +533,12 @@ mod tests {
"#,
)
.unwrap();
assert!(config
.permissions
.get(&PermSel::for_build_script("foo"))
.is_some());
assert!(
config
.permissions
.get(&PermSel::for_build_script("foo"))
.is_some()
);
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion src/config/permissions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::crate_index::CrateKind;
use crate::crate_index::CrateSel;
use crate::crate_index::PackageId;
use anyhow::Result;
use fxhash::FxHashMap;
use rustc_hash::FxHashMap;
use serde::Deserialize;
use serde::Serialize;
use std::fmt::Display;
Expand Down
20 changes: 10 additions & 10 deletions src/config_editor.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
//! This module is responsible for applying automatic edits to cackle.toml.

use crate::checker::common_prefix::common_to_prefixes;
use crate::config::permissions::PermSel;
use crate::config::versions::Version;
use crate::config::ApiName;
use crate::config::ApiPath;
use crate::config::Config;
use crate::config::PackageName;
use crate::config::SandboxKind;
use crate::config::permissions::PermSel;
use crate::config::versions::Version;
use crate::problem::ApiUsages;
use crate::problem::AvailableApi;
use crate::problem::PossibleExportedApi;
use crate::problem::Problem;
use crate::problem::ProblemList;
use crate::problem::UnusedAllowApi;
use anyhow::anyhow;
use anyhow::Result;
use anyhow::anyhow;
use std::borrow::Borrow;
use std::borrow::Cow;
use std::fmt::Display;
Expand Down Expand Up @@ -1118,10 +1118,10 @@ fn set_table_value(
opts: &EditOpts,
) {
table[key] = item;
if let Some(comment) = &opts.comment {
if let Some(decor) = table.key_decor_mut(key) {
*decor = toml_edit::Decor::new(format!("# {comment}\n"), " ");
}
if let Some(comment) = &opts.comment
&& let Some(decor) = table.key_decor_mut(key)
{
*decor = toml_edit::Decor::new(format!("# {comment}\n"), " ");
}
}

Expand All @@ -1130,15 +1130,15 @@ mod tests {
use super::ConfigEditor;
use super::Edit;
use super::InlineStdApi;
use crate::config::permissions::PermSel;
use crate::config::permissions::PermissionScope;
use crate::config::ApiName;
use crate::config::Config;
use crate::config::SandboxConfig;
use crate::config::permissions::PermSel;
use crate::config::permissions::PermissionScope;
use crate::config_editor::fixes_for_problem;
use crate::crate_index::testing::pkg_id;
use crate::crate_index::CrateSel;
use crate::crate_index::PackageId;
use crate::crate_index::testing::pkg_id;
use crate::location::SourceLocation;
use crate::problem::ApiUsages;
use crate::problem::DisallowedBuildInstruction;
Expand Down
2 changes: 1 addition & 1 deletion src/config_validation.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::config::ApiName;
use crate::config::Config;
use crate::config::MAX_VERSION;
use fxhash::FxHashSet;
use rustc_hash::FxHashSet;
use std::fmt::Display;
use std::path::Path;
use std::path::PathBuf;
Expand Down
Loading