Source code for pkgcheck.checks.glsa
import os
from collections import defaultdict
from pkgcore.pkgsets.glsa import GlsaDirSet
from pkgcore.restrictions import packages, values
from pkgcore.restrictions.util import collect_package_restrictions
from snakeoil.cli.arghparse import existent_dir
from snakeoil.osutils import pjoin
from snakeoil.strings import pluralism
from .. import results
from . import GentooRepoCheck, SkipCheck
[docs]
class VulnerablePackage(results.VersionResult, results.Error):
"""Packages marked as vulnerable by GLSAs."""
def __init__(self, arches, glsa, **kwargs):
super().__init__(**kwargs)
self.arches = tuple(arches)
self.glsa = glsa
@property
def desc(self):
s = pluralism(self.arches)
arches = ", ".join(self.arches)
return f"vulnerable via {self.glsa}, keyword{s}: {arches}"
[docs]
class GlsaCheck(GentooRepoCheck):
"""Scan for vulnerable ebuilds in the tree.
Requires a GLSA directory for vulnerability info.
"""
known_results = frozenset([VulnerablePackage])
[docs]
@staticmethod
def mangle_argparser(parser):
parser.plugin.add_argument("--glsa-dir", type=existent_dir, help="custom glsa directory")
def __init__(self, *args):
super().__init__(*args)
glsa_dir = self.options.glsa_dir
if glsa_dir is None:
# search for glsa dir in target repo and then any masters
for repo in reversed(self.options.target_repo.trees):
path = pjoin(repo.location, "metadata", "glsa")
if os.path.isdir(path):
glsa_dir = path
break
else:
raise SkipCheck(self, "no available glsa source")
# this is a bit brittle
self.vulns = defaultdict(list)
for r in GlsaDirSet(glsa_dir):
val = r[1] if len(r) <= 2 else packages.AndRestriction(*r[1:])
self.vulns[r[0].key].append(val)
[docs]
def feed(self, pkg):
for vuln in self.vulns.get(pkg.key, ()):
if vuln.match(pkg):
arches = set()
for v in collect_package_restrictions(vuln, ["keywords"]):
if isinstance(v.restriction, values.ContainmentMatch2):
arches.update(x.lstrip("~") for x in v.restriction.vals)
else:
raise Exception(
f"unexpected restriction sequence- {v.restriction} in {vuln}"
)
keys = {x.lstrip("~") for x in pkg.keywords if not x.startswith("-")}
if arches:
arches = sorted(arches.intersection(keys))
assert arches
else:
arches = sorted(keys)
yield VulnerablePackage(arches, str(vuln), pkg=pkg)