diff options
| author | Niko Mauno <niko.mauno@vaisala.com> | 2025-11-04 08:33:31 +0000 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2025-11-07 13:15:35 +0000 |
| commit | 085208eb70daec4a936d4f58ee6b7e9ef0988f41 (patch) | |
| tree | b9d53ded45063311133d901c066d7c790e133757 /meta | |
| parent | 35f915165ac023333cb5cae46dc48c8d47f75923 (diff) | |
| download | poky-085208eb70daec4a936d4f58ee6b7e9ef0988f41.tar.gz | |
cve-update: Drop obsolete NVD1 support
Since enabling NVD1 as NVD_DB_VERSION nowadays leads to BitBake failure
WARNING: cve-update-db-native-1.0-r0 do_fetch: Failed to fetch CVE data (HTTP Error 403: Forbidden)
WARNING: cve-update-db-native-1.0-r0 do_fetch: Host IPs are 172.65.90.26, 172.65.90.25, 172.65.90.24, 172.65.90.27, 2606:4700:78::90:0:180, 2606:4700:78::90:0:183, 2606:4700:78::90:0:181, 2606:4700:78::90:0:182
WARNING: cve-update-db-native-1.0-r0 do_fetch: CVE database update failed
ERROR: cve-update-db-native-1.0-r0 do_unpack: Error executing a python function in exec_func_python() autogenerated:
Remove the support for obsolete NVD1.
(From OE-Core rev: 9cd19f0dc1629086ab1dd18d969e0b4e9acac3ea)
Signed-off-by: Niko Mauno <niko.mauno@vaisala.com>
Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta')
| -rw-r--r-- | meta/classes/cve-check.bbclass | 8 | ||||
| -rw-r--r-- | meta/recipes-core/meta/cve-update-db-native.bb | 87 |
2 files changed, 15 insertions, 80 deletions
diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass index c63ebd56e1..259c699af2 100644 --- a/meta/classes/cve-check.bbclass +++ b/meta/classes/cve-check.bbclass | |||
| @@ -31,11 +31,11 @@ | |||
| 31 | CVE_PRODUCT ??= "${BPN}" | 31 | CVE_PRODUCT ??= "${BPN}" |
| 32 | CVE_VERSION ??= "${PV}" | 32 | CVE_VERSION ??= "${PV}" |
| 33 | 33 | ||
| 34 | # Possible database sources: NVD1, NVD2, FKIE | 34 | # Possible database sources: NVD2, FKIE |
| 35 | NVD_DB_VERSION ?= "FKIE" | 35 | NVD_DB_VERSION ?= "FKIE" |
| 36 | 36 | ||
| 37 | # Use different file names for each database source, as they synchronize at different moments, so may be slightly different | 37 | # Use different file names for each database source, as they synchronize at different moments, so may be slightly different |
| 38 | CVE_CHECK_DB_FILENAME ?= "${@'nvdcve_2-2.db' if d.getVar('NVD_DB_VERSION') == 'NVD2' else 'nvdcve_1-3.db' if d.getVar('NVD_DB_VERSION') == 'NVD1' else 'nvdfkie_1-1.db'}" | 38 | CVE_CHECK_DB_FILENAME ?= "${@'nvdcve_2-2.db' if d.getVar('NVD_DB_VERSION') == 'NVD2' else 'nvdfkie_1-1.db'}" |
| 39 | CVE_CHECK_DB_FETCHER ?= "${@'cve-update-nvd2-native' if d.getVar('NVD_DB_VERSION') == 'NVD2' else 'cve-update-db-native'}" | 39 | CVE_CHECK_DB_FETCHER ?= "${@'cve-update-nvd2-native' if d.getVar('NVD_DB_VERSION') == 'NVD2' else 'cve-update-db-native'}" |
| 40 | CVE_CHECK_DB_DIR ?= "${STAGING_DIR}/CVE_CHECK" | 40 | CVE_CHECK_DB_DIR ?= "${STAGING_DIR}/CVE_CHECK" |
| 41 | CVE_CHECK_DB_FILE ?= "${CVE_CHECK_DB_DIR}/${CVE_CHECK_DB_FILENAME}" | 41 | CVE_CHECK_DB_FILE ?= "${CVE_CHECK_DB_DIR}/${CVE_CHECK_DB_FILENAME}" |
| @@ -108,8 +108,8 @@ python () { | |||
| 108 | extend_cve_status(d) | 108 | extend_cve_status(d) |
| 109 | 109 | ||
| 110 | nvd_database_type = d.getVar("NVD_DB_VERSION") | 110 | nvd_database_type = d.getVar("NVD_DB_VERSION") |
| 111 | if nvd_database_type not in ("NVD1", "NVD2", "FKIE"): | 111 | if nvd_database_type not in ("NVD2", "FKIE"): |
| 112 | bb.erroronce("Malformed NVD_DB_VERSION, must be one of: NVD1, NVD2, FKIE. Defaulting to NVD2") | 112 | bb.erroronce("Malformed NVD_DB_VERSION, must be one of: NVD2, FKIE. Defaulting to NVD2") |
| 113 | d.setVar("NVD_DB_VERSION", "NVD2") | 113 | d.setVar("NVD_DB_VERSION", "NVD2") |
| 114 | } | 114 | } |
| 115 | 115 | ||
diff --git a/meta/recipes-core/meta/cve-update-db-native.bb b/meta/recipes-core/meta/cve-update-db-native.bb index 3a6dc95580..4423216be5 100644 --- a/meta/recipes-core/meta/cve-update-db-native.bb +++ b/meta/recipes-core/meta/cve-update-db-native.bb | |||
| @@ -11,7 +11,6 @@ deltask do_compile | |||
| 11 | deltask do_install | 11 | deltask do_install |
| 12 | deltask do_populate_sysroot | 12 | deltask do_populate_sysroot |
| 13 | 13 | ||
| 14 | NVDCVE_URL ?= "https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-" | ||
| 15 | FKIE_URL ?= "https://github.com/fkie-cad/nvd-json-data-feeds/releases/latest/download/CVE-" | 14 | FKIE_URL ?= "https://github.com/fkie-cad/nvd-json-data-feeds/releases/latest/download/CVE-" |
| 16 | 15 | ||
| 17 | # CVE database update interval, in seconds. By default: once a day (23*60*60). | 16 | # CVE database update interval, in seconds. By default: once a day (23*60*60). |
| @@ -108,30 +107,12 @@ def cleanup_db_download(db_tmp_file): | |||
| 108 | if os.path.exists(db_tmp_file): | 107 | if os.path.exists(db_tmp_file): |
| 109 | os.remove(db_tmp_file) | 108 | os.remove(db_tmp_file) |
| 110 | 109 | ||
| 111 | def db_file_names(d, year, is_nvd): | 110 | def db_file_names(d, year): |
| 112 | if is_nvd: | ||
| 113 | year_url = d.getVar('NVDCVE_URL') + str(year) | ||
| 114 | meta_url = year_url + ".meta" | ||
| 115 | json_url = year_url + ".json.gz" | ||
| 116 | return json_url, meta_url | ||
| 117 | year_url = d.getVar('FKIE_URL') + str(year) | 111 | year_url = d.getVar('FKIE_URL') + str(year) |
| 118 | meta_url = year_url + ".meta" | 112 | meta_url = year_url + ".meta" |
| 119 | json_url = year_url + ".json.xz" | 113 | json_url = year_url + ".json.xz" |
| 120 | return json_url, meta_url | 114 | return json_url, meta_url |
| 121 | 115 | ||
| 122 | def host_db_name(d, is_nvd): | ||
| 123 | if is_nvd: | ||
| 124 | return "nvd.nist.gov" | ||
| 125 | return "github.com" | ||
| 126 | |||
| 127 | def db_decompress(d, data, is_nvd): | ||
| 128 | import gzip, lzma | ||
| 129 | |||
| 130 | if is_nvd: | ||
| 131 | return gzip.decompress(data).decode('utf-8') | ||
| 132 | # otherwise | ||
| 133 | return lzma.decompress(data) | ||
| 134 | |||
| 135 | def update_db_file(db_tmp_file, d): | 116 | def update_db_file(db_tmp_file, d): |
| 136 | """ | 117 | """ |
| 137 | Update the given database file | 118 | Update the given database file |
| @@ -139,12 +120,12 @@ def update_db_file(db_tmp_file, d): | |||
| 139 | import bb.progress | 120 | import bb.progress |
| 140 | import bb.utils | 121 | import bb.utils |
| 141 | from datetime import date | 122 | from datetime import date |
| 123 | import lzma | ||
| 142 | import sqlite3 | 124 | import sqlite3 |
| 143 | import urllib | 125 | import urllib |
| 144 | 126 | ||
| 145 | YEAR_START = 2002 | 127 | YEAR_START = 2002 |
| 146 | cve_socket_timeout = int(d.getVar("CVE_SOCKET_TIMEOUT")) | 128 | cve_socket_timeout = int(d.getVar("CVE_SOCKET_TIMEOUT")) |
| 147 | is_nvd = d.getVar("NVD_DB_VERSION") == "NVD1" | ||
| 148 | 129 | ||
| 149 | # Connect to database | 130 | # Connect to database |
| 150 | conn = sqlite3.connect(db_tmp_file) | 131 | conn = sqlite3.connect(db_tmp_file) |
| @@ -155,7 +136,7 @@ def update_db_file(db_tmp_file, d): | |||
| 155 | for i, year in enumerate(range(YEAR_START, date.today().year + 1)): | 136 | for i, year in enumerate(range(YEAR_START, date.today().year + 1)): |
| 156 | bb.note("Updating %d" % year) | 137 | bb.note("Updating %d" % year) |
| 157 | ph.update((float(i + 1) / total_years) * 100) | 138 | ph.update((float(i + 1) / total_years) * 100) |
| 158 | json_url, meta_url = db_file_names(d, year, is_nvd) | 139 | json_url, meta_url = db_file_names(d, year) |
| 159 | 140 | ||
| 160 | # Retrieve meta last modified date | 141 | # Retrieve meta last modified date |
| 161 | try: | 142 | try: |
| @@ -164,7 +145,7 @@ def update_db_file(db_tmp_file, d): | |||
| 164 | cve_f.write('Warning: CVE db update error, Unable to fetch CVE data.\n\n') | 145 | cve_f.write('Warning: CVE db update error, Unable to fetch CVE data.\n\n') |
| 165 | bb.warn("Failed to fetch CVE data (%s)" % e) | 146 | bb.warn("Failed to fetch CVE data (%s)" % e) |
| 166 | import socket | 147 | import socket |
| 167 | result = socket.getaddrinfo(host_db_name(d, is_nvd), 443, proto=socket.IPPROTO_TCP) | 148 | result = socket.getaddrinfo("github.com", 443, proto=socket.IPPROTO_TCP) |
| 168 | bb.warn("Host IPs are %s" % (", ".join(t[4][0] for t in result))) | 149 | bb.warn("Host IPs are %s" % (", ".join(t[4][0] for t in result))) |
| 169 | return False | 150 | return False |
| 170 | 151 | ||
| @@ -192,7 +173,7 @@ def update_db_file(db_tmp_file, d): | |||
| 192 | try: | 173 | try: |
| 193 | response = urllib.request.urlopen(json_url, timeout=cve_socket_timeout) | 174 | response = urllib.request.urlopen(json_url, timeout=cve_socket_timeout) |
| 194 | if response: | 175 | if response: |
| 195 | update_db(d, conn, db_decompress(d, response.read(), is_nvd)) | 176 | update_db(conn, lzma.decompress(response.read())) |
| 196 | conn.execute("insert or replace into META values (?, ?)", [year, last_modified]).close() | 177 | conn.execute("insert or replace into META values (?, ?)", [year, last_modified]).close() |
| 197 | except urllib.error.URLError as e: | 178 | except urllib.error.URLError as e: |
| 198 | cve_f.write('Warning: CVE db update error, CVE data is outdated.\n\n') | 179 | cve_f.write('Warning: CVE db update error, CVE data is outdated.\n\n') |
| @@ -224,17 +205,14 @@ def initialize_db(conn): | |||
| 224 | 205 | ||
| 225 | c.close() | 206 | c.close() |
| 226 | 207 | ||
| 227 | def parse_node_and_insert(conn, node, cveId, is_nvd): | 208 | def parse_node_and_insert(conn, node, cveId): |
| 228 | # Parse children node if needed | 209 | # Parse children node if needed |
| 229 | for child in node.get('children', ()): | 210 | for child in node.get('children', ()): |
| 230 | parse_node_and_insert(conn, child, cveId, is_nvd) | 211 | parse_node_and_insert(conn, child, cveId) |
| 231 | 212 | ||
| 232 | def cpe_generator(is_nvd): | 213 | def cpe_generator(): |
| 233 | match_string = "cpeMatch" | 214 | match_string = "cpeMatch" |
| 234 | cpe_string = 'criteria' | 215 | cpe_string = 'criteria' |
| 235 | if is_nvd: | ||
| 236 | match_string = "cpe_match" | ||
| 237 | cpe_string = 'cpe23Uri' | ||
| 238 | 216 | ||
| 239 | for cpe in node.get(match_string, ()): | 217 | for cpe in node.get(match_string, ()): |
| 240 | if not cpe['vulnerable']: | 218 | if not cpe['vulnerable']: |
| @@ -290,44 +268,7 @@ def parse_node_and_insert(conn, node, cveId, is_nvd): | |||
| 290 | # Save processing by representing as -. | 268 | # Save processing by representing as -. |
| 291 | yield [cveId, vendor, product, '-', '', '', ''] | 269 | yield [cveId, vendor, product, '-', '', '', ''] |
| 292 | 270 | ||
| 293 | conn.executemany("insert into PRODUCTS values (?, ?, ?, ?, ?, ?, ?)", cpe_generator(is_nvd)).close() | 271 | conn.executemany("insert into PRODUCTS values (?, ?, ?, ?, ?, ?, ?)", cpe_generator()).close() |
| 294 | |||
| 295 | def update_db_nvdjson(conn, jsondata): | ||
| 296 | import json | ||
| 297 | root = json.loads(jsondata) | ||
| 298 | |||
| 299 | for elt in root['CVE_Items']: | ||
| 300 | if not elt['impact']: | ||
| 301 | continue | ||
| 302 | |||
| 303 | accessVector = None | ||
| 304 | vectorString = None | ||
| 305 | cvssv2 = 0.0 | ||
| 306 | cvssv3 = 0.0 | ||
| 307 | cvssv4 = 0.0 | ||
| 308 | cveId = elt['cve']['CVE_data_meta']['ID'] | ||
| 309 | cveDesc = elt['cve']['description']['description_data'][0]['value'] | ||
| 310 | date = elt['lastModifiedDate'] | ||
| 311 | try: | ||
| 312 | accessVector = elt['impact']['baseMetricV2']['cvssV2']['accessVector'] | ||
| 313 | vectorString = elt['impact']['baseMetricV2']['cvssV2']['vectorString'] | ||
| 314 | cvssv2 = elt['impact']['baseMetricV2']['cvssV2']['baseScore'] | ||
| 315 | except KeyError: | ||
| 316 | cvssv2 = 0.0 | ||
| 317 | try: | ||
| 318 | accessVector = accessVector or elt['impact']['baseMetricV3']['cvssV3']['attackVector'] | ||
| 319 | vectorString = vectorString or elt['impact']['baseMetricV3']['cvssV3']['vectorString'] | ||
| 320 | cvssv3 = elt['impact']['baseMetricV3']['cvssV3']['baseScore'] | ||
| 321 | except KeyError: | ||
| 322 | accessVector = accessVector or "UNKNOWN" | ||
| 323 | cvssv3 = 0.0 | ||
| 324 | |||
| 325 | conn.execute("insert or replace into NVD values (?, ?, ?, ?, ?, ?, ?, ?)", | ||
| 326 | [cveId, cveDesc, cvssv2, cvssv3, cvssv4, date, accessVector, vectorString]).close() | ||
| 327 | |||
| 328 | configurations = elt['configurations']['nodes'] | ||
| 329 | for config in configurations: | ||
| 330 | parse_node_and_insert(conn, config, cveId, True) | ||
| 331 | 272 | ||
| 332 | def get_metric_entry(metric): | 273 | def get_metric_entry(metric): |
| 333 | primaries = [c for c in metric if c['type'] == "Primary"] | 274 | primaries = [c for c in metric if c['type'] == "Primary"] |
| @@ -338,7 +279,7 @@ def get_metric_entry(metric): | |||
| 338 | return secondaries[0] | 279 | return secondaries[0] |
| 339 | return None | 280 | return None |
| 340 | 281 | ||
| 341 | def update_db_fkie(conn, jsondata): | 282 | def update_db(conn, jsondata): |
| 342 | import json | 283 | import json |
| 343 | root = json.loads(jsondata) | 284 | root = json.loads(jsondata) |
| 344 | 285 | ||
| @@ -403,13 +344,7 @@ def update_db_fkie(conn, jsondata): | |||
| 403 | for config in elt['configurations']: | 344 | for config in elt['configurations']: |
| 404 | # This is suboptimal as it doesn't handle AND/OR and negate, but is better than nothing | 345 | # This is suboptimal as it doesn't handle AND/OR and negate, but is better than nothing |
| 405 | for node in config.get("nodes") or []: | 346 | for node in config.get("nodes") or []: |
| 406 | parse_node_and_insert(conn, node, cveId, False) | 347 | parse_node_and_insert(conn, node, cveId) |
| 407 | |||
| 408 | def update_db(d, conn, jsondata): | ||
| 409 | if (d.getVar("NVD_DB_VERSION") == "FKIE"): | ||
| 410 | return update_db_fkie(conn, jsondata) | ||
| 411 | else: | ||
| 412 | return update_db_nvdjson(conn, jsondata) | ||
| 413 | 348 | ||
| 414 | do_fetch[nostamp] = "1" | 349 | do_fetch[nostamp] = "1" |
| 415 | 350 | ||
