A managed volume plugin could return a path containing dot-dot elements that passed the propagated-mount string prefix check, then escaped the host mount root when filepath.Join cleaned it. Sibling paths sharing the same string prefix were also treated as propagated paths. Normalize returned paths in the plugin's rooted namespace. Use filepath.Rel and filepath.IsLocal so only path-component descendants are mapped through the propagated mount. Other paths remain confined beneath the plugin rootfs. Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
89 lines
2.2 KiB
Go
89 lines
2.2 KiB
Go
package v2
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/moby/moby/api/types/plugin"
|
|
"gotest.tools/v3/assert"
|
|
)
|
|
|
|
func TestScopedPath(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
propagatedMount string
|
|
path string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "ordinary rootfs path",
|
|
propagatedMount: "/propagated",
|
|
path: "/etc/plugin.json",
|
|
expected: "/plugin/rootfs/etc/plugin.json",
|
|
},
|
|
{
|
|
name: "exact propagated root",
|
|
propagatedMount: "/propagated",
|
|
path: "/propagated",
|
|
expected: "/plugin/propagated-mount",
|
|
},
|
|
{
|
|
name: "propagated child",
|
|
propagatedMount: "/propagated",
|
|
path: "/propagated/child",
|
|
expected: "/plugin/propagated-mount/child",
|
|
},
|
|
{
|
|
name: "in-subtree normalization",
|
|
propagatedMount: "/propagated",
|
|
path: "/propagated/subtree/../child",
|
|
expected: "/plugin/propagated-mount/child",
|
|
},
|
|
{
|
|
name: "reported traversal escape",
|
|
propagatedMount: "/propagated",
|
|
path: "/propagated/../../../volumes/victim/_data",
|
|
expected: "/plugin/rootfs/volumes/victim/_data",
|
|
},
|
|
{
|
|
name: "sibling prefix path",
|
|
propagatedMount: "/propagated",
|
|
path: "/propagated-other/child",
|
|
expected: "/plugin/rootfs/propagated-other/child",
|
|
},
|
|
{
|
|
name: "relative dot-dot containment",
|
|
propagatedMount: "/propagated",
|
|
path: "../../../outside",
|
|
expected: "/plugin/rootfs/outside",
|
|
},
|
|
{
|
|
name: "trailing separator",
|
|
propagatedMount: "/propagated/",
|
|
path: "/propagated/",
|
|
expected: "/plugin/propagated-mount",
|
|
},
|
|
{
|
|
name: "propagated root slash",
|
|
propagatedMount: "/",
|
|
path: "/var/lib",
|
|
expected: "/plugin/propagated-mount/var/lib",
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
p := &Plugin{
|
|
Rootfs: "/plugin/rootfs",
|
|
PluginObj: plugin.Plugin{
|
|
Config: plugin.Config{PropagatedMount: tc.propagatedMount},
|
|
},
|
|
}
|
|
assert.Equal(t, p.ScopedPath(tc.path), tc.expected)
|
|
})
|
|
}
|
|
}
|