cuvat-rs/src/analyzer/mod.rs
Jia Chao f82ff6ac72 完成扫描整体结果展示
Signed-off-by: Jia Chao <jiachao2130@126.com>
2024-08-06 11:32:38 +08:00

164 lines
4.3 KiB
Rust

use std::collections::HashMap;
use std::str::FromStr;
use cvrf_xmlparser::{Severity, CUSA};
use lazy_static::lazy_static;
use rpm_rs::rpm::{get_installed_packages, Package};
use rpm_rs::rpmio::rpmvercmp;
use updateinfo_xmlparser::{RpmInfo, UpdateInfoDb};
use crate::analyzer::db::{CveDb, PackgeDb, SaDb};
use crate::cli::Cli;
lazy_static! {
pub static ref update_pkgs: PackgeDb = {
let mut updatedb = UpdateInfoDb::new();
updatedb.load_xml("test/updateinfo.xml").unwrap();
let mut pkgdb = PackgeDb::new();
pkgdb.load_from_updateinfodb(&updatedb);
pkgdb
};
pub static ref sadb: SaDb = {
let mut _sadb = SaDb::new();
_sadb.load_from_file("test/cvrf_sainfos.json").unwrap();
_sadb
};
pub static ref cvedb: CveDb = sadb.get_cvedb();
}
pub mod db;
pub fn cuvat_run(cli: &Cli) -> crate::Result<()> {
// 只报告 cve 相关
if cli.cves {
return list_cves(cli);
}
// 只报告 sa 相关
if cli.sas {
return list_sas(cli);
}
// 生成报告
if cli.report {
return repoter(cli);
}
// 默认报告格式
summary(cli)
}
fn list_cves(cli: &Cli) -> crate::Result<()> {
Ok(())
}
fn list_sas(cli: &Cli) -> crate::Result<()> {
Ok(())
}
fn repoter(cli: &Cli) -> crate::Result<()> {
Ok(())
}
fn summary(cli: &Cli) -> crate::Result<()> {
let avaliable = get_avaliable()?;
let severity = Severity::from_str(&cli.severity)?;
let mut res = vec![0; 5];
for (cusa, rpms) in &avaliable {
// 过滤
if cusa.severity() < &severity {
continue;
}
let pos: usize = cusa.severity().into();
res[pos] += 1;
}
let msg = format!("
漏洞扫描结果如下:
致命漏洞: {:3}
高危漏洞: {:3}
中危漏洞: {:3}
低危漏洞: {:3}
", res[4], res[3], res[2], res[1]);
println!("{}", msg);
Ok(())
}
// 获取当前可用的更新,所有安全检查均基于此
fn get_avaliable() -> crate::Result<HashMap<CUSA, Vec<RpmInfo>>> {
let mut avaliable: HashMap<CUSA, Vec<RpmInfo>> = HashMap::new();
// 当前系统所有已安装的 rpm 包
let installed = get_installed_packages();
// installed 已被消费掉
// latest_installed 是所有最新版本软件包的 Vec
let latest_installed: Vec<Package> = installed
.into_iter()
.map(|(_, pkgs)| {
let mut latest = pkgs[0].clone();
for pkg in pkgs.into_iter() {
latest = rpmdb_package_vercmp(latest, pkg);
}
latest
})
.collect();
// 获取 sa 更新列表
for pkg in latest_installed {
let name = pkg.name();
if let Some(updates) = update_pkgs.db().get(name) {
for update in updates {
// 因 updateinfo 里包含所有架构,故于此做个判断
// 是否考虑架构信息在不同的版本有所不同?
if update.arch() != pkg.arch().unwrap() {
continue;
}
// epoch 判断
match (update.epoch(), pkg.epoch()) {
(Some(_), None) => {
_add_to_avaliable(&mut avaliable, update.sa(), update.clone());
}
(None, Some(_)) => continue,
_ => {}
}
// evr 对比
if rpmvercmp(&update.evr(), &pkg.evr()) > 0 {
_add_to_avaliable(&mut avaliable, update.sa(), update.clone());
}
}
}
}
Ok(avaliable)
}
fn _add_to_avaliable(avaliable: &mut HashMap<CUSA, Vec<RpmInfo>>, sa: &str, rpm: RpmInfo) {
let sainfo = sadb.db().get(sa).unwrap();
if let Some(rpms) = avaliable.get_mut(sainfo) {
rpms.push(rpm);
} else {
let rpms = vec![rpm];
avaliable.insert(sainfo.clone(), rpms);
}
}
// 对比两个 rpm Package 的版本,返回最新的一个
fn rpmdb_package_vercmp(pa: Package, pb: Package) -> Package {
// 首先进行 epoch 的比较
match (pa.epoch(), pb.epoch()) {
(Some(_), None) => return pa,
(None, Some(_)) => return pb,
_ => {} // 继续往下对比
}
if rpmvercmp(&pa.evr(), &pb.evr()) > 0 {
return pa;
} else {
return pb;
}
}