Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 26 May 2026 12:02:08 +0000
From:      Michael Gmelin <grembo@FreeBSD.org>
To:        ports-committers@FreeBSD.org, dev-commits-ports-all@FreeBSD.org, dev-commits-ports-main@FreeBSD.org
Subject:   git: bcfad8754e68 - main - security/vuxml: Add PORTEPOCH validation
Message-ID:  <6a158bc0.413c3.2ae5e926@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by grembo:

URL: https://cgit.FreeBSD.org/ports/commit/?id=bcfad8754e683583ad46269fe30a7f2d228b8714

commit bcfad8754e683583ad46269fe30a7f2d228b8714
Author:     Michael Gmelin <grembo@FreeBSD.org>
AuthorDate: 2026-05-26 12:01:00 +0000
Commit:     Michael Gmelin <grembo@FreeBSD.org>
CommitDate: 2026-05-26 12:01:47 +0000

    security/vuxml: Add PORTEPOCH validation
    
    This adds a check if portepoch has been forgotten
    in affected version range specifications, which leads
    to pkg audit not reporting a vulnerability.
    
    Usage:
    
        make check-portepoch
    
    This is also invoked when running `make validate`.
    
    Approved by:    fernape (ports-secteam)
    Differential Revision:  https://reviews.freebsd.org/D57193
---
 security/vuxml/Makefile                      |  5 +-
 security/vuxml/files/check_vuln_portepoch.py | 94 ++++++++++++++++++++++++++++
 2 files changed, 98 insertions(+), 1 deletion(-)

diff --git a/security/vuxml/Makefile b/security/vuxml/Makefile
index 243b5cd5723e..0f00f3364b0b 100644
--- a/security/vuxml/Makefile
+++ b/security/vuxml/Makefile
@@ -61,7 +61,7 @@ do-test:
 ${VUXML_FLAT_NAME}: ${VUXML_FILE} vuln/*.xml
 	xmllint -noent ${.ALLSRC:[1]} > ${.TARGET}
 
-validate: tidy
+validate: tidy check-portepoch
 	@${SH} ${FILESDIR}/validate.sh "${VUXML_FLAT_FILE}"
 	@${ECHO_MSG} Checking if tidy differs...
 	@if ${DIFF} -u "${VUXML_FLAT_FILE}" "${VUXML_FILE}.tidy"; \
@@ -96,6 +96,9 @@ tidy: ${VUXML_FLAT_NAME}
 	fi
 	${SH} ${FILESDIR}/tidy.sh "${FILESDIR}/tidy.xsl" "${VUXML_FLAT_FILE}" > "${VUXML_FILE}.tidy"
 
+check-portepoch:
+	${PYTHON_CMD} ${FILESDIR}/check_vuln_portepoch.py ${VUXML_CURRENT_FILE}
+
 newentry:
 	@${ECHO_CMD}
 	@${ECHO_CMD} 'Be sure to get versioning right for PORTEPOCH and remember possible linux-* ports!'
diff --git a/security/vuxml/files/check_vuln_portepoch.py b/security/vuxml/files/check_vuln_portepoch.py
new file mode 100755
index 000000000000..2f9884a7de74
--- /dev/null
+++ b/security/vuxml/files/check_vuln_portepoch.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python3
+
+import argparse
+import csv
+import os
+import subprocess
+import sys
+import time
+from xml.dom.minidom import parseString
+
+
+def check_pkg(vid, node, allpackages):
+    name = str(node.getElementsByTagName('name')[0].firstChild.data)
+    knownversion = allpackages.get(name, None)
+    range = node.getElementsByTagName('range')[0]
+    for r in range.childNodes:
+        if r.nodeType == r.TEXT_NODE:
+            continue
+        if r.tagName not in ['eq', 'le', 'lt', 'ge', 'gt']:
+            raise Exception('Unknown range type ' + r.tagName)
+        version = r.firstChild.data
+        if knownversion and ',' in knownversion and ',' not in version:
+            print(vid + ' (' + name + ') might have a portepoch issue')
+
+
+def read_index(path_to_index, max_age_secs, create_locally):
+    if path_to_index is None:
+        os_version = subprocess.check_output(['freebsd-version']).decode()
+        os_major_version = os_version.split('.', 2)[0]
+        index_file = "INDEX-" + os_major_version
+        portsdir = os.getenv('PORTSDIR')
+        if portsdir is None:
+            portsdir = subprocess.check_output(
+              ['make', '-V', 'PORTSDIR']).decode().strip()
+        path_to_index = portsdir + "/" + index_file
+        fetch_index = True
+        if os.path.isfile(path_to_index):
+            stat = os.stat(path_to_index)
+            if time.time() - stat.st_ctime < max_age_secs and (
+              stat.st_size > 1024 * 1024 * 4):  # 4mb
+                fetch_index = False
+        if fetch_index:
+            cwd = os.getcwd()
+            os.chdir(portsdir)
+            if create_locally:
+                subprocess.check_output(["make", "index"])
+            else:
+                subprocess.check_output(["make", "fetchindex"])
+            os.chdir(cwd)
+
+    ret = {}
+    with open(path_to_index) as f:
+        reader = csv.reader(f, delimiter='|')
+        for row in reader:
+            (name, ver) = row[0].rsplit('-', 1)
+            ret[name] = ver
+    return ret
+
+
+def main():
+    parser = argparse.ArgumentParser(
+      prog=sys.argv[0],
+      description='Check vuxml vuln file PORTEPOCH',
+      epilog='Example: ' + sys.argv[0] + ' vuln/2026.xml')
+    parser.add_argument(
+      '-i', metavar='path_to_index',
+      help='path to index file, disables automatic detection/updating.')
+    parser.add_argument(
+      '-l', action=argparse.BooleanOptionalAction,
+      help='make index locally instead of fetching from cluster')
+    parser.add_argument(
+      '-m', metavar='index_max_age', default=3600, type=float,
+      help='maximum age of index file before re-fetching (seconds)')
+    parser.add_argument(
+      'vuln_file',
+      help='path to yearly vuln file to check, e.g., vuln/2026.xml')
+    args = parser.parse_args(sys.argv[1:])
+
+    with open(args.vuln_file) as f:
+        doc = parseString(
+          '<vuxml xmlns="http://www.vuxml.org/apps/vuxml-1">' +
+          f.read()
+          + "\n</vuxml>")
+    allpackages = read_index(args.i, args.m, args.l)
+    vulns = doc.getElementsByTagName('vuln')
+    for vuln in vulns:
+        vid = vuln.getAttribute('vid')
+        packages = vuln.getElementsByTagName('package')
+        for package in packages:
+            check_pkg(vid, package, allpackages)
+
+
+if __name__ == '__main__':
+    main()


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a158bc0.413c3.2ae5e926>