Signed-off-by: Daniel Nephin <dnephin@docker.com>
| ... | ... |
@@ -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) |