Skip to content

Commit

Permalink
Merge pull request #89 from owasp-dep-scan/feature/rust-binary-part2
Browse files Browse the repository at this point in the history
Recover dependency tree for rust
  • Loading branch information
prabhu authored Apr 21, 2024
2 parents 82eb390 + e7a1259 commit d572f2d
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 63 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ LABEL maintainer="appthreat" \
org.opencontainers.image.authors="Team AppThreat <cloud@appthreat.com>" \
org.opencontainers.image.source="https://github.com/owasp-dep-scan/blint" \
org.opencontainers.image.url="https://github.com/owasp-dep-scan/blint" \
org.opencontainers.image.version="2.0.x" \
org.opencontainers.image.version="2.1.x" \
org.opencontainers.image.vendor="OWASP" \
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.title="blint" \
Expand Down
8 changes: 1 addition & 7 deletions blint/android.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,7 @@

ANDROID_HOME = os.getenv("ANDROID_HOME")
APKANALYZER_CMD = os.getenv("APKANALYZER_CMD")
if (
not APKANALYZER_CMD
and ANDROID_HOME
and (
os.path.exists(os.path.join(ANDROID_HOME, "cmdline-tools", "latest", "bin", "apkanalyzer"))
)
):
if not APKANALYZER_CMD and ANDROID_HOME and os.path.exists(os.path.join(ANDROID_HOME, "cmdline-tools", "latest", "bin", "apkanalyzer")):
APKANALYZER_CMD = os.path.join(ANDROID_HOME, "cmdline-tools", "latest", "bin", "apkanalyzer")
elif check_command("apkanalyzer"):
APKANALYZER_CMD = "apkanalyzer"
Expand Down
81 changes: 31 additions & 50 deletions blint/binary.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import contextlib
import json
import sys
from typing import Tuple
import zlib

import lief
Expand Down Expand Up @@ -218,24 +219,6 @@ def parse_strings(parsed_obj):
return strings_list


def ignorable_symbol(symbol_name: str | None) -> bool:
"""
Determines if a symbol is ignorable.
Args:
symbol_name (str): The name of the symbol to check.
Returns:
bool: True if the symbol is ignorable, False otherwise.
"""
if not symbol_name:
return True
for pref in ("_$f", "$f64.", "__"):
if symbol_name.startswith(pref):
return True
return False


def parse_symbols(symbols):
"""
Parse symbols from a list of symbols.
Expand All @@ -261,24 +244,23 @@ def parse_symbols(symbols):
symbol_name = symbol.demangled_name
if isinstance(symbol_name, lief.lief_errors):
symbol_name = symbol.name
if not ignorable_symbol(symbol_name):
exe_type = guess_exe_type(symbol_name)
symbols_list.append(
{
"name": symbol_name,
"type": str(symbol.type).rsplit(".", maxsplit=1)[-1],
"value": symbol.value,
"visibility": str(symbol.visibility).rsplit(".", maxsplit=1)[-1],
"binding": str(symbol.binding).rsplit(".", maxsplit=1)[-1],
"is_imported": is_imported,
"is_exported": is_exported,
"information": symbol.information,
"is_function": symbol.is_function,
"is_static": symbol.is_static,
"is_variable": symbol.is_variable,
"version": str(symbol_version),
}
)
exe_type = guess_exe_type(symbol_name)
symbols_list.append(
{
"name": symbol_name,
"type": str(symbol.type).rsplit(".", maxsplit=1)[-1],
"value": symbol.value,
"visibility": str(symbol.visibility).rsplit(".", maxsplit=1)[-1],
"binding": str(symbol.binding).rsplit(".", maxsplit=1)[-1],
"is_imported": is_imported,
"is_exported": is_exported,
"information": symbol.information,
"is_function": symbol.is_function,
"is_static": symbol.is_static,
"is_variable": symbol.is_variable,
"version": str(symbol_version),
}
)
except (AttributeError, IndexError, TypeError):
continue
return symbols_list, exe_type
Expand Down Expand Up @@ -657,19 +639,18 @@ def parse_macho_symbols(symbols):
if not symbol_name or isinstance(symbol_name, lief.lief_errors):
symbol_name = symbol.name
symbol_name = symbol_name.replace("..", "::")
if not ignorable_symbol(symbol_name):
if not exe_type:
exe_type = guess_exe_type(symbol_name)
symbols_list.append(
{
"name": (f"{libname}::{symbol_name}" if libname else symbol_name),
"short_name": symbol_name,
"type": symbol.type,
"num_sections": symbol.numberof_sections,
"description": symbol.description,
"value": symbol_value,
}
)
if not exe_type:
exe_type = guess_exe_type(symbol_name)
symbols_list.append(
{
"name": (f"{libname}::{symbol_name}" if libname else symbol_name),
"short_name": symbol_name,
"type": symbol.type,
"num_sections": symbol.numberof_sections,
"description": symbol.description,
"value": symbol_value,
}
)
except (AttributeError, TypeError):
continue
return symbols_list, exe_type
Expand Down Expand Up @@ -932,7 +913,7 @@ def parse_overlay(parsed_obj: lief.Binary) -> dict[str, dict]:
return deps


def parse_go_buildinfo(parsed_obj: lief.Binary) -> (dict[str, dict[str, str]], dict[str, str]):
def parse_go_buildinfo(parsed_obj: lief.Binary) -> Tuple[dict[str, dict[str, str]], dict[str, str]]:
"""
Parse the go build info section to extract go dependencies
Args:
Expand Down
18 changes: 14 additions & 4 deletions blint/sbom.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ def process_exe_file(
)
# Convert rust dependencies
if metadata.get("rust_dependencies"):
rust_components = process_rust_dependencies(metadata.get("rust_dependencies"))
rust_components = process_rust_dependencies(metadata.get("rust_dependencies"), dependencies_dict)
lib_components += rust_components
if lib_components:
components += lib_components
Expand Down Expand Up @@ -587,7 +587,7 @@ def process_go_dependencies(go_deps: dict[str, str]) -> list[Component]:
return components


def process_rust_dependencies(rust_deps: list) -> list[Component]:
def process_rust_dependencies(rust_deps: list, dependencies_dict: dict[str, set]) -> list[Component]:
"""
Process the rust dependencies metadata extracted for binary overlays
Expand All @@ -598,18 +598,28 @@ def process_rust_dependencies(rust_deps: list) -> list[Component]:
list: New component list
"""
components = []
idx_to_purl = {}
for idx, dep in enumerate(rust_deps):
idx_to_purl[idx] = f"""pkg:cargo/{dep["name"]}@{dep["version"]}"""
for dependency in rust_deps:
purl = f"""pkg:cargo/{dependency["name"]}@{dependency["version"]}"""
purl_qualifer = f"""?repository={dependency.get("source")}""" if dependency.get("source", "") != "crates.io" else ""
comp = Component(
type=Type.library,
name=dependency["name"],
version=dependency["version"],
purl=purl,
purl=f"{purl}{purl_qualifer}",
scope=Scope.required,
evidence=create_component_evidence(dependency["name"], 1.0)
evidence=create_component_evidence(dependency["name"], 0.8)
)
comp.bom_ref = RefType(purl)
components.append(comp)
if not dependencies_dict.get(purl):
dependencies_dict[purl] = set()
# Recover the dependency tree
if dependency.get("dependencies"):
for adep in dependency.get("dependencies"):
dependencies_dict[purl].add(idx_to_purl[adep])
return components


Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "blint"
version = "2.1.2"
version = "2.1.3"
description = "Linter and SBOM generator for binary files."
authors = ["Prabhu Subramanian <prabhu@appthreat.com>", "Caroline Russell <caroline@appthreat.dev>"]
license = "MIT"
Expand Down

0 comments on commit d572f2d

Please sign in to comment.