diff options
| author | Pierre Le Magourou <pierre.lemagourou@softbankrobotics.com> | 2019-06-19 15:59:37 +0200 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2019-06-20 13:14:21 +0100 |
| commit | 1704028878e6e6dbd806c2822b8794047b0f031a (patch) | |
| tree | 1bccd8d471a6ca7edaaf65a0d411055a163ce79f /meta/recipes-core | |
| parent | f850f85b82b2ba1f5da9050b0669a6c7b9d6230a (diff) | |
| download | poky-1704028878e6e6dbd806c2822b8794047b0f031a.tar.gz | |
cve-update-db: New recipe to update CVE database
cve-check-tool-native do_populate_cve_db task was using deprecated NVD
xml data feeds, cve-update-db uses NVD json data feeds.
Sqlite database schema was updated to take into account CVSSv3 CVE
scores and operator in affected product versions.
A new META table was added to store the last modification date of the
NVD json data feeds.
(From OE-Core rev: 546d14135c50c6a571dfbf3baf6e9b22ce3d58e0)
Signed-off-by: Pierre Le Magourou <pierre.lemagourou@softbankrobotics.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/recipes-core')
| -rw-r--r-- | meta/recipes-core/meta/cve-update-db.bb | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/meta/recipes-core/meta/cve-update-db.bb b/meta/recipes-core/meta/cve-update-db.bb new file mode 100644 index 0000000000..522fd23807 --- /dev/null +++ b/meta/recipes-core/meta/cve-update-db.bb | |||
| @@ -0,0 +1,121 @@ | |||
| 1 | SUMMARY = "Updates the NVD CVE database" | ||
| 2 | LICENSE = "MIT" | ||
| 3 | |||
| 4 | INHIBIT_DEFAULT_DEPS = "1" | ||
| 5 | PACKAGES = "" | ||
| 6 | |||
| 7 | inherit nopackages | ||
| 8 | |||
| 9 | deltask do_fetch | ||
| 10 | deltask do_unpack | ||
| 11 | deltask do_patch | ||
| 12 | deltask do_configure | ||
| 13 | deltask do_compile | ||
| 14 | deltask do_install | ||
| 15 | deltask do_populate_sysroot | ||
| 16 | |||
| 17 | python do_populate_cve_db() { | ||
| 18 | """ | ||
| 19 | Update NVD database with json data feed | ||
| 20 | """ | ||
| 21 | |||
| 22 | import sqlite3, urllib3, shutil, gzip, re | ||
| 23 | from datetime import date | ||
| 24 | |||
| 25 | BASE_URL = "https://nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-" | ||
| 26 | YEAR_START = 2002 | ||
| 27 | JSON_TMPFILE = d.getVar("CVE_CHECK_DB_DIR") + '/nvd.json.gz' | ||
| 28 | |||
| 29 | # Connect to database | ||
| 30 | db_file = d.getVar("CVE_CHECK_DB_FILE") | ||
| 31 | conn = sqlite3.connect(db_file) | ||
| 32 | c = conn.cursor() | ||
| 33 | |||
| 34 | initialize_db(c) | ||
| 35 | |||
| 36 | http = urllib3.PoolManager() | ||
| 37 | |||
| 38 | for year in range(YEAR_START, date.today().year + 1): | ||
| 39 | year_url = BASE_URL + str(year) | ||
| 40 | meta_url = year_url + ".meta" | ||
| 41 | json_url = year_url + ".json.gz" | ||
| 42 | |||
| 43 | # Retrieve meta last modified date | ||
| 44 | with http.request('GET', meta_url, preload_content=False) as r: | ||
| 45 | date_line = str(r.data.splitlines()[0]) | ||
| 46 | last_modified = re.search('lastModifiedDate:(.*)', date_line).group(1) | ||
| 47 | |||
| 48 | # Compare with current db last modified date | ||
| 49 | c.execute("select DATE from META where YEAR = '%d'" % year) | ||
| 50 | meta = c.fetchone() | ||
| 51 | if not meta or meta[0] != last_modified: | ||
| 52 | # Update db with current year json file | ||
| 53 | with http.request('GET', json_url, preload_content=False) as r, open(JSON_TMPFILE, 'wb') as tmpfile: | ||
| 54 | shutil.copyfileobj(r, tmpfile) | ||
| 55 | with gzip.open(JSON_TMPFILE, 'rt') as jsonfile: | ||
| 56 | update_db(c, jsonfile) | ||
| 57 | c.execute("insert or replace into META values (?, ?)", | ||
| 58 | [year, last_modified]) | ||
| 59 | |||
| 60 | conn.commit() | ||
| 61 | conn.close() | ||
| 62 | |||
| 63 | with open(d.getVar("CVE_CHECK_TMP_FILE"), 'a'): | ||
| 64 | os.utime(d.getVar("CVE_CHECK_TMP_FILE"), None) | ||
| 65 | } | ||
| 66 | |||
| 67 | # DJB2 hash algorithm | ||
| 68 | def hash_djb2(s): | ||
| 69 | hash = 5381 | ||
| 70 | for x in s: | ||
| 71 | hash = (( hash << 5) + hash) + ord(x) | ||
| 72 | |||
| 73 | return hash & 0xFFFFFFFF | ||
| 74 | |||
| 75 | def initialize_db(c): | ||
| 76 | c.execute("CREATE TABLE IF NOT EXISTS META (YEAR INTEGER UNIQUE, DATE TEXT)") | ||
| 77 | c.execute("CREATE TABLE IF NOT EXISTS NVD (ID TEXT UNIQUE, SUMMARY TEXT, \ | ||
| 78 | SCOREV2 TEXT, SCOREV3 TEXT, MODIFIED INTEGER, VECTOR TEXT)") | ||
| 79 | c.execute("CREATE TABLE IF NOT EXISTS PRODUCTS (HASH INTEGER UNIQUE, ID TEXT, \ | ||
| 80 | VENDOR TEXT, PRODUCT TEXT, VERSION TEXT, OPERATOR TEXT)") | ||
| 81 | c.execute("CREATE INDEX IF NOT EXISTS PRODUCT_IDX ON PRODUCTS \ | ||
| 82 | (PRODUCT, VERSION)") | ||
| 83 | |||
| 84 | def update_db(c, json_filename): | ||
| 85 | import json | ||
| 86 | root = json.load(json_filename) | ||
| 87 | |||
| 88 | for elt in root['CVE_Items']: | ||
| 89 | if not elt['impact']: | ||
| 90 | continue | ||
| 91 | |||
| 92 | cveId = elt['cve']['CVE_data_meta']['ID'] | ||
| 93 | cveDesc = elt['cve']['description']['description_data'][0]['value'] | ||
| 94 | date = elt['lastModifiedDate'] | ||
| 95 | accessVector = elt['impact']['baseMetricV2']['cvssV2']['accessVector'] | ||
| 96 | cvssv2 = elt['impact']['baseMetricV2']['cvssV2']['baseScore'] | ||
| 97 | |||
| 98 | try: | ||
| 99 | cvssv3 = elt['impact']['baseMetricV3']['cvssV3']['baseScore'] | ||
| 100 | except: | ||
| 101 | cvssv3 = 0.0 | ||
| 102 | |||
| 103 | c.execute("insert or replace into NVD values (?, ?, ?, ?, ?, ?)", | ||
| 104 | [cveId, cveDesc, cvssv2, cvssv3, date, accessVector]) | ||
| 105 | |||
| 106 | for vendor in elt['cve']['affects']['vendor']['vendor_data']: | ||
| 107 | for product in vendor['product']['product_data']: | ||
| 108 | for version in product['version']['version_data']: | ||
| 109 | product_str = cveId+vendor['vendor_name']+product['product_name']+version['version_value'] | ||
| 110 | hashstr = hash_djb2(product_str) | ||
| 111 | c.execute("insert or replace into PRODUCTS values (?, ?, ?, ?, ?, ?)", | ||
| 112 | [ hashstr, cveId, vendor['vendor_name'], | ||
| 113 | product['product_name'], version['version_value'], | ||
| 114 | version['version_affected']]) | ||
| 115 | |||
| 116 | |||
| 117 | |||
| 118 | addtask do_populate_cve_db before do_cve_check | ||
| 119 | do_populate_cve_db[nostamp] = "1" | ||
| 120 | |||
| 121 | EXCLUDE_FROM_WORLD = "1" | ||
