// Init returns a new AUFS driver. // An error is returned if AUFS is not supported. func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { // Try to load the aufs kernel module if err := supportsAufs(); err != nil { return nil, graphdriver.ErrNotSupported } fsMagic, err := graphdriver.GetFSMagic(root) if err != nil { return nil, err } if fsName, ok := graphdriver.FsNames[fsMagic]; ok { backingFs = fsName } for _, magic := range incompatibleFsMagic { if fsMagic == magic { return nil, graphdriver.ErrIncompatibleFS } } paths := []string{ "mnt", "diff", "layers", } a := &Driver{ root: root, uidMaps: uidMaps, gidMaps: gidMaps, pathCache: make(map[string]string), } rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) if err != nil { return nil, err } // Create the root aufs driver dir and return // if it already exists // If not populate the dir structure if err := idtools.MkdirAllAs(root, 0700, rootUID, rootGID); err != nil { if os.IsExist(err) { return a, nil } return nil, err } if err := mountpk.MakePrivate(root); err != nil { return nil, err } // Populate the dir structure for _, p := range paths { if err := idtools.MkdirAllAs(path.Join(root, p), 0700, rootUID, rootGID); err != nil { return nil, err } } return a, nil }
// setupInitLayer populates a directory with mountpoints suitable // for bind-mounting dockerinit into the container. The mountpoint is simply an // empty file at /.dockerinit // // This extra layer is used by all containers as the top-most ro layer. It protects // the container from unwanted side-effects on the rw layer. func setupInitLayer(initLayer string, rootUID, rootGID int) error { for pth, typ := range map[string]string{ "/dev/pts": "dir", "/dev/shm": "dir", "/proc": "dir", "/sys": "dir", "/.dockerinit": "file", "/.dockerenv": "file", "/etc/resolv.conf": "file", "/etc/hosts": "file", "/etc/hostname": "file", "/dev/console": "file", "/etc/mtab": "/proc/mounts", } { parts := strings.Split(pth, "/") prev := "/" for _, p := range parts[1:] { prev = filepath.Join(prev, p) syscall.Unlink(filepath.Join(initLayer, prev)) } if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil { if os.IsNotExist(err) { if err := idtools.MkdirAllAs(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootUID, rootGID); err != nil { return err } switch typ { case "dir": if err := idtools.MkdirAllAs(filepath.Join(initLayer, pth), 0755, rootUID, rootGID); err != nil { return err } case "file": f, err := os.OpenFile(filepath.Join(initLayer, pth), os.O_CREATE, 0755) if err != nil { return err } f.Close() f.Chown(rootUID, rootGID) default: if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil { return err } } } else { return err } } } // Layer is ready to use, if it wasn't before. return nil }
// Get mounts a device with given id into the root filesystem func (d *Driver) Get(id, mountLabel string) (string, error) { mp := path.Join(d.home, "mnt", id) rootFs := path.Join(mp, "rootfs") if count := d.ctr.Increment(mp); count > 1 { return rootFs, nil } uid, gid, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) if err != nil { d.ctr.Decrement(mp) return "", err } // Create the target directories if they don't exist if err := idtools.MkdirAllAs(path.Join(d.home, "mnt"), 0755, uid, gid); err != nil && !os.IsExist(err) { d.ctr.Decrement(mp) return "", err } if err := idtools.MkdirAs(mp, 0755, uid, gid); err != nil && !os.IsExist(err) { d.ctr.Decrement(mp) return "", err } // Mount the device if err := d.DeviceSet.MountDevice(id, mp, mountLabel); err != nil { d.ctr.Decrement(mp) return "", err } if err := idtools.MkdirAllAs(rootFs, 0755, uid, gid); err != nil && !os.IsExist(err) { d.ctr.Decrement(mp) d.DeviceSet.UnmountDevice(id, mp) return "", err } idFile := path.Join(mp, "id") if _, err := os.Stat(idFile); err != nil && os.IsNotExist(err) { // Create an "id" file with the container/image id in it to help reconstruct this in case // of later problems if err := ioutil.WriteFile(idFile, []byte(id), 0600); err != nil { d.ctr.Decrement(mp) d.DeviceSet.UnmountDevice(id, mp) return "", err } } return rootFs, nil }
func (daemon *Daemon) setupIpcDirs(c *container.Container) error { rootUID, rootGID := daemon.GetRemappedUIDGID() if !c.HasMountFor("/dev/shm") { shmPath, err := c.ShmResourcePath() if err != nil { return err } if err := idtools.MkdirAllAs(shmPath, 0700, rootUID, rootGID); err != nil { return err } shmSize := container.DefaultSHMSize if c.HostConfig.ShmSize != 0 { shmSize = c.HostConfig.ShmSize } shmproperty := "mode=1777,size=" + strconv.FormatInt(shmSize, 10) if err := syscall.Mount("shm", shmPath, "tmpfs", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), label.FormatMountLabel(shmproperty, c.GetMountLabel())); err != nil { return fmt.Errorf("mounting shm tmpfs: %s", err) } if err := os.Chown(shmPath, rootUID, rootGID); err != nil { return err } } return nil }
// Init returns a new BTRFS driver. // An error is returned if BTRFS is not supported. func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { fsMagic, err := graphdriver.GetFSMagic(home) if err != nil { return nil, err } if fsMagic != graphdriver.FsMagicBtrfs { return nil, graphdriver.ErrPrerequisites } rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) if err != nil { return nil, err } if err := idtools.MkdirAllAs(home, 0700, rootUID, rootGID); err != nil { return nil, err } if err := mount.MakePrivate(home); err != nil { return nil, err } driver := &Driver{ home: home, uidMaps: uidMaps, gidMaps: gidMaps, } return graphdriver.NewNaiveDiffDriver(driver, uidMaps, gidMaps), nil }
// Init returns a new BTRFS driver. // An error is returned if BTRFS is not supported. func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { rootdir := path.Dir(home) var buf syscall.Statfs_t if err := syscall.Statfs(rootdir, &buf); err != nil { return nil, err } if graphdriver.FsMagic(buf.Type) != graphdriver.FsMagicBtrfs { return nil, graphdriver.ErrPrerequisites } rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) if err != nil { return nil, err } if err := idtools.MkdirAllAs(home, 0700, rootUID, rootGID); err != nil { return nil, err } if err := mount.MakePrivate(home); err != nil { return nil, err } driver := &Driver{ home: home, uidMaps: uidMaps, gidMaps: gidMaps, } return graphdriver.NewNaiveDiffDriver(driver, uidMaps, gidMaps), nil }
// Create the filesystem with given id. func (d *Driver) Create(id, parent, mountLabel string) error { subvolumes := path.Join(d.home, "subvolumes") rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) if err != nil { return err } if err := idtools.MkdirAllAs(subvolumes, 0700, rootUID, rootGID); err != nil { return err } if parent == "" { if err := subvolCreate(subvolumes, id); err != nil { return err } } else { parentDir, err := d.Get(parent, "") if err != nil { return err } if err := subvolSnapshot(parentDir, subvolumes, id); err != nil { return err } } return label.Relabel(path.Join(subvolumes, id), mountLabel, false) }
// Create prepares the filesystem for the VFS driver and copies the directory for the given id under the parent. func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) error { if len(storageOpt) != 0 { return fmt.Errorf("--storage-opt is not supported for vfs") } dir := d.dir(id) rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) if err != nil { return err } if err := idtools.MkdirAllAs(filepath.Dir(dir), 0700, rootUID, rootGID); err != nil { return err } if err := idtools.MkdirAs(dir, 0755, rootUID, rootGID); err != nil { return err } opts := []string{"level:s0"} if _, mountLabel, err := label.InitLabels(opts); err == nil { label.SetFileLabel(dir, mountLabel) } if parent == "" { return nil } parentDir, err := d.Get(parent, "") if err != nil { return fmt.Errorf("%s: %s", parent, err) } if err := CopyWithTar(parentDir, dir); err != nil { return err } return nil }
// Create the filesystem with given id. func (d *Driver) Create(id, parent, mountLabel string) error { subvolumes := path.Join(d.home, "subvolumes") rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) if err != nil { return err } if err := idtools.MkdirAllAs(subvolumes, 0700, rootUID, rootGID); err != nil { return err } if parent == "" { if err := subvolCreate(subvolumes, id); err != nil { return err } } else { parentDir, err := d.Get(parent, "") if err != nil { return err } if err := subvolSnapshot(parentDir, subvolumes, id); err != nil { return err } } // if we have a remapped root (user namespaces enabled), change the created snapshot // dir ownership to match if rootUID != 0 || rootGID != 0 { if err := os.Chown(path.Join(subvolumes, id), rootUID, rootGID); err != nil { return err } } return label.Relabel(path.Join(subvolumes, id), mountLabel, false) }
// Create prepares the filesystem for the VFS driver and copies the directory for the given id under the parent. func (d *Driver) Create(id, parent, mountLabel string) error { dir := d.dir(id) rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) if err != nil { return err } if err := idtools.MkdirAllAs(filepath.Dir(dir), 0700, rootUID, rootGID); err != nil { return err } if err := idtools.MkdirAs(dir, 0755, rootUID, rootGID); err != nil { return err } opts := []string{"level:s0"} if _, mountLabel, err := label.InitLabels(opts); err == nil { label.SetFileLabel(dir, mountLabel) } if parent == "" { return nil } parentDir, err := d.Get(parent, "") if err != nil { return fmt.Errorf("%s: %s", parent, err) } if err := chrootarchive.CopyWithTar(parentDir, dir); err != nil { return err } return nil }
func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error { config.Root = rootDir // the docker root metadata directory needs to have execute permissions for all users (o+x) // so that syscalls executing as non-root, operating on subdirectories of the graph root // (e.g. mounted layers of a container) can traverse this path. // The user namespace support will create subdirectories for the remapped root host uid:gid // pair owned by that same uid:gid pair for proper write access to those needed metadata and // layer content subtrees. if _, err := os.Stat(rootDir); err == nil { // root current exists; verify the access bits are correct by setting them if err = os.Chmod(rootDir, 0701); err != nil { return err } } else if os.IsNotExist(err) { // no root exists yet, create it 0701 with root:root ownership if err := os.MkdirAll(rootDir, 0701); err != nil { return err } } // if user namespaces are enabled we will create a subtree underneath the specified root // with any/all specified remapped root uid/gid options on the daemon creating // a new subdirectory with ownership set to the remapped uid/gid (so as to allow // `chdir()` to work for containers namespaced to that uid/gid) if config.RemappedRoot != "" { config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootUID, rootGID)) logrus.Debugf("Creating user namespaced daemon root: %s", config.Root) // Create the root directory if it doesn't exists if err := idtools.MkdirAllAs(config.Root, 0700, rootUID, rootGID); err != nil { return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err) } } return nil }
// NewGraph instantiates a new graph at the given root path in the filesystem. // `root` will be created if it doesn't exist. func NewGraph(root string, driver graphdriver.Driver, uidMaps, gidMaps []idtools.IDMap) (*Graph, error) { abspath, err := filepath.Abs(root) if err != nil { return nil, err } rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) if err != nil { return nil, err } // Create the root directory if it doesn't exists if err := idtools.MkdirAllAs(root, 0700, rootUID, rootGID); err != nil && !os.IsExist(err) { return nil, err } graph := &Graph{ root: abspath, idIndex: truncindex.NewTruncIndex([]string{}), driver: driver, retained: &retainedLayers{layerHolders: make(map[string]map[string]struct{})}, uidMaps: uidMaps, gidMaps: gidMaps, parentRefs: make(map[string]int), } // Windows does not currently support tarsplit functionality. if runtime.GOOS == "windows" { graph.tarSplitDisabled = true } if err := graph.restore(); err != nil { return nil, err } return graph, nil }
// Create creates a new volume.Volume with the provided name, creating // the underlying directory tree required for this volume in the // process. func (r *Root) Create(name string, _ map[string]string) (volume.Volume, error) { if err := r.validateName(name); err != nil { return nil, err } r.m.Lock() defer r.m.Unlock() v, exists := r.volumes[name] if exists { return v, nil } path := r.DataPath(name) if err := idtools.MkdirAllAs(path, 0755, r.rootUID, r.rootGID); err != nil { if os.IsExist(err) { return nil, fmt.Errorf("volume already exists under %s", filepath.Dir(path)) } return nil, err } v = &localVolume{ driverName: r.Name(), name: name, path: path, } r.volumes[name] = v return v, nil }
// Get returns the mountpoint for the given id after creating the target directories if necessary. func (d *Driver) Get(id, mountLabel string) (string, error) { mountpoint := d.mountPath(id) filesystem := d.zfsPath(id) options := label.FormatMountLabel("", mountLabel) logrus.Debugf(`[zfs] mount("%s", "%s", "%s")`, filesystem, mountpoint, options) rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) if err != nil { return "", err } // Create the target directories if they don't exist if err := idtools.MkdirAllAs(mountpoint, 0755, rootUID, rootGID); err != nil { return "", err } if err := mount.Mount(filesystem, mountpoint, "zfs", options); err != nil { return "", fmt.Errorf("error creating zfs mount of %s to %s: %v", filesystem, mountpoint, err) } // this could be our first mount after creation of the filesystem, and the root dir may still have root // permissions instead of the remapped root uid:gid (if user namespaces are enabled): if err := os.Chown(mountpoint, rootUID, rootGID); err != nil { return "", fmt.Errorf("error modifying zfs mountpoint (%s) directory ownership: %v", mountpoint, err) } return mountpoint, nil }
// tempDir returns the default directory to use for temporary files. func tempDir(rootDir string, rootUID, rootGID int) (string, error) { var tmpDir string if tmpDir = os.Getenv("DOCKER_TMPDIR"); tmpDir == "" { tmpDir = filepath.Join(rootDir, "tmp") } return tmpDir, idtools.MkdirAllAs(tmpDir, 0700, rootUID, rootGID) }
// New instantiates a new Root instance with the provided scope. Scope // is the base path that the Root instance uses to store its // volumes. The base path is created here if it does not exist. func New(scope string, rootUID, rootGID int) (*Root, error) { rootDirectory := filepath.Join(scope, volumesPathName) if err := idtools.MkdirAllAs(rootDirectory, 0700, rootUID, rootGID); err != nil { return nil, err } r := &Root{ scope: scope, path: rootDirectory, volumes: make(map[string]*localVolume), rootUID: rootUID, rootGID: rootGID, } dirs, err := ioutil.ReadDir(rootDirectory) if err != nil { return nil, err } for _, d := range dirs { name := filepath.Base(d.Name()) r.volumes[name] = &localVolume{ driverName: r.Name(), name: name, path: r.DataPath(name), } } return r, nil }
// Init returns the a native diff driver for overlay filesystem. // If overlay filesystem is not supported on the host, graphdriver.ErrNotSupported is returned as error. // If a overlay filesystem is not supported over a existing filesystem then error graphdriver.ErrIncompatibleFS is returned. func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { opts, err := parseOptions(options) if err != nil { return nil, err } if err := supportsOverlay(); err != nil { return nil, graphdriver.ErrNotSupported } // require kernel 4.0.0 to ensure multiple lower dirs are supported v, err := kernel.GetKernelVersion() if err != nil { return nil, err } if kernel.CompareKernelVersion(*v, kernel.VersionInfo{Kernel: 4, Major: 0, Minor: 0}) < 0 { if !opts.overrideKernelCheck { return nil, graphdriver.ErrNotSupported } logrus.Warnf("Using pre-4.0.0 kernel for overlay2, mount failures may require kernel update") } fsMagic, err := graphdriver.GetFSMagic(home) if err != nil { return nil, err } if fsName, ok := graphdriver.FsNames[fsMagic]; ok { backingFs = fsName } // check if they are running over btrfs, aufs, zfs, overlay, or ecryptfs switch fsMagic { case graphdriver.FsMagicBtrfs, graphdriver.FsMagicAufs, graphdriver.FsMagicZfs, graphdriver.FsMagicOverlay, graphdriver.FsMagicEcryptfs: logrus.Errorf("'overlay2' is not supported over %s", backingFs) return nil, graphdriver.ErrIncompatibleFS } rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) if err != nil { return nil, err } // Create the driver home dir if err := idtools.MkdirAllAs(path.Join(home, linkDir), 0700, rootUID, rootGID); err != nil && !os.IsExist(err) { return nil, err } if err := mount.MakePrivate(home); err != nil { return nil, err } d := &Driver{ home: home, uidMaps: uidMaps, gidMaps: gidMaps, ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicOverlay)), } return d, nil }
// New instantiates a new Root instance with the provided scope. Scope // is the base path that the Root instance uses to store its // volumes. The base path is created here if it does not exist. func New(scope string, rootUID, rootGID int) (*Root, error) { rootDirectory := filepath.Join(scope, volumesPathName) if err := idtools.MkdirAllAs(rootDirectory, 0700, rootUID, rootGID); err != nil { return nil, err } r := &Root{ scope: scope, path: rootDirectory, volumes: make(map[string]*localVolume), rootUID: rootUID, rootGID: rootGID, } dirs, err := ioutil.ReadDir(rootDirectory) if err != nil { return nil, err } mountInfos, err := mount.GetMounts() if err != nil { logrus.Debugf("error looking up mounts for local volume cleanup: %v", err) } for _, d := range dirs { if !d.IsDir() { continue } name := filepath.Base(d.Name()) v := &localVolume{ driverName: r.Name(), name: name, path: r.DataPath(name), } r.volumes[name] = v optsFilePath := filepath.Join(rootDirectory, name, "opts.json") if b, err := ioutil.ReadFile(optsFilePath); err == nil { opts := optsConfig{} if err := json.Unmarshal(b, &opts); err != nil { return nil, err } if !reflect.DeepEqual(opts, optsConfig{}) { v.opts = &opts } // unmount anything that may still be mounted (for example, from an unclean shutdown) for _, info := range mountInfos { if info.Mountpoint == v.path { mount.Unmount(v.path) break } } } } return r, nil }
func (daemon *Daemon) setupIpcDirs(container *Container) error { rootUID, rootGID := daemon.GetRemappedUIDGID() if !container.hasMountFor("/dev/shm") { shmPath, err := container.shmPath() if err != nil { return err } if err := idtools.MkdirAllAs(shmPath, 0700, rootUID, rootGID); err != nil { return err } // When ShmSize is 0 or less, the SHM size is set to 64MB. if container.hostConfig.ShmSize <= 0 { container.hostConfig.ShmSize = 67108864 } shmproperty := "mode=1777,size=" + strconv.FormatInt(container.hostConfig.ShmSize, 10) if err := syscall.Mount("shm", shmPath, "tmpfs", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), label.FormatMountLabel(shmproperty, container.getMountLabel())); err != nil { return fmt.Errorf("mounting shm tmpfs: %s", err) } if err := os.Chown(shmPath, rootUID, rootGID); err != nil { return err } } if !container.hasMountFor("/dev/mqueue") { mqueuePath, err := container.mqueuePath() if err != nil { return err } if err := idtools.MkdirAllAs(mqueuePath, 0700, rootUID, rootGID); err != nil { return err } if err := syscall.Mount("mqueue", mqueuePath, "mqueue", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), ""); err != nil { return fmt.Errorf("mounting mqueue mqueue : %s", err) } if err := os.Chown(mqueuePath, rootUID, rootGID); err != nil { return err } } return nil }
// Create the filesystem with given id. func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error { subvolumes := path.Join(d.home, "subvolumes") rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) if err != nil { return err } if err := idtools.MkdirAllAs(subvolumes, 0700, rootUID, rootGID); err != nil { return err } if parent == "" { if err := subvolCreate(subvolumes, id); err != nil { return err } } else { parentDir := d.subvolumesDirID(parent) st, err := os.Stat(parentDir) if err != nil { return err } if !st.IsDir() { return fmt.Errorf("%s: not a directory", parentDir) } if err := subvolSnapshot(parentDir, subvolumes, id); err != nil { return err } } var storageOpt map[string]string if opts != nil { storageOpt = opts.StorageOpt } if _, ok := storageOpt["size"]; ok { driver := &Driver{} if err := d.parseStorageOpt(storageOpt, driver); err != nil { return err } if err := d.setStorageSize(path.Join(subvolumes, id), driver); err != nil { return err } } // if we have a remapped root (user namespaces enabled), change the created snapshot // dir ownership to match if rootUID != 0 || rootGID != 0 { if err := os.Chown(path.Join(subvolumes, id), rootUID, rootGID); err != nil { return err } } mountLabel := "" if opts != nil { mountLabel = opts.MountLabel } return label.Relabel(path.Join(subvolumes, id), mountLabel, false) }
func (clnt *client) Create(containerID string, spec Spec, options ...CreateOption) (err error) { clnt.lock(containerID) defer clnt.unlock(containerID) if ctr, err := clnt.getContainer(containerID); err == nil { if ctr.restarting { ctr.restartManager.Cancel() ctr.clean() } else { return fmt.Errorf("Container %s is aleady active", containerID) } } uid, gid, err := getRootIDs(specs.Spec(spec)) if err != nil { return err } dir, err := clnt.prepareBundleDir(uid, gid) if err != nil { return err } container := clnt.newContainer(filepath.Join(dir, containerID), options...) if err := container.clean(); err != nil { return err } defer func() { if err != nil { container.clean() clnt.deleteContainer(containerID) } }() // uid/gid rootfsDir := filepath.Join(container.dir, "rootfs") if err := idtools.MkdirAllAs(rootfsDir, 0700, uid, gid); err != nil && !os.IsExist(err) { return err } if err := syscall.Mount(spec.Root.Path, rootfsDir, "bind", syscall.MS_REC|syscall.MS_BIND, ""); err != nil { return err } spec.Root.Path = "rootfs" f, err := os.Create(filepath.Join(container.dir, configFilename)) if err != nil { return err } defer f.Close() if err := json.NewEncoder(f).Encode(spec); err != nil { return err } return container.start() }
// mktemp creates a temporary sub-directory inside the graph's filesystem. func (graph *Graph) mktemp() (string, error) { dir := filepath.Join(graph.root, "_tmp", stringid.GenerateNonCryptoID()) rootUID, rootGID, err := idtools.GetRootUIDGID(graph.uidMaps, graph.gidMaps) if err != nil { return "", err } if err := idtools.MkdirAllAs(dir, 0700, rootUID, rootGID); err != nil { return "", err } return dir, nil }
// Init returns the NaiveDiffDriver, a native diff driver for overlay filesystem. // If overlay filesystem is not supported on the host, graphdriver.ErrNotSupported is returned as error. // If a overlay filesystem is not supported over a existing filesystem then error graphdriver.ErrIncompatibleFS is returned. func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { if err := supportsOverlay(); err != nil { return nil, graphdriver.ErrNotSupported } fsMagic, err := graphdriver.GetFSMagic(home) if err != nil { return nil, err } if fsName, ok := graphdriver.FsNames[fsMagic]; ok { backingFs = fsName } // check if they are running over btrfs, aufs, zfs or overlay switch fsMagic { case graphdriver.FsMagicBtrfs: logrus.Error("'overlay' is not supported over btrfs.") return nil, graphdriver.ErrIncompatibleFS case graphdriver.FsMagicAufs: logrus.Error("'overlay' is not supported over aufs.") return nil, graphdriver.ErrIncompatibleFS case graphdriver.FsMagicZfs: logrus.Error("'overlay' is not supported over zfs.") return nil, graphdriver.ErrIncompatibleFS case graphdriver.FsMagicOverlay: logrus.Error("'overlay' is not supported over overlay.") return nil, graphdriver.ErrIncompatibleFS } rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) if err != nil { return nil, err } // Create the driver home dir if err := idtools.MkdirAllAs(home, 0700, rootUID, rootGID); err != nil && !os.IsExist(err) { return nil, err } if err := mount.MakePrivate(home); err != nil { return nil, err } d := &Driver{ home: home, pathCache: make(map[string]string), uidMaps: uidMaps, gidMaps: gidMaps, ctr: graphdriver.NewRefCounter(), } return NaiveDiffDriverWithApply(d, uidMaps, gidMaps), nil }
func (container *Container) setupIpcDirs() error { rootUID, rootGID := container.daemon.GetRemappedUIDGID() if !container.hasMountFor("/dev/shm") { shmPath, err := container.shmPath() if err != nil { return err } if err := idtools.MkdirAllAs(shmPath, 0700, rootUID, rootGID); err != nil { return err } if err := syscall.Mount("shm", shmPath, "tmpfs", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), label.FormatMountLabel("mode=1777,size=65536k", container.getMountLabel())); err != nil { return fmt.Errorf("mounting shm tmpfs: %s", err) } if err := os.Chown(shmPath, rootUID, rootGID); err != nil { return err } } if !container.hasMountFor("/dev/mqueue") { mqueuePath, err := container.mqueuePath() if err != nil { return err } if err := idtools.MkdirAllAs(mqueuePath, 0700, rootUID, rootGID); err != nil { return err } if err := syscall.Mount("mqueue", mqueuePath, "mqueue", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), ""); err != nil { return fmt.Errorf("mounting mqueue mqueue : %s", err) } if err := os.Chown(mqueuePath, rootUID, rootGID); err != nil { return err } } return nil }
// Init returns the NaiveDiffDriver, a native diff driver for overlay filesystem. // If overlay filesystem is not supported on the host, graphdriver.ErrNotSupported is returned as error. // If an overlay filesystem is not supported over an existing filesystem then error graphdriver.ErrIncompatibleFS is returned. func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { if err := supportsOverlay(); err != nil { return nil, graphdriver.ErrNotSupported } fsMagic, err := graphdriver.GetFSMagic(home) if err != nil { return nil, err } if fsName, ok := graphdriver.FsNames[fsMagic]; ok { backingFs = fsName } switch fsMagic { case graphdriver.FsMagicAufs, graphdriver.FsMagicBtrfs, graphdriver.FsMagicOverlay, graphdriver.FsMagicZfs, graphdriver.FsMagicEcryptfs: logrus.Errorf("'overlay' is not supported over %s", backingFs) return nil, graphdriver.ErrIncompatibleFS } rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) if err != nil { return nil, err } // Create the driver home dir if err := idtools.MkdirAllAs(home, 0700, rootUID, rootGID); err != nil && !os.IsExist(err) { return nil, err } if err := mount.MakePrivate(home); err != nil { return nil, err } supportsDType, err := fsutils.SupportsDType(home) if err != nil { return nil, err } if !supportsDType { // not a fatal error until v1.16 (#27443) logrus.Warn(overlayutils.ErrDTypeNotSupported("overlay", backingFs)) } d := &Driver{ home: home, uidMaps: uidMaps, gidMaps: gidMaps, ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicOverlay)), supportsDType: supportsDType, } return NaiveDiffDriverWithApply(d, uidMaps, gidMaps), nil }
func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error { // the main docker root needs to be accessible by all users, as user namespace support // will create subdirectories owned by either a) the real system root (when no remapping // is setup) or b) the remapped root host ID (when --root=uid:gid is used) // for "first time" users of user namespaces, we need to migrate the current directory // contents to the "0.0" (root == root "namespace" daemon root) nsRoot := "0.0" if _, err := os.Stat(rootDir); err == nil { // root current exists; we need to check for a prior migration if _, err := os.Stat(filepath.Join(rootDir, nsRoot)); err != nil && os.IsNotExist(err) { // need to migrate current root to "0.0" subroot // 1. create non-usernamespaced root as "0.0" if err := os.Mkdir(filepath.Join(rootDir, nsRoot), 0700); err != nil { return fmt.Errorf("Cannot create daemon root %q: %v", filepath.Join(rootDir, nsRoot), err) } // 2. move current root content to "0.0" new subroot if err := directory.MoveToSubdir(rootDir, nsRoot); err != nil { return fmt.Errorf("Cannot migrate current daemon root %q for user namespaces: %v", rootDir, err) } // 3. chmod outer root to 755 if chmodErr := os.Chmod(rootDir, 0755); chmodErr != nil { return chmodErr } } } else if os.IsNotExist(err) { // no root exists yet, create it 0755 with root:root ownership if err := os.MkdirAll(rootDir, 0755); err != nil { return err } // create the "0.0" subroot (so no future "migration" happens of the root) if err := os.Mkdir(filepath.Join(rootDir, nsRoot), 0700); err != nil { return err } } // for user namespaces we will create a subtree underneath the specified root // with any/all specified remapped root uid/gid options on the daemon creating // a new subdirectory with ownership set to the remapped uid/gid (so as to allow // `chdir()` to work for containers namespaced to that uid/gid) if config.RemappedRoot != "" { nsRoot = fmt.Sprintf("%d.%d", rootUID, rootGID) } config.Root = filepath.Join(rootDir, nsRoot) logrus.Debugf("Creating actual daemon root: %s", config.Root) // Create the root directory if it doesn't exists if err := idtools.MkdirAllAs(config.Root, 0700, rootUID, rootGID); err != nil { return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err) } return nil }
// Create creates a new volume.Volume with the provided name, creating // the underlying directory tree required for this volume in the // process. func (r *Root) Create(name string, opts map[string]string) (volume.Volume, error) { if err := r.validateName(name); err != nil { return nil, err } r.m.Lock() defer r.m.Unlock() v, exists := r.volumes[name] if exists { return v, nil } path := r.DataPath(name) if err := idtools.MkdirAllAs(path, 0755, r.rootUID, r.rootGID); err != nil { if os.IsExist(err) { return nil, fmt.Errorf("volume already exists under %s", filepath.Dir(path)) } return nil, errors.Wrapf(err, "error while creating volume path '%s'", path) } var err error defer func() { if err != nil { os.RemoveAll(filepath.Dir(path)) } }() v = &localVolume{ driverName: r.Name(), name: name, path: path, } if len(opts) != 0 { if err = setOpts(v, opts); err != nil { return nil, err } var b []byte b, err = json.Marshal(v.opts) if err != nil { return nil, err } if err = ioutil.WriteFile(filepath.Join(filepath.Dir(path), "opts.json"), b, 600); err != nil { return nil, errors.Wrap(err, "error while persisting volume options") } } r.volumes[name] = v return v, nil }
func (clnt *client) Create(containerID string, spec Spec, attachStdio StdioCallback, options ...CreateOption) (err error) { clnt.lock(containerID) defer clnt.unlock(containerID) if ctr, err := clnt.getContainer(containerID); err == nil { if ctr.restarting { ctr.restartManager.Cancel() ctr.clean() } else { return fmt.Errorf("Container %s is already active", containerID) } } uid, gid, err := getRootIDs(specs.Spec(spec)) if err != nil { return err } dir, err := clnt.prepareBundleDir(uid, gid) if err != nil { return err } container := clnt.newContainer(filepath.Join(dir, containerID), options...) if err := container.clean(); err != nil { return err } container.attachStdio = attachStdio // hack for v1.12 backport defer func() { if err != nil { container.clean() clnt.deleteContainer(containerID) } }() if err := idtools.MkdirAllAs(container.dir, 0700, uid, gid); err != nil && !os.IsExist(err) { return err } f, err := os.Create(filepath.Join(container.dir, configFilename)) if err != nil { return err } defer f.Close() if err := json.NewEncoder(f).Encode(spec); err != nil { return err } return container.start(attachStdio) }
// Init returns a new VFS driver. // This sets the home directory for the driver and returns NaiveDiffDriver. func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { d := &Driver{ home: home, uidMaps: uidMaps, gidMaps: gidMaps, } rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) if err != nil { return nil, err } if err := idtools.MkdirAllAs(home, 0700, rootUID, rootGID); err != nil { return nil, err } return graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps), nil }
func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error { config.Root = rootDir // the docker root metadata directory needs to have execute permissions for all users (g+x,o+x) // so that syscalls executing as non-root, operating on subdirectories of the graph root // (e.g. mounted layers of a container) can traverse this path. // The user namespace support will create subdirectories for the remapped root host uid:gid // pair owned by that same uid:gid pair for proper write access to those needed metadata and // layer content subtrees. if _, err := os.Stat(rootDir); err == nil { // root current exists; verify the access bits are correct by setting them if err = os.Chmod(rootDir, 0711); err != nil { return err } } else if os.IsNotExist(err) { // no root exists yet, create it 0711 with root:root ownership if err := os.MkdirAll(rootDir, 0711); err != nil { return err } } // if user namespaces are enabled we will create a subtree underneath the specified root // with any/all specified remapped root uid/gid options on the daemon creating // a new subdirectory with ownership set to the remapped uid/gid (so as to allow // `chdir()` to work for containers namespaced to that uid/gid) if config.RemappedRoot != "" { config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootUID, rootGID)) logrus.Debugf("Creating user namespaced daemon root: %s", config.Root) // Create the root directory if it doesn't exist if err := idtools.MkdirAllAs(config.Root, 0700, rootUID, rootGID); err != nil { return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err) } // we also need to verify that any pre-existing directories in the path to // the graphroot won't block access to remapped root--if any pre-existing directory // has strict permissions that don't allow "x", container start will fail, so // better to warn and fail now dirPath := config.Root for { dirPath = filepath.Dir(dirPath) if dirPath == "/" { break } if !idtools.CanAccess(dirPath, rootUID, rootGID) { return fmt.Errorf("A subdirectory in your graphroot path (%s) restricts access to the remapped root uid/gid; please fix by allowing 'o+x' permissions on existing directories.", config.Root) } } } return nil }