diff --git a/pkg/sca/sca.go b/pkg/sca/sca.go index ca48e9123..58255f3ea 100644 --- a/pkg/sca/sca.go +++ b/pkg/sca/sca.go @@ -15,6 +15,7 @@ package sca import ( + "bufio" "bytes" "context" "debug/buildinfo" @@ -86,6 +87,84 @@ func isInDir(path string, dirs []string) bool { return false } +// getLdSoConfDLibPaths will iterate over the files being installed by +// the package and all its subpackages, and for each configuration +// file found under /etc/ld.so.conf.d/ it will parse the file and add +// its contents to a string vector. This vector will ultimately +// contain all extra paths that will be considered by ld when doing +// symbol resolution. +func getLdSoConfDLibPaths(ctx context.Context, hdl SCAHandle) ([]string, error) { + var extraLibPaths []string + targetPackageNames := hdl.RelativeNames() + + log := clog.FromContext(ctx) + + log.Info("scanning for ld.so.conf.d files...") + + for _, pkgName := range targetPackageNames { + fsys, err := hdl.FilesystemForRelative(pkgName) + if err != nil { + return nil, err + } + + if err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + // We're only interested in files inside /etc/ld.so.conf.d/... + if !isInDir(path, []string{"etc/ld.so.conf.d"}) { + return nil + } + + // ... and whose suffix is ".conf"... + if !strings.HasSuffix(path, ".conf") { + return nil + } + + fi, err := d.Info() + if err != nil { + return err + } + + if !fi.Mode().IsRegular() { + return nil + } + + log.Infof(" found ld.so.conf.d file %s", path) + + fd, err := fsys.Open(path) + if err != nil { + return err + } + defer fd.Close() + + scanner := bufio.NewScanner(fd) + for scanner.Scan() { + line := scanner.Text() + if line[0] != '/' { + continue + } + // Strip the initial slash since + // libDirs paths need to be relative. + line = line[1:] + log.Infof(" found extra lib path %s", line) + extraLibPaths = append(extraLibPaths, line) + } + + if err := scanner.Err(); err != nil { + return err + } + + return nil + }); err != nil { + return nil, err + } + } + + return extraLibPaths, nil +} + func generateCmdProviders(ctx context.Context, hdl SCAHandle, generated *config.Dependencies) error { log := clog.FromContext(ctx) @@ -766,6 +845,17 @@ func generateShbangDeps(ctx context.Context, hdl SCAHandle, generated *config.De // Analyze runs the SCA analyzers on a given SCA handle, modifying the generated dependencies // set as needed. func Analyze(ctx context.Context, hdl SCAHandle, generated *config.Dependencies) error { + var oldLibDirs []string + + extraLibPaths, err := getLdSoConfDLibPaths(ctx, hdl) + if err != nil { + return err + } + if extraLibPaths != nil { + oldLibDirs = libDirs + libDirs = append(libDirs, extraLibPaths...) + } + generators := []DependencyGenerator{ generateSharedObjectNameDeps, generateCmdProviders, @@ -804,5 +894,9 @@ func Analyze(ctx context.Context, hdl SCAHandle, generated *config.Dependencies) generated.Provides = nil } + if oldLibDirs != nil { + libDirs = oldLibDirs + } + return nil } diff --git a/pkg/sca/sca_test.go b/pkg/sca/sca_test.go index f7793c5d4..c3e8ecf0f 100644 --- a/pkg/sca/sca_test.go +++ b/pkg/sca/sca_test.go @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:generate go run ./../../ build --generate-index=false --out-dir=./testdata/generated ./testdata/ld-so-conf-d-test.yaml --arch=x86_64 //go:generate go run ./../../ build --generate-index=false --out-dir=./testdata/generated ./testdata/shbang-test.yaml --arch=x86_64 //go:generate go run ./../../ build --generate-index=false --source-dir=./testdata/go-fips-bin/ --out-dir=./testdata/generated ./testdata/go-fips-bin/go-fips-bin.yaml --arch=x86_64 //go:generate curl -s -o ./testdata/py3-seaborn.yaml https://raw.githubusercontent.com/wolfi-dev/os/7a39ac1d0603a3561790ea2201dd8ad7c2b7e51e/py3-seaborn.yaml @@ -56,7 +57,7 @@ func (th *testHandle) Version() string { func (th *testHandle) RelativeNames() []string { // TODO: Support subpackages? - return []string{th.pkg.Origin} + return []string{th.pkg.Name} } func (th *testHandle) FilesystemForRelative(pkgName string) (SCAFS, error) { @@ -337,3 +338,20 @@ func TestGetShbang(t *testing.T) { } } } + +func TestLdSoConfD(t *testing.T) { + ctx := slogtest.Context(t) + // Generated with `go generate ./...` + th := handleFromApk(ctx, t, "generated/x86_64/ld-so-conf-d-test-1-r1.apk", "ld-so-conf-d-test.yaml") + defer th.exp.Close() + + if extraLibPaths, err := getLdSoConfDLibPaths(ctx, th); err != nil { + t.Fatal(err) + } else if extraLibPaths == nil { + t.Error("getLdSoConfDLibPaths: expected 'my/lib/test', got nil") + } else { + if extraLibPaths[0] != "my/lib/test" { + t.Errorf("getLdSoConfDLibPaths: expected 'my/lib/test', got '%s'", extraLibPaths[0]) + } + } +} diff --git a/pkg/sca/testdata/generated/x86_64/ld-so-conf-d-test-1-r1.apk b/pkg/sca/testdata/generated/x86_64/ld-so-conf-d-test-1-r1.apk new file mode 100644 index 000000000..3b666c538 Binary files /dev/null and b/pkg/sca/testdata/generated/x86_64/ld-so-conf-d-test-1-r1.apk differ diff --git a/pkg/sca/testdata/ld-so-conf-d-test.yaml b/pkg/sca/testdata/ld-so-conf-d-test.yaml new file mode 100644 index 000000000..db9c37fc7 --- /dev/null +++ b/pkg/sca/testdata/ld-so-conf-d-test.yaml @@ -0,0 +1,25 @@ +package: + name: ld-so-conf-d-test + version: 1 + epoch: 1 + description: ld.so.conf.d test + copyright: + - license: MIT + +environment: + contents: + repositories: + - https://packages.wolfi.dev/os + keyring: + - https://packages.wolfi.dev/os/wolfi-signing.rsa.pub + packages: + - build-base + - busybox + +pipeline: + - runs: | + mkdir -p "${{targets.destdir}}"/etc/ld.so.conf.d + echo "/my/lib/test" > "${{targets.destdir}}"/etc/ld.so.conf.d/ld-so-conf-d-test.conf + +update: + enabled: false