Giter VIP home page Giter VIP logo

cackle's Introduction

Cackle / cargo acl

A code ACL checker for Rust.

Cackle is a tool to analyse the transitive dependencies of your crate to see what kinds of APIs each crate uses.

The idea is look for crates that are using APIs that you don't think they should be using. For example a crate that from its description should just be doing some data processing, but is actually using network APIs.

Installation

Currently Cackle only works on Linux. See PORTING.md for more details.

cargo install --locked cargo-acl

Or if you'd like to install from git:

cargo install --locked --git https://github.com/cackle-rs/cackle.git cargo-acl

Installing bubblewrap is recommended as it allows build scripts (build.rs), tests and rustc to be run inside a sandbox.

On systems with apt, this can be done by running:

sudo apt install bubblewrap

Usage

From the root of your project (the directory containing Cargo.toml), run:

cargo acl

This will interactively guide you through creating an initial cackle.toml. Some manual editing of your cackle.toml is recommended. In particular, you should look through your dependency tree and think about which crates export APIs that you'd like to restrict. e.g. if you're using a crate that provides network APIs, you should declare this in your config. See CONFIG.md for more details.

Running from CI

Cackle can be run from GitHub actions. See the instructions in the cackle-action repository.

Features

  • Checks what APIs are used by each crate in your dependency tree.
  • Ignores dead code, so if a crate uses an API, but in code that isn't called in your binary, then it doesn't count.
  • Restrict which crates are allowed to use unsafe.
  • A terminal UI that shows problems as they're found.
    • Preview the source where the API usage or unsafe was detected.
    • For API usages, show a backtrace of how that code is reachable.
    • Select from several edits that can be applied to your config file to allow the usage.
  • Can run build scripts, tests in a sandbox to restrict network and filesystem access.
  • The sandbox for each build script is configured separately, so if one build script needs extra access you can grant it to just that build script.
  • Can run rustc in a sandbox, thus sandboxing all proc macros. This however is currently not granular, so if one proc macro needs more access it needs to be granted to all. Fortunately proc macros that need network access are relatively rare.

Limitations and precautions

  • A proc macro might detect that it's being run under Cackle and emit different code.
  • Even without proc macros, a crate may only use problematic APIs only in certain configurations that don't match the configuration used when you run Cackle.
  • This tool is intended to supplement and aid manual review of 3rd party code, not replace it.
  • Your configuration might miss defining an API provided by a crate as falling into a certain category that you care about.
  • There are undoubtedly countless ways that a determined person could circumvent detection that they're using some APIs. With time we may try to prevent such circumventions, but for now, you should definitely assume that circumvention is possible.

With all these limitations, what's the point? The goal really is to just raise the bar for what's required to sneak problematic code unnoticed into some package. Use of Cackle should not replace any manual code reviews of your dependencies that you would otherwise have done.

How it works

See HOW_IT_WORKS.md.

FAQ

FAQ

Contributing

Contributions are very welcome. If you'd like to get involved, please reach out either by filing an issue or emailing David Lattimore (email address is in the commit log).

License

This software is distributed under the terms of both the MIT license and the Apache License (Version 2.0).

See LICENSE for details.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

cackle's People

Contributors

daveed07 avatar davidlattimore avatar pinkforest avatar teromene avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

cackle's Issues

Display code snippets with syntax highlighting

Would be nice to show the code diffs in the "Usage details" window with colored syntax highlighting to more easily be able to read it, esp. as one may be scanning through quite a lot of diffs when triaging with this tool. Though not a high priority as would just be a "nice to have".

Believe seen some Rust syntax highlighting crate that may be easy to integrate

Incorrect `net` API attribution to `futures-util` crate

In one of our bigger projects where we use hyper, rustls, we get this problem highlighted by cackle attributed to the futures-util crate, but as far as I can see it doesn't use any of the std::net functions. But it is a generic type here that are used in other crates with their network types.


ERROR: 'futures-util' uses disallowed APIs:
  net:
    /home/repi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-util-0.3.28/src/future/future/map.rs
      <futures_util::future::future::map::Map<Fut,F> as core::future::future::Future>::poll
        -> call_once<hyper::client::client::{impl#3}::connect_to::{closure#0}::{closure_env#0}<hyper_rustls::connector::HttpsConnector<hyper::client::connect::http::HttpConnector<hyper::client::connect::dns::GaiResolver>>, http_body::full::Full<bytes::bytes::Bytes>>, hyper_rustls::stream::MaybeHttpsStream<tokio::net::tcp::stream::TcpStream>, hyper::error::Error> [57:73]
        -> core::ptr::drop_in_place<core::result::Result<hyper_rustls::stream::MaybeHttpsStream<tokio::net::tcp::stream::TcpStream>,hyper::error::Error>> [60:13]
    /home/repi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-util-0.3.28/src/future/select.rs
      futures_util::future::select::select
        -> assert_future<futures_util::future::either::Either<(core::result::Result<tokio::net::tcp::stream::TcpStream, hyper::client::connect::http::ConnectError>, core::pin::Pin<&mut hyper::client::connect::http::{impl#14}::connect::{async_fn_env#0}>), (core::result::Result<tokio::net::tcp::stream::TcpStream, hyper::client::connect::http::ConnectError>, core::pin::Pin<&mut hyper::client::connect::http::{impl#14}::connect::{async_fn_env#0}>)>, futures_util::future::select::Select<core::pin::Pin<&mut hyper::client::connect::http::{impl#14}::connect::{async_fn_env#0}>, core::pin::Pin<&mut hyper::client::connect::http::{impl#14}::connect::{async_fn_env#0}>>> [89:5]
      futures_util::future::select::select
        -> assert_future<futures_util::future::either::Either<(core::result::Result<tokio::net::tcp::stream::TcpStream, hyper::client::connect::http::ConnectError>, core::pin::Pin<&mut tokio::time::sleep::Sleep>), ((), core::pin::Pin<&mut hyper::client::connect::http::{impl#14}::connect::{async_fn_env#0}>)>, futures_util::future::select::Select<core::pin::Pin<&mut hyper::client::connect::http::{impl#14}::connect::{async_fn_env#0}>, core::pin::Pin<&mut tokio::time::sleep::Sleep>>> [89:5]
      <futures_util::future::select::Select<A,B> as core::future::future::Future>::poll
        -> core::ptr::drop_in_place<core::result::Result<tokio::net::tcp::stream::TcpStream,hyper::client::connect::http::ConnectError>> [115:85]
        -> core::ptr::drop_in_place<core::task::poll::Poll<core::result::Result<tokio::net::tcp::stream::TcpStream,hyper::client::connect::http::ConnectError>>> [116:9]
      <futures_util::future::select::Select<A,B> as core::future::future::Future>::poll
        -> core::ptr::drop_in_place<core::task::poll::Poll<core::result::Result<tokio::net::tcp::stream::TcpStream,hyper::client::connect::http::ConnectError>>> [116:9]
        -> core::ptr::drop_in_place<core::task::poll::Poll<core::result::Result<tokio::net::tcp::stream::TcpStream,hyper::client::connect::http::ConnectError>>> [120:9]
        -> core::ptr::drop_in_place<core::result::Result<tokio::net::tcp::stream::TcpStream,hyper::client::connect::http::ConnectError>> [119:86]
        -> core::ptr::drop_in_place<core::result::Result<tokio::net::tcp::stream::TcpStream,hyper::client::connect::http::ConnectError>> [115:85]
    /home/repi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-util-0.3.28/src/future/try_future/into_future.rs
      <futures_util::future::try_future::into_future::IntoFuture<Fut> as core::future::future::Future>::poll
        -> try_poll<futures_util::future::try_future::MapErr<hyper::service::oneshot::Oneshot<hyper_rustls::connector::HttpsConnector<hyper::client::connect::http::HttpConnector<hyper::client::connect::dns::GaiResolver>>, http::uri::Uri>, fn(alloc::boxed::Box<(dyn core::error::Error + core::marker::Send + core::marker::Sync), alloc::alloc::Global>) -> hyper::error::Error>, hyper_rustls::stream::MaybeHttpsStream<tokio::net::tcp::stream::TcpStream>, hyper::error::Error> [34:9]
      <futures_util::future::try_future::into_future::IntoFuture<Fut> as core::future::future::Future>::poll
        -> try_poll<hyper::service::oneshot::Oneshot<hyper_rustls::connector::HttpsConnector<hyper::client::connect::http::HttpConnector<hyper::client::connect::dns::GaiResolver>>, http::uri::Uri>, hyper_rustls::stream::MaybeHttpsStream<tokio::net::tcp::stream::TcpStream>, alloc::boxed::Box<(dyn core::error::Error + core::marker::Send + core::marker::Sync), alloc::alloc::Global>> [34:9]
    /home/repi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-util-0.3.28/src/future/try_future/mod.rs
      futures_util::future::try_future::TryFutureExt::map_err
        -> assert_future<core::result::Result<hyper_rustls::stream::MaybeHttpsStream<tokio::net::tcp::stream::TcpStream>, hyper::error::Error>, futures_util::future::try_future::MapErr<hyper::service::oneshot::Oneshot<hyper_rustls::connector::HttpsConnector<hyper::client::connect::http::HttpConnector<hyper::client::connect::dns::GaiResolver>>, http::uri::Uri>, fn(alloc::boxed::Box<(dyn core::error::Error + core::marker::Send + core::marker::Sync), alloc::alloc::Global>) -> hyper::error::Error>> [313:9]
    /home/repi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-util-0.3.28/src/lib.rs
      <futures_util::future::future::Map<Fut,F> as core::future::future::Future>::poll
        -> poll<futures_util::future::try_future::into_future::IntoFuture<hyper::service::oneshot::Oneshot<hyper_rustls::connector::HttpsConnector<hyper::client::connect::http::HttpConnector<hyper::client::connect::dns::GaiResolver>>, http::uri::Uri>>, futures_util::fns::MapErrFn<fn(alloc::boxed::Box<(dyn core::error::Error + core::marker::Send + core::marker::Sync), alloc::alloc::Global>) -> hyper::error::Error>, core::result::Result<hyper_rustls::stream::MaybeHttpsStream<tokio::net::tcp::stream::TcpStream>, hyper::error::Error>> [91:13]

So believe the detection of this using net APIs is correct, but not for this crate, it should have been attributed to the crate using the generic type. So maybe a problem with handling/parsing of generic types and which crates get assigned the "problem"?

cargo cackle [..]

Would it make sense to add cargo sub-command so it can be integrated with cargo ?

This is how we do it with e.g. cargo-geiger, audit, deny, hack etc.

cargo acl fails to build

Hello, I tried cargo acn but it fails compiling with:

error: extern location for autocfg does not exist: /home/mrcool/dev/rust/cargo_target_dir/cackle/deps/libautocfg-95fddeba77b8019b.rlib
 --> /home/mrcool/.cargo/registry/src/index.crates.io-6f17d22bba15001f/lock_api-0.4.10/build.rs:2:15
  |
2 |     let cfg = autocfg::new();
  |               ^^^^^^^

error: could not compile `lock_api` (build script) due to previous error
warning: build failed, waiting for other jobs to finish...

Error: `cargo` exited with non-zero exit status

"Namespace missing name attribute" failure

Using latest v0.1.1 released version runs fine on our project, but wanted to try out the latest version from git and when running that it aborts on this error:

$ cackle ui
Namespace missing name attribute

Saw that was introduced in 705c657, so tested running the commit just before that 6328b15 and it works fine:

$ cackle ui
Completed successfully for configuration /home/repi/git/embark/ark/cackle.toml
num_packages: 897
no_special_permissions: 401

Any ideas if there is an issue with the parsing there or are there new requirements/configuration needed from that version? And let me know if there is any more information I can provide that would be of help!

should std::path not require`fs` permission ?

I feel like this is not needed, I expected fs permission for only manipulating files like reads/writes etc, but requires fs permission just for creating paths from strings seems to much in my opinion.

Analyzing `--release` profile of binaries

Is there an option to analyze the builds from --release mode instead of the ordinary debug mode? typically they are the same but can and are differences between them and generally is the --release binaries that are used for users, and that have highest security importance.

Could see it being of interest to analyze multiple profiles, just to be safe, and to cover potential custom Cargo profiles also.

Example

One concrete "issue" I ran into that motivated this was with @nical's lyon_tessellation crate that in debug-only reads an environment variable and as such uses env capability/API:

image

https://github.com/nical/lyon/blob/529a166dbccd1560b1c8e30387508f332e662609/crates/tessellation/src/fill.rs#L549

I could ofc all the env capability to the this crate in our config, but as this is only for debug builds and not our --release builds I would like to avoid that.

Disabling sandboxing on non-build scripts?

hi, thanks for an interesting and nicely complementary tool! (we built cargo-deny that does dependency graph linting)

tested using cackle on one of our larger projects and one problem ran into was that crates that use system libraries such as gdk-sys & pango-sys fail to build when sandboxing is enabled. But it also does not seem to be possible to disable sandboxing on non-build scripts? which I believe is needed for this so the build can use its system library, and hope could be supported.

This is the the error we run into with sandboxing enabled:

image

but if I add:

[pkg.pango-sys]
sandbox.kind = "Disabled"

we fail on:

$ cackle ui
Invalid config /home/repi/git/embark/ark/cackle.toml
  Sandbox config for regular package `pango-sys` isn't permitted

Duplicate listings of problems

Noticed that on our big project the same "problem" gets listed multiple times, which is confusing. Example:

image

we are using:

[common]
version = 1
import_std = ["fs", "net", "process", "env", "terminate"]
build_flags = []

is this an artifact of how the tool works, or is it missing some de-duplication in its analysis or display?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.