fix: check path for OoS symlinks

pull/3756/head
Laurynas Gadliauskas 2021-06-09 10:37:29 +03:00
parent 094ee331d6
commit 592606a00d
2 changed files with 35 additions and 26 deletions

View File

@ -65,21 +65,6 @@ func NewFileInfo(opts FileOptions) (*FileInfo, error) {
return nil, os.ErrPermission
}
isSymlink := false
symlink := ""
if lst, ok := opts.Fs.(afero.Lstater); ok {
info, _, err := lst.LstatIfPossible(opts.Path)
if err == nil {
isSymlink = IsSymlink(info.Mode())
}
}
if isSymlink {
if lsf, ok := opts.Fs.(afero.LinkReader); ok {
symlink, _ = lsf.ReadlinkIfPossible(opts.Path)
}
}
info, err := opts.Fs.Stat(opts.Path)
if err != nil {
return nil, err
@ -92,8 +77,6 @@ func NewFileInfo(opts FileOptions) (*FileInfo, error) {
ModTime: info.ModTime(),
Mode: info.Mode(),
IsDir: info.IsDir(),
IsSymlink: isSymlink,
Link: symlink,
Size: info.Size(),
Extension: filepath.Ext(info.Name()),
Token: opts.Token,

View File

@ -37,15 +37,9 @@ var resourceGetHandler = withUser(func(w http.ResponseWriter, r *http.Request, d
return errToStatus(err), err
}
// check if symlink's target is within base path
if file.IsSymlink {
parentDir := filepath.Dir(filepath.Clean(file.Path))
fullLinkTarget := filepath.Join(d.user.FullPath(parentDir), file.Link)
scopedLinkTarget := d.user.FullPath(filepath.Join(parentDir, file.Link))
if fullLinkTarget != scopedLinkTarget {
err = errors.ErrNotExist
return errToStatus(err), err
}
err = checkOutOfScopeSymlink(d, file.Path)
if err != nil {
return errToStatus(err), err
}
if r.URL.Query().Get("disk_usage") == "true" {
@ -322,6 +316,38 @@ func checkParent(src, dst string) error {
return nil
}
// Checks if path contains symlink to out-of-scope targets.
// Returns error ErrNotExist if it does.
func checkOutOfScopeSymlink(d *data, path string) error {
lsf, ok := d.user.Fs.(afero.LinkReader)
if !ok {
return nil
}
var parts []string
for _, part := range strings.Split(path, string(os.PathSeparator)) {
if part != "" {
parts = append(parts, part)
}
}
evalPath := string(os.PathSeparator)
for _, part := range parts {
evalPath = filepath.Join(evalPath, filepath.Clean(part))
symlink, err := lsf.ReadlinkIfPossible(evalPath)
if err == nil {
parentDir := filepath.Dir(evalPath)
fullLinkTarget := filepath.Join(d.user.FullPath(parentDir), symlink)
scopedLinkTarget := d.user.FullPath(filepath.Join(parentDir, symlink))
if fullLinkTarget != scopedLinkTarget {
return errors.ErrNotExist
}
}
}
return nil
}
func addVersionSuffix(source string, fs afero.Fs) string {
counter := 1
dir, name := path.Split(source)