Documentation
¶
Overview ¶
Package pkgdb reads the package databases a system or container image carries (dpkg, apk, rpm) and answers which installed package owns a file, so a PHP binary installed by a distribution is judged by that distribution's fix and not by its upstream version string.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrLinkLoop = errors.New("too many levels of symbolic links")
ErrLinkLoop is returned when resolving a path needs more than 40 symlink expansions.
Functions ¶
func OSRelease ¶
OSRelease reads the distribution identity: /etc/os-release, or /usr/lib/os-release when /etc/os-release is absent from files (in images it is usually a symlink to ../usr/lib/os-release, so the walk only collects the target). Without either, it falls back to /etc/alpine-release (ID alpine) and /etc/debian_version (ID debian; a numeric "12.7" gives VERSION_ID "12", "trixie/sid" gives the codename). It returns false when nothing identifies the system.
func RegisterRPMSQLiteReader ¶
func RegisterRPMSQLiteReader(r RPMSQLiteReader)
RegisterRPMSQLiteReader installs the reader for rpm sqlite databases. The package github.com/DefectDojo/earlylight/detectors/php2shell/internal/pkgdb/rpmdb registers one from init(); blank-import it to read rpm 4.16+ databases (RHEL 9, Fedora, Amazon Linux 2023, SLES 16). Without it, Build records a problem for every sqlite database it finds. Berkeley DB and ndb databases need no registration.
func Wanted ¶
Wanted reports whether an absolute path (within the scanned root) is a file Build or OSRelease needs: package databases, dpkg file lists and digests, and release files. The caller collects the content of every wanted regular file (path -> bytes) and passes the map to Build and OSRelease; symlinks and hard links go to a Resolver instead.
Types ¶
type File ¶
type File struct {
Path string
// Algo is "md5", "sha1", "sha256" (or another name rpm uses); empty when the
// database records no digest for the file.
Algo string
Digest []byte
}
File is one file a package installed, with the digest the database records for it, if any.
type Index ¶
type Index struct {
// DBs lists the databases that were read.
DBs []string
// Problems lists databases that exist but could not be read fully. A file
// under such a database may have an owner this index does not know.
Problems []string
// contains filtered or unexported fields
}
Index maps absolute paths to the packages that own them, across every database found.
func Build ¶
Build parses the collected files (absolute path -> content) into an Index. It never fails: databases that exist but cannot be read completely are recorded in Index.Problems with the reason, and every database read is in Index.DBs. A package read from a database with a problem is still indexed when its own record was readable.
func (*Index) Owners ¶
Owners returns every package that lists p. Callers resolve symlinked directories first (see Resolver).
func (*Index) OwnersOf ¶
OwnersOf returns the owners of p under every alias the resolver knows (see Resolver.Aliases), deduplicated. With a nil resolver it equals Owners(p).
func (*Index) Packages ¶
Packages returns every installed package read, including packages whose database records no file list (distroless status.d entries without .md5sums, for example): those have no Files. Callers can thus tell "a PHP package is installed but its files are unknown" from "no package owns this file". The slice is shared; do not modify it.
type Package ¶
type Package struct {
Format Format `json:"format"`
Name string `json:"name"`
// Version is the full version as the package manager writes it, with the
// epoch if it has one: "1:8.2.35-1~deb12u1", "8.3.29-r0", "8.2.13-1.module+el9.4.0+20xxx".
// For rpm it is EPOCH:VERSION-RELEASE (epoch omitted when zero).
Version string `json:"version"`
// Source is the source package it was built from: dpkg "Source:", apk origin,
// rpm source rpm name without version. Equals Name when the database has none.
Source string `json:"source"`
// Vendor is rpm's Vendor tag, or dpkg's Maintainer. Empty for apk.
Vendor string `json:"vendor,omitempty"`
Arch string `json:"arch,omitempty"`
// DB is the database file the package was read from.
DB string `json:"db"`
}
Package is one installed package.
type RPMRecord ¶
RPMRecord is one row of an rpm sqlite database's Packages table: the package's instance number (hnum) and its header blob.
type RPMSQLiteReader ¶
RPMSQLiteReader returns every row of the Packages table of an rpm sqlite database (rpmdb.sqlite), applying the write-ahead log wal when non-nil. It must fail rather than return a partial table.
type Resolver ¶
type Resolver struct {
// contains filtered or unexported fields
}
Resolver knows the symbolic and hard links of a scanned filesystem and maps a path to the other paths that name the same file, so a file found at /usr/bin/bash is matched with a package database that lists /bin/bash (merged /usr), and a hard-linked copy is matched with the name a package lists.
How to feed it, during the single walk over the filesystem or image tar:
- every symbolic link: AddSymlink(abs, target), where abs is the link's absolute path within the scanned root ("/bin", "/etc/os-release") and target is the link text exactly as stored ("usr/bin", "../usr/lib/os-release", "/usr/bin/php8.2"). Relative targets are relative to the link's directory; absolute targets are interpreted inside the scanned root (chroot semantics), never on the host;
- every tar hard link entry: AddHardlink(abs, target), with target the entry's Linkname made absolute ("usr/bin/php8.2" -> "/usr/bin/php8.2"). For a directory walk, pass files sharing (device, inode) the same way.
For an image, feed the flattened (whiteouts applied) view: a link removed by a later layer must not be added. Paths are cleaned; a link added twice keeps the last target. Resolution is bounded: at most maxLinkHops symlink expansions per lookup (Linux allows 40), so loops end with an error.
A Resolver may be read (Canonical, Resolve, Aliases) from several goroutines once it is fully fed; adding links concurrently with reads is not supported.
func NewResolver ¶
NewResolver returns a resolver for the given symlinks (absolute path -> target as written). The map may be nil; more links can be added later.
func (*Resolver) AddHardlink ¶
AddHardlink records that abs is a hard link to target (both name one inode).
func (*Resolver) AddSymlink ¶
AddSymlink records a symbolic link.
func (*Resolver) Aliases ¶
Aliases returns every path that names the same file as p through symlinked parent directories and hard links: p itself, its canonical path, and each path obtained by replacing a directory prefix with a symlink that resolves to it, or the file with a member of its hard link group. A symlink to the file itself is not an alias (it is a different directory entry). The result is sorted, deduplicated and bounded to 256 paths. p is expected clean and absolute, as a walk produces it; a path with "." or ".." components that cross symlinks is first resolved physically.
func (*Resolver) Canonical ¶
Canonical resolves symlinks in the directories of p (not its last component) and returns the cleaned absolute path of the directory entry p names. "/bin/bash" becomes "/usr/bin/bash" when /bin -> usr/bin.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package rpmdb lets pkgdb read rpm sqlite databases (rpmdb.sqlite, rpm 4.16 and later: RHEL 9, Fedora 33+, Amazon Linux 2023, SLES 16).
|
Package rpmdb lets pkgdb read rpm sqlite databases (rpmdb.sqlite, rpm 4.16 and later: RHEL 9, Fedora 33+, Amazon Linux 2023, SLES 16). |