prevent again security warning about 'Zip Slip' in RPI camera downloader (#6108)

This commit is contained in:
Alessandro Ros
2026-08-18 07:49:58 +00:00
committed by GitHub
parent 5d877b4512
commit 5fb93cceaf
2 changed files with 69 additions and 8 deletions
@@ -21,13 +21,18 @@ const (
maxInboundRPICameraSize = 10 * 1024 * 1024
)
func safeArchivePath(name string) (string, error) {
func safeArchivePath(baseDir string, name string) (string, error) {
name = filepath.Clean(filepath.FromSlash(name))
if filepath.IsAbs(name) || name == ".." || strings.HasPrefix(name, ".."+string(filepath.Separator)) {
if name == "." || !filepath.IsLocal(name) {
return "", fmt.Errorf("invalid archive entry: %s", name)
}
return name, nil
targetPath := filepath.Join(baseDir, name)
if targetPath != baseDir && !strings.HasPrefix(targetPath, baseDir+string(filepath.Separator)) {
return "", fmt.Errorf("invalid archive entry: %s", name)
}
return targetPath, nil
}
func dumpTar(src io.Reader) error {
@@ -36,7 +41,11 @@ func dumpTar(src io.Reader) error {
return err
}
baseDir := "."
baseDir, err := filepath.Abs(".")
if err != nil {
return err
}
tr := tar.NewReader(uncompressed)
for {
@@ -49,14 +58,12 @@ func dumpTar(src io.Reader) error {
return err
}
var entryName string
entryName, err = safeArchivePath(header.Name)
var targetPath string
targetPath, err = safeArchivePath(baseDir, header.Name)
if err != nil {
return err
}
targetPath := filepath.Join(baseDir, entryName)
switch header.Typeflag {
case tar.TypeDir:
err = os.Mkdir(targetPath, header.FileInfo().Mode())
@@ -0,0 +1,54 @@
package main
import (
"path/filepath"
"testing"
)
func TestSafeArchivePath(t *testing.T) {
baseDir := filepath.Clean(string(filepath.Separator) + filepath.Join("tmp", "base"))
for _, ca := range []struct {
name string
path string
ok bool
result string
}{
{
name: "simple file",
path: "dir/file",
ok: true,
result: filepath.Join(baseDir, "dir", "file"),
},
{
name: "parent traversal",
path: "../file",
},
{
name: "absolute path",
path: "/etc/passwd",
},
{
name: "empty path",
path: "",
},
{
name: "dot path",
path: ".",
},
} {
t.Run(ca.name, func(t *testing.T) {
res, err := safeArchivePath(baseDir, ca.path)
if ca.ok {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if res != ca.result {
t.Fatalf("unexpected result: got %q, want %q", res, ca.result)
}
} else if err == nil {
t.Fatalf("expected error")
}
})
}
}