summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/debian-releases.mk9
-rw-r--r--lib/python/sectracker/analyzers.py6
-rw-r--r--lib/python/sectracker/parsers.py92
-rw-r--r--lib/python/sectracker/xpickle.py2
-rw-r--r--lib/python/sectracker_test/test_parsers.py55
-rw-r--r--lib/python/security_db.py94
6 files changed, 180 insertions, 78 deletions
diff --git a/lib/debian-releases.mk b/lib/debian-releases.mk
index eb03a874da..52e238adee 100644
--- a/lib/debian-releases.mk
+++ b/lib/debian-releases.mk
@@ -7,7 +7,7 @@ endef
MAIN_RELEASES = $(call get_config, '.distributions | to_entries[] | select(.value.release) | .key')
SECURITY_RELEASES = $(filter-out sid, $(MAIN_RELEASES))
-BACKPORT_RELEASES = $(SECURITY_RELEASES)
+BACKPORT_RELEASES = $(filter-out buster, $(SECURITY_RELEASES))
# Define the variables for the release on the main mirror
define add_main_release =
@@ -15,6 +15,11 @@ $(1)_MIRROR = $$(MIRROR)
$(1)_DIST = $(1)
$(1)_ARCHS = $(call get_config, '.distributions.$(1).architectures[]')
$(1)_RELEASE = $(1)
+ifneq (,$(filter jessie stretch buster bullseye,$(1)))
+$(1)_SECTIONS = main contrib non-free
+else
+$(1)_SECTIONS = main contrib non-free non-free-firmware
+endif
$(1)_SUBRELEASE =
RELEASES += $(1)
endef
@@ -34,6 +39,7 @@ $(1)_security_DIST = $(1)-security
endif
$(1)_security_ARCHS = $$($(1)_ARCHS)
$(1)_security_RELEASE = $(1)
+$(1)_security_SECTIONS = $$($(1)_SECTIONS)
$(1)_security_SUBRELEASE = security
RELEASES += $(1)_security
endef
@@ -45,6 +51,7 @@ $(1)_backports_MIRROR = $$(MIRROR)
$(1)_backports_DIST = $(1)-backports
$(1)_backports_ARCHS = $$($(1)_ARCHS)
$(1)_backports_RELEASE = $(1)-backports
+$(1)_backports_SECTIONS = $$($(1)_SECTIONS)
$(1)_backports_SUBRELEASE =
RELEASES += $(1)_backports
endef
diff --git a/lib/python/sectracker/analyzers.py b/lib/python/sectracker/analyzers.py
index 386af47974..641227dd1a 100644
--- a/lib/python/sectracker/analyzers.py
+++ b/lib/python/sectracker/analyzers.py
@@ -30,14 +30,14 @@ def mergelists(listfiles, diag):
in diag."""
result = {}
for listfile in listfiles:
- for bug in listfile.list:
+ for bug in listfile:
header = bug.header
name = header.name
if name in result:
diag.error("duplicate bug %r" % name,
- file=header.file, line=header.header.line)
+ file=bug.file, line=header.line)
diag.error("location of previous bug",
- file=result[name].file, line=result[name].line)
+ file=result[name].file, line=result[name].header.line)
continue
result[name] = bug
return result
diff --git a/lib/python/sectracker/parsers.py b/lib/python/sectracker/parsers.py
index 26bf59bf10..6b42d4a417 100644
--- a/lib/python/sectracker/parsers.py
+++ b/lib/python/sectracker/parsers.py
@@ -17,7 +17,11 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+from dataclasses import dataclass
+import typing
+import traceback
import re
+import sys
from sys import intern
import debian_support
@@ -26,7 +30,9 @@ from collections import namedtuple as _namedtuple
import sectracker.xpickle as _xpickle
import sectracker.diagnostics
-FORMAT = "4"
+FORMAT = "5"
+
+_debug_enabled = False
def _sortedtuple(seq):
l = list(seq)
@@ -71,15 +77,41 @@ def sourcepackages(name, f):
data[pkg_name] = SourcePackage(pkg_name, pkg_version, pkg_binary)
return data
-FlagAnnotation = _namedtuple("FlagAnnotation", "line type")
-StringAnnotation = _namedtuple("StringAnnotation",
- "line type description")
-XrefAnnotation = _namedtuple("XrefAnnotation", "line type bugs")
-PackageAnnotation = _namedtuple(
- "PackageAnnotation",
- "line type release package kind version description flags")
-PackageBugAnnotation = _namedtuple("PackageBugAnnotation", "bug")
-PackageUrgencyAnnotation = _namedtuple("PackageUrgencyAnnotation", "severity")
+@dataclass
+class FlagAnnotation:
+ line: int
+ type: str
+
+@dataclass
+class StringAnnotation:
+ line: int
+ type: str
+ description: str
+
+@dataclass
+class XrefAnnotation:
+ line: int
+ type: str
+ bugs: typing.List[str]
+
+@dataclass
+class PackageAnnotation:
+ line: int
+ type: str
+ release: str
+ package: str
+ kind: str
+ version: str
+ description: str
+ flags: list
+
+@dataclass
+class PackageBugAnnotation:
+ bug: int
+
+@dataclass
+class PackageUrgencyAnnotation:
+ severity: str
def _annotationdispatcher():
# Parser for inner annotations, like (bug #1345; low)
@@ -156,7 +188,7 @@ def _annotationdispatcher():
)
elif kind in pseudo_struct:
flags = parseinner(diag, inner)
- if kind == "itp" and not inner[1]:
+ if kind == "itp" and not [flag for flag in flags if isinstance(flag, PackageBugAnnotation)]:
diag.error("<itp> needs Debian bug reference")
return PackageAnnotation(
line=diag.line(),
@@ -169,14 +201,14 @@ def _annotationdispatcher():
flags=flags,
)
else:
- diag.error("invalid pseudo-version: " + repr(version))
+ diag.error("invalid pseudo-version: " + repr(kind))
return None
@_regexpcase.rule(r'\{(.*)\}')
def xref(groups, diag):
- x = tuple(groups[0].strip().split())
+ x = groups[0].strip().split()
if x:
- return XrefAnnotation(diag.line(), "xref", x)
+ return XrefAnnotation(line=diag.line(), type="xref", bugs=list(x))
else:
diag.error("empty cross-reference")
return None
@@ -191,9 +223,17 @@ def _annotationdispatcher():
default=lambda text, diag: diag.error("invalid annotation"))
_annotationdispatcher = _annotationdispatcher()
-List = _namedtuple("List", "list messages")
-Bug = _namedtuple("Bug", "file header annotations")
-Header = _namedtuple("Header", "line name description")
+@dataclass
+class Header:
+ line: int
+ name: str
+ description: str
+
+@dataclass
+class Bug:
+ file: str
+ header: Header
+ annotations: list # TODO: use a list of annotations
def _parselist(path, f, parseheader, finish):
lineno = 0
@@ -248,7 +288,13 @@ def _parselist(path, f, parseheader, finish):
if header is not None:
bugs.append(finish(header, headerlineno, anns, diag))
- return List(tuple(bugs), diag.messages())
+
+ if _debug_enabled:
+ for m in diag.messages():
+ sys.stderr.write(str(m) + "\n")
+ print("%s:%d: %s: %s" % (m.file, m.line, m.level, m.message))
+
+ return bugs
@_xpickle.loader("CVE" + FORMAT)
def cvelist(path, f):
@@ -268,7 +314,7 @@ def cvelist(path, f):
return (name, desc)
def finish(header, headerlineno, anns, diag):
name, desc = header
- return Bug(path, Header(headerlineno, name, desc), tuple(anns))
+ return Bug(path, Header(headerlineno, name, desc), list(anns))
return _parselist(path, f, parseheader, finish)
def writecvelist(data, f):
@@ -348,7 +394,7 @@ def dsalist(path, f):
def finish(header, headerlineno, anns, diag):
d, m, y, name, desc = header
_checkrelease(anns, diag, "DSA")
- return Bug(path, Header(headerlineno, name, None), tuple(anns))
+ return Bug(path, Header(headerlineno, name, None), list(anns))
return _parselist(path, f, parseheader, finish)
@_xpickle.loader("DTSA" + FORMAT)
@@ -365,7 +411,7 @@ def dtsalist(path, f):
def finish(header, headerlineno, anns, diag):
d, m, y, name, desc = header
_checkrelease(anns, diag, "DTSA")
- return Bug(path, Header(headerlineno, name, None), tuple(anns))
+ return Bug(path, Header(headerlineno, name, None), list(anns))
return _parselist(path, f, parseheader, finish)
@_xpickle.loader("DLA" + FORMAT)
@@ -381,7 +427,7 @@ def dlalist(path, f):
def finish(header, headerlineno, anns, diag):
d, m, y, name, desc = header
_checkrelease(anns, diag, "DLA")
- return Bug(path, Header(headerlineno, name, None), tuple(anns))
+ return Bug(path, Header(headerlineno, name, None), list(anns))
return _parselist(path, f, parseheader, finish)
@_xpickle.loader("EXT" + FORMAT)
@@ -397,5 +443,5 @@ def extadvlist(path, f):
def finish(header, headerlineno, anns, diag):
d, m, y, name, desc = header
_checkrelease(anns, diag, "EXT")
- return Bug(path, Header(headerlineno, name, None), tuple(anns))
+ return Bug(path, Header(headerlineno, name, None), list(anns))
return _parselist(path, f, parseheader, finish)
diff --git a/lib/python/sectracker/xpickle.py b/lib/python/sectracker/xpickle.py
index d3324825ce..13fa8bb82e 100644
--- a/lib/python/sectracker/xpickle.py
+++ b/lib/python/sectracker/xpickle.py
@@ -63,7 +63,7 @@ def _wraploader(typ, parser):
try:
with open(path + EXTENSION, "rb") as f:
return (_pickle.load(f), True)
- except (EOFError, IOError, _pickle.PickleError):
+ except (AttributeError, EOFError, IOError, _pickle.PickleError):
return (None, False)
def check(data, st):
diff --git a/lib/python/sectracker_test/test_parsers.py b/lib/python/sectracker_test/test_parsers.py
index 8cdd141a47..4c724ebced 100644
--- a/lib/python/sectracker_test/test_parsers.py
+++ b/lib/python/sectracker_test/test_parsers.py
@@ -25,85 +25,78 @@ assert "bash" in o
assert o["bash"].name == "bash"
assert "bash" in o["bash"].binary
-safeunlink("../../data/CVE/list" + EXTENSION)
-o = cvelist("../../data/CVE/list")
-for err in o.messages:
- print("%s:%d: %s: %s" % (err.file, err.line, err.level, err.message))
+p._debug_enabled = True
safeunlink("../../data/DSA/list" + EXTENSION)
-o = dsalist("../../data/DSA/list")
-for err in o.messages:
- print("%s:%d: %s: %s" % (err.file, err.line, err.level, err.message))
+dsalist("../../data/DSA/list")
safeunlink("../../data/DTSA/list" + EXTENSION)
-o = dtsalist("../../data/DTSA/list")
-for err in o.messages:
- print("%s:%d: %s: %s" % (err.file, err.line, err.level, err.message))
+dtsalist("../../data/DTSA/list")
safeunlink("../../data/DLA/list" + EXTENSION)
-o = dlalist("../../data/DLA/list")
-for err in o.messages:
- print("%s:%d: %s: %s" % (err.file, err.line, err.level, err.message))
+dlalist("../../data/DLA/list")
Message = sectracker.diagnostics.Message
for (line, res, xmsgs) in [
(' - foo <unfixed>',
PackageAnnotation(17, "package", None, "foo", "unfixed", None,
- None, None, (), False), ()),
+ None, []), ()),
(' - foo',
PackageAnnotation(17, "package", None, "foo", "unfixed", None,
- None, None, (), False), ()),
+ None, []), ()),
(' [lenny] - foo <unfixed>',
PackageAnnotation(17, "package", "lenny", "foo", "unfixed", None,
- None, None, (), False), ()),
+ None, []), ()),
(' [lenny] - foo <undetermined> (bug #1234)',
PackageAnnotation(17, "package", "lenny", "foo", "undetermined",
- None, None, None, (1234,), False), ()),
+ None, None, [PackageBugAnnotation(1234)]), ()),
(' [lenny] - foo <itp> (bug #1234)',
PackageAnnotation(17, "package", "lenny", "foo", "itp", None,
- None, None, (1234,), False), ()),
+ None, [PackageBugAnnotation(1234)]), ()),
(' [lenny] - foo <itp>',
PackageAnnotation(17, "package", "lenny", "foo", "itp", None,
- None, None, (), False),
+ None, []),
(Message("CVE", 17, "error",
"<itp> needs Debian bug reference"),)),
(' [lenny] - foo 1.0',
PackageAnnotation(17, "package", "lenny", "foo", "fixed", "1.0" ,
- None, None, (), False), ()),
+ None, []), ()),
(' [lenny] - foo <unfixed> (bug filed)',
PackageAnnotation(17, "package", "lenny", "foo", "unfixed", None,
- None, None, (), True), ()),
+ None, []),
+ (Message("CVE", 17, "error",
+ "invalid inner annotation: 'bug filed'"),)),
(' [lenny] - foo <unfixed> (bug filed; bug #1234)',
PackageAnnotation(17, "package", "lenny", "foo", "unfixed", None,
- None, None, (1234,), False),
+ None, [PackageBugAnnotation(1234)]),
(Message("CVE", 17, "error",
- "'bug filed' and bug numbers listed"),)),
+ "invalid inner annotation: 'bug filed'"),)),
(' [lenny] - foo <unfixed> (low)',
PackageAnnotation(17, "package", "lenny", "foo", "unfixed", None,
- None, "low", (), False), ()),
+ None, [PackageUrgencyAnnotation("low")]), ()),
(' [lenny] - foo <unfixed> (low; low)',
PackageAnnotation(17, "package", "lenny", "foo", "unfixed", None,
- None, "low", (), False),
- (Message("CVE", 17, "error", "duplicate flag: 'low'"),)),
+ None, [PackageUrgencyAnnotation("low")]),
+ (Message("CVE", 17, "error", "duplicate urgency: 'low'"),)),
(' [lenny] - foo <unfixed> (bug #1234; garbled)',
PackageAnnotation(17, "package", "lenny", "foo", "unfixed", None,
- None, None, (1234,), False),
+ None, [PackageBugAnnotation(1234)]),
(Message("CVE", 17, "error",
"invalid inner annotation: 'garbled'"),)),
(' [lenny] - foo <no-dsa> (explanation goes here)',
PackageAnnotation(17, "package", "lenny", "foo", "no-dsa", None,
- "explanation goes here", None, (), False), ()),
+ "explanation goes here", []), ()),
(' [lenny] - foo <end-of-life> (explanation goes here)',
PackageAnnotation(17, "package", "lenny", "foo", "end-of-life",
- None, "explanation goes here", None, (), False),
+ None, "explanation goes here", []),
()),
(' [lenny] - foo <not-affected> (explanation goes here)',
PackageAnnotation(17, "package", "lenny", "foo", "not-affected",
None,
- "explanation goes here", None, (), False), ()),
+ "explanation goes here", []), ()),
('\t{CVE-2009-1234 CVE-2009-1235}',
XrefAnnotation(17, "xref",
- tuple("CVE-2009-1234 CVE-2009-1235".split())),
+ ["CVE-2009-1234", "CVE-2009-1235"]),
()),
('\t{}', None,
(Message("CVE", 17, "error", "empty cross-reference"),)),
diff --git a/lib/python/security_db.py b/lib/python/security_db.py
index c4f163cb7a..d02c803d56 100644
--- a/lib/python/security_db.py
+++ b/lib/python/security_db.py
@@ -420,6 +420,10 @@ class DB:
cursor.execute(
"CREATE TABLE removed_packages (name TEXT NOT NULL PRIMARY KEY)")
+ # This table is used to keep the list of source packages, for which the filing of a bug is not required.
+ cursor.execute(
+ "CREATE TABLE ignored_packages (name TEXT NOT NULL PRIMARY KEY)")
+
cursor.execute(
"""CREATE TABLE nvd_data
(cve_name TEXT NOT NULL PRIMARY KEY,
@@ -908,19 +912,29 @@ class DB:
def clear_db(cleared=[False]):
# Avoid clearing the database multiple times.
if cleared[0]:
+ if self.verbose:
+ print(" finished (already cleared)")
return
else:
+ if self.verbose:
+ print(" clearing database")
cleared[0] = True
- cursor.execute("DELETE FROM debian_bugs")
- cursor.execute("DELETE FROM bugs")
- cursor.execute("DELETE FROM package_notes")
- cursor.execute("DELETE FROM bugs_notes")
- cursor.execute("DELETE FROM bugs_xref")
- cursor.execute("DELETE FROM package_notes_nodsa")
- cursor.execute("DELETE FROM removed_packages")
- cursor.execute("DELETE FROM next_point_update")
+ tables = ['debian_bugs', 'bugs', 'package_notes', 'bugs_notes', 'bugs_xref', 'package_notes_nodsa', 'ignored_packages', 'removed_packages', 'next_point_update']
+ # clean up all tables
+ for table in tables:
+ # check first, whether the table exists
+ try:
+ cursor.execute(f"SELECT * FROM {table} LIMIT 1")
+ except:
+ # table does not exist
+ if self.verbose:
+ print(f"Table {table} does not exist")
+ continue
+ if self.verbose:
+ print (f"Clearing table {table}")
+ cursor.execute(f"DELETE FROM {table}")
# The *_status tables are regenerated anyway, no need to
# delete them here.
@@ -953,21 +967,34 @@ class DB:
"SELECT inodeprint FROM inodeprints WHERE file = ?",
(filename,)):
if old_print == current_print:
+ if self.verbose:
+ print(" unchanged: " + repr(filename))
return False
else:
+ if self.verbose:
+ print(" changed: " + repr(filename))
+ print(f" old: {old_print}, new: {current_print}")
return True
return True
source_removed_packages = '/packages/removed-packages'
+ source_ignored_unreported = '/packages/ignored-debian-bug-packages'
sources = self.getSources()
source_paths = [src["path"] for src in sources]
- unchanged = True
- for filename in source_paths + [source_removed_packages]:
+ changed_source = None
+ for filename in source_paths + [source_removed_packages, source_ignored_unreported]:
if has_changed(path + filename):
- unchanged = False
+ if self.verbose:
+ print(" changed: " + repr(path + filename))
+ print (" clearing database")
+ changed_source = path + filename
break
- if unchanged:
+
+ if changed_source:
+ if self.verbose:
+ print(f" clearing database, because some files have changed (at least {changed_source})")
+ else:
if self.verbose:
print(" finished (no changes)")
return
@@ -975,6 +1002,8 @@ class DB:
clear_db()
def read_one(source):
+ if self.verbose:
+ print(" reading " + repr(source.name))
filename = source.name
current_print = self.filePrint(filename)
@@ -989,9 +1018,16 @@ class DB:
cls = getattr(bugs, cls)
read_one(cls(path + srcpath))
+ # Read list of packages, which were removed from the status/unreported
if self.verbose:
print(" update removed packages")
- self.readRemovedPackages(cursor, path + source_removed_packages)
+ self.readRemovedAndIgnoredPackages(cursor, path + source_removed_packages, table = "removed_packages")
+
+ # Read list of packages, which should be ignored for the status/unreported
+ if self.verbose:
+ print(" update ignored packages")
+ self.readRemovedAndIgnoredPackages(cursor, path + source_ignored_unreported, table = "ignored_packages")
+
errors = []
@@ -1966,9 +2002,15 @@ class DB:
ORDER BY bug""", (bug, bug, bug, bug)):
yield bug_name
- def readRemovedPackages(self, cursor, filename):
- """Reads a file of removed packages and stores it in the database.
- The original contents of the removed_packages table is preserved."""
+ def readRemovedAndIgnoredPackages(self, cursor, filename, table='removed_packages'):
+ """Reads a file of removed or ignored packages and stores it in the database.
+ For that the table parameter must be set to 'removed_packages'.
+ This is the default value.
+ The original contents of the removed_packages table is preserved.
+
+ This function also reads the file of packages, where filing debian bugs is being ignored
+ and stores it in the database.
+ """
f = open(filename)
@@ -1989,8 +2031,21 @@ class DB:
else:
raise ValueError("not a package: " + repr(line))
+ # check, if {table} exists, otherwise create it
+ cursor.execute(
+ f"CREATE TABLE IF NOT EXISTS {table} (name TEXT NOT NULL PRIMARY KEY)")
+
+ # Add packages into the table
cursor.executemany(
- "INSERT OR IGNORE INTO removed_packages (name) VALUES (?)", gen())
+ f"INSERT OR IGNORE INTO {table} (name) VALUES (?)", gen())
+
+
+ # Add file print to database for removed packages
+ current_print = self.filePrint(filename)
+ cursor.execute(
+ """INSERT OR REPLACE INTO inodeprints (inodeprint, file)
+ VALUES (?, ?)""", (current_print, filename))
+
def getUnknownPackages(self, cursor):
"""Returns a generator for a list of unknown packages.
@@ -2030,7 +2085,7 @@ class DB:
st.bug_name > 'TEMP-' AND st.bug_name LIKE 'TEMP-%'
ORDER BY st.bug_name""",(vulnerability,)))
- def getUnreportedVulnerabilities(self, cursor=None):
+ def getUnreportedVulnerabilities(self, cursor=None, show_ignored=False):
"""Returns a list of pairs (BUG_NAME, DESCRIPTION)
of vulnerabilities which are unfixed in unstable and lack a filed bug.
"""
@@ -2039,7 +2094,7 @@ class DB:
last_bug = None
result = []
for bug, pkg in cursor.execute(
-"""SELECT DISTINCT source_package_status.bug_name, source_packages.name
+f"""SELECT DISTINCT source_package_status.bug_name, source_packages.name
FROM source_packages
JOIN source_package_status
ON source_packages.rowid = source_package_status.package
@@ -2052,6 +2107,7 @@ class DB:
AND package_notes.urgency <> 'unimportant'
AND package_notes.rowid NOT IN (SELECT note FROM debian_bugs)
AND source_package_status.vulnerable
+ AND ({show_ignored} OR NOT EXISTS (SELECT * FROM ignored_packages WHERE ignored_packages.name = source_packages.name))
ORDER BY source_package_status.bug_name, source_packages.name"""):
if last_bug is None or last_bug != bug:
last_bug = bug

© 2014-2024 Faster IT GmbH | imprint | privacy policy