RustPräzi: Representing crates.io as a call-based dependency network
Constructing call-based dependency networks of crates.io as conceptually described in
With RustPräzi, we go from coarse-grained package-based dependency networks (such as what GitHub uses for their vulnerable package detection) to more fine-grained call-based dependency networks. These allow us to track, for example, whether a vulnerable function of a library is actually being used and whether a security warning really needs to be raised. This is much more precise than package-based dependency networks. In fact, RustPräzi makes such analyses a lot more precise (upto 3x).
RustPräzi opens the door to many new or more precise analyses:
rustup
(download at the offical website)config.ini
(root of the repository), specify the path to the uncompressed LLVM binary.conf.ini
file at the root of the project with the following contentencoding=utf-8
[llvm]
# specify the path to the untared LLVM binary folder.
path=/path_where/clang+llvm-4.0.0-[your_platform]
[compiler]
stable=1.23.0
nightly=1.24.0
[storage]
# all data will be stored in this folder
path=/where/you/want/to/store/prazi/data
Since the bitcode generation changed in newer versions of Rust, we advise to stick to the compiler versions specified above.
cargo build --bin prazi --release
./target/release/prazi downloader
Cargo.toml
files (e.g., specifying a non-existent local dependency) by emulating a dry-run of cargo publish
./target/release/prazi rewriter
conf.ini
). To use a nightly version for failing builds, prepend the flag --nightly
./target/release/prazi build-crates
./target/release/prazi build-callgraphs
rustfilt
for demangling of Rust symbolscargo install rustfilt
./create_prazi_graph.sh 2> err.log 1> out.log
Two graphs are generated:
../cdn/graphs/callgraph.ufi.merged.graph
-- the call-based dependency network (CDN)../cdn/graphs/crate.dependency.callgraph.graph
-- the packaged-based dependency network derived from the CDNimport networkx as nx
import re
regex = r"^(.*?) \[label:"
def load_prazi(file):
PRAZI = nx.DiGraph()
with open(file) as f: #callgraph.ufi.merged.graph
for line in f:
if "->" not in line:
g = re.match(regex, line)
if g:
PRAZI.add_node(g.group(1).strip('"'))
else:
print "error, could not extract node: %s" % line
else:
g = re.match('\W*"(.*)" -> "(.*)";', line)
if g:
PRAZI.add_edge(g.group(1), g.group(2))
else:
print "error, could not extract edge: %s" % line
return PRAZI
def load_prazi_dep(file):
PRAZI_DEP = nx.DiGraph()
with open(file) as f: #crate.dependency.callgraph.graph
for line in f:
if "io :: crates :: " in line:
if "->" not in line:
PRAZI_DEP.add_node(line[:-2])
else:
g = re.match('\W*"(.*)" -> "(.*)";', line)
if g and ("io :: crates" in g.group(1) and "io :: crates" in g.group(2)):
PRAZI_DEP.add_edge(g.group(1), g.group(2))
else:
print "skip edge: %s" % line
else:
continue
return PRAZI_DEP
This project is licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in RustPräzi by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.