cgroups: fs: fix cgroup.Parent path sanitisation

Properly sanitise the --cgroup-parent path, to avoid potential issues
(as it starts creating directories and writing to files as root). In
addition, fix an infinite recursion due to incomplete base cases.

It might be a good idea to move pathClean to a separate library (which
deals with path safety concerns, so all of runC and Docker can take
advantage of it).

Signed-off-by: Aleksa Sarai <asarai@suse.com>
This commit is contained in:
Aleksa Sarai 2015-12-31 11:05:45 +11:00 committed by Michael Crosby
parent 47e3f834d7
commit f36b00aa12
2 changed files with 32 additions and 0 deletions

View File

@ -230,12 +230,39 @@ func (m *Manager) GetPids() ([]int, error) {
return cgroups.GetPids(dir) return cgroups.GetPids(dir)
} }
// pathClean makes a path safe for use with filepath.Join. This is done by not
// only cleaning the path, but also (if the path is relative) adding a leading
// '/' and cleaning it (then removing the leading '/'). This ensures that a
// path resulting from prepending another path will always resolve to lexically
// be a subdirectory of the prefixed path. This is all done lexically, so paths
// that include symlinks won't be safe as a result of using pathClean.
func pathClean(path string) string {
// Ensure that all paths are cleaned (especially problematic ones like
// "/../../../../../" which can cause lots of issues).
path = filepath.Clean(path)
// If the path isn't absolute, we need to do more processing to fix paths
// such as "../../../../<etc>/some/path". We also shouldn't convert absolute
// paths to relative ones.
if !filepath.IsAbs(path) {
path = filepath.Clean(string(os.PathSeparator) + path)
// This can't fail, as (by definition) all paths are relative to root.
path, _ = filepath.Rel(string(os.PathSeparator), path)
}
// Clean the path again for good measure.
return filepath.Clean(path)
}
func getCgroupData(c *configs.Cgroup, pid int) (*cgroupData, error) { func getCgroupData(c *configs.Cgroup, pid int) (*cgroupData, error) {
root, err := getCgroupRoot() root, err := getCgroupRoot()
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Clean the parent slice path.
c.Parent = pathClean(c.Parent)
return &cgroupData{ return &cgroupData{
root: root, root: root,
parent: c.Parent, parent: c.Parent,

View File

@ -4,6 +4,7 @@ package fs
import ( import (
"bytes" "bytes"
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -95,6 +96,10 @@ func (s *CpusetGroup) ensureParent(current, root string) error {
if filepath.Clean(parent) == root { if filepath.Clean(parent) == root {
return nil return nil
} }
// Avoid infinite recursion.
if parent == current {
return fmt.Errorf("cpuset: cgroup parent path outside cgroup root")
}
if err := s.ensureParent(parent, root); err != nil { if err := s.ensureParent(parent, root); err != nil {
return err return err
} }