Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pkg/sca/sca.go: Implement getLdSoConfDLibPaths #1850

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions pkg/sca/sca.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package sca

import (
"bufio"
"bytes"
"context"
"debug/buildinfo"
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -804,5 +894,9 @@ func Analyze(ctx context.Context, hdl SCAHandle, generated *config.Dependencies)
generated.Provides = nil
}

if oldLibDirs != nil {
libDirs = oldLibDirs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This frightens me a bit -- instead of mutating the global here do you mind plumbing this around everywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For sure. But let me take the opportunity and ask a broader question.

I thought about moving libDirs inside the SCABuildInterface, because this really should be a per-package variable. However, SCABuildInterface only represents one single entity in the package (either the sole package, or one of its subpackages if they exist). I couldn't find a way to say "hey, this applies to the package and its subpackages".

The reason I wanted to do it is because, as you can see now, getLdSoConfDLibPaths is being invoked for the package and its subpackages, and it iterates over all files from them, every time. This is suboptimal.

Something else I thought about is that we could have a global flag to signal whether getLdSoConfDLibPaths was already invoked. But then I have another question: is it guaranteed that we will be dealing with only one package (and its subpackages)?

Sorry for the barrage of questions and thoughts; this code is new to me and I'm trying to make sense of how to best implement what I need here. Thanks!

}

return nil
}
20 changes: 19 additions & 1 deletion pkg/sca/sca_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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])
}
}
}
Binary file not shown.
25 changes: 25 additions & 0 deletions pkg/sca/testdata/ld-so-conf-d-test.yaml
Original file line number Diff line number Diff line change
@@ -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
Loading