carlos / platform Public

hostfiles: removePastCap refuses a final name that is not plain ("", ".", ".."), as descendCtx refuses such a directory component (census ruling condition 2, platform-1e)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paul Campbell pushed by claude agent, operated by paul@keymail.dev cc1c3d2401da879f5763fa19cbc576449eae78e4 parent 3ab48ff
2 files changed, +22 −0
  • internal/hostfiles/fix5_linux_test.go +16 −0
  • internal/hostfiles/restore_unix.go +6 −0
diff --git a/internal/hostfiles/fix5_linux_test.go b/internal/hostfiles/fix5_linux_test.go
index 8a9824237..a394664a6 100644
--- a/internal/hostfiles/fix5_linux_test.go
+++ b/internal/hostfiles/fix5_linux_test.go
@@ -433,3 +433,19 @@ func TestRestoreNeverFollowsASymlinkOnADeepTombstone(t *testing.T) {
})
}
}
+
+// The census ruling for removePastCap (platform-1e, #236) holds it to a
+// plain final name, as descendCtx holds each directory component: an
+// empty, "." or ".." final name refuses, and nothing is removed.
+func TestRemovePastCapRefusesANameThatIsNotPlain(t *testing.T) {
+ r, err := os.OpenRoot(t.TempDir())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer r.Close()
+ for _, rel := range []string{"a/", "a/.", "a/..", ".."} {
+ if removed, err := removePastCap(context.Background(), r, rel); err == nil || removed {
+ t.Fatalf("removePastCap(%q): %v, removed %v", rel, err, removed)
+ }
+ }
+}
diff --git a/internal/hostfiles/restore_unix.go b/internal/hostfiles/restore_unix.go
index 5bff6bd08..8f935e1d4 100644
--- a/internal/hostfiles/restore_unix.go
+++ b/internal/hostfiles/restore_unix.go
@@ -7,6 +7,7 @@ import (
"errors"
"os"
"path"
+ "strconv"
"strings"
"golang.org/x/sys/unix"
@@ -43,6 +44,11 @@ func removePastCap(ctx context.Context, root *os.Root, rel string) (bool, error)
return false, err
}
parent, name := path.Split(rel)
+ if name == "" || name == "." || name == ".." {
+ // descendCtx refuses such a directory component; the final name is
+ // held to the same rule, so only a plain name is ever unlinked.
+ return false, errors.New("hostfiles: path component " + strconv.Quote(name) + " in " + strconv.Quote(rel) + " is not a plain name")
+ }
dir, gone, err := top.descendCtx(ctx, strings.TrimSuffix(parent, "/"))
if err != nil || gone {
return false, err