Re: [OE-core] [PATCH 2/2] cve-update-db-native: Remove hash column from database.

2019-07-18 Thread Pierre Le Magourou
Hello Ross,

> Can you rebase this on top of the patches I sent yesterday to change
> the path construction to use os.path.join() please.

I can't find the patches your are referring to. My patches are rebased
on the last master, and I don't see a patch from you in master-next.

Pierre

Le jeu. 18 juil. 2019 à 15:10, Burton, Ross  a écrit :
>

>
> Ross
>
> On Thu, 18 Jul 2019 at 13:41, Pierre Le Magourou  wrote:
> >
> > From: Pierre Le Magourou 
> >
> > djb2 hash algorithm was found to do collisions, so the database was
> > sometime missing data. Remove this hash mechanism, clear and populate
> > elements from scratch in PRODUCTS table if the current year needs an
> > update.
> >
> > Signed-off-by: Pierre Le Magourou 
> > ---
> >  meta/classes/cve-check.bbclass | 12 ++--
> >  meta/recipes-core/meta/cve-update-db-native.bb | 21 +++--
> >  2 files changed, 13 insertions(+), 20 deletions(-)
> >
> > diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
> > index 512d4c7302..c00d2910be 100644
> > --- a/meta/classes/cve-check.bbclass
> > +++ b/meta/classes/cve-check.bbclass
> > @@ -26,7 +26,7 @@ CVE_PRODUCT ??= "${BPN}"
> >  CVE_VERSION ??= "${PV}"
> >
> >  CVE_CHECK_DB_DIR ?= "${DL_DIR}/CVE_CHECK"
> > -CVE_CHECK_DB_FILE ?= "${CVE_CHECK_DB_DIR}/nvdcve.db"
> > +CVE_CHECK_DB_FILE ?= "${CVE_CHECK_DB_DIR}/nvdcve_1.0.db"
> >
> >  CVE_CHECK_LOG ?= "${T}/cve.log"
> >  CVE_CHECK_TMP_FILE ?= "${TMPDIR}/cve_check"
> > @@ -200,11 +200,11 @@ def check_cves(d, patched_cves):
> >  c.execute("SELECT * FROM PRODUCTS WHERE PRODUCT IS ?", 
> > (product,))
> >
> >  for row in c:
> > -cve = row[1]
> > -version_start = row[4]
> > -operator_start = row[5]
> > -version_end = row[6]
> > -operator_end = row[7]
> > +cve = row[0]
> > +version_start = row[3]
> > +operator_start = row[4]
> > +version_end = row[5]
> > +operator_end = row[6]
> >
> >  if cve in cve_whitelist:
> >  bb.note("%s-%s has been whitelisted for %s" % (product, 
> > pv, cve))
> > diff --git a/meta/recipes-core/meta/cve-update-db-native.bb 
> > b/meta/recipes-core/meta/cve-update-db-native.bb
> > index 72d1f48835..3519beae5f 100644
> > --- a/meta/recipes-core/meta/cve-update-db-native.bb
> > +++ b/meta/recipes-core/meta/cve-update-db-native.bb
> > @@ -30,7 +30,7 @@ python do_populate_cve_db() {
> >  YEAR_START = 2002
> >
> >  db_dir = d.getVar("DL_DIR") + '/CVE_CHECK'
> > -db_file = db_dir + '/nvdcve.db'
> > +db_file = db_dir + '/nvdcve_1.0.db'
> >  json_tmpfile = db_dir + '/nvd.json.gz'
> >  proxy = d.getVar("https_proxy")
> >  cve_f = open(d.getVar("TMPDIR") + '/cve_check', 'a')
> > @@ -65,6 +65,10 @@ python do_populate_cve_db() {
> >  c.execute("select DATE from META where YEAR = ?", (year,))
> >  meta = c.fetchone()
> >  if not meta or meta[0] != last_modified:
> > +# Clear products table entries corresponding to current year
> > +cve_year = 'CVE-' + str(year) + '%'
> > +c.execute("delete from PRODUCTS where ID like ?", (cve_year,))
> > +
> >  # Update db with current year json file
> >  req = urllib.request.Request(json_url)
> >  if proxy:
> > @@ -91,27 +95,16 @@ python do_populate_cve_db() {
> >  conn.close()
> >  }
> >
> > -# DJB2 hash algorithm
> > -def hash_djb2(s):
> > -hash = 5381
> > -for x in s:
> > -hash = (( hash << 5) + hash) + ord(x)
> > -
> > -return hash & 0x
> > -
> >  def initialize_db(c):
> >  c.execute("CREATE TABLE IF NOT EXISTS META (YEAR INTEGER UNIQUE, DATE 
> > TEXT)")
> >  c.execute("CREATE TABLE IF NOT EXISTS NVD (ID TEXT UNIQUE, SUMMARY 
> > TEXT, \
> >  SCOREV2 TEXT, SCOREV3 TEXT, MODIFIED INTEGER, VECTOR TEXT)")
> > -c.execute("CREATE TABLE IF NOT EXISTS PRODUCTS (HASH INTEGER UNIQUE, 
> > ID TEXT, \
> > +c.execute("CREATE TABLE IF NOT EXISTS PRODUCTS (ID TEXT, \
> >  VENDOR TEXT, PRODUCT TEXT, VERSION_START TEXT, OPERATOR_START 
> > TEXT, \
> >  VERSION_END T

[OE-core] [PATCH 1/2] cve-check: Replace CVE_CHECK_CVE_WHITELIST by CVE_CHECK_WHITELIST

2019-07-18 Thread Pierre Le Magourou
From: Pierre Le Magourou 

CVE_CHECK_WHITELIST does not contain version anymore, as it was not
used. This variable should be set per recipe.

Signed-off-by: Pierre Le Magourou 
---
 meta/classes/cve-check.bbclass | 22 +++---
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
index e8668b2566..512d4c7302 100644
--- a/meta/classes/cve-check.bbclass
+++ b/meta/classes/cve-check.bbclass
@@ -39,15 +39,12 @@ CVE_CHECK_CREATE_MANIFEST ??= "1"
 # Whitelist for packages (PN)
 CVE_CHECK_PN_WHITELIST ?= ""
 
-# Whitelist for CVE and version of package. If a CVE is found then the PV is
-# compared with the version list, and if found the CVE is considered
-# patched.
-#
-# The value should be valid Python in this format:
-# {
-#   'CVE-2014-2524': ('6.3','5.2')
-# }
-CVE_CHECK_CVE_WHITELIST ?= "{}"
+# Whitelist for CVE. If a CVE is found, then it is considered patched.
+# The value is a string containing space separated CVE values:
+# 
+# CVE_CHECK_WHITELIST = 'CVE-2014-2524 CVE-2018-1234'
+# 
+CVE_CHECK_WHITELIST ?= ""
 
 python do_cve_check () {
 """
@@ -185,7 +182,10 @@ def check_cves(d, patched_cves):
 bb.note("Recipe has been whitelisted, skipping check")
 return ([], [])
 
-cve_whitelist = ast.literal_eval(d.getVar("CVE_CHECK_CVE_WHITELIST"))
+old_cve_whitelist =  d.getVar("CVE_CHECK_CVE_WHITELIST")
+if old_cve_whitelist:
+bb.warn("CVE_CHECK_CVE_WHITELIST is deprecated, please use 
CVE_CHECK_WHITELIST.")
+cve_whitelist = d.getVar("CVE_CHECK_WHITELIST").split()
 
 import sqlite3
 db_file = d.getVar("CVE_CHECK_DB_FILE")
@@ -206,7 +206,7 @@ def check_cves(d, patched_cves):
 version_end = row[6]
 operator_end = row[7]
 
-if pv in cve_whitelist.get(cve, []):
+if cve in cve_whitelist:
 bb.note("%s-%s has been whitelisted for %s" % (product, pv, 
cve))
 elif cve in patched_cves:
 bb.note("%s has been patched" % (cve))
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [PATCH 2/2] cve-update-db-native: Remove hash column from database.

2019-07-18 Thread Pierre Le Magourou
From: Pierre Le Magourou 

djb2 hash algorithm was found to do collisions, so the database was
sometime missing data. Remove this hash mechanism, clear and populate
elements from scratch in PRODUCTS table if the current year needs an
update.

Signed-off-by: Pierre Le Magourou 
---
 meta/classes/cve-check.bbclass | 12 ++--
 meta/recipes-core/meta/cve-update-db-native.bb | 21 +++--
 2 files changed, 13 insertions(+), 20 deletions(-)

diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
index 512d4c7302..c00d2910be 100644
--- a/meta/classes/cve-check.bbclass
+++ b/meta/classes/cve-check.bbclass
@@ -26,7 +26,7 @@ CVE_PRODUCT ??= "${BPN}"
 CVE_VERSION ??= "${PV}"
 
 CVE_CHECK_DB_DIR ?= "${DL_DIR}/CVE_CHECK"
-CVE_CHECK_DB_FILE ?= "${CVE_CHECK_DB_DIR}/nvdcve.db"
+CVE_CHECK_DB_FILE ?= "${CVE_CHECK_DB_DIR}/nvdcve_1.0.db"
 
 CVE_CHECK_LOG ?= "${T}/cve.log"
 CVE_CHECK_TMP_FILE ?= "${TMPDIR}/cve_check"
@@ -200,11 +200,11 @@ def check_cves(d, patched_cves):
 c.execute("SELECT * FROM PRODUCTS WHERE PRODUCT IS ?", (product,))
 
 for row in c:
-cve = row[1]
-version_start = row[4]
-operator_start = row[5]
-version_end = row[6]
-operator_end = row[7]
+cve = row[0]
+version_start = row[3]
+operator_start = row[4]
+version_end = row[5]
+operator_end = row[6]
 
 if cve in cve_whitelist:
 bb.note("%s-%s has been whitelisted for %s" % (product, pv, 
cve))
diff --git a/meta/recipes-core/meta/cve-update-db-native.bb 
b/meta/recipes-core/meta/cve-update-db-native.bb
index 72d1f48835..3519beae5f 100644
--- a/meta/recipes-core/meta/cve-update-db-native.bb
+++ b/meta/recipes-core/meta/cve-update-db-native.bb
@@ -30,7 +30,7 @@ python do_populate_cve_db() {
 YEAR_START = 2002
 
 db_dir = d.getVar("DL_DIR") + '/CVE_CHECK'
-db_file = db_dir + '/nvdcve.db'
+db_file = db_dir + '/nvdcve_1.0.db'
 json_tmpfile = db_dir + '/nvd.json.gz'
 proxy = d.getVar("https_proxy")
 cve_f = open(d.getVar("TMPDIR") + '/cve_check', 'a')
@@ -65,6 +65,10 @@ python do_populate_cve_db() {
 c.execute("select DATE from META where YEAR = ?", (year,))
 meta = c.fetchone()
 if not meta or meta[0] != last_modified:
+# Clear products table entries corresponding to current year
+cve_year = 'CVE-' + str(year) + '%'
+c.execute("delete from PRODUCTS where ID like ?", (cve_year,))
+
 # Update db with current year json file
 req = urllib.request.Request(json_url)
 if proxy:
@@ -91,27 +95,16 @@ python do_populate_cve_db() {
 conn.close()
 }
 
-# DJB2 hash algorithm
-def hash_djb2(s):
-hash = 5381
-for x in s:
-hash = (( hash << 5) + hash) + ord(x)
-
-return hash & 0x
-
 def initialize_db(c):
 c.execute("CREATE TABLE IF NOT EXISTS META (YEAR INTEGER UNIQUE, DATE 
TEXT)")
 c.execute("CREATE TABLE IF NOT EXISTS NVD (ID TEXT UNIQUE, SUMMARY TEXT, \
 SCOREV2 TEXT, SCOREV3 TEXT, MODIFIED INTEGER, VECTOR TEXT)")
-c.execute("CREATE TABLE IF NOT EXISTS PRODUCTS (HASH INTEGER UNIQUE, ID 
TEXT, \
+c.execute("CREATE TABLE IF NOT EXISTS PRODUCTS (ID TEXT, \
 VENDOR TEXT, PRODUCT TEXT, VERSION_START TEXT, OPERATOR_START TEXT, \
 VERSION_END TEXT, OPERATOR_END TEXT)")
 
 def insert_elt(c, db_values):
-product_str = db_values[0] + db_values[1] + db_values[2] + db_values[3]
-hashstr = hash_djb2(product_str)
-db_values.insert(0, hashstr)
-query = "insert or replace into PRODUCTS values (?, ?, ?, ?, ?, ?, ?, ?)"
+query = "insert into PRODUCTS values (?, ?, ?, ?, ?, ?, ?)"
 c.execute(query, db_values)
 
 def parse_node_and_insert(c, node, cveId):
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


Re: [OE-core] [PATCH 1/4] cve-update-db: New recipe to update CVE database

2019-07-10 Thread Pierre Le Magourou
Hi Kevin,

> I found that the hash function is causing collisions in the generated 
> database such that some CVEs are being overwritten because of the UNIQUE 
> constraint on the HASH column. For example, CVE-2018-1000873 has the same 
> hash of 623198722 as CVE-2018-18338. This results in one of the two CVEs not 
> appearing in the database.

This is problematic. I kept using djb2 hash function, because it was
the one used in the previous cve-check-tool and it was fast. But it
might not be the right hash function to use. Do you have a better hash
function in mind ?
I can also drop hash function, remove everything from the database and
recreate all entries at each update but it will increase database
update time.

I don't have the same hash as you for CVE-2018-1000873 and
CVE-2018-18338, do you use my latest patches from master ? I did
several changes recently.

Pierre Le Magourou
-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


Re: [OE-core] [PATCH] cve-update-db: Skip recipe when cve-check class is not loaded.

2019-07-08 Thread Pierre Le Magourou
>
> Great, the "bitbake universe --runall=fetch" works now.
>

I just forgot to rebase this patch on the previous ones that are in
master-next, I sent a rebased v2.

Pierre
-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [PATCH v2] cve-update-db-native: Skip recipe when cve-check class is not loaded.

2019-07-08 Thread Pierre Le Magourou
From: Pierre Le Magourou 

Signed-off-by: Pierre Le Magourou 
---
 meta/recipes-core/meta/cve-update-db-native.bb | 5 +
 1 file changed, 5 insertions(+)

diff --git a/meta/recipes-core/meta/cve-update-db-native.bb 
b/meta/recipes-core/meta/cve-update-db-native.bb
index d658c7bfea..e16c41a72f 100644
--- a/meta/recipes-core/meta/cve-update-db-native.bb
+++ b/meta/recipes-core/meta/cve-update-db-native.bb
@@ -13,6 +13,11 @@ deltask do_compile
 deltask do_install
 deltask do_populate_sysroot
 
+python () {
+if not d.getVar("CVE_CHECK_DB_FILE"):
+raise bb.parse.SkipRecipe("Skip recipe when cve-check class is not 
loaded.")
+}
+
 python do_populate_cve_db() {
 """
 Update NVD database with json data feed
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


Re: [OE-core] [meta-oe][PATCH v5] cve-update-db: do_populate_cve_db depends on do_fetch

2019-07-08 Thread Pierre Le Magourou
Hello,

> Did you try
>
> $ bitbake universe --runall=fetch
>
> Please? It still doesn't work on latest master branch.
>

I sent a patch to skip cve-update-db recipe if the cve-check class is
not loaded. This should fix the problem.

Pierre
-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [PATCH] cve-update-db: Skip recipe when cve-check class is not loaded.

2019-07-08 Thread Pierre Le Magourou
From: Pierre Le Magourou 

Signed-off-by: Pierre Le Magourou 
---
 meta/recipes-core/meta/cve-update-db.bb | 5 +
 1 file changed, 5 insertions(+)

diff --git a/meta/recipes-core/meta/cve-update-db.bb 
b/meta/recipes-core/meta/cve-update-db.bb
index ae8f1a958b..cfeee91c2e 100644
--- a/meta/recipes-core/meta/cve-update-db.bb
+++ b/meta/recipes-core/meta/cve-update-db.bb
@@ -13,6 +13,11 @@ deltask do_compile
 deltask do_install
 deltask do_populate_sysroot
 
+python () {
+if not d.getVar("CVE_CHECK_DB_FILE"):
+raise bb.parse.SkipRecipe("Skip recipe when cve-check class is not 
loaded.")
+}
+
 python do_populate_cve_db() {
 """
 Update NVD database with json data feed
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [PATCH v2 2/3] cve-update-db: Use NVD CPE data to populate PRODUCTS table

2019-07-05 Thread Pierre Le Magourou
From: Pierre Le Magourou 

Instead of using expanded list of affected versions that is not
reliable, use the 'cpe_match' node in the 'configurations' json node.

For cve-check to correctly match affected CVE, the sqlite database need to
contain operator_start, operator_end and the corresponding versions fields.

Signed-off-by: Pierre Le Magourou 
---
 meta/recipes-core/meta/cve-update-db-native.bb | 88 ++
 1 file changed, 74 insertions(+), 14 deletions(-)

diff --git a/meta/recipes-core/meta/cve-update-db-native.bb 
b/meta/recipes-core/meta/cve-update-db-native.bb
index ae8f1a958b..d658c7bfea 100644
--- a/meta/recipes-core/meta/cve-update-db-native.bb
+++ b/meta/recipes-core/meta/cve-update-db-native.bb
@@ -25,7 +25,7 @@ python do_populate_cve_db() {
 YEAR_START = 2002
 
 db_dir = d.getVar("DL_DIR") + '/CVE_CHECK'
-db_file = db_dir + '/nvd-json.db'
+db_file = db_dir + '/nvdcve.db'
 json_tmpfile = db_dir + '/nvd.json.gz'
 proxy = d.getVar("https_proxy")
 cve_f = open(d.getVar("TMPDIR") + '/cve_check', 'a')
@@ -99,9 +99,76 @@ def initialize_db(c):
 c.execute("CREATE TABLE IF NOT EXISTS NVD (ID TEXT UNIQUE, SUMMARY TEXT, \
 SCOREV2 TEXT, SCOREV3 TEXT, MODIFIED INTEGER, VECTOR TEXT)")
 c.execute("CREATE TABLE IF NOT EXISTS PRODUCTS (HASH INTEGER UNIQUE, ID 
TEXT, \
-VENDOR TEXT, PRODUCT TEXT, VERSION TEXT, OPERATOR TEXT)")
-c.execute("CREATE INDEX IF NOT EXISTS PRODUCT_IDX ON PRODUCTS \
-(PRODUCT, VERSION)")
+VENDOR TEXT, PRODUCT TEXT, VERSION_START TEXT, OPERATOR_START TEXT, \
+VERSION_END TEXT, OPERATOR_END TEXT)")
+
+def insert_elt(c, db_values):
+product_str = db_values[0] + db_values[1] + db_values[2] + db_values[3]
+hashstr = hash_djb2(product_str)
+db_values.insert(0, hashstr)
+query = "insert or replace into PRODUCTS values (?, ?, ?, ?, ?, ?, ?, ?)"
+c.execute(query, db_values)
+
+def parse_node_and_insert(c, node, cveId):
+# Parse children node if needed
+try:
+for child in node['children']:
+parse_node_and_insert(c, child, cveId)
+except:
+pass
+
+# Exit if the cpe_match node does not exists
+try:
+cpe_match = node['cpe_match']
+except:
+return
+
+for cpe in cpe_match:
+if not cpe['vulnerable']:
+return
+cpe23 = cpe['cpe23Uri'].split(':')
+vendor = cpe23[3]
+product = cpe23[4]
+version = cpe23[5]
+
+if version != '*':
+# Version is defined, this is a '=' match
+db_values = [cveId, vendor, product, version, '=', '', '']
+insert_elt(c, db_values)
+else:
+# Parse start version, end version and operators
+op_start = ''
+op_end = ''
+v_start = ''
+v_end = ''
+
+try:
+if cpe['versionStartIncluding']:
+op_start = '>='
+v_start = cpe['versionStartIncluding']
+except:
+pass
+try:
+if cpe['versionStartExcluding']:
+op_start = '>'
+v_start = cpe['versionStartExcluding']
+except:
+pass
+try:
+if cpe['versionEndIncluding']:
+op_end = '<='
+v_end = cpe['versionEndIncluding']
+except:
+pass
+try:
+if cpe['versionEndExcluding']:
+op_end = '<'
+v_end = cpe['versionEndExcluding']
+except:
+pass
+
+db_values = [cveId, vendor, product, v_start, op_start, v_end, 
op_end]
+insert_elt(c, db_values)
 
 def update_db(c, json_filename):
 import json
@@ -125,16 +192,9 @@ def update_db(c, json_filename):
 c.execute("insert or replace into NVD values (?, ?, ?, ?, ?, ?)",
 [cveId, cveDesc, cvssv2, cvssv3, date, accessVector])
 
-for vendor in elt['cve']['affects']['vendor']['vendor_data']:
-for product in vendor['product']['product_data']:
-for version in product['version']['version_data']:
-product_str = 
cveId+vendor['vendor_name']+product['product_name']+version['version_value']
-hashstr = hash_djb2(product_str)
-c.execute("insert or replace into PRODUCTS values (?, ?, 
?, ?, ?, ?)",
-[ hashstr, cveId, vendor['vendor_name'],
-product['product_name'], 
version['version_value'],
-version['version_affected']])
-
+configurations = elt['configurations']['nodes']
+for config in configurations:
+   

[OE-core] [PATCH v2 1/3] cve-check: Depends on cve-update-db-native

2019-07-05 Thread Pierre Le Magourou
From: Pierre Le Magourou 

do_populate_cve_db is a native task.

Signed-off-by: Pierre Le Magourou 
---
 meta/classes/cve-check.bbclass   | 2 +-
 meta/recipes-core/meta/{cve-update-db.bb => cve-update-db-native.bb} | 0
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename meta/recipes-core/meta/{cve-update-db.bb => cve-update-db-native.bb} 
(100%)

diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
index 81071e3f19..6ffa0c4688 100644
--- a/meta/classes/cve-check.bbclass
+++ b/meta/classes/cve-check.bbclass
@@ -63,7 +63,7 @@ python do_cve_check () {
 }
 
 addtask cve_check after do_unpack before do_build
-do_cve_check[depends] = "cve-update-db:do_populate_cve_db"
+do_cve_check[depends] = "cve-update-db-native:do_populate_cve_db"
 do_cve_check[nostamp] = "1"
 
 python cve_check_cleanup () {
diff --git a/meta/recipes-core/meta/cve-update-db.bb 
b/meta/recipes-core/meta/cve-update-db-native.bb
similarity index 100%
rename from meta/recipes-core/meta/cve-update-db.bb
rename to meta/recipes-core/meta/cve-update-db-native.bb
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [PATCH v2 3/3] cve-check: Update unpatched CVE matching

2019-07-05 Thread Pierre Le Magourou
From: Pierre Le Magourou 

Now that cve-update-db added CPE information to NVD database. We can
check for unpatched versions with operators '<', '<=', '>', and '>='.

Signed-off-by: Pierre Le Magourou 
---
 meta/classes/cve-check.bbclass | 54 +++---
 1 file changed, 40 insertions(+), 14 deletions(-)

diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
index 6ffa0c4688..ffd624333f 100644
--- a/meta/classes/cve-check.bbclass
+++ b/meta/classes/cve-check.bbclass
@@ -26,7 +26,7 @@ CVE_PRODUCT ??= "${BPN}"
 CVE_VERSION ??= "${PV}"
 
 CVE_CHECK_DB_DIR ?= "${DL_DIR}/CVE_CHECK"
-CVE_CHECK_DB_FILE ?= "${CVE_CHECK_DB_DIR}/nvd-json.db"
+CVE_CHECK_DB_FILE ?= "${CVE_CHECK_DB_DIR}/nvdcve.db"
 
 CVE_CHECK_LOG ?= "${T}/cve.log"
 CVE_CHECK_TMP_FILE ?= "${TMPDIR}/cve_check"
@@ -189,27 +189,53 @@ def check_cves(d, patched_cves):
 conn = sqlite3.connect(db_file)
 c = conn.cursor()
 
-query = """SELECT * FROM PRODUCTS WHERE
-   (PRODUCT IS '{0}' AND VERSION = '{1}' AND OPERATOR IS '=') OR
-   (PRODUCT IS '{0}' AND OPERATOR IS '<=');"""
+query = "SELECT * FROM PRODUCTS WHERE PRODUCT IS '{0}';"
+
 for product in products:
 for row in c.execute(query.format(product, pv)):
 cve = row[1]
-version = row[4]
-
-try:
-discardVersion = LooseVersion(version) < LooseVersion(pv)
-except:
-discardVersion = True
+version_start = row[4]
+operator_start = row[5]
+version_end = row[6]
+operator_end = row[7]
 
 if pv in cve_whitelist.get(cve, []):
 bb.note("%s-%s has been whitelisted for %s" % (product, pv, 
cve))
 elif cve in patched_cves:
 bb.note("%s has been patched" % (cve))
-elif discardVersion:
-bb.debug(2, "Do not consider version %s " % (version))
 else:
-cves_unpatched.append(cve)
+if (operator_start == '=' and pv == version_start):
+cves_unpatched.append(cve)
+else:
+if operator_start:
+try:
+to_append_start =  (operator_start == '>=' and 
LooseVersion(pv) >= LooseVersion(version_start))
+to_append_start |= (operator_start == '>' and 
LooseVersion(pv) > LooseVersion(version_start))
+except:
+bb.note("%s: Failed to compare %s %s %s for %s" %
+(product, pv, operator_start, 
version_start, cve))
+to_append_start = False
+else:
+to_append_start = False
+
+if operator_end:
+try:
+to_append_end  = (operator_end == '<=' and 
LooseVersion(pv) <= LooseVersion(version_end))
+to_append_end |= (operator_end == '<' and 
LooseVersion(pv) < LooseVersion(version_end))
+except:
+bb.note("%s: Failed to compare %s %s %s for %s" %
+(product, pv, operator_end, version_end, 
cve))
+to_append_end = False
+else:
+to_append_end = False
+
+if operator_start and operator_end:
+to_append = to_append_start and to_append_end
+else:
+to_append = to_append_start or to_append_end
+
+if to_append:
+cves_unpatched.append(cve)
 bb.debug(2, "%s-%s is not patched for %s" % (product, pv, cve))
 conn.close()
 
@@ -217,7 +243,7 @@ def check_cves(d, patched_cves):
 
 def get_cve_info(d, cves):
 """
-Get CVE information from the database used by cve-check-tool.
+Get CVE information from the database.
 
 Unfortunately the only way to get CVE info is set the output to
 html (hard to parse) or query directly the database.
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


Re: [OE-core] [meta-oe][PATCH 1/3] cve-check: Depends on cve-update-db-native

2019-07-05 Thread Pierre Le Magourou
Hello,

> > From: Pierre Le Magourou 
> >
> > do_populate_cve_db is a native task.
> >
> > Signed-off-by: Pierre Le Magourou <
> > pierre.lemagou...@softbankrobotics.com>
> > ---
> >  meta/classes/cve-check.bbclass  | 2 +-
> >  meta/recipes-core/meta/cve-update-db.bb | 1 +
> >  2 files changed, 2 insertions(+), 1 deletion(-)
>
>
> https://autobuilder.yoctoproject.org/typhoon/#/builders/23/builds/1015
>
> :(

The autobuilder job launches cve-update-db and cve-update-db-native in
parallel, this cannot work because they both try to update the same
sqlite db.
As cve-update-db is only used for the build machine (native only), we
only need a cve-update-db-native.bb recipe. I'll send a v2 patch to
fix that.

ps: Sorry I just realized I was sending the patches to the wrong
destination (meta-oe instead of oe-core)

Pierre
-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [meta-oe][PATCH 1/3] cve-check: Depends on cve-update-db-native

2019-07-04 Thread Pierre Le Magourou
From: Pierre Le Magourou 

do_populate_cve_db is a native task.

Signed-off-by: Pierre Le Magourou 
---
 meta/classes/cve-check.bbclass  | 2 +-
 meta/recipes-core/meta/cve-update-db.bb | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
index 81071e3f19..6ffa0c4688 100644
--- a/meta/classes/cve-check.bbclass
+++ b/meta/classes/cve-check.bbclass
@@ -63,7 +63,7 @@ python do_cve_check () {
 }
 
 addtask cve_check after do_unpack before do_build
-do_cve_check[depends] = "cve-update-db:do_populate_cve_db"
+do_cve_check[depends] = "cve-update-db-native:do_populate_cve_db"
 do_cve_check[nostamp] = "1"
 
 python cve_check_cleanup () {
diff --git a/meta/recipes-core/meta/cve-update-db.bb 
b/meta/recipes-core/meta/cve-update-db.bb
index ae8f1a958b..8e553b4f9b 100644
--- a/meta/recipes-core/meta/cve-update-db.bb
+++ b/meta/recipes-core/meta/cve-update-db.bb
@@ -141,3 +141,4 @@ addtask do_populate_cve_db before do_fetch
 do_populate_cve_db[nostamp] = "1"
 
 EXCLUDE_FROM_WORLD = "1"
+BBCLASSEXTEND =+ "native"
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [meta-oe][PATCH 2/3] cve-update-db: Use NVD CPE data to populate PRODUCTS table

2019-07-04 Thread Pierre Le Magourou
From: Pierre Le Magourou 

Instead of using expanded list of affected versions that is not
reliable, use the 'cpe_match' node in the 'configurations' json node.

For cve-check to correctly match affected CVE, the sqlite database need to
contain operator_start, operator_end and the corresponding versions fields.

Signed-off-by: Pierre Le Magourou 
---
 meta/recipes-core/meta/cve-update-db.bb | 88 +++--
 1 file changed, 74 insertions(+), 14 deletions(-)

diff --git a/meta/recipes-core/meta/cve-update-db.bb 
b/meta/recipes-core/meta/cve-update-db.bb
index 8e553b4f9b..3ba80a0d28 100644
--- a/meta/recipes-core/meta/cve-update-db.bb
+++ b/meta/recipes-core/meta/cve-update-db.bb
@@ -25,7 +25,7 @@ python do_populate_cve_db() {
 YEAR_START = 2002
 
 db_dir = d.getVar("DL_DIR") + '/CVE_CHECK'
-db_file = db_dir + '/nvd-json.db'
+db_file = db_dir + '/nvdcve.db'
 json_tmpfile = db_dir + '/nvd.json.gz'
 proxy = d.getVar("https_proxy")
 cve_f = open(d.getVar("TMPDIR") + '/cve_check', 'a')
@@ -99,9 +99,76 @@ def initialize_db(c):
 c.execute("CREATE TABLE IF NOT EXISTS NVD (ID TEXT UNIQUE, SUMMARY TEXT, \
 SCOREV2 TEXT, SCOREV3 TEXT, MODIFIED INTEGER, VECTOR TEXT)")
 c.execute("CREATE TABLE IF NOT EXISTS PRODUCTS (HASH INTEGER UNIQUE, ID 
TEXT, \
-VENDOR TEXT, PRODUCT TEXT, VERSION TEXT, OPERATOR TEXT)")
-c.execute("CREATE INDEX IF NOT EXISTS PRODUCT_IDX ON PRODUCTS \
-(PRODUCT, VERSION)")
+VENDOR TEXT, PRODUCT TEXT, VERSION_START TEXT, OPERATOR_START TEXT, \
+VERSION_END TEXT, OPERATOR_END TEXT)")
+
+def insert_elt(c, db_values):
+product_str = db_values[0] + db_values[1] + db_values[2] + db_values[3]
+hashstr = hash_djb2(product_str)
+db_values.insert(0, hashstr)
+query = "insert or replace into PRODUCTS values (?, ?, ?, ?, ?, ?, ?, ?)"
+c.execute(query, db_values)
+
+def parse_node_and_insert(c, node, cveId):
+# Parse children node if needed
+try:
+for child in node['children']:
+parse_node_and_insert(c, child, cveId)
+except:
+pass
+
+# Exit if the cpe_match node does not exists
+try:
+cpe_match = node['cpe_match']
+except:
+return
+
+for cpe in cpe_match:
+if not cpe['vulnerable']:
+return
+cpe23 = cpe['cpe23Uri'].split(':')
+vendor = cpe23[3]
+product = cpe23[4]
+version = cpe23[5]
+
+if version != '*':
+# Version is defined, this is a '=' match
+db_values = [cveId, vendor, product, version, '=', '', '']
+insert_elt(c, db_values)
+else:
+# Parse start version, end version and operators
+op_start = ''
+op_end = ''
+v_start = ''
+v_end = ''
+
+try:
+if cpe['versionStartIncluding']:
+op_start = '>='
+v_start = cpe['versionStartIncluding']
+except:
+pass
+try:
+if cpe['versionStartExcluding']:
+op_start = '>'
+v_start = cpe['versionStartExcluding']
+except:
+pass
+try:
+if cpe['versionEndIncluding']:
+op_end = '<='
+v_end = cpe['versionEndIncluding']
+except:
+pass
+try:
+if cpe['versionEndExcluding']:
+op_end = '<'
+v_end = cpe['versionEndExcluding']
+except:
+pass
+
+db_values = [cveId, vendor, product, v_start, op_start, v_end, 
op_end]
+insert_elt(c, db_values)
 
 def update_db(c, json_filename):
 import json
@@ -125,16 +192,9 @@ def update_db(c, json_filename):
 c.execute("insert or replace into NVD values (?, ?, ?, ?, ?, ?)",
 [cveId, cveDesc, cvssv2, cvssv3, date, accessVector])
 
-for vendor in elt['cve']['affects']['vendor']['vendor_data']:
-for product in vendor['product']['product_data']:
-for version in product['version']['version_data']:
-product_str = 
cveId+vendor['vendor_name']+product['product_name']+version['version_value']
-hashstr = hash_djb2(product_str)
-c.execute("insert or replace into PRODUCTS values (?, ?, 
?, ?, ?, ?)",
-[ hashstr, cveId, vendor['vendor_name'],
-product['product_name'], 
version['version_value'],
-version['version_affected']])
-
+configurations = elt['configurations']['nodes']
+for config in configurations:
+parse_node_and_insert(c, config, cveId)
 
 
 addtask do_popula

[OE-core] [meta-oe][PATCH 3/3] cve-check: Update unpatched CVE matching

2019-07-04 Thread Pierre Le Magourou
From: Pierre Le Magourou 

Now that cve-update-db added CPE information to NVD database. We can
check for unpatched versions with operators '<', '<=', '>', and '>='.

Signed-off-by: Pierre Le Magourou 
---
 meta/classes/cve-check.bbclass | 54 +++---
 1 file changed, 40 insertions(+), 14 deletions(-)

diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
index 6ffa0c4688..ffd624333f 100644
--- a/meta/classes/cve-check.bbclass
+++ b/meta/classes/cve-check.bbclass
@@ -26,7 +26,7 @@ CVE_PRODUCT ??= "${BPN}"
 CVE_VERSION ??= "${PV}"
 
 CVE_CHECK_DB_DIR ?= "${DL_DIR}/CVE_CHECK"
-CVE_CHECK_DB_FILE ?= "${CVE_CHECK_DB_DIR}/nvd-json.db"
+CVE_CHECK_DB_FILE ?= "${CVE_CHECK_DB_DIR}/nvdcve.db"
 
 CVE_CHECK_LOG ?= "${T}/cve.log"
 CVE_CHECK_TMP_FILE ?= "${TMPDIR}/cve_check"
@@ -189,27 +189,53 @@ def check_cves(d, patched_cves):
 conn = sqlite3.connect(db_file)
 c = conn.cursor()
 
-query = """SELECT * FROM PRODUCTS WHERE
-   (PRODUCT IS '{0}' AND VERSION = '{1}' AND OPERATOR IS '=') OR
-   (PRODUCT IS '{0}' AND OPERATOR IS '<=');"""
+query = "SELECT * FROM PRODUCTS WHERE PRODUCT IS '{0}';"
+
 for product in products:
 for row in c.execute(query.format(product, pv)):
 cve = row[1]
-version = row[4]
-
-try:
-discardVersion = LooseVersion(version) < LooseVersion(pv)
-except:
-discardVersion = True
+version_start = row[4]
+operator_start = row[5]
+version_end = row[6]
+operator_end = row[7]
 
 if pv in cve_whitelist.get(cve, []):
 bb.note("%s-%s has been whitelisted for %s" % (product, pv, 
cve))
 elif cve in patched_cves:
 bb.note("%s has been patched" % (cve))
-elif discardVersion:
-bb.debug(2, "Do not consider version %s " % (version))
 else:
-cves_unpatched.append(cve)
+if (operator_start == '=' and pv == version_start):
+cves_unpatched.append(cve)
+else:
+if operator_start:
+try:
+to_append_start =  (operator_start == '>=' and 
LooseVersion(pv) >= LooseVersion(version_start))
+to_append_start |= (operator_start == '>' and 
LooseVersion(pv) > LooseVersion(version_start))
+except:
+bb.note("%s: Failed to compare %s %s %s for %s" %
+(product, pv, operator_start, 
version_start, cve))
+to_append_start = False
+else:
+to_append_start = False
+
+if operator_end:
+try:
+to_append_end  = (operator_end == '<=' and 
LooseVersion(pv) <= LooseVersion(version_end))
+to_append_end |= (operator_end == '<' and 
LooseVersion(pv) < LooseVersion(version_end))
+except:
+bb.note("%s: Failed to compare %s %s %s for %s" %
+(product, pv, operator_end, version_end, 
cve))
+to_append_end = False
+else:
+to_append_end = False
+
+if operator_start and operator_end:
+to_append = to_append_start and to_append_end
+else:
+to_append = to_append_start or to_append_end
+
+if to_append:
+cves_unpatched.append(cve)
 bb.debug(2, "%s-%s is not patched for %s" % (product, pv, cve))
 conn.close()
 
@@ -217,7 +243,7 @@ def check_cves(d, patched_cves):
 
 def get_cve_info(d, cves):
 """
-Get CVE information from the database used by cve-check-tool.
+Get CVE information from the database.
 
 Unfortunately the only way to get CVE info is set the output to
 html (hard to parse) or query directly the database.
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


Re: [OE-core] [meta-oe][PATCH v5] cve-update-db: do_populate_cve_db depends on do_fetch

2019-07-03 Thread Pierre Le Magourou
Hello,

> This patch broke "bitbake universe --runall=fetch" totally:
>
> The line which caused the problem is:
> addtask do_populate_cve_db before do_fetch
>
> Would you please fix it? Or I can help if needed.
>

This seems related to the NVD website down problem. I sent a patch to
manage inaccessible URLs. cve-update-db will not fail anymore if the
NVD data feeds cannot be downloaded.

Pierre
-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [meta-oe][PATCH] cve-update-db: Catch request.urlopen errors.

2019-07-03 Thread Pierre Le Magourou
From: Pierre Le Magourou 

If the NVD url is not accessible, print a warning on top of the CVE
report, and continue. The database will not be fully updated, but
cve_check can still run on the previous database.

Signed-off-by: Pierre Le Magourou 
---
 meta/classes/cve-check.bbclass  |  5 +++--
 meta/recipes-core/meta/cve-update-db.bb | 30 +-
 2 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
index 1e7e8dd441..81071e3f19 100644
--- a/meta/classes/cve-check.bbclass
+++ b/meta/classes/cve-check.bbclass
@@ -51,14 +51,15 @@ python do_cve_check () {
 Check recipe for patched and unpatched CVEs
 """
 
-if os.path.exists(d.getVar("CVE_CHECK_TMP_FILE")):
+if os.path.exists(d.getVar("CVE_CHECK_DB_FILE")):
 patched_cves = get_patches_cves(d)
 patched, unpatched = check_cves(d, patched_cves)
 if patched or unpatched:
 cve_data = get_cve_info(d, patched + unpatched)
 cve_write_data(d, patched, unpatched, cve_data)
 else:
-bb.note("Failed to update CVE database, skipping CVE check")
+bb.note("No CVE database found, skipping CVE check")
+
 }
 
 addtask cve_check after do_unpack before do_build
diff --git a/meta/recipes-core/meta/cve-update-db.bb 
b/meta/recipes-core/meta/cve-update-db.bb
index 3e5bae8b1d..ae8f1a958b 100644
--- a/meta/recipes-core/meta/cve-update-db.bb
+++ b/meta/recipes-core/meta/cve-update-db.bb
@@ -28,6 +28,7 @@ python do_populate_cve_db() {
 db_file = db_dir + '/nvd-json.db'
 json_tmpfile = db_dir + '/nvd.json.gz'
 proxy = d.getVar("https_proxy")
+cve_f = open(d.getVar("TMPDIR") + '/cve_check', 'a')
 
 if not os.path.isdir(db_dir):
 os.mkdir(db_dir)
@@ -47,9 +48,13 @@ python do_populate_cve_db() {
 req = urllib.request.Request(meta_url)
 if proxy:
 req.set_proxy(proxy, 'https')
-with urllib.request.urlopen(req) as r:
-date_line = str(r.read().splitlines()[0])
-last_modified = re.search('lastModifiedDate:(.*)', 
date_line).group(1)
+try:
+with urllib.request.urlopen(req, timeout=1) as r:
+date_line = str(r.read().splitlines()[0])
+last_modified = re.search('lastModifiedDate:(.*)', 
date_line).group(1)
+except:
+cve_f.write('Warning: CVE db update error, CVE data is 
outdated.\n\n')
+break
 
 # Compare with current db last modified date
 c.execute("select DATE from META where YEAR = '%d'" % year)
@@ -59,19 +64,26 @@ python do_populate_cve_db() {
 req = urllib.request.Request(json_url)
 if proxy:
 req.set_proxy(proxy, 'https')
-with urllib.request.urlopen(req) as r, open(json_tmpfile, 'wb') as 
tmpfile:
-shutil.copyfileobj(r, tmpfile)
+try:
+with urllib.request.urlopen(req, timeout=1) as r, \
+ open(json_tmpfile, 'wb') as tmpfile:
+shutil.copyfileobj(r, tmpfile)
+except:
+cve_f.write('Warning: CVE db update error, CVE data is 
outdated.\n\n')
+break
+
 with gzip.open(json_tmpfile, 'rt') as jsonfile:
 update_db(c, jsonfile)
 c.execute("insert or replace into META values (?, ?)",
 [year, last_modified])
 
+# Update success, set the date to cve_check file.
+if year == date.today().year:
+cve_f.write('CVE database update : %s\n\n' % date.today())
+
+cve_f.close()
 conn.commit()
 conn.close()
-
-cve_check_tmp_file =  d.getVar("TMPDIR") + '/cve_check'
-with open(cve_check_tmp_file, 'a'):
-os.utime(cve_check_tmp_file, None)
 }
 
 # DJB2 hash algorithm
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


Re: [OE-core] [PATCH] cve-update-db: Use std library instead of urllib3

2019-07-02 Thread Pierre Le Magourou
Hi,

> > On 07/02/2019 03:39 PM, ChenQi wrote:
> > > A recent do_populate_cve_db failure:
> > > https://autobuilder.yoctoproject.org/typhoon/#/builders/23/builds/1005/steps/7/logs/errors
> > >
> > >
> > > Could you please help look at what's going on?
> On Tue, 2019-07-02 at 16:08 +0800, ChenQi wrote:
> > I just tired to open the web but failed. The web seems down.
> >
>
> We were making some changes to the autobuilder to speed it up (changing
> database backends), its back now.
>

The NVD website is down, cve-update-db should not fail in that case. I
need to update it, so it prints a warning instead.
I am also wondering if we should mirror NVD json data feeds, to avoid
too many requests from Yocto users. (but I don't know how to do that)

Pierre
-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [meta-oe][PATCH v5] cve-update-db: do_populate_cve_db depends on do_fetch

2019-06-27 Thread Pierre Le Magourou
From: Pierre Le Magourou 

To be able to populate NVD database on a fetchall
(bitbake  --run-all=fetch), set the do_populate_cve_db task to be
executed before do_fetch.

Do not get CVE_CHECK_DB_DIR, CVE_CHECK_DB_FILE and CVE_CHECK_TMP_FILE
variable because do_populate_cve_db can be called in a context where
cve-check class is not loaded.

Signed-off-by: Pierre Le Magourou 
---
 meta/recipes-core/meta/cve-update-db.bb | 21 +
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/meta/recipes-core/meta/cve-update-db.bb 
b/meta/recipes-core/meta/cve-update-db.bb
index 4c896dc880..3e5bae8b1d 100644
--- a/meta/recipes-core/meta/cve-update-db.bb
+++ b/meta/recipes-core/meta/cve-update-db.bb
@@ -6,7 +6,6 @@ PACKAGES = ""
 
 inherit nopackages
 
-deltask do_fetch
 deltask do_unpack
 deltask do_patch
 deltask do_configure
@@ -24,11 +23,16 @@ python do_populate_cve_db() {
 
 BASE_URL = "https://nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-;
 YEAR_START = 2002
-JSON_TMPFILE = d.getVar("CVE_CHECK_DB_DIR") + '/nvd.json.gz'
+
+db_dir = d.getVar("DL_DIR") + '/CVE_CHECK'
+db_file = db_dir + '/nvd-json.db'
+json_tmpfile = db_dir + '/nvd.json.gz'
 proxy = d.getVar("https_proxy")
 
+if not os.path.isdir(db_dir):
+os.mkdir(db_dir)
+
 # Connect to database
-db_file = d.getVar("CVE_CHECK_DB_FILE")
 conn = sqlite3.connect(db_file)
 c = conn.cursor()
 
@@ -55,9 +59,9 @@ python do_populate_cve_db() {
 req = urllib.request.Request(json_url)
 if proxy:
 req.set_proxy(proxy, 'https')
-with urllib.request.urlopen(req) as r, open(JSON_TMPFILE, 'wb') as 
tmpfile:
+with urllib.request.urlopen(req) as r, open(json_tmpfile, 'wb') as 
tmpfile:
 shutil.copyfileobj(r, tmpfile)
-with gzip.open(JSON_TMPFILE, 'rt') as jsonfile:
+with gzip.open(json_tmpfile, 'rt') as jsonfile:
 update_db(c, jsonfile)
 c.execute("insert or replace into META values (?, ?)",
 [year, last_modified])
@@ -65,8 +69,9 @@ python do_populate_cve_db() {
 conn.commit()
 conn.close()
 
-with open(d.getVar("CVE_CHECK_TMP_FILE"), 'a'):
-os.utime(d.getVar("CVE_CHECK_TMP_FILE"), None)
+cve_check_tmp_file =  d.getVar("TMPDIR") + '/cve_check'
+with open(cve_check_tmp_file, 'a'):
+os.utime(cve_check_tmp_file, None)
 }
 
 # DJB2 hash algorithm
@@ -120,7 +125,7 @@ def update_db(c, json_filename):
 
 
 
-addtask do_populate_cve_db before do_cve_check
+addtask do_populate_cve_db before do_fetch
 do_populate_cve_db[nostamp] = "1"
 
 EXCLUDE_FROM_WORLD = "1"
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [meta-oe][PATCH v4] cve-update-db: do_populate_cve_db depends on do_fetch

2019-06-27 Thread Pierre Le Magourou
From: Pierre Le Magourou 

To be able to populate NVD database on a fetchall
(bitbake  --run-all=fetch), set the do_populate_cve_db task to be
executed before do_fetch.

Do not get CVE_CHECK_DB_DIR, CVE_CHECK_DB_FILE and CVE_CHECK_TMP_FILE
variable because do_populate_cve_db can be called in a context where
cve-check class is not loaded.

Signed-off-by: Pierre Le Magourou 
---
 meta/recipes-core/meta/cve-update-db.bb | 22 ++
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/meta/recipes-core/meta/cve-update-db.bb 
b/meta/recipes-core/meta/cve-update-db.bb
index 522fd23807..0875c00835 100644
--- a/meta/recipes-core/meta/cve-update-db.bb
+++ b/meta/recipes-core/meta/cve-update-db.bb
@@ -6,7 +6,6 @@ PACKAGES = ""
 
 inherit nopackages
 
-deltask do_fetch
 deltask do_unpack
 deltask do_patch
 deltask do_configure
@@ -24,10 +23,16 @@ python do_populate_cve_db() {
 
 BASE_URL = "https://nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-;
 YEAR_START = 2002
-JSON_TMPFILE = d.getVar("CVE_CHECK_DB_DIR") + '/nvd.json.gz'
+
+db_dir = d.getVar("DL_DIR") + '/CVE_CHECK'
+db_file = db_dir + '/nvd-json.db'
+json_tmpfile = db_dir + '/nvd.json.gz'
+proxy = d.getVar("https_proxy")
+
+if not os.path.isdir(db_dir):
+os.mkdir(db_dir)
 
 # Connect to database
-db_file = d.getVar("CVE_CHECK_DB_FILE")
 conn = sqlite3.connect(db_file)
 c = conn.cursor()
 
@@ -50,9 +55,9 @@ python do_populate_cve_db() {
 meta = c.fetchone()
 if not meta or meta[0] != last_modified:
 # Update db with current year json file
-with http.request('GET', json_url, preload_content=False) as r, 
open(JSON_TMPFILE, 'wb') as tmpfile:
+with http.request('GET', json_url, preload_content=False) as r, 
open(json_tmpfile, 'wb') as tmpfile:
 shutil.copyfileobj(r, tmpfile)
-with gzip.open(JSON_TMPFILE, 'rt') as jsonfile:
+with gzip.open(json_tmpfile, 'rt') as jsonfile:
 update_db(c, jsonfile)
 c.execute("insert or replace into META values (?, ?)",
 [year, last_modified])
@@ -60,8 +65,9 @@ python do_populate_cve_db() {
 conn.commit()
 conn.close()
 
-with open(d.getVar("CVE_CHECK_TMP_FILE"), 'a'):
-os.utime(d.getVar("CVE_CHECK_TMP_FILE"), None)
+cve_check_tmp_file =  d.getVar("TMPDIR") + '/cve_check'
+with open(cve_check_tmp_file, 'a'):
+os.utime(cve_check_tmp_file, None)
 }
 
 # DJB2 hash algorithm
@@ -115,7 +121,7 @@ def update_db(c, json_filename):
 
 
 
-addtask do_populate_cve_db before do_cve_check
+addtask do_populate_cve_db before do_fetch
 do_populate_cve_db[nostamp] = "1"
 
 EXCLUDE_FROM_WORLD = "1"
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [meta-oe][PATCH v3] cve-update-db: do_populate_cve_db depends on do_fetch

2019-06-27 Thread Pierre Le Magourou
From: Pierre Le Magourou 

To be able to populate NVD database on a fetchall
(bitbake  --run-all=fetch), set the do_populate_cve_db task to be
executed before do_fetch.

Do not get CVE_CHECK_DB_DIR, CVE_CHECK_DB_FILE and CVE_CHECK_TMP_FILE
variable because do_populate_cve_db can be called in a context where
cve-check class is not loaded.

Signed-off-by: Pierre Le Magourou 
---
 meta/recipes-core/meta/cve-update-db.bb | 22 ++
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/meta/recipes-core/meta/cve-update-db.bb 
b/meta/recipes-core/meta/cve-update-db.bb
index 522fd23807..5c14cf60af 100644
--- a/meta/recipes-core/meta/cve-update-db.bb
+++ b/meta/recipes-core/meta/cve-update-db.bb
@@ -6,7 +6,6 @@ PACKAGES = ""
 
 inherit nopackages
 
-deltask do_fetch
 deltask do_unpack
 deltask do_patch
 deltask do_configure
@@ -24,10 +23,16 @@ python do_populate_cve_db() {
 
 BASE_URL = "https://nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-;
 YEAR_START = 2002
-JSON_TMPFILE = d.getVar("CVE_CHECK_DB_DIR") + '/nvd.json.gz'
+
+db_dir = d.getVar("DL_DIR") + 'CVE_CHECK'
+db_file = db_dir + '/nvd-json.db'
+json_tmpfile = db_dir + '/nvd.json.gz'
+proxy = d.getVar("https_proxy")
+
+if not os.path.isdir(db_dir):
+os.mkdir(db_dir)
 
 # Connect to database
-db_file = d.getVar("CVE_CHECK_DB_FILE")
 conn = sqlite3.connect(db_file)
 c = conn.cursor()
 
@@ -50,9 +55,9 @@ python do_populate_cve_db() {
 meta = c.fetchone()
 if not meta or meta[0] != last_modified:
 # Update db with current year json file
-with http.request('GET', json_url, preload_content=False) as r, 
open(JSON_TMPFILE, 'wb') as tmpfile:
+with http.request('GET', json_url, preload_content=False) as r, 
open(json_tmpfile, 'wb') as tmpfile:
 shutil.copyfileobj(r, tmpfile)
-with gzip.open(JSON_TMPFILE, 'rt') as jsonfile:
+with gzip.open(json_tmpfile, 'rt') as jsonfile:
 update_db(c, jsonfile)
 c.execute("insert or replace into META values (?, ?)",
 [year, last_modified])
@@ -60,8 +65,9 @@ python do_populate_cve_db() {
 conn.commit()
 conn.close()
 
-with open(d.getVar("CVE_CHECK_TMP_FILE"), 'a'):
-os.utime(d.getVar("CVE_CHECK_TMP_FILE"), None)
+cve_check_tmp_file =  d.getVar("TMPDIR") + '/cve_check'
+with open(cve_check_tmp_file, 'a'):
+os.utime(cve_check_tmp_file, None)
 }
 
 # DJB2 hash algorithm
@@ -115,7 +121,7 @@ def update_db(c, json_filename):
 
 
 
-addtask do_populate_cve_db before do_cve_check
+addtask do_populate_cve_db before do_fetch
 do_populate_cve_db[nostamp] = "1"
 
 EXCLUDE_FROM_WORLD = "1"
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


Re: [OE-core] [meta-oe][PATCH v2] cve-update-db: do_populate_cve_db depends on do_fetch

2019-06-27 Thread Pierre Le Magourou
> Thanks for the fast turnaround on the patch. This seems to move the
> problem to:
>
> https://autobuilder.yoctoproject.org/typhoon/#/builders/23/builds/990/steps/7/logs/step1b
>
> :(
>
> Perhaps we need to skip the recipe if the class isn't enabled? Is that
> the reason its failing like this?

It is failing with 'sqlite3.OperationalError' exception when opening
the sqlite3 db file.
I reproduced the bug by removing the ${DL_DIR}/CVE_CHECK directory

I forgot to check that the ${DL_DIR}/CVE_CHECK directory exists before
creating sqlite db file in it.
I'll send a v3 patch to fix this.

Pierre
-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [meta-oe][PATCH v2] cve-update-db: do_populate_cve_db depends on do_fetch

2019-06-27 Thread Pierre Le Magourou
From: Pierre Le Magourou 

To be able to populate NVD database on a fetchall
(bitbake  --run-all=fetch), set the do_populate_cve_db task to be
executed before do_fetch.

Signed-off-by: Pierre Le Magourou 
---
 meta/recipes-core/meta/cve-update-db.bb | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/meta/recipes-core/meta/cve-update-db.bb 
b/meta/recipes-core/meta/cve-update-db.bb
index 522fd23807..e096db7717 100644
--- a/meta/recipes-core/meta/cve-update-db.bb
+++ b/meta/recipes-core/meta/cve-update-db.bb
@@ -4,9 +4,12 @@ LICENSE = "MIT"
 INHIBIT_DEFAULT_DEPS = "1"
 PACKAGES = ""
 
+CVE_CHECK_DB_DIR ?= "${DL_DIR}/CVE_CHECK"
+CVE_CHECK_DB_FILE ?= "${CVE_CHECK_DB_DIR}/nvd-json.db"
+CVE_CHECK_TMP_FILE ?= "${TMPDIR}/cve_check"
+
 inherit nopackages
 
-deltask do_fetch
 deltask do_unpack
 deltask do_patch
 deltask do_configure
@@ -115,7 +118,7 @@ def update_db(c, json_filename):
 
 
 
-addtask do_populate_cve_db before do_cve_check
+addtask do_populate_cve_db before do_fetch
 do_populate_cve_db[nostamp] = "1"
 
 EXCLUDE_FROM_WORLD = "1"
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


Re: [OE-core] [PATCH 1/4] cve-update-db: New recipe to update CVE database

2019-06-27 Thread Pierre Le Magourou
Hi,

> It looks like CVE_CHECK_DB_DIR has no default value which resulted in:
>
> https://autobuilder.yoctoproject.org/typhoon/#/builders/23/builds/988/steps/7/logs/step1b
>
> We only started seeing that error after your later patch to add back
> the do_fetch task. build-appliance is trying to collect up all the
> sources it may need.
>

I see the problem, it happens when cve-update-db do_fetch task is executed and
cve-check class is not inherited. I sent a v2 patch that sets default value to
CVE_CHECK_DB_DIR.


Pierre
-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [PATCH] cve-update-db: Manage proxy if needed.

2019-06-26 Thread Pierre Le Magourou
From: Pierre Le Magourou 

If https_proxy environment variable is defined, manage proxy to be able
to download meta and json data feeds from https://nvd.nist.gov

Signed-off-by: Pierre Le Magourou 
---
 meta/recipes-core/meta/cve-update-db.bb | 11 +--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/meta/recipes-core/meta/cve-update-db.bb 
b/meta/recipes-core/meta/cve-update-db.bb
index 5778e00e79..bcc8d4ab1a 100644
--- a/meta/recipes-core/meta/cve-update-db.bb
+++ b/meta/recipes-core/meta/cve-update-db.bb
@@ -24,6 +24,7 @@ python do_populate_cve_db() {
 BASE_URL = "https://nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-;
 YEAR_START = 2002
 JSON_TMPFILE = d.getVar("CVE_CHECK_DB_DIR") + '/nvd.json.gz'
+proxy = d.getVar("https_proxy")
 
 # Connect to database
 db_file = d.getVar("CVE_CHECK_DB_FILE")
@@ -38,7 +39,10 @@ python do_populate_cve_db() {
 json_url = year_url + ".json.gz"
 
 # Retrieve meta last modified date
-with urllib.request.urlopen(meta_url) as r:
+req = urllib.request.Request(meta_url)
+if proxy:
+req.set_proxy(proxy, 'https')
+with urllib.request.urlopen(req) as r:
 date_line = str(r.read().splitlines()[0])
 last_modified = re.search('lastModifiedDate:(.*)', 
date_line).group(1)
 
@@ -47,7 +51,10 @@ python do_populate_cve_db() {
 meta = c.fetchone()
 if not meta or meta[0] != last_modified:
 # Update db with current year json file
-with urllib.request.urlopen(json_url) as r, open(JSON_TMPFILE, 
'wb') as tmpfile:
+req = urllib.request.Request(json_url)
+if proxy:
+req.set_proxy(proxy, 'https')
+with urllib.request.urlopen(req) as r, open(JSON_TMPFILE, 'wb') as 
tmpfile:
 shutil.copyfileobj(r, tmpfile)
 with gzip.open(JSON_TMPFILE, 'rt') as jsonfile:
 update_db(c, jsonfile)
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [PATCH] cve-update-db: do_populate_cve_db depends on do_fetch

2019-06-26 Thread Pierre Le Magourou
From: Pierre Le Magourou 

To be able to populate NVD database on a fetchall
(bitbake  --run-all=fetch), set the do_populate_cve_db task to be
executed before do_fetch.

Signed-off-by: Pierre Le Magourou 
---
 meta/recipes-core/meta/cve-update-db.bb | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/meta/recipes-core/meta/cve-update-db.bb 
b/meta/recipes-core/meta/cve-update-db.bb
index 1f48820cc6..5778e00e79 100644
--- a/meta/recipes-core/meta/cve-update-db.bb
+++ b/meta/recipes-core/meta/cve-update-db.bb
@@ -6,7 +6,6 @@ PACKAGES = ""
 
 inherit nopackages
 
-deltask do_fetch
 deltask do_unpack
 deltask do_patch
 deltask do_configure
@@ -113,7 +112,7 @@ def update_db(c, json_filename):
 
 
 
-addtask do_populate_cve_db before do_cve_check
+addtask do_populate_cve_db before do_fetch
 do_populate_cve_db[nostamp] = "1"
 
 EXCLUDE_FROM_WORLD = "1"
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


Re: [OE-core] [PATCH 1/4] cve-update-db: New recipe to update CVE database

2019-06-25 Thread Pierre Le Magourou
Hi,

> Also, the CVE db is updated using this custom task without link to
> do_fetch, which means a fetchall task would not update the database for
> off line NO_NETWORK builds.
>
> Could the task be added as dependency to do_fetch() or are there some other
> side effects?
>

Yes I can do that, I don't think this will cause side effects.

Pierre
-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [PATCH] cve-update-db: Use std library instead of urllib3

2019-06-24 Thread Pierre Le Magourou
From: Pierre Le Magourou 

urllib3 was used in this recipe but it was not set as a
dependency. As it is not specifically needed, rewrite the recipe with
urllib from the standard library.

Signed-off-by: Pierre Le Magourou 
---
 meta/recipes-core/meta/cve-update-db.bb | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/meta/recipes-core/meta/cve-update-db.bb 
b/meta/recipes-core/meta/cve-update-db.bb
index 522fd23807..1f48820cc6 100644
--- a/meta/recipes-core/meta/cve-update-db.bb
+++ b/meta/recipes-core/meta/cve-update-db.bb
@@ -19,7 +19,7 @@ python do_populate_cve_db() {
 Update NVD database with json data feed
 """
 
-import sqlite3, urllib3, shutil, gzip, re
+import sqlite3, urllib, shutil, gzip, re
 from datetime import date
 
 BASE_URL = "https://nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-;
@@ -33,16 +33,14 @@ python do_populate_cve_db() {
 
 initialize_db(c)
 
-http = urllib3.PoolManager()
-
 for year in range(YEAR_START, date.today().year + 1):
 year_url = BASE_URL + str(year)
 meta_url = year_url + ".meta"
 json_url = year_url + ".json.gz"
 
 # Retrieve meta last modified date
-with http.request('GET', meta_url, preload_content=False) as r:
-date_line = str(r.data.splitlines()[0])
+with urllib.request.urlopen(meta_url) as r:
+date_line = str(r.read().splitlines()[0])
 last_modified = re.search('lastModifiedDate:(.*)', 
date_line).group(1)
 
 # Compare with current db last modified date
@@ -50,7 +48,7 @@ python do_populate_cve_db() {
 meta = c.fetchone()
 if not meta or meta[0] != last_modified:
 # Update db with current year json file
-with http.request('GET', json_url, preload_content=False) as r, 
open(JSON_TMPFILE, 'wb') as tmpfile:
+with urllib.request.urlopen(json_url) as r, open(JSON_TMPFILE, 
'wb') as tmpfile:
 shutil.copyfileobj(r, tmpfile)
 with gzip.open(JSON_TMPFILE, 'rt') as jsonfile:
 update_db(c, jsonfile)
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


Re: [OE-core] [PATCH 1/4] cve-update-db: New recipe to update CVE database

2019-06-24 Thread Pierre Le Magourou
Hi,

> > This adds python3 urllib3 (python3-urllib3 in Debian) to build environment
> > dependencies. It's the first user of urllib3 in poky, AFAIK. Maybe
> > documentation could be updated too, e.g.
> > https://www.yoctoproject.org/docs/latest/mega-manual/mega-manual.html#brief-build-system-packages
>
> Somehow I didn't notice it, thanks.
>
> Pierre, can you rewrite this to use standard library instead of urllib3?

Yes of course,
I only need urrlib to fetch the NVD json feeds, so I don't need
urllib3, I can use standard library.

Pierre
-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


Re: [OE-core] [PATCH 1/4] cve-update-db: New recipe to update CVE database

2019-06-20 Thread Pierre Le Magourou
> Not sure which of the changes is responsible, but this is new:
> WARNING: flex-native-2.6.0-r0 do_cve_check: Found unpatched CVE
> (CVE-2015-1773)
>
> https://nvd.nist.gov/vuln/detail/CVE-2015-1773
>
> Note that the flex tool is completely unrelated to Apache Flex.
>
>
I see, the 4/4 patch is responsible for that (Consider CVE that affects
versions with less than operator). It takes into account the comparison
operator in the json NVD file (new 'version_affected' field that was not in
the XML data feed). So this CVE matches because 2.6.0 <= 4.14.0. But it
should not match because it concerns another product (flex_project/flex vs
Apache/flex).

There is indeed a problem I didn't manage. The CVE_PRODUCT variable we use
in cve-check only takes the product name (here 'flex') into account, we
should also consider the vendor name (here 'flex_project').

Without this patch (4/4), the behaviour should be the same as before.

Pierre
-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


Re: [OE-core] [PATCH 2/4] cve-check: Remove dependency to cve-check-tool-native

2019-06-19 Thread Pierre Le Magourou
> Does this mean we can delete the cve-check-tool recipe itself too?
>

Yes, with this patch cve-check class does not need cve-check-tool anymore.

Pierre
-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [PATCH 4/4] cve-check: Consider CVE that affects versions with less than operator

2019-06-19 Thread Pierre Le Magourou
From: Pierre Le Magourou 

In the NVD json CVE feed, affected versions can be strictly matched to a
version, but they can also be matched with the operator '<='.

Add a new condition in the sqlite query to match affected versions that
are defined with the operator '<='. Then use LooseVersion to discard all
versions that are not relevant.

Signed-off-by: Pierre Le Magourou 
---
 meta/classes/cve-check.bbclass | 16 ++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
index e7540b8c1f..379f7121cc 100644
--- a/meta/classes/cve-check.bbclass
+++ b/meta/classes/cve-check.bbclass
@@ -166,6 +166,7 @@ def check_cves(d, patched_cves):
 Connect to the NVD database and find unpatched cves.
 """
 import ast, csv, tempfile, subprocess, io
+from distutils.version import LooseVersion
 
 cves_unpatched = []
 # CVE_PRODUCT can contain more than one product (eg. curl/libcurl)
@@ -186,14 +187,25 @@ def check_cves(d, patched_cves):
 conn = sqlite3.connect(db_file)
 c = conn.cursor()
 
-query = "SELECT * FROM PRODUCTS WHERE PRODUCT IS '%s' AND VERSION IS '%s';"
+query = """SELECT * FROM PRODUCTS WHERE
+   (PRODUCT IS '{0}' AND VERSION = '{1}' AND OPERATOR IS '=') OR
+   (PRODUCT IS '{0}' AND OPERATOR IS '<=');"""
 for idx in range(len(bpn)):
-for row in c.execute(query % (bpn[idx],pv)):
+for row in c.execute(query.format(bpn[idx],pv)):
 cve = row[1]
+version = row[4]
+
+try:
+discardVersion = LooseVersion(version) < LooseVersion(pv)
+except:
+discardVersion = True
+
 if pv in cve_whitelist.get(cve,[]):
 bb.note("%s-%s has been whitelisted for %s" % (bpn[idx], pv, 
cve))
 elif cve in patched_cves:
 bb.note("%s has been patched" % (cve))
+elif discardVersion:
+bb.debug(2, "Do not consider version %s " % (version))
 else:
 cves_unpatched.append(cve)
 bb.debug(2, "%s-%s is not patched for %s" % (bpn[idx], pv, 
cve))
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [PATCH 3/4] cve-check: Manage CVE_PRODUCT with more than one name

2019-06-19 Thread Pierre Le Magourou
From: Pierre Le Magourou 

In some rare cases (eg. curl recipe) the CVE_PRODUCT contains more than
one name.

Signed-off-by: Pierre Le Magourou 
---
 meta/classes/cve-check.bbclass | 25 ++---
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
index 28619c7bd4..e7540b8c1f 100644
--- a/meta/classes/cve-check.bbclass
+++ b/meta/classes/cve-check.bbclass
@@ -168,9 +168,10 @@ def check_cves(d, patched_cves):
 import ast, csv, tempfile, subprocess, io
 
 cves_unpatched = []
-bpn = d.getVar("CVE_PRODUCT")
+# CVE_PRODUCT can contain more than one product (eg. curl/libcurl)
+bpn = d.getVar("CVE_PRODUCT").split()
 # If this has been unset then we're not scanning for CVEs here (for 
example, image recipes)
-if not bpn:
+if len(bpn) == 0:
 return ([], [])
 pv = d.getVar("CVE_VERSION").split("+git")[0]
 cve_whitelist = ast.literal_eval(d.getVar("CVE_CHECK_CVE_WHITELIST"))
@@ -184,16 +185,18 @@ def check_cves(d, patched_cves):
 db_file = d.getVar("CVE_CHECK_DB_FILE")
 conn = sqlite3.connect(db_file)
 c = conn.cursor()
+
 query = "SELECT * FROM PRODUCTS WHERE PRODUCT IS '%s' AND VERSION IS '%s';"
-for row in c.execute(query % (bpn,pv)):
-cve = row[1]
-if pv in cve_whitelist.get(cve,[]):
-bb.note("%s-%s has been whitelisted for %s" % (bpn, pv, cve))
-elif cve in patched_cves:
-bb.note("%s has been patched" % (cve))
-else:
-cves_unpatched.append(cve)
-bb.debug(2, "%s-%s is not patched for %s" % (bpn, pv, cve))
+for idx in range(len(bpn)):
+for row in c.execute(query % (bpn[idx],pv)):
+cve = row[1]
+if pv in cve_whitelist.get(cve,[]):
+bb.note("%s-%s has been whitelisted for %s" % (bpn[idx], pv, 
cve))
+elif cve in patched_cves:
+bb.note("%s has been patched" % (cve))
+else:
+cves_unpatched.append(cve)
+bb.debug(2, "%s-%s is not patched for %s" % (bpn[idx], pv, 
cve))
 conn.close()
 
 return (list(patched_cves), cves_unpatched)
-- 
2.11.0

-- 
___
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core


[OE-core] [PATCH 1/4] cve-update-db: New recipe to update CVE database

2019-06-19 Thread Pierre Le Magourou
From: Pierre Le Magourou 

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.

Signed-off-by: Pierre Le Magourou 
---
 meta/recipes-core/meta/cve-update-db.bb | 121 
 1 file changed, 121 insertions(+)
 create mode 100644 meta/recipes-core/meta/cve-update-db.bb

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 00..522fd23807
--- /dev/null
+++ b/meta/recipes-core/meta/cve-update-db.bb
@@ -0,0 +1,121 @@
+SUMMARY = "Updates the NVD CVE database"
+LICENSE = "MIT"
+
+INHIBIT_DEFAULT_DEPS = "1"
+PACKAGES = ""
+
+inherit nopackages
+
+deltask do_fetch
+deltask do_unpack
+deltask do_patch
+deltask do_configure
+deltask do_compile
+deltask do_install
+deltask do_populate_sysroot
+
+python do_populate_cve_db() {
+"""
+Update NVD database with json data feed
+"""
+
+import sqlite3, urllib3, shutil, gzip, re
+from datetime import date
+
+BASE_URL = "https://nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-;
+YEAR_START = 2002
+JSON_TMPFILE = d.getVar("CVE_CHECK_DB_DIR") + '/nvd.json.gz'
+
+# Connect to database
+db_file = d.getVar("CVE_CHECK_DB_FILE")
+conn = sqlite3.connect(db_file)
+c = conn.cursor()
+
+initialize_db(c)
+
+http = urllib3.PoolManager()
+
+for year in range(YEAR_START, date.today().year + 1):
+year_url = BASE_URL + str(year)
+meta_url = year_url + ".meta"
+json_url = year_url + ".json.gz"
+
+# Retrieve meta last modified date
+with http.request('GET', meta_url, preload_content=False) as r:
+date_line = str(r.data.splitlines()[0])
+last_modified = re.search('lastModifiedDate:(.*)', 
date_line).group(1)
+
+# Compare with current db last modified date
+c.execute("select DATE from META where YEAR = '%d'" % year)
+meta = c.fetchone()
+if not meta or meta[0] != last_modified:
+# Update db with current year json file
+with http.request('GET', json_url, preload_content=False) as r, 
open(JSON_TMPFILE, 'wb') as tmpfile:
+shutil.copyfileobj(r, tmpfile)
+with gzip.open(JSON_TMPFILE, 'rt') as jsonfile:
+update_db(c, jsonfile)
+c.execute("insert or replace into META values (?, ?)",
+[year, last_modified])
+
+conn.commit()
+conn.close()
+
+with open(d.getVar("CVE_CHECK_TMP_FILE"), 'a'):
+os.utime(d.getVar("CVE_CHECK_TMP_FILE"), None)
+}
+
+# DJB2 hash algorithm
+def hash_djb2(s):
+hash = 5381
+for x in s:
+hash = (( hash << 5) + hash) + ord(x)
+
+return hash & 0x
+
+def initialize_db(c):
+c.execute("CREATE TABLE IF NOT EXISTS META (YEAR INTEGER UNIQUE, DATE 
TEXT)")
+c.execute("CREATE TABLE IF NOT EXISTS NVD (ID TEXT UNIQUE, SUMMARY TEXT, \
+SCOREV2 TEXT, SCOREV3 TEXT, MODIFIED INTEGER, VECTOR TEXT)")
+c.execute("CREATE TABLE IF NOT EXISTS PRODUCTS (HASH INTEGER UNIQUE, ID 
TEXT, \
+VENDOR TEXT, PRODUCT TEXT, VERSION TEXT, OPERATOR TEXT)")
+c.execute("CREATE INDEX IF NOT EXISTS PRODUCT_IDX ON PRODUCTS \
+(PRODUCT, VERSION)")
+
+def update_db(c, json_filename):
+import json
+root = json.load(json_filename)
+
+for elt in root['CVE_Items']:
+if not elt['impact']:
+continue
+
+cveId = elt['cve']['CVE_data_meta']['ID']
+cveDesc = elt['cve']['description']['description_data'][0]['value']
+date = elt['lastModifiedDate']
+accessVector = elt['impact']['baseMetricV2']['cvssV2']['accessVector']
+cvssv2 = elt['impact']['baseMetricV2']['cvssV2']['baseScore']
+
+try:
+cvssv3 = elt['impact']['baseMetricV3']['cvssV3']['baseScore']
+except:
+cvssv3 = 0.0
+
+c.execute("insert or replace into NVD values (?, ?, ?, ?, ?, ?)",
+[cveId, cveDesc, cvssv2, cvssv3, date, accessVector])
+
+for vendor in elt['cve']['affects']['vendor']['vendor_data']:
+for product in vendor['product']['product_data']:
+for version in product['version']['version_data']:
+product_str = 
cveId+vendor['vendor_name']+product['product_name']+version['version_value']
+hashstr = hash_djb2(product_str)
+c.execute("insert or replace into PRODUCTS values (?, ?, 
?, ?, ?, ?)",
+  

[OE-core] [PATCH 2/4] cve-check: Remove dependency to cve-check-tool-native

2019-06-19 Thread Pierre Le Magourou
From: Pierre Le Magourou 

Use the new update-cve-db recipe to update database.

Signed-off-by: Pierre Le Magourou 
---
 meta/classes/cve-check.bbclass | 71 --
 1 file changed, 26 insertions(+), 45 deletions(-)

diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
index 743bc08a4f..28619c7bd4 100644
--- a/meta/classes/cve-check.bbclass
+++ b/meta/classes/cve-check.bbclass
@@ -26,7 +26,7 @@ CVE_PRODUCT ??= "${BPN}"
 CVE_VERSION ??= "${PV}"
 
 CVE_CHECK_DB_DIR ?= "${DL_DIR}/CVE_CHECK"
-CVE_CHECK_DB_FILE ?= "${CVE_CHECK_DB_DIR}/nvd.db"
+CVE_CHECK_DB_FILE ?= "${CVE_CHECK_DB_DIR}/nvd-json.db"
 
 CVE_CHECK_LOG ?= "${T}/cve.log"
 CVE_CHECK_TMP_FILE ?= "${TMPDIR}/cve_check"
@@ -62,7 +62,7 @@ python do_cve_check () {
 }
 
 addtask cve_check after do_unpack before do_build
-do_cve_check[depends] = "cve-check-tool-native:do_populate_sysroot 
cve-check-tool-native:do_populate_cve_db"
+do_cve_check[depends] = "cve-update-db:do_populate_cve_db"
 do_cve_check[nostamp] = "1"
 
 python cve_check_cleanup () {
@@ -163,61 +163,40 @@ def get_patches_cves(d):
 
 def check_cves(d, patched_cves):
 """
-Run cve-check-tool looking for patched and unpatched CVEs.
+Connect to the NVD database and find unpatched cves.
 """
-
 import ast, csv, tempfile, subprocess, io
 
-cves_patched = []
 cves_unpatched = []
 bpn = d.getVar("CVE_PRODUCT")
 # If this has been unset then we're not scanning for CVEs here (for 
example, image recipes)
 if not bpn:
 return ([], [])
 pv = d.getVar("CVE_VERSION").split("+git")[0]
-cves = " ".join(patched_cves)
-cve_db_dir = d.getVar("CVE_CHECK_DB_DIR")
 cve_whitelist = ast.literal_eval(d.getVar("CVE_CHECK_CVE_WHITELIST"))
-cve_cmd = "cve-check-tool"
-cmd = [cve_cmd, "--no-html", "--skip-update", "--csv", "--not-affected", 
"-t", "faux", "-d", cve_db_dir]
 
 # If the recipe has been whitlisted we return empty lists
 if d.getVar("PN") in d.getVar("CVE_CHECK_PN_WHITELIST").split():
 bb.note("Recipe has been whitelisted, skipping check")
 return ([], [])
 
-try:
-# Write the faux CSV file to be used with cve-check-tool
-fd, faux = tempfile.mkstemp(prefix="cve-faux-")
-with os.fdopen(fd, "w") as f:
-for pn in bpn.split():
-f.write("%s,%s,%s,\n" % (pn, pv, cves))
-cmd.append(faux)
-
-output = subprocess.check_output(cmd).decode("utf-8")
-bb.debug(2, "Output of command %s:\n%s" % ("\n".join(cmd), output))
-except subprocess.CalledProcessError as e:
-bb.warn("Couldn't check for CVEs: %s (output %s)" % (e, e.output))
-finally:
-os.remove(faux)
-
-for row in csv.reader(io.StringIO(output)):
-# Third row has the unpatched CVEs
-if row[2]:
-for cve in row[2].split():
-# Skip if the CVE has been whitlisted for the current version
-if pv in cve_whitelist.get(cve,[]):
-bb.note("%s-%s has been whitelisted for %s" % (bpn, pv, 
cve))
-else:
-cves_unpatched.append(cve)
-bb.debug(2, "%s-%s is not patched for %s" % (bpn, pv, cve))
-# Fourth row has patched CVEs
-if row[3]:
-for cve in row[3].split():
-cves_patched.append(cve)
-bb.debug(2, "%s-%s is patched for %s" % (bpn, pv, cve))
-
-return (cves_patched, cves_unpatched)
+import sqlite3
+db_file = d.getVar("CVE_CHECK_DB_FILE")
+conn = sqlite3.connect(db_file)
+c = conn.cursor()
+query = "SELECT * FROM PRODUCTS WHERE PRODUCT IS '%s' AND VERSION IS '%s';"
+for row in c.execute(query % (bpn,pv)):
+cve = row[1]
+if pv in cve_whitelist.get(cve,[]):
+bb.note("%s-%s has been whitelisted for %s" % (bpn, pv, cve))
+elif cve in patched_cves:
+bb.note("%s has been patched" % (cve))
+else:
+cves_unpatched.append(cve)
+bb.debug(2, "%s-%s is not patched for %s" % (bpn, pv, cve))
+conn.close()
+
+return (list(patched_cves), cves_unpatched)
 
 def get_cve_info(d, cves):
 """
@@ -241,9 +220,10 @@ def get_cve_info(d, cves):
 for row in cur.execute(query, tuple(cves)):
 cve_data[row[0]] = {}
 cve_data[row[0]]["summary"] = row[1]
-cve_data[row[0]]["score"] = row[2]
-cve_data[row[0]]["modified"] = row[3