Files
Fanjun Kong 72f2e1a897 just for testing
Signed-off-by: Fanjun Kong <kongfanjun@iscas.ac.cn>
2026-01-30 16:04:18 +08:00

276 lines
6.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# RPM 包安全特性大规模扫描系统
## 架构概览
```
[包列表获取] → [并行下载] → [ELF提取] → [安全扫描] → [结果入库] → [报告生成]
```
## 快速开始
### 1. 安装依赖
```bash
# RHEL/Fedora/OpenEuler
sudo dnf install -y parallel checksec sqlite
# 验证
checksec --version
parallel --version
```
### 2. 初始化
```bash
chmod +x *.sh
./01_init.sh
```
### 3. 执行扫描(无锁设计)
```bash
# 全量扫描(8 并发)
./02_scan.sh
# 自定义并发数
PARALLEL_JOBS=16 ./02_scan.sh
```
**输出文件**
- `results/scanned.txt` - 已扫描包列表
- `results/success.txt` - 扫描成功的包
- `results/failed.txt` - 扫描失败的包
- `results/no_binary.txt` - 无二进制文件的包
- `results/*.json` - checksec 原始结果
### 4. 导入数据库
```bash
python3 04_import_results.py scan_workspace/results/scan_results.db scan_workspace/results
```
**为什么分两步?**
- 避免多进程并发写入 SQLite 导致的数据库锁定问题
- 扫描阶段只写文件,完全无锁
- 导入阶段串行处理,安全可靠
### 5. 生成报告
```bash
# 生成统计报告和 CSV
python3 03_report.py scan_workspace/results/scan_results.db --export-csv report.csv
```
## 核心设计
### 1. 预筛选策略
**问题**: `dnf repoquery` 默认包含 noarch 包,浪费资源
**解决方案**:
```bash
# 只查询 x86_64 架构(注意格式字符串末尾的 \n)
dnf repoquery --arch x86_64 --qf '%{name}-%{version}-%{release}.%{arch}\n'
# 进一步过滤:检查是否包含目标路径
dnf repoquery --arch x86_64 --list PACKAGE | grep -E '^/(usr/)?(bin|sbin|lib64)'
```
### 2. 软链接去重
**问题**: `/bin``/usr/bin` 导致重复扫描
**解决方案**:
```bash
# 使用 inode 去重
find . -type f -exec stat -c '%i %n' {} \; | sort -u -k1,1 | cut -d' ' -f2-
```
### 3. 并行优化
**三级并行**:
- **包级**: GNU Parallel 并行处理包 (`-j 8`)
- **下载级**: DNF 并行下载配置
- **扫描级**: checksec 批量调用
### 4. 无锁设计(重要)
**问题**: SQLite 不支持多进程并发写入
**解决方案**: 扫描与入库分离
```bash
# 扫描阶段:多进程并发写文件(无锁)
./02_scan.sh
→ results/scanned.txt
→ results/success.txt
→ results/failed.txt
→ results/*.json
# 导入阶段:单进程串行入库(安全)
python3 04_import_results.py scan_results.db results/
```
**关键改进**:
- ✅ 使用 `flock` 文件锁代替数据库查询
- ✅ 状态文件代替数据库状态查询
- ✅ JSON 文件存储中间结果
- ✅ 批量导入代替逐条写入
### 5. 增量扫描
文件记录扫描状态,跳过已扫描的包:
```bash
# 使用 flock 检查是否已扫描
if grep -qx "$pkg_name" "$status_file"; then
echo "跳过已扫描: $pkg_name"
exit 0
fi
```
### 6. 错误处理
- 下载超时: `timeout 300s`
- 解压失败: 记录状态到数据库
- checksec 超时: 单包超时 60s
- 重试机制: `parallel --retries 2`
## 数据库 Schema
```sql
packages (id, name, version, status, scan_time)
binaries (id, package_id, file_path, inode)
security_checks (id, binary_id, pie, nx, canary, fortify, relro)
```
## 配置文件
编辑 `config.sh`:
```bash
PARALLEL_JOBS=8 # 并发数
REPO_ARCH="x86_64" # 架构
DOWNLOAD_TIMEOUT=300 # 下载超时
CHECKSEC_TIMEOUT=60 # 扫描超时
```
## 输出文件
```
scan_workspace/
├── rpm_cache/ # RPM 缓存
├── extracted/ # 临时解压目录
├── results/
│ ├── scan_results.db # SQLite 数据库
│ ├── *.json # checksec 原始结果
│ └── report.csv # CSV 报告
├── scan.log # 运行日志
├── error.log # 错误日志
└── parallel.log # GNU Parallel 日志
```
## 性能估算
- 单包平均耗时: 10-30s (下载 + 解压 + 扫描)
- 8 并发处理 1000 个包: ~30-60 分钟
- 磁盘空间: 每包 10-100MB (临时)
## 故障排查
### 1. checksec 找不到
```bash
# 从源码安装
git clone https://github.com/slimm609/checksec.sh
sudo cp checksec /usr/local/bin/
```
### 2. 并行任务失败
查看日志:
```bash
tail -f scan_workspace/error.log
cat scan_workspace/parallel.log | grep -v "^0"
```
### 3. 数据库锁定(已解决)
**旧版本问题**
```
Error: in prepare, database is locked (5)
```
**新版本解决方案**
- ✅ 采用无锁设计,扫描阶段不写数据库
- ✅ 使用文件锁 `flock` 代替数据库锁
- ✅ 扫描完成后批量导入
如果仍然遇到数据库锁定:
```bash
# 删除锁文件
rm scan_workspace/results/scanned.txt.lock
# 或使用新的工作目录重新扫描
WORK_DIR="./scan_workspace_new" ./02_scan.sh
```
## 扩展功能
### 1. 分布式扫描
```bash
# 机器 A: 扫描前 500 个包
head -500 packages.list | parallel -j 8 ./scan_package.sh
# 机器 B: 扫描后 500 个包
tail -500 packages.list | parallel -j 8 ./scan_package.sh
# 合并结果文件(不需要合并数据库)
cat machine_a/results/*.json > all_results.json
cat machine_a/results/success.txt machine_b/results/success.txt > all_success.txt
# 导入到统一数据库
python3 04_import_results.py merged.db results/
```
**优势**
- 每台机器独立工作,无数据库冲突
- 只需合并文本文件和 JSON
- 最后统一导入数据库
### 2. 定时增量扫描
```bash
# crontab
0 2 * * * cd /path/to/scan && ./01_init.sh && ./02_scan.sh && python3 04_import_results.py scan_results.db results/
```
### 3. Web Dashboard
使用 Grafana + SQLite 数据源可视化结果
## 潜在问题与解决方案
| 问题 | 影响 | 解决方案 |
|------|------|----------|
| noarch 包误扫描 | 浪费资源 | `--arch x86_64` 预筛选 |
| 软链接重复 | 结果重复 | inode 去重 |
| 内核模块误报 | PIE 检查不适用 | 排除 `*.ko` |
| 网络不稳定 | 下载失败 | 超时 + 重试 |
| 磁盘空间不足 | 解压失败 | 及时清理临时文件 |
| checksec 慢 | 扫描耗时长 | 批量调用 + 并行 |
## 最佳实践
1. **首次运行**: 先用小样本测试 (`head -10 packages.list`)
2. **并发调优**: 根据 CPU 核心数和网络带宽调整 `PARALLEL_JOBS`
3. **磁盘管理**: 定期清理 `rpm_cache/``extracted/`
4. **日志监控**: 实时查看 `tail -f scan.log`
5. **增量更新**: 定期运行获取新包
## 参考资料
- [checksec 文档](https://github.com/slimm609/checksec.sh)
- [GNU Parallel 教程](https://www.gnu.org/software/parallel/parallel_tutorial.html)
- [RPM 包管理](https://rpm.org/)