github.com/anchore/syft@v1.38.2/syft/pkg/cataloger/binary/classifiers.go (about) 1 package binary 2 3 import ( 4 "fmt" 5 6 "github.com/anchore/packageurl-go" 7 "github.com/anchore/syft/syft/cpe" 8 "github.com/anchore/syft/syft/pkg/cataloger/internal/binutils" 9 ) 10 11 // in both binaries and shared libraries, the version pattern is [NUL]3.11.2[NUL] 12 var pythonVersionTemplate = `(?m)\x00(?P<version>{{ .version }}[-._a-zA-Z0-9]*)\x00` 13 14 //nolint:funlen 15 func DefaultClassifiers() []binutils.Classifier { 16 m := binutils.ContextualEvidenceMatchers{CatalogerName: catalogerName} 17 18 var libpythonMatcher = m.FileNameTemplateVersionMatcher( 19 `(?:.*/|^)libpython(?P<version>[0-9]+(?:\.[0-9]+)+)[a-z]?\.so.*$`, 20 pythonVersionTemplate, 21 ) 22 23 var rubyMatcher = m.FileContentsVersionMatcher( 24 // ruby 3.4.0dev (2024-09-15T01:06:11Z master 532af89e3b) [x86_64-linux] 25 // ruby 3.4.0preview1 (2024-05-16 master 9d69619623) [x86_64-linux] 26 // ruby 3.3.0rc1 (2023-12-11 master a49643340e) [x86_64-linux] 27 // ruby 3.2.1 (2023-02-08 revision 31819e82c8) [x86_64-linux] 28 // ruby 2.7.7p221 (2022-11-24 revision 168ec2b1e5) [x86_64-linux] 29 `(?m)ruby (?P<version>[0-9]+\.[0-9]+\.[0-9]+((p|preview|rc|dev)[0-9]*)?) `) 30 31 classifiers := []binutils.Classifier{ 32 { 33 Class: "python-binary", 34 FileGlob: "**/python*", 35 EvidenceMatcher: binutils.MatchAny( 36 // try to find version information from libpython shared libraries 37 binutils.SharedLibraryLookup( 38 `^libpython[0-9]+(?:\.[0-9]+)+[a-z]?\.so.*$`, 39 libpythonMatcher), 40 // check for version information in the binary 41 m.FileNameTemplateVersionMatcher( 42 `(?:.*/|^)python(?P<version>[0-9]+(?:\.[0-9]+)+)$`, 43 pythonVersionTemplate), 44 ), 45 Package: "python", 46 PURL: mustPURL("pkg:generic/python@version"), 47 CPEs: []cpe.CPE{ 48 cpe.Must("cpe:2.3:a:python_software_foundation:python:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 49 cpe.Must("cpe:2.3:a:python:python:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 50 }, 51 }, 52 { 53 Class: "python-binary-lib", 54 FileGlob: "**/libpython*.so*", 55 EvidenceMatcher: libpythonMatcher, 56 Package: "python", 57 PURL: mustPURL("pkg:generic/python@version"), 58 CPEs: []cpe.CPE{ 59 cpe.Must("cpe:2.3:a:python_software_foundation:python:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 60 cpe.Must("cpe:2.3:a:python:python:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 61 }, 62 }, 63 { 64 Class: "pypy-binary-lib", 65 FileGlob: "**/libpypy*.so*", 66 EvidenceMatcher: m.FileContentsVersionMatcher( 67 `(?m)\[PyPy (?P<version>[0-9]+\.[0-9]+\.[0-9]+)`), 68 Package: "pypy", 69 PURL: mustPURL("pkg:generic/pypy@version"), 70 }, 71 { 72 Class: "go-binary", 73 FileGlob: "**/go", 74 EvidenceMatcher: m.FileContentsVersionMatcher( 75 `(?m)go(?P<version>[0-9]+\.[0-9]+(\.[0-9]+|beta[0-9]+|alpha[0-9]+|rc[0-9]+)?)\x00`), 76 Package: "go", 77 PURL: mustPURL("pkg:generic/go@version"), 78 CPEs: singleCPE("cpe:2.3:a:golang:go:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 79 }, 80 { 81 Class: "julia-binary", 82 FileGlob: "**/libjulia-internal.so", 83 EvidenceMatcher: m.FileContentsVersionMatcher( 84 `(?m)__init__\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00verify`), 85 Package: "julia", 86 PURL: mustPURL("pkg:generic/julia@version"), 87 CPEs: singleCPE("cpe:2.3:a:julialang:julia:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 88 }, 89 { 90 Class: "helm", 91 FileGlob: "**/helm", 92 EvidenceMatcher: m.FileContentsVersionMatcher( 93 `(?m)\x00v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`), 94 Package: "helm", 95 PURL: mustPURL("pkg:golang/helm.sh/helm@version"), 96 CPEs: singleCPE("cpe:2.3:a:helm:helm:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 97 }, 98 { 99 Class: "redis-binary", 100 FileGlob: "**/redis-server", 101 EvidenceMatcher: binutils.MatchAny( 102 // matches most recent versions of redis (~v7), e.g. "7.0.14buildkitsandbox-1702957741000000000" 103 m.FileContentsVersionMatcher(`[^\d](?P<version>\d+.\d+\.\d+)buildkitsandbox-\d+`), 104 // matches against older versions of redis (~v3 - v6), e.g. "4.0.11841ce7054bd9-1542359302000000000" 105 m.FileContentsVersionMatcher(`[^\d](?P<version>[0-9]+\.[0-9]+\.[0-9]+)\w{12}-\d+`), 106 // matches against older versions of redis (~v2), e.g. "Server started, Redis version 2.8.23" 107 m.FileContentsVersionMatcher(`Redis version (?P<version>[0-9]+\.[0-9]+\.[0-9]+)`), 108 ), 109 Package: "redis", 110 PURL: mustPURL("pkg:generic/redis@version"), 111 CPEs: []cpe.CPE{ 112 cpe.Must("cpe:2.3:a:redislabs:redis:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 113 cpe.Must("cpe:2.3:a:redis:redis:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 114 }, 115 }, 116 { 117 Class: "nodejs-binary", 118 FileGlob: "**/node", 119 EvidenceMatcher: binutils.MatchAny( 120 // [NUL]node v0.10.48[NUL] 121 // [NUL]v0.12.18[NUL] 122 // [NUL]v4.9.1[NUL] 123 // node.js/v22.9.0 124 m.FileContentsVersionMatcher(`(?m)\x00(node )?v(?P<version>(0|4|5|6)\.[0-9]+\.[0-9]+)\x00`), 125 m.FileContentsVersionMatcher(`(?m)node\.js\/v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`), 126 ), 127 Package: "node", 128 PURL: mustPURL("pkg:generic/node@version"), 129 CPEs: singleCPE("cpe:2.3:a:nodejs:node.js:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 130 }, 131 { 132 Class: "go-binary-hint", 133 FileGlob: "**/VERSION*", 134 EvidenceMatcher: m.FileContentsVersionMatcher( 135 `(?m)go(?P<version>[0-9]+\.[0-9]+(\.[0-9]+|beta[0-9]+|alpha[0-9]+|rc[0-9]+)?(-[0-9a-f]{7})?)`), 136 Package: "go", 137 PURL: mustPURL("pkg:generic/go@version"), 138 CPEs: singleCPE("cpe:2.3:a:golang:go:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 139 }, 140 { 141 Class: "busybox-binary", 142 FileGlob: "**/busybox", 143 EvidenceMatcher: m.FileContentsVersionMatcher( 144 `(?m)BusyBox\s+v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`), 145 Package: "busybox", 146 PURL: mustPURL("pkg:generic/busybox@version"), 147 CPEs: singleCPE("cpe:2.3:a:busybox:busybox:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 148 }, 149 { 150 Class: "util-linux-binary", 151 FileGlob: "**/getopt", 152 EvidenceMatcher: m.FileContentsVersionMatcher( 153 `\x00util-linux\s(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`), 154 Package: "util-linux", 155 PURL: mustPURL("pkg:generic/util-linux@version"), 156 CPEs: singleCPE("cpe:2.3:a:kernel:util-linux:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 157 }, 158 { 159 Class: "haproxy-binary", 160 FileGlob: "**/haproxy", 161 EvidenceMatcher: binutils.MatchAny( 162 m.FileContentsVersionMatcher(`(?m)version (?P<version>[0-9]+\.[0-9]+(\.|-dev|-rc)[0-9]+)(-[a-z0-9]{7})?, released 20`), 163 m.FileContentsVersionMatcher(`(?m)HA-Proxy version (?P<version>[0-9]+\.[0-9]+(\.|-dev)[0-9]+)`), 164 m.FileContentsVersionMatcher(`(?m)(?P<version>[0-9]+\.[0-9]+(\.|-dev)[0-9]+)-[0-9a-zA-Z]{7}.+HAProxy version`), 165 ), 166 Package: "haproxy", 167 PURL: mustPURL("pkg:generic/haproxy@version"), 168 CPEs: singleCPE("cpe:2.3:a:haproxy:haproxy:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 169 }, 170 { 171 Class: "perl-binary", 172 FileGlob: "**/perl", 173 EvidenceMatcher: m.FileContentsVersionMatcher( 174 `(?m)\/usr\/local\/lib\/perl\d\/(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`), 175 Package: "perl", 176 PURL: mustPURL("pkg:generic/perl@version"), 177 CPEs: singleCPE("cpe:2.3:a:perl:perl:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 178 }, 179 { 180 Class: "php-composer-binary", 181 FileGlob: "**/composer*", 182 EvidenceMatcher: m.FileContentsVersionMatcher( 183 `(?m)'pretty_version'\s*=>\s*'(?P<version>[0-9]+\.[0-9]+\.[0-9]+(beta[0-9]+|alpha[0-9]+|RC[0-9]+)?)'`), 184 Package: "composer", 185 PURL: mustPURL("pkg:generic/composer@version"), 186 CPEs: singleCPE("cpe:2.3:a:getcomposer:composer:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 187 }, 188 { 189 Class: "httpd-binary", 190 FileGlob: "**/httpd", 191 EvidenceMatcher: m.FileContentsVersionMatcher( 192 `(?m)Apache\/(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`), 193 Package: "httpd", 194 PURL: mustPURL("pkg:generic/httpd@version"), 195 CPEs: singleCPE("cpe:2.3:a:apache:http_server:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 196 }, 197 { 198 Class: "memcached-binary", 199 FileGlob: "**/memcached", 200 EvidenceMatcher: m.FileContentsVersionMatcher( 201 `(?m)memcached\s(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`), 202 Package: "memcached", 203 PURL: mustPURL("pkg:generic/memcached@version"), 204 CPEs: singleCPE("cpe:2.3:a:memcached:memcached:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 205 }, 206 { 207 Class: "traefik-binary", 208 FileGlob: "**/traefik", 209 EvidenceMatcher: m.FileContentsVersionMatcher( 210 // [NUL]v1.7.34[NUL] 211 // [NUL]2.9.6[NUL] 212 // 3.0.4[NUL] 213 `(?m)(\x00|\x{FFFD})?v?(?P<version>[0-9]+\.[0-9]+\.[0-9]+(-alpha[0-9]|-beta[0-9]|-rc[0-9])?)\x00`), 214 Package: "traefik", 215 PURL: mustPURL("pkg:generic/traefik@version"), 216 CPEs: singleCPE("cpe:2.3:a:traefik:traefik:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 217 }, 218 { 219 Class: "arangodb-binary", 220 FileGlob: "**/arangosh", 221 EvidenceMatcher: m.FileContentsVersionMatcher( 222 `(?m)\x00*(?P<version>[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?)\s\[linux\]`), 223 Package: "arangodb", 224 PURL: mustPURL("pkg:generic/arangodb@version"), 225 CPEs: singleCPE("cpe:2.3:a:arangodb:arangodb:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 226 }, 227 { 228 Class: "postgresql-binary", 229 FileGlob: "**/postgres", 230 EvidenceMatcher: m.FileContentsVersionMatcher( 231 // [NUL]PostgreSQL 15beta4 232 // [NUL]PostgreSQL 15.1 233 // [NUL]PostgreSQL 9.6.24 234 // ?PostgreSQL 9.5alpha1 235 `(?m)(\x00|\?)PostgreSQL (?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)`), 236 Package: "postgresql", 237 PURL: mustPURL("pkg:generic/postgresql@version"), 238 CPEs: singleCPE("cpe:2.3:a:postgresql:postgresql:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 239 }, 240 { 241 Class: "mysql-binary", 242 FileGlob: "**/mysql", 243 EvidenceMatcher: binutils.MatchAny( 244 // shutdown[NUL]8.0.37[NUL][NUL][NUL][NUL][NUL]mysql_real_esc 245 m.FileContentsVersionMatcher(`\x00(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)\x00+mysql`), 246 // /export/home/pb2/build/sb_0-26781090-1516292385.58/release/mysql-8.0.4-rc/mysys_ssl/my_default.cc 247 m.FileContentsVersionMatcher(`(?m).*/mysql-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)`), 248 ), 249 Package: "mysql", 250 PURL: mustPURL("pkg:generic/mysql@version"), 251 CPEs: singleCPE("cpe:2.3:a:oracle:mysql:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 252 }, 253 { 254 Class: "mysql-binary", 255 FileGlob: "**/mysql", 256 EvidenceMatcher: m.FileContentsVersionMatcher( 257 `(?m).*/percona-server-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)`), 258 Package: "percona-server", 259 PURL: mustPURL("pkg:generic/percona-server@version"), 260 CPEs: []cpe.CPE{ 261 cpe.Must("cpe:2.3:a:oracle:mysql:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 262 cpe.Must("cpe:2.3:a:percona:percona_server:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 263 }, 264 }, 265 { 266 Class: "mysql-binary", 267 FileGlob: "**/mysql", 268 EvidenceMatcher: m.FileContentsVersionMatcher( 269 `(?m).*/Percona-XtraDB-Cluster-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)`), 270 Package: "percona-xtradb-cluster", 271 PURL: mustPURL("pkg:generic/percona-xtradb-cluster@version"), 272 CPEs: []cpe.CPE{ 273 cpe.Must("cpe:2.3:a:oracle:mysql:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 274 cpe.Must("cpe:2.3:a:percona:percona_server:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 275 cpe.Must("cpe:2.3:a:percona:xtradb_cluster:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 276 }, 277 }, 278 { 279 Class: "xtrabackup-binary", 280 FileGlob: "**/xtrabackup", 281 EvidenceMatcher: m.FileContentsVersionMatcher( 282 `(?m).*/percona-xtrabackup-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)`), 283 Package: "percona-xtrabackup", 284 PURL: mustPURL("pkg:generic/percona-xtrabackup@version"), 285 CPEs: singleCPE("cpe:2.3:a:percona:xtrabackup:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 286 }, 287 { 288 Class: "mariadb-binary", 289 FileGlob: "**/{mariadb,mysql}", 290 EvidenceMatcher: m.FileContentsVersionMatcher( 291 // 10.6.15-MariaDB 292 `(?m)(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)-MariaDB`), 293 Package: "mariadb", 294 PURL: mustPURL("pkg:generic/mariadb@version"), 295 CPEs: singleCPE("cpe:2.3:a:mariadb:mariadb:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 296 }, 297 { 298 Class: "rust-standard-library-linux", 299 FileGlob: "**/libstd-????????????????.so", 300 EvidenceMatcher: m.FileContentsVersionMatcher( 301 // clang LLVM (rustc version 1.48.0 (7eac88abb 2020-11-16)) 302 `(?m)(\x00)clang LLVM \(rustc version (?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)) \(\w+ \d{4}\-\d{2}\-\d{2}\)`), 303 Package: "rust", 304 PURL: mustPURL("pkg:generic/rust@version"), 305 CPEs: singleCPE("cpe:2.3:a:rust-lang:rust:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 306 }, 307 { 308 Class: "rust-standard-library-macos", 309 FileGlob: "**/libstd-????????????????.dylib", 310 EvidenceMatcher: m.FileContentsVersionMatcher( 311 // c 1.48.0 (7eac88abb 2020-11-16) 312 `(?m)c (?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)) \(\w+ \d{4}\-\d{2}\-\d{2}\)`), 313 Package: "rust", 314 PURL: mustPURL("pkg:generic/rust@version"), 315 CPEs: singleCPE("cpe:2.3:a:rust-lang:rust:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 316 }, 317 { 318 Class: "ruby-binary", 319 FileGlob: "**/ruby", 320 EvidenceMatcher: binutils.MatchAny( 321 rubyMatcher, 322 binutils.SharedLibraryLookup( 323 // try to find version information from libruby shared libraries 324 `^libruby\.so.*$`, 325 rubyMatcher), 326 ), 327 Package: "ruby", 328 PURL: mustPURL("pkg:generic/ruby@version"), 329 CPEs: singleCPE("cpe:2.3:a:ruby-lang:ruby:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 330 }, 331 { 332 Class: "erlang-binary", 333 FileGlob: "**/erlexec", 334 EvidenceMatcher: binutils.MatchAny( 335 m.FileContentsVersionMatcher( 336 // <artificial>[NUL]/usr/src/otp_src_25.3.2.6/erts/ 337 `(?m)/src/otp_src_(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`, 338 ), 339 m.FileContentsVersionMatcher( 340 // <artificial>[NUL]/usr/local/src/otp-25.3.2.7/erts/ 341 `(?m)/usr/local/src/otp-(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`, 342 ), 343 ), 344 Package: "erlang", 345 PURL: mustPURL("pkg:generic/erlang@version"), 346 CPEs: singleCPE("cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 347 }, 348 { 349 Class: "erlang-alpine-binary", 350 FileGlob: "**/beam.smp", 351 EvidenceMatcher: binutils.MatchAny( 352 m.FileContentsVersionMatcher( 353 // <artificial>[NUL]/usr/src/otp_src_25.3.2.6/erts/ 354 `(?m)/src/otp_src_(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`, 355 ), 356 m.FileContentsVersionMatcher( 357 // <artificial>[NUL]/usr/local/src/otp-25.3.2.7/erts/ 358 `(?m)/usr/local/src/otp-(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`, 359 ), 360 m.FileContentsVersionMatcher( 361 // [NUL][NUL]26.1.2[NUL][NUL][NUL][NUL][NUL][NUL][NUL]NUL[NUL][NUL]Erlang/OTP 362 `\x00+(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)\x00+Erlang/OTP`, 363 ), 364 ), 365 Package: "erlang", 366 PURL: mustPURL("pkg:generic/erlang@version"), 367 CPEs: singleCPE("cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 368 }, 369 { 370 Class: "erlang-library", 371 FileGlob: "**/liberts_internal.a", 372 EvidenceMatcher: binutils.MatchAny( 373 m.FileContentsVersionMatcher( 374 // <artificial>[NUL]/usr/src/otp_src_25.3.2.6/erts/ 375 `(?m)/src/otp_src_(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`, 376 ), 377 m.FileContentsVersionMatcher( 378 // <artificial>[NUL]/usr/local/src/otp-25.3.2.7/erts/ 379 `(?m)/usr/local/src/otp-(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`, 380 ), 381 ), 382 Package: "erlang", 383 PURL: mustPURL("pkg:generic/erlang@version"), 384 CPEs: singleCPE("cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 385 }, 386 { 387 Class: "swipl-binary", 388 FileGlob: "**/swipl", 389 EvidenceMatcher: m.FileContentsVersionMatcher( 390 `(?m)swipl-(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\/`, 391 ), 392 Package: "swipl", 393 PURL: mustPURL("pkg:generic/swipl@version"), 394 CPEs: singleCPE("cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 395 }, 396 { 397 Class: "dart-binary", 398 FileGlob: "**/dart", 399 EvidenceMatcher: m.FileContentsVersionMatcher( 400 // MathAtan[NUL]2.12.4 (stable) 401 // "%s"[NUL]3.0.0 (stable) 402 // Dart,GC"[NUL]3.5.2 (stable) 403 // Dart,GC"[NUL]3.6.0-216.1.beta (beta) 404 `(?m)\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+(\.[0-9]+)?\.beta)?) `, 405 ), 406 Package: "dart", 407 PURL: mustPURL("pkg:generic/dart@version"), 408 CPEs: singleCPE("cpe:2.3:a:dart:dart_software_development_kit:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 409 }, 410 { 411 Class: "haskell-ghc-binary", 412 FileGlob: "**/ghc*", 413 EvidenceMatcher: m.FileContentsVersionMatcher( 414 `(?m)\x00GHC (?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`, 415 ), 416 Package: "haskell/ghc", 417 PURL: mustPURL("pkg:generic/haskell/ghc@version"), 418 CPEs: singleCPE("cpe:2.3:a:haskell:ghc:*:*:*:*:*:*:*:*"), 419 }, 420 { 421 Class: "haskell-cabal-binary", 422 FileGlob: "**/cabal", 423 EvidenceMatcher: m.FileContentsVersionMatcher( 424 `(?m)\x00Cabal-(?P<version>[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?)-`, 425 ), 426 Package: "haskell/cabal", 427 PURL: mustPURL("pkg:generic/haskell/cabal@version"), 428 CPEs: singleCPE("cpe:2.3:a:haskell:cabal:*:*:*:*:*:*:*:*"), 429 }, 430 { 431 Class: "haskell-stack-binary", 432 FileGlob: "**/stack", 433 EvidenceMatcher: m.FileContentsVersionMatcher( 434 `(?m)Version\s*(?P<version>[0-9]+\.[0-9]+\.[0-9]+),\s*Git`, 435 ), 436 Package: "haskell/stack", 437 PURL: mustPURL("pkg:generic/haskell/stack@version"), 438 CPEs: singleCPE("cpe:2.3:a:haskell:stack:*:*:*:*:*:*:*:*"), 439 }, 440 { 441 Class: "consul-binary", 442 FileGlob: "**/consul", 443 EvidenceMatcher: m.FileContentsVersionMatcher( 444 // NOTE: This is brittle and may not work for past or future versions 445 `CONSUL_VERSION: (?P<version>\d+\.\d+\.\d+)`, 446 ), 447 Package: "consul", 448 PURL: mustPURL("pkg:golang/github.com/hashicorp/consul@version"), 449 CPEs: singleCPE("cpe:2.3:a:hashicorp:consul:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 450 }, 451 { 452 Class: "hashicorp-vault-binary", 453 FileGlob: "**/vault", 454 EvidenceMatcher: m.FileContentsVersionMatcher( 455 // revoke1.18.0 456 `(?m)revoke(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`), 457 Package: "github.com/hashicorp/vault", 458 PURL: mustPURL("pkg:golang/github.com/hashicorp/vault@version"), 459 CPEs: singleCPE("cpe:2.3:a:hashicorp:vault:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 460 }, 461 { 462 Class: "nginx-binary", 463 FileGlob: "**/nginx", 464 EvidenceMatcher: m.FileContentsVersionMatcher( 465 // [NUL]nginx version: nginx/1.25.1 - fetches '1.25.1' 466 // [NUL]nginx version: openresty/1.21.4.1 - fetches '1.21.4' as this is the nginx version part 467 `(?m)(\x00|\?)nginx version: [^\/]+\/(?P<version>[0-9]+\.[0-9]+\.[0-9]+(?:\+\d+)?(?:-\d+)?)`, 468 ), 469 Package: "nginx", 470 PURL: mustPURL("pkg:generic/nginx@version"), 471 CPEs: []cpe.CPE{ 472 cpe.Must("cpe:2.3:a:f5:nginx:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 473 cpe.Must("cpe:2.3:a:nginx:nginx:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 474 }, 475 }, 476 { 477 Class: "bash-binary", 478 FileGlob: "**/bash", 479 EvidenceMatcher: m.FileContentsVersionMatcher( 480 // @(#)Bash version 5.2.15(1) release GNU 481 // @(#)Bash version 5.2.0(1) alpha GNU 482 // @(#)Bash version 5.2.0(1) beta GNU 483 // @(#)Bash version 5.2.0(1) rc4 GNU 484 `(?m)@\(#\)Bash version (?P<version>[0-9]+\.[0-9]+\.[0-9]+)\([0-9]\) [a-z0-9]+ GNU`, 485 ), 486 Package: "bash", 487 PURL: mustPURL("pkg:generic/bash@version"), 488 CPEs: singleCPE("cpe:2.3:a:gnu:bash:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 489 }, 490 { 491 Class: "openssl-binary", 492 FileGlob: "**/openssl", 493 EvidenceMatcher: m.FileContentsVersionMatcher( 494 // [NUL]OpenSSL 3.1.4' 495 // [NUL]OpenSSL 1.1.1w' 496 `\x00OpenSSL (?P<version>[0-9]+\.[0-9]+\.[0-9]+([a-z]+|-alpha[0-9]|-beta[0-9]|-rc[0-9])?)`, 497 ), 498 Package: "openssl", 499 PURL: mustPURL("pkg:generic/openssl@version"), 500 CPEs: singleCPE("cpe:2.3:a:openssl:openssl:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 501 }, 502 { 503 Class: "gcc-binary", 504 FileGlob: "**/gcc", 505 EvidenceMatcher: m.FileContentsVersionMatcher( 506 // GCC: \(GNU\) 12.3.0' 507 `GCC: \(GNU\) (?P<version>[0-9]+\.[0-9]+\.[0-9]+)`, 508 ), 509 Package: "gcc", 510 PURL: mustPURL("pkg:generic/gcc@version"), 511 CPEs: singleCPE("cpe:2.3:a:gnu:gcc:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 512 }, 513 { 514 Class: "fluent-bit-binary", 515 FileGlob: "**/fluent-bit", 516 EvidenceMatcher: m.FileContentsVersionMatcher( 517 // [NUL]3.0.2[NUL]%sFluent Bit 518 // [NUL]2.2.3[NUL]Fluent Bit 519 // [NUL]2.2.1[NUL][NUL][NUL]Fluent Bit 520 // [NUL]1.7.0[NUL]\x1b[1m[NUL]%sFluent Bit (versions 1.7.0-dev-3 through 1.7.0-dev-9 and 1.7.0-rc4 through 1.7.0-rc8) 521 // [NUL][NUL]1.3.10[NUL][NUL]Fluent Bit v%s 522 `\x00(\x00)?(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00(\x1b\[1m\x00|\x00|\x00\x00)?(%s)?Fluent`, 523 ), 524 Package: "fluent-bit", 525 PURL: mustPURL("pkg:github/fluent/fluent-bit@version"), 526 CPEs: singleCPE("cpe:2.3:a:treasuredata:fluent_bit:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 527 }, 528 { 529 Class: "wordpress-cli-binary", 530 FileGlob: "**/wp", 531 EvidenceMatcher: m.FileContentsVersionMatcher( 532 // wp-cli/wp-cli 2.9.0' 533 `(?m)wp-cli/wp-cli (?P<version>[0-9]+\.[0-9]+\.[0-9]+)`, 534 ), 535 Package: "wp-cli", 536 PURL: mustPURL("pkg:generic/wp-cli@version"), 537 CPEs: singleCPE("cpe:2.3:a:wp-cli:wp-cli:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 538 }, 539 { 540 Class: "curl-binary", 541 FileGlob: "**/curl", 542 EvidenceMatcher: m.FileContentsVersionMatcher( 543 `curl/(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`, 544 ), 545 Package: "curl", 546 PURL: mustPURL("pkg:generic/curl@version"), 547 CPEs: singleCPE("cpe:2.3:a:haxx:curl:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 548 }, 549 { 550 Class: "lighttpd-binary", 551 FileGlob: "**/lighttpd", 552 EvidenceMatcher: m.FileContentsVersionMatcher( 553 `\x00lighttpd/(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`, 554 ), 555 Package: "lighttpd", 556 PURL: mustPURL("pkg:generic/lighttpd@version"), 557 CPEs: singleCPE("cpe:2.3:a:lighttpd:lighttpd:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 558 }, 559 { 560 Class: "proftpd-binary", 561 FileGlob: "**/proftpd", 562 EvidenceMatcher: m.FileContentsVersionMatcher( 563 `\x00ProFTPD Version (?P<version>[0-9]+\.[0-9]+\.[0-9]+[a-z]?)\x00`, 564 ), 565 Package: "proftpd", 566 PURL: mustPURL("pkg:generic/proftpd@version"), 567 CPEs: singleCPE("cpe:2.3:a:proftpd:proftpd:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 568 }, 569 { 570 Class: "zstd-binary", 571 FileGlob: "**/zstd", 572 EvidenceMatcher: m.FileContentsVersionMatcher( 573 `\x00v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`, 574 ), 575 Package: "zstd", 576 PURL: mustPURL("pkg:generic/zstd@version"), 577 CPEs: singleCPE("cpe:2.3:a:facebook:zstandard:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 578 }, 579 { 580 Class: "xz-binary", 581 FileGlob: "**/xz", 582 EvidenceMatcher: m.FileContentsVersionMatcher( 583 `\x00xz \(XZ Utils\) (?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`, 584 ), 585 Package: "xz", 586 PURL: mustPURL("pkg:generic/xz@version"), 587 CPEs: singleCPE("cpe:2.3:a:tukaani:xz:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 588 }, 589 { 590 Class: "gzip-binary", 591 FileGlob: "**/gzip", 592 EvidenceMatcher: m.FileContentsVersionMatcher( 593 `\x00(?P<version>[0-9]+\.[0-9]+)\x00`, 594 ), 595 Package: "gzip", 596 PURL: mustPURL("pkg:generic/gzip@version"), 597 CPEs: singleCPE("cpe:2.3:a:gnu:gzip:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 598 }, 599 { 600 Class: "sqlcipher-binary", 601 FileGlob: "**/sqlcipher", 602 EvidenceMatcher: m.FileContentsVersionMatcher( 603 `[^0-9]\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`, 604 ), 605 Package: "sqlcipher", 606 PURL: mustPURL("pkg:generic/sqlcipher@version"), 607 CPEs: singleCPE("cpe:2.3:a:zetetic:sqlcipher:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 608 }, 609 { 610 Class: "jq-binary", 611 FileGlob: "**/jq", 612 EvidenceMatcher: m.FileContentsVersionMatcher( 613 `\x00(?P<version>[0-9]{1,3}\.[0-9]{1,3}(\.[0-9]+)?)\x00`, 614 ), 615 Package: "jq", 616 PURL: mustPURL("pkg:generic/jq@version"), 617 CPEs: singleCPE("cpe:2.3:a:jqlang:jq:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 618 }, 619 { 620 Class: "chrome-binary", 621 FileGlob: "**/chrome", 622 EvidenceMatcher: m.FileContentsVersionMatcher( 623 // [NUL]127.0.6533.119[NUL]Default 624 `\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\x00Default`, 625 ), 626 Package: "chrome", 627 PURL: mustPURL("pkg:generic/chrome@version"), 628 CPEs: singleCPE("cpe:2.3:a:google:chrome:*:*:*:*:*:*:*:*"), 629 }, 630 { 631 Class: "ffmpeg-binary", 632 FileGlob: "**/ffmpeg", 633 EvidenceMatcher: m.FileContentsVersionMatcher( 634 // Pattern found in the binary: "%s version 7.1.1" or "%s version 6.0" 635 // When executed outputs: "ffmpeg version 7.1.1" or "ffmpeg version 6.0" 636 `(?m)%s version (?P<version>[0-9]+\.[0-9]+(\.[0-9]+)?)`, 637 ), 638 Package: "ffmpeg", 639 PURL: mustPURL("pkg:generic/ffmpeg@version"), 640 CPEs: singleCPE("cpe:2.3:a:ffmpeg:ffmpeg:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 641 }, 642 { 643 Class: "ffmpeg-library", 644 FileGlob: "**/libav*", 645 EvidenceMatcher: binutils.MatchAny( 646 // Primary pattern: FFmpeg version found in most libraries 647 m.FileContentsVersionMatcher(`(?m)FFmpeg version (?P<version>[0-9]+\.[0-9]+(\.[0-9]+)?)`), 648 // Fallback: library-specific version patterns for libavcodec and libavformat 649 m.FileContentsVersionMatcher(`(?m)Lavc(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`), 650 m.FileContentsVersionMatcher(`(?m)Lavf(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`), 651 ), 652 Package: "ffmpeg", 653 PURL: mustPURL("pkg:generic/ffmpeg@version"), 654 CPEs: singleCPE("cpe:2.3:a:ffmpeg:ffmpeg:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 655 }, 656 { 657 Class: "ffmpeg-library", 658 FileGlob: "**/libswresample*", 659 EvidenceMatcher: m.FileContentsVersionMatcher( 660 // FFmpeg version pattern for libswresample 661 `(?m)FFmpeg version (?P<version>[0-9]+\.[0-9]+(\.[0-9]+)?)`), 662 Package: "ffmpeg", 663 PURL: mustPURL("pkg:generic/ffmpeg@version"), 664 CPEs: singleCPE("cpe:2.3:a:ffmpeg:ffmpeg:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 665 }, 666 { 667 Class: "elixir-binary", 668 FileGlob: "**/elixir", 669 EvidenceMatcher: m.FileContentsVersionMatcher( 670 `(?m)ELIXIR_VERSION=(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`), 671 Package: "elixir", 672 PURL: mustPURL("pkg:generic/elixir@version"), 673 CPEs: []cpe.CPE{ 674 cpe.Must("cpe:2.3:a:elixir-lang:elixir:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 675 }, 676 }, 677 { 678 Class: "elixir-library", 679 FileGlob: "**/elixir/ebin/elixir.app", 680 EvidenceMatcher: m.FileContentsVersionMatcher( 681 `(?m)\{vsn,"(?P<version>[0-9]+\.[0-9]+\.[0-9]+(-[a-z0-9]+)?)"\}`), 682 Package: "elixir", 683 PURL: mustPURL("pkg:generic/elixir@version"), 684 CPEs: singleCPE("cpe:2.3:a:elixir-lang:elixir:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), 685 }, 686 } 687 688 return append(classifiers, defaultJavaClassifiers()...) 689 } 690 691 // singleCPE returns a []cpe.CPE with Source: Generated based on the cpe string or panics if the 692 // cpe string cannot be parsed into valid CPE Attributes 693 func singleCPE(cpeString string, source ...cpe.Source) []cpe.CPE { 694 src := cpe.GeneratedSource 695 if len(source) > 0 { 696 src = source[0] 697 } 698 return []cpe.CPE{ 699 cpe.Must(cpeString, src), 700 } 701 } 702 703 func mustPURL(purl string) packageurl.PackageURL { 704 p, err := packageurl.FromString(purl) 705 if err != nil { 706 panic(fmt.Sprintf("invalid PURL: %s", p)) 707 } 708 return p 709 }