github.com/jfrazelle/docker@v1.1.2-0.20210712172922-bf78e25fe508/rootless/specconv/specconv_linux.go (about) 1 package specconv // import "github.com/docker/docker/rootless/specconv" 2 3 import ( 4 "io/ioutil" 5 "os" 6 "path" 7 "strconv" 8 "strings" 9 10 specs "github.com/opencontainers/runtime-spec/specs-go" 11 "github.com/sirupsen/logrus" 12 ) 13 14 // ToRootless converts spec to be compatible with "rootless" runc. 15 // * Remove non-supported cgroups 16 // * Fix up OOMScoreAdj 17 // * Fix up /proc if --pid=host 18 // 19 // v2Controllers should be non-nil only if running with v2 and systemd. 20 func ToRootless(spec *specs.Spec, v2Controllers []string) error { 21 return toRootless(spec, v2Controllers, getCurrentOOMScoreAdj()) 22 } 23 24 func getCurrentOOMScoreAdj() int { 25 b, err := ioutil.ReadFile("/proc/self/oom_score_adj") 26 if err != nil { 27 logrus.WithError(err).Warn("failed to read /proc/self/oom_score_adj") 28 return 0 29 } 30 s := string(b) 31 i, err := strconv.Atoi(strings.TrimSpace(s)) 32 if err != nil { 33 logrus.WithError(err).Warnf("failed to parse /proc/self/oom_score_adj (%q)", s) 34 return 0 35 } 36 return i 37 } 38 39 func toRootless(spec *specs.Spec, v2Controllers []string, currentOOMScoreAdj int) error { 40 if len(v2Controllers) == 0 { 41 // Remove cgroup settings. 42 spec.Linux.Resources = nil 43 spec.Linux.CgroupsPath = "" 44 } else { 45 if spec.Linux.Resources != nil { 46 m := make(map[string]struct{}) 47 for _, s := range v2Controllers { 48 m[s] = struct{}{} 49 } 50 // Remove devices: https://github.com/containers/crun/issues/255 51 spec.Linux.Resources.Devices = nil 52 if _, ok := m["memory"]; !ok { 53 spec.Linux.Resources.Memory = nil 54 } 55 if _, ok := m["cpu"]; !ok { 56 spec.Linux.Resources.CPU = nil 57 } 58 if _, ok := m["cpuset"]; !ok { 59 if spec.Linux.Resources.CPU != nil { 60 spec.Linux.Resources.CPU.Cpus = "" 61 spec.Linux.Resources.CPU.Mems = "" 62 } 63 } 64 if _, ok := m["pids"]; !ok { 65 spec.Linux.Resources.Pids = nil 66 } 67 if _, ok := m["io"]; !ok { 68 spec.Linux.Resources.BlockIO = nil 69 } 70 if _, ok := m["rdma"]; !ok { 71 spec.Linux.Resources.Rdma = nil 72 } 73 spec.Linux.Resources.HugepageLimits = nil 74 spec.Linux.Resources.Network = nil 75 } 76 } 77 78 if spec.Process.OOMScoreAdj != nil && *spec.Process.OOMScoreAdj < currentOOMScoreAdj { 79 *spec.Process.OOMScoreAdj = currentOOMScoreAdj 80 } 81 82 // Fix up /proc if --pid=host 83 pidHost, err := isPidHost(spec) 84 if err != nil { 85 return err 86 } 87 if !pidHost { 88 return nil 89 } 90 return bindMountHostProcfs(spec) 91 } 92 93 func isPidHost(spec *specs.Spec) (bool, error) { 94 for _, ns := range spec.Linux.Namespaces { 95 if ns.Type == specs.PIDNamespace { 96 if ns.Path == "" { 97 return false, nil 98 } 99 pidNS, err := os.Readlink(ns.Path) 100 if err != nil { 101 return false, err 102 } 103 selfPidNS, err := os.Readlink("/proc/self/ns/pid") 104 if err != nil { 105 return false, err 106 } 107 return pidNS == selfPidNS, nil 108 } 109 } 110 return true, nil 111 } 112 113 func bindMountHostProcfs(spec *specs.Spec) error { 114 // Replace procfs mount with rbind 115 // https://github.com/containers/podman/blob/v3.0.0-rc1/pkg/specgen/generate/oci.go#L248-L257 116 for i, m := range spec.Mounts { 117 if path.Clean(m.Destination) == "/proc" { 118 newM := specs.Mount{ 119 Destination: "/proc", 120 Type: "bind", 121 Source: "/proc", 122 Options: []string{"rbind", "nosuid", "noexec", "nodev"}, 123 } 124 spec.Mounts[i] = newM 125 } 126 } 127 128 // Remove ReadonlyPaths for /proc/* 129 newROP := spec.Linux.ReadonlyPaths[:0] 130 for _, s := range spec.Linux.ReadonlyPaths { 131 s = path.Clean(s) 132 if !strings.HasPrefix(s, "/proc/") { 133 newROP = append(newROP, s) 134 } 135 } 136 spec.Linux.ReadonlyPaths = newROP 137 138 return nil 139 }