Skip to content

Commit

Permalink
Support scanning files in other mount namespaces
Browse files Browse the repository at this point in the history
* honour the base-path flag when scanning files
* don't evaluate symlinks for the base path
* use procfsroot.EvalSymlinks() instead of filepath.EvalSymlinks() so
  that symlinks are always resolved relative to the base path

Fixes anchore#3396

Signed-off-by: Ariel Miculas-Trif <[email protected]>
  • Loading branch information
ariel-miculas committed Oct 30, 2024
1 parent df3998b commit d7d6658
Show file tree
Hide file tree
Showing 9 changed files with 55 additions and 24 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ require (
github.com/OneOfOne/xxhash v1.2.8
github.com/adrg/xdg v0.5.2
github.com/magiconair/properties v1.8.7
github.com/thediveo/procfsroot v1.0.1
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
)

Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,8 @@ github.com/go-restruct/restruct v1.2.0-alpha h1:2Lp474S/9660+SJjpVxoKuWX09JsXHSr
github.com/go-restruct/restruct v1.2.0-alpha/go.mod h1:KqrpKpn4M8OLznErihXTGLlsXFGeLxHUrLRRI/1YjGk=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
Expand Down Expand Up @@ -613,6 +615,8 @@ github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
Expand Down Expand Up @@ -768,6 +772,10 @@ github.com/sylabs/squashfs v1.0.0 h1:xAyMS21ogglkuR5HaY55PCfqY3H32ma9GkasTYo28Zg
github.com/sylabs/squashfs v1.0.0/go.mod h1:rhWzvgefq1X+R+LZdts10hfMsTg3g74OfGunW8tvg/4=
github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo=
github.com/terminalstatic/go-xsd-validate v0.1.5/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw=
github.com/thediveo/procfsroot v1.0.1 h1:uJBK+LARIa8fJVyMqgsdZHaK8/XYyLAB0QzQr0zEeIs=
github.com/thediveo/procfsroot v1.0.1/go.mod h1:COuiAyTYS1iy2NP2Uti9YzTxxWqQlNMD57Xvfn65kIk=
github.com/thediveo/success v1.0.1 h1:NVwUOwKUwaN8szjkJ+vsiM2L3sNBFscldoDJ2g2tAPg=
github.com/thediveo/success v1.0.1/go.mod h1:AZ8oUArgbIsCuDEWrzWNQHdKnPbDOLQsWOFj9ynwLt0=
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
Expand Down
33 changes: 23 additions & 10 deletions syft/internal/fileresolver/chroot_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package fileresolver
import (
"fmt"
"os"
"github.com/anchore/syft/internal/log"
"path"
"path/filepath"
"strings"

"github.com/anchore/syft/syft/internal/windows"
"github.com/thediveo/procfsroot"
)

// ChrootContext helps to modify path from a real filesystem to a chroot-like filesystem, taking into account
Expand All @@ -30,12 +32,12 @@ func NewChrootContextFromCWD(root, base string) (*ChrootContext, error) {
}

func NewChrootContext(root, base, cwd string) (*ChrootContext, error) {
cleanRoot, err := NormalizeRootDirectory(root)
cleanBase, err := NormalizeBaseDirectory(base)
if err != nil {
return nil, err
}

cleanBase, err := NormalizeBaseDirectory(base)
cleanRoot, err := NormalizeRootDirectory(root, base)
if err != nil {
return nil, err
}
Expand All @@ -49,11 +51,27 @@ func NewChrootContext(root, base, cwd string) (*ChrootContext, error) {
return chroot, chroot.ChangeDirectory(cwd)
}

func NormalizeRootDirectory(root string) (string, error) {
cleanRoot, err := filepath.EvalSymlinks(root)
func EvalSymlinksRelativeToBase(source string, base string) (string, error) {
if !strings.HasPrefix(source, base) {
return "", fmt.Errorf("source %q is not inside base %q", source, base)
}
source = strings.TrimPrefix(source, base)
normalizedPath, err := procfsroot.EvalSymlinks(source, base, procfsroot.EvalFullPath)
if err != nil {
return "", fmt.Errorf("could not evaluate source=%q, base=%q symlinks: %w", source, base, err)
}

log.Debugf("normalizedPath = %s", base + normalizedPath)

return base + normalizedPath, nil
}

func NormalizeRootDirectory(root string, base string) (string, error) {
cleanRoot, err := EvalSymlinksRelativeToBase(root, base)
if err != nil {
return "", fmt.Errorf("could not evaluate root=%q symlinks: %w", root, err)
}

return cleanRoot, nil
}

Expand All @@ -62,12 +80,7 @@ func NormalizeBaseDirectory(base string) (string, error) {
return "", nil
}

cleanBase, err := filepath.EvalSymlinks(base)
if err != nil {
return "", fmt.Errorf("could not evaluate base=%q symlinks: %w", base, err)
}

return filepath.Abs(cleanBase)
return filepath.Abs(base)
}

// Root returns the root path with all symlinks evaluated.
Expand Down
6 changes: 3 additions & 3 deletions syft/internal/fileresolver/directory_indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func (r *directoryIndexer) indexTree(root string, stager *progress.Stage) ([]str
return roots, nil
}

shouldIndexFullTree, err := isRealPath(root)
shouldIndexFullTree, err := isRealPath(root, r.base)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -166,10 +166,10 @@ func (r *directoryIndexer) indexTree(root string, stager *progress.Stage) ([]str
return roots, nil
}

func isRealPath(root string) (bool, error) {
func isRealPath(root string, base string) (bool, error) {
rootParent := filepath.Clean(filepath.Dir(root))

realRootParent, err := filepath.EvalSymlinks(rootParent)
realRootParent, err := EvalSymlinksRelativeToBase(rootParent, base)
if err != nil {
return false, err
}
Expand Down
4 changes: 2 additions & 2 deletions syft/internal/fileresolver/path_skipper.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ func newPathSkipperFromMounts(root string, infos []*mountinfo.Info) pathSkipper
// - udev - userspace implementation that replaced devfs
// - tmpfs - used for /dev in special instances (within a container)
ignorableMountTypes := map[string][]string{
"proc": nil,
"procfs": nil,
// "proc": nil,
// "procfs": nil,
"sysfs": nil,
"devfs": nil,
"devtmpfs": nil,
Expand Down
2 changes: 1 addition & 1 deletion syft/source/directorysource/directory_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ func cleanDirPath(path, base string) string {
}

if base != "" {
cleanRoot, rootErr := fileresolver.NormalizeRootDirectory(path)
cleanBase, baseErr := fileresolver.NormalizeBaseDirectory(base)
cleanRoot, rootErr := fileresolver.NormalizeRootDirectory(path, cleanBase)

if rootErr == nil && baseErr == nil {
// allows for normalizing inputs:
Expand Down
18 changes: 12 additions & 6 deletions syft/source/filesource/file_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var _ source.Source = (*fileSource)(nil)

type Config struct {
Path string
Base string
Exclude source.ExcludeConfig
DigestAlgorithms []crypto.Hash
Alias source.Alias
Expand Down Expand Up @@ -160,7 +161,12 @@ func (s fileSource) FileResolver(_ source.Scope) (file.Resolver, error) {
}
isArchiveAnalysis := fi.IsDir()

absParentDir, err := absoluteSymlinkFreePathToParent(s.analysisPath)
base, err := fileresolver.NormalizeBaseDirectory(s.config.Base)
if err != nil {
return nil, fmt.Errorf("unable to normalize base=%q: %w", s.config.Base, err)
}

absParentDir, err := absoluteSymlinkFreePathToParent(s.analysisPath, base)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -199,7 +205,7 @@ func (s fileSource) FileResolver(_ source.Scope) (file.Resolver, error) {
},
}, exclusionFunctions...)

res, err = fileresolver.NewFromDirectory(absParentDir, absParentDir, exclusionFunctions...)
res, err = fileresolver.NewFromDirectory(absParentDir, base, exclusionFunctions...)
if err != nil {
return nil, fmt.Errorf("unable to create directory resolver: %w", err)
}
Expand All @@ -210,14 +216,14 @@ func (s fileSource) FileResolver(_ source.Scope) (file.Resolver, error) {
return s.resolver, nil
}

func absoluteSymlinkFreePathToParent(path string) (string, error) {
func absoluteSymlinkFreePathToParent(path string, base string) (string, error) {
absAnalysisPath, err := filepath.Abs(path)
if err != nil {
return "", fmt.Errorf("unable to get absolute path for analysis path=%q: %w", path, err)
return "", fmt.Errorf("[1] unable to get absolute path for analysis path=%q: %w", path, err)
}
dereferencedAbsAnalysisPath, err := filepath.EvalSymlinks(absAnalysisPath)
dereferencedAbsAnalysisPath, err := fileresolver.EvalSymlinksRelativeToBase(absAnalysisPath, base)
if err != nil {
return "", fmt.Errorf("unable to get absolute path for analysis path=%q: %w", path, err)
return "", fmt.Errorf("[2] unable to get absolute path for analysis path=%q (%q): %w", path, absAnalysisPath, err)
}
return filepath.Dir(dereferencedAbsAnalysisPath), nil
}
Expand Down
5 changes: 4 additions & 1 deletion syft/source/filesource/file_source_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import (
"github.com/anchore/syft/syft/source"
)

func NewSourceProvider(path string, exclude source.ExcludeConfig, digestAlgorithms []crypto.Hash, alias source.Alias) source.Provider {
func NewSourceProvider(path string, exclude source.ExcludeConfig, digestAlgorithms []crypto.Hash, alias source.Alias, basePath string) source.Provider {
return &fileSourceProvider{
path: path,
basePath: basePath,
exclude: exclude,
digestAlgorithms: digestAlgorithms,
alias: alias,
Expand All @@ -22,6 +23,7 @@ func NewSourceProvider(path string, exclude source.ExcludeConfig, digestAlgorith

type fileSourceProvider struct {
path string
basePath string
exclude source.ExcludeConfig
digestAlgorithms []crypto.Hash
alias source.Alias
Expand Down Expand Up @@ -50,6 +52,7 @@ func (p fileSourceProvider) Provide(_ context.Context) (source.Source, error) {
return New(
Config{
Path: location,
Base: p.basePath,
Exclude: p.exclude,
DigestAlgorithms: p.digestAlgorithms,
Alias: p.alias,
Expand Down
2 changes: 1 addition & 1 deletion syft/source/sourceproviders/source_providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func All(userInput string, cfg *Config) []collections.TaggedValue[source.Provide
return collections.TaggedValueSet[source.Provider]{}.
// --from file, dir, oci-archive, etc.
Join(stereoscopeProviders.Select(FileTag, DirTag)...).
Join(tagProvider(filesource.NewSourceProvider(userInput, cfg.Exclude, cfg.DigestAlgorithms, cfg.Alias), FileTag)).
Join(tagProvider(filesource.NewSourceProvider(userInput, cfg.Exclude, cfg.DigestAlgorithms, cfg.Alias, cfg.BasePath), FileTag)).
Join(tagProvider(directorysource.NewSourceProvider(userInput, cfg.Exclude, cfg.Alias, cfg.BasePath), DirTag)).

// --from docker, registry, etc.
Expand Down

0 comments on commit d7d6658

Please sign in to comment.