diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-14 19:42:17 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-14 19:42:17 +0200 |
| commit | 00aae60378982902b871a87850e0ed427b28a347 (patch) | |
| tree | dffaba9ffadc517b50c175595e5c509f5d826221 /internal/trash/trash.go | |
| parent | eab84ab42f51beab5debc03b8049f0929c5e8904 (diff) | |
| download | krino-00aae60378982902b871a87850e0ed427b28a347.tar.gz krino-00aae60378982902b871a87850e0ed427b28a347.zip | |
plan 8: trash refuses unsafe entry names and relative paths
Diffstat (limited to 'internal/trash/trash.go')
| -rw-r--r-- | internal/trash/trash.go | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/internal/trash/trash.go b/internal/trash/trash.go index cc9bc23..b96c3aa 100644 --- a/internal/trash/trash.go +++ b/internal/trash/trash.go @@ -174,7 +174,9 @@ func percentDecode(s string) string { } // Restore moves an entry back to the Path recorded in its .trashinfo and -// removes the .trashinfo. It refuses when that path already exists. +// removes the .trashinfo. It refuses when that path already exists. It also +// refuses an entry that is not a plain name inside the Trash, and a +// trashinfo whose Path is not absolute. // // Once the rename back to the original path has succeeded, removing the // .trashinfo is best-effort: that file back in place is the substantive @@ -183,6 +185,11 @@ func percentDecode(s string) string { // as an error — Restore returns (path, nil) regardless — and the // .trashinfo may survive as a stale, otherwise-harmless record. func Restore(entry string) (restored string, err error) { + // An entry comes from the log; it must name something inside the Trash + // (spec §15.1), never a path that climbs out of it. + if entry == "" || entry == "." || entry == ".." || strings.ContainsRune(entry, '/') { + return "", fmt.Errorf("trash: bad entry name %q", entry) + } infoPath := filepath.Join(infoDir(), entry+".trashinfo") b, err := os.ReadFile(infoPath) if err != nil { @@ -211,11 +218,17 @@ func Restore(entry string) (restored string, err error) { return path, nil } -// parsePath extracts and decodes the Path= line of a .trashinfo file. +// parsePath extracts and decodes the Path= line of a .trashinfo file. The +// path must be absolute: Restore must never resolve one against the +// working directory. func parsePath(info string) (string, error) { for _, line := range strings.Split(info, "\n") { if v, ok := strings.CutPrefix(line, "Path="); ok { - return percentDecode(v), nil + p := percentDecode(v) + if !filepath.IsAbs(p) { + return "", fmt.Errorf("trashinfo path %q is not absolute", p) + } + return p, nil } } return "", errors.New("trashinfo has no path") |
