Skip to content

Commit

Permalink
Merge branch 'intel:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
ffontaine authored May 10, 2023
2 parents 5267ddd + b94d922 commit 0e9749a
Show file tree
Hide file tree
Showing 20 changed files with 124 additions and 14 deletions.
3 changes: 2 additions & 1 deletion cve_bin_tool/checkers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@ from cve_bin_tool.checkers import Checker
class CurlChecker(Checker):
```

Every checker must contain following 4 class attributes specific to product(ex: curl)
Every checker may contain following 5 class attributes specific to product(ex: curl)
you are making checker for:

1. CONTAINS_PATTERNS - list of commonly found strings in the binary of the product
2. FILENAME_PATTERNS - list of different filename for the product
3. VERSION_PATTERNS - list of version patterns found in binary of the product.
4. VENDOR_PRODUCT - list of vendor product pairs for the product as they appear in
NVD.
5. IGNORE_PATTERNS (optional) - list of patterns that could cause false positives (e.g. error messages that mention specific product/versions)

`CONTAINS_PATTERN`, `FILENAME_PATTERNS` and `VERSION_PATTERNS` supports regex to cover
wide range of use cases.
Expand Down
10 changes: 9 additions & 1 deletion cve_bin_tool/checkers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"binutils",
"bird",
"bison",
"bluez",
"boinc",
"botan",
"bro",
Expand Down Expand Up @@ -328,6 +329,10 @@ def __new__(cls, name, bases, props):
raise InvalidCheckerError(
f"Checker {name} has a VENDOR_PRODUCT string that is not lowercase"
)
if cls.IGNORE_PATTERNS is None:
cls.IGNORE_PATTERNS = []
else:
cls.IGNORE_PATTERNS = list(map(re.compile, cls.IGNORE_PATTERNS))
# Compile regex
cls.CONTAINS_PATTERNS = list(map(re.compile, cls.CONTAINS_PATTERNS))
cls.VERSION_PATTERNS = list(map(re.compile, cls.VERSION_PATTERNS))
Expand All @@ -342,6 +347,7 @@ class Checker(metaclass=CheckerMetaClass):
VERSION_PATTERNS: list[str] = []
FILENAME_PATTERNS: list[str] = []
VENDOR_PRODUCT: list[tuple[str, str]] = []
IGNORE_PATTERNS: list[str] = []

def guess_contains(self, lines):
if any(pattern.search(lines) for pattern in self.CONTAINS_PATTERNS):
Expand All @@ -358,6 +364,8 @@ def get_version(self, lines, filename):
version_info["is_or_contains"] = "contains"

if "is_or_contains" in version_info:
version_info["version"] = regex_find(lines, self.VERSION_PATTERNS)
version_info["version"] = regex_find(
lines, self.VERSION_PATTERNS, self.IGNORE_PATTERNS
)

return version_info
24 changes: 24 additions & 0 deletions cve_bin_tool/checkers/bluez.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright (C) 2023 Orange
# SPDX-License-Identifier: GPL-3.0-or-later


"""
CVE checker for bluez
https://www.cvedetails.com/product/35116/Bluez-Bluez.html?vendor_id=8316
https://www.cvedetails.com/product/35329/Bluez-Project-Bluez.html?vendor_id=3242
"""
from __future__ import annotations

from cve_bin_tool.checkers import Checker


class BluezChecker(Checker):
CONTAINS_PATTERNS: list[str] = []
FILENAME_PATTERNS: list[str] = []
VERSION_PATTERNS = [
r"bluez-([0-9]+\.[0-9]+)",
r"([0-9]+\.[0-9]+)\r?\n[a-zA-Z :]*(?:BlueZ|hcidump|hcitool|OBEX daemon)",
]
VENDOR_PRODUCT = [("bluez", "bluez"), ("bluez_project", "bluez")]
2 changes: 1 addition & 1 deletion cve_bin_tool/checkers/libtiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ class LibtiffChecker(Checker):
r'TIFF directory is missing required "StripByteCounts" field, calculating from imagelength',
]
FILENAME_PATTERNS = [r"libtiff.so."]
VERSION_PATTERNS = [r"LIBTIFF, Version ([0-9]+\.[0-9]+\.[0-9]+)"]
VERSION_PATTERNS = [r"LIBTIFF, Version ([0-9]+\.[0-9]+\.[0-9]+)\r?\nCopyright"]
VENDOR_PRODUCT = [("libtiff", "libtiff")]
5 changes: 4 additions & 1 deletion cve_bin_tool/checkers/pango.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@
class PangoChecker(Checker):
CONTAINS_PATTERNS: list[str] = []
FILENAME_PATTERNS: list[str] = []
VERSION_PATTERNS = [r"([0-9]+\.[0-9]+\.[0-9]+)\r?\n[pP]ango"]
VERSION_PATTERNS = [
r"([0-9]+\.[0-9]+\.[0-9]+)\r?\n/etc/pango",
r"([0-9]+\.[0-9]+\.[0-9]+)\r?\nPango version",
]
VENDOR_PRODUCT = [("gnome", "pango"), ("pango", "pango")]
2 changes: 1 addition & 1 deletion cve_bin_tool/checkers/proftpd.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@
class ProftpdChecker(Checker):
CONTAINS_PATTERNS: list[str] = []
FILENAME_PATTERNS: list[str] = []
VERSION_PATTERNS = [r"ProFTPD ([0-9]+\.[0-9]+\.[0-9a-z]+)"]
VERSION_PATTERNS = [r"ProFTPD ([0-9]+\.[0-9]+\.[0-9a-z]+) "]
VENDOR_PRODUCT = [("proftpd_project", "proftpd"), ("proftpd", "proftpd")]
2 changes: 1 addition & 1 deletion cve_bin_tool/checkers/tcpdump.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ class TcpdumpChecker(Checker):
r"tcpdump-([0-9]+\.[0-9]+\.[0-9]+)",
r"([0-9]+\.[0-9]+\.[0-9]+)\r?\n[0-9a-f]*lookup_(?:emem|protoid)",
r"Running\r?\n([0-9]+\.[0-9]+\.[0-9]+)\r?\n0123456789",
r"tcpdump[0-9a-zA-Z ,!'%:_=\(\)\\\.\-\r\n]*([0-9]+\.[0-9]+\.[0-9]+)",
r"tcpdump[0-9a-zA-Z ,!'%:_=\(\)\\\.\-\r\n]*\r?\n([0-9]+\.[0-9]+\.[0-9]+)",
]
VENDOR_PRODUCT = [("tcpdump", "tcpdump")]
7 changes: 6 additions & 1 deletion cve_bin_tool/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,19 @@ def __missing__(self, key: str) -> list[CVE] | set[str]:
return self[key]


def regex_find(lines: str, version_patterns: list[Pattern[str]]) -> str:
def regex_find(
lines: str, version_patterns: list[Pattern[str]], ignore: list[Pattern[str]]
) -> str:
"""Search a set of lines to find a match for the given regex"""
new_guess = ""

for pattern in version_patterns:
match = pattern.search(lines)
if match:
new_guess = match.group(1).strip()
for i in ignore:
if str(i) in str(new_guess) or str(new_guess) in str(i):
new_guess = ""
break
if new_guess != "":
new_guess = new_guess.replace("_", ".")
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
22 changes: 22 additions & 0 deletions test/test_checkers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Copyright (C) 2021 Intel Corporation
# SPDX-License-Identifier: GPL-3.0-or-later

from __future__ import annotations

import re
import sys

Expand All @@ -25,11 +27,13 @@ class MyChecker(Checker):
VERSION_PATTERNS = [r"for"]
FILENAME_PATTERNS = [r"myproduct"]
VENDOR_PRODUCT = [("myvendor", "myproduct")]
IGNORE_PATTERNS = [r"ignore"]

assert type(MyChecker.CONTAINS_PATTERNS[0]) == Pattern
assert type(MyChecker.VERSION_PATTERNS[0]) == Pattern
assert type(MyChecker.FILENAME_PATTERNS[0]) == Pattern
assert type(MyChecker.VENDOR_PRODUCT[0]) == VendorProductPair
assert type(MyChecker.IGNORE_PATTERNS[0]) == Pattern

def test_no_vpkg(self):
with pytest.raises(AssertionError) as e:
Expand All @@ -39,6 +43,7 @@ class MyChecker(Checker):
VERSION_PATTERNS = [r"for"]
FILENAME_PATTERNS = [r"myproduct"]
PRODUCT_NAME = "mychecker"
IGNORE_PATTERNS = [r"ignore"]

assert e.value.args[0] == "MyChecker needs at least one vendor product pair"

Expand Down Expand Up @@ -139,3 +144,20 @@ def test_filename_is(self, checker_name, file_name, expected_results):

for result, expected_result in zip(results, expected_results):
assert result["is_or_contains"] == "is"

class MyFakeChecker(Checker):
CONTAINS_PATTERNS: list[str] = []
FILENAME_PATTERNS: list[str] = [r"checker"]
VERSION_PATTERNS = [r"mychecker-([0-9].[0-9]+)"]
VENDOR_PRODUCT = [("my", "checker")]
IGNORE_PATTERNS = [r"mychecker-5.6"]

string = "Some other lines. \n Ignore this version pattern mychecker-5.6. \n Consider this version pattern mychecker-5.8. \n Some more lines."
lines = string.split("\n")
checker = MyFakeChecker()

result1 = checker.get_version(lines[1], "")
assert result1["version"] == "UNKNOWN"

result2 = checker.get_version(lines[2], "")
assert result2["version"] == "5.8"
33 changes: 33 additions & 0 deletions test/test_data/bluez.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright (C) 2022 Orange
# SPDX-License-Identifier: GPL-3.0-or-later

mapping_test_data = [
{"product": "bluez", "version": "5.28", "version_strings": ["bluez-5.28"]},
{
"product": "bluez",
"version": "5.50",
"version_strings": ["5.50\nUsage: hcidump"],
},
{"product": "bluez", "version": "5.50", "version_strings": ["5.50\nhcitool"]},
{"product": "bluez", "version": "5.66", "version_strings": ["5.66\nBlueZ"]},
]
package_test_data = [
{
"url": "http://rpmfind.net/linux/fedora/linux/development/rawhide/Everything/aarch64/os/Packages/b/",
"package_name": "bluez-5.66-5.fc38.aarch64.rpm",
"product": "bluez",
"version": "5.66",
},
{
"url": "http://ftp.fr.debian.org/debian/pool/main/b/bluez/",
"package_name": "bluez_5.50-1.2~deb10u2_amd64.deb",
"product": "bluez",
"version": "5.50",
},
{
"url": "https://downloads.openwrt.org/releases/packages-19.07/x86_64/packages/",
"package_name": "bluez-daemon_5.50-5_x86_64.ipk",
"product": "bluez",
"version": "5.50",
},
]
14 changes: 13 additions & 1 deletion test/test_data/libtiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"version": "4.0.2",
"version_strings": [
'TIFF directory is missing required \\"StripByteCounts\\" field, calculating from imagelength',
"LIBTIFF, Version 4.0.2",
"LIBTIFF, Version 4.0.2\nCopyright",
],
}
]
Expand All @@ -24,4 +24,16 @@
"product": "libtiff",
"version": "4.0.3",
},
{
"url": "http://ftp.fr.debian.org/debian/pool/main/t/tiff/",
"package_name": "libtiff5_4.2.0-1+deb11u4_amd64.deb",
"product": "libtiff",
"version": "4.2.0",
},
{
"url": "https://downloads.openwrt.org/releases/packages-19.07/x86_64/packages/",
"package_name": "libtiff_4.1.0-1_x86_64.ipk",
"product": "libtiff",
"version": "4.1.0",
},
]
4 changes: 0 additions & 4 deletions test/test_data/lynx.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,23 @@
"package_name": "lynx-2.9.0-dev.10.2.fc37.1.aarch64.rpm",
"product": "lynx",
"version": "2.9.0dev.10",
"other_products": ["proftpd"],
},
{
"url": "http://rpmfind.net/linux/fedora-secondary/development/rawhide/Everything/ppc64le/os/Packages/l/",
"package_name": "lynx-2.9.0-dev.10.2.fc37.1.ppc64le.rpm",
"product": "lynx",
"version": "2.9.0dev.10",
"other_products": ["proftpd"],
},
{
"url": "http://ftp.fr.debian.org/debian/pool/main/l/lynx/",
"package_name": "lynx_2.8.9dev11-1_arm64.deb",
"product": "lynx",
"version": "2.8.9dev.11",
"other_products": ["proftpd"],
},
{
"url": "https://downloads.openwrt.org/releases/packages-19.07/x86_64/packages/",
"package_name": "lynx_2.8.9rel.1-1_x86_64.ipk",
"product": "lynx",
"version": "2.8.9rel.1",
"other_products": ["proftpd"],
},
]
7 changes: 6 additions & 1 deletion test/test_data/pango.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@
# SPDX-License-Identifier: GPL-3.0-or-later

mapping_test_data = [
{
"product": "pango",
"version": "1.40.5",
"version_strings": ["1.40.5\n/etc/pango"],
},
{
"product": "pango",
"version": "1.40.5",
"version_strings": ["1.40.5\nPango version"],
}
},
]
package_test_data = [
{
Expand Down
2 changes: 1 addition & 1 deletion test/test_data/proftpd.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{
"product": "proftpd",
"version": "1.3.8rc4",
"version_strings": ["ProFTPD 1.3.8rc4"],
"version_strings": ["ProFTPD 1.3.8rc4 "],
}
]
package_test_data = [
Expand Down
1 change: 1 addition & 0 deletions test/test_data/tcpdump.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"version": "4.9.2",
"version_strings": ["Running\n4.9.2\n0123456789"],
},
{"product": "tcpdump", "version": "4.1.1", "version_strings": ["tcpdump\n4.1.1"]},
]
package_test_data = [
{
Expand Down

0 comments on commit 0e9749a

Please sign in to comment.