lib: Prevent using protocol method with native path (fixes #7557) (#7563)

This commit is contained in:
Simon Frei 2021-04-11 15:29:43 +02:00 committed by GitHub
parent ec0a66c75b
commit 1a00ea7c6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 20 additions and 29 deletions

View File

@ -11,7 +11,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"path/filepath" "path/filepath"
"strings"
"sync" "sync"
"time" "time"
@ -400,7 +399,7 @@ func (r *defaultRealCaser) realCase(name string) (string, error) {
return realName, nil return realName, nil
} }
for _, comp := range strings.Split(name, string(PathSeparator)) { for _, comp := range PathComponents(name) {
node := r.cache.getExpireAdd(realName) node := r.cache.getExpireAdd(realName)
node.once.Do(func() { node.once.Do(func() {

View File

@ -15,6 +15,8 @@ import (
"unicode" "unicode"
) )
const pathSeparatorString = string(PathSeparator)
func ExpandTilde(path string) (string, error) { func ExpandTilde(path string) (string, error) {
if path == "~" { if path == "~" {
return getHomeDir() return getHomeDir()
@ -164,7 +166,7 @@ func IsParent(path, parent string) bool {
return path != "/" return path != "/"
} }
if parent[len(parent)-1] != PathSeparator { if parent[len(parent)-1] != PathSeparator {
parent += string(PathSeparator) parent += pathSeparatorString
} }
return strings.HasPrefix(path, parent) return strings.HasPrefix(path, parent)
} }
@ -175,8 +177,8 @@ func CommonPrefix(first, second string) string {
return "" return ""
} }
firstParts := strings.Split(filepath.Clean(first), string(PathSeparator)) firstParts := PathComponents(filepath.Clean(first))
secondParts := strings.Split(filepath.Clean(second), string(PathSeparator)) secondParts := PathComponents(filepath.Clean(second))
isAbs := filepath.IsAbs(first) && filepath.IsAbs(second) isAbs := filepath.IsAbs(first) && filepath.IsAbs(second)
@ -200,7 +202,7 @@ func CommonPrefix(first, second string) string {
common = append(common, "") common = append(common, "")
} else if len(common) == 1 { } else if len(common) == 1 {
// If isAbs on non Windows, first element in both first and second is "", hence joining that returns nothing. // If isAbs on non Windows, first element in both first and second is "", hence joining that returns nothing.
return string(PathSeparator) return pathSeparatorString
} }
} }
@ -211,10 +213,16 @@ func CommonPrefix(first, second string) string {
} }
// This has to be strings.Join, because filepath.Join([]string{"", "", "?", "C:", "Audrius"}...) returns garbage // This has to be strings.Join, because filepath.Join([]string{"", "", "?", "C:", "Audrius"}...) returns garbage
result := strings.Join(common, string(PathSeparator)) result := strings.Join(common, pathSeparatorString)
return filepath.Clean(result) return filepath.Clean(result)
} }
// PathComponents returns a list of names of parent directories and the leaf
// item for the given native (fs.PathSeparator delimited) and clean path.
func PathComponents(path string) []string {
return strings.Split(path, pathSeparatorString)
}
func isVolumeNameOnly(parts []string) bool { func isVolumeNameOnly(parts []string) bool {
isNormalVolumeName := len(parts) == 1 && strings.HasSuffix(parts[0], ":") isNormalVolumeName := len(parts) == 1 && strings.HasSuffix(parts[0], ":")
isUNCVolumeName := len(parts) == 4 && strings.HasSuffix(parts[3], ":") isUNCVolumeName := len(parts) == 4 && strings.HasSuffix(parts[3], ":")

View File

@ -558,7 +558,7 @@ func (f *folder) scanSubdirsBatchAppendFunc(batch *fileInfoBatch) batchAppendFun
// This is a "virtual" parent directory of encrypted files. // This is a "virtual" parent directory of encrypted files.
// We don't track it, but check if anything still exists // We don't track it, but check if anything still exists
// within and delete it otherwise. // within and delete it otherwise.
if fi.IsDirectory() && protocol.IsEncryptedParent(fi.Name) { if fi.IsDirectory() && protocol.IsEncryptedParent(fs.PathComponents(fi.Name)) {
if names, err := f.mtimefs.DirNames(fi.Name); err == nil && len(names) == 0 { if names, err := f.mtimefs.DirNames(fi.Name); err == nil && len(names) == 0 {
f.mtimefs.Remove(fi.Name) f.mtimefs.Remove(fi.Name)
} }

View File

@ -9,7 +9,6 @@ package osutil
import ( import (
"fmt" "fmt"
"path/filepath" "path/filepath"
"strings"
"github.com/syncthing/syncthing/lib/fs" "github.com/syncthing/syncthing/lib/fs"
) )
@ -47,7 +46,7 @@ func TraversesSymlink(filesystem fs.Filesystem, name string) error {
} }
var path string var path string
for _, part := range strings.Split(name, string(fs.PathSeparator)) { for _, part := range fs.PathComponents(name) {
path = filepath.Join(path, part) path = filepath.Join(path, part)
info, err := filesystem.Lstat(path) info, err := filesystem.Lstat(path)
if err != nil { if err != nil {

View File

@ -559,24 +559,10 @@ func (r rawResponse) Data() []byte {
func (r rawResponse) Close() {} func (r rawResponse) Close() {}
func (r rawResponse) Wait() {} func (r rawResponse) Wait() {}
// IsEncryptedPath returns true if the path points at encrypted data. This is
// determined by checking for a sentinel string in the path.
func IsEncryptedPath(path string) bool {
pathComponents := strings.Split(path, "/")
if len(pathComponents) != 3 {
return false
}
return isEncryptedParentFromComponents(pathComponents[:2])
}
// IsEncryptedParent returns true if the path points at a parent directory of // IsEncryptedParent returns true if the path points at a parent directory of
// encrypted data, i.e. is not a "real" directory. This is determined by // encrypted data, i.e. is not a "real" directory. This is determined by
// checking for a sentinel string in the path. // checking for a sentinel string in the path.
func IsEncryptedParent(path string) bool { func IsEncryptedParent(pathComponents []string) bool {
return isEncryptedParentFromComponents(strings.Split(path, "/"))
}
func isEncryptedParentFromComponents(pathComponents []string) bool {
l := len(pathComponents) l := len(pathComponents)
if l == 2 && len(pathComponents[1]) != 2 { if l == 2 && len(pathComponents[1]) != 2 {
return false return false

View File

@ -196,7 +196,7 @@ func TestIsEncryptedParent(t *testing.T) {
{"1" + encryptedDirExtension + "/bc/" + comp + "/a/" + comp, false}, {"1" + encryptedDirExtension + "/bc/" + comp + "/a/" + comp, false},
} }
for _, tc := range cases { for _, tc := range cases {
if res := IsEncryptedParent(tc.path); res != tc.is { if res := IsEncryptedParent(strings.Split(tc.path, "/")); res != tc.is {
t.Errorf("%v: got %v, expected %v", tc.path, res, tc.is) t.Errorf("%v: got %v, expected %v", tc.path, res, tc.is)
} }
} }

View File

@ -10,7 +10,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
"time" "time"
@ -43,7 +42,7 @@ func (i infiniteFS) DirNames(name string) ([]string, error) {
for j := 0; j < i.width; j++ { for j := 0; j < i.width; j++ {
names = append(names, fmt.Sprintf("aa-file-%d", j)) names = append(names, fmt.Sprintf("aa-file-%d", j))
} }
if len(strings.Split(name, string(os.PathSeparator))) < i.depth { if len(fs.PathComponents(name)) < i.depth {
for j := 0; j < i.width; j++ { for j := 0; j < i.width; j++ {
names = append(names, fmt.Sprintf("zz-dir-%d", j)) names = append(names, fmt.Sprintf("zz-dir-%d", j))
} }

View File

@ -311,7 +311,7 @@ func (w *walker) walkAndHashFiles(ctx context.Context, toHashChan chan<- protoco
// ignored path need to be handled as well. // ignored path need to be handled as well.
// Prepend an empty string to handle ignoredParent without anything // Prepend an empty string to handle ignoredParent without anything
// appended in the first iteration. // appended in the first iteration.
for _, name := range append([]string{""}, strings.Split(rel, string(fs.PathSeparator))...) { for _, name := range append([]string{""}, fs.PathComponents(rel)...) {
ignoredParent = filepath.Join(ignoredParent, name) ignoredParent = filepath.Join(ignoredParent, name)
info, err = w.Filesystem.Lstat(ignoredParent) info, err = w.Filesystem.Lstat(ignoredParent)
// An error here would be weird as we've already gotten to this point, but act on it nonetheless // An error here would be weird as we've already gotten to this point, but act on it nonetheless