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 | |
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')
-rw-r--r-- | meta/conf/distro/include/maintainers.inc | 1 | ||||
-rw-r--r-- | meta/recipes-core/meta/cve-update-db.bb | 121 |
2 files changed, 122 insertions, 0 deletions
diff --git a/meta/conf/distro/include/maintainers.inc b/meta/conf/distro/include/maintainers.inc index f034e3adc8..64856e1057 100644 --- a/meta/conf/distro/include/maintainers.inc +++ b/meta/conf/distro/include/maintainers.inc | |||
@@ -136,6 +136,7 @@ RECIPE_MAINTAINER_pn-cryptodev-tests = "Robert Yang <liezhi.yang@windriver.com>" | |||
136 | RECIPE_MAINTAINER_pn-cups = "Chen Qi <Qi.Chen@windriver.com>" | 136 | RECIPE_MAINTAINER_pn-cups = "Chen Qi <Qi.Chen@windriver.com>" |
137 | RECIPE_MAINTAINER_pn-curl = "Armin Kuster <akuster808@gmail.com>" | 137 | RECIPE_MAINTAINER_pn-curl = "Armin Kuster <akuster808@gmail.com>" |
138 | RECIPE_MAINTAINER_pn-cve-check-tool = "Ross Burton <ross.burton@intel.com>" | 138 | RECIPE_MAINTAINER_pn-cve-check-tool = "Ross Burton <ross.burton@intel.com>" |
139 | RECIPE_MAINTAINER_pn-cve-update-db = "Ross Burton <ross.burton@intel.com>" | ||
139 | RECIPE_MAINTAINER_pn-cwautomacros = "Ross Burton <ross.burton@intel.com>" | 140 | RECIPE_MAINTAINER_pn-cwautomacros = "Ross Burton <ross.burton@intel.com>" |
140 | RECIPE_MAINTAINER_pn-db = "Mark Hatle <mark.hatle@windriver.com>" | 141 | RECIPE_MAINTAINER_pn-db = "Mark Hatle <mark.hatle@windriver.com>" |
141 | RECIPE_MAINTAINER_pn-dbus = "Chen Qi <Qi.Chen@windriver.com>" | 142 | RECIPE_MAINTAINER_pn-dbus = "Chen Qi <Qi.Chen@windriver.com>" |
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" | ||