From de418588a4e1b1edb501aeba4778b14ff3d26d35 Mon Sep 17 00:00:00 2001 From: Kraemii Date: Mon, 11 Nov 2024 17:53:48 +0100 Subject: [PATCH] Fix: Overflow when parsing large version numbers in notus Before we used u32 for parsing version numbers within the version comparison algorithm. Now it is checked if the version part is a number, then leading zeroes are removed and both strings are then checked. --- rust/src/notus/packages/mod.rs | 25 +++++++++++++++++++++---- rust/src/notus/packages/rpm.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/rust/src/notus/packages/mod.rs b/rust/src/notus/packages/mod.rs index da0c0d1be..196f55a61 100644 --- a/rust/src/notus/packages/mod.rs +++ b/rust/src/notus/packages/mod.rs @@ -87,10 +87,27 @@ impl PartialOrd for PackageVersion { } // check if parts are numbers - match (a_part.parse::(), b_part.parse::()) { - (Ok(a), Ok(b)) => return a.partial_cmp(&b), - (Ok(_), _) => return Some(Ordering::Greater), - (_, Ok(_)) => return Some(Ordering::Less), + match ( + a_part.chars().all(char::is_numeric), + b_part.chars().all(char::is_numeric), + ) { + (true, true) => { + // Remove leading zeros + let a_trimmed = a_part.trim_start_matches('0'); + let b_trimmed = b_part.trim_start_matches('0'); + // Compare the length of the numbers + match a_trimmed.len().cmp(&b_trimmed.len()) { + // If the length is the same, compare the numbers + Ordering::Equal => match a_trimmed.cmp(b_trimmed) { + // After trimming zeroes, the numbers could be the same + Ordering::Equal => continue, + ord => return Some(ord), + }, + ord => return Some(ord), + } + } + (true, _) => return Some(Ordering::Greater), + (_, true) => return Some(Ordering::Less), _ => (), } diff --git a/rust/src/notus/packages/rpm.rs b/rust/src/notus/packages/rpm.rs index 0c4b839fa..5ea6e0d5d 100644 --- a/rust/src/notus/packages/rpm.rs +++ b/rust/src/notus/packages/rpm.rs @@ -446,6 +446,39 @@ mod rpm_tests { full_version: "1.2.3-5.x86_64".to_string(), }; assert!(package1 < package2); + + let package1 = Rpm { + name: "vim-minimal".to_string(), + epoch: 0, + version: PackageVersion("9.0.2092".to_string()), + release: PackageVersion("8.oe2403".to_string()), + arch: "x86_64".to_string(), + full_name: "vim-minimal-9.0.2092-8.oe2403.x86_64".to_string(), + full_version: "9.0.2092-8.oe2403.x86_64".to_string(), + }; + + let package2 = Rpm { + name: "vim-minimal".to_string(), + epoch: 0, + version: PackageVersion("4294967296.0.2092".to_string()), + release: PackageVersion("8.oe2403".to_string()), + arch: "x86_64".to_string(), + full_name: "vim-minimal-4294967296.0.2092-8.oe2403.x86_64".to_string(), + full_version: "4294967296.0.2092-8.oe2403.x86_64".to_string(), + }; + assert!(package1 < package2); + + let package2 = Rpm { + name: "vim-minimal".to_string(), + epoch: 0, + version: PackageVersion("429496729542949672954294967295.0.2092".to_string()), + release: PackageVersion("8.oe2403".to_string()), + arch: "x86_64".to_string(), + full_name: "vim-minimal-429496729542949672954294967295.0.2092-8.oe2403.x86_64" + .to_string(), + full_version: "429496729542949672954294967295.0.2092-8.oe2403.x86_64".to_string(), + }; + assert!(package1 < package2); } #[test]