fix: discover deb file relationships in distroless images (#1901)

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
This commit is contained in:
Weston Steimel 2023-06-28 13:28:20 +01:00 committed by GitHub
parent 026be3c0f1
commit 8219f8d55b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 198 additions and 65 deletions

View File

@ -9,81 +9,151 @@ import (
) )
func TestDpkgCataloger(t *testing.T) { func TestDpkgCataloger(t *testing.T) {
licenseLocation := file.NewVirtualLocation("/usr/share/doc/libpam-runtime/copyright", "/usr/share/doc/libpam-runtime/copyright") tests := []struct {
expected := []pkg.Package{ name string
expected []pkg.Package
}{
{ {
Name: "libpam-runtime", name: "image-dpkg",
Version: "1.1.8-3.6", expected: []pkg.Package{
FoundBy: "dpkgdb-cataloger", {
Licenses: pkg.NewLicenseSet( Name: "libpam-runtime",
pkg.NewLicenseFromLocations("GPL-1", licenseLocation), Version: "1.1.8-3.6",
pkg.NewLicenseFromLocations("GPL-2", licenseLocation), FoundBy: "dpkgdb-cataloger",
pkg.NewLicenseFromLocations("LGPL-2.1", licenseLocation), Licenses: pkg.NewLicenseSet(
), pkg.NewLicenseFromLocations("GPL-1", file.NewVirtualLocation("/usr/share/doc/libpam-runtime/copyright", "/usr/share/doc/libpam-runtime/copyright")),
Locations: file.NewLocationSet( pkg.NewLicenseFromLocations("GPL-2", file.NewVirtualLocation("/usr/share/doc/libpam-runtime/copyright", "/usr/share/doc/libpam-runtime/copyright")),
file.NewVirtualLocation("/var/lib/dpkg/status", "/var/lib/dpkg/status"), pkg.NewLicenseFromLocations("LGPL-2.1", file.NewVirtualLocation("/usr/share/doc/libpam-runtime/copyright", "/usr/share/doc/libpam-runtime/copyright")),
file.NewVirtualLocation("/var/lib/dpkg/info/libpam-runtime.md5sums", "/var/lib/dpkg/info/libpam-runtime.md5sums"), ),
file.NewVirtualLocation("/var/lib/dpkg/info/libpam-runtime.conffiles", "/var/lib/dpkg/info/libpam-runtime.conffiles"), Locations: file.NewLocationSet(
file.NewVirtualLocation("/usr/share/doc/libpam-runtime/copyright", "/usr/share/doc/libpam-runtime/copyright"), file.NewVirtualLocation("/var/lib/dpkg/status", "/var/lib/dpkg/status"),
), file.NewVirtualLocation("/var/lib/dpkg/info/libpam-runtime.md5sums", "/var/lib/dpkg/info/libpam-runtime.md5sums"),
Type: pkg.DebPkg, file.NewVirtualLocation("/var/lib/dpkg/info/libpam-runtime.conffiles", "/var/lib/dpkg/info/libpam-runtime.conffiles"),
MetadataType: pkg.DpkgMetadataType, file.NewVirtualLocation("/usr/share/doc/libpam-runtime/copyright", "/usr/share/doc/libpam-runtime/copyright"),
Metadata: pkg.DpkgMetadata{ ),
Package: "libpam-runtime", Type: pkg.DebPkg,
Source: "pam", MetadataType: pkg.DpkgMetadataType,
Version: "1.1.8-3.6", Metadata: pkg.DpkgMetadata{
Architecture: "all", Package: "libpam-runtime",
Maintainer: "Steve Langasek <vorlon@debian.org>", Source: "pam",
InstalledSize: 1016, Version: "1.1.8-3.6",
Description: `Runtime support for the PAM library Architecture: "all",
Maintainer: "Steve Langasek <vorlon@debian.org>",
InstalledSize: 1016,
Description: `Runtime support for the PAM library
Contains configuration files and directories required for Contains configuration files and directories required for
authentication to work on Debian systems. This package is required authentication to work on Debian systems. This package is required
on almost all installations.`, on almost all installations.`,
Files: []pkg.DpkgFileRecord{ Files: []pkg.DpkgFileRecord{
{ {
Path: "/etc/pam.conf", Path: "/etc/pam.conf",
Digest: &file.Digest{ Digest: &file.Digest{
Algorithm: "md5", Algorithm: "md5",
Value: "87fc76f18e98ee7d3848f6b81b3391e5", Value: "87fc76f18e98ee7d3848f6b81b3391e5",
},
IsConfigFile: true,
},
{
Path: "/etc/pam.d/other",
Digest: &file.Digest{
Algorithm: "md5",
Value: "31aa7f2181889ffb00b87df4126d1701",
},
IsConfigFile: true,
},
{Path: "/lib/x86_64-linux-gnu/libz.so.1.2.11", Digest: &file.Digest{
Algorithm: "md5",
Value: "55f905631797551d4d936a34c7e73474",
}},
{Path: "/usr/share/doc/zlib1g/changelog.Debian.gz", Digest: &file.Digest{
Algorithm: "md5",
Value: "cede84bda30d2380217f97753c8ccf3a",
}},
{Path: "/usr/share/doc/zlib1g/changelog.gz", Digest: &file.Digest{
Algorithm: "md5",
Value: "f3c9dafa6da7992c47328b4464f6d122",
}},
{Path: "/usr/share/doc/zlib1g/copyright", Digest: &file.Digest{
Algorithm: "md5",
Value: "a4fae96070439a5209a62ae5b8017ab2",
}},
}, },
IsConfigFile: true,
}, },
{ },
Path: "/etc/pam.d/other", },
Digest: &file.Digest{ },
Algorithm: "md5", {
Value: "31aa7f2181889ffb00b87df4126d1701", name: "image-distroless-deb",
expected: []pkg.Package{
{
Name: "libsqlite3-0",
Version: "3.34.1-3",
FoundBy: "dpkgdb-cataloger",
Licenses: pkg.NewLicenseSet(
pkg.NewLicenseFromLocations("public-domain", file.NewVirtualLocation("/usr/share/doc/libsqlite3-0/copyright", "/usr/share/doc/libsqlite3-0/copyright")),
pkg.NewLicenseFromLocations("GPL-2+", file.NewVirtualLocation("/usr/share/doc/libsqlite3-0/copyright", "/usr/share/doc/libsqlite3-0/copyright")),
pkg.NewLicenseFromLocations("GPL-2", file.NewVirtualLocation("/usr/share/doc/libsqlite3-0/copyright", "/usr/share/doc/libsqlite3-0/copyright")),
),
Locations: file.NewLocationSet(
file.NewVirtualLocation("/var/lib/dpkg/status.d/libsqlite3-0", "/var/lib/dpkg/status.d/libsqlite3-0"),
file.NewVirtualLocation("/var/lib/dpkg/status.d/libsqlite3-0.md5sums", "/var/lib/dpkg/status.d/libsqlite3-0.md5sums"),
file.NewVirtualLocation("/usr/share/doc/libsqlite3-0/copyright", "/usr/share/doc/libsqlite3-0/copyright"),
),
Type: pkg.DebPkg,
MetadataType: pkg.DpkgMetadataType,
Metadata: pkg.DpkgMetadata{
Package: "libsqlite3-0",
Source: "sqlite3",
Version: "3.34.1-3",
Architecture: "arm64",
Maintainer: "Laszlo Boszormenyi (GCS) <gcs@debian.org>",
InstalledSize: 1490,
Description: `SQLite 3 shared library
SQLite is a C library that implements an SQL database engine.
Programs that link with the SQLite library can have SQL database
access without running a separate RDBMS process.`,
Files: []pkg.DpkgFileRecord{
{Path: "/usr/lib/aarch64-linux-gnu/libsqlite3.so.0.8.6", Digest: &file.Digest{
Algorithm: "md5",
Value: "e11d70c96979a1328ae4e7e50542782b",
}},
{Path: "/usr/share/doc/libsqlite3-0/README.Debian", Digest: &file.Digest{
Algorithm: "md5",
Value: "9d8facc2fa9d2df52f1c7cb4e5fa4741",
}},
{Path: "/usr/share/doc/libsqlite3-0/changelog.Debian.gz", Digest: &file.Digest{
Algorithm: "md5",
Value: "a58942e742f5056be0595e6ba69a323f",
}},
{Path: "/usr/share/doc/libsqlite3-0/changelog.gz", Digest: &file.Digest{
Algorithm: "md5",
Value: "52317be84c3ca44b7888c6921131e37d",
}},
{Path: "/usr/share/doc/libsqlite3-0/changelog.html.gz", Digest: &file.Digest{
Algorithm: "md5",
Value: "a856310354e6c8768e85b39ae838dd0a",
}},
{Path: "/usr/share/doc/libsqlite3-0/copyright", Digest: &file.Digest{
Algorithm: "md5",
Value: "be64db3e095486e5e105652c51199358",
}},
}, },
IsConfigFile: true,
}, },
{Path: "/lib/x86_64-linux-gnu/libz.so.1.2.11", Digest: &file.Digest{
Algorithm: "md5",
Value: "55f905631797551d4d936a34c7e73474",
}},
{Path: "/usr/share/doc/zlib1g/changelog.Debian.gz", Digest: &file.Digest{
Algorithm: "md5",
Value: "cede84bda30d2380217f97753c8ccf3a",
}},
{Path: "/usr/share/doc/zlib1g/changelog.gz", Digest: &file.Digest{
Algorithm: "md5",
Value: "f3c9dafa6da7992c47328b4464f6d122",
}},
{Path: "/usr/share/doc/zlib1g/copyright", Digest: &file.Digest{
Algorithm: "md5",
Value: "a4fae96070439a5209a62ae5b8017ab2",
}},
}, },
}, },
}, },
} }
c := NewDpkgdbCataloger() for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pkgtest.NewCatalogTester(). c := NewDpkgdbCataloger()
WithImageResolver(t, "image-dpkg"). pkgtest.NewCatalogTester().
IgnoreLocationLayer(). // this fixture can be rebuilt, thus the layer ID will change WithImageResolver(t, tt.name).
Expects(expected, nil). IgnoreLocationLayer(). // this fixture can be rebuilt, thus the layer ID will change
TestCataloger(t, c) Expects(tt.expected, nil).
TestCataloger(t, c)
})
}
} }
func TestCataloger_Globs(t *testing.T) { func TestCataloger_Globs(t *testing.T) {

View File

@ -6,6 +6,7 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"sort" "sort"
"strings"
"github.com/anchore/packageurl-go" "github.com/anchore/packageurl-go"
"github.com/anchore/syft/internal" "github.com/anchore/syft/internal"
@ -176,16 +177,24 @@ func fetchMd5Contents(resolver file.Resolver, dbLocation file.Location, m pkg.Dp
return nil, nil return nil, nil
} }
parentPath := filepath.Dir(dbLocation.RealPath) // for typical debian-base distributions, the installed package info is at /var/lib/dpkg/status
// and the md5sum information is under /var/lib/dpkg/info/; however, for distroless the installed
// package info is across multiple files under /var/lib/dpkg/status.d/ and the md5sums are contained in
// the same directory
searchPath := filepath.Dir(dbLocation.RealPath)
if !strings.HasSuffix(searchPath, "status.d") {
searchPath = path.Join(searchPath, "info")
}
// look for /var/lib/dpkg/info/NAME:ARCH.md5sums // look for /var/lib/dpkg/info/NAME:ARCH.md5sums
name := md5Key(m) name := md5Key(m)
location := resolver.RelativeFileByPath(dbLocation, path.Join(parentPath, "info", name+md5sumsExt)) location := resolver.RelativeFileByPath(dbLocation, path.Join(searchPath, name+md5sumsExt))
if location == nil { if location == nil {
// the most specific key did not work, fallback to just the name // the most specific key did not work, fallback to just the name
// look for /var/lib/dpkg/info/NAME.md5sums // look for /var/lib/dpkg/info/NAME.md5sums
location = resolver.RelativeFileByPath(dbLocation, path.Join(parentPath, "info", m.Package+md5sumsExt)) location = resolver.RelativeFileByPath(dbLocation, path.Join(searchPath, m.Package+md5sumsExt))
} }
if location == nil { if location == nil {

View File

@ -0,0 +1,2 @@
FROM scratch
COPY . .

View File

@ -0,0 +1,30 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: sqlite3
Source: https://www.sqlite.org/cgi/src/dir?ci=trunk
Files: *
Copyright: D. Richard Hipp <drh@hwaci.com>
License: public-domain
The files listed have been put on the public domain by the sqlite3
contributors.
Files: debian/*
Copyright: 2006- Laszlo Boszormenyi (GCS) <gcs@debian.org>,
2005-2006 Tomas Fasth <tomfa@debian.org>,
2001-2005 Andreas Rottmann <rotty@debian.org>
License: GPL-2+
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License version 2 as published
by the Free Software Foundation.
.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
.
You should have received a copy of the GNU General Public License along
with this package; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
.
On Debian systems, the full text of the GNU General Public License
version 2 can be found in the file `/usr/share/common-licenses/GPL-2'.

View File

@ -0,0 +1,16 @@
Package: libsqlite3-0
Source: sqlite3
Version: 3.34.1-3
Architecture: arm64
Maintainer: Laszlo Boszormenyi (GCS) <gcs@debian.org>
Installed-Size: 1490
Depends: libc6 (>= 2.29)
Breaks: python-migrate (<< 0.11.0-4~), python3-migrate (<< 0.11.0-4~)
Section: libs
Priority: optional
Multi-Arch: same
Homepage: https://www.sqlite.org/
Description: SQLite 3 shared library
SQLite is a C library that implements an SQL database engine.
Programs that link with the SQLite library can have SQL database
access without running a separate RDBMS process.

View File

@ -0,0 +1,6 @@
e11d70c96979a1328ae4e7e50542782b usr/lib/aarch64-linux-gnu/libsqlite3.so.0.8.6
9d8facc2fa9d2df52f1c7cb4e5fa4741 usr/share/doc/libsqlite3-0/README.Debian
a58942e742f5056be0595e6ba69a323f usr/share/doc/libsqlite3-0/changelog.Debian.gz
52317be84c3ca44b7888c6921131e37d usr/share/doc/libsqlite3-0/changelog.gz
a856310354e6c8768e85b39ae838dd0a usr/share/doc/libsqlite3-0/changelog.html.gz
be64db3e095486e5e105652c51199358 usr/share/doc/libsqlite3-0/copyright