Signed-off-by: Daniel Nephin <dnephin@docker.com>
Daniel Nephin authored on 2017/05/20 07:06:46... | ... |
@@ -216,7 +216,7 @@ func (container *Container) WriteHostConfig() error { |
216 | 216 |
} |
217 | 217 |
|
218 | 218 |
// SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir |
219 |
-func (container *Container) SetupWorkingDirectory(rootUID, rootGID int) error { |
|
219 |
+func (container *Container) SetupWorkingDirectory(rootIDs idtools.IDPair) error { |
|
220 | 220 |
if container.Config.WorkingDir == "" { |
221 | 221 |
return nil |
222 | 222 |
} |
... | ... |
@@ -228,7 +228,7 @@ func (container *Container) SetupWorkingDirectory(rootUID, rootGID int) error { |
228 | 228 |
return err |
229 | 229 |
} |
230 | 230 |
|
231 |
- if err := idtools.MkdirAllNewAs(pth, 0755, rootUID, rootGID); err != nil { |
|
231 |
+ if err := idtools.MkdirAllAndChownNew(pth, 0755, rootIDs); err != nil { |
|
232 | 232 |
pthInfo, err2 := os.Stat(pth) |
233 | 233 |
if err2 == nil && pthInfo != nil && !pthInfo.IsDir() { |
234 | 234 |
return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir) |
... | ... |
@@ -375,7 +375,7 @@ func (daemon *Daemon) CopyOnBuild(cID, destPath, srcRoot, srcPath string, decomp |
375 | 375 |
|
376 | 376 |
destExists := true |
377 | 377 |
destDir := false |
378 |
- rootUID, rootGID := daemon.GetRemappedUIDGID() |
|
378 |
+ rootIDs, _ := daemon.idMappings.RootPair() |
|
379 | 379 |
|
380 | 380 |
// Work in daemon-local OS specific file paths |
381 | 381 |
destPath = filepath.FromSlash(destPath) |
... | ... |
@@ -413,11 +413,10 @@ func (daemon *Daemon) CopyOnBuild(cID, destPath, srcRoot, srcPath string, decomp |
413 | 413 |
destExists = false |
414 | 414 |
} |
415 | 415 |
|
416 |
- uidMaps, gidMaps := daemon.GetUIDGIDMaps() |
|
417 | 416 |
archiver := &archive.Archiver{ |
418 | 417 |
Untar: chrootarchive.Untar, |
419 |
- UIDMaps: uidMaps, |
|
420 |
- GIDMaps: gidMaps, |
|
418 |
+ UIDMaps: daemon.idMappings.UIDs(), |
|
419 |
+ GIDMaps: daemon.idMappings.GIDs(), |
|
421 | 420 |
} |
422 | 421 |
|
423 | 422 |
src, err := os.Stat(fullSrcPath) |
... | ... |
@@ -430,7 +429,7 @@ func (daemon *Daemon) CopyOnBuild(cID, destPath, srcRoot, srcPath string, decomp |
430 | 430 |
if err := archiver.CopyWithTar(fullSrcPath, destPath); err != nil { |
431 | 431 |
return err |
432 | 432 |
} |
433 |
- return fixPermissions(fullSrcPath, destPath, rootUID, rootGID, destExists) |
|
433 |
+ return fixPermissions(fullSrcPath, destPath, rootIDs.UID, rootIDs.GID, destExists) |
|
434 | 434 |
} |
435 | 435 |
if decompress && archive.IsArchivePath(fullSrcPath) { |
436 | 436 |
// Only try to untar if it is a file and that we've been told to decompress (when ADD-ing a remote file) |
... | ... |
@@ -459,12 +458,12 @@ func (daemon *Daemon) CopyOnBuild(cID, destPath, srcRoot, srcPath string, decomp |
459 | 459 |
destPath = filepath.Join(destPath, filepath.Base(srcPath)) |
460 | 460 |
} |
461 | 461 |
|
462 |
- if err := idtools.MkdirAllNewAs(filepath.Dir(destPath), 0755, rootUID, rootGID); err != nil { |
|
462 |
+ if err := idtools.MkdirAllAndChownNew(filepath.Dir(destPath), 0755, rootIDs); err != nil { |
|
463 | 463 |
return err |
464 | 464 |
} |
465 | 465 |
if err := archiver.CopyFileWithTar(fullSrcPath, destPath); err != nil { |
466 | 466 |
return err |
467 | 467 |
} |
468 | 468 |
|
469 |
- return fixPermissions(fullSrcPath, destPath, rootUID, rootGID, destExists) |
|
469 |
+ return fixPermissions(fullSrcPath, destPath, rootIDs.UID, rootIDs.GID, destExists) |
|
470 | 470 |
} |
... | ... |
@@ -7,10 +7,9 @@ import ( |
7 | 7 |
// defaultTarCopyOptions is the setting that is used when unpacking an archive |
8 | 8 |
// for a copy API event. |
9 | 9 |
func (daemon *Daemon) defaultTarCopyOptions(noOverwriteDirNonDir bool) *archive.TarOptions { |
10 |
- uidMaps, gidMaps := daemon.GetUIDGIDMaps() |
|
11 | 10 |
return &archive.TarOptions{ |
12 | 11 |
NoOverwriteDirNonDir: noOverwriteDirNonDir, |
13 |
- UIDMaps: uidMaps, |
|
14 |
- GIDMaps: gidMaps, |
|
12 |
+ UIDMaps: daemon.idMappings.UIDs(), |
|
13 |
+ GIDMaps: daemon.idMappings.GIDs(), |
|
15 | 14 |
} |
16 | 15 |
} |
... | ... |
@@ -109,14 +109,14 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error { |
109 | 109 |
} |
110 | 110 |
c.ShmPath = "/dev/shm" |
111 | 111 |
} else { |
112 |
- rootUID, rootGID := daemon.GetRemappedUIDGID() |
|
112 |
+ rootIDs, _ := daemon.idMappings.RootPair() |
|
113 | 113 |
if !c.HasMountFor("/dev/shm") { |
114 | 114 |
shmPath, err := c.ShmResourcePath() |
115 | 115 |
if err != nil { |
116 | 116 |
return err |
117 | 117 |
} |
118 | 118 |
|
119 |
- if err := idtools.MkdirAllAs(shmPath, 0700, rootUID, rootGID); err != nil { |
|
119 |
+ if err := idtools.MkdirAllAndChown(shmPath, 0700, rootIDs); err != nil { |
|
120 | 120 |
return err |
121 | 121 |
} |
122 | 122 |
|
... | ... |
@@ -128,7 +128,7 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error { |
128 | 128 |
if err := syscall.Mount("shm", shmPath, "tmpfs", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), label.FormatMountLabel(shmproperty, c.GetMountLabel())); err != nil { |
129 | 129 |
return fmt.Errorf("mounting shm tmpfs: %s", err) |
130 | 130 |
} |
131 |
- if err := os.Chown(shmPath, rootUID, rootGID); err != nil { |
|
131 |
+ if err := os.Chown(shmPath, rootIDs.UID, rootIDs.GID); err != nil { |
|
132 | 132 |
return err |
133 | 133 |
} |
134 | 134 |
} |
... | ... |
@@ -147,9 +147,9 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) { |
147 | 147 |
logrus.Debugf("secrets: setting up secret dir: %s", localMountPath) |
148 | 148 |
|
149 | 149 |
// retrieve possible remapped range start for root UID, GID |
150 |
- rootUID, rootGID := daemon.GetRemappedUIDGID() |
|
150 |
+ rootIDs, _ := daemon.idMappings.RootPair() |
|
151 | 151 |
// create tmpfs |
152 |
- if err := idtools.MkdirAllAs(localMountPath, 0700, rootUID, rootGID); err != nil { |
|
152 |
+ if err := idtools.MkdirAllAndChown(localMountPath, 0700, rootIDs); err != nil { |
|
153 | 153 |
return errors.Wrap(err, "error creating secret local mount path") |
154 | 154 |
} |
155 | 155 |
|
... | ... |
@@ -164,7 +164,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) { |
164 | 164 |
} |
165 | 165 |
}() |
166 | 166 |
|
167 |
- tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootUID, rootGID) |
|
167 |
+ tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID) |
|
168 | 168 |
if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil { |
169 | 169 |
return errors.Wrap(err, "unable to setup secret mount") |
170 | 170 |
} |
... | ... |
@@ -183,7 +183,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) { |
183 | 183 |
// secrets are created in the SecretMountPath on the host, at a |
184 | 184 |
// single level |
185 | 185 |
fPath := c.SecretFilePath(*s) |
186 |
- if err := idtools.MkdirAllAs(filepath.Dir(fPath), 0700, rootUID, rootGID); err != nil { |
|
186 |
+ if err := idtools.MkdirAllAndChown(filepath.Dir(fPath), 0700, rootIDs); err != nil { |
|
187 | 187 |
return errors.Wrap(err, "error creating secret mount path") |
188 | 188 |
} |
189 | 189 |
|
... | ... |
@@ -208,7 +208,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) { |
208 | 208 |
return err |
209 | 209 |
} |
210 | 210 |
|
211 |
- if err := os.Chown(fPath, rootUID+uid, rootGID+gid); err != nil { |
|
211 |
+ if err := os.Chown(fPath, rootIDs.UID+uid, rootIDs.GID+gid); err != nil { |
|
212 | 212 |
return errors.Wrap(err, "error setting ownership for secret") |
213 | 213 |
} |
214 | 214 |
} |
... | ... |
@@ -232,9 +232,9 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) { |
232 | 232 |
logrus.Debugf("configs: setting up config dir: %s", localPath) |
233 | 233 |
|
234 | 234 |
// retrieve possible remapped range start for root UID, GID |
235 |
- rootUID, rootGID := daemon.GetRemappedUIDGID() |
|
235 |
+ rootIDs, _ := daemon.idMappings.RootPair() |
|
236 | 236 |
// create tmpfs |
237 |
- if err := idtools.MkdirAllAs(localPath, 0700, rootUID, rootGID); err != nil { |
|
237 |
+ if err := idtools.MkdirAllAndChown(localPath, 0700, rootIDs); err != nil { |
|
238 | 238 |
return errors.Wrap(err, "error creating config dir") |
239 | 239 |
} |
240 | 240 |
|
... | ... |
@@ -261,7 +261,7 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) { |
261 | 261 |
|
262 | 262 |
log := logrus.WithFields(logrus.Fields{"name": configRef.File.Name, "path": fPath}) |
263 | 263 |
|
264 |
- if err := idtools.MkdirAllAs(filepath.Dir(fPath), 0700, rootUID, rootGID); err != nil { |
|
264 |
+ if err := idtools.MkdirAllAndChown(filepath.Dir(fPath), 0700, rootIDs); err != nil { |
|
265 | 265 |
return errors.Wrap(err, "error creating config path") |
266 | 266 |
} |
267 | 267 |
|
... | ... |
@@ -283,7 +283,7 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) { |
283 | 283 |
return err |
284 | 284 |
} |
285 | 285 |
|
286 |
- if err := os.Chown(fPath, rootUID+uid, rootGID+gid); err != nil { |
|
286 |
+ if err := os.Chown(fPath, rootIDs.UID+uid, rootIDs.GID+gid); err != nil { |
|
287 | 287 |
return errors.Wrap(err, "error setting ownership for config") |
288 | 288 |
} |
289 | 289 |
} |
... | ... |
@@ -117,14 +117,14 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) ( |
117 | 117 |
return nil, err |
118 | 118 |
} |
119 | 119 |
|
120 |
- rootUID, rootGID, err := idtools.GetRootUIDGID(daemon.uidMaps, daemon.gidMaps) |
|
120 |
+ rootIDs, err := daemon.idMappings.RootPair() |
|
121 | 121 |
if err != nil { |
122 | 122 |
return nil, err |
123 | 123 |
} |
124 |
- if err := idtools.MkdirAs(container.Root, 0700, rootUID, rootGID); err != nil { |
|
124 |
+ if err := idtools.MkdirAndChown(container.Root, 0700, rootIDs); err != nil { |
|
125 | 125 |
return nil, err |
126 | 126 |
} |
127 |
- if err := idtools.MkdirAs(container.CheckpointDir(), 0700, rootUID, rootGID); err != nil { |
|
127 |
+ if err := idtools.MkdirAndChown(container.CheckpointDir(), 0700, rootIDs); err != nil { |
|
128 | 128 |
return nil, err |
129 | 129 |
} |
130 | 130 |
|
... | ... |
@@ -22,8 +22,8 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain |
22 | 22 |
} |
23 | 23 |
defer daemon.Unmount(container) |
24 | 24 |
|
25 |
- rootUID, rootGID := daemon.GetRemappedUIDGID() |
|
26 |
- if err := container.SetupWorkingDirectory(rootUID, rootGID); err != nil { |
|
25 |
+ rootIDs, _ := daemon.idMappings.RootPair() |
|
26 |
+ if err := container.SetupWorkingDirectory(rootIDs); err != nil { |
|
27 | 27 |
return err |
28 | 28 |
} |
29 | 29 |
|
... | ... |
@@ -94,8 +94,7 @@ type Daemon struct { |
94 | 94 |
seccompEnabled bool |
95 | 95 |
apparmorEnabled bool |
96 | 96 |
shutdown bool |
97 |
- uidMaps []idtools.IDMap |
|
98 |
- gidMaps []idtools.IDMap |
|
97 |
+ idMappings *idtools.IDMappings |
|
99 | 98 |
layerStore layer.Store |
100 | 99 |
imageStore image.Store |
101 | 100 |
PluginStore *plugin.Store // todo: remove |
... | ... |
@@ -524,11 +523,11 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe |
524 | 524 |
return nil, err |
525 | 525 |
} |
526 | 526 |
|
527 |
- uidMaps, gidMaps, err := setupRemappedRoot(config) |
|
527 |
+ idMappings, err := setupRemappedRoot(config) |
|
528 | 528 |
if err != nil { |
529 | 529 |
return nil, err |
530 | 530 |
} |
531 |
- rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) |
|
531 |
+ rootIDs, err := idMappings.RootPair() |
|
532 | 532 |
if err != nil { |
533 | 533 |
return nil, err |
534 | 534 |
} |
... | ... |
@@ -538,7 +537,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe |
538 | 538 |
} |
539 | 539 |
|
540 | 540 |
// set up the tmpDir to use a canonical path |
541 |
- tmp, err := prepareTempDir(config.Root, rootUID, rootGID) |
|
541 |
+ tmp, err := prepareTempDir(config.Root, rootIDs) |
|
542 | 542 |
if err != nil { |
543 | 543 |
return nil, fmt.Errorf("Unable to get the TempDir under %s: %s", config.Root, err) |
544 | 544 |
} |
... | ... |
@@ -587,7 +586,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe |
587 | 587 |
} |
588 | 588 |
|
589 | 589 |
daemonRepo := filepath.Join(config.Root, "containers") |
590 |
- if err := idtools.MkdirAllAs(daemonRepo, 0700, rootUID, rootGID); err != nil && !os.IsExist(err) { |
|
590 |
+ if err := idtools.MkdirAllAndChown(daemonRepo, 0700, rootIDs); err != nil && !os.IsExist(err) { |
|
591 | 591 |
return nil, err |
592 | 592 |
} |
593 | 593 |
|
... | ... |
@@ -632,8 +631,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe |
632 | 632 |
MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"), |
633 | 633 |
GraphDriver: driverName, |
634 | 634 |
GraphDriverOptions: config.GraphOptions, |
635 |
- UIDMaps: uidMaps, |
|
636 |
- GIDMaps: gidMaps, |
|
635 |
+ IDMappings: idMappings, |
|
637 | 636 |
PluginGetter: d.PluginStore, |
638 | 637 |
ExperimentalEnabled: config.Experimental, |
639 | 638 |
}) |
... | ... |
@@ -665,7 +663,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe |
665 | 665 |
} |
666 | 666 |
|
667 | 667 |
// Configure the volumes driver |
668 |
- volStore, err := d.configureVolumes(rootUID, rootGID) |
|
668 |
+ volStore, err := d.configureVolumes(rootIDs) |
|
669 | 669 |
if err != nil { |
670 | 670 |
return nil, err |
671 | 671 |
} |
... | ... |
@@ -728,8 +726,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe |
728 | 728 |
d.EventsService = eventsService |
729 | 729 |
d.volumes = volStore |
730 | 730 |
d.root = config.Root |
731 |
- d.uidMaps = uidMaps |
|
732 |
- d.gidMaps = gidMaps |
|
731 |
+ d.idMappings = idMappings |
|
733 | 732 |
d.seccompEnabled = sysInfo.Seccomp |
734 | 733 |
d.apparmorEnabled = sysInfo.AppArmor |
735 | 734 |
|
... | ... |
@@ -970,25 +967,10 @@ func (daemon *Daemon) GraphDriverName() string { |
970 | 970 |
return daemon.layerStore.DriverName() |
971 | 971 |
} |
972 | 972 |
|
973 |
-// GetUIDGIDMaps returns the current daemon's user namespace settings |
|
974 |
-// for the full uid and gid maps which will be applied to containers |
|
975 |
-// started in this instance. |
|
976 |
-func (daemon *Daemon) GetUIDGIDMaps() ([]idtools.IDMap, []idtools.IDMap) { |
|
977 |
- return daemon.uidMaps, daemon.gidMaps |
|
978 |
-} |
|
979 |
- |
|
980 |
-// GetRemappedUIDGID returns the current daemon's uid and gid values |
|
981 |
-// if user namespaces are in use for this daemon instance. If not |
|
982 |
-// this function will return "real" root values of 0, 0. |
|
983 |
-func (daemon *Daemon) GetRemappedUIDGID() (int, int) { |
|
984 |
- uid, gid, _ := idtools.GetRootUIDGID(daemon.uidMaps, daemon.gidMaps) |
|
985 |
- return uid, gid |
|
986 |
-} |
|
987 |
- |
|
988 | 973 |
// prepareTempDir prepares and returns the default directory to use |
989 | 974 |
// for temporary files. |
990 | 975 |
// If it doesn't exist, it is created. If it exists, its content is removed. |
991 |
-func prepareTempDir(rootDir string, rootUID, rootGID int) (string, error) { |
|
976 |
+func prepareTempDir(rootDir string, rootIDs idtools.IDPair) (string, error) { |
|
992 | 977 |
var tmpDir string |
993 | 978 |
if tmpDir = os.Getenv("DOCKER_TMPDIR"); tmpDir == "" { |
994 | 979 |
tmpDir = filepath.Join(rootDir, "tmp") |
... | ... |
@@ -1008,12 +990,12 @@ func prepareTempDir(rootDir string, rootUID, rootGID int) (string, error) { |
1008 | 1008 |
} |
1009 | 1009 |
// We don't remove the content of tmpdir if it's not the default, |
1010 | 1010 |
// it may hold things that do not belong to us. |
1011 |
- return tmpDir, idtools.MkdirAllAs(tmpDir, 0700, rootUID, rootGID) |
|
1011 |
+ return tmpDir, idtools.MkdirAllAndChown(tmpDir, 0700, rootIDs) |
|
1012 | 1012 |
} |
1013 | 1013 |
|
1014 | 1014 |
func (daemon *Daemon) setupInitLayer(initPath string) error { |
1015 |
- rootUID, rootGID := daemon.GetRemappedUIDGID() |
|
1016 |
- return initlayer.Setup(initPath, rootUID, rootGID) |
|
1015 |
+ rootIDs, _ := daemon.idMappings.RootPair() |
|
1016 |
+ return initlayer.Setup(initPath, rootIDs) |
|
1017 | 1017 |
} |
1018 | 1018 |
|
1019 | 1019 |
func setDefaultMtu(conf *config.Config) { |
... | ... |
@@ -1024,8 +1006,8 @@ func setDefaultMtu(conf *config.Config) { |
1024 | 1024 |
conf.Mtu = config.DefaultNetworkMtu |
1025 | 1025 |
} |
1026 | 1026 |
|
1027 |
-func (daemon *Daemon) configureVolumes(rootUID, rootGID int) (*store.VolumeStore, error) { |
|
1028 |
- volumesDriver, err := local.New(daemon.configStore.Root, rootUID, rootGID) |
|
1027 |
+func (daemon *Daemon) configureVolumes(rootIDs idtools.IDPair) (*store.VolumeStore, error) { |
|
1028 |
+ volumesDriver, err := local.New(daemon.configStore.Root, rootIDs) |
|
1029 | 1029 |
if err != nil { |
1030 | 1030 |
return nil, err |
1031 | 1031 |
} |
... | ... |
@@ -1171,16 +1153,16 @@ func CreateDaemonRoot(config *config.Config) error { |
1171 | 1171 |
} |
1172 | 1172 |
} |
1173 | 1173 |
|
1174 |
- uidMaps, gidMaps, err := setupRemappedRoot(config) |
|
1174 |
+ idMappings, err := setupRemappedRoot(config) |
|
1175 | 1175 |
if err != nil { |
1176 | 1176 |
return err |
1177 | 1177 |
} |
1178 |
- rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) |
|
1178 |
+ rootIDs, err := idMappings.RootPair() |
|
1179 | 1179 |
if err != nil { |
1180 | 1180 |
return err |
1181 | 1181 |
} |
1182 | 1182 |
|
1183 |
- if err := setupDaemonRoot(config, realRoot, rootUID, rootGID); err != nil { |
|
1183 |
+ if err := setupDaemonRoot(config, realRoot, rootIDs); err != nil { |
|
1184 | 1184 |
return err |
1185 | 1185 |
} |
1186 | 1186 |
|
... | ... |
@@ -11,6 +11,7 @@ import ( |
11 | 11 |
containertypes "github.com/docker/docker/api/types/container" |
12 | 12 |
"github.com/docker/docker/container" |
13 | 13 |
_ "github.com/docker/docker/pkg/discovery/memory" |
14 |
+ "github.com/docker/docker/pkg/idtools" |
|
14 | 15 |
"github.com/docker/docker/pkg/registrar" |
15 | 16 |
"github.com/docker/docker/pkg/truncindex" |
16 | 17 |
"github.com/docker/docker/volume" |
... | ... |
@@ -127,7 +128,7 @@ func initDaemonWithVolumeStore(tmp string) (*Daemon, error) { |
127 | 127 |
return nil, err |
128 | 128 |
} |
129 | 129 |
|
130 |
- volumesDriver, err := local.New(tmp, 0, 0) |
|
130 |
+ volumesDriver, err := local.New(tmp, idtools.IDPair{UID: 0, GID: 0}) |
|
131 | 131 |
if err != nil { |
132 | 132 |
return nil, err |
133 | 133 |
} |
... | ... |
@@ -1026,40 +1026,38 @@ func parseRemappedRoot(usergrp string) (string, string, error) { |
1026 | 1026 |
return username, groupname, nil |
1027 | 1027 |
} |
1028 | 1028 |
|
1029 |
-func setupRemappedRoot(config *config.Config) ([]idtools.IDMap, []idtools.IDMap, error) { |
|
1029 |
+func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) { |
|
1030 | 1030 |
if runtime.GOOS != "linux" && config.RemappedRoot != "" { |
1031 |
- return nil, nil, fmt.Errorf("User namespaces are only supported on Linux") |
|
1031 |
+ return nil, fmt.Errorf("User namespaces are only supported on Linux") |
|
1032 | 1032 |
} |
1033 | 1033 |
|
1034 | 1034 |
// if the daemon was started with remapped root option, parse |
1035 | 1035 |
// the config option to the int uid,gid values |
1036 |
- var ( |
|
1037 |
- uidMaps, gidMaps []idtools.IDMap |
|
1038 |
- ) |
|
1039 | 1036 |
if config.RemappedRoot != "" { |
1040 | 1037 |
username, groupname, err := parseRemappedRoot(config.RemappedRoot) |
1041 | 1038 |
if err != nil { |
1042 |
- return nil, nil, err |
|
1039 |
+ return nil, err |
|
1043 | 1040 |
} |
1044 | 1041 |
if username == "root" { |
1045 | 1042 |
// Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op |
1046 | 1043 |
// effectively |
1047 | 1044 |
logrus.Warn("User namespaces: root cannot be remapped with itself; user namespaces are OFF") |
1048 |
- return uidMaps, gidMaps, nil |
|
1045 |
+ return &idtools.IDMappings{}, nil |
|
1049 | 1046 |
} |
1050 | 1047 |
logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname) |
1051 | 1048 |
// update remapped root setting now that we have resolved them to actual names |
1052 | 1049 |
config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname) |
1053 | 1050 |
|
1054 |
- uidMaps, gidMaps, err = idtools.CreateIDMappings(username, groupname) |
|
1051 |
+ mappings, err := idtools.NewIDMappings(username, groupname) |
|
1055 | 1052 |
if err != nil { |
1056 |
- return nil, nil, fmt.Errorf("Can't create ID mappings: %v", err) |
|
1053 |
+ return nil, errors.Wrapf(err, "Can't create ID mappings: %v") |
|
1057 | 1054 |
} |
1055 |
+ return mappings, nil |
|
1058 | 1056 |
} |
1059 |
- return uidMaps, gidMaps, nil |
|
1057 |
+ return &idtools.IDMappings{}, nil |
|
1060 | 1058 |
} |
1061 | 1059 |
|
1062 |
-func setupDaemonRoot(config *config.Config, rootDir string, rootUID, rootGID int) error { |
|
1060 |
+func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error { |
|
1063 | 1061 |
config.Root = rootDir |
1064 | 1062 |
// the docker root metadata directory needs to have execute permissions for all users (g+x,o+x) |
1065 | 1063 |
// so that syscalls executing as non-root, operating on subdirectories of the graph root |
... | ... |
@@ -1084,10 +1082,10 @@ func setupDaemonRoot(config *config.Config, rootDir string, rootUID, rootGID int |
1084 | 1084 |
// a new subdirectory with ownership set to the remapped uid/gid (so as to allow |
1085 | 1085 |
// `chdir()` to work for containers namespaced to that uid/gid) |
1086 | 1086 |
if config.RemappedRoot != "" { |
1087 |
- config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootUID, rootGID)) |
|
1087 |
+ config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootIDs.UID, rootIDs.GID)) |
|
1088 | 1088 |
logrus.Debugf("Creating user namespaced daemon root: %s", config.Root) |
1089 | 1089 |
// Create the root directory if it doesn't exist |
1090 |
- if err := idtools.MkdirAllAs(config.Root, 0700, rootUID, rootGID); err != nil { |
|
1090 |
+ if err := idtools.MkdirAllAndChown(config.Root, 0700, rootIDs); err != nil { |
|
1091 | 1091 |
return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err) |
1092 | 1092 |
} |
1093 | 1093 |
// we also need to verify that any pre-existing directories in the path to |
... | ... |
@@ -1100,7 +1098,7 @@ func setupDaemonRoot(config *config.Config, rootDir string, rootUID, rootGID int |
1100 | 1100 |
if dirPath == "/" { |
1101 | 1101 |
break |
1102 | 1102 |
} |
1103 |
- if !idtools.CanAccess(dirPath, rootUID, rootGID) { |
|
1103 |
+ if !idtools.CanAccess(dirPath, rootIDs) { |
|
1104 | 1104 |
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) |
1105 | 1105 |
} |
1106 | 1106 |
} |
... | ... |
@@ -11,6 +11,7 @@ import ( |
11 | 11 |
containertypes "github.com/docker/docker/api/types/container" |
12 | 12 |
"github.com/docker/docker/container" |
13 | 13 |
"github.com/docker/docker/daemon/config" |
14 |
+ "github.com/docker/docker/pkg/idtools" |
|
14 | 15 |
"github.com/docker/docker/volume" |
15 | 16 |
"github.com/docker/docker/volume/drivers" |
16 | 17 |
"github.com/docker/docker/volume/local" |
... | ... |
@@ -277,7 +278,7 @@ func TestMigratePre17Volumes(t *testing.T) { |
277 | 277 |
if err != nil { |
278 | 278 |
t.Fatal(err) |
279 | 279 |
} |
280 |
- drv, err := local.New(volumeRoot, 0, 0) |
|
280 |
+ drv, err := local.New(volumeRoot, idtools.IDPair{UID: 0, GID: 0}) |
|
281 | 281 |
if err != nil { |
282 | 282 |
t.Fatal(err) |
283 | 283 |
} |
... | ... |
@@ -454,11 +454,11 @@ func (daemon *Daemon) cleanupMounts() error { |
454 | 454 |
return nil |
455 | 455 |
} |
456 | 456 |
|
457 |
-func setupRemappedRoot(config *config.Config) ([]idtools.IDMap, []idtools.IDMap, error) { |
|
458 |
- return nil, nil, nil |
|
457 |
+func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) { |
|
458 |
+ return &idtools.IDMappings{}, nil |
|
459 | 459 |
} |
460 | 460 |
|
461 |
-func setupDaemonRoot(config *config.Config, rootDir string, rootUID, rootGID int) error { |
|
461 |
+func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error { |
|
462 | 462 |
config.Root = rootDir |
463 | 463 |
// Create the root directory if it doesn't exists |
464 | 464 |
if err := system.MkdirAllWithACL(config.Root, 0); err != nil && !os.IsExist(err) { |
... | ... |
@@ -40,11 +40,10 @@ func (daemon *Daemon) containerExport(container *container.Container) (io.ReadCl |
40 | 40 |
return nil, err |
41 | 41 |
} |
42 | 42 |
|
43 |
- uidMaps, gidMaps := daemon.GetUIDGIDMaps() |
|
44 | 43 |
archive, err := archive.TarWithOptions(container.BaseFS, &archive.TarOptions{ |
45 | 44 |
Compression: archive.Uncompressed, |
46 |
- UIDMaps: uidMaps, |
|
47 |
- GIDMaps: gidMaps, |
|
45 |
+ UIDMaps: daemon.idMappings.UIDs(), |
|
46 |
+ GIDMaps: daemon.idMappings.GIDs(), |
|
48 | 47 |
}) |
49 | 48 |
if err != nil { |
50 | 49 |
daemon.Unmount(container) |
... | ... |
@@ -72,8 +72,8 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) { |
72 | 72 |
if selinuxEnabled() { |
73 | 73 |
securityOptions = append(securityOptions, "name=selinux") |
74 | 74 |
} |
75 |
- uid, gid := daemon.GetRemappedUIDGID() |
|
76 |
- if uid != 0 || gid != 0 { |
|
75 |
+ rootIDs, _ := daemon.idMappings.RootPair() |
|
76 |
+ if rootIDs.UID != 0 || rootIDs.GID != 0 { |
|
77 | 77 |
securityOptions = append(securityOptions, "name=userns") |
78 | 78 |
} |
79 | 79 |
|
... | ... |
@@ -16,7 +16,7 @@ import ( |
16 | 16 |
// |
17 | 17 |
// This extra layer is used by all containers as the top-most ro layer. It protects |
18 | 18 |
// the container from unwanted side-effects on the rw layer. |
19 |
-func Setup(initLayer string, rootUID, rootGID int) error { |
|
19 |
+func Setup(initLayer string, rootIDs idtools.IDPair) error { |
|
20 | 20 |
for pth, typ := range map[string]string{ |
21 | 21 |
"/dev/pts": "dir", |
22 | 22 |
"/dev/shm": "dir", |
... | ... |
@@ -38,12 +38,12 @@ func Setup(initLayer string, rootUID, rootGID int) error { |
38 | 38 |
|
39 | 39 |
if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil { |
40 | 40 |
if os.IsNotExist(err) { |
41 |
- if err := idtools.MkdirAllNewAs(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootUID, rootGID); err != nil { |
|
41 |
+ if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootIDs); err != nil { |
|
42 | 42 |
return err |
43 | 43 |
} |
44 | 44 |
switch typ { |
45 | 45 |
case "dir": |
46 |
- if err := idtools.MkdirAllNewAs(filepath.Join(initLayer, pth), 0755, rootUID, rootGID); err != nil { |
|
46 |
+ if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, pth), 0755, rootIDs); err != nil { |
|
47 | 47 |
return err |
48 | 48 |
} |
49 | 49 |
case "file": |
... | ... |
@@ -51,7 +51,7 @@ func Setup(initLayer string, rootUID, rootGID int) error { |
51 | 51 |
if err != nil { |
52 | 52 |
return err |
53 | 53 |
} |
54 |
- f.Chown(rootUID, rootGID) |
|
54 |
+ f.Chown(rootIDs.UID, rootIDs.GID) |
|
55 | 55 |
f.Close() |
56 | 56 |
default: |
57 | 57 |
if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil { |
... | ... |
@@ -2,12 +2,16 @@ |
2 | 2 |
|
3 | 3 |
package initlayer |
4 | 4 |
|
5 |
+import ( |
|
6 |
+ "github.com/docker/docker/pkg/idtools" |
|
7 |
+) |
|
8 |
+ |
|
5 | 9 |
// Setup populates a directory with mountpoints suitable |
6 | 10 |
// for bind-mounting dockerinit into the container. The mountpoint is simply an |
7 | 11 |
// empty file at /.dockerinit |
8 | 12 |
// |
9 | 13 |
// This extra layer is used by all containers as the top-most ro layer. It protects |
10 | 14 |
// the container from unwanted side-effects on the rw layer. |
11 |
-func Setup(initLayer string, rootUID, rootGID int) error { |
|
15 |
+func Setup(initLayer string, rootIDs idtools.IDPair) error { |
|
12 | 16 |
return nil |
13 | 17 |
} |
... | ... |
@@ -271,13 +271,13 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error |
271 | 271 |
userNS := false |
272 | 272 |
// user |
273 | 273 |
if c.HostConfig.UsernsMode.IsPrivate() { |
274 |
- uidMap, gidMap := daemon.GetUIDGIDMaps() |
|
274 |
+ uidMap := daemon.idMappings.UIDs() |
|
275 | 275 |
if uidMap != nil { |
276 | 276 |
userNS = true |
277 | 277 |
ns := specs.LinuxNamespace{Type: "user"} |
278 | 278 |
setNamespace(s, ns) |
279 | 279 |
s.Linux.UIDMappings = specMapping(uidMap) |
280 |
- s.Linux.GIDMappings = specMapping(gidMap) |
|
280 |
+ s.Linux.GIDMappings = specMapping(daemon.idMappings.GIDs()) |
|
281 | 281 |
} |
282 | 282 |
} |
283 | 283 |
// network |
... | ... |
@@ -591,7 +591,7 @@ func setMounts(daemon *Daemon, s *specs.Spec, c *container.Container, mounts []c |
591 | 591 |
|
592 | 592 |
// TODO: until a kernel/mount solution exists for handling remount in a user namespace, |
593 | 593 |
// we must clear the readonly flag for the cgroups mount (@mrunalp concurs) |
594 |
- if uidMap, _ := daemon.GetUIDGIDMaps(); uidMap != nil || c.HostConfig.Privileged { |
|
594 |
+ if uidMap := daemon.idMappings.UIDs(); uidMap != nil || c.HostConfig.Privileged { |
|
595 | 595 |
for i, m := range s.Mounts { |
596 | 596 |
if m.Type == "cgroup" { |
597 | 597 |
clearReadOnly(&s.Mounts[i]) |
... | ... |
@@ -611,8 +611,8 @@ func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container) |
611 | 611 |
Path: c.BaseFS, |
612 | 612 |
Readonly: c.HostConfig.ReadonlyRootfs, |
613 | 613 |
} |
614 |
- rootUID, rootGID := daemon.GetRemappedUIDGID() |
|
615 |
- if err := c.SetupWorkingDirectory(rootUID, rootGID); err != nil { |
|
614 |
+ rootIDs, _ := daemon.idMappings.RootPair() |
|
615 |
+ if err := c.SetupWorkingDirectory(rootIDs); err != nil { |
|
616 | 616 |
return err |
617 | 617 |
} |
618 | 618 |
cwd := c.Config.WorkingDir |
... | ... |
@@ -130,8 +130,8 @@ func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container) |
130 | 130 |
Path: filepath.Dir(c.BaseFS), |
131 | 131 |
Readonly: c.HostConfig.ReadonlyRootfs, |
132 | 132 |
} |
133 |
- rootUID, rootGID := daemon.GetRemappedUIDGID() |
|
134 |
- if err := c.SetupWorkingDirectory(rootUID, rootGID); err != nil { |
|
133 |
+ rootIDs, _ := daemon.idMappings.RootPair() |
|
134 |
+ if err := c.SetupWorkingDirectory(rootIDs); err != nil { |
|
135 | 135 |
return err |
136 | 136 |
} |
137 | 137 |
cwd := c.Config.WorkingDir |
... | ... |
@@ -54,8 +54,8 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er |
54 | 54 |
return nil |
55 | 55 |
} |
56 | 56 |
|
57 |
- rootUID, rootGID := daemon.GetRemappedUIDGID() |
|
58 |
- path, err := m.Setup(c.MountLabel, rootUID, rootGID, checkfunc) |
|
57 |
+ rootIDs, _ := daemon.idMappings.RootPair() |
|
58 |
+ path, err := m.Setup(c.MountLabel, rootIDs, checkfunc) |
|
59 | 59 |
if err != nil { |
60 | 60 |
return nil, err |
61 | 61 |
} |
... | ... |
@@ -85,9 +85,9 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er |
85 | 85 |
// if we are going to mount any of the network files from container |
86 | 86 |
// metadata, the ownership must be set properly for potential container |
87 | 87 |
// remapped root (user namespaces) |
88 |
- rootUID, rootGID := daemon.GetRemappedUIDGID() |
|
88 |
+ rootIDs, _ := daemon.idMappings.RootPair() |
|
89 | 89 |
for _, mount := range netMounts { |
90 |
- if err := os.Chown(mount.Source, rootUID, rootGID); err != nil { |
|
90 |
+ if err := os.Chown(mount.Source, rootIDs.UID, rootIDs.GID); err != nil { |
|
91 | 91 |
return nil, err |
92 | 92 |
} |
93 | 93 |
} |
... | ... |
@@ -6,6 +6,7 @@ import ( |
6 | 6 |
"sort" |
7 | 7 |
|
8 | 8 |
"github.com/docker/docker/container" |
9 |
+ "github.com/docker/docker/pkg/idtools" |
|
9 | 10 |
"github.com/docker/docker/volume" |
10 | 11 |
) |
11 | 12 |
|
... | ... |
@@ -24,7 +25,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er |
24 | 24 |
if err := daemon.lazyInitializeVolume(c.ID, mount); err != nil { |
25 | 25 |
return nil, err |
26 | 26 |
} |
27 |
- s, err := mount.Setup(c.MountLabel, 0, 0, nil) |
|
27 |
+ s, err := mount.Setup(c.MountLabel, idtools.IDPair{0, 0}, nil) |
|
28 | 28 |
if err != nil { |
29 | 29 |
return nil, err |
30 | 30 |
} |
... | ... |
@@ -16,6 +16,6 @@ func (daemon *Daemon) ContainerCreateWorkdir(cID string) error { |
16 | 16 |
return err |
17 | 17 |
} |
18 | 18 |
defer daemon.Unmount(container) |
19 |
- rootUID, rootGID := daemon.GetRemappedUIDGID() |
|
20 |
- return container.SetupWorkingDirectory(rootUID, rootGID) |
|
19 |
+ rootIDs, _ := daemon.idMappings.RootPair() |
|
20 |
+ return container.SetupWorkingDirectory(rootIDs) |
|
21 | 21 |
} |
... | ... |
@@ -44,8 +44,7 @@ type StoreOptions struct { |
44 | 44 |
MetadataStorePathTemplate string |
45 | 45 |
GraphDriver string |
46 | 46 |
GraphDriverOptions []string |
47 |
- UIDMaps []idtools.IDMap |
|
48 |
- GIDMaps []idtools.IDMap |
|
47 |
+ IDMappings *idtools.IDMappings |
|
49 | 48 |
PluginGetter plugingetter.PluginGetter |
50 | 49 |
ExperimentalEnabled bool |
51 | 50 |
} |
... | ... |
@@ -55,8 +54,8 @@ func NewStoreFromOptions(options StoreOptions) (Store, error) { |
55 | 55 |
driver, err := graphdriver.New(options.GraphDriver, options.PluginGetter, graphdriver.Options{ |
56 | 56 |
Root: options.StorePath, |
57 | 57 |
DriverOptions: options.GraphDriverOptions, |
58 |
- UIDMaps: options.UIDMaps, |
|
59 |
- GIDMaps: options.GIDMaps, |
|
58 |
+ UIDMaps: options.IDMappings.UIDs(), |
|
59 |
+ GIDMaps: options.IDMappings.GIDs(), |
|
60 | 60 |
ExperimentalEnabled: options.ExperimentalEnabled, |
61 | 61 |
}) |
62 | 62 |
if err != nil { |
... | ... |
@@ -37,6 +37,7 @@ const ( |
37 | 37 |
// MkdirAllAs creates a directory (include any along the path) and then modifies |
38 | 38 |
// ownership to the requested uid/gid. If the directory already exists, this |
39 | 39 |
// function will still change ownership to the requested uid/gid pair. |
40 |
+// Deprecated: Use MkdirAllAndChown |
|
40 | 41 |
func MkdirAllAs(path string, mode os.FileMode, ownerUID, ownerGID int) error { |
41 | 42 |
return mkdirAs(path, mode, ownerUID, ownerGID, true, true) |
42 | 43 |
} |
... | ... |
@@ -44,16 +45,38 @@ func MkdirAllAs(path string, mode os.FileMode, ownerUID, ownerGID int) error { |
44 | 44 |
// MkdirAllNewAs creates a directory (include any along the path) and then modifies |
45 | 45 |
// ownership ONLY of newly created directories to the requested uid/gid. If the |
46 | 46 |
// directories along the path exist, no change of ownership will be performed |
47 |
+// Deprecated: Use MkdirAllAndChownNew |
|
47 | 48 |
func MkdirAllNewAs(path string, mode os.FileMode, ownerUID, ownerGID int) error { |
48 | 49 |
return mkdirAs(path, mode, ownerUID, ownerGID, true, false) |
49 | 50 |
} |
50 | 51 |
|
51 | 52 |
// MkdirAs creates a directory and then modifies ownership to the requested uid/gid. |
52 | 53 |
// If the directory already exists, this function still changes ownership |
54 |
+// Deprecated: Use MkdirAndChown with a IDPair |
|
53 | 55 |
func MkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int) error { |
54 | 56 |
return mkdirAs(path, mode, ownerUID, ownerGID, false, true) |
55 | 57 |
} |
56 | 58 |
|
59 |
+// MkdirAllAndChown creates a directory (include any along the path) and then modifies |
|
60 |
+// ownership to the requested uid/gid. If the directory already exists, this |
|
61 |
+// function will still change ownership to the requested uid/gid pair. |
|
62 |
+func MkdirAllAndChown(path string, mode os.FileMode, ids IDPair) error { |
|
63 |
+ return mkdirAs(path, mode, ids.UID, ids.GID, true, true) |
|
64 |
+} |
|
65 |
+ |
|
66 |
+// MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid. |
|
67 |
+// If the directory already exists, this function still changes ownership |
|
68 |
+func MkdirAndChown(path string, mode os.FileMode, ids IDPair) error { |
|
69 |
+ return mkdirAs(path, mode, ids.UID, ids.GID, false, true) |
|
70 |
+} |
|
71 |
+ |
|
72 |
+// MkdirAllAndChownNew creates a directory (include any along the path) and then modifies |
|
73 |
+// ownership ONLY of newly created directories to the requested uid/gid. If the |
|
74 |
+// directories along the path exist, no change of ownership will be performed |
|
75 |
+func MkdirAllAndChownNew(path string, mode os.FileMode, ids IDPair) error { |
|
76 |
+ return mkdirAs(path, mode, ids.UID, ids.GID, true, false) |
|
77 |
+} |
|
78 |
+ |
|
57 | 79 |
// GetRootUIDGID retrieves the remapped root uid/gid pair from the set of maps. |
58 | 80 |
// If the maps are empty, then the root uid/gid will default to "real" 0/0 |
59 | 81 |
func GetRootUIDGID(uidMap, gidMap []IDMap) (int, int, error) { |
... | ... |
@@ -108,26 +131,59 @@ func ToHost(contID int, idMap []IDMap) (int, error) { |
108 | 108 |
return -1, fmt.Errorf("Container ID %d cannot be mapped to a host ID", contID) |
109 | 109 |
} |
110 | 110 |
|
111 |
-// CreateIDMappings takes a requested user and group name and |
|
111 |
+// IDPair is a UID and GID pair |
|
112 |
+type IDPair struct { |
|
113 |
+ UID int |
|
114 |
+ GID int |
|
115 |
+} |
|
116 |
+ |
|
117 |
+// IDMappings contains a mappings of UIDs and GIDs |
|
118 |
+type IDMappings struct { |
|
119 |
+ uids []IDMap |
|
120 |
+ gids []IDMap |
|
121 |
+} |
|
122 |
+ |
|
123 |
+// NewIDMappings takes a requested user and group name and |
|
112 | 124 |
// using the data from /etc/sub{uid,gid} ranges, creates the |
113 | 125 |
// proper uid and gid remapping ranges for that user/group pair |
114 |
-func CreateIDMappings(username, groupname string) ([]IDMap, []IDMap, error) { |
|
126 |
+func NewIDMappings(username, groupname string) (*IDMappings, error) { |
|
115 | 127 |
subuidRanges, err := parseSubuid(username) |
116 | 128 |
if err != nil { |
117 |
- return nil, nil, err |
|
129 |
+ return nil, err |
|
118 | 130 |
} |
119 | 131 |
subgidRanges, err := parseSubgid(groupname) |
120 | 132 |
if err != nil { |
121 |
- return nil, nil, err |
|
133 |
+ return nil, err |
|
122 | 134 |
} |
123 | 135 |
if len(subuidRanges) == 0 { |
124 |
- return nil, nil, fmt.Errorf("No subuid ranges found for user %q", username) |
|
136 |
+ return nil, fmt.Errorf("No subuid ranges found for user %q", username) |
|
125 | 137 |
} |
126 | 138 |
if len(subgidRanges) == 0 { |
127 |
- return nil, nil, fmt.Errorf("No subgid ranges found for group %q", groupname) |
|
139 |
+ return nil, fmt.Errorf("No subgid ranges found for group %q", groupname) |
|
128 | 140 |
} |
129 | 141 |
|
130 |
- return createIDMap(subuidRanges), createIDMap(subgidRanges), nil |
|
142 |
+ return &IDMappings{ |
|
143 |
+ uids: createIDMap(subuidRanges), |
|
144 |
+ gids: createIDMap(subgidRanges), |
|
145 |
+ }, nil |
|
146 |
+} |
|
147 |
+ |
|
148 |
+// RootPair returns a uid and gid pair for the root user |
|
149 |
+func (i *IDMappings) RootPair() (IDPair, error) { |
|
150 |
+ uid, gid, err := GetRootUIDGID(i.uids, i.gids) |
|
151 |
+ return IDPair{UID: uid, GID: gid}, err |
|
152 |
+} |
|
153 |
+ |
|
154 |
+// UIDs return the UID mapping |
|
155 |
+// TODO: remove this once everything has been refactored to use pairs |
|
156 |
+func (i *IDMappings) UIDs() []IDMap { |
|
157 |
+ return i.uids |
|
158 |
+} |
|
159 |
+ |
|
160 |
+// GIDs return the UID mapping |
|
161 |
+// TODO: remove this once everything has been refactored to use pairs |
|
162 |
+func (i *IDMappings) GIDs() []IDMap { |
|
163 |
+ return i.gids |
|
131 | 164 |
} |
132 | 165 |
|
133 | 166 |
func createIDMap(subidRanges ranges) []IDMap { |
... | ... |
@@ -69,15 +69,15 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown |
69 | 69 |
|
70 | 70 |
// CanAccess takes a valid (existing) directory and a uid, gid pair and determines |
71 | 71 |
// if that uid, gid pair has access (execute bit) to the directory |
72 |
-func CanAccess(path string, uid, gid int) bool { |
|
72 |
+func CanAccess(path string, pair IDPair) bool { |
|
73 | 73 |
statInfo, err := system.Stat(path) |
74 | 74 |
if err != nil { |
75 | 75 |
return false |
76 | 76 |
} |
77 | 77 |
fileMode := os.FileMode(statInfo.Mode()) |
78 | 78 |
permBits := fileMode.Perm() |
79 |
- return accessible(statInfo.UID() == uint32(uid), |
|
80 |
- statInfo.GID() == uint32(gid), permBits) |
|
79 |
+ return accessible(statInfo.UID() == uint32(pair.UID), |
|
80 |
+ statInfo.GID() == uint32(pair.GID), permBits) |
|
81 | 81 |
} |
82 | 82 |
|
83 | 83 |
func accessible(isOwner, isGroup bool, perms os.FileMode) bool { |
... | ... |
@@ -20,6 +20,6 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown |
20 | 20 |
// CanAccess takes a valid (existing) directory and a uid, gid pair and determines |
21 | 21 |
// if that uid, gid pair has access (execute bit) to the directory |
22 | 22 |
// Windows does not require/support this function, so always return true |
23 |
-func CanAccess(path string, uid, gid int) bool { |
|
23 |
+func CanAccess(path string, pair IDPair) bool { |
|
24 | 24 |
return true |
25 | 25 |
} |
... | ... |
@@ -15,6 +15,7 @@ import ( |
15 | 15 |
"github.com/docker/docker/api/types" |
16 | 16 |
"github.com/docker/docker/daemon/initlayer" |
17 | 17 |
"github.com/docker/docker/libcontainerd" |
18 |
+ "github.com/docker/docker/pkg/idtools" |
|
18 | 19 |
"github.com/docker/docker/pkg/mount" |
19 | 20 |
"github.com/docker/docker/pkg/plugins" |
20 | 21 |
"github.com/docker/docker/pkg/stringid" |
... | ... |
@@ -58,7 +59,7 @@ func (pm *Manager) enable(p *v2.Plugin, c *controller, force bool) error { |
58 | 58 |
} |
59 | 59 |
} |
60 | 60 |
|
61 |
- if err := initlayer.Setup(filepath.Join(pm.config.Root, p.PluginObj.ID, rootFSFileName), 0, 0); err != nil { |
|
61 |
+ if err := initlayer.Setup(filepath.Join(pm.config.Root, p.PluginObj.ID, rootFSFileName), idtools.IDPair{0, 0}); err != nil { |
|
62 | 62 |
return errors.WithStack(err) |
63 | 63 |
} |
64 | 64 |
|
... | ... |
@@ -55,10 +55,10 @@ type activeMount struct { |
55 | 55 |
// New instantiates a new Root instance with the provided scope. Scope |
56 | 56 |
// is the base path that the Root instance uses to store its |
57 | 57 |
// volumes. The base path is created here if it does not exist. |
58 |
-func New(scope string, rootUID, rootGID int) (*Root, error) { |
|
58 |
+func New(scope string, rootIDs idtools.IDPair) (*Root, error) { |
|
59 | 59 |
rootDirectory := filepath.Join(scope, volumesPathName) |
60 | 60 |
|
61 |
- if err := idtools.MkdirAllAs(rootDirectory, 0700, rootUID, rootGID); err != nil { |
|
61 |
+ if err := idtools.MkdirAllAndChown(rootDirectory, 0700, rootIDs); err != nil { |
|
62 | 62 |
return nil, err |
63 | 63 |
} |
64 | 64 |
|
... | ... |
@@ -66,8 +66,7 @@ func New(scope string, rootUID, rootGID int) (*Root, error) { |
66 | 66 |
scope: scope, |
67 | 67 |
path: rootDirectory, |
68 | 68 |
volumes: make(map[string]*localVolume), |
69 |
- rootUID: rootUID, |
|
70 |
- rootGID: rootGID, |
|
69 |
+ rootIDs: rootIDs, |
|
71 | 70 |
} |
72 | 71 |
|
73 | 72 |
dirs, err := ioutil.ReadDir(rootDirectory) |
... | ... |
@@ -125,8 +124,7 @@ type Root struct { |
125 | 125 |
scope string |
126 | 126 |
path string |
127 | 127 |
volumes map[string]*localVolume |
128 |
- rootUID int |
|
129 |
- rootGID int |
|
128 |
+ rootIDs idtools.IDPair |
|
130 | 129 |
} |
131 | 130 |
|
132 | 131 |
// List lists all the volumes |
... | ... |
@@ -167,7 +165,7 @@ func (r *Root) Create(name string, opts map[string]string) (volume.Volume, error |
167 | 167 |
} |
168 | 168 |
|
169 | 169 |
path := r.DataPath(name) |
170 |
- if err := idtools.MkdirAllAs(path, 0755, r.rootUID, r.rootGID); err != nil { |
|
170 |
+ if err := idtools.MkdirAllAndChown(path, 0755, r.rootIDs); err != nil { |
|
171 | 171 |
if os.IsExist(err) { |
172 | 172 |
return nil, fmt.Errorf("volume already exists under %s", filepath.Dir(path)) |
173 | 173 |
} |
... | ... |
@@ -9,6 +9,7 @@ import ( |
9 | 9 |
"strings" |
10 | 10 |
"testing" |
11 | 11 |
|
12 |
+ "github.com/docker/docker/pkg/idtools" |
|
12 | 13 |
"github.com/docker/docker/pkg/mount" |
13 | 14 |
) |
14 | 15 |
|
... | ... |
@@ -40,7 +41,7 @@ func TestRemove(t *testing.T) { |
40 | 40 |
} |
41 | 41 |
defer os.RemoveAll(rootDir) |
42 | 42 |
|
43 |
- r, err := New(rootDir, 0, 0) |
|
43 |
+ r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0}) |
|
44 | 44 |
if err != nil { |
45 | 45 |
t.Fatal(err) |
46 | 46 |
} |
... | ... |
@@ -82,7 +83,7 @@ func TestInitializeWithVolumes(t *testing.T) { |
82 | 82 |
} |
83 | 83 |
defer os.RemoveAll(rootDir) |
84 | 84 |
|
85 |
- r, err := New(rootDir, 0, 0) |
|
85 |
+ r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0}) |
|
86 | 86 |
if err != nil { |
87 | 87 |
t.Fatal(err) |
88 | 88 |
} |
... | ... |
@@ -92,7 +93,7 @@ func TestInitializeWithVolumes(t *testing.T) { |
92 | 92 |
t.Fatal(err) |
93 | 93 |
} |
94 | 94 |
|
95 |
- r, err = New(rootDir, 0, 0) |
|
95 |
+ r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0}) |
|
96 | 96 |
if err != nil { |
97 | 97 |
t.Fatal(err) |
98 | 98 |
} |
... | ... |
@@ -114,7 +115,7 @@ func TestCreate(t *testing.T) { |
114 | 114 |
} |
115 | 115 |
defer os.RemoveAll(rootDir) |
116 | 116 |
|
117 |
- r, err := New(rootDir, 0, 0) |
|
117 |
+ r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0}) |
|
118 | 118 |
if err != nil { |
119 | 119 |
t.Fatal(err) |
120 | 120 |
} |
... | ... |
@@ -151,7 +152,7 @@ func TestCreate(t *testing.T) { |
151 | 151 |
} |
152 | 152 |
} |
153 | 153 |
|
154 |
- r, err = New(rootDir, 0, 0) |
|
154 |
+ r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0}) |
|
155 | 155 |
if err != nil { |
156 | 156 |
t.Fatal(err) |
157 | 157 |
} |
... | ... |
@@ -189,7 +190,7 @@ func TestCreateWithOpts(t *testing.T) { |
189 | 189 |
} |
190 | 190 |
defer os.RemoveAll(rootDir) |
191 | 191 |
|
192 |
- r, err := New(rootDir, 0, 0) |
|
192 |
+ r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0}) |
|
193 | 193 |
if err != nil { |
194 | 194 |
t.Fatal(err) |
195 | 195 |
} |
... | ... |
@@ -270,7 +271,7 @@ func TestCreateWithOpts(t *testing.T) { |
270 | 270 |
t.Fatal("expected mount to still be active") |
271 | 271 |
} |
272 | 272 |
|
273 |
- r, err = New(rootDir, 0, 0) |
|
273 |
+ r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0}) |
|
274 | 274 |
if err != nil { |
275 | 275 |
t.Fatal(err) |
276 | 276 |
} |
... | ... |
@@ -292,7 +293,7 @@ func TestRealodNoOpts(t *testing.T) { |
292 | 292 |
} |
293 | 293 |
defer os.RemoveAll(rootDir) |
294 | 294 |
|
295 |
- r, err := New(rootDir, 0, 0) |
|
295 |
+ r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0}) |
|
296 | 296 |
if err != nil { |
297 | 297 |
t.Fatal(err) |
298 | 298 |
} |
... | ... |
@@ -320,7 +321,7 @@ func TestRealodNoOpts(t *testing.T) { |
320 | 320 |
t.Fatal(err) |
321 | 321 |
} |
322 | 322 |
|
323 |
- r, err = New(rootDir, 0, 0) |
|
323 |
+ r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0}) |
|
324 | 324 |
if err != nil { |
325 | 325 |
t.Fatal(err) |
326 | 326 |
} |
... | ... |
@@ -151,7 +151,7 @@ func (m *MountPoint) Cleanup() error { |
151 | 151 |
// configured, or creating the source directory if supplied. |
152 | 152 |
// The, optional, checkFun parameter allows doing additional checking |
153 | 153 |
// before creating the source directory on the host. |
154 |
-func (m *MountPoint) Setup(mountLabel string, rootUID, rootGID int, checkFun func(m *MountPoint) error) (path string, err error) { |
|
154 |
+func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.IDPair, checkFun func(m *MountPoint) error) (path string, err error) { |
|
155 | 155 |
defer func() { |
156 | 156 |
if err == nil { |
157 | 157 |
if label.RelabelNeeded(m.Mode) { |
... | ... |
@@ -196,7 +196,7 @@ func (m *MountPoint) Setup(mountLabel string, rootUID, rootGID int, checkFun fun |
196 | 196 |
} |
197 | 197 |
// idtools.MkdirAllNewAs() produces an error if m.Source exists and is a file (not a directory) |
198 | 198 |
// also, makes sure that if the directory is created, the correct remapped rootUID/rootGID will own it |
199 |
- if err := idtools.MkdirAllNewAs(m.Source, 0755, rootUID, rootGID); err != nil { |
|
199 |
+ if err := idtools.MkdirAllAndChownNew(m.Source, 0755, rootIDs); err != nil { |
|
200 | 200 |
if perr, ok := err.(*os.PathError); ok { |
201 | 201 |
if perr.Err != syscall.ENOTDIR { |
202 | 202 |
return "", errors.Wrapf(err, "error while creating mount source path '%s'", m.Source) |