mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
fix:Resolve ancestral symlinks correctly (#3783)
* Resolve upstream symlinks correctly Signed-off-by: Yuntao Hu <victorhu493@gmail.com> * in case of the root directory Signed-off-by: Yuntao Hu <victorhu493@gmail.com> * for static analysis check pass Signed-off-by: Yuntao Hu <victorhu493@gmail.com> * add unit test cases for the symlink scenarios Signed-off-by: Yuntao Hu <victorhu493@gmail.com> --------- Signed-off-by: Yuntao Hu <victorhu493@gmail.com>
This commit is contained in:
parent
6dca10fe1f
commit
09c3b7cbea
@ -379,6 +379,28 @@ func (r directoryIndexer) addSymlinkToIndex(p string, info os.FileInfo) (string,
|
|||||||
// if the base is set, then we first need to resolve the link,
|
// if the base is set, then we first need to resolve the link,
|
||||||
// before finding it's location in the base
|
// before finding it's location in the base
|
||||||
dir, err := filepath.Rel(r.base, filepath.Dir(p))
|
dir, err := filepath.Rel(r.base, filepath.Dir(p))
|
||||||
|
// if the relative path to the base contains "..",i.e. p is the parent or ancestor of the base
|
||||||
|
// For example:
|
||||||
|
// dir: "/root/asymlink" -> "/root/realdir" (linkTarget:"realdir")
|
||||||
|
// base: "/root/asymlink"
|
||||||
|
// so the relative path of /root to the "/root/asymlink" is ".."
|
||||||
|
// we cannot directly concatenate ".." to "/root/symlink",however,
|
||||||
|
// the parent directory of linkTarget should be "/root"
|
||||||
|
for strings.HasPrefix(dir, "..") {
|
||||||
|
if strings.HasPrefix(dir, "../") {
|
||||||
|
dir = strings.TrimPrefix(dir, "../")
|
||||||
|
} else {
|
||||||
|
dir = strings.TrimPrefix(dir, "..")
|
||||||
|
}
|
||||||
|
lastSlash := strings.LastIndex(r.base, "/")
|
||||||
|
if lastSlash != -1 {
|
||||||
|
r.base = r.base[:lastSlash]
|
||||||
|
}
|
||||||
|
// In case of the root directory
|
||||||
|
if r.base == "" {
|
||||||
|
r.base = "/"
|
||||||
|
}
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("unable to resolve relative path for path=%q: %w", p, err)
|
return "", fmt.Errorf("unable to resolve relative path for path=%q: %w", p, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
package fileresolver
|
package fileresolver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@ -223,6 +225,55 @@ func TestDirectoryIndexer_index(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDirectoryIndexer_index_for_AncestorSymlinks(t *testing.T) {
|
||||||
|
// note: this test is testing the effects from NewFromDirectory, indexTree, and addPathToIndex
|
||||||
|
_, filename, _, ok := runtime.Caller(0)
|
||||||
|
require.True(t, ok)
|
||||||
|
dir := filepath.Dir(filename)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
path string
|
||||||
|
relative_base string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "the parent directory has symlink target",
|
||||||
|
path: "test-fixtures/system_paths/target/symlinks-to-dev",
|
||||||
|
relative_base: "test-fixtures/system_paths/target/symlinks-to-dev",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "the ancestor directory has symlink target",
|
||||||
|
path: "test-fixtures/system_paths/target/symlinks-to-hierarchical-dev",
|
||||||
|
relative_base: "test-fixtures/system_paths/target/symlinks-to-hierarchical-dev/module_1/module_1_1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
indexer := newDirectoryIndexer("test-fixtures/system_paths/target",
|
||||||
|
fmt.Sprintf("%v/%v", dir, test.relative_base))
|
||||||
|
tree, index, err := indexer.build()
|
||||||
|
require.NoError(t, err)
|
||||||
|
info, err := os.Stat(test.path)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// note: the index uses absolute paths, so assertions MUST keep this in mind
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
p := file.Path(path.Join(cwd, test.path))
|
||||||
|
assert.Equal(t, true, tree.HasPath(p))
|
||||||
|
exists, ref, err := tree.File(p)
|
||||||
|
assert.Equal(t, true, exists)
|
||||||
|
if assert.NoError(t, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
entry, err := index.Get(*ref.Reference)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, info.Mode(), entry.Mode)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
func TestDirectoryIndexer_index_survive_badSymlink(t *testing.T) {
|
func TestDirectoryIndexer_index_survive_badSymlink(t *testing.T) {
|
||||||
// test-fixtures/bad-symlinks
|
// test-fixtures/bad-symlinks
|
||||||
// ├── root
|
// ├── root
|
||||||
|
|||||||
@ -811,7 +811,7 @@ func TestDirectoryResolverDoesNotIgnoreRelativeSystemPaths(t *testing.T) {
|
|||||||
// 4: within target/
|
// 4: within target/
|
||||||
// 1: target/link --> relative path to "place" // NOTE: this is filtered out since it not unique relative to outside_root/link_target/place
|
// 1: target/link --> relative path to "place" // NOTE: this is filtered out since it not unique relative to outside_root/link_target/place
|
||||||
// 1: outside_root/link_target/place
|
// 1: outside_root/link_target/place
|
||||||
assert.Len(t, locations, 5)
|
assert.Len(t, locations, 6)
|
||||||
|
|
||||||
// ensure that symlink indexing outside of root worked
|
// ensure that symlink indexing outside of root worked
|
||||||
testLocation := "test-fixtures/system_paths/outside_root/link_target/place"
|
testLocation := "test-fixtures/system_paths/outside_root/link_target/place"
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
bad
|
||||||
@ -0,0 +1 @@
|
|||||||
|
dev
|
||||||
@ -0,0 +1 @@
|
|||||||
|
hierarchical-dev
|
||||||
@ -833,7 +833,7 @@ func Test_UnindexedDirectoryResolverDoesNotIgnoreRelativeSystemPaths(t *testing.
|
|||||||
// 4: within target/
|
// 4: within target/
|
||||||
// 1: target/link --> relative path to "place" // NOTE: this is filtered out since it not unique relative to outside_root/link_target/place
|
// 1: target/link --> relative path to "place" // NOTE: this is filtered out since it not unique relative to outside_root/link_target/place
|
||||||
// 1: outside_root/link_target/place
|
// 1: outside_root/link_target/place
|
||||||
assert.Len(t, locations, 5)
|
assert.Len(t, locations, 6)
|
||||||
|
|
||||||
// ensure that symlink indexing outside of root worked
|
// ensure that symlink indexing outside of root worked
|
||||||
testLocation := "../outside_root/link_target/place"
|
testLocation := "../outside_root/link_target/place"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user