Skip to content

Commit 2b17cc9

Browse files
Address feedback and add docstrings
Signed-off-by: Ayan Sinha Mahapatra <ayansmahapatra@gmail.com>
1 parent 2d05cfd commit 2b17cc9

12 files changed

Lines changed: 158 additions & 79 deletions

File tree

.github/workflows/docs-ci.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: CI Documentation
1+
name: CI Documentation and Code style
22

33
on: [push, pull_request]
44

@@ -21,7 +21,7 @@ jobs:
2121
python-version: ${{ matrix.python-version }}
2222

2323
- name: Install Dependencies
24-
run: pip install -e .[docs]
24+
run: pip install -e .[docs,testing]
2525

2626
- name: Check Sphinx Documentation build minimally
2727
working-directory: ./docs
@@ -31,4 +31,5 @@ jobs:
3131
working-directory: ./docs
3232
run: ./scripts/doc8_style_check.sh
3333

34-
34+
- name: Check for Code style errors
35+
run: make check-ci

Makefile

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,19 @@ valid: isort black
3333

3434
check:
3535
@echo "-> Run pycodestyle (PEP8) validation"
36-
@${ACTIVATE} pycodestyle --max-line-length=100 --exclude=.eggs,venv,lib,thirdparty,docs,migrations,settings.py,.cache .
36+
@${ACTIVATE} pycodestyle --max-line-length=100 --exclude=.eggs,venv,lib,thirdparty,docs,scripts,tests,migrations,settings.py,.cache .
3737
@echo "-> Run isort imports ordering validation"
38-
@${ACTIVATE} isort --sl --check-only -l 100 setup.py src tests .
38+
@${ACTIVATE} isort --sl -l 100 src tests setup.py --check-only
3939
@echo "-> Run black validation"
40-
@${ACTIVATE} black --check --check -l 100 src tests setup.py
40+
@${ACTIVATE} black --check -l 100 src tests setup.py
41+
42+
check-ci:
43+
@echo "-> Run pycodestyle (PEP8) validation"
44+
pycodestyle --max-line-length=100 --exclude=.eggs,venv,lib,thirdparty,docs,scripts,tests,migrations,settings.py,.cache .
45+
@echo "-> Run isort imports ordering validation"
46+
isort --sl -l 100 src tests setup.py --check-only
47+
@echo "-> Run black validation"
48+
black --check -l 100 src tests setup.py
4149

4250
clean:
4351
@echo "-> Clean the Python env"

src/rust_inspector/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,3 @@
77
# See https://github.com/nexB/rust-inspector for support or download.
88
# See https://aboutcode.org for more information about nexB OSS projects.
99
#
10-

src/rust_inspector/binary.py

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
# See https://aboutcode.org for more information about nexB OSS projects.
99
#
1010

11-
import os
12-
import lief
1311
import json
12+
import os
1413
import zlib
1514

15+
import lief
1616
from typecode import contenttype
1717
from typecode.contenttype import get_type
1818

@@ -67,7 +67,7 @@ def get_rust_packages_data(location):
6767
to the rust binary with data on packages and dependencies.
6868
See https://github.com/rust-secure-code/cargo-auditable for more info.
6969
70-
Code for parsing rust bianries to get package data is from
70+
Code for parsing rust binaries to get package data is from
7171
https://github.com/rust-secure-code/cargo-auditable/blob/master/PARSING.md
7272
"""
7373
if not is_executable_binary(location):
@@ -87,9 +87,12 @@ def get_rust_packages_data(location):
8787
return packages_data
8888

8989

90-
9190
def might_have_rust_symbols(string_with_symbols):
92-
91+
"""
92+
Given a demangled symbol string obtained from a rust binary, return True if
93+
there are rust symbols present in the string which could be mapped to rust
94+
source symbols potentially, return False otherwise.
95+
"""
9396
if not string_with_symbols:
9497
return False
9598

@@ -120,16 +123,20 @@ def might_have_rust_symbols(string_with_symbols):
120123

121124
return True
122125

123-
def remove_standard_symbols(rust_symbols):
124-
return [
125-
symbol
126-
for symbol in rust_symbols
127-
if symbol not in STANDARD_SYMBOLS_RUST
128-
]
126+
127+
def remove_standard_symbols(rust_symbols, standard_symbols=STANDARD_SYMBOLS_RUST):
128+
"""
129+
Remove standard symbols usually found in rust binaries. Given a list of rust
130+
symbol strings, return a list of symbol strings which are most likely non-standard.
131+
"""
132+
return [symbol for symbol in rust_symbols if symbol not in standard_symbols]
129133

130134

131135
def split_strings_by_char(split_strings, split_char):
132-
136+
"""
137+
Given a list of strings, return another list of strings with all
138+
the substrings from each string, split by the `split_char`.
139+
"""
133140
final_split_strings = []
134141
for split_str in split_strings:
135142
if split_char in split_str:
@@ -138,15 +145,16 @@ def split_strings_by_char(split_strings, split_char):
138145
else:
139146
final_split_strings.append(split_str)
140147

141-
return [
142-
split_string
143-
for split_string in final_split_strings
144-
if split_string
145-
]
148+
return [split_string for split_string in final_split_strings if split_string]
146149

147150

148151
def split_strings_into_rust_symbols(strings_to_split, split_by_chars=SPLIT_CHARACTERS_RUST):
149-
152+
"""
153+
Given a list of strings containing a group of rust symbols, get a list
154+
of strings with the extracted individual symbol strings, using a list of
155+
`split_by_chars` which are common characters found between rust symbols in
156+
demangled rust string containing multiple symbols.
157+
"""
150158
split_strings = []
151159
split_strings_log = []
152160
for split_char in split_by_chars:
@@ -159,10 +167,17 @@ def split_strings_into_rust_symbols(strings_to_split, split_by_chars=SPLIT_CHARA
159167
return split_strings
160168

161169

162-
def cleanup_symbols(split_symbols, include_stdlib=False, unique=True, sort_symbols=False):
170+
def cleanup_symbols(symbols, include_stdlib=False, unique=True, sort_symbols=False):
171+
"""
172+
Given a list of `symbols` strings, return a list of cleaned up
173+
symbol strings, removing strings which does not have symbols.
163174
175+
If `include_stdlib` is False, remove standard rust symbols.
176+
If `unique` is True, only return unique symbol strings.
177+
If `sort_symbols` is True, return a sorted list of symbols.
178+
"""
164179
rust_symbols = []
165-
for split_string in split_symbols:
180+
for split_string in symbols:
166181
if might_have_rust_symbols(split_string):
167182
rust_symbols.append(split_string)
168183

@@ -178,17 +193,22 @@ def cleanup_symbols(split_symbols, include_stdlib=False, unique=True, sort_symbo
178193
return rust_symbols
179194

180195

181-
def extract_strings_with_symbols(symbols_data, include_stdlib=False, unique=True, sort_symbols=False):
182-
196+
def extract_strings_with_symbols(
197+
symbols_data, include_stdlib=False, unique=True, sort_symbols=False
198+
):
199+
"""
200+
From a list of rust symbols data parsed and demangled from a binary,
201+
return a list of individual symbols (after cleanup) found in the strings.
202+
"""
183203
strings_with_symbols = []
184-
204+
185205
ignore_types = ["NOTYPE", "TLS"]
186206

187207
for symbol_data in symbols_data:
188208

189209
if not symbol_data.get("name"):
190210
continue
191-
211+
192212
if symbol_data.get("type") in ignore_types:
193213
continue
194214

@@ -202,14 +222,14 @@ def extract_strings_with_symbols(symbols_data, include_stdlib=False, unique=True
202222
# These are usually like the following:
203223
# `getrandom@GLIBC_2.25`, `__umodti3`, `_ITM_registerTMCloneTable`
204224
# So these doesn't have source symbols
205-
if symbol_data.get("binding") == 'WEAK':
225+
if symbol_data.get("binding") == "WEAK":
206226
continue
207227

208228
# file/module names are also source symbols as they
209229
# are imported in source code files
210230
if symbol_data.get("type") == "FILE":
211231
file_string = symbol_data.get("name")
212-
file_segments = file_string.split('.')
232+
file_segments = file_string.split(".")
213233
if not file_segments:
214234
continue
215235

@@ -227,7 +247,7 @@ def extract_strings_with_symbols(symbols_data, include_stdlib=False, unique=True
227247

228248
split_symbols = split_strings_into_rust_symbols(strings_to_split=strings_with_symbols)
229249
rust_symbols = cleanup_symbols(
230-
split_symbols=split_symbols,
250+
symbols=split_symbols,
231251
include_stdlib=include_stdlib,
232252
unique=unique,
233253
sort_symbols=sort_symbols,
@@ -240,7 +260,6 @@ def collect_and_parse_rust_symbols(location, include_stdlib=False, sort_symbols=
240260
"""
241261
Return a mapping of Rust symbols of interest for the Rust binary file at ``location``.
242262
Return an empty mapping if there is no symbols or if this is not a binary.
243-
Raise exceptions on errors.
244263
"""
245264
if not is_executable_binary(location):
246265
return
@@ -254,11 +273,12 @@ def collect_and_parse_rust_symbols(location, include_stdlib=False, sort_symbols=
254273
)
255274

256275

257-
def collect_and_parse_rust_symbols_from_data(rust_data, include_stdlib=False, unique=True, sort_symbols=False, **kwargs):
276+
def collect_and_parse_rust_symbols_from_data(
277+
rust_data, include_stdlib=False, unique=True, sort_symbols=False, **kwargs
278+
):
258279
"""
259280
Return a mapping of Rust symbols of interest for the mapping of Rust binary of ``rust_data``.
260281
Return an empty mapping if there is no symbols or if this is not a binary.
261-
Raise exceptions on errors.
262282
"""
263283
if not rust_data:
264284
return {}

src/rust_inspector/blint_binary.py

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
1-
import lief
2-
from symbolic._lowlevel import ffi, lib
3-
from symbolic.utils import encode_str, decode_str, rustcall
1+
#
2+
# Copyright (c) OWASP Foundation
3+
# SPDX-License-Identifier: MIT
4+
#
5+
# Originally taken from
6+
# https://github.com/owasp-dep-scan/blint/blob/1e1250a4bf6c25eccba8970bd877901ee56070c7/blint/lib/binary.py
7+
# Used after minor modifications.
8+
#
49

10+
import lief
11+
from symbolic._lowlevel import ffi
12+
from symbolic._lowlevel import lib
13+
from symbolic.utils import decode_str
14+
from symbolic.utils import encode_str
15+
from symbolic.utils import rustcall
516

617
# TODO: Consider using blint as a dependency instead of vendoring
718

819

920
def demangle_symbolic_name(symbol, lang=None, no_args=False):
10-
"""Demangles symbol using llvm demangle falling back to some heuristics. Covers legacy rust."""
21+
"""
22+
Return a demangled symbol string, given a symbol string.
23+
24+
Demangles symbols obtained from a rust binary using llvm demangle (using symbolic),
25+
falling back to some heuristics. Also covers legacy rust.
26+
"""
1127
try:
1228
func = lib.symbolic_demangle_no_args if no_args else lib.symbolic_demangle
1329
lang_str = encode_str(lang) if lang else ffi.NULL
@@ -27,7 +43,10 @@ def demangle_symbolic_name(symbol, lang=None, no_args=False):
2743
or symbol.startswith(".rdata$")
2844
or symbol.startswith(".refptr.")
2945
):
30-
symbol = f"__declspec(dllimport) {symbol.removeprefix('__imp_').removeprefix('.rdata$').removeprefix('.refptr.')}"
46+
symbol_without_prefix = (
47+
symbol.removeprefix("__imp_").removeprefix(".rdata$").removeprefix(".refptr.")
48+
)
49+
symbol = f"__declspec(dllimport) {symbol_without_prefix}"
3150
demangled_symbol = (
3251
symbol.replace("..", "::")
3352
.replace("$SP$", "@")
@@ -58,13 +77,8 @@ def demangle_symbolic_name(symbol, lang=None, no_args=False):
5877

5978
def parse_symbols(symbols):
6079
"""
61-
Parse symbols from a list of symbols.
62-
63-
Args:
64-
symbols (it_symbols): A list of symbols to parse.
65-
66-
Returns:
67-
tuple[list[dict], str]: A tuple containing the symbols_list and exe_type
80+
Parse symbols from a list of symbol strings and get a list of symbol
81+
data, with the demangled symbol string and other attributes for the symbol.
6882
"""
6983
symbols_list = []
7084

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ download_url: https://github.com/owasp-dep-scan/blint/blob/1e1250a4bf6c25eccba89
77
license_expression: mit
88
copyright: Copyright (c) OWASP Foundation
99
package_url: pkg:pypi/blint@2.3.2
10+
notice_file: blint_binary.py.LICENSE
1011
notes: only a subset of functions from binary.py is used, after minor modifications
File renamed without changes.

src/rust_inspector/config.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
SPLIT_CHARACTERS_RUST = ["::", "_<", "<", ">", "(", ")", ",", " as ", " for "]
1717

1818

19-
19+
# Standard symbols present in rust binaries which are not usually from rust
20+
# source files, and sometimes they are standard library symbols
2021
STANDARD_SYMBOLS_RUST = [
2122
"std",
2223
"vector",
23-
]
24+
]

0 commit comments

Comments
 (0)