mirror of
https://github.com/rclone/rclone.git
synced 2026-10-28 14:28:38 -04:00
vfs: stop --links objects called "...rclonelink" appearing as ".." in directory listings
When reading a directory with --links the VFS skipped entries called "." and ".." before removing the ".rclonelink" suffix, so an object called "...rclonelink" (or "..rclonelink" or ".rclonelink") produced a directory entry called ".." (or "." or "") whose path resolved to the parent directory. The same happened for names added back from the VFS cache. The check is now done after the suffix is removed. See GHSA-55qp-jrwr-x827
This commit is contained in:
1 parent
4d1bd4c71d
commit
93ba2d40f0
2 files changed
+44
-3
No files matched your search
+8
-3
@@ -478,6 +478,9 @@ func (d *Dir) AddVirtual(leaf string, size int64, isDir bool) {
|
||||
// since the path came from the cache it may have fs.LinkSuffix,
|
||||
// so remove it and mark the *File accordingly
|
||||
leaf, isLink = strings.CutSuffix(leaf, fs.LinkSuffix)
|
||||
if leaf == "" || leaf == "." || leaf == ".." {
|
||||
return
|
||||
}
|
||||
}
|
||||
f := newFile(d, dPath, nil, leaf)
|
||||
if isLink {
|
||||
@@ -724,12 +727,14 @@ func (d *Dir) _readDirFromEntries(entries fs.DirEntries, dirTree dirtree.DirTree
|
||||
mv := d._newManageVirtuals()
|
||||
for _, entry := range entries {
|
||||
name := path.Base(entry.Remote())
|
||||
if name == "." || name == ".." {
|
||||
continue
|
||||
}
|
||||
if d.vfs.Opt.Links {
|
||||
name, _ = strings.CutSuffix(name, fs.LinkSuffix)
|
||||
}
|
||||
// Check after removing the suffix so "...rclonelink" can't
|
||||
// become an entry called ".."
|
||||
if name == "" || name == "." || name == ".." {
|
||||
continue
|
||||
}
|
||||
node := d.items[name]
|
||||
if mv.add(d, name) {
|
||||
continue
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/fs/operations"
|
||||
"github.com/rclone/rclone/fstest"
|
||||
"github.com/rclone/rclone/vfs/vfscommon"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -33,6 +34,41 @@ func dirCreate(t *testing.T) (r *fstest.Run, vfs *VFS, dir *Dir, item fstest.Ite
|
||||
return r, vfs, node.(*Dir), file1
|
||||
}
|
||||
|
||||
// TestDirLinksInvalidName checks that with --links an object called
|
||||
// "...rclonelink" doesn't become a directory entry called "..", which
|
||||
// would address the parent, whether it comes from a listing or from
|
||||
// the cache.
|
||||
func TestDirLinksInvalidName(t *testing.T) {
|
||||
opt := vfscommon.Opt
|
||||
opt.Links = true
|
||||
r, vfs := newTestVFSOpt(t, &opt)
|
||||
|
||||
file1 := r.WriteObject(context.Background(), "dir/.."+fs.LinkSuffix, "target", t1)
|
||||
file2 := r.WriteObject(context.Background(), "dir/file1", "file1 contents", t1)
|
||||
r.CheckRemoteItems(t, file1, file2)
|
||||
|
||||
node, err := vfs.Stat("dir")
|
||||
require.NoError(t, err)
|
||||
dir := node.(*Dir)
|
||||
|
||||
checkEntries := func() {
|
||||
t.Helper()
|
||||
entries, err := dir.ReadDirAll()
|
||||
require.NoError(t, err)
|
||||
var names []string
|
||||
for _, entry := range entries {
|
||||
names = append(names, entry.Name())
|
||||
}
|
||||
assert.Equal(t, []string{"file1"}, names)
|
||||
}
|
||||
checkEntries()
|
||||
|
||||
for _, leaf := range []string{".." + fs.LinkSuffix, "." + fs.LinkSuffix, fs.LinkSuffix} {
|
||||
dir.AddVirtual(leaf, 6, false)
|
||||
}
|
||||
checkEntries()
|
||||
}
|
||||
|
||||
func TestDirMethods(t *testing.T) {
|
||||
_, vfs, dir, _ := dirCreate(t)
|
||||
|
||||
|
||||
Reference in new issue
Block a user