Harden debug bundle filesystem collaborators

This commit is contained in:
2026-07-18 13:42:17 +00:00
parent 9746a42e04
commit 7bcce9953e
4 changed files with 184 additions and 4 deletions

View File

@@ -46,6 +46,9 @@ func SafePath(root, name string) (string, error) {
if rel == "." || rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
return "", fmt.Errorf("artifact name %q resolves outside file root", name)
}
if err := rejectSymlinkComponents(absRoot, name); err != nil {
return "", err
}
return target, nil
}
@@ -62,16 +65,44 @@ func WriteBytes(root, name string, data []byte, dirMode, fileMode os.FileMode) e
if err != nil {
return err
}
if err := writeAtomic(target, data, dirMode, fileMode); err != nil {
if err := os.MkdirAll(filepath.Dir(target), dirMode); err != nil {
return fmt.Errorf("write artifact %q: %w", name, err)
}
if err := rejectSymlinkComponents(root, name); err != nil {
return err
}
if err := writeAtomic(target, data, fileMode); err != nil {
return fmt.Errorf("write artifact %q: %w", name, err)
}
return nil
}
func writeAtomic(target string, data []byte, dirMode, fileMode os.FileMode) error {
if err := os.MkdirAll(filepath.Dir(target), dirMode); err != nil {
return err
func rejectSymlinkComponents(root, name string) error {
absRoot, err := filepath.Abs(root)
if err != nil {
return fmt.Errorf("resolve file root %q: %w", root, err)
}
current := absRoot
for _, component := range strings.Split(filepath.FromSlash(name), string(filepath.Separator)) {
if component == "" || component == "." {
continue
}
current = filepath.Join(current, component)
info, err := os.Lstat(current)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return fmt.Errorf("inspect artifact path %q: %w", name, err)
}
if info.Mode()&os.ModeSymlink != 0 {
return fmt.Errorf("artifact path %q must not traverse symbolic links", name)
}
}
return nil
}
func writeAtomic(target string, data []byte, fileMode os.FileMode) error {
temp, err := os.CreateTemp(filepath.Dir(target), "."+filepath.Base(target)+".tmp-*")
if err != nil {
return err