Browse Source

Merge pull request #25959 from estesp/fail-on-graphdir-perms

Don't start daemon in userns mode if graphdir inaccessible
Vincent Demeester 8 years ago
parent
commit
4a1b048c15

+ 14 - 0
daemon/daemon_unix.go

@@ -1004,6 +1004,20 @@ func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error
 		if err := idtools.MkdirAllAs(config.Root, 0700, rootUID, rootGID); err != nil {
 			return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err)
 		}
+		// we also need to verify that any pre-existing directories in the path to
+		// the graphroot won't block access to remapped root--if any pre-existing directory
+		// has strict permissions that don't allow "x", container start will fail, so
+		// better to warn and fail now
+		dirPath := config.Root
+		for {
+			dirPath = filepath.Dir(dirPath)
+			if dirPath == "/" {
+				break
+			}
+			if !idtools.CanAccess(dirPath, rootUID, rootGID) {
+				return fmt.Errorf("A subdirectory in your graphroot path (%s) restricts access to the remapped root uid/gid; please fix by allowing 'o+x' permissions on existing directories.", config.Root)
+			}
+		}
 	}
 	return nil
 }

+ 26 - 0
pkg/idtools/idtools_unix.go

@@ -58,3 +58,29 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
 	}
 	return nil
 }
+
+// CanAccess takes a valid (existing) directory and a uid, gid pair and determines
+// if that uid, gid pair has access (execute bit) to the directory
+func CanAccess(path string, uid, gid int) bool {
+	statInfo, err := system.Stat(path)
+	if err != nil {
+		return false
+	}
+	fileMode := os.FileMode(statInfo.Mode())
+	permBits := fileMode.Perm()
+	return accessible(statInfo.UID() == uint32(uid),
+		statInfo.GID() == uint32(gid), permBits)
+}
+
+func accessible(isOwner, isGroup bool, perms os.FileMode) bool {
+	if isOwner && (perms&0100 == 0100) {
+		return true
+	}
+	if isGroup && (perms&0010 == 0010) {
+		return true
+	}
+	if perms&0001 == 0001 {
+		return true
+	}
+	return false
+}

+ 7 - 0
pkg/idtools/idtools_windows.go

@@ -16,3 +16,10 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
 	}
 	return nil
 }
+
+// CanAccess takes a valid (existing) directory and a uid, gid pair and determines
+// if that uid, gid pair has access (execute bit) to the directory
+// Windows does not require/support this function, so always return true
+func CanAccess(path string, uid, gid int) bool {
+	return true
+}

+ 32 - 0
pkg/system/stat_darwin.go

@@ -0,0 +1,32 @@
+package system
+
+import (
+	"syscall"
+)
+
+// fromStatT creates a system.StatT type from a syscall.Stat_t type
+func fromStatT(s *syscall.Stat_t) (*StatT, error) {
+	return &StatT{size: s.Size,
+		mode: uint32(s.Mode),
+		uid:  s.Uid,
+		gid:  s.Gid,
+		rdev: uint64(s.Rdev),
+		mtim: s.Mtimespec}, nil
+}
+
+// FromStatT loads a system.StatT from a syscall.Stat_t.
+func FromStatT(s *syscall.Stat_t) (*StatT, error) {
+	return fromStatT(s)
+}
+
+// Stat takes a path to a file and returns
+// a system.StatT type pertaining to that file.
+//
+// Throws an error if the file does not exist
+func Stat(path string) (*StatT, error) {
+	s := &syscall.Stat_t{}
+	if err := syscall.Stat(path, s); err != nil {
+		return nil, err
+	}
+	return fromStatT(s)
+}

+ 1 - 1
pkg/system/stat_unsupported.go

@@ -1,4 +1,4 @@
-// +build !linux,!windows,!freebsd,!solaris,!openbsd
+// +build !linux,!windows,!freebsd,!solaris,!openbsd,!darwin
 
 package system