2 个不稳定版本

0.2.0 2023年11月3日
0.1.0 2022年1月26日

#386数据库接口

MPL-2.0 许可证

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