carlos / platform Public

rootfsimage: a directory source's root is always 0:0 0755 (rootfs Plan 1 Task 5, fix)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 8bb143750846ebf173338bcfdb6d0727c845de00 parent 5b033e7
2 files changed, +27 −2
  • internal/rootfsimage/dir.go +7 −2
  • internal/rootfsimage/dir_test.go +20 −0
diff --git a/internal/rootfsimage/dir.go b/internal/rootfsimage/dir.go
index 31cc89322..9b9eda4ef 100644
--- a/internal/rootfsimage/dir.go
+++ b/internal/rootfsimage/dir.go
@@ -12,7 +12,9 @@ import (
// root, and what it holds is the image's files.
//
// Every entry is owned by 0:0, since a developer's own uid means nothing on
-// a box. Modes and times come from Lstat. A regular file is not copied: its
+// a box: Entry's UID and GID are never set from the source, and the tests
+// check every entry. Modes and times come from Lstat, except the root, which
+// is always mode 0755. A regular file is not copied: its
// src is its path in the directory, so the spool stays empty and the bytes
// are read when something opens the entry. Hardlinks (one device and inode)
// share one src. A symlink is kept as the link it is, with its target as it
@@ -49,7 +51,10 @@ func readDir(t *Tree, dir string) error {
if !fi.IsDir() {
return fmt.Errorf("rootfsimage: %s is not a directory", shown(dir))
}
- t.Root = Entry{Path: ".", Type: TypeDir, Mode: modeOf(fi), ModTime: timeOf(fi)}
+ // The root is 0:0 0755 whatever the source directory is: boxes run
+ // processes as an unprivileged user, and a 0700 root (a mktemp -d
+ // source) would make the image unenterable. Only its time is the source's.
+ t.Root = Entry{Path: ".", Type: TypeDir, Mode: 0o755, ModTime: timeOf(fi)}
type fileKey struct{ dev, ino uint64 }
linked := map[fileKey]string{} // the src of the first name of a multiply linked file
diff --git a/internal/rootfsimage/dir_test.go b/internal/rootfsimage/dir_test.go
index 643c8d49c..866d132ac 100644
--- a/internal/rootfsimage/dir_test.go
+++ b/internal/rootfsimage/dir_test.go
@@ -69,11 +69,31 @@ func TestOpenDirOwnsEverythingByRoot(t *testing.T) {
if tr.Root.UID != 0 || tr.Root.GID != 0 {
t.Errorf("root owner = %d:%d, want 0:0", tr.Root.UID, tr.Root.GID)
}
+ for _, e := range tr.Entries() {
+ if e.UID != 0 || e.GID != 0 {
+ t.Errorf("%s owner = %d:%d, want 0:0", e.Path, e.UID, e.GID)
+ }
+ }
if tr.Files() != 3 {
t.Errorf("Files = %d, want 3", tr.Files())
}
}
+func TestOpenDirRootIs0755RootWhateverTheSource(t *testing.T) {
+ dir := t.TempDir()
+ writeSrc(t, filepath.Join(dir, "f"), "x", 0o644)
+ if err := os.Chmod(dir, 0o700); err != nil {
+ t.Fatal(err)
+ }
+ tr, err := OpenDir(dir, t.TempDir())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if tr.Root.Mode != 0o755 || tr.Root.UID != 0 || tr.Root.GID != 0 {
+ t.Errorf("root = mode %v owner %d:%d, want 0755 0:0", tr.Root.Mode, tr.Root.UID, tr.Root.GID)
+ }
+}
+
func TestOpenDirReadsInPlaceAndKeepsHardlinks(t *testing.T) {
dir := t.TempDir()
writeSrc(t, filepath.Join(dir, "a"), "same", 0o644)