feat: elf_binary_package_cataloger

Signed-off-by: Brian Ebarb <brian.ebarb@cgifederal.com>
This commit is contained in:
Brian Ebarb 2024-03-13 14:34:06 -05:00 committed by Alex Goodman
parent 5534c38d0f
commit a35f64c971
32 changed files with 739 additions and 5 deletions

View File

@ -117,6 +117,7 @@ func DefaultPackageTaskFactories() PackageTaskFactories {
},
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.NewWorkflowUsageCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, "github", "github-actions"),
newPackageTaskFactory(

View File

@ -630,6 +630,33 @@
"dso"
]
},
"ElfBinaryPackageNotes": {
"properties": {
"type": {
"type": "string"
},
"vendor": {
"type": "string"
},
"system": {
"type": "string"
},
"sourceRepo": {
"type": "string"
},
"commit": {
"type": "string"
}
},
"type": "object",
"required": [
"type",
"vendor",
"system",
"sourceRepo",
"commit"
]
},
"ElixirMixLockEntry": {
"properties": {
"name": {
@ -1410,6 +1437,9 @@
{
"$ref": "#/$defs/DpkgDbEntry"
},
{
"$ref": "#/$defs/ElfBinaryPackageNotes"
},
{
"$ref": "#/$defs/ElixirMixLockEntry"
},

View File

@ -630,6 +630,33 @@
"dso"
]
},
"ElfBinaryPackageNotes": {
"properties": {
"type": {
"type": "string"
},
"vendor": {
"type": "string"
},
"system": {
"type": "string"
},
"sourceRepo": {
"type": "string"
},
"commit": {
"type": "string"
}
},
"type": "object",
"required": [
"type",
"vendor",
"system",
"sourceRepo",
"commit"
]
},
"ElixirMixLockEntry": {
"properties": {
"name": {
@ -1425,6 +1452,9 @@
{
"$ref": "#/$defs/DpkgDbEntry"
},
{
"$ref": "#/$defs/ElfBinaryPackageNotes"
},
{
"$ref": "#/$defs/ElixirMixLockEntry"
},

View File

@ -19,6 +19,7 @@ func AllTypes() []any {
pkg.DotnetDepsEntry{},
pkg.DotnetPortableExecutableEntry{},
pkg.DpkgDBEntry{},
pkg.ELFBinaryPackageNotes{},
pkg.ElixirMixLockEntry{},
pkg.ErlangRebarLockEntry{},
pkg.GolangBinaryBuildinfoEntry{},

View File

@ -74,6 +74,7 @@ var jsonTypes = makeJSONTypes(
jsonNames(pkg.DotnetDepsEntry{}, "dotnet-deps-entry", "DotnetDepsMetadata"),
jsonNames(pkg.DotnetPortableExecutableEntry{}, "dotnet-portable-executable-entry"),
jsonNames(pkg.DpkgDBEntry{}, "dpkg-db-entry", "DpkgMetadata"),
jsonNames(pkg.ELFBinaryPackageNotes{}, "elf-binary-package-notes"),
jsonNames(pkg.RubyGemspec{}, "ruby-gemspec", "GemMetadata"),
jsonNames(pkg.GolangBinaryBuildinfoEntry{}, "go-module-buildinfo-entry", "GolangBinMetadata", "GolangMetadata"),
jsonNames(pkg.GolangModuleEntry{}, "go-module-entry", "GolangModMetadata"),

View File

@ -12,3 +12,12 @@ type ClassifierMatch struct {
Classifier string `mapstructure:"Classifier" json:"classifier"`
Location file.Location `mapstructure:"Location" json:"location"`
}
// ELFBinaryPackageNotes Represents metadata captured from the .note.package section of the binary
type ELFBinaryPackageNotes struct {
Type string `json:"type"`
Vendor string `json:"vendor"`
System string `json:"system"`
Source string `json:"sourceRepo"`
Commit string `json:"commit"`
}

View File

@ -1,4 +1,4 @@
# Adding tests for the Binary cataloger
# Adding tests for the Binary classifier cataloger
> [!TIP]
> **TL;DR** to add a test for a new classifier:

View File

@ -125,7 +125,7 @@ func fileNameTemplateVersionMatcher(fileNamePattern string, contentTemplate stri
matchMetadata := internal.MatchNamedCaptureGroups(tmplPattern, string(contents))
p := newPackage(classifier, location, matchMetadata)
p := newClassifierPackage(classifier, location, matchMetadata)
if p == nil {
return nil, nil
}
@ -144,7 +144,7 @@ func FileContentsVersionMatcher(pattern string) EvidenceMatcher {
matchMetadata := internal.MatchNamedCaptureGroups(pat, string(contents))
p := newPackage(classifier, location, matchMetadata)
p := newClassifierPackage(classifier, location, matchMetadata)
if p == nil {
return nil, nil
}

View File

@ -11,7 +11,7 @@ import (
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"]
if !ok {
return nil

View File

@ -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.ELFBinaryPackageNotes,
}
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()
}

View File

@ -0,0 +1,147 @@
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 {
}
type elfBinaryPackageNotes struct {
Name string `json:"name"`
Version string `json:"version"`
PURL string `json:"purl"`
CPE string `json:"cpe"`
License string `json:"license"`
pkg.ELFBinaryPackageNotes `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.Warnf("unable to parse ELF notes: %v", err)
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 {
log.WithFields("error", err).Trace("unable to read .note.package")
return nil, err
}
var metadata elfBinaryPackageNotes
if err := json.Unmarshal(notes, &metadata); err != nil {
log.WithFields("error", err).Trace("unable to unmarshal ELF package notes as JSON")
return nil, nil
}
return &metadata, err
}

View File

@ -0,0 +1,124 @@
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.ELFBinaryPackageNotes{
Type: "testfixture",
Vendor: "syft",
System: "syftsys",
Source: "",
Commit: "",
},
},
{
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.ELFBinaryPackageNotes{
Type: "testfixture",
Vendor: "syft",
System: "syftsys",
Source: "",
Commit: "",
},
},
}
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())
// 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/syftelftest/lib/libhello_world.so", "/usr/local/bin/syftelftest/lib/libhello_world.so")),
// Language: "",
// Type: pkg.BinaryPkg,
// Metadata: pkg.ELFBinaryPackageNotes{
// Type: "testfixture",
// Vendor: "syft",
// System: "syftsys",
// },
// },
// {
// Name: "syfttestfixture",
// Version: "0.01",
// PURL: "pkg:generic/syftsys/syfttestfixture@0.01",
// FoundBy: "",
// Locations: file.NewLocationSet(file.NewVirtualLocation("/usr/local/bin/syftelftest/bin/elfwithparallellibbin1", "/usr/local/bin/syftelftest/bin/elfwithparallellibbin1")),
// Language: "",
// Type: pkg.BinaryPkg,
// Metadata: pkg.ELFBinaryPackageNotes{
// Type: "testfixture",
// Vendor: "syft",
// System: "syftsys",
// },
// },
// {
// Name: "libhello_world2.so",
// Version: "0.01",
// PURL: "pkg:generic/syftsys/libhello_world2.so@0.01",
// FoundBy: "",
// Locations: file.NewLocationSet(file.NewVirtualLocation("/usr/local/bin/syftelftest/lib/libhello_world2.so", "/usr/local/bin/syftelftest/lib/libhello_world2.so")),
// Language: "",
// Type: pkg.BinaryPkg,
// Metadata: pkg.ELFBinaryPackageNotes{
// Type: "testfixture",
// Vendor: "syft",
// System: "syftsys",
// },
// },
// {
// Name: "syfttestfixture",
// Version: "0.01",
// PURL: "pkg:generic/syftsys/syfttestfixture@0.01",
// FoundBy: "",
// Locations: file.NewLocationSet(file.NewVirtualLocation("/usr/local/bin/syftelftest/bin/elfwithparallellibbin2", "/usr/local/bin/syftelftest/bin/elfwithparallellibbin2")),
// Language: "",
// Type: pkg.BinaryPkg,
// Metadata: pkg.ELFBinaryPackageNotes{
// Type: "testfixture",
// Vendor: "syft",
// System: "syftsys",
// },
// },
// }
// pkgtest.NewCatalogTester().
// WithImageResolver(t, "elf-test-fixture-sister-lib").
// IgnoreLocationLayer(). // this fixture can be rebuilt, thus the layer ID will change
// Expects(expectedPkgs, nil).
// TestCataloger(t, NewELFPackageCataloger())
}

View File

@ -0,0 +1,96 @@
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",
ELFBinaryPackageNotes: pkg.ELFBinaryPackageNotes{
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",
ELFBinaryPackageNotes: pkg.ELFBinaryPackageNotes{
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",
ELFBinaryPackageNotes: pkg.ELFBinaryPackageNotes{
Type: "binary",
System: "syftsys",
},
},
expected: pkg.Package{
Name: "syfttestfixture",
Version: "0.01",
Type: "binary",
PURL: "pkg:generic/syftsys/syfttestfixture@0.01",
Metadata: pkg.ELFBinaryPackageNotes{
Type: "binary",
System: "syftsys",
},
},
},
}
// for _, test := range tests {
// t.Run(test.name, func(t *testing.T) {
// assert.Equal(t, test.expected, newELFPackage(test.metadata, file.NewLocationSet(), nil))
// })
// }
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)
}
})
}
}

View File

@ -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

View File

@ -0,0 +1,6 @@
#include <iostream>
#include "hello_world.h"
void print_hello_world() {
std::cout << "Hello, World!" << std::endl;
}

View File

@ -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

View File

@ -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","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","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

View File

@ -0,0 +1,8 @@
#include "hello_world.h"
int main() {
// Call the function from the shared library
print_hello_world();
return 0;
}

View File

@ -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

View File

@ -0,0 +1,6 @@
#include <iostream>
#include "hello_world.h"
void print_hello_world() {
std::cout << "Hello, World!" << std::endl;
}

View File

@ -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

View File

@ -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","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","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

View File

@ -0,0 +1,8 @@
#include "hello_world.h"
int main() {
// Call the function from the shared library
print_hello_world();
return 0;
}

View File

@ -0,0 +1,6 @@
#include <iostream>
#include "hello_world2.h"
void print_hello_world() {
std::cout << "Hello, World again!!" << std::endl;
}

View File

@ -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

View File

@ -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","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","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

View File

@ -0,0 +1,8 @@
#include "hello_world2.h"
int main() {
// Call the function from the shared library
print_hello_world();
return 0;
}

View File

@ -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

View File

@ -82,7 +82,7 @@ func LanguageByName(name string) Language {
return Dart
case string(Dotnet), ".net", packageurl.TypeNuget:
return Dotnet
case packageurl.TypeCocoapods, packageurl.TypeSwift, string(CocoapodsPkg):
case packageurl.TypeCocoapods, packageurl.TypeSwift, string(CocoapodsPkg), string(SwiftPkg):
return Swift
case packageurl.TypeConan, string(CPP):
return CPP