Skip to content

Commit

Permalink
feat(os-adapter): support gentoo linux
Browse files Browse the repository at this point in the history
  • Loading branch information
mrl5 committed Feb 1, 2022
1 parent 54a867d commit 3fcfce8
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 78 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ Discover CVEs for software.

- **Use case 1)** as a [Funtoo Linux] user I want to have awareness about CVEs on my system
- **Use case 2)** as user I want to list CVEs for given package
- **Use case 3)** as a [Gentoo Linux] user I want to have awareness about CVEs on my system

## DISCLAIMER

Running `vulner scan` doesn't guarantee that all CVEs present on your system will be
detected. It tries to map packages installed by the portage (funtoo package
manager) to a set of known NVD CPEs. It is possible that not all packages will
be successfully tagged.
detected. It tries to map packages installed by the [portage] to a set of known
NVD CPEs. It is possible that not all packages will be successfully tagged.

For more info about false negatives and false positives check
[docs/CAVEATS.md](docs/CAVEATS.md)
Expand Down Expand Up @@ -61,5 +61,7 @@ ADR.


[Funtoo Linux]: https://www.funtoo.org/
[Gentoo Linux]: https://www.gentoo.org/
[CVE]: https://nvd.nist.gov/vuln
[CPE]: https://nvd.nist.gov/products/cpe
[portage]: https://en.wikipedia.org/wiki/Portage_(software)
18 changes: 16 additions & 2 deletions crates/os-adapter/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,20 @@ use std::io;
use std::str::FromStr;
use std::vec::Vec;
mod linux_funtoo;
mod linux_gentoo;
mod portage;

pub trait OsAdapter {
pub trait OsInfo {
fn get_os(&self) -> &Os;
fn get_os_flavor(&self) -> Option<OsFlavor>;
}

pub trait OsPackages {
fn get_all_catpkgs(&self) -> Result<HashMap<String, Vec<Package>>, Box<dyn Error>>;
}

pub trait OsAdapter: OsInfo + OsPackages {}

pub fn get_adapter() -> Result<Box<dyn OsAdapter>, Box<dyn Error>> {
let os = Os::from_str(env::consts::OS)?;

Expand All @@ -46,19 +53,24 @@ pub enum OsFlavor<'a> {
#[derive(Debug, PartialEq)]
pub enum LinuxDistro {
Funtoo,
Gentoo,
}

pub fn get_supported_map() -> HashMap<Os, Vec<OsFlavor<'static>>> {
HashMap::from([(
Os::GnuLinux,
vec![OsFlavor::LinuxDistro(&LinuxDistro::Funtoo)],
vec![
OsFlavor::LinuxDistro(&LinuxDistro::Funtoo),
OsFlavor::LinuxDistro(&LinuxDistro::Gentoo),
],
)])
}

fn get_linux_adapter(id: LinuxDistro) -> Box<dyn OsAdapter> {
// https://refactoring.guru/design-patterns/factory-method
match id {
LinuxDistro::Funtoo => Box::new(linux_funtoo::Funtoo::new()),
LinuxDistro::Gentoo => Box::new(linux_gentoo::Gentoo::new()),
}
}

Expand Down Expand Up @@ -89,6 +101,7 @@ impl FromStr for LinuxDistro {
// ID of https://www.freedesktop.org/software/systemd/man/os-release.html
match input {
"funtoo" => Ok(LinuxDistro::Funtoo),
"gentoo" => Ok(LinuxDistro::Gentoo),
_ => Err(io::Error::new(err_kind, err_msg)),
}
}
Expand All @@ -107,6 +120,7 @@ mod tests {
#[test]
fn it_should_know_supported_distros() {
assert!(LinuxDistro::from_str("funtoo").is_ok());
assert!(LinuxDistro::from_str("gentoo").is_ok());
assert!(LinuxDistro::from_str("debian").is_err());
}
}
80 changes: 7 additions & 73 deletions crates/os-adapter/src/adapter/linux_funtoo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,103 +5,37 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use cpe_tag::package::{convert_to_pkg, Package};
use std::collections::HashMap;
use std::error::Error;
use std::fs::read_dir;
use super::portage::Portage;
use std::path::Path;

pub struct Funtoo {
os: super::Os,
flavor: super::LinuxDistro,
pkg_dir: String,
}

impl Funtoo {
pub fn new() -> Self {
Self {
os: super::Os::GnuLinux,
flavor: super::LinuxDistro::Funtoo,
pkg_dir: "/var/db/pkg/".to_owned(),
}
}
}

impl super::OsAdapter for Funtoo {
impl super::OsAdapter for Funtoo {}

impl super::OsInfo for Funtoo {
fn get_os(&self) -> &super::Os {
&self.os
}

fn get_os_flavor(&self) -> Option<super::OsFlavor> {
Some(super::OsFlavor::LinuxDistro(&self.flavor))
}

fn get_all_catpkgs(&self) -> Result<HashMap<String, Vec<Package>>, Box<dyn Error>> {
let pkg_prefix_adapter: HashMap<&str, String> =
HashMap::from([("dev-libs", "lib".to_owned())]);
let skipped_dirs = vec!["virtual"];
let mut all_catpkgs = HashMap::new();

log::info!("walking {} ...", &self.pkg_dir);
for category in read_dir(Path::new(&self.pkg_dir))? {
let category = category?;
let path = &category.path();

if !path.is_dir() {
continue;
}

match category.file_name().into_string() {
Ok(ctgr) => {
if skipped_dirs.contains(&ctgr.as_str()) {
log::warn!("SKIPPING packages in {} ...", ctgr);
continue;
}

log::debug!("collecting packages in {} ...", ctgr);
let pkgs = list_pkgs(path, pkg_prefix_adapter.get(ctgr.as_str()))?;
all_catpkgs.insert(ctgr, pkgs);
}
Err(os_path) => {
log::error!("skipping {:?}", os_path);
continue;
}
}
}

Ok(all_catpkgs)
}
}

fn list_pkgs(path: &Path, prefix: Option<&String>) -> Result<Vec<Package>, Box<dyn Error>> {
let mut pkgs: Vec<Package> = vec![];

for pkg in read_dir(path)? {
let pkg = pkg?;
let path = &pkg.path();

if !path.is_dir() {
continue;
}

match pkg.file_name().into_string() {
Ok(p) => {
if let Some(converted) = convert_to_pkg(&p) {
pkgs.push(converted);
}

if let Some(prfx) = prefix {
if let Some(converted) = convert_to_pkg(&format!("{}{}", prfx, &p)) {
pkgs.push(converted);
}
}
}
Err(os_string) => {
log::error!("skipping {:?}", os_string);
continue;
}
}
impl Portage for Funtoo {
fn get_pkg_dir(&self) -> &Path {
Path::new("/var/db/pkg/")
}

Ok(pkgs)
}
41 changes: 41 additions & 0 deletions crates/os-adapter/src/adapter/linux_gentoo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* SPDX-License-Identifier: MPL-2.0
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use super::portage::Portage;
use std::path::Path;

pub struct Gentoo {
os: super::Os,
flavor: super::LinuxDistro,
}

impl Gentoo {
pub fn new() -> Self {
Self {
os: super::Os::GnuLinux,
flavor: super::LinuxDistro::Funtoo,
}
}
}

impl super::OsAdapter for Gentoo {}

impl super::OsInfo for Gentoo {
fn get_os(&self) -> &super::Os {
&self.os
}

fn get_os_flavor(&self) -> Option<super::OsFlavor> {
Some(super::OsFlavor::LinuxDistro(&self.flavor))
}
}

impl Portage for Gentoo {
fn get_pkg_dir(&self) -> &Path {
Path::new("/var/db/pkg/")
}
}
91 changes: 91 additions & 0 deletions crates/os-adapter/src/adapter/portage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* SPDX-License-Identifier: MPL-2.0
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use cpe_tag::package::{convert_to_pkg, Package};
use std::collections::HashMap;
use std::error::Error;
use std::fs::read_dir;
use std::path::Path;

pub trait Portage {
fn get_pkg_dir(&self) -> &Path;
}

impl<T> super::OsPackages for T
where
T: Portage,
{
// https://riptutorial.com/rust/example/22917/inheritance-with-traits
fn get_all_catpkgs(&self) -> Result<HashMap<String, Vec<Package>>, Box<dyn Error>> {
let pkg_prefix_adapter: HashMap<&str, String> =
HashMap::from([("dev-libs", "lib".to_owned())]);
let skipped_dirs = vec!["virtual"];
let mut all_catpkgs = HashMap::new();

log::info!("walking {:?} ...", &self.get_pkg_dir().as_os_str());
for category in read_dir(&self.get_pkg_dir())? {
let category = category?;
let path = &category.path();

if !path.is_dir() {
continue;
}

match category.file_name().into_string() {
Ok(ctgr) => {
if skipped_dirs.contains(&ctgr.as_str()) {
log::warn!("SKIPPING packages in {} ...", ctgr);
continue;
}

log::debug!("collecting packages in {} ...", ctgr);
let pkgs = list_pkgs(path, pkg_prefix_adapter.get(ctgr.as_str()))?;
all_catpkgs.insert(ctgr, pkgs);
}
Err(os_path) => {
log::error!("skipping {:?}", os_path);
continue;
}
}
}

Ok(all_catpkgs)
}
}

fn list_pkgs(path: &Path, prefix: Option<&String>) -> Result<Vec<Package>, Box<dyn Error>> {
let mut pkgs: Vec<Package> = vec![];

for pkg in read_dir(path)? {
let pkg = pkg?;
let path = &pkg.path();

if !path.is_dir() {
continue;
}

match pkg.file_name().into_string() {
Ok(p) => {
if let Some(converted) = convert_to_pkg(&p) {
pkgs.push(converted);
}

if let Some(prfx) = prefix {
if let Some(converted) = convert_to_pkg(&format!("{}{}", prfx, &p)) {
pkgs.push(converted);
}
}
}
Err(os_string) => {
log::error!("skipping {:?}", os_string);
continue;
}
}
}

Ok(pkgs)
}

0 comments on commit 3fcfce8

Please sign in to comment.