ValidTreePath rejects path strings that, if materialised into a worktree, would let an attacker-controlled tree entry escape the worktree or rewrite repository metadata. It rejects: - control characters (< 0x20, 0x7f); - empty paths and "." / ".." components; - Windows volume name prefixes (e.g. C:
(p string)
| 36 | // |
| 37 | // [1]: https://github.com/git/git/blob/v2.54.0/read-cache.c#L987 |
| 38 | func ValidTreePath(p string) error { |
| 39 | for i := 0; i < len(p); i++ { |
| 40 | if p[i] < 0x20 || p[i] == 0x7f { |
| 41 | return fmt.Errorf("%w %q: contains control character", ErrInvalidPath, p) |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | parts := strings.FieldsFunc(p, func(r rune) bool { return r == '\\' || r == '/' }) |
| 46 | if len(parts) == 0 { |
| 47 | return fmt.Errorf("%w: %q", ErrInvalidPath, p) |
| 48 | } |
| 49 | |
| 50 | // Volume names are not supported, in both formats: \\ and <DRIVE_LETTER>:. |
| 51 | if vol := filepath.VolumeName(p); vol != "" { |
| 52 | return fmt.Errorf("%w: %q", ErrInvalidPath, p) |
| 53 | } |
| 54 | |
| 55 | for _, part := range parts { |
| 56 | if part == "." || part == ".." { |
| 57 | return fmt.Errorf("%w %q: cannot use %q", ErrInvalidPath, p, part) |
| 58 | } |
| 59 | |
| 60 | if IsDotGitName(part) || IsHFSDotGit(part) || IsNTFSDotGit(part) { |
| 61 | return fmt.Errorf("%w component: %q", ErrInvalidPath, p) |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | return nil |
| 66 | } |
searching dependent graphs…