-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcounter3.py
144 lines (128 loc) · 6.87 KB
/
counter3.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/usr/bin/python
import os
import json
import re
from collections import defaultdict
# Define the ranges for each LTS, expressed as dictionaries with range tuples
lts_ranges = [
{'version': '3.0', 'range': ((3, 0, 0), (3, 0, 101))},
{'version': '3.2', 'range': ((3, 2, 0), (3, 2, 102))},
{'version': '3.4', 'range': ((3, 4, 0), (3, 4, 113))},
{'version': '3.10', 'range': ((3, 10, 0), (3, 10, 108))},
{'version': '3.12', 'range': ((3, 12, 0), (3, 12, 74))},
{'version': '3.14', 'range': ((3, 14, 0), (3, 14, 79))},
{'version': '3.16', 'range': ((3, 16, 0), (3, 16, 85))},
{'version': '3.18', 'range': ((3, 18, 0), (3, 18, 140))},
{'version': '4.1', 'range': ((4, 1, 0), (4, 1, 52))},
{'version': '4.4', 'range': ((4, 4, 0), (4, 4, 302))},
{'version': '4.9', 'range': ((4, 9, 0), (4, 9, 337))},
{'version': '4.14', 'range': ((4, 14, 0), (4, 14, 336))},
{'version': '4.18', 'range': ((4, 18, 0), (4, 18, 20))},
{'version': '4.19', 'range': ((4, 19, 0), (4, 19, 315))},
{'version': '5.4', 'range': ((5, 4, 0), (5, 4, 277))},
{'version': '5.10', 'range': ((5, 10, 0), (5, 10, 218))},
{'version': '5.15', 'range': ((5, 15, 0), (5, 15, 160))},
{'version': '6.1', 'range': ((6, 1, 0), (6, 1, 92))},
{'version': '6.6', 'range': ((6, 6, 0), (6, 6, 32))},
]
# Function to check if a version falls within a given range
def is_version_in_range(version_tuple, version_range):
lower_bound, upper_bound = version_range
return lower_bound <= version_tuple <= upper_bound
# Function to check if a version string is a valid kernel version. This rules out git commit ids in the version field
def is_valid_kernel_version(version_str):
parts = version_str.split('.')
if len(parts) < 2:
return False
try:
# Pad the version parts to ensure they have three parts
while len(parts) < 3:
parts.append('0')
tuple(map(int, parts))
return True
except ValueError:
return False
# Directory containing JSON files
json_directory = "json"
# Directory containing CVE text files
cve_directory = "CVEs"
# Dictionary to hold counts of vulnerabilities per kernel version
vulnerability_counts = defaultdict(int)
# Dictionary to hold counts of vulnerabilities per patch version
patch_vulnerability_counts = defaultdict(int)
# Dictionary to hold counts of fixed vulnerabilities per kernel version
fixed_vulnerability_counts = defaultdict(int)
# Dictionary to hold counts of fixed vulnerabilities per patch version
patch_fixed_vulnerability_counts = defaultdict(int)
# Parse JSON files and count vulnerabilities
for json_file in os.listdir(json_directory):
json_path = os.path.join(json_directory, json_file)
if json_file.endswith(".json"):
try:
with open(json_path, 'r') as file:
cve_data = json.load(file)
affected_products = cve_data.get('containers', {}).get('cna', {}).get('affected', [])
for product in affected_products:
versions = product.get('versions', [])
for version_info in versions:
version_str = version_info.get('version', '')
if version_str and is_valid_kernel_version(version_str) and product['defaultStatus'] == 'affected':
version_tuple = tuple(map(int, version_str.split('.')))
for lts in lts_ranges:
if is_version_in_range(version_tuple, lts['range']):
vulnerability_counts[lts['version']] += 1
patch_vulnerability_counts[version_str] += 1
break
except Exception as e:
print(f"Failed to read {json_path}: {e}")
# Parse CVE text files and count fixed vulnerabilities
fixed_version_pattern = re.compile(r'fixed in (\d+\.\d+(?:\.\d+)?)')
for cve_file in os.listdir(cve_directory):
cve_path = os.path.join(cve_directory, cve_file)
if cve_file.endswith(".txt"):
try:
with open(cve_path, 'r') as file:
print(f"Reading {cve_path}")
cve_data = file.read()
for match in fixed_version_pattern.finditer(cve_data):
fixed_version = match.group(1)
# Check if the fixed version is a valid kernel version
if is_valid_kernel_version(fixed_version):
version_tuple = tuple(map(int, fixed_version.split('.')))
for lts in lts_ranges:
if is_version_in_range(version_tuple, lts['range']):
fixed_vulnerability_counts[lts['version']] += 1
patch_fixed_vulnerability_counts[fixed_version] += 1
break
else:
print(f"Invalid fixed version: {fixed_version}")
except Exception as e:
print(f"Failed to read {cve_path}: {e}")
# Output the results sorted by version
print("Vulnerabilities by minor version (e.g., 4.4):")
for version, count in sorted(vulnerability_counts.items(), key=lambda x: tuple(map(int, x[0].split('.')))):
print(f"Kernel version {version} is affected by {count} CVEs.")
print("\nVulnerabilities by full patch version (e.g., 4.4.1):")
for version, count in sorted(patch_vulnerability_counts.items(), key=lambda x: tuple(map(int, x[0].split('.')))):
print(f"Kernel version {version} is affected by {count} CVEs.")
print("\nFixed vulnerabilities by minor version (e.g., 4.4):")
for version, count in sorted(fixed_vulnerability_counts.items(), key=lambda x: tuple(map(int, x[0].split('.')))):
print(f"Kernel version {version} has {count} fixed CVEs.")
print("\nFixed vulnerabilities by full patch version (e.g., 4.4.1):")
for version, count in sorted(patch_fixed_vulnerability_counts.items(), key=lambda x: tuple(map(int, x[0].split('.')))):
print(f"Kernel version {version} has {count} fixed CVEs.")
# Output the results as a CSV table
print("\nCSV Table:")
print("Version, Vulnerabilities, Fixed")
all_versions = set(vulnerability_counts.keys()).union(set(fixed_vulnerability_counts.keys()))
for version in sorted(all_versions, key=lambda x: tuple(map(int, x.split('.')))):
vulnerabilities = vulnerability_counts.get(version, 0)
fixed = fixed_vulnerability_counts.get(version, 0)
print(f"{version}, {vulnerabilities}, {fixed}")
print("\nCSV Table for patch versions:")
print("Patch Version, Vulnerabilities, Fixed")
all_patch_versions = set(patch_vulnerability_counts.keys()).union(set(patch_fixed_vulnerability_counts.keys()))
for patch_version in sorted(all_patch_versions, key=lambda x: tuple(map(int, x.split('.')))):
vulnerabilities = patch_vulnerability_counts.get(patch_version, 0)
fixed = patch_fixed_vulnerability_counts.get(patch_version, 0)
print(f"{patch_version}, {vulnerabilities}, {fixed}")