| // +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{ |
| // TODO (AkihiroSuda): unmask /sys/firmware on Windows daemon for LCOW support? |
| // https://github.com/moby/moby/pull/33241/files#diff-a1f5051ce84e711a2ee688ab9ded5e74R215 |
| MaskedPaths: []string{ |
| "/proc/kcore", |
| "/proc/latency_stats", |
| "/proc/timer_list", |
| "/proc/timer_stats", |
| "/proc/sched_debug", |
| "/sys/firmware", |
| }, |
| 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) |
| } |
| } |