2 个不稳定版本
0.2.0 | 2023年11月3日 |
---|---|
0.1.0 | 2022年1月26日 |
#386 在 数据库接口
545KB
11K SLoC
linux-package-analyzer
linux-package-analyzer
是一个提供 lpa
命令行可执行文件的二进制 Rust crate。此 CLI 工具便于索引并检查 Linux 包仓库的内容。支持基于 Debian 和 RPM 的仓库。
运行 lpa help
获取更多信息。
安装
# From the latest released version on crates.io:
$ cargo install linux-package-analyzer
# From the latest commit in the canonical Git repository:
$ cargo install --git https://github.com/indygreg/linux-packaging-rs linux-package-analyzer
# From the root directory of a Git source checkout:
$ cargo install --path linux-package-analyzer
工作原理
lpa
提供子命令,用于将指定包仓库的内容导入到本地 SQLite 数据库中。实际上,从远程仓库检索包列表,并下载引用的包及其内容进行索引。索引内容包括
- 由包安装的文件
- ELF 文件内容
- 文件头值
- 部分元数据
- 动态库依赖项
- 符号
- x86 指令计数
还存在其他子命令,用于在 SQLite 数据库中对索引内容进行分析。然而,SQLite 数据库中有大量数据无法通过 CLI 暴露或查询。
示例
以下命令将所有 Ubuntu 21.10 Impish for amd64 包导入到 SQLite 数据库 ubuntu-impish.db
lpa --db ubuntu-impish.db \
import-debian-repository \
--components main,multiverse,restricted,universe \
--architectures amd64 \
http://us.archive.ubuntu.com/ubuntu impish
这将下载约 96 GB 的包(截至 2022 年 1 月),并创建一个约 12 GB 的 SQLite 数据库。
一旦数据库中有数据,就可以运行命令来查询其内容。
查看哪些文件导入(并可能调用)特定的 C 函数
lpa --db ubuntu-impish.db \
elf-files-importing-symbol OPENSSL_init_ssl
查看最受欢迎的 ELF 部分名称
lpa --db ubuntu-impish.db elf-section-name-counts
高级用户可能希望针对数据库编写自己的查询。要开始,请打开 SQLite 数据库并四处查看
$ sqlite3 ubuntu-impish.db
SQLite version 3.35.5 2021-04-19 18:32:05
Enter ".help" for usage hints.
sqlite> .tables
elf_file package_file
elf_file_needed_library symbol_name
elf_file_x86_base_register_count v_elf_needed_library
elf_file_x86_instruction_count v_elf_symbol
elf_file_x86_register_count v_package_elf_file
elf_section v_package_file
elf_symbol v_package_instruction_count
package
sqlite> select * from v_elf_needed_library where library_name = "libc.so.6" order by package_name asc limit 1;
0ad|0.0.25b-1|http://us.archive.ubuntu.com/ubuntu/pool/universe/0/0ad/0ad_0.0.25b-1_amd64.deb|usr/games/pyrogenesis|libc.so.6
前缀为 v_
的表是视图,方便地从多个表中拉取数据。例如,v_elf_symbol
包含 elf_symbol
的所有列,但也扩展了包名、版本、文件路径等。
常量和特殊值
各种 ELF 数据使用常量来定义属性。例如,elf_file.machine
是一个包含 ELF 机器类型的整数。这些常量值的良好参考是 https://docs.rs/object/0.28.2/src/object/elf.rs.html#1-6256。
lpa
还公开了各种 reference-*
命令,用于打印已知值。
已知问题
x86 汇编奇异性
在包索引/导入过程中,尝试对 x86 / x86-64 文件进行反汇编,以便将指令计数和寄存器使用情况存储到数据库中。
我们反汇编所有标记为可执行的部分。其他部分中的指令可能找不到(希望这种情况很少发生)。
我们使用 iced_x86 Rust 包进行反汇编。因此,该包中的任何限制都适用于反汇编器。
我们通过迭代二进制部分的内文内容来反汇编指令,尝试读取指令直到部分结束。可执行部分可以包含 NULL 字节、内联数据和其他可能不代表有效指令的字节。这会导致许多字节序列解码为特殊的 无效 指令。在某些情况下,字节序列可能解码为指令,尽管底层数据实际上不是指令。即指令计数可能存在误报。
包检索时的间歇性 HTTP 故障
由于网络固有的不可靠性,导入包时可能会出现间歇性的 HTTP GET 故障。这通常表现为以下错误
error processing package (ignoring): repository I/O error on path pool/universe/g/gcc-10/gnat-10_10.3.0-11ubuntu1_amd64.deb: Custom { kind: Other, error: "error sending HTTP request: reqwest::Error { kind: Request, url: Url { scheme: \"http\", cannot_be_a_base: false, username: \"\", password: None, host: Some(Domain(\"us.archive.ubuntu.com\")), port: None, path: \"/ubuntu/pool/universe/g/gcc-10/gnat-10_10.3.0-11ubuntu1_amd64.deb\", query: None, fragment: None }, source: hyper::Error(IncompleteMessage) }" }
如果您看到此类故障,只需重新尝试导入操作即可。已导入的包应自动跳过。
包服务器节流
lpa
可以发出并行 HTTP 请求来检索内容。默认情况下,它发出的并行请求数量与 CPU 核心或线程数量相同。
一些包仓库限制客户端同时进行的 HTTP 连接/请求数量。如果您的计算机具有许多 CPU 核心,您可能会遇到这些限制,并在获取包时出现大量 HTTP 错误。为了缓解,可以通过 --threads
减少同时进行的 I/O 操作数量。例如:lpa --threads 4 ...
SQLite 完整性减弱
为了最大化导入操作的速度,SQLite 数据库通过在数据库打开时发出的 PRAGMA
语句减弱其内容完整性和耐久性保证。在写入操作期间,进程或机器崩溃更容易损坏 SQLite 数据库。
依赖项
~91MB
~1.5M SLoC