| Message ID | 20251103143157.315178-5-niko.mauno@vaisala.com |
|---|---|
| State | New |
| Headers | show |
| Series | [1/5] cve-update-nvd2-native: pycodestyle fixes | expand |
Thanks for this contribution, it was on my TODO list for too much time. I have also one small comment inline below. Peter > -----Original Message----- > From: Niko Mauno <niko.mauno@vaisala.com> > Sent: Monday, November 3, 2025 15:32 > To: openembedded-core@lists.openembedded.org > Cc: ross.burton@arm.com; rybczynska@gmail.com; Marko, Peter (FT D EU SK > BFS1) <Peter.Marko@siemens.com>; Niko Mauno <niko.mauno@vaisala.com> > Subject: [PATCH 5/5] cve-update: Keep mtime stamp in the database itself > > This should help to avoid problems that will occur if the modification > time of database file itself is altered e.g. by unassociated > process(es) on the file system which hosts the database file. > > Since this change updates the database structure by adding a new table, > bump the 'minor' version number in database file names to enforce full > database fetch. This should also iron out e.g. situation where the > database might have inconspicuously omitted entries due to way in which > the mtime of database file itself was relied upon. > > Signed-off-by: Niko Mauno <niko.mauno@vaisala.com> > --- > meta/classes/cve-check.bbclass | 2 +- > .../recipes-core/meta/cve-update-db-native.bb | 3 + > meta/recipes-core/meta/cve-update-native.inc | 59 ++++++++++++------- > .../meta/cve-update-nvd2-native.bb | 3 + > 4 files changed, 46 insertions(+), 21 deletions(-) > > diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass > index 259c699af2..7252c4ecdc 100644 > --- a/meta/classes/cve-check.bbclass > +++ b/meta/classes/cve-check.bbclass > @@ -35,7 +35,7 @@ CVE_VERSION ??= "${PV}" > NVD_DB_VERSION ?= "FKIE" > > # Use different file names for each database source, as they synchronize at > different moments, so may be slightly different > -CVE_CHECK_DB_FILENAME ?= "${@'nvdcve_2-2.db' if > d.getVar('NVD_DB_VERSION') == 'NVD2' else 'nvdfkie_1-1.db'}" > +CVE_CHECK_DB_FILENAME ?= "${@'nvdcve_2-3.db' if > d.getVar('NVD_DB_VERSION') == 'NVD2' else 'nvdfkie_1-2.db'}" > CVE_CHECK_DB_FETCHER ?= "${@'cve-update-nvd2-native' if > d.getVar('NVD_DB_VERSION') == 'NVD2' else 'cve-update-db-native'}" > CVE_CHECK_DB_DIR ?= "${STAGING_DIR}/CVE_CHECK" > CVE_CHECK_DB_FILE ?= > "${CVE_CHECK_DB_DIR}/${CVE_CHECK_DB_FILENAME}" > diff --git a/meta/recipes-core/meta/cve-update-db-native.bb b/meta/recipes- > core/meta/cve-update-db-native.bb > index ca83c80958..c1db67ce55 100644 > --- a/meta/recipes-core/meta/cve-update-db-native.bb > +++ b/meta/recipes-core/meta/cve-update-db-native.bb > @@ -18,6 +18,7 @@ def update_db_file(db_tmp_file, d, *_): > """ > import bb.progress > import bb.utils > + import datetime > from datetime import date > import lzma > import sqlite3 > @@ -31,6 +32,7 @@ def update_db_file(db_tmp_file, d, *_): > initialize_db(conn) > > with bb.progress.ProgressHandler(d) as ph, > open(os.path.join(d.getVar("TMPDIR"), 'cve_check'), 'a') as cve_f: > + pre_update_utc_timestamp = > datetime.datetime.now().astimezone(tz=datetime.timezone.utc) > total_years = date.today().year + 1 - YEAR_START > for i, year in enumerate(range(YEAR_START, date.today().year + 1)): > bb.note("Updating %d" % year) > @@ -82,6 +84,7 @@ def update_db_file(db_tmp_file, d, *_): > bb.debug(2, "Already up to date (last modified %s)" % last_modified) > # Update success, set the date to cve_check file. > if year == date.today().year: > + conn.execute("insert into MTIME values (?)", > [pre_update_utc_timestamp.isoformat()]).close() > cve_f.write('CVE database update : %s\n\n' % date.today()) > > conn.commit() > diff --git a/meta/recipes-core/meta/cve-update-native.inc b/meta/recipes- > core/meta/cve-update-native.inc > index 298c89b498..2934f7ad07 100644 > --- a/meta/recipes-core/meta/cve-update-native.inc > +++ b/meta/recipes-core/meta/cve-update-native.inc > @@ -33,6 +33,7 @@ python do_fetch() { > import bb.utils > import bb.progress > import shutil > + import time > > bb.utils.export_proxies(d) > > @@ -46,26 +47,24 @@ python do_fetch() { > > # The NVD database changes once a day, so no need to update more > frequently > # Allow the user to force-update > - try: > - import time > - update_interval = int(d.getVar("CVE_DB_UPDATE_INTERVAL")) > - if update_interval < 0: > - bb.note("CVE database update skipped") > - if not os.path.exists(db_file): > - bb.error("CVE database %s not present, database fetch/update > skipped" % db_file) > - return > - curr_time = time.time() > - database_time = os.path.getmtime(db_file) > - bb.note("Current time: %s; DB time: %s" % (time.ctime(curr_time), > time.ctime(database_time))) > - if curr_time < database_time: > - bb.warn("Database time is in the future, force DB update") > - database_time = 0 > - elif curr_time - database_time < update_interval: > - bb.note("CVE database recently updated, skipping") > - return > - > - except OSError: > - pass > + update_interval = int(d.getVar("CVE_DB_UPDATE_INTERVAL")) > + if update_interval < 0: > + bb.note("CVE database update skipped") > + if not os.path.exists(db_file): > + bb.error("CVE database %s not present, database fetch/update skipped" > % db_file) > + return > + > + if os.path.exists(db_file): > + database_time = get_mtime_timestamp_from(db_file) > + if database_time > 0: How can we hit the database_time being <= 0? Did you plan some try/catch in function get_mtime_timestamp_from? > + curr_time = time.time() > + bb.note("Current time: %s; DB time: %s" % (time.ctime(curr_time), > time.ctime(database_time))) > + if curr_time < database_time: > + bb.warn("Database time is in the future, force DB update") > + database_time = 0 > + elif curr_time - database_time < update_interval: > + bb.note("CVE database recently updated, skipping") > + return > > if bb.utils.to_boolean(d.getVar("BB_NO_NETWORK")): > bb.error("BB_NO_NETWORK attempted to disable fetch, this recipe uses > CVE_DB_UPDATE_INTERVAL to control download, set to '-1' to disable fetch or > update") > @@ -107,10 +106,30 @@ def cleanup_db_download(db_tmp_file): > os.remove(db_tmp_file) > > > +def get_mtime_timestamp_from(db_file): > + """ > + Resolve the time when the CVE database was previously updated > + """ > + import datetime > + import sqlite3 > + > + conn = sqlite3.connect(db_file) > + curs = conn.cursor() > + res = curs.execute("select TIMESTAMP from MTIME order by TIMESTAMP > desc limit 1;") > + latest = res.fetchone()[0] > + latest = datetime.datetime.strptime(latest, '%Y-%m- > %dT%H:%M:%S.%f+00:00') > + latest = latest.astimezone(tz=datetime.timezone.utc) > + curs.close() > + conn.close() > + return latest.timestamp() > + > + > def initialize_db(conn): > with conn: > c = conn.cursor() > > + c.execute("CREATE TABLE IF NOT EXISTS MTIME (TIMESTAMP INT)") > + > 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, \ > diff --git a/meta/recipes-core/meta/cve-update-nvd2-native.bb b/meta/recipes- > core/meta/cve-update-nvd2-native.bb > index 01d3e8e754..77d7408b16 100644 > --- a/meta/recipes-core/meta/cve-update-nvd2-native.bb > +++ b/meta/recipes-core/meta/cve-update-nvd2-native.bb > @@ -72,6 +72,8 @@ def update_db_file(db_tmp_file, d, database_time): > import sqlite3 > import json > > + pre_update_utc_timestamp = > datetime.datetime.now().astimezone(tz=datetime.timezone.utc) > + > # Connect to database > conn = sqlite3.connect(db_tmp_file) > initialize_db(conn) > @@ -141,6 +143,7 @@ def update_db_file(db_tmp_file, d, database_time): > > # Update success, set the date to cve_check file. > cve_f.write('CVE database update : %s\n\n' % datetime.date.today()) > + conn.execute("insert into MTIME values (?)", > [pre_update_utc_timestamp.isoformat()]).close() > > conn.commit() > conn.close() > -- > 2.47.3
diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass index 259c699af2..7252c4ecdc 100644 --- a/meta/classes/cve-check.bbclass +++ b/meta/classes/cve-check.bbclass @@ -35,7 +35,7 @@ CVE_VERSION ??= "${PV}" NVD_DB_VERSION ?= "FKIE" # Use different file names for each database source, as they synchronize at different moments, so may be slightly different -CVE_CHECK_DB_FILENAME ?= "${@'nvdcve_2-2.db' if d.getVar('NVD_DB_VERSION') == 'NVD2' else 'nvdfkie_1-1.db'}" +CVE_CHECK_DB_FILENAME ?= "${@'nvdcve_2-3.db' if d.getVar('NVD_DB_VERSION') == 'NVD2' else 'nvdfkie_1-2.db'}" CVE_CHECK_DB_FETCHER ?= "${@'cve-update-nvd2-native' if d.getVar('NVD_DB_VERSION') == 'NVD2' else 'cve-update-db-native'}" CVE_CHECK_DB_DIR ?= "${STAGING_DIR}/CVE_CHECK" CVE_CHECK_DB_FILE ?= "${CVE_CHECK_DB_DIR}/${CVE_CHECK_DB_FILENAME}" diff --git a/meta/recipes-core/meta/cve-update-db-native.bb b/meta/recipes-core/meta/cve-update-db-native.bb index ca83c80958..c1db67ce55 100644 --- a/meta/recipes-core/meta/cve-update-db-native.bb +++ b/meta/recipes-core/meta/cve-update-db-native.bb @@ -18,6 +18,7 @@ def update_db_file(db_tmp_file, d, *_): """ import bb.progress import bb.utils + import datetime from datetime import date import lzma import sqlite3 @@ -31,6 +32,7 @@ def update_db_file(db_tmp_file, d, *_): initialize_db(conn) with bb.progress.ProgressHandler(d) as ph, open(os.path.join(d.getVar("TMPDIR"), 'cve_check'), 'a') as cve_f: + pre_update_utc_timestamp = datetime.datetime.now().astimezone(tz=datetime.timezone.utc) total_years = date.today().year + 1 - YEAR_START for i, year in enumerate(range(YEAR_START, date.today().year + 1)): bb.note("Updating %d" % year) @@ -82,6 +84,7 @@ def update_db_file(db_tmp_file, d, *_): bb.debug(2, "Already up to date (last modified %s)" % last_modified) # Update success, set the date to cve_check file. if year == date.today().year: + conn.execute("insert into MTIME values (?)", [pre_update_utc_timestamp.isoformat()]).close() cve_f.write('CVE database update : %s\n\n' % date.today()) conn.commit() diff --git a/meta/recipes-core/meta/cve-update-native.inc b/meta/recipes-core/meta/cve-update-native.inc index 298c89b498..2934f7ad07 100644 --- a/meta/recipes-core/meta/cve-update-native.inc +++ b/meta/recipes-core/meta/cve-update-native.inc @@ -33,6 +33,7 @@ python do_fetch() { import bb.utils import bb.progress import shutil + import time bb.utils.export_proxies(d) @@ -46,26 +47,24 @@ python do_fetch() { # The NVD database changes once a day, so no need to update more frequently # Allow the user to force-update - try: - import time - update_interval = int(d.getVar("CVE_DB_UPDATE_INTERVAL")) - if update_interval < 0: - bb.note("CVE database update skipped") - if not os.path.exists(db_file): - bb.error("CVE database %s not present, database fetch/update skipped" % db_file) - return - curr_time = time.time() - database_time = os.path.getmtime(db_file) - bb.note("Current time: %s; DB time: %s" % (time.ctime(curr_time), time.ctime(database_time))) - if curr_time < database_time: - bb.warn("Database time is in the future, force DB update") - database_time = 0 - elif curr_time - database_time < update_interval: - bb.note("CVE database recently updated, skipping") - return - - except OSError: - pass + update_interval = int(d.getVar("CVE_DB_UPDATE_INTERVAL")) + if update_interval < 0: + bb.note("CVE database update skipped") + if not os.path.exists(db_file): + bb.error("CVE database %s not present, database fetch/update skipped" % db_file) + return + + if os.path.exists(db_file): + database_time = get_mtime_timestamp_from(db_file) + if database_time > 0: + curr_time = time.time() + bb.note("Current time: %s; DB time: %s" % (time.ctime(curr_time), time.ctime(database_time))) + if curr_time < database_time: + bb.warn("Database time is in the future, force DB update") + database_time = 0 + elif curr_time - database_time < update_interval: + bb.note("CVE database recently updated, skipping") + return if bb.utils.to_boolean(d.getVar("BB_NO_NETWORK")): bb.error("BB_NO_NETWORK attempted to disable fetch, this recipe uses CVE_DB_UPDATE_INTERVAL to control download, set to '-1' to disable fetch or update") @@ -107,10 +106,30 @@ def cleanup_db_download(db_tmp_file): os.remove(db_tmp_file) +def get_mtime_timestamp_from(db_file): + """ + Resolve the time when the CVE database was previously updated + """ + import datetime + import sqlite3 + + conn = sqlite3.connect(db_file) + curs = conn.cursor() + res = curs.execute("select TIMESTAMP from MTIME order by TIMESTAMP desc limit 1;") + latest = res.fetchone()[0] + latest = datetime.datetime.strptime(latest, '%Y-%m-%dT%H:%M:%S.%f+00:00') + latest = latest.astimezone(tz=datetime.timezone.utc) + curs.close() + conn.close() + return latest.timestamp() + + def initialize_db(conn): with conn: c = conn.cursor() + c.execute("CREATE TABLE IF NOT EXISTS MTIME (TIMESTAMP INT)") + 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, \ diff --git a/meta/recipes-core/meta/cve-update-nvd2-native.bb b/meta/recipes-core/meta/cve-update-nvd2-native.bb index 01d3e8e754..77d7408b16 100644 --- a/meta/recipes-core/meta/cve-update-nvd2-native.bb +++ b/meta/recipes-core/meta/cve-update-nvd2-native.bb @@ -72,6 +72,8 @@ def update_db_file(db_tmp_file, d, database_time): import sqlite3 import json + pre_update_utc_timestamp = datetime.datetime.now().astimezone(tz=datetime.timezone.utc) + # Connect to database conn = sqlite3.connect(db_tmp_file) initialize_db(conn) @@ -141,6 +143,7 @@ def update_db_file(db_tmp_file, d, database_time): # Update success, set the date to cve_check file. cve_f.write('CVE database update : %s\n\n' % datetime.date.today()) + conn.execute("insert into MTIME values (?)", [pre_update_utc_timestamp.isoformat()]).close() conn.commit() conn.close()
This should help to avoid problems that will occur if the modification time of database file itself is altered e.g. by unassociated process(es) on the file system which hosts the database file. Since this change updates the database structure by adding a new table, bump the 'minor' version number in database file names to enforce full database fetch. This should also iron out e.g. situation where the database might have inconspicuously omitted entries due to way in which the mtime of database file itself was relied upon. Signed-off-by: Niko Mauno <niko.mauno@vaisala.com> --- meta/classes/cve-check.bbclass | 2 +- .../recipes-core/meta/cve-update-db-native.bb | 3 + meta/recipes-core/meta/cve-update-native.inc | 59 ++++++++++++------- .../meta/cve-update-nvd2-native.bb | 3 + 4 files changed, 46 insertions(+), 21 deletions(-)