lib/model, lib/versioner: Prevent symlink attack via versioning (fixes #4286)

Prior to this, the following is possible:

- Create a symlink "foo -> /somewhere", it gets synced
- Delete "foo", it gets versioned
- Create "foo/bar", it gets synced
- Delete "foo/bar", it gets versioned in "/somewhere/bar"

With this change, versioners should never version symlinks.
This commit is contained in:
Jakob Borg
2017-07-25 11:36:09 +02:00
parent 54155cb42d
commit f1f21bf220
8 changed files with 146 additions and 5 deletions

View File

@@ -28,6 +28,8 @@ type Trashcan struct {
}
func NewTrashcan(folderID, folderPath string, params map[string]string) Versioner {
cleanSymlinks(folderPath)
cleanoutDays, _ := strconv.Atoi(params["cleanoutDays"])
// On error we default to 0, "do not clean out the trash can"
@@ -44,13 +46,16 @@ func NewTrashcan(folderID, folderPath string, params map[string]string) Versione
// Archive moves the named file away to a version archive. If this function
// returns nil, the named file does not exist any more (has been archived).
func (t *Trashcan) Archive(filePath string) error {
_, err := osutil.Lstat(filePath)
info, err := osutil.Lstat(filePath)
if os.IsNotExist(err) {
l.Debugln("not archiving nonexistent file", filePath)
return nil
} else if err != nil {
return err
}
if info.Mode()&os.ModeSymlink != 0 {
panic("bug: attempting to version a symlink")
}
versionsDir := filepath.Join(t.folderPath, ".stversions")
if _, err := os.Stat(versionsDir); err != nil {