save
Signed-off-by: Jia Chao <jiachao2130@126.com>
This commit is contained in:
parent
946f13f35c
commit
d6a6d100b0
|
@ -6,7 +6,7 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.0", features = ["derive"] }
|
clap = { version = "4.0", features = ["derive"] }
|
||||||
serde = { version = "1", features = ["serde_derive"] }
|
serde = { version = "1", features = ["serde_derive"] }
|
||||||
toml = { version = "0.8" }
|
serde_json = { version = "1.0" }
|
||||||
updateinfo-xmlparser = { git = "https://git.zhgsun.com:8089/jiachao2130/updateinfo-xmlparser.git", version = "0.1.0" }
|
updateinfo-xmlparser = { git = "https://git.zhgsun.com:8089/jiachao2130/updateinfo-xmlparser.git", version = "0.1.0" }
|
||||||
cvrf-xmlparser = { git = "https://git.zhgsun.com:8089/jiachao2130/cvrf-xmlparser.git", version = "0.1.0" }
|
cvrf-xmlparser = { git = "https://git.zhgsun.com:8089/jiachao2130/cvrf-xmlparser.git", version = "0.1.0" }
|
||||||
rpm-rs = { git = "https://git.zhgsun.com:8089/jiachao2130/rpm-rs.git", version = "0.1.0" }
|
rpm-rs = { git = "https://git.zhgsun.com:8089/jiachao2130/rpm-rs.git", version = "0.1.0" }
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use cvrf_xmlparser::{SaInfo, CVE};
|
use cvrf_xmlparser::{CUSA, CVE};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use updateinfo_xmlparser::{UpdateInfoDb, RpmInfo};
|
use updateinfo_xmlparser::{RpmInfo, UpdateInfoDb};
|
||||||
|
|
||||||
// PackageDb 从 updateinfo 中获取
|
// PackageDb 从 updateinfo 中获取
|
||||||
// 以包名为键,值为一个 Vector ,里面包含更新的不同版本的 rpm 包信息
|
// 以包名为键,值为一个 Vector ,里面包含更新的不同版本的 rpm 包信息
|
||||||
|
@ -13,9 +13,7 @@ pub struct PackgeDb {
|
||||||
|
|
||||||
impl PackgeDb {
|
impl PackgeDb {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
PackgeDb {
|
PackgeDb { db: HashMap::new() }
|
||||||
db: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 从已有的 updateinfo 仓库文件中,获取所有与安全更新相关的软件包
|
/// 从已有的 updateinfo 仓库文件中,获取所有与安全更新相关的软件包
|
||||||
|
@ -43,24 +41,26 @@ impl PackgeDb {
|
||||||
// 其键为 SA id,值为详情
|
// 其键为 SA id,值为详情
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct SaDb {
|
pub struct SaDb {
|
||||||
db: HashMap<String, SaInfo>,
|
db: HashMap<String, CUSA>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SaDb {
|
impl SaDb {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
SaDb {
|
SaDb { db: HashMap::new() }
|
||||||
db: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 一般来自对 cvrf 文件解析并转换为 SaInfo 的文本数据文件
|
pub fn db(&self) -> &HashMap<String, CUSA> {
|
||||||
|
&self.db
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 一般来自对 cvrf 文件解析并转换为 CUSA 的文本数据文件
|
||||||
pub fn load_from_file(&mut self, file: &str) -> crate::Result<()> {
|
pub fn load_from_file(&mut self, file: &str) -> crate::Result<()> {
|
||||||
let data = std::fs::read_to_string(file)?;
|
let data = std::fs::read_to_string(file)?;
|
||||||
self.db = toml::from_str(&data)?;
|
self.db = serde_json::from_str(&data)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 从 SaInfo 中提取出所有的 CVE 源
|
/// 从 CUSA 中提取出所有的 CVE 源
|
||||||
pub fn get_cvedb(&self) -> CveDb {
|
pub fn get_cvedb(&self) -> CveDb {
|
||||||
let mut cvedb = CveDb::new();
|
let mut cvedb = CveDb::new();
|
||||||
|
|
||||||
|
@ -84,9 +84,7 @@ pub struct CveDb {
|
||||||
impl CveDb {
|
impl CveDb {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
CveDb {
|
CveDb { db: HashMap::new() }
|
||||||
db: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
use std::collections::HashSet;
|
use std::collections::HashMap;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use cvrf_xmlparser::{Severity, CUSA};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use rpm_rs::rpm::{
|
use rpm_rs::rpm::{get_installed_packages, Package};
|
||||||
get_installed_packages,
|
|
||||||
Package,
|
|
||||||
};
|
|
||||||
use rpm_rs::rpmio::rpmvercmp;
|
use rpm_rs::rpmio::rpmvercmp;
|
||||||
use updateinfo_xmlparser::{UpdateInfoDb, RpmInfo};
|
use updateinfo_xmlparser::{RpmInfo, UpdateInfoDb};
|
||||||
|
|
||||||
|
use crate::analyzer::db::{CveDb, PackgeDb, SaDb};
|
||||||
use crate::cli::Cli;
|
use crate::cli::Cli;
|
||||||
use crate::analyzer::db::PackgeDb;
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref update_pkgs: PackgeDb= {
|
pub static ref update_pkgs: PackgeDb = {
|
||||||
let mut updatedb = UpdateInfoDb::new();
|
let mut updatedb = UpdateInfoDb::new();
|
||||||
updatedb.load_xml("test/updateinfo.xml").unwrap();
|
updatedb.load_xml("test/updateinfo.xml").unwrap();
|
||||||
|
|
||||||
|
@ -20,6 +19,13 @@ lazy_static! {
|
||||||
pkgdb.load_from_updateinfodb(&updatedb);
|
pkgdb.load_from_updateinfodb(&updatedb);
|
||||||
pkgdb
|
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 mod db;
|
||||||
|
@ -27,17 +33,17 @@ pub mod db;
|
||||||
pub fn cuvat_run(cli: &Cli) -> crate::Result<()> {
|
pub fn cuvat_run(cli: &Cli) -> crate::Result<()> {
|
||||||
// 只报告 cve 相关
|
// 只报告 cve 相关
|
||||||
if cli.cves {
|
if cli.cves {
|
||||||
return list_cves(cli)
|
return list_cves(cli);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 只报告 sa 相关
|
// 只报告 sa 相关
|
||||||
if cli.sas {
|
if cli.sas {
|
||||||
return list_sas(cli)
|
return list_sas(cli);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成报告
|
// 生成报告
|
||||||
if cli.report {
|
if cli.report {
|
||||||
return repoter(cli)
|
return repoter(cli);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 默认报告格式
|
// 默认报告格式
|
||||||
|
@ -57,45 +63,80 @@ fn repoter(cli: &Cli) -> crate::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn summary(cli: &Cli) -> crate::Result<()> {
|
fn summary(cli: &Cli) -> crate::Result<()> {
|
||||||
let mut sa_ids: HashSet<String> = HashSet::new();
|
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;
|
||||||
|
}
|
||||||
|
println!("{:?}", res);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前可用的更新,所有安全检查均基于此
|
||||||
|
fn get_avaliable() -> crate::Result<HashMap<CUSA, Vec<RpmInfo>>> {
|
||||||
|
let mut avaliable: HashMap<CUSA, Vec<RpmInfo>> = HashMap::new();
|
||||||
// 当前系统所有已安装的 rpm 包
|
// 当前系统所有已安装的 rpm 包
|
||||||
let installed = get_installed_packages();
|
let installed = get_installed_packages();
|
||||||
// installed 已被消费掉
|
// installed 已被消费掉
|
||||||
// latest_installed 是所有最新版本软件包的 Vec
|
// latest_installed 是所有最新版本软件包的 Vec
|
||||||
let latest_installed: Vec<Package> = installed.into_iter().map(|(_, pkgs)| {
|
let latest_installed: Vec<Package> = installed
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_, pkgs)| {
|
||||||
let mut latest = pkgs[0].clone();
|
let mut latest = pkgs[0].clone();
|
||||||
for pkg in pkgs.into_iter() {
|
for pkg in pkgs.into_iter() {
|
||||||
latest = rpmdb_package_vercmp(latest, pkg);
|
latest = rpmdb_package_vercmp(latest, pkg);
|
||||||
}
|
}
|
||||||
latest
|
latest
|
||||||
}).collect();
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
// 获取 sa 更新列表
|
// 获取 sa 更新列表
|
||||||
for pkg in latest_installed {
|
for pkg in latest_installed {
|
||||||
let name = pkg.name();
|
let name = pkg.name();
|
||||||
if let Some(updates) = update_pkgs.db().get(name) {
|
if let Some(updates) = update_pkgs.db().get(name) {
|
||||||
for update in updates {
|
for update in updates {
|
||||||
|
// 因 updateinfo 里包含所有架构,故于此做个判断
|
||||||
|
// 是否考虑架构信息在不同的版本有所不同?
|
||||||
|
if update.arch() != pkg.arch().unwrap() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// epoch 判断
|
// epoch 判断
|
||||||
match (update.epoch(), pkg.epoch()) {
|
match (update.epoch(), pkg.epoch()) {
|
||||||
(Some(_), None) => {
|
(Some(_), None) => {
|
||||||
let _ = sa_ids.insert(update.sa().into());
|
_add_to_avaliable(&mut avaliable, update.sa(), update.clone());
|
||||||
},
|
}
|
||||||
(None, Some(_)) => continue,
|
(None, Some(_)) => continue,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// evr 对比
|
// evr 对比
|
||||||
if rpmvercmp(&update.evr(), &pkg.evr()) > 0 {
|
if rpmvercmp(&update.evr(), &pkg.evr()) > 0 {
|
||||||
sa_ids.insert(update.sa().into());
|
_add_to_avaliable(&mut avaliable, update.sa(), update.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{:#?}", sa_ids.len());
|
Ok(avaliable)
|
||||||
// TODO: sa -> { rpms, cves }
|
}
|
||||||
|
|
||||||
Ok(())
|
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 的版本,返回最新的一个
|
// 对比两个 rpm Package 的版本,返回最新的一个
|
||||||
|
@ -104,12 +145,12 @@ fn rpmdb_package_vercmp(pa: Package, pb: Package) -> Package {
|
||||||
match (pa.epoch(), pb.epoch()) {
|
match (pa.epoch(), pb.epoch()) {
|
||||||
(Some(_), None) => return pa,
|
(Some(_), None) => return pa,
|
||||||
(None, Some(_)) => return pb,
|
(None, Some(_)) => return pb,
|
||||||
_ => {}, // 继续往下对比
|
_ => {} // 继续往下对比
|
||||||
}
|
}
|
||||||
|
|
||||||
if rpmvercmp(&pa.evr(), &pb.evr()) > 0 {
|
if rpmvercmp(&pa.evr(), &pb.evr()) > 0 {
|
||||||
return pa
|
return pa;
|
||||||
} else {
|
} else {
|
||||||
return pb
|
return pb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,8 @@ pub struct Cli {
|
||||||
#[arg(action = clap::ArgAction::Append)]
|
#[arg(action = clap::ArgAction::Append)]
|
||||||
pub sources: Vec<String>,
|
pub sources: Vec<String>,
|
||||||
|
|
||||||
/// 设置过滤级别,由高到低为:[Critical, Important, Moderate, Low]
|
/// 设置过滤级别,由高到低为:[Critical, High, Medium, Low, None]
|
||||||
#[arg(long, default_value_t = String::from("Low"))]
|
#[arg(long, default_value_t = String::from("None"))]
|
||||||
pub severity: String,
|
pub severity: String,
|
||||||
|
|
||||||
/// 生成漏洞扫描报告
|
/// 生成漏洞扫描报告
|
||||||
|
|
43386
test/cvrf_sainfos.json
Normal file
43386
test/cvrf_sainfos.json
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user