security: harden recursive file operations
This commit is contained in:
@@ -97,10 +97,36 @@ func (s Local) Create(path string) (*os.File, error) {
|
||||
}
|
||||
func (s Local) Remove(path string) error {
|
||||
p, e := s.real(path)
|
||||
if e != nil {
|
||||
if e == nil {
|
||||
return os.RemoveAll(p)
|
||||
}
|
||||
// A final symlink that points outside the root is still safe to delete:
|
||||
// remove the link itself, but never follow it to its target. Validate its
|
||||
// parent through real() so nested symlink escapes remain rejected.
|
||||
clean := strings.TrimPrefix(filepath.Clean("/"+path), string(filepath.Separator))
|
||||
if clean == "" {
|
||||
return e
|
||||
}
|
||||
return os.RemoveAll(p)
|
||||
parent := filepath.ToSlash(filepath.Dir(clean))
|
||||
if parent == "." {
|
||||
parent = ""
|
||||
}
|
||||
if _, parentErr := s.real(parent); parentErr != nil {
|
||||
return e
|
||||
}
|
||||
root, rootErr := filepath.Abs(s.Root)
|
||||
if rootErr != nil {
|
||||
return e
|
||||
}
|
||||
root, rootErr = filepath.EvalSymlinks(root)
|
||||
if rootErr != nil {
|
||||
return e
|
||||
}
|
||||
candidate := filepath.Join(root, filepath.FromSlash(clean))
|
||||
if info, lstatErr := os.Lstat(candidate); lstatErr == nil && info.Mode()&os.ModeSymlink != 0 {
|
||||
return os.Remove(candidate)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func (s Local) Trash(path string) error {
|
||||
|
||||
Reference in New Issue
Block a user