Use os.Root for copy operations in vminitd#168
Use os.Root for copy operations in vminitd#168dmcgowan wants to merge 1 commit intocontainerd:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the container filesystem transfer logic in vminitd to anchor copy/export/import operations using os.Root, aiming to prevent path traversal and symlink-escape issues by avoiding destination-path resolution.
Changes:
- Introduces
rootReland migrateswritePathto useos.OpenRoot+root.FS()walking and*os.Rootfile operations. - Migrates
readPathextraction to enforce destination boundaries via a sub-*os.Root, removing prior lexical prefix checks. - Adds comprehensive tests covering tar path traversal, symlink/hardlink attacks, and round-trip export/import behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| internal/transfer/containerfs.go | Switches export/import implementation to *os.Root-anchored operations and adds rootRel helper. |
| internal/transfer/containerfs_test.go | Adds security- and correctness-focused tests for export/import behavior (symlinks, traversal, round-trips). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Signed-off-by: Derek McGowan <derek@mcg.dev>
| // walkPath is always slash-separated (fs.FS contract) and | ||
| // rooted at relPath. Strip the prefix to get the entry's | ||
| // path within the walk. | ||
| rel := strings.TrimPrefix(strings.TrimPrefix(walkPath, relPath), "/") |
There was a problem hiding this comment.
Potential issue for dotfiles at rootfs root:
// TestWritePathExportRootDotfilesPreserved verifies that files whose
// names begin with "." (dotfiles) at the rootfs root are exported with
// their full name intact when src is "/". The double-TrimPrefix in the
// walk loop incorrectly strips the leading "." because relPath is also
// "." — exposing this regression.
func TestWritePathExportRootDotfilesPreserved(t *testing.T) {
_, rootfs, _ := makeRootfs(t)
if err := os.WriteFile(filepath.Join(rootfs, ".bashrc"), []byte("rc"), 0644); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(rootfs, "plain"), []byte("plain"), 0644); err != nil {
t.Fatal(err)
}
buf := &bytes.Buffer{}
if err := writePath(rootfs, "/", buf, mediaTypeTar, false); err != nil {
t.Fatalf("writePath: %v", err)
}
entries := readTar(t, buf)
if _, ok := entries[".bashrc"]; !ok {
t.Errorf("dotfile '.bashrc' missing from tar; got entries: %v", keys(entries))
}
if _, ok := entries["bashrc"]; ok {
t.Errorf("dotfile was renamed to 'bashrc' (leading dot stripped by TrimPrefix bug)")
}
}
Updates the transfer in vminitd to use os.Root rather than path resolution into the destination path