mirror of
https://github.com/mudler/LocalAI.git
synced 2026-09-29 09:35:02 -04:00
chore: merge master into distributed transport PR
Keep the version-reporting import from master and omit the unused sanitize import after the transport changes. Assisted-by: Codex:GPT-6
This commit is contained in:
commit
4151ceda85
51 files changed
+1785
-72
No files matched your search
+18
-4
@@ -13,21 +13,35 @@ func ExistsInPath(path string, s string) bool {
|
||||
}
|
||||
|
||||
func InTrustedRoot(path string, trustedRoot string) error {
|
||||
for path != "/" {
|
||||
path = filepath.Dir(path)
|
||||
for {
|
||||
parent := filepath.Dir(path)
|
||||
// Dir stops changing at "/" for an absolute path and at "." for a
|
||||
// relative one; waiting for "/" alone spins forever on the latter.
|
||||
if parent == path {
|
||||
return fmt.Errorf("path is outside of trusted root")
|
||||
}
|
||||
path = parent
|
||||
if path == trustedRoot {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("path is outside of trusted root")
|
||||
}
|
||||
|
||||
// VerifyPath verifies that path is based in basePath.
|
||||
// VerifyPath verifies that path, taken relative to basePath, is based in
|
||||
// basePath. It joins path onto basePath first, so an absolute path is read as
|
||||
// relative to the base as well: give it the untrusted relative name, never a
|
||||
// path that has already been joined. For a full path use VerifyResolvedPath.
|
||||
func VerifyPath(path, basePath string) error {
|
||||
c := filepath.Clean(filepath.Join(basePath, path))
|
||||
return InTrustedRoot(c, filepath.Clean(basePath))
|
||||
}
|
||||
|
||||
// VerifyResolvedPath verifies that path, a full path rather than one relative
|
||||
// to basePath, is based in basePath.
|
||||
func VerifyResolvedPath(path, basePath string) error {
|
||||
return InTrustedRoot(filepath.Clean(path), filepath.Clean(basePath))
|
||||
}
|
||||
|
||||
// SanitizeFileName sanitizes the given filename
|
||||
func SanitizeFileName(fileName string) string {
|
||||
// filepath.Clean to clean the path
|
||||
|
||||
@@ -3,6 +3,7 @@ package utils_test
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
. "github.com/mudler/LocalAI/pkg/utils"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
@@ -71,6 +72,25 @@ var _ = Describe("utils/path tests", func() {
|
||||
})
|
||||
})
|
||||
|
||||
Describe("VerifyResolvedPath", func() {
|
||||
It("accepts a full path inside the base", func() {
|
||||
Expect(VerifyResolvedPath("/srv/models/a/model.yaml", "/srv/models")).To(Succeed())
|
||||
})
|
||||
|
||||
It("rejects a full path outside the base", func() {
|
||||
// VerifyPath would join this onto the base and accept it.
|
||||
Expect(VerifyResolvedPath("/etc/passwd", "/srv/models")).ToNot(Succeed())
|
||||
})
|
||||
|
||||
It("rejects a joined path that climbed out of the base", func() {
|
||||
Expect(VerifyResolvedPath(filepath.Join("/srv/models", "../other/x"), "/srv/models")).ToNot(Succeed())
|
||||
})
|
||||
|
||||
It("cleans both paths before comparing", func() {
|
||||
Expect(VerifyResolvedPath("/srv/models/./a/../b.yaml", "/srv/models/")).To(Succeed())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("InTrustedRoot", func() {
|
||||
It("accepts a strict descendant of the trusted root", func() {
|
||||
Expect(InTrustedRoot("/srv/models/file", "/srv/models")).To(Succeed())
|
||||
@@ -93,6 +113,21 @@ var _ = Describe("utils/path tests", func() {
|
||||
It("rejects an unrelated absolute path", func() {
|
||||
Expect(InTrustedRoot("/etc/passwd", "/srv/models")).ToNot(Succeed())
|
||||
})
|
||||
|
||||
It("rejects a relative path outside a relative root instead of looping", func() {
|
||||
// Walking up a relative path ends at ".", never at "/", so the
|
||||
// walk must stop when it stops making progress.
|
||||
done := make(chan error, 1)
|
||||
go func() { done <- InTrustedRoot("x", "models") }()
|
||||
Eventually(done).WithTimeout(2 * time.Second).Should(Receive(HaveOccurred()))
|
||||
|
||||
go func() { done <- VerifyPath("../x", "models") }()
|
||||
Eventually(done).WithTimeout(2 * time.Second).Should(Receive(HaveOccurred()))
|
||||
})
|
||||
|
||||
It("accepts a relative descendant of a relative root", func() {
|
||||
Expect(InTrustedRoot("models/a/file", "models")).To(Succeed())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("SanitizeFileName", func() {
|
||||
|
||||
Reference in new issue
Block a user