205 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			205 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // +build !windows
 | |
| 
 | |
| package containerd
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"io/ioutil"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"syscall"
 | |
| 
 | |
| 	"golang.org/x/sys/unix"
 | |
| 
 | |
| 	"github.com/containerd/containerd/mount"
 | |
| 	"github.com/containerd/containerd/namespaces"
 | |
| 	specs "github.com/opencontainers/runtime-spec/specs-go"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	rwm               = "rwm"
 | |
| 	defaultRootfsPath = "rootfs"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	defaultEnv = []string{
 | |
| 		"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
 | |
| 	}
 | |
| )
 | |
| 
 | |
| func defaultCaps() []string {
 | |
| 	return []string{
 | |
| 		"CAP_CHOWN",
 | |
| 		"CAP_DAC_OVERRIDE",
 | |
| 		"CAP_FSETID",
 | |
| 		"CAP_FOWNER",
 | |
| 		"CAP_MKNOD",
 | |
| 		"CAP_NET_RAW",
 | |
| 		"CAP_SETGID",
 | |
| 		"CAP_SETUID",
 | |
| 		"CAP_SETFCAP",
 | |
| 		"CAP_SETPCAP",
 | |
| 		"CAP_NET_BIND_SERVICE",
 | |
| 		"CAP_SYS_CHROOT",
 | |
| 		"CAP_KILL",
 | |
| 		"CAP_AUDIT_WRITE",
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func defaultNamespaces() []specs.LinuxNamespace {
 | |
| 	return []specs.LinuxNamespace{
 | |
| 		{
 | |
| 			Type: specs.PIDNamespace,
 | |
| 		},
 | |
| 		{
 | |
| 			Type: specs.IPCNamespace,
 | |
| 		},
 | |
| 		{
 | |
| 			Type: specs.UTSNamespace,
 | |
| 		},
 | |
| 		{
 | |
| 			Type: specs.MountNamespace,
 | |
| 		},
 | |
| 		{
 | |
| 			Type: specs.NetworkNamespace,
 | |
| 		},
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func createDefaultSpec(ctx context.Context, id string) (*specs.Spec, error) {
 | |
| 	ns, err := namespaces.NamespaceRequired(ctx)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	s := &specs.Spec{
 | |
| 		Version: specs.Version,
 | |
| 		Root: &specs.Root{
 | |
| 			Path: defaultRootfsPath,
 | |
| 		},
 | |
| 		Process: &specs.Process{
 | |
| 			Env:             defaultEnv,
 | |
| 			Cwd:             "/",
 | |
| 			NoNewPrivileges: true,
 | |
| 			User: specs.User{
 | |
| 				UID: 0,
 | |
| 				GID: 0,
 | |
| 			},
 | |
| 			Capabilities: &specs.LinuxCapabilities{
 | |
| 				Bounding:    defaultCaps(),
 | |
| 				Permitted:   defaultCaps(),
 | |
| 				Inheritable: defaultCaps(),
 | |
| 				Effective:   defaultCaps(),
 | |
| 			},
 | |
| 			Rlimits: []specs.POSIXRlimit{
 | |
| 				{
 | |
| 					Type: "RLIMIT_NOFILE",
 | |
| 					Hard: uint64(1024),
 | |
| 					Soft: uint64(1024),
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		Mounts: []specs.Mount{
 | |
| 			{
 | |
| 				Destination: "/proc",
 | |
| 				Type:        "proc",
 | |
| 				Source:      "proc",
 | |
| 			},
 | |
| 			{
 | |
| 				Destination: "/dev",
 | |
| 				Type:        "tmpfs",
 | |
| 				Source:      "tmpfs",
 | |
| 				Options:     []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
 | |
| 			},
 | |
| 			{
 | |
| 				Destination: "/dev/pts",
 | |
| 				Type:        "devpts",
 | |
| 				Source:      "devpts",
 | |
| 				Options:     []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
 | |
| 			},
 | |
| 			{
 | |
| 				Destination: "/dev/shm",
 | |
| 				Type:        "tmpfs",
 | |
| 				Source:      "shm",
 | |
| 				Options:     []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"},
 | |
| 			},
 | |
| 			{
 | |
| 				Destination: "/dev/mqueue",
 | |
| 				Type:        "mqueue",
 | |
| 				Source:      "mqueue",
 | |
| 				Options:     []string{"nosuid", "noexec", "nodev"},
 | |
| 			},
 | |
| 			{
 | |
| 				Destination: "/sys",
 | |
| 				Type:        "sysfs",
 | |
| 				Source:      "sysfs",
 | |
| 				Options:     []string{"nosuid", "noexec", "nodev", "ro"},
 | |
| 			},
 | |
| 			{
 | |
| 				Destination: "/run",
 | |
| 				Type:        "tmpfs",
 | |
| 				Source:      "tmpfs",
 | |
| 				Options:     []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
 | |
| 			},
 | |
| 		},
 | |
| 		Linux: &specs.Linux{
 | |
| 			MaskedPaths: []string{
 | |
| 				"/proc/kcore",
 | |
| 				"/proc/latency_stats",
 | |
| 				"/proc/timer_list",
 | |
| 				"/proc/timer_stats",
 | |
| 				"/proc/sched_debug",
 | |
| 				"/sys/firmware",
 | |
| 				"/proc/scsi",
 | |
| 			},
 | |
| 			ReadonlyPaths: []string{
 | |
| 				"/proc/asound",
 | |
| 				"/proc/bus",
 | |
| 				"/proc/fs",
 | |
| 				"/proc/irq",
 | |
| 				"/proc/sys",
 | |
| 				"/proc/sysrq-trigger",
 | |
| 			},
 | |
| 			CgroupsPath: filepath.Join("/", ns, id),
 | |
| 			Resources: &specs.LinuxResources{
 | |
| 				Devices: []specs.LinuxDeviceCgroup{
 | |
| 					{
 | |
| 						Allow:  false,
 | |
| 						Access: rwm,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			Namespaces: defaultNamespaces(),
 | |
| 		},
 | |
| 	}
 | |
| 	return s, nil
 | |
| }
 | |
| 
 | |
| func remapRootFS(mounts []mount.Mount, uid, gid uint32) error {
 | |
| 	root, err := ioutil.TempDir("", "ctd-remap")
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	defer os.RemoveAll(root)
 | |
| 	for _, m := range mounts {
 | |
| 		if err := m.Mount(root); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 	defer unix.Unmount(root, 0)
 | |
| 	return filepath.Walk(root, incrementFS(root, uid, gid))
 | |
| }
 | |
| 
 | |
| func incrementFS(root string, uidInc, gidInc uint32) filepath.WalkFunc {
 | |
| 	return func(path string, info os.FileInfo, err error) error {
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		var (
 | |
| 			stat = info.Sys().(*syscall.Stat_t)
 | |
| 			u, g = int(stat.Uid + uidInc), int(stat.Gid + gidInc)
 | |
| 		)
 | |
| 		// be sure the lchown the path as to not de-reference the symlink to a host file
 | |
| 		return os.Lchown(path, u, g)
 | |
| 	}
 | |
| }
 | 
