mirror of
https://github.com/anchore/syft.git
synced 2026-10-25 19:42:21 +01:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78ad3d648f | ||
|
|
1b3e57c264 | ||
|
|
ad7edba2a5 | ||
|
|
e51d4bcda1 | ||
|
|
d8113b5f07 | ||
|
|
a35f64c971 |
@@ -3,5 +3,5 @@ package internal
|
|||||||
const (
|
const (
|
||||||
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
||||||
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
||||||
JSONSchemaVersion = "16.0.5"
|
JSONSchemaVersion = "16.0.6"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package binary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/internal/sbomsync"
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/sbom"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewDependencyRelationships(resolver file.Resolver, accessor sbomsync.Accessor) []artifact.Relationship {
|
||||||
|
// TODO: consider library format (e.g. ELF, Mach-O, PE) for the meantime assume all binaries are homogeneous format
|
||||||
|
|
||||||
|
// start with building new file-to-file relationships for executables-to-executables
|
||||||
|
// you need to make certain that they are unique, store in a map[id]map[id]relationship to avoid dupes.
|
||||||
|
// before creating the new file-to-file relationship, check to see if there are packages that represent each
|
||||||
|
// file. If there are, create a package-to-package, file-to-package, or package-to-file relationship as appropriate.
|
||||||
|
|
||||||
|
// 1 & 2... build an index of all shared libraries and their owning packages to search against
|
||||||
|
index := newShareLibIndex(resolver, accessor)
|
||||||
|
|
||||||
|
// 3. craft package-to-package or package-to-file relationships that represent binary shared library dependencies
|
||||||
|
// note: prefer package-to-package relationships over package-to-file relationships
|
||||||
|
|
||||||
|
relIndex := newRelationshipIndex()
|
||||||
|
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||||
|
// read all existing dependencyOf relationships
|
||||||
|
for _, r := range s.Relationships {
|
||||||
|
if r.Type != artifact.DependencyOfRelationship {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
relIndex.track(r)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// find all new relationships to add...
|
||||||
|
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||||
|
for _, parentPkg := range s.Artifacts.Packages.Sorted(pkg.BinaryPkg) {
|
||||||
|
for _, evidentLocation := range parentPkg.Locations.ToSlice() {
|
||||||
|
if evidentLocation.Annotations[pkg.EvidenceAnnotationKey] != pkg.PrimaryEvidenceAnnotation {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// find all libraries that this package depends on
|
||||||
|
exec, ok := s.Artifacts.Executables[evidentLocation.Coordinates]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, libReference := range exec.ImportedLibraries {
|
||||||
|
// TODO: is this always a basename? technically no, it could be a path...
|
||||||
|
libBasename := path.Base(libReference)
|
||||||
|
|
||||||
|
pkgsThatOwnLib := index.owningLibraryPackage(libBasename)
|
||||||
|
if pkgsThatOwnLib == nil {
|
||||||
|
// create package-to-file relationship...
|
||||||
|
// if there is more than one library for this given library name, then we will include
|
||||||
|
// all of them as dependencies since we don't know the LD_LIBRARY_PATH order
|
||||||
|
// TODO: add configuration for LD_LIBRARY_PATH order?
|
||||||
|
for _, libCoord := range index.owningLibraryLocations(libBasename).ToSlice() {
|
||||||
|
relIndex.add(
|
||||||
|
artifact.Relationship{
|
||||||
|
From: libCoord,
|
||||||
|
To: parentPkg,
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't create a package-to-package relationship for this library... since we can't
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a package-to-package relationship between the binary package and the library package
|
||||||
|
// if there is more than one library for this given library name, then we will include
|
||||||
|
// all of them as dependencies since we don't know the LD_LIBRARY_PATH order
|
||||||
|
for _, pkgThatOwnsLib := range pkgsThatOwnLib.Sorted() {
|
||||||
|
relIndex.add(
|
||||||
|
artifact.Relationship{
|
||||||
|
From: pkgThatOwnsLib,
|
||||||
|
To: parentPkg,
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// so far this handles the first order dependencies from the binary package. Odds are that the OS package manager
|
||||||
|
// will have already created a package-to-package relationship for the lib packages to other lib packages.
|
||||||
|
|
||||||
|
return relIndex.newRelationships()
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package binary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/scylladb/go-set/strset"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
)
|
||||||
|
|
||||||
|
type relationshipIndex struct {
|
||||||
|
typesByFromTo map[artifact.ID]map[artifact.ID]*strset.Set
|
||||||
|
additional []artifact.Relationship
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRelationshipIndex(existing ...artifact.Relationship) *relationshipIndex {
|
||||||
|
r := &relationshipIndex{
|
||||||
|
typesByFromTo: make(map[artifact.ID]map[artifact.ID]*strset.Set),
|
||||||
|
additional: make([]artifact.Relationship, 0),
|
||||||
|
}
|
||||||
|
for _, rel := range existing {
|
||||||
|
r.track(rel)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// track this relationship as "exists" in the index (this is used to prevent duplicate relationships from being added).
|
||||||
|
// returns true if the relationship is new to the index, false otherwise.
|
||||||
|
func (i *relationshipIndex) track(r artifact.Relationship) bool {
|
||||||
|
fromID := r.From.ID()
|
||||||
|
if _, ok := i.typesByFromTo[fromID]; !ok {
|
||||||
|
i.typesByFromTo[fromID] = make(map[artifact.ID]*strset.Set)
|
||||||
|
}
|
||||||
|
|
||||||
|
toID := r.To.ID()
|
||||||
|
if _, ok := i.typesByFromTo[fromID][toID]; !ok {
|
||||||
|
i.typesByFromTo[fromID][toID] = strset.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
var exists bool
|
||||||
|
if i.typesByFromTo[fromID][toID].Has(string(r.Type)) {
|
||||||
|
exists = true
|
||||||
|
}
|
||||||
|
|
||||||
|
i.typesByFromTo[fromID][toID].Add(string(r.Type))
|
||||||
|
return exists
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a new relationship to the index, returning true if the relationship is new to the index, false otherwise (thus is a duplicate).
|
||||||
|
func (i *relationshipIndex) add(r artifact.Relationship) bool {
|
||||||
|
if !i.track(r) {
|
||||||
|
i.additional = append(i.additional, r)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *relationshipIndex) newRelationships() []artifact.Relationship {
|
||||||
|
return i.additional
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
package binary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/internal/log"
|
||||||
|
"github.com/anchore/syft/internal/sbomsync"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/sbom"
|
||||||
|
)
|
||||||
|
|
||||||
|
type sharedLibraryIndex struct {
|
||||||
|
libLocationsByBasename map[string]file.CoordinateSet
|
||||||
|
allLibLocations file.CoordinateSet
|
||||||
|
packagesByLibraryPath map[file.Coordinates]*pkg.Collection
|
||||||
|
}
|
||||||
|
|
||||||
|
func newShareLibIndex(resolver file.Resolver, accessor sbomsync.Accessor) *sharedLibraryIndex {
|
||||||
|
s := &sharedLibraryIndex{
|
||||||
|
libLocationsByBasename: make(map[string]file.CoordinateSet),
|
||||||
|
allLibLocations: file.NewCoordinateSet(),
|
||||||
|
packagesByLibraryPath: make(map[file.Coordinates]*pkg.Collection),
|
||||||
|
}
|
||||||
|
|
||||||
|
s.build(resolver, accessor)
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *sharedLibraryIndex) build(resolver file.Resolver, accessor sbomsync.Accessor) {
|
||||||
|
// 1. map out all locations that provide libraries (indexed by the basename)
|
||||||
|
i.libLocationsByBasename, i.allLibLocations = locationsThatProvideLibraries(accessor)
|
||||||
|
|
||||||
|
// 2. for each library path, find all packages that claim ownership of the library
|
||||||
|
i.packagesByLibraryPath = packagesWithLibraryOwnership(resolver, accessor, i.allLibLocations)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *sharedLibraryIndex) owningLibraryLocations(libraryBasename string) file.CoordinateSet {
|
||||||
|
if set, ok := i.libLocationsByBasename[libraryBasename]; ok {
|
||||||
|
return set
|
||||||
|
}
|
||||||
|
|
||||||
|
return file.NewCoordinateSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *sharedLibraryIndex) owningLibraryPackage(libraryBasename string) *pkg.Collection {
|
||||||
|
// find all packages that own a library by it's basename
|
||||||
|
if set, ok := i.libLocationsByBasename[libraryBasename]; ok {
|
||||||
|
for _, coord := range set.ToSlice() {
|
||||||
|
if pkgSet, ok := i.packagesByLibraryPath[coord]; ok {
|
||||||
|
return pkgSet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func locationsThatProvideLibraries(accessor sbomsync.Accessor) (map[string]file.CoordinateSet, file.CoordinateSet) {
|
||||||
|
// map out all locations that provide libraries (indexed by the basename)
|
||||||
|
libLocationsByBasename := make(map[string]file.CoordinateSet)
|
||||||
|
allLibLocations := file.NewCoordinateSet()
|
||||||
|
|
||||||
|
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||||
|
for coord, f := range s.Artifacts.Executables {
|
||||||
|
if !f.HasExports {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
basename := path.Base(coord.RealPath)
|
||||||
|
set := libLocationsByBasename[basename]
|
||||||
|
set.Add(coord)
|
||||||
|
allLibLocations.Add(coord)
|
||||||
|
libLocationsByBasename[basename] = set
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return libLocationsByBasename, allLibLocations
|
||||||
|
}
|
||||||
|
func packagesWithLibraryOwnership(resolver file.Resolver, accessor sbomsync.Accessor, allLibLocations file.CoordinateSet) map[file.Coordinates]*pkg.Collection {
|
||||||
|
// map out all packages that claim ownership of a library at a specific path
|
||||||
|
packagesByLibraryPath := make(map[file.Coordinates]*pkg.Collection)
|
||||||
|
|
||||||
|
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||||
|
for _, p := range s.Artifacts.Packages.Sorted() {
|
||||||
|
fileOwner, ok := p.Metadata.(pkg.FileOwner)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pth := range fileOwner.OwnedFiles() {
|
||||||
|
ownedLocation, err := resolver.FilesByPath(pth)
|
||||||
|
if err != nil {
|
||||||
|
log.WithFields("error", err, "path", pth).Trace("unable to find path for owned file")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, loc := range ownedLocation {
|
||||||
|
// if the location is a library, add the package to the set of packages that own the library
|
||||||
|
if !allLibLocations.Contains(loc.Coordinates) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := packagesByLibraryPath[loc.Coordinates]; !ok {
|
||||||
|
packagesByLibraryPath[loc.Coordinates] = pkg.NewCollection()
|
||||||
|
}
|
||||||
|
|
||||||
|
// we have a library path, add the package to the set of packages that own the library
|
||||||
|
packagesByLibraryPath[loc.Coordinates].Add(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return packagesByLibraryPath
|
||||||
|
}
|
||||||
@@ -1,15 +1,20 @@
|
|||||||
package relationship
|
package relationship
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/anchore/syft/internal/relationship/binary"
|
||||||
"github.com/anchore/syft/internal/sbomsync"
|
"github.com/anchore/syft/internal/sbomsync"
|
||||||
"github.com/anchore/syft/syft/artifact"
|
"github.com/anchore/syft/syft/artifact"
|
||||||
"github.com/anchore/syft/syft/cataloging"
|
"github.com/anchore/syft/syft/cataloging"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
"github.com/anchore/syft/syft/sbom"
|
"github.com/anchore/syft/syft/sbom"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Finalize(builder sbomsync.Builder, cfg cataloging.RelationshipsConfig, src artifact.Identifiable) {
|
func Finalize(resolver file.Resolver, builder sbomsync.Builder, cfg cataloging.RelationshipsConfig, src artifact.Identifiable) {
|
||||||
accessor := builder.(sbomsync.Accessor)
|
accessor := builder.(sbomsync.Accessor)
|
||||||
|
|
||||||
|
// remove ELF packages that are already represented by a non-ELF package
|
||||||
|
// TODO (also, how should we update the TUI to reflect that we removed packages?)
|
||||||
|
|
||||||
// add relationships showing packages that are evident by a file which is owned by another package (package-to-package)
|
// add relationships showing packages that are evident by a file which is owned by another package (package-to-package)
|
||||||
if cfg.PackageFileOwnershipOverlap {
|
if cfg.PackageFileOwnershipOverlap {
|
||||||
byFileOwnershipOverlapWorker(accessor)
|
byFileOwnershipOverlapWorker(accessor)
|
||||||
@@ -21,6 +26,12 @@ func Finalize(builder sbomsync.Builder, cfg cataloging.RelationshipsConfig, src
|
|||||||
excludeBinariesByFileOwnershipOverlap(accessor)
|
excludeBinariesByFileOwnershipOverlap(accessor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add the new relationships for executables to the SBOM
|
||||||
|
newBinaryRelationships := binary.NewDependencyRelationships(resolver, accessor)
|
||||||
|
accessor.WriteToSBOM(func(s *sbom.SBOM) {
|
||||||
|
s.Relationships = append(s.Relationships, newBinaryRelationships...)
|
||||||
|
})
|
||||||
|
|
||||||
// add source "contains package" relationship (source-to-package)
|
// add source "contains package" relationship (source-to-package)
|
||||||
var sourceRelationships []artifact.Relationship
|
var sourceRelationships []artifact.Relationship
|
||||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ func DefaultPackageTaskFactories() PackageTaskFactories {
|
|||||||
},
|
},
|
||||||
pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, "binary",
|
pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, "binary",
|
||||||
),
|
),
|
||||||
|
newSimplePackageTaskFactory(binary.NewELFPackageCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, "binary", "elf-package"),
|
||||||
newSimplePackageTaskFactory(githubactions.NewActionUsageCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, "github", "github-actions"),
|
newSimplePackageTaskFactory(githubactions.NewActionUsageCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, "github", "github-actions"),
|
||||||
newSimplePackageTaskFactory(githubactions.NewWorkflowUsageCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, "github", "github-actions"),
|
newSimplePackageTaskFactory(githubactions.NewWorkflowUsageCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, "github", "github-actions"),
|
||||||
newPackageTaskFactory(
|
newPackageTaskFactory(
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ func (s sourceIdentifierAdapter) ID() artifact.ID {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewRelationshipsTask(cfg cataloging.RelationshipsConfig, src source.Description) Task {
|
func NewRelationshipsTask(cfg cataloging.RelationshipsConfig, src source.Description) Task {
|
||||||
fn := func(_ context.Context, _ file.Resolver, builder sbomsync.Builder) error {
|
fn := func(_ context.Context, resolver file.Resolver, builder sbomsync.Builder) error {
|
||||||
relationship.Finalize(
|
relationship.Finalize(
|
||||||
|
resolver,
|
||||||
builder,
|
builder,
|
||||||
cfg,
|
cfg,
|
||||||
&sourceIdentifierAdapter{desc: src})
|
&sourceIdentifierAdapter{desc: src})
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "anchore.io/schema/syft/json/16.0.5/document",
|
"$id": "anchore.io/schema/syft/json/16.0.6/document",
|
||||||
"$ref": "#/$defs/Document",
|
"$ref": "#/$defs/Document",
|
||||||
"$defs": {
|
"$defs": {
|
||||||
"AlpmDbEntry": {
|
"AlpmDbEntry": {
|
||||||
@@ -630,6 +630,26 @@
|
|||||||
"dso"
|
"dso"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"ElfBinaryPackageNoteJsonPayload": {
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"vendor": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"system": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"sourceRepo": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"commit": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"ElixirMixLockEntry": {
|
"ElixirMixLockEntry": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
@@ -1425,6 +1445,9 @@
|
|||||||
{
|
{
|
||||||
"$ref": "#/$defs/DpkgDbEntry"
|
"$ref": "#/$defs/DpkgDbEntry"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/ElfBinaryPackageNoteJsonPayload"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"$ref": "#/$defs/ElixirMixLockEntry"
|
"$ref": "#/$defs/ElixirMixLockEntry"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ func AllTypes() []any {
|
|||||||
pkg.DotnetDepsEntry{},
|
pkg.DotnetDepsEntry{},
|
||||||
pkg.DotnetPortableExecutableEntry{},
|
pkg.DotnetPortableExecutableEntry{},
|
||||||
pkg.DpkgDBEntry{},
|
pkg.DpkgDBEntry{},
|
||||||
|
pkg.ELFBinaryPackageNoteJSONPayload{},
|
||||||
pkg.ElixirMixLockEntry{},
|
pkg.ElixirMixLockEntry{},
|
||||||
pkg.ErlangRebarLockEntry{},
|
pkg.ErlangRebarLockEntry{},
|
||||||
pkg.GolangBinaryBuildinfoEntry{},
|
pkg.GolangBinaryBuildinfoEntry{},
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ var jsonTypes = makeJSONTypes(
|
|||||||
jsonNames(pkg.DotnetDepsEntry{}, "dotnet-deps-entry", "DotnetDepsMetadata"),
|
jsonNames(pkg.DotnetDepsEntry{}, "dotnet-deps-entry", "DotnetDepsMetadata"),
|
||||||
jsonNames(pkg.DotnetPortableExecutableEntry{}, "dotnet-portable-executable-entry"),
|
jsonNames(pkg.DotnetPortableExecutableEntry{}, "dotnet-portable-executable-entry"),
|
||||||
jsonNames(pkg.DpkgDBEntry{}, "dpkg-db-entry", "DpkgMetadata"),
|
jsonNames(pkg.DpkgDBEntry{}, "dpkg-db-entry", "DpkgMetadata"),
|
||||||
|
jsonNames(pkg.ELFBinaryPackageNoteJSONPayload{}, "elf-binary-package-note-json-payload"),
|
||||||
jsonNames(pkg.RubyGemspec{}, "ruby-gemspec", "GemMetadata"),
|
jsonNames(pkg.RubyGemspec{}, "ruby-gemspec", "GemMetadata"),
|
||||||
jsonNames(pkg.GolangBinaryBuildinfoEntry{}, "go-module-buildinfo-entry", "GolangBinMetadata", "GolangMetadata"),
|
jsonNames(pkg.GolangBinaryBuildinfoEntry{}, "go-module-buildinfo-entry", "GolangBinMetadata", "GolangMetadata"),
|
||||||
jsonNames(pkg.GolangModuleEntry{}, "go-module-entry", "GolangModMetadata"),
|
jsonNames(pkg.GolangModuleEntry{}, "go-module-entry", "GolangModMetadata"),
|
||||||
|
|||||||
@@ -12,3 +12,12 @@ type ClassifierMatch struct {
|
|||||||
Classifier string `mapstructure:"Classifier" json:"classifier"`
|
Classifier string `mapstructure:"Classifier" json:"classifier"`
|
||||||
Location file.Location `mapstructure:"Location" json:"location"`
|
Location file.Location `mapstructure:"Location" json:"location"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ELFBinaryPackageNoteJSONPayload Represents metadata captured from the .note.package section of the binary
|
||||||
|
type ELFBinaryPackageNoteJSONPayload struct {
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
Vendor string `json:"vendor,omitempty"`
|
||||||
|
System string `json:"system,omitempty"`
|
||||||
|
SourceRepo string `json:"sourceRepo,omitempty"`
|
||||||
|
Commit string `json:"commit,omitempty"`
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Adding tests for the Binary cataloger
|
# Adding tests for the Binary classifier cataloger
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> **TL;DR** to add a test for a new classifier:
|
> **TL;DR** to add a test for a new classifier:
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ func fileNameTemplateVersionMatcher(fileNamePattern string, contentTemplate stri
|
|||||||
|
|
||||||
matchMetadata := internal.MatchNamedCaptureGroups(tmplPattern, string(contents))
|
matchMetadata := internal.MatchNamedCaptureGroups(tmplPattern, string(contents))
|
||||||
|
|
||||||
p := newPackage(classifier, location, matchMetadata)
|
p := newClassifierPackage(classifier, location, matchMetadata)
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ func FileContentsVersionMatcher(pattern string) EvidenceMatcher {
|
|||||||
|
|
||||||
matchMetadata := internal.MatchNamedCaptureGroups(pat, string(contents))
|
matchMetadata := internal.MatchNamedCaptureGroups(pat, string(contents))
|
||||||
|
|
||||||
p := newPackage(classifier, location, matchMetadata)
|
p := newClassifierPackage(classifier, location, matchMetadata)
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
var emptyPURL = packageurl.PackageURL{}
|
var emptyPURL = packageurl.PackageURL{}
|
||||||
|
|
||||||
func newPackage(classifier Classifier, location file.Location, matchMetadata map[string]string) *pkg.Package {
|
func newClassifierPackage(classifier Classifier, location file.Location, matchMetadata map[string]string) *pkg.Package {
|
||||||
version, ok := matchMetadata["version"]
|
version, ok := matchMetadata["version"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package binary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anchore/packageurl-go"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newELFPackage(metadata elfBinaryPackageNotes, locations file.LocationSet, licenses []pkg.License) pkg.Package {
|
||||||
|
p := pkg.Package{
|
||||||
|
Name: metadata.Name,
|
||||||
|
Version: metadata.Version,
|
||||||
|
Licenses: pkg.NewLicenseSet(licenses...),
|
||||||
|
PURL: packageURL(metadata),
|
||||||
|
Type: pkg.BinaryPkg,
|
||||||
|
Locations: locations,
|
||||||
|
Metadata: metadata.ELFBinaryPackageNoteJSONPayload,
|
||||||
|
}
|
||||||
|
|
||||||
|
p.SetID()
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func packageURL(metadata elfBinaryPackageNotes) string {
|
||||||
|
// TODO: what if the System value is not set?
|
||||||
|
return packageurl.NewPackageURL(
|
||||||
|
packageurl.TypeGeneric,
|
||||||
|
metadata.System,
|
||||||
|
metadata.Name,
|
||||||
|
metadata.Version,
|
||||||
|
nil,
|
||||||
|
"",
|
||||||
|
).ToString()
|
||||||
|
}
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
package binary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"debug/elf"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/internal/log"
|
||||||
|
"github.com/anchore/syft/internal/mimetype"
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/internal/unionreader"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ pkg.Cataloger = (*elfPackageCataloger)(nil)
|
||||||
|
|
||||||
|
type elfPackageCataloger struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: for now this accounts for a single data shape from the .note.package section of an ELF binary.
|
||||||
|
// In the future, this should be generalized to support multiple data shapes, including non-json data.
|
||||||
|
// For example, fedora includes an ELF section header as a prefix to the JSON payload: https://github.com/anchore/syft/issues/2713
|
||||||
|
|
||||||
|
type elfBinaryPackageNotes struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
PURL string `json:"purl"`
|
||||||
|
CPE string `json:"cpe"`
|
||||||
|
License string `json:"license"`
|
||||||
|
pkg.ELFBinaryPackageNoteJSONPayload `json:",inline"`
|
||||||
|
Location file.Location `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type elfPackageKey struct {
|
||||||
|
Name string
|
||||||
|
Version string
|
||||||
|
PURL string
|
||||||
|
CPE string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewELFPackageCataloger() pkg.Cataloger {
|
||||||
|
return &elfPackageCataloger{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *elfPackageCataloger) Name() string {
|
||||||
|
return "elf-binary-package-cataloger"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *elfPackageCataloger) Catalog(_ context.Context, resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
|
locations, err := resolver.FilesByMIMEType(mimetype.ExecutableMIMETypeSet.List()...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("unable to get binary files by mime type: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// first find all ELF binaries that have notes
|
||||||
|
var notesByLocation = make(map[elfPackageKey][]elfBinaryPackageNotes)
|
||||||
|
for _, location := range locations {
|
||||||
|
reader, err := resolver.FileContentsByLocation(location)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("unable to get binary contents %q: %w", location.Path(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
notes, err := c.parseElfNotes(file.LocationReadCloser{
|
||||||
|
Location: location,
|
||||||
|
ReadCloser: reader,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.WithFields("file", location.Path(), "error", err).Trace("unable to parse ELF notes")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if notes == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
notes.Location = location
|
||||||
|
key := elfPackageKey{
|
||||||
|
Name: notes.Name,
|
||||||
|
Version: notes.Version,
|
||||||
|
PURL: notes.PURL,
|
||||||
|
CPE: notes.CPE,
|
||||||
|
}
|
||||||
|
notesByLocation[key] = append(notesByLocation[key], *notes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we have all ELF binaries that have notes, let's create packages for them.
|
||||||
|
// we do this in a second pass since it is possible that we have multiple ELF binaries with the same name and version
|
||||||
|
// which means the set of binaries collectively represent a single logical package.
|
||||||
|
var pkgs []pkg.Package
|
||||||
|
for _, notes := range notesByLocation {
|
||||||
|
noteLocations := file.NewLocationSet()
|
||||||
|
for _, note := range notes {
|
||||||
|
noteLocations.Add(note.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation))
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a package for each unique name/version pair (based on the first note found)
|
||||||
|
pkgs = append(pkgs, newELFPackage(notes[0], noteLocations, nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// why not return relationships? We have an executable cataloger that will note the dynamic libraries imported by
|
||||||
|
// each binary. After all files and packages are processed there is a final task that creates package-to-package
|
||||||
|
// and package-to-file relationships based on the dynamic libraries imported by each binary.
|
||||||
|
return pkgs, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *elfPackageCataloger) parseElfNotes(reader file.LocationReadCloser) (*elfBinaryPackageNotes, error) {
|
||||||
|
metadata, err := getELFNotes(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to process ELF binary: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if metadata == nil || metadata.Name == "" || metadata.Version == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadata, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getELFNotes(r file.LocationReadCloser) (*elfBinaryPackageNotes, error) {
|
||||||
|
unionReader, err := unionreader.GetUnionReader(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to get union reader for binary: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := elf.NewFile(unionReader)
|
||||||
|
if f == nil || err != nil {
|
||||||
|
log.WithFields("file", r.Location.Path(), "error", err).Trace("unable to parse binary as ELF")
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
noteSection := f.Section(".note.package")
|
||||||
|
if noteSection == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
notes, err := noteSection.Data()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var metadata elfBinaryPackageNotes
|
||||||
|
if err := json.Unmarshal(notes, &metadata); err != nil {
|
||||||
|
log.WithFields("file", r.Location.Path(), "error", err).Trace("unable to unmarshal ELF package notes as JSON")
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &metadata, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package binary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_ELF_Package_Cataloger(t *testing.T) {
|
||||||
|
expectedPkgs := []pkg.Package{
|
||||||
|
{
|
||||||
|
Name: "libhello_world.so",
|
||||||
|
Version: "0.01",
|
||||||
|
PURL: "pkg:generic/syftsys/libhello_world.so@0.01",
|
||||||
|
FoundBy: "",
|
||||||
|
Locations: file.NewLocationSet(
|
||||||
|
file.NewVirtualLocation("/usr/local/bin/elftests/elfbinwithnestedlib/bin/lib/libhello_world.so", "/usr/local/bin/elftests/elfbinwithnestedlib/bin/lib/libhello_world.so"),
|
||||||
|
file.NewVirtualLocation("/usr/local/bin/elftests/elfbinwithsisterlib/lib/libhello_world.so", "/usr/local/bin/elftests/elfbinwithsisterlib/lib/libhello_world.so"),
|
||||||
|
file.NewVirtualLocation("/usr/local/bin/elftests/elfbinwithsisterlib/lib/libhello_world2.so", "/usr/local/bin/elftests/elfbinwithsisterlib/lib/libhello_world2.so"),
|
||||||
|
),
|
||||||
|
Language: "",
|
||||||
|
Type: pkg.BinaryPkg,
|
||||||
|
Metadata: pkg.ELFBinaryPackageNoteJSONPayload{
|
||||||
|
Type: "testfixture",
|
||||||
|
Vendor: "syft",
|
||||||
|
System: "syftsys",
|
||||||
|
SourceRepo: "https://github.com/someone/somewhere.git",
|
||||||
|
Commit: "5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "syfttestfixture",
|
||||||
|
Version: "0.01",
|
||||||
|
PURL: "pkg:generic/syftsys/syfttestfixture@0.01",
|
||||||
|
FoundBy: "",
|
||||||
|
Locations: file.NewLocationSet(
|
||||||
|
file.NewLocation("/usr/local/bin/elftests/elfbinwithnestedlib/bin/elfbinwithnestedlib").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||||
|
file.NewLocation("/usr/local/bin/elftests/elfbinwithsisterlib/bin/elfwithparallellibbin1").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||||
|
file.NewLocation("/usr/local/bin/elftests/elfbinwithsisterlib/bin/elfwithparallellibbin2").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||||
|
),
|
||||||
|
Language: "",
|
||||||
|
Type: pkg.BinaryPkg,
|
||||||
|
Metadata: pkg.ELFBinaryPackageNoteJSONPayload{
|
||||||
|
Type: "testfixture",
|
||||||
|
Vendor: "syft",
|
||||||
|
System: "syftsys",
|
||||||
|
SourceRepo: "https://github.com/someone/somewhere.git",
|
||||||
|
Commit: "5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgtest.NewCatalogTester().
|
||||||
|
WithImageResolver(t, "elf-test-fixtures").
|
||||||
|
IgnoreLocationLayer(). // this fixture can be rebuilt, thus the layer ID will change
|
||||||
|
Expects(expectedPkgs, nil).
|
||||||
|
TestCataloger(t, NewELFPackageCataloger())
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
package binary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_packageURL(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
notes elfBinaryPackageNotes
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "elf-binary-package-cataloger",
|
||||||
|
notes: elfBinaryPackageNotes{
|
||||||
|
Name: "github.com/anchore/syft",
|
||||||
|
Version: "v0.1.0",
|
||||||
|
ELFBinaryPackageNoteJSONPayload: pkg.ELFBinaryPackageNoteJSONPayload{
|
||||||
|
System: "syftsys",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: "pkg:generic/syftsys/github.com/anchore/syft@v0.1.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "elf binary package short name",
|
||||||
|
notes: elfBinaryPackageNotes{
|
||||||
|
Name: "go.opencensus.io",
|
||||||
|
Version: "v0.23.0",
|
||||||
|
ELFBinaryPackageNoteJSONPayload: pkg.ELFBinaryPackageNoteJSONPayload{
|
||||||
|
System: "syftsys",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: "pkg:generic/syftsys/go.opencensus.io@v0.23.0",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
assert.Equal(t, test.expected, packageURL(test.notes))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_newELFPackage(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
metadata elfBinaryPackageNotes
|
||||||
|
expected pkg.Package
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "elf-binary-package-cataloger",
|
||||||
|
metadata: elfBinaryPackageNotes{
|
||||||
|
Name: "syfttestfixture",
|
||||||
|
Version: "0.01",
|
||||||
|
PURL: "pkg:generic/syftsys/syfttestfixture@0.01",
|
||||||
|
CPE: "cpe:/o:syft:syftsys_testfixture_syfttestfixture:0.01",
|
||||||
|
ELFBinaryPackageNoteJSONPayload: pkg.ELFBinaryPackageNoteJSONPayload{
|
||||||
|
Type: "binary",
|
||||||
|
System: "syftsys",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
expected: pkg.Package{
|
||||||
|
Name: "syfttestfixture",
|
||||||
|
Version: "0.01",
|
||||||
|
Type: "binary",
|
||||||
|
PURL: "pkg:generic/syftsys/syfttestfixture@0.01",
|
||||||
|
Metadata: pkg.ELFBinaryPackageNoteJSONPayload{
|
||||||
|
Type: "binary",
|
||||||
|
System: "syftsys",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
actual := newELFPackage(test.metadata, file.NewLocationSet(), nil)
|
||||||
|
if diff := cmp.Diff(test.expected, actual, cmpopts.IgnoreFields(pkg.Package{}, "id"), cmpopts.IgnoreUnexported(pkg.Package{}, file.LocationSet{}, pkg.LicenseSet{})); diff != "" {
|
||||||
|
t.Errorf("newELFPackage() mismatch (-want +got):\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
FROM rockylinux:8
|
||||||
|
RUN dnf update -y; \
|
||||||
|
dnf install make automake gcc gcc-c++ kernel-devel -y; \
|
||||||
|
dnf clean all
|
||||||
|
RUN mkdir -p /usr/local/bin/elftests/elfbinwithnestedlib
|
||||||
|
RUN mkdir -p /usr/local/bin/elftests/elfbinwithsisterlib
|
||||||
|
COPY ./elfbinwithnestedlib /usr/local/bin/elftests/elfbinwithnestedlib
|
||||||
|
COPY ./elfbinwithsisterlib /usr/local/bin/elftests/elfbinwithsisterlib
|
||||||
|
ENV LD_LIBRARY_PATH=/usr/local/bin/elftests/elfbinwithnestedlib/bin/lib
|
||||||
|
WORKDIR /usr/local/bin/elftests/elfbinwithnestedlib/
|
||||||
|
RUN make
|
||||||
|
WORKDIR /usr/local/bin/elftests/elfbinwithsisterlib
|
||||||
|
RUN make
|
||||||
|
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include "hello_world.h"
|
||||||
|
|
||||||
|
void print_hello_world() {
|
||||||
|
std::cout << "Hello, World!" << std::endl;
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
#ifndef HELLO_WORLD_H
|
||||||
|
#define HELLO_WORLD_H
|
||||||
|
|
||||||
|
// Function declaration for printing "Hello, World!" to stdout
|
||||||
|
void print_hello_world();
|
||||||
|
|
||||||
|
#endif // HELLO_WORLD_H
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
LDFLAGS := -L/lib64 -lstdc++
|
||||||
|
|
||||||
|
SRC_DIR := ./
|
||||||
|
BUILD_DIR := ../build
|
||||||
|
BIN_DIR := ../bin
|
||||||
|
LIB_DIR := $(BIN_DIR)/lib
|
||||||
|
|
||||||
|
LIB_NAME := hello_world
|
||||||
|
LIB_SRC := $(SRC_DIR)/hello_world.cpp
|
||||||
|
LIB_OBJ := $(BUILD_DIR)/$(LIB_NAME).o
|
||||||
|
LIB_SO := $(LIB_DIR)/lib$(LIB_NAME).so
|
||||||
|
|
||||||
|
EXECUTABLE := elfbinwithnestedlib
|
||||||
|
EXEC_SRC := $(SRC_DIR)/testbin.cpp
|
||||||
|
EXEC_OBJ := $(BUILD_DIR)/$(EXECUTABLE).o
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
all: testfixture
|
||||||
|
|
||||||
|
$(LIB_SO): $(LIB_OBJ) | $(LIB_DIR)
|
||||||
|
$(CC) -shared -o $@ $<
|
||||||
|
echo '{"type": "testfixture","license":"MIT","commit":"5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb","sourceRepo":"https://github.com/someone/somewhere.git","vendor": "syft","system": "syftsys","name": "libhello_world.so","version": "0.01","purl": "pkg:generic/syftsys/syfttestfixture@0.01","cpe": "cpe:/o:syft:syftsys_testfixture_syfttestfixture:0.01"}' | objcopy --add-section .note.package=/dev/stdin --set-section-flags .note.package=noload,readonly $@
|
||||||
|
|
||||||
|
$(LIB_OBJ): $(LIB_SRC) | $(BUILD_DIR)
|
||||||
|
$(CC) $(CFLAGS) -fPIC -c $< -o $@
|
||||||
|
|
||||||
|
$(EXEC_OBJ): $(EXEC_SRC) | $(BUILD_DIR)
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(BIN_DIR):
|
||||||
|
mkdir -p $(BIN_DIR)
|
||||||
|
$(BUILD_DIR):
|
||||||
|
mkdir -p $(BUILD_DIR)
|
||||||
|
$(LIB_DIR):
|
||||||
|
mkdir -p $(LIB_DIR)
|
||||||
|
|
||||||
|
$(BIN_DIR)/$(EXECUTABLE): $(EXEC_OBJ) $(LIB_SO) | $(BIN_DIR)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ -L$(LIB_DIR) -l$(LIB_NAME) $(LDFLAGS)
|
||||||
|
echo '{"type": "testfixture","license":"MIT","commit":"5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb","sourceRepo":"https://github.com/someone/somewhere.git","vendor": "syft","system": "syftsys","name": "syfttestfixture","version": "0.01","purl": "pkg:generic/syftsys/syfttestfixture@0.01","cpe": "cpe:/o:syft:syftsys_testfixture_syfttestfixture:0.01"}' | objcopy --add-section .note.package=/dev/stdin --set-section-flags .note.package=noload,readonly $@
|
||||||
|
|
||||||
|
testfixture: $(BIN_DIR)/$(EXECUTABLE)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(BUILD_DIR) $(LIB_DIR) $(BIN_DIR) $(EXECUTABLE)
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
#include "hello_world.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Call the function from the shared library
|
||||||
|
print_hello_world();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
CC = g++
|
||||||
|
CFLAGS = -std=c++17 -Wall -Wextra -pedantic
|
||||||
|
BUILD_DIR := ./build
|
||||||
|
BIN_DIR := ./bin
|
||||||
|
LIB_DIR := $(BIN_DIR)/lib
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
all: testfixtures
|
||||||
|
|
||||||
|
testfixtures:
|
||||||
|
$(MAKE) -C elfsrc
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(BUILD_DIR) $(BIN_DIR)
|
||||||
|
|
||||||
|
.PHONY: all clean testfixtures
|
||||||
|
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include "hello_world.h"
|
||||||
|
|
||||||
|
void print_hello_world() {
|
||||||
|
std::cout << "Hello, World!" << std::endl;
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
#ifndef HELLO_WORLD_H
|
||||||
|
#define HELLO_WORLD_H
|
||||||
|
|
||||||
|
// Function declaration for printing "Hello, World!" to stdout
|
||||||
|
void print_hello_world();
|
||||||
|
|
||||||
|
#endif // HELLO_WORLD_H
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
LDFLAGS := -L/lib64 -lstdc++
|
||||||
|
|
||||||
|
SRC_DIR := ./
|
||||||
|
BUILD_DIR := ../build
|
||||||
|
LIB_DIR := ../lib
|
||||||
|
BIN_DIR := ../bin
|
||||||
|
|
||||||
|
LIB_NAME := hello_world
|
||||||
|
LIB_SRC := $(SRC_DIR)/hello_world.cpp
|
||||||
|
LIB_OBJ := $(BUILD_DIR)/$(LIB_NAME).o
|
||||||
|
LIB_SO := $(LIB_DIR)/lib$(LIB_NAME).so
|
||||||
|
|
||||||
|
EXECUTABLE := elfwithparallellibbin1
|
||||||
|
EXEC_SRC := $(SRC_DIR)/testbin.cpp
|
||||||
|
EXEC_OBJ := $(BUILD_DIR)/$(EXECUTABLE).o
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
all: testfixture
|
||||||
|
|
||||||
|
$(LIB_SO): $(LIB_OBJ) | $(LIB_DIR)
|
||||||
|
$(CC) -shared -o $@ $<
|
||||||
|
echo '{"type": "testfixture","license":"MIT","commit":"5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb","sourceRepo":"https://github.com/someone/somewhere.git","vendor": "syft","system": "syftsys","name": "libhello_world.so","version": "0.01","purl": "pkg:generic/syftsys/syfttestfixture@0.01","cpe": "cpe:/o:syft:syftsys_testfixture_syfttestfixture:0.01"}' | objcopy --add-section .note.package=/dev/stdin --set-section-flags .note.package=noload,readonly $@
|
||||||
|
|
||||||
|
$(LIB_OBJ): $(LIB_SRC) | $(BUILD_DIR)
|
||||||
|
$(CC) $(CFLAGS) -fPIC -c $< -o $@
|
||||||
|
|
||||||
|
$(EXEC_OBJ): $(EXEC_SRC) | $(BUILD_DIR)
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(BIN_DIR):
|
||||||
|
mkdir -p $(BIN_DIR)
|
||||||
|
$(BUILD_DIR):
|
||||||
|
mkdir -p $(BUILD_DIR)
|
||||||
|
$(LIB_DIR):
|
||||||
|
mkdir -p $(LIB_DIR)
|
||||||
|
|
||||||
|
$(BIN_DIR)/$(EXECUTABLE): $(EXEC_OBJ) $(LIB_SO) | $(BIN_DIR)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ -L$(LIB_DIR) -l$(LIB_NAME) $(LDFLAGS)
|
||||||
|
echo '{"type": "testfixture","license":"MIT","commit":"5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb","sourceRepo":"https://github.com/someone/somewhere.git","vendor": "syft","system": "syftsys","name": "syfttestfixture","version": "0.01","purl": "pkg:generic/syftsys/syfttestfixture@0.01","cpe": "cpe:/o:syft:syftsys_testfixture_syfttestfixture:0.01"}' | objcopy --add-section .note.package=/dev/stdin --set-section-flags .note.package=noload,readonly $@
|
||||||
|
|
||||||
|
testfixture: $(BIN_DIR)/$(EXECUTABLE)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(BUILD_DIR) $(LIB_DIR) $(BIN_DIR) $(EXECUTABLE)
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
#include "hello_world.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Call the function from the shared library
|
||||||
|
print_hello_world();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include "hello_world2.h"
|
||||||
|
|
||||||
|
void print_hello_world() {
|
||||||
|
std::cout << "Hello, World again!!" << std::endl;
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
#ifndef HELLO_WORLD2_H
|
||||||
|
#define HELLO_WORLD2_H
|
||||||
|
|
||||||
|
// Function declaration for printing "Hello, World!" to stdout
|
||||||
|
void print_hello_world();
|
||||||
|
|
||||||
|
#endif // HELLO_WORLD2_H
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
LDFLAGS := -L/lib64 -lstdc++
|
||||||
|
|
||||||
|
SRC_DIR := ./
|
||||||
|
BUILD_DIR := ../build
|
||||||
|
LIB_DIR := ../lib
|
||||||
|
BIN_DIR := ../bin
|
||||||
|
|
||||||
|
LIB_NAME := hello_world2
|
||||||
|
LIB_SRC := $(SRC_DIR)/hello_world2.cpp
|
||||||
|
LIB_OBJ := $(BUILD_DIR)/$(LIB_NAME).o
|
||||||
|
LIB_SO := $(LIB_DIR)/lib$(LIB_NAME).so
|
||||||
|
|
||||||
|
EXECUTABLE := elfwithparallellibbin2
|
||||||
|
EXEC_SRC := $(SRC_DIR)/testbin2.cpp
|
||||||
|
EXEC_OBJ := $(BUILD_DIR)/$(EXECUTABLE).o
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
all: testfixture
|
||||||
|
|
||||||
|
$(LIB_SO): $(LIB_OBJ) | $(LIB_DIR)
|
||||||
|
$(CC) -shared -o $@ $<
|
||||||
|
echo '{"type": "testfixture","license":"MIT","commit":"5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb","sourceRepo":"https://github.com/someone/somewhere.git","vendor": "syft","system": "syftsys","name": "libhello_world.so","version": "0.01","purl": "pkg:generic/syftsys/syfttestfixture@0.01","cpe": "cpe:/o:syft:syftsys_testfixture_syfttestfixture:0.01"}' | objcopy --add-section .note.package=/dev/stdin --set-section-flags .note.package=noload,readonly $@
|
||||||
|
|
||||||
|
$(LIB_OBJ): $(LIB_SRC) | $(BUILD_DIR)
|
||||||
|
$(CC) $(CFLAGS) -fPIC -c $< -o $@
|
||||||
|
|
||||||
|
$(EXEC_OBJ): $(EXEC_SRC) | $(BUILD_DIR)
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(BIN_DIR):
|
||||||
|
mkdir -p $(BIN_DIR)
|
||||||
|
$(BUILD_DIR):
|
||||||
|
mkdir -p $(BUILD_DIR)
|
||||||
|
$(LIB_DIR):
|
||||||
|
mkdir -p $(LIB_DIR)
|
||||||
|
|
||||||
|
$(BIN_DIR)/$(EXECUTABLE): $(EXEC_OBJ) $(LIB_SO) | $(BIN_DIR)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ -L$(LIB_DIR) -l$(LIB_NAME) $(LDFLAGS)
|
||||||
|
echo '{"type": "testfixture","license":"MIT","commit":"5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb","sourceRepo":"https://github.com/someone/somewhere.git","vendor": "syft","system": "syftsys","name": "syfttestfixture","version": "0.01","purl": "pkg:generic/syftsys/syfttestfixture@0.01","cpe": "cpe:/o:syft:syftsys_testfixture_syfttestfixture:0.01"}' | objcopy --add-section .note.package=/dev/stdin --set-section-flags .note.package=noload,readonly $@
|
||||||
|
|
||||||
|
testfixture: $(BIN_DIR)/$(EXECUTABLE)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(BUILD_DIR) $(LIB_DIR) $(BIN_DIR) $(EXECUTABLE)
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
#include "hello_world2.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Call the function from the shared library
|
||||||
|
print_hello_world();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
CC = g++
|
||||||
|
CFLAGS = -std=c++17 -Wall -Wextra -pedantic
|
||||||
|
BUILD_DIR := ./build
|
||||||
|
LIB_DIR := ./lib
|
||||||
|
BIN_DIR := ./bin
|
||||||
|
|
||||||
|
|
||||||
|
all: testfixtures
|
||||||
|
|
||||||
|
testfixtures:
|
||||||
|
$(MAKE) -C elfsrc1
|
||||||
|
$(MAKE) -C elfsrc2
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(BUILD_DIR) $(LIB_DIR) $(BIN_DIR)
|
||||||
|
|
||||||
|
.PHONY: all clean testfixtures
|
||||||
|
|
||||||
Reference in New Issue
Block a user