Skip to content

Commit bf899fe

Browse files
committed
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 <[email protected]>
1 parent d97d5e8 commit bf899fe

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

libcontainer/cgroups/fs/apply_raw.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,12 +230,39 @@ func (m *Manager) GetPids() ([]int, error) {
230230
return cgroups.GetPids(dir)
231231
}
232232

233+
// pathClean makes a path safe for use with filepath.Join. This is done by not
234+
// only cleaning the path, but also (if the path is relative) adding a leading
235+
// '/' and cleaning it (then removing the leading '/'). This ensures that a
236+
// path resulting from prepending another path will always resolve to lexically
237+
// be a subdirectory of the prefixed path. This is all done lexically, so paths
238+
// that include symlinks won't be safe as a result of using pathClean.
239+
func pathClean(path string) string {
240+
// Ensure that all paths are cleaned (especially problematic ones like
241+
// "/../../../../../" which can cause lots of issues).
242+
path = filepath.Clean(path)
243+
244+
// If the path isn't absolute, we need to do more processing to fix paths
245+
// such as "../../../../<etc>/some/path". We also shouldn't convert absolute
246+
// paths to relative ones.
247+
if !filepath.IsAbs(path) {
248+
path = filepath.Clean(string(os.PathSeparator) + path)
249+
// This can't fail, as (by definition) all paths are relative to root.
250+
path, _ = filepath.Rel(string(os.PathSeparator), path)
251+
}
252+
253+
// Clean the path again for good measure.
254+
return filepath.Clean(path)
255+
}
256+
233257
func getCgroupData(c *configs.Cgroup, pid int) (*cgroupData, error) {
234258
root, err := getCgroupRoot()
235259
if err != nil {
236260
return nil, err
237261
}
238262

263+
// Clean the parent slice path.
264+
c.Parent = pathClean(c.Parent)
265+
239266
return &cgroupData{
240267
root: root,
241268
parent: c.Parent,

libcontainer/cgroups/fs/cpuset.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package fs
44

55
import (
66
"bytes"
7+
"fmt"
78
"io/ioutil"
89
"os"
910
"path/filepath"
@@ -95,6 +96,10 @@ func (s *CpusetGroup) ensureParent(current, root string) error {
9596
if filepath.Clean(parent) == root {
9697
return nil
9798
}
99+
// Avoid infinite recursion.
100+
if parent == current {
101+
return fmt.Errorf("cpuset: cgroup parent path outside cgroup root")
102+
}
98103
if err := s.ensureParent(parent, root); err != nil {
99104
return err
100105
}

0 commit comments

Comments
 (0)