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