CVRF: 处理 vulnerabilities

Signed-off-by: Jia Chao <jiac13@chinaunicom.cn>
This commit is contained in:
Jia Chao 2024-06-11 15:31:52 +08:00
parent 973e22c89e
commit 89c831a48b
2 changed files with 245 additions and 4 deletions

View File

@ -95,7 +95,7 @@ impl XmlReader {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct CVRF {
pub struct CVRF {
// <DocumentTitle xml:lang="en">
pub documenttitle: String,
@ -118,7 +118,7 @@ struct CVRF {
pub producttree: ProductTree,
// <Vulnerability xmlns="http://www.icasi.org/CVRF/schema/vuln/1.1" Ordinal="1">
pub vulnerability: Vulnerability,
pub vulnerabilities: Vec<Vulnerability>,
}
impl CVRF {
@ -133,7 +133,7 @@ impl CVRF {
documentnotes: vec![],
documentreferences: vec![],
producttree: ProductTree::new(),
vulnerability: Vulnerability::new(),
vulnerabilities: vec![],
}
}
@ -163,6 +163,7 @@ impl CVRF {
"DocumentNotes" => self.handle_notes(xmlreader),
"DocumentReferences" => self.handle_references(xmlreader),
"ProductTree" => self.producttree.load_from_xmlreader(xmlreader),
"Vulnerability" => self.handle_vulnerabilities(xmlreader),
_ => {}
},
Err(e) => {
@ -199,6 +200,14 @@ impl CVRF {
self.documentreferences.push(reference);
}
}
fn handle_vulnerabilities(&mut self, xmlreader: &mut XmlReader) {
let mut vulnerability = Vulnerability::new();
vulnerability.load_from_xmlreader(xmlreader);
if vulnerability.cve != "" {
self.vulnerabilities.push(vulnerability);
}
}
}
// depth = 2
@ -628,7 +637,6 @@ impl ProductTree {
_type.clear();
_name.clear();
}
}
#[instrument(skip(self, xmlreader))]
@ -756,6 +764,84 @@ impl Vulnerability {
remediations: Vec::new(),
}
}
#[instrument(skip(self, xmlreader))]
fn load_from_xmlreader(&mut self, xmlreader: &mut XmlReader) {
loop {
let key = if let Some(key) = xmlreader.next_start_name_under_depth(1) {
key
} else {
break;
};
match key.as_str() {
"Notes" => self.handle_notes(xmlreader),
"ReleaseDate" => self.releasedate = xmlreader.next_characters(),
"CVE" => self.cve = xmlreader.next_characters(),
"ProductStatuses" => self.handle_productstatuses(xmlreader),
"Threats" => self.handle_threats(xmlreader),
"CVSSScoreSets" => self.handle_cvssscoresets(xmlreader),
"Remediations" => self.handle_remediations(xmlreader),
_ => {}
}
}
}
fn handle_notes(&mut self, xmlreader: &mut XmlReader) {
loop {
let mut note = Note::new();
note.load_from_xmlreader(xmlreader);
if xmlreader.depth < 3 {
break;
}
self.notes.push(note);
}
}
fn handle_productstatuses(&mut self, xmlreader: &mut XmlReader) {
loop {
let mut status = ProductStatus::new();
status.load_from_xmlreader(xmlreader);
if xmlreader.depth < 3 {
break;
}
self.productstatuses.push(status);
}
}
fn handle_threats(&mut self, xmlreader: &mut XmlReader) {
loop {
let mut threat = Threat::new();
threat.load_from_xmlreader(xmlreader);
if xmlreader.depth < 3 {
break;
}
self.threats.push(threat);
}
}
fn handle_cvssscoresets(&mut self, xmlreader: &mut XmlReader) {
loop {
let mut scoreset = ScoreSet::new();
scoreset.load_from_xmlreader(xmlreader);
if xmlreader.depth < 3 {
break;
}
self.cvssscoresets.push(scoreset);
}
}
fn handle_remediations(&mut self, xmlreader: &mut XmlReader) {
loop {
let mut remediation = Remediation::new();
remediation.load_from_xmlreader(xmlreader);
if xmlreader.depth < 3 {
break;
}
self.remediations.push(remediation);
}
}
}
// depth = 4
@ -779,6 +865,30 @@ impl ProductStatus {
products: Vec::new(),
}
}
#[instrument(skip(self, xmlreader))]
fn load_from_xmlreader(&mut self, xmlreader: &mut XmlReader) {
loop {
match xmlreader.next() {
Ok(XmlEvent::StartElement { attributes, .. }) => {
if xmlreader.depth == 4 {
self.status = attributes[0].value.clone();
}
self.products.push(xmlreader.next_characters());
}
Ok(XmlEvent::EndElement { .. }) => {
if xmlreader.depth < 4 {
break;
}
}
Err(e) => {
error!("XmlReader Error: {e}");
break;
}
_ => {}
}
}
}
}
// depth = 4
@ -801,6 +911,31 @@ impl Threat {
description: String::new(),
}
}
#[instrument(skip(self, xmlreader))]
fn load_from_xmlreader(&mut self, xmlreader: &mut XmlReader) {
loop {
match xmlreader.next() {
Ok(XmlEvent::StartElement { attributes, .. }) => {
if xmlreader.depth == 4 {
self.r#type = attributes[0].value.clone();
} else {
self.description = xmlreader.next_characters();
}
}
Ok(XmlEvent::EndElement { .. }) => {
if xmlreader.depth < 4 {
break;
}
}
Err(e) => {
error!("XmlReader Error: {e}");
break;
}
_ => {}
}
}
}
}
// depth = 4
@ -824,6 +959,23 @@ impl ScoreSet {
vector: String::new(),
}
}
#[instrument(skip(self, xmlreader))]
fn load_from_xmlreader(&mut self, xmlreader: &mut XmlReader) {
loop {
let key = if let Some(key) = xmlreader.next_start_name_under_depth(3) {
key
} else {
break;
};
match key.as_str() {
"BaseScore" => self.basescore = xmlreader.next_characters(),
"Vector" => self.vector = xmlreader.next_characters(),
_ => {}
}
}
}
}
// depth = 4
@ -858,4 +1010,45 @@ impl Remediation {
url: String::new(),
}
}
#[instrument(skip(self, xmlreader))]
fn load_from_xmlreader(&mut self, xmlreader: &mut XmlReader) {
// 读取类型
loop {
match xmlreader.next() {
Ok(XmlEvent::StartElement { attributes, .. }) => {
if xmlreader.depth == 4 {
self.r#type = attributes[0].value.clone();
}
break;
}
Ok(XmlEvent::EndElement { .. }) => {
if xmlreader.depth < 4 {
break;
}
}
Err(e) => {
error!("XmlReader Error: {e}");
break;
}
_ => {}
}
}
// 其它字段
loop {
let key = if let Some(key) = xmlreader.next_start_name_under_depth(3) {
key
} else {
break;
};
match key.as_str() {
"Description" => self.description = xmlreader.next_characters(),
"DATE" => self.date = xmlreader.next_characters(),
"URL" => self.url = xmlreader.next_characters(),
_ => {}
}
}
}
}

View File

@ -84,4 +84,52 @@ fn cvrf_works() {
cvrf.producttree.packages.get(producttree_src).unwrap()[2].content,
producttree_src_content
);
// vulnerabilities
let cvrf_vulner_releasedate = "2024-04-19";
let cvrf_vulner_cve = "CVE-2023-45288";
let cvrf_vulner_productstatues_status = "Fixed";
let cvrf_vulner_productstatues_product = "openEuler-22.03-LTS";
let cvrf_vulner_basescore = "7.5";
let cvrf_vulner_vector = "AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H";
let cvrf_vulner_remedition_type = "Vendor Fix";
let cvrf_vulner_remedition_descrition = "golang security update";
let cvrf_vulner_remedition_date = "2024-04-19";
let cvrf_vulner_remedition_url = "https://www.openeuler.org/en/security/safety-bulletin/detail.html?id=openEuler-SA-2024-1488";
assert_eq!(cvrf.vulnerabilities[0].notes.len(), 1);
assert_eq!(cvrf.vulnerabilities[0].releasedate, cvrf_vulner_releasedate);
assert_eq!(cvrf.vulnerabilities[0].cve, cvrf_vulner_cve);
assert_eq!(
cvrf.vulnerabilities[0].productstatuses[0].status,
cvrf_vulner_productstatues_status
);
assert_eq!(
cvrf.vulnerabilities[0].productstatuses[0].products[2],
cvrf_vulner_productstatues_product
);
assert_eq!(
cvrf.vulnerabilities[0].cvssscoresets[0].basescore,
cvrf_vulner_basescore
);
assert_eq!(
cvrf.vulnerabilities[0].cvssscoresets[0].vector,
cvrf_vulner_vector
);
assert_eq!(
cvrf.vulnerabilities[0].remediations[0].r#type,
cvrf_vulner_remedition_type
);
assert_eq!(
cvrf.vulnerabilities[0].remediations[0].description,
cvrf_vulner_remedition_descrition
);
assert_eq!(
cvrf.vulnerabilities[0].remediations[0].date,
cvrf_vulner_remedition_date
);
assert_eq!(
cvrf.vulnerabilities[0].remediations[0].url,
cvrf_vulner_remedition_url
);
}