serve docker: reject volume names resolving to the base directory itself GHSA-p6vx-hf7p-98j6

An empty or "." volume name joined onto the base directory resolves to the
base directory itself. newVolume does not call validate, so such a name
would mount a remote over the base directory and shadow every other
volume's mountpoint.

Require the resolved mountpoint to be a strict descendant of the base
directory so these degenerate names are refused.
This commit is contained in:
Nick Craig-Wood
2026-09-04 19:00:22 +01:00
parent f5795d00c2
commit 142172c21f
2 changed files with 16 additions and 4 deletions
+10
View File
@@ -245,6 +245,16 @@ func TestDockerPluginVolumeNameConfined(t *testing.T) {
// The volume must not have been registered.
_, err = drv.Get(&docker.GetRequest{Name: escape})
assert.Error(t, err)
// A name that resolves to the base directory itself (empty or ".")
// must also be rejected, since mounting there would shadow every
// other volume.
for _, name := range []string{"", ".", filepath.Join("a", "..")} {
volReq.Name = name
err = drv.Create(volReq)
assertErrorContains(t, err, "resolves outside the base directory",
"name %q should be rejected", name)
}
}
// TestDockerPluginRestoreStateConfined checks that a persisted state file
+6 -4
View File
@@ -56,16 +56,18 @@ type VolInfo struct {
}
// volumeMountPath returns the mountpoint for a volume called name below
// root, together with whether that path stays confined within root.
// root, together with whether that path is a strict descendant of root.
//
// filepath.Join cleans its result, collapsing any ".." components in the
// volume name, so a crafted name could otherwise resolve to an arbitrary
// host path outside root. Callers must reject names for which confined is
// false rather than creating a directory and mounting there.
// host path outside root, or to root itself (for an empty or "." name)
// where a mount would shadow every other volume. Callers must reject names
// for which confined is false rather than creating a directory and mounting
// there.
func volumeMountPath(root, name string) (path string, confined bool) {
path = filepath.Join(root, name)
root = filepath.Clean(root)
return path, path == root || strings.HasPrefix(path, root+string(filepath.Separator))
return path, strings.HasPrefix(path, root+string(filepath.Separator))
}
func newVolume(ctx context.Context, name string, volOpt VolOpts, drv *Driver) (*Volume, error) {