Skip to content

Commit

Permalink
Merge branch 'main' into type_hints_version
Browse files Browse the repository at this point in the history
  • Loading branch information
rhythmrx9 committed Feb 18, 2022
2 parents 2ca6237 + ab07fb9 commit e5e30c1
Show file tree
Hide file tree
Showing 22 changed files with 1,405 additions and 60 deletions.
1 change: 1 addition & 0 deletions .github/actions/spelling/allow.txt
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ liblas
libnss
libpng
libraryname
librsvg
libsndfile
libsoup
libsqlite
Expand Down
26 changes: 16 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,23 +194,23 @@ The following checkers are available for finding components in binary files:

<!--CHECKERS TABLE BEGIN-->
| | | | Available checkers | | | |
|--------------- |--------- |------------- |---------- |------------- |---------- |------------ |
|--------------- |--------------- |--------- |------------- |------------- |---------- |---------- |
| accountsservice |avahi |bash |bind |binutils |bolt |bubblewrap |
| busybox |bzip2 |cronie |cryptsetup |cups |curl |dbus |
| dnsmasq |dovecot |dpkg |enscript |expat |ffmpeg |freeradius |
| ftp |gcc |gimp |glibc |gnomeshell |gnupg |gnutls |
| gpgme |gstreamer |gupnp |haproxy |hdf5 |hostapd |hunspell |
| icecast |icu |irssi |kbd |kerberos |kexectools |libarchive |
| libbpg |libdb |libgcrypt |libical |libjpeg_turbo |liblas |libnss |
| libsndfile |libsoup |libsrtp |libssh2 |libtiff |libvirt |libvncserver |
| libxslt |lighttpd |logrotate |lua |mariadb |mdadm |memcached |
| mtr |mysql |nano |ncurses |nessus |netpbm |nginx |
| node |ntp |open_vm_tools |openafs |openjpeg |openldap |openssh |
| openssl |openswan |openvpn |p7zip |pcsc_lite |pigz |png |
| polarssl_fedora |poppler |postgresql |pspp |python |qt |radare2 |
| rsyslog |samba |sane_backends |sqlite |strongswan |subversion |sudo |
| syslogng |systemd |tcpdump |trousers |varnish |webkitgtk |wireshark |
| wpa_supplicant |xerces |xml2 |zlib |zsh | | |
| librsvg |libsndfile |libsoup |libsrtp |libssh2 |libtiff |libvirt |
| libvncserver |libxslt |lighttpd |logrotate |lua |mariadb |mdadm |
| memcached |mtr |mysql |nano |ncurses |nessus |netpbm |
| nginx |node |ntp |open_vm_tools |openafs |openjpeg |openldap |
| openssh |openssl |openswan |openvpn |p7zip |pcsc_lite |pigz |
| png |polarssl_fedora |poppler |postgresql |pspp |python |qt |
| radare2 |rsyslog |samba |sane_backends |sqlite |strongswan |subversion |
| sudo |syslogng |systemd |tcpdump |trousers |varnish |webkitgtk |
| wireshark |wpa_supplicant |xerces |xml2 |zlib |zsh | |
<!--CHECKERS TABLE END-->

All the checkers can be found in the checkers directory, as can the
Expand All @@ -228,6 +228,12 @@ The scanner examines the `pom.xml` file within a Java package archive to identif

JAR, WAR and EAR archives are supported.

### Javascript

The scanner examines the `package-lock.json` file within a javascript application
to identify components. The package names and versions are used to search the database for vulnerabilities.


### Python

The scanner examines the `PKG-INFO` and `METADATA` files for an installed Python package to extract the component name and version which
Expand Down
8 changes: 4 additions & 4 deletions cve_bin_tool/available_fix/debian_cve_tracker.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Copyright (C) 2021 Intel Corporation
# SPDX-License-Identifier: GPL-3.0-or-later

from json import dump, load, loads
from json import dump, load
from os.path import exists, expanduser, getmtime, join
from time import time
from typing import Dict
from urllib import request

import requests

from cve_bin_tool.cve_scanner import CVEData
from cve_bin_tool.log import LOGGER
Expand Down Expand Up @@ -96,8 +97,7 @@ def update_json():
"""Update the Debian CVE JSON file"""

LOGGER.info("Updating Debian CVE JSON file for checking available fixes.")
response = request.urlopen(JSON_URL).read().decode("utf-8") # nosec - static url
response = loads(response)
response = requests.get(JSON_URL).json()
with open(DEB_CVE_JSON_PATH, "w") as debian_json:
dump(response, debian_json, indent=4)
LOGGER.info("Debian CVE JSON file for checking available fixes is updated.")
11 changes: 5 additions & 6 deletions cve_bin_tool/available_fix/redhat_cve_tracker.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Copyright (C) 2021 Intel Corporation
# SPDX-License-Identifier: GPL-3.0-or-later

from json import loads
from re import search, split
from typing import Dict
from urllib import error, request

import requests

from cve_bin_tool.cve_scanner import CVEData
from cve_bin_tool.log import LOGGER
Expand Down Expand Up @@ -74,10 +74,9 @@ def cve_info(

def get_data(self, cve_number: str, product: str):
try:
full_query = f"{RH_CVE_API}/{cve_number}.json" # static https url above
response = request.urlopen(full_query).read().decode("utf-8") # nosec
return loads(response)
except error.HTTPError as e:
full_query = f"{RH_CVE_API}/{cve_number}.json"
return requests.get(full_query).json()
except requests.HTTPError as e:
LOGGER.debug(e)

def parse_package_data(self, package_data: str) -> str:
Expand Down
1 change: 1 addition & 0 deletions cve_bin_tool/checkers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"libjpeg_turbo",
"liblas",
"libnss",
"librsvg",
"libsndfile",
"libsoup",
"libsrtp",
Expand Down
18 changes: 18 additions & 0 deletions cve_bin_tool/checkers/librsvg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright (C) 2022 Intel Corporation
# SPDX-License-Identifier: GPL-3.0-or-later

"""
CVE checker for librsvg
https://www.cvedetails.com/vulnerability-list/vendor_id-283/product_id-23082/Gnome-Librsvg.html
"""

from cve_bin_tool.checkers import Checker


class LibrsvgChecker(Checker):
CONTAINS_PATTERNS = []
FILENAME_PATTERNS = [r"librsvg"]
VERSION_PATTERNS = [r"librsvg[0-9]?-([0-9]+\.[0-9]+\.[0-9]+)"]
VENDOR_PRODUCT = [("gnome", "librsvg")]
14 changes: 6 additions & 8 deletions cve_bin_tool/checkers/sqlite.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
"""
import re
import urllib.error as error
import urllib.request as request

import requests

from cve_bin_tool.checkers import Checker
from cve_bin_tool.log import LOGGER
Expand All @@ -31,13 +31,11 @@ def get_version_map():
re.compile(r'"*(\d{4}-\d{2}-\d{2} \d+:\d+:\d+ [\w]+)"*'),
]
try:
response = request.urlopen(changeurl) # nosec - static url above
lines = response.readlines()
response = requests.get(changeurl).text
lines = response.splitlines()

last_version = "UNKNOWN"
for line_encoded in lines:
line = line_encoded.decode("UTF-8")

for line in lines:
ver_match = version_pattern.search(line)
if ver_match:
last_version = ver_match.group(1)
Expand All @@ -47,7 +45,7 @@ def get_version_map():
version_map.append([last_version, id_match.group(1)])
break

except error.URLError as err:
except requests.RequestException as err:
LOGGER.error("Could not fetch " + changeurl + ", " + str(err))

return version_map
Expand Down
22 changes: 10 additions & 12 deletions cve_bin_tool/version.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
# Copyright (C) 2021 Intel Corporation
# SPDX-License-Identifier: GPL-3.0-or-later

import json
import textwrap
from urllib import request

import requests
from packaging import version

from cve_bin_tool.log import LOGGER
Expand All @@ -18,19 +17,18 @@ def check_latest_version():
name: str = "cve-bin-tool"
url: str = f"https://pypi.org/pypi/{name}/json"
try:
with request.urlopen(url) as resp: # nosec - static url above
package_json = json.load(resp)
pypi_version = package_json["info"]["version"]
if pypi_version != VERSION:
package_json = requests.get(url).json()
pypi_version = package_json["info"]["version"]
if pypi_version != VERSION:
LOGGER.info(
f"[bold red]You are running version {VERSION} of {name} but the latest PyPI Version is {pypi_version}.[/]",
extra={"markup": True},
)
if version.parse(VERSION) < version.parse(pypi_version):
LOGGER.info(
f"[bold red]You are running version {VERSION} of {name} but the latest PyPI Version is {pypi_version}.[/]",
"[bold yellow]Alert: We recommend using the latest stable release.[/]",
extra={"markup": True},
)
if version.parse(VERSION) < version.parse(pypi_version):
LOGGER.info(
"[bold yellow]Alert: We recommend using the latest stable release.[/]",
extra={"markup": True},
)
except Exception as error:
LOGGER.warning(
textwrap.dedent(
Expand Down
70 changes: 67 additions & 3 deletions cve_bin_tool/version_scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import annotations

import json
import os
import subprocess
import sys
Expand Down Expand Up @@ -128,6 +129,7 @@ def is_executable(self, filename: str) -> tuple[bool, str | None]:
and ("PKG-INFO: " not in output)
and ("METADATA: " not in output)
and ("pom.xml" not in output)
and ("package-lock.json" not in output)
):
return False, None
# otherwise use python implementation of file
Expand Down Expand Up @@ -175,8 +177,11 @@ def scan_file(self, filename: str) -> infogen:

# Check for Java package
if output and "pom.xml" in output:
java_lines = "\n".join(lines.splitlines())
yield from self.run_java_checker(filename, java_lines)
yield from self.run_java_checker(filename)

# Javascript checker
if output and "package-lock.json" in output:
yield from self.run_js_checker(filename)

# If python package then strip the lines to avoid detecting other product strings
if output and ("PKG-INFO: " in output or "METADATA: " in output):
Expand Down Expand Up @@ -206,7 +211,7 @@ def find_java_vendor(
self.logger.debug(f"{file_path} {product} {version} by {vendor}")
return ProductInfo(vendor, product, version), file_path
return None, None

def run_java_checker(self, filename: str, lines: str) -> infogen:
"""Process maven pom.xml file and extract product and dependency details"""
tree = ET.parse(filename)
Expand Down Expand Up @@ -254,6 +259,65 @@ def run_java_checker(self, filename: str, lines: str) -> infogen:
yield product_info, file_path

self.logger.debug(f"Done scanning file: {filename}")

def find_js_vendor(self, product: str, version: str) -> list[list[str]] | None:
"""Find vendor for Javascript product"""
if version == "*":
return None
vendor_package_pair = self.cve_db.get_vendor_product_pairs(product)
vendorlist: list[list[str]] = []
if vendor_package_pair != []:
# To handle multiple vendors, return all combinations of product/vendor mappings
for v in vendor_package_pair:
vendor = v["vendor"]
file_path = "".join(self.file_stack)
# Tidy up version string
if "^" in version:
version = version[1:]
self.logger.debug(f"{file_path} {product} {version} by {vendor}")
vendorlist.append([ProductInfo(vendor, product, version), file_path])
return vendorlist if len(vendorlist) > 0 else None
return None

def run_js_checker(self, filename: str) -> None:
"""Process package-lock.json file and extract product and dependency details"""
fh = open(filename)
data = json.load(fh)
product = data["name"]
version = data["version"]
vendor = self.find_js_vendor(product, version)
if vendor is not None:
for v in vendor:
yield v[0], v[1] # product_info, file_path
# Now process dependencies
for i in data["dependencies"]:
# To handle @actions/<product>: lines, extract product name from line
product = i.split("/")[1] if "/" in i else i
# Handle different formats. Either <product> : <version> or
# <product>: {
# ...
# "version" : <version>
# ...
# }
try:
version = data["dependencies"][i]["version"]
except Exception:
# Cater for case when version field not present
version = data["dependencies"][i]
vendor = self.find_js_vendor(product, version)
if vendor is not None:
for v in vendor:
yield v[0], v[1] # product_info, file_path
if "requires" in data["dependencies"][i]:
for r in data["dependencies"][i]["requires"]:
# To handle @actions/<product>: lines, extract product name from line
product = r.split("/")[1] if "/" in r else r
version = data["dependencies"][i]["requires"][r]
vendor = self.find_js_vendor(product, version)
if vendor is not None:
for v in vendor:
yield v[0], v[1] # product_info, file_path
self.logger.debug(f"Done scanning file: {filename}")

def run_python_package_checkers(self, filename: str, lines: str) -> infogen:
"""
Expand Down
20 changes: 10 additions & 10 deletions doc/MANUAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,23 +118,23 @@ which is useful if you're trying the latest code from

<!--CHECKERS TABLE BEGIN-->
| | | | Available checkers | | | |
|--------------- |--------- |------------- |---------- |------------- |---------- |------------ |
|--------------- |--------------- |--------- |------------- |------------- |---------- |---------- |
| accountsservice |avahi |bash |bind |binutils |bolt |bubblewrap |
| busybox |bzip2 |cronie |cryptsetup |cups |curl |dbus |
| dnsmasq |dovecot |dpkg |enscript |expat |ffmpeg |freeradius |
| ftp |gcc |gimp |glibc |gnomeshell |gnupg |gnutls |
| gpgme |gstreamer |gupnp |haproxy |hdf5 |hostapd |hunspell |
| icecast |icu |irssi |kbd |kerberos |kexectools |libarchive |
| libbpg |libdb |libgcrypt |libical |libjpeg_turbo |liblas |libnss |
| libsndfile |libsoup |libsrtp |libssh2 |libtiff |libvirt |libvncserver |
| libxslt |lighttpd |logrotate |lua |mariadb |mdadm |memcached |
| mtr |mysql |nano |ncurses |nessus |netpbm |nginx |
| node |ntp |open_vm_tools |openafs |openjpeg |openldap |openssh |
| openssl |openswan |openvpn |p7zip |pcsc_lite |pigz |png |
| polarssl_fedora |poppler |postgresql |pspp |python |qt |radare2 |
| rsyslog |samba |sane_backends |sqlite |strongswan |subversion |sudo |
| syslogng |systemd |tcpdump |trousers |varnish |webkitgtk |wireshark |
| wpa_supplicant |xerces |xml2 |zlib |zsh | | |
| librsvg |libsndfile |libsoup |libsrtp |libssh2 |libtiff |libvirt |
| libvncserver |libxslt |lighttpd |logrotate |lua |mariadb |mdadm |
| memcached |mtr |mysql |nano |ncurses |nessus |netpbm |
| nginx |node |ntp |open_vm_tools |openafs |openjpeg |openldap |
| openssh |openssl |openswan |openvpn |p7zip |pcsc_lite |pigz |
| png |polarssl_fedora |poppler |postgresql |pspp |python |qt |
| radare2 |rsyslog |samba |sane_backends |sqlite |strongswan |subversion |
| sudo |syslogng |systemd |tcpdump |trousers |varnish |webkitgtk |
| wireshark |wpa_supplicant |xerces |xml2 |zlib |zsh | |
<!--CHECKERS TABLE END-->

For a quick overview of usage and how it works, you can also see [the readme file](README.md).
Expand Down
3 changes: 2 additions & 1 deletion requirements.csv
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ srossross_not_in_db,rpmfile
indygreg_not_in_db,zstandard
nir0s_not_in_db,distro
tiran_not_in_db,defusedxml
python_not_in_db,importlib_metadata
python_not_in_db,importlib_metadata
python,requests
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ zstandard; python_version >= "3.4"
reportlab
distro
defusedxml
importlib_metadata; python_version < "3.8"
importlib_metadata; python_version < "3.8"
requests
Binary file not shown.
Binary file not shown.

0 comments on commit e5e30c1

Please sign in to comment.