|
@@ -15,6 +15,7 @@ import (
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
"sync"
|
|
|
+ "syscall"
|
|
|
"time"
|
|
|
|
|
|
"github.com/containerd/cgroups"
|
|
@@ -1247,7 +1248,7 @@ func setupDaemonRoot(config *config.Config, rootDir string, remappedRoot idtools
|
|
|
if dirPath == "/" {
|
|
|
break
|
|
|
}
|
|
|
- if !idtools.CanAccess(dirPath, remappedRoot) {
|
|
|
+ if !canAccess(dirPath, remappedRoot) {
|
|
|
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)
|
|
|
}
|
|
|
}
|
|
@@ -1259,6 +1260,34 @@ func setupDaemonRoot(config *config.Config, rootDir string, remappedRoot idtools
|
|
|
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.
|
|
|
+//
|
|
|
+// Note: this is a very rudimentary check, and may not produce accurate results,
|
|
|
+// so should not be used for anything other than the current use, see:
|
|
|
+// https://github.com/moby/moby/issues/43724
|
|
|
+func canAccess(path string, pair idtools.Identity) bool {
|
|
|
+ statInfo, err := os.Stat(path)
|
|
|
+ if err != nil {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ perms := statInfo.Mode().Perm()
|
|
|
+ if perms&0o001 == 0o001 {
|
|
|
+ // world access
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ ssi := statInfo.Sys().(*syscall.Stat_t)
|
|
|
+ if ssi.Uid == uint32(pair.UID) && (perms&0o100 == 0o100) {
|
|
|
+ // owner access.
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ if ssi.Gid == uint32(pair.GID) && (perms&0o010 == 0o010) {
|
|
|
+ // group access.
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
func setupDaemonRootPropagation(cfg *config.Config) error {
|
|
|
rootParentMount, mountOptions, err := getSourceMount(cfg.Root)
|
|
|
if err != nil {
|