feat: mysqld, ndbd, ndbmtd and ndb_mgmd classifier (#4907)

Signed-off-by: witchcraze <witchcraze@gmail.com>
This commit is contained in:
witchcraze 2026-05-15 00:29:42 +09:00 committed by GitHub
parent 4579d11abc
commit e2e5e223ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 338 additions and 22 deletions

View File

@ -490,11 +490,15 @@ func (e *EnrichmentData) EnrichWithBinaryClassifier(catalogerName string, entry
} }
for _, o := range binaryClassifierOverrides[classifier.Class] { for _, o := range binaryClassifierOverrides[classifier.Class] {
cpeStrings := make([]string, len(o.CPEs))
for i, c := range o.CPEs {
cpeStrings[i] = c.Attributes.BindToFmtString()
}
packages = append(packages, capabilities.DetectorPackageInfo{ packages = append(packages, capabilities.DetectorPackageInfo{
Class: o.Class, Class: o.Class,
Name: o.Package, Name: o.Package,
PURL: stripPURLVersion(o.PURL), PURL: stripPURLVersion(o.PURL),
CPEs: o.CPEs, CPEs: cpeStrings,
Type: "BinaryPkg", Type: "BinaryPkg",
}) })
} }

View File

@ -10,7 +10,7 @@ type binaryClassifierOverride struct {
Class string Class string
Package string Package string
PURL string PURL string
CPEs []string CPEs []cpe.CPE
} }
var binaryClassifierOverrides = map[string][]binaryClassifierOverride{ var binaryClassifierOverrides = map[string][]binaryClassifierOverride{
@ -110,12 +110,47 @@ var binaryClassifierOverrides = map[string][]binaryClassifierOverride{
CPEs: singleCPE("cpe:2.3:a:openssl:openssl:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), CPEs: singleCPE("cpe:2.3:a:openssl:openssl:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
}, },
}, },
"mysqld-binary": {
{
Class: "mysqld-mysql-cluster-legacy-binary",
Package: "mysql-cluster",
PURL: mustPURL("pkg:generic/mysql-cluster@version"),
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:a:oracle:mysql_cluster:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
},
{
Class: "mysqld-mysql-cluster-binary",
Package: "mysql-cluster",
PURL: mustPURL("pkg:generic/mysql-cluster@version"),
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:a:oracle:mysql:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
cpe.Must("cpe:2.3:a:oracle:mysql_server:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
cpe.Must("cpe:2.3:a:oracle:mysql_cluster:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
},
{
Class: "mysqld-mysql-server-binary",
Package: "mysql-server",
PURL: mustPURL("pkg:generic/mysql-server@version"),
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:a:oracle:mysql:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
cpe.Must("cpe:2.3:a:oracle:mysql_server:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
},
},
} }
func mustPURL(purl string) string { func mustPURL(purl string) string {
return purl return purl
} }
func singleCPE(cpeString string, _ ...any) []string { func singleCPE(cpeString string, source ...cpe.Source) []cpe.CPE {
return []string{cpeString} src := cpe.GeneratedSource
if len(source) > 0 {
src = source[0]
}
return []cpe.CPE{
cpe.Must(cpeString, src),
}
} }

View File

@ -242,6 +242,77 @@ catalogers:
- cpe:2.3:a:percona:percona_server:*:*:*:*:*:*:*:* - cpe:2.3:a:percona:percona_server:*:*:*:*:*:*:*:*
- cpe:2.3:a:percona:xtradb_cluster:*:*:*:*:*:*:*:* - cpe:2.3:a:percona:xtradb_cluster:*:*:*:*:*:*:*:*
type: BinaryPkg type: BinaryPkg
- method: glob
criteria:
- '**/mysqld'
packages:
- class: mysqld-mysql-cluster-legacy-binary
name: mysql-server
purl: pkg:generic/mysql-server
cpes:
- cpe:2.3:a:oracle:mysql:*:*:*:*:*:*:*:*
- cpe:2.3:a:oracle:mysql_server:*:*:*:*:*:*:*:*
type: BinaryPkg
- method: glob
criteria:
- '**/mysqld'
packages:
- class: mysqld-binary
name: ""
purl: pkg:/
cpes: []
type: BinaryPkg
- class: mysqld-mysql-cluster-legacy-binary
name: mysql-cluster
purl: pkg:generic/mysql-cluster
cpes:
- cpe:2.3:a:oracle:mysql_cluster:*:*:*:*:*:*:*:*
type: BinaryPkg
- class: mysqld-mysql-cluster-binary
name: mysql-cluster
purl: pkg:generic/mysql-cluster
cpes:
- cpe:2.3:a:oracle:mysql:*:*:*:*:*:*:*:*
- cpe:2.3:a:oracle:mysql_server:*:*:*:*:*:*:*:*
- cpe:2.3:a:oracle:mysql_cluster:*:*:*:*:*:*:*:*
type: BinaryPkg
- class: mysqld-mysql-server-binary
name: mysql-server
purl: pkg:generic/mysql-server
cpes:
- cpe:2.3:a:oracle:mysql:*:*:*:*:*:*:*:*
- cpe:2.3:a:oracle:mysql_server:*:*:*:*:*:*:*:*
type: BinaryPkg
- method: glob
criteria:
- '**/ndbd'
packages:
- class: ndbd-binary
name: mysql-cluster
purl: pkg:generic/mysql-cluster
cpes:
- cpe:2.3:a:oracle:mysql_cluster:*:*:*:*:*:*:*:*
type: BinaryPkg
- method: glob
criteria:
- '**/ndbmtd'
packages:
- class: ndbmtd-binary
name: mysql-cluster
purl: pkg:generic/mysql-cluster
cpes:
- cpe:2.3:a:oracle:mysql_cluster:*:*:*:*:*:*:*:*
type: BinaryPkg
- method: glob
criteria:
- '**/ndb_mgmd'
packages:
- class: ndb_mgmd-binary
name: mysql-cluster
purl: pkg:generic/mysql-cluster
cpes:
- cpe:2.3:a:oracle:mysql_cluster:*:*:*:*:*:*:*:*
type: BinaryPkg
- method: glob - method: glob
criteria: criteria:
- '**/xtrabackup' - '**/xtrabackup'

View File

@ -38,6 +38,7 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
// full binaries are tested (no snippets), and if no binary is found the test will be skipped. // full binaries are tested (no snippets), and if no binary is found the test will be skipped.
logicalFixture string logicalFixture string
expected pkg.Package expected pkg.Package
expectedPackages []pkg.Package
}{ }{
{ {
logicalFixture: "arangodb/3.11.8/linux-amd64", logicalFixture: "arangodb/3.11.8/linux-amd64",
@ -206,6 +207,82 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
Metadata: metadata("mariadb-binary"), Metadata: metadata("mariadb-binary"),
}, },
}, },
{
logicalFixture: "mysqld/9.7.0/linux-amd64",
expected: pkg.Package{
Name: "mysql-server",
Version: "9.7.0",
Type: "binary",
PURL: "pkg:generic/mysql-server@9.7.0",
Locations: locations("mysqld"),
Metadata: metadata("mysqld-mysql-server-binary"),
},
},
{
logicalFixture: "mysql-cluster/9.7.0/linux-amd64",
expected: pkg.Package{
Name: "mysql-cluster",
Version: "9.7.0",
Type: "binary",
PURL: "pkg:generic/mysql-cluster@9.7.0",
Locations: locations("mysqld"),
Metadata: metadata("mysqld-mysql-cluster-binary"),
},
},
{
logicalFixture: "mysql-cluster/7.6.17/linux-amd64",
expectedPackages: []pkg.Package{
{
Name: "mysql-server",
Version: "5.7.33",
Type: "binary",
PURL: "pkg:generic/mysql-server@5.7.33",
Locations: locations("mysqld"),
Metadata: metadata("mysqld-mysql-cluster-legacy-binary"),
},
{
Name: "mysql-cluster",
Version: "7.6.17",
Type: "binary",
PURL: "pkg:generic/mysql-cluster@7.6.17",
Locations: locations("mysqld"),
Metadata: metadata("mysqld-mysql-cluster-legacy-binary"),
},
},
},
{
logicalFixture: "ndbd/9.7.0/linux-amd64",
expected: pkg.Package{
Name: "mysql-cluster",
Version: "9.7.0",
Type: "binary",
PURL: "pkg:generic/mysql-cluster@9.7.0",
Locations: locations("ndbd"),
Metadata: metadata("ndbd-binary"),
},
},
{
logicalFixture: "ndbmtd/9.7.0/linux-amd64",
expected: pkg.Package{
Name: "mysql-cluster",
Version: "9.7.0",
Type: "binary",
PURL: "pkg:generic/mysql-cluster@9.7.0",
Locations: locations("ndbmtd"),
Metadata: metadata("ndbmtd-binary"),
},
},
{
logicalFixture: "ndb_mgmd/9.7.0/linux-amd64",
expected: pkg.Package{
Name: "mysql-cluster",
Version: "9.7.0",
Type: "binary",
PURL: "pkg:generic/mysql-cluster@9.7.0",
Locations: locations("ndb_mgmd"),
Metadata: metadata("ndb_mgmd-binary"),
},
},
{ {
logicalFixture: "mongodb/8.0.17/linux-amd64", logicalFixture: "mongodb/8.0.17/linux-amd64",
expected: pkg.Package{ expected: pkg.Package{
@ -2377,9 +2454,16 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
packages, _, err := c.Catalog(context.Background(), resolver) packages, _, err := c.Catalog(context.Background(), resolver)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, packages, 1, "mismatched package count") expected := test.expectedPackages
if len(expected) == 0 {
expected = []pkg.Package{test.expected}
}
assertPackagesAreEqual(t, test.expected, packages[0]) require.Len(t, packages, len(expected), "mismatched package count")
for i := range expected {
assertPackagesAreEqual(t, expected[i], packages[i])
}
}) })
} }
} }

View File

@ -294,6 +294,96 @@ func DefaultClassifiers() []binutils.Classifier {
cpe.Must("cpe:2.3:a:percona:xtradb_cluster:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), cpe.Must("cpe:2.3:a:percona:xtradb_cluster:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
}, },
}, },
{
// Legacy MySQL Cluster contains both MySQL Server and MySQL Cluster versions (Example: 5.7.33-ndb-7.5.21)
// This classifier identifies the MySQL Server version of the mysqld binary (5.7.33 in the example above).
Class: "mysqld-mysql-cluster-legacy-binary",
FileGlob: "**/mysqld",
EvidenceMatcher: m.FileContentsVersionMatcher(
`cluster-gpl\x00(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?)\-ndb\-[0-9]+(\.[0-9]+)?(\.[0-9]+)?`),
Package: "mysql-server",
PURL: mustPURL("pkg:generic/mysql-server@version"),
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:a:oracle:mysql:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
cpe.Must("cpe:2.3:a:oracle:mysql_server:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
},
{
Class: "mysqld-binary",
FileGlob: "**/mysqld",
EvidenceMatcher: binutils.BranchingEvidenceMatcher([]binutils.Classifier{
{
// Legacy MySQL Cluster contains both MySQL Server and MySQL Cluster versions (Example: 5.7.33-ndb-7.5.21)
// This classifier identifies the MySQL Cluster version of the mysqld binary (7.5.21 in the example above).
Class: "mysqld-mysql-cluster-legacy-binary",
EvidenceMatcher: m.FileContentsVersionMatcher(
`cluster-gpl\x00[0-9]+(\.[0-9]+)?(\.[0-9]+)?\-ndb\-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?)`),
Package: "mysql-cluster",
PURL: mustPURL("pkg:generic/mysql-cluster@version"),
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:a:oracle:mysql_cluster:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
},
{
// mysqld from MySQL Cluster after versioning was aligned with MySQL Server
Class: "mysqld-mysql-cluster-binary",
EvidenceMatcher: m.FileContentsVersionMatcher(
`/mysql-cluster-gpl-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)/`),
Package: "mysql-cluster",
PURL: mustPURL("pkg:generic/mysql-cluster@version"),
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:a:oracle:mysql:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
cpe.Must("cpe:2.3:a:oracle:mysql_server:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
cpe.Must("cpe:2.3:a:oracle:mysql_cluster:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
},
{
// mysqld from MySQL Server
Class: "mysqld-mysql-server-binary",
EvidenceMatcher: m.FileContentsVersionMatcher(
`/mysql-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)/`),
Package: "mysql-server",
PURL: mustPURL("pkg:generic/mysql-server@version"),
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:a:oracle:mysql:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
cpe.Must("cpe:2.3:a:oracle:mysql_server:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
},
}...),
},
{
Class: "ndbd-binary",
FileGlob: "**/ndbd",
EvidenceMatcher: m.FileContentsVersionMatcher(
`/mysql-cluster-gpl-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)/`),
Package: "mysql-cluster",
PURL: mustPURL("pkg:generic/mysql-cluster@version"),
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:a:oracle:mysql_cluster:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
},
{
Class: "ndbmtd-binary",
FileGlob: "**/ndbmtd",
EvidenceMatcher: m.FileContentsVersionMatcher(
`/mysql-cluster-gpl-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)/`),
Package: "mysql-cluster",
PURL: mustPURL("pkg:generic/mysql-cluster@version"),
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:a:oracle:mysql_cluster:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
},
{
Class: "ndb_mgmd-binary",
FileGlob: "**/ndb_mgmd",
EvidenceMatcher: m.FileContentsVersionMatcher(
`/mysql-cluster-gpl-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)/`),
Package: "mysql-cluster",
PURL: mustPURL("pkg:generic/mysql-cluster@version"),
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:a:oracle:mysql_cluster:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
},
{ {
Class: "xtrabackup-binary", Class: "xtrabackup-binary",
FileGlob: "**/xtrabackup", FileGlob: "**/xtrabackup",

View File

@ -312,20 +312,52 @@ from-images:
paths: paths:
- /usr/bin/mysql - /usr/bin/mysql
# TODO: add pattern for mysqld - version: 9.7.0
# - version: 5.6.51 images:
# images: - ref: mysql:9.7.0@sha256:6e5e46e6aece0bc8edb5abecc6fd726653f36447860f7f4dbf3481c91b477f69
# - ref: mysql:5.6.51@sha256:897086d07d1efa876224b147397ea8d3147e61dd84dce963aace1d5e9dc2802d platform: linux/amd64
# platform: linux/amd64 paths:
# paths: - /usr/sbin/mysqld
# - /usr/sbin/mysqld
# - name: mysql-cluster
# - version: 8.0.34 version: 9.7.0
# images: images:
# - ref: mysql:8.0.34@sha256:8b8835a2c32cd7357a5d2ea4b49ad870ff519c8c1d4add362803feddf4a0a973 - ref: container-registry.oracle.com/mysql/community-cluster:9.7.0
# platform: linux/amd64 platform: linux/amd64
# paths: paths:
# - /usr/sbin/mysqld - /usr/sbin/mysqld
- name: mysql-cluster
version: 7.6.17
images:
- ref: container-registry.oracle.com/mysql/community-cluster:7.6.17
platform: linux/amd64
paths:
- /usr/sbin/mysqld
- name: ndbd
version: 9.7.0
images:
- ref: container-registry.oracle.com/mysql/community-cluster:9.7.0
platform: linux/amd64
paths:
- /usr/sbin/ndbd
- name: ndbmtd
version: 9.7.0
images:
- ref: container-registry.oracle.com/mysql/community-cluster:9.7.0
platform: linux/amd64
paths:
- /usr/sbin/ndbmtd
- name: ndb_mgmd
version: 9.7.0
images:
- ref: container-registry.oracle.com/mysql/community-cluster:9.7.0
platform: linux/amd64
paths:
- /usr/sbin/ndb_mgmd
- name: mongodb - name: mongodb
version: 8.0.17 version: 8.0.17