diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go index 9d5fba366e..7e5b313e55 100644 --- a/daemon/daemon_unix.go +++ b/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 } diff --git a/pkg/idtools/idtools_unix.go b/pkg/idtools/idtools_unix.go index b57d6ef125..dcbb305f69 100644 --- a/pkg/idtools/idtools_unix.go +++ b/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 +} diff --git a/pkg/idtools/idtools_windows.go b/pkg/idtools/idtools_windows.go index c9e3c937cd..49f67e78c1 100644 --- a/pkg/idtools/idtools_windows.go +++ b/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 +}