From ee2f9251b5426cfd7c95205e0ef41d8ab31a68a7 Mon Sep 17 00:00:00 2001 From: Sergio Durigan Junior Date: Tue, 11 Mar 2025 18:31:03 -0400 Subject: [PATCH 1/2] pkg/sca/sca.go: Implement getLdSoConfDLibPaths This commit implements the machinery necessary for SCA to consider files under /etc/ld.so.conf.d/. The idea is that, if there is a configuration for ld.so.conf.d being installed by the package on hand, then the libraries shipped by the package should be listed as "provides" if they're installed inside the paths listed in the ld.so.conf.d configuration file. Signed-off-by: Sergio Durigan Junior --- pkg/sca/sca.go | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) 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 } From d040dd1d9bb1e253d3819dd4e3f0dfcd64b1c49e Mon Sep 17 00:00:00 2001 From: Sergio Durigan Junior Date: Tue, 11 Mar 2025 18:31:40 -0400 Subject: [PATCH 2/2] pkg/sca/sca_test.go et al: Implement test for getLdSoConfDLibPaths This commit implements a simple test to make sure that the new function is properly parsing the configuration file inside /etc/ld.so.conf.d/. A small modification had to be made to the (th *testHandle) RelativeNames() function in order to make TestDocSca pass, because (th *testHandle) FilesystemForRelative() isn't implemented. Signed-off-by: Sergio Durigan Junior --- pkg/sca/sca_test.go | 20 +++++++++++++- .../x86_64/ld-so-conf-d-test-1-r1.apk | Bin 0 -> 2180 bytes pkg/sca/testdata/ld-so-conf-d-test.yaml | 25 ++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 pkg/sca/testdata/generated/x86_64/ld-so-conf-d-test-1-r1.apk create mode 100644 pkg/sca/testdata/ld-so-conf-d-test.yaml 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 0000000000000000000000000000000000000000..3b666c538c2bb6548ded9972eef9104183ce5daf GIT binary patch literal 2180 zcmV-~2z&P*iwFP!32ul0|Lj&lkJ~mA%~`)<;O`hvA|+Y&3eX1xX_^E@x;f-tP~=!9 zERiZnZPsb~-wQHcTf4TK0Bs5c=v*YtYAFkht{SRKFM$0`)X!kH+&vl2% zxa%|@5E|$uafS$^H$)PT&IjxcEi}N0WeK-p3k}?_t6!=zaq3eD%Bymj7^^y^uTe;J zB4VjCX~0qmk$$p0G>`~049Y_T8;(M*QSensHye&66G+)jD`mS9EwW;h-{7XolYuMk zxze$=N$<4zsFPj^)GpNY?(K&}a?iKig@TtiRZf>{K{;P-D!y74d0yS*%a(~&wxy^j zO4$~iuZm*D)`BrkD?#~M;7z%{DUwIq_}yB1c;o4w5B(hY2ki^`FP5}=qW_{;760k~ z-_ZZa#g2DaCjde4^#!p4+@W>K=o%JmkpSRm#I^>O00b3VHTsC2YZ>6PjO(vgaR?dr zR&`q+iUJ^T&~P0k3}Dfj$qIBe{PstJ`c7G+2h?%BFxsQ`F5HKuqjAa`tMK3nd|U5F zS7+Iwcb9%N{YIq{?=s_J+z$6v>Fz5-viLxp>a@~bY8_9MmN6+Q}dmSM5WuRRX|;Fw<#b zOqy_4!y*hifXShqi8nlc9+Oe62S321WDShchiwMv&OC05eSahlwlxDvWoyX7U3Q}E zteM7H+W34a?|GI1hjvzSFmenEXSD-FfDf_?>U=Ul0bbv}yZzziimuZS!V_#qwBEx{fiH89`%r=5zaajSG>7>_v#UzjB3PQ>G;{o4X;y4iIGruCrX{9@3JT$*L{ib~(fRt$gR}-N!5qc^w&pj0m=U=xGs`!5n z{?nskz!eC6-IHeG0e?`qk{yw=7)oe_H;v z#1+%h%+uj;{&kB~{67c(50w83R${Cs5udC7CL%05Iv_L;*8c>VmQmIJ&s_gI7G|Cc z%(Fq)sckeIPPxGuVLGx6*CWhv!J>9mHoV}nVLShyDCG~S{|!Pm{R}lkux^=E{eO!3 z|3_Vt6u+-@TUtIPArT(H>`!t{bpA&DrF?82-xCzt&n|g#;CRmQE8{E3PPX`hf`z{pW*sym=*@TW@ zA6NC&rR8X8S9tibj@zyx9`Lz|_*yGFc7@5!GQ2Ax$amL!egH`;q`~5QE(?za32bIp zB(+7zf*H>ZJ`uNW}ig4>R4# z&22q>2`8cW78YKUSri36JjRrXXc7CPaXN%~x_5V&rx1rUxB{6kB2aYDACXFWAY3HU9`4{(%-qPNX zKUPYFwY(B*?1bHBnu^$!T+N4MJY;*(2-j^P~FH8RCS(cswG} "${{targets.destdir}}"/etc/ld.so.conf.d/ld-so-conf-d-test.conf + +update: + enabled: false