diff --git a/internal/archive/archives/archives.go b/internal/archive/archives/archives.go index d9c59aa9..6f6245a8 100644 --- a/internal/archive/archives/archives.go +++ b/internal/archive/archives/archives.go @@ -1,10 +1,11 @@ package archives import ( + "fmt" "io" "io/fs" "os" - stdpath "path" + "path/filepath" "strings" "github.com/OpenListTeam/OpenList/v4/internal/archive/tool" @@ -107,7 +108,7 @@ func (Archives) Decompress(ss []*stream.SeekableStream, outputPath string, args } if stat.IsDir() { isDir = true - outputPath = stdpath.Join(outputPath, stat.Name()) + outputPath = filepath.Join(outputPath, stat.Name()) err = os.Mkdir(outputPath, 0700) if err != nil { return filterPassword(err) @@ -120,11 +121,14 @@ func (Archives) Decompress(ss []*stream.SeekableStream, outputPath string, args return err } relPath := strings.TrimPrefix(p, path+"/") - dstPath := stdpath.Join(outputPath, relPath) + dstPath := filepath.Join(outputPath, relPath) + if !strings.HasPrefix(dstPath, outputPath+string(os.PathSeparator)) { + return fmt.Errorf("illegal file path: %s", relPath) + } if d.IsDir() { err = os.MkdirAll(dstPath, 0700) } else { - dir := stdpath.Dir(dstPath) + dir := filepath.Dir(dstPath) err = decompress(fsys, p, dir, func(_ float64) {}) } return err diff --git a/internal/archive/archives/utils.go b/internal/archive/archives/utils.go index ce84da09..ddead84c 100644 --- a/internal/archive/archives/utils.go +++ b/internal/archive/archives/utils.go @@ -1,10 +1,11 @@ package archives import ( + "fmt" "io" fs2 "io/fs" "os" - stdpath "path" + "path/filepath" "strings" "github.com/OpenListTeam/OpenList/v4/internal/errs" @@ -69,7 +70,11 @@ func decompress(fsys fs2.FS, filePath, targetPath string, up model.UpdateProgres if err != nil { return err } - f, err := os.OpenFile(stdpath.Join(targetPath, stat.Name()), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600) + destPath := filepath.Join(targetPath, stat.Name()) + if !strings.HasPrefix(destPath, targetPath+string(os.PathSeparator)) { + return fmt.Errorf("illegal file path: %s", stat.Name()) + } + f, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600) if err != nil { return err } diff --git a/internal/archive/iso9660/iso9660.go b/internal/archive/iso9660/iso9660.go index eb4e975d..7b26dcae 100644 --- a/internal/archive/iso9660/iso9660.go +++ b/internal/archive/iso9660/iso9660.go @@ -1,9 +1,11 @@ package iso9660 import ( + "fmt" "io" "os" - stdpath "path" + "path/filepath" + "strings" "github.com/OpenListTeam/OpenList/v4/internal/archive/tool" "github.com/OpenListTeam/OpenList/v4/internal/errs" @@ -79,7 +81,11 @@ func (ISO9660) Decompress(ss []*stream.SeekableStream, outputPath string, args m } if obj.IsDir() { if args.InnerPath != "/" { - outputPath = stdpath.Join(outputPath, obj.Name()) + rootpath := outputPath + outputPath = filepath.Join(outputPath, obj.Name()) + if !strings.HasPrefix(outputPath, rootpath+string(os.PathSeparator)) { + return fmt.Errorf("illegal file path: %s", obj.Name()) + } if err = os.MkdirAll(outputPath, 0700); err != nil { return err } diff --git a/internal/archive/iso9660/utils.go b/internal/archive/iso9660/utils.go index e3326b9b..0e915133 100644 --- a/internal/archive/iso9660/utils.go +++ b/internal/archive/iso9660/utils.go @@ -1,8 +1,9 @@ package iso9660 import ( + "fmt" "os" - stdpath "path" + "path/filepath" "strings" "github.com/OpenListTeam/OpenList/v4/internal/errs" @@ -62,7 +63,11 @@ func toModelObj(file *iso9660.File) model.Obj { } func decompress(f *iso9660.File, path string, up model.UpdateProgress) error { - file, err := os.OpenFile(stdpath.Join(path, f.Name()), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600) + destPath := filepath.Join(path, f.Name()) + if !strings.HasPrefix(destPath, path+string(os.PathSeparator)) { + return fmt.Errorf("illegal file path: %s", f.Name()) + } + file, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600) if err != nil { return err } @@ -84,7 +89,10 @@ func decompressAll(children []*iso9660.File, path string) error { if err != nil { return err } - nextPath := stdpath.Join(path, child.Name()) + nextPath := filepath.Join(path, child.Name()) + if !strings.HasPrefix(nextPath, path+string(os.PathSeparator)) { + return fmt.Errorf("illegal file path: %s", child.Name()) + } if err = os.MkdirAll(nextPath, 0700); err != nil { return err } diff --git a/internal/archive/rardecode/rardecode.go b/internal/archive/rardecode/rardecode.go index d2c6a448..13a22e3e 100644 --- a/internal/archive/rardecode/rardecode.go +++ b/internal/archive/rardecode/rardecode.go @@ -3,7 +3,7 @@ package rardecode import ( "io" "os" - stdpath "path" + "path/filepath" "strings" "github.com/OpenListTeam/OpenList/v4/internal/archive/tool" @@ -93,7 +93,7 @@ func (RarDecoder) Decompress(ss []*stream.SeekableStream, outputPath string, arg } } else { innerPath := strings.TrimPrefix(args.InnerPath, "/") - innerBase := stdpath.Base(innerPath) + innerBase := filepath.Base(innerPath) createdBaseDir := false for { var header *rardecode.FileHeader @@ -115,7 +115,7 @@ func (RarDecoder) Decompress(ss []*stream.SeekableStream, outputPath string, arg } break } else if strings.HasPrefix(name, innerPath+"/") { - targetPath := stdpath.Join(outputPath, innerBase) + targetPath := filepath.Join(outputPath, innerBase) if !createdBaseDir { err = os.Mkdir(targetPath, 0700) if err != nil { diff --git a/internal/archive/rardecode/utils.go b/internal/archive/rardecode/utils.go index 93a71da9..e933005a 100644 --- a/internal/archive/rardecode/utils.go +++ b/internal/archive/rardecode/utils.go @@ -5,7 +5,7 @@ import ( "io" "io/fs" "os" - stdpath "path" + "path/filepath" "sort" "strings" "time" @@ -124,7 +124,7 @@ type WrapFileInfo struct { } func (f *WrapFileInfo) Name() string { - return stdpath.Base(f.File.Name) + return filepath.Base(f.File.Name) } func (f *WrapFileInfo) Size() int64 { @@ -183,12 +183,16 @@ func getReader(ss []*stream.SeekableStream, password string) (*rardecode.Reader, func decompress(reader *rardecode.Reader, header *rardecode.FileHeader, filePath, outputPath string) error { targetPath := outputPath - dir, base := stdpath.Split(filePath) + dir, base := filepath.Split(filePath) if dir != "" { - targetPath = stdpath.Join(targetPath, dir) - err := os.MkdirAll(targetPath, 0700) - if err != nil { - return err + targetPath = filepath.Join(targetPath, dir) + if strings.HasPrefix(targetPath, outputPath+string(os.PathSeparator)) { + err := os.MkdirAll(targetPath, 0700) + if err != nil { + return err + } + } else { + targetPath = outputPath } } if base != "" { @@ -201,7 +205,11 @@ func decompress(reader *rardecode.Reader, header *rardecode.FileHeader, filePath } func _decompress(reader *rardecode.Reader, header *rardecode.FileHeader, targetPath string, up model.UpdateProgress) error { - f, err := os.OpenFile(stdpath.Join(targetPath, stdpath.Base(header.Name)), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600) + destPath := filepath.Join(targetPath, filepath.Base(header.Name)) + if !strings.HasPrefix(destPath, targetPath+string(os.PathSeparator)) { + return fmt.Errorf("illegal file path: %s", filepath.Base(header.Name)) + } + f, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600) if err != nil { return err } diff --git a/internal/archive/tool/helper.go b/internal/archive/tool/helper.go index 6b5658a9..adbe56ed 100644 --- a/internal/archive/tool/helper.go +++ b/internal/archive/tool/helper.go @@ -1,10 +1,11 @@ package tool import ( + "fmt" "io" "io/fs" "os" - stdpath "path" + "path/filepath" "strings" "github.com/OpenListTeam/OpenList/v4/internal/model" @@ -40,13 +41,13 @@ func GenerateMetaTreeFromFolderTraversal(r ArchiveReader) (bool, []model.ObjTree isNewFolder := false if !file.FileInfo().IsDir() { // 先将 文件 添加到 所在的文件夹 - dir = stdpath.Dir(name) + dir = filepath.Dir(name) dirObj = dirMap[dir] if dirObj == nil { isNewFolder = dir != "." dirObj = &model.ObjectTree{} dirObj.IsFolder = true - dirObj.Name = stdpath.Base(dir) + dirObj.Name = filepath.Base(dir) dirObj.Modified = file.FileInfo().ModTime() dirMap[dir] = dirObj } @@ -64,28 +65,28 @@ func GenerateMetaTreeFromFolderTraversal(r ArchiveReader) (bool, []model.ObjTree dirMap[dir] = dirObj } dirObj.IsFolder = true - dirObj.Name = stdpath.Base(dir) + dirObj.Name = filepath.Base(dir) dirObj.Modified = file.FileInfo().ModTime() } if isNewFolder { // 将 文件夹 添加到 父文件夹 // 考虑压缩包仅记录文件的路径,不记录文件夹 // 循环创建所有父文件夹 - parentDir := stdpath.Dir(dir) + parentDir := filepath.Dir(dir) for { parentDirObj := dirMap[parentDir] if parentDirObj == nil { parentDirObj = &model.ObjectTree{} if parentDir != "." { parentDirObj.IsFolder = true - parentDirObj.Name = stdpath.Base(parentDir) + parentDirObj.Name = filepath.Base(parentDir) parentDirObj.Modified = file.FileInfo().ModTime() } dirMap[parentDir] = parentDirObj } parentDirObj.Children = append(parentDirObj.Children, dirObj) - parentDir = stdpath.Dir(parentDir) + parentDir = filepath.Dir(parentDir) if dirMap[parentDir] != nil { break } @@ -127,7 +128,7 @@ func DecompressFromFolderTraversal(r ArchiveReader, outputPath string, args mode } } else { innerPath := strings.TrimPrefix(args.InnerPath, "/") - innerBase := stdpath.Base(innerPath) + innerBase := filepath.Base(innerPath) createdBaseDir := false for _, file := range files { name := file.Name() @@ -138,7 +139,7 @@ func DecompressFromFolderTraversal(r ArchiveReader, outputPath string, args mode } break } else if strings.HasPrefix(name, innerPath+"/") { - targetPath := stdpath.Join(outputPath, innerBase) + targetPath := filepath.Join(outputPath, innerBase) if !createdBaseDir { err = os.Mkdir(targetPath, 0700) if err != nil { @@ -159,12 +160,16 @@ func DecompressFromFolderTraversal(r ArchiveReader, outputPath string, args mode func decompress(file SubFile, filePath, outputPath, password string) error { targetPath := outputPath - dir, base := stdpath.Split(filePath) + dir, base := filepath.Split(filePath) if dir != "" { - targetPath = stdpath.Join(targetPath, dir) - err := os.MkdirAll(targetPath, 0700) - if err != nil { - return err + targetPath = filepath.Join(targetPath, dir) + if strings.HasPrefix(targetPath, outputPath+string(os.PathSeparator)) { + err := os.MkdirAll(targetPath, 0700) + if err != nil { + return err + } + } else { + targetPath = outputPath } } if base != "" { @@ -185,7 +190,11 @@ func _decompress(file SubFile, targetPath, password string, up model.UpdateProgr return err } defer func() { _ = rc.Close() }() - f, err := os.OpenFile(stdpath.Join(targetPath, file.FileInfo().Name()), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600) + destPath := filepath.Join(targetPath, file.FileInfo().Name()) + if !strings.HasPrefix(destPath, targetPath+string(os.PathSeparator)) { + return fmt.Errorf("illegal file path: %s", file.FileInfo().Name()) + } + f, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600) if err != nil { return err }