From 21dc85c4b830f1b2ae2da875690b9086e6c5fb58 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Fri, 12 Feb 2016 18:46:17 +1100 Subject: [PATCH] libcontainer: cgroups: fs: add cgroup path safety unit tests In order to avoid problems with security regressions going unnoticed, add some unit tests that should make sure security regressions in cgroup path safety cause tests to fail in runC. Signed-off-by: Aleksa Sarai --- libcontainer/cgroups/fs/apply_raw_test.go | 272 ++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 libcontainer/cgroups/fs/apply_raw_test.go diff --git a/libcontainer/cgroups/fs/apply_raw_test.go b/libcontainer/cgroups/fs/apply_raw_test.go new file mode 100644 index 00000000..ba4e9e54 --- /dev/null +++ b/libcontainer/cgroups/fs/apply_raw_test.go @@ -0,0 +1,272 @@ +// +build linux + +package fs + +import ( + "path/filepath" + "strings" + "testing" + + "github.com/opencontainers/runc/libcontainer/configs" +) + +func TestInvalidCgroupPath(t *testing.T) { + root, err := getCgroupRoot() + if err != nil { + t.Errorf("couldn't get cgroup root: %v", err) + } + + config := &configs.Cgroup{ + Path: "../../../../../../../../../../some/path", + } + + data, err := getCgroupData(config, 0) + if err != nil { + t.Errorf("couldn't get cgroup data: %v", err) + } + + // Make sure the final innerPath doesn't go outside the cgroup mountpoint. + if strings.HasPrefix(data.innerPath, "..") { + t.Errorf("SECURITY: cgroup innerPath is outside cgroup mountpoint!") + } + + // Double-check, using an actual cgroup. + deviceRoot := filepath.Join(root, "devices") + devicePath, err := data.path("devices") + if err != nil { + t.Errorf("couldn't get cgroup path: %v", err) + } + if !strings.HasPrefix(devicePath, deviceRoot) { + t.Errorf("SECURITY: cgroup path() is outside cgroup mountpoint!") + } +} + +func TestInvalidAbsoluteCgroupPath(t *testing.T) { + root, err := getCgroupRoot() + if err != nil { + t.Errorf("couldn't get cgroup root: %v", err) + } + + config := &configs.Cgroup{ + Path: "/../../../../../../../../../../some/path", + } + + data, err := getCgroupData(config, 0) + if err != nil { + t.Errorf("couldn't get cgroup data: %v", err) + } + + // Make sure the final innerPath doesn't go outside the cgroup mountpoint. + if strings.HasPrefix(data.innerPath, "..") { + t.Errorf("SECURITY: cgroup innerPath is outside cgroup mountpoint!") + } + + // Double-check, using an actual cgroup. + deviceRoot := filepath.Join(root, "devices") + devicePath, err := data.path("devices") + if err != nil { + t.Errorf("couldn't get cgroup path: %v", err) + } + if !strings.HasPrefix(devicePath, deviceRoot) { + t.Errorf("SECURITY: cgroup path() is outside cgroup mountpoint!") + } +} + +// XXX: Remove me after we get rid of configs.Cgroup.Name and configs.Cgroup.Parent. +func TestInvalidCgroupParent(t *testing.T) { + root, err := getCgroupRoot() + if err != nil { + t.Errorf("couldn't get cgroup root: %v", err) + } + + config := &configs.Cgroup{ + Parent: "../../../../../../../../../../some/path", + Name: "name", + } + + data, err := getCgroupData(config, 0) + if err != nil { + t.Errorf("couldn't get cgroup data: %v", err) + } + + // Make sure the final innerPath doesn't go outside the cgroup mountpoint. + if strings.HasPrefix(data.innerPath, "..") { + t.Errorf("SECURITY: cgroup innerPath is outside cgroup mountpoint!") + } + + // Double-check, using an actual cgroup. + deviceRoot := filepath.Join(root, "devices") + devicePath, err := data.path("devices") + if err != nil { + t.Errorf("couldn't get cgroup path: %v", err) + } + if !strings.HasPrefix(devicePath, deviceRoot) { + t.Errorf("SECURITY: cgroup path() is outside cgroup mountpoint!") + } +} + +// XXX: Remove me after we get rid of configs.Cgroup.Name and configs.Cgroup.Parent. +func TestInvalidAbsoluteCgroupParent(t *testing.T) { + root, err := getCgroupRoot() + if err != nil { + t.Errorf("couldn't get cgroup root: %v", err) + } + + config := &configs.Cgroup{ + Parent: "/../../../../../../../../../../some/path", + Name: "name", + } + + data, err := getCgroupData(config, 0) + if err != nil { + t.Errorf("couldn't get cgroup data: %v", err) + } + + // Make sure the final innerPath doesn't go outside the cgroup mountpoint. + if strings.HasPrefix(data.innerPath, "..") { + t.Errorf("SECURITY: cgroup innerPath is outside cgroup mountpoint!") + } + + // Double-check, using an actual cgroup. + deviceRoot := filepath.Join(root, "devices") + devicePath, err := data.path("devices") + if err != nil { + t.Errorf("couldn't get cgroup path: %v", err) + } + if !strings.HasPrefix(devicePath, deviceRoot) { + t.Errorf("SECURITY: cgroup path() is outside cgroup mountpoint!") + } +} + +// XXX: Remove me after we get rid of configs.Cgroup.Name and configs.Cgroup.Parent. +func TestInvalidCgroupName(t *testing.T) { + root, err := getCgroupRoot() + if err != nil { + t.Errorf("couldn't get cgroup root: %v", err) + } + + config := &configs.Cgroup{ + Parent: "parent", + Name: "../../../../../../../../../../some/path", + } + + data, err := getCgroupData(config, 0) + if err != nil { + t.Errorf("couldn't get cgroup data: %v", err) + } + + // Make sure the final innerPath doesn't go outside the cgroup mountpoint. + if strings.HasPrefix(data.innerPath, "..") { + t.Errorf("SECURITY: cgroup innerPath is outside cgroup mountpoint!") + } + + // Double-check, using an actual cgroup. + deviceRoot := filepath.Join(root, "devices") + devicePath, err := data.path("devices") + if err != nil { + t.Errorf("couldn't get cgroup path: %v", err) + } + if !strings.HasPrefix(devicePath, deviceRoot) { + t.Errorf("SECURITY: cgroup path() is outside cgroup mountpoint!") + } + +} + +// XXX: Remove me after we get rid of configs.Cgroup.Name and configs.Cgroup.Parent. +func TestInvalidAbsoluteCgroupName(t *testing.T) { + root, err := getCgroupRoot() + if err != nil { + t.Errorf("couldn't get cgroup root: %v", err) + } + + config := &configs.Cgroup{ + Parent: "parent", + Name: "/../../../../../../../../../../some/path", + } + + data, err := getCgroupData(config, 0) + if err != nil { + t.Errorf("couldn't get cgroup data: %v", err) + } + + // Make sure the final innerPath doesn't go outside the cgroup mountpoint. + if strings.HasPrefix(data.innerPath, "..") { + t.Errorf("SECURITY: cgroup innerPath is outside cgroup mountpoint!") + } + + // Double-check, using an actual cgroup. + deviceRoot := filepath.Join(root, "devices") + devicePath, err := data.path("devices") + if err != nil { + t.Errorf("couldn't get cgroup path: %v", err) + } + if !strings.HasPrefix(devicePath, deviceRoot) { + t.Errorf("SECURITY: cgroup path() is outside cgroup mountpoint!") + } +} + +// XXX: Remove me after we get rid of configs.Cgroup.Name and configs.Cgroup.Parent. +func TestInvalidCgroupNameAndParent(t *testing.T) { + root, err := getCgroupRoot() + if err != nil { + t.Errorf("couldn't get cgroup root: %v", err) + } + + config := &configs.Cgroup{ + Parent: "../../../../../../../../../../some/path", + Name: "../../../../../../../../../../some/path", + } + + data, err := getCgroupData(config, 0) + if err != nil { + t.Errorf("couldn't get cgroup data: %v", err) + } + + // Make sure the final innerPath doesn't go outside the cgroup mountpoint. + if strings.HasPrefix(data.innerPath, "..") { + t.Errorf("SECURITY: cgroup innerPath is outside cgroup mountpoint!") + } + + // Double-check, using an actual cgroup. + deviceRoot := filepath.Join(root, "devices") + devicePath, err := data.path("devices") + if err != nil { + t.Errorf("couldn't get cgroup path: %v", err) + } + if !strings.HasPrefix(devicePath, deviceRoot) { + t.Errorf("SECURITY: cgroup path() is outside cgroup mountpoint!") + } +} + +// XXX: Remove me after we get rid of configs.Cgroup.Name and configs.Cgroup.Parent. +func TestInvalidAbsoluteCgroupNameAndParent(t *testing.T) { + root, err := getCgroupRoot() + if err != nil { + t.Errorf("couldn't get cgroup root: %v", err) + } + + config := &configs.Cgroup{ + Parent: "/../../../../../../../../../../some/path", + Name: "/../../../../../../../../../../some/path", + } + + data, err := getCgroupData(config, 0) + if err != nil { + t.Errorf("couldn't get cgroup data: %v", err) + } + + // Make sure the final innerPath doesn't go outside the cgroup mountpoint. + if strings.HasPrefix(data.innerPath, "..") { + t.Errorf("SECURITY: cgroup innerPath is outside cgroup mountpoint!") + } + + // Double-check, using an actual cgroup. + deviceRoot := filepath.Join(root, "devices") + devicePath, err := data.path("devices") + if err != nil { + t.Errorf("couldn't get cgroup path: %v", err) + } + if !strings.HasPrefix(devicePath, deviceRoot) { + t.Errorf("SECURITY: cgroup path() is outside cgroup mountpoint!") + } +}