blob: b65ad7a5b06c3d11ea9fe346e549f2fecd8b828b [file] [log] [blame]
// +build experimental
package daemon
import (
"fmt"
"os"
"path/filepath"
"runtime"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/directory"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/runconfig"
)
func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) {
if config.ExecDriver != "native" && config.RemappedRoot != "" {
return nil, nil, fmt.Errorf("User namespace remapping is only supported with the native execdriver")
}
if runtime.GOOS == "windows" && config.RemappedRoot != "" {
return nil, nil, fmt.Errorf("User namespaces are not supported on Windows")
}
// if the daemon was started with remapped root option, parse
// the config option to the int uid,gid values
var (
uidMaps, gidMaps []idtools.IDMap
)
if config.RemappedRoot != "" {
username, groupname, err := parseRemappedRoot(config.RemappedRoot)
if err != nil {
return nil, nil, err
}
if username == "root" {
// Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op
// effectively
logrus.Warnf("User namespaces: root cannot be remapped with itself; user namespaces are OFF")
return uidMaps, gidMaps, nil
}
logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname)
// update remapped root setting now that we have resolved them to actual names
config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname)
uidMaps, gidMaps, err = idtools.CreateIDMappings(username, groupname)
if err != nil {
return nil, nil, fmt.Errorf("Can't create ID mappings: %v", err)
}
}
return 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
}
func (daemon *Daemon) verifyExperimentalContainerSettings(hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) {
if hostConfig.Privileged && daemon.config().RemappedRoot != "" {
return nil, fmt.Errorf("Privileged mode is incompatible with user namespace mappings")
}
return nil, nil
}