From 708a917b7d76b704f706998442caf5404024740e Mon Sep 17 00:00:00 2001 From: Odin Ugedal Date: Sat, 5 Oct 2019 13:45:54 +0200 Subject: [PATCH 1/7] Bump dependency opencontainers/runc@v1.0.0-rc9 --- go.mod | 4 +- go.sum | 4 +- .../runc/libcontainer/README.md | 1 + .../runc/libcontainer/apparmor/apparmor.go | 10 +- .../runc/libcontainer/capabilities_linux.go | 6 +- .../runc/libcontainer/cgroups/fs/BUILD | 6 + .../runc/libcontainer/cgroups/fs/apply_raw.go | 35 +- .../runc/libcontainer/cgroups/fs/cpu_v2.go | 92 +++++ .../runc/libcontainer/cgroups/fs/cpuset_v2.go | 159 +++++++++ .../libcontainer/cgroups/fs/freezer_v2.go | 74 ++++ .../runc/libcontainer/cgroups/fs/io_v2.go | 191 ++++++++++ .../runc/libcontainer/cgroups/fs/memory_v2.go | 164 +++++++++ .../runc/libcontainer/cgroups/fs/pids_v2.go | 107 ++++++ .../runc/libcontainer/cgroups/fs/utils.go | 7 +- .../runc/libcontainer/cgroups/systemd/BUILD | 2 +- .../cgroups/systemd/apply_systemd.go | 140 +++----- .../cgroups/systemd/unified_hierarchy.go | 329 ++++++++++++++++++ .../runc/libcontainer/cgroups/utils.go | 58 ++- .../runc/libcontainer/configs/BUILD | 2 +- .../runc/libcontainer/configs/blkio_device.go | 5 + .../runc/libcontainer/configs/cgroup_linux.go | 8 + ...group_windows.go => cgroup_unsupported.go} | 2 + .../runc/libcontainer/configs/config.go | 1 + .../runc/libcontainer/container_linux.go | 15 +- .../runc/libcontainer/rootfs_linux.go | 186 ++++++---- .../runc/libcontainer/seccomp/config.go | 1 + .../libcontainer/seccomp/seccomp_linux.go | 3 + .../libcontainer/system/syscall_linux_64.go | 2 +- .../runc/libcontainer/utils/utils_unix.go | 44 ++- vendor/modules.txt | 2 +- 30 files changed, 1463 insertions(+), 197 deletions(-) create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu_v2.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset_v2.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer_v2.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/io_v2.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory_v2.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids_v2.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/unified_hierarchy.go rename vendor/github.com/opencontainers/runc/libcontainer/configs/{cgroup_windows.go => cgroup_unsupported.go} (89%) diff --git a/go.mod b/go.mod index d64fa40723a..a4c37068a91 100644 --- a/go.mod +++ b/go.mod @@ -97,7 +97,7 @@ require ( github.com/onsi/gomega v1.7.0 github.com/opencontainers/go-digest v1.0.0-rc1 github.com/opencontainers/image-spec v1.0.1 // indirect - github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830 + github.com/opencontainers/runc v1.0.0-rc9 github.com/opencontainers/runtime-spec v1.0.0 // indirect github.com/opencontainers/selinux v1.2.2 github.com/pborman/uuid v1.2.0 @@ -367,7 +367,7 @@ replace ( github.com/onsi/gomega => github.com/onsi/gomega v1.7.0 github.com/opencontainers/go-digest => github.com/opencontainers/go-digest v1.0.0-rc1 github.com/opencontainers/image-spec => github.com/opencontainers/image-spec v1.0.1 - github.com/opencontainers/runc => github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830 + github.com/opencontainers/runc => github.com/opencontainers/runc v1.0.0-rc9 github.com/opencontainers/runtime-spec => github.com/opencontainers/runtime-spec v1.0.0 github.com/opencontainers/selinux => github.com/opencontainers/selinux v1.2.2 github.com/pborman/uuid => github.com/pborman/uuid v1.2.0 diff --git a/go.sum b/go.sum index c54c328e471..6758f1d5211 100644 --- a/go.sum +++ b/go.sum @@ -345,8 +345,8 @@ github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2i github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830 h1:yvQ/2Pupw60ON8TYEIGGTAI77yZsWYkiOeHFZWkwlCk= -github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU4LguQVtc= +github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runtime-spec v1.0.0 h1:O6L965K88AilqnxeYPks/75HLpp4IG+FjeSCI3cVdRg= github.com/opencontainers/runtime-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.2.2 h1:Kx9J6eDG5/24A6DtUquGSpJQ+m2MUTahn4FtGEe8bFg= diff --git a/vendor/github.com/opencontainers/runc/libcontainer/README.md b/vendor/github.com/opencontainers/runc/libcontainer/README.md index 1d7fa04c082..a791ca2d249 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/README.md +++ b/vendor/github.com/opencontainers/runc/libcontainer/README.md @@ -261,6 +261,7 @@ process := &libcontainer.Process{ Stdin: os.Stdin, Stdout: os.Stdout, Stderr: os.Stderr, + Init: true, } err := container.Run(process) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go b/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go index 7fff0627fa1..debfc1e489e 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go @@ -6,6 +6,8 @@ import ( "fmt" "io/ioutil" "os" + + "github.com/opencontainers/runc/libcontainer/utils" ) // IsEnabled returns true if apparmor is enabled for the host. @@ -19,7 +21,7 @@ func IsEnabled() bool { return false } -func setprocattr(attr, value string) error { +func setProcAttr(attr, value string) error { // Under AppArmor you can only change your own attr, so use /proc/self/ // instead of /proc// like libapparmor does path := fmt.Sprintf("/proc/self/attr/%s", attr) @@ -30,6 +32,10 @@ func setprocattr(attr, value string) error { } defer f.Close() + if err := utils.EnsureProcHandle(f); err != nil { + return err + } + _, err = fmt.Fprintf(f, "%s", value) return err } @@ -37,7 +43,7 @@ func setprocattr(attr, value string) error { // changeOnExec reimplements aa_change_onexec from libapparmor in Go func changeOnExec(name string) error { value := "exec " + name - if err := setprocattr("exec", value); err != nil { + if err := setProcAttr("exec", value); err != nil { return fmt.Errorf("apparmor failed to apply profile: %s", err) } return nil diff --git a/vendor/github.com/opencontainers/runc/libcontainer/capabilities_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/capabilities_linux.go index 7c66f572580..9daef29e480 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/capabilities_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/capabilities_linux.go @@ -71,7 +71,11 @@ func newContainerCapList(capConfig *configs.Capabilities) (*containerCapabilitie } ambient = append(ambient, v) } - pid, err := capability.NewPid(0) + pid, err := capability.NewPid2(0) + if err != nil { + return nil, err + } + err = pid.Load() if err != nil { return nil, err } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/BUILD b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/BUILD index 8626e7a2360..9b113a196f9 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/BUILD +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/BUILD @@ -6,19 +6,25 @@ go_library( "apply_raw.go", "blkio.go", "cpu.go", + "cpu_v2.go", "cpuacct.go", "cpuset.go", + "cpuset_v2.go", "devices.go", "freezer.go", + "freezer_v2.go", "fs_unsupported.go", "hugetlb.go", + "io_v2.go", "kmem.go", "memory.go", + "memory_v2.go", "name.go", "net_cls.go", "net_prio.go", "perf_event.go", "pids.go", + "pids_v2.go", "utils.go", ], importmap = "k8s.io/kubernetes/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs", diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go index f672ba27377..512fd700104 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go @@ -18,7 +18,7 @@ import ( ) var ( - subsystems = subsystemSet{ + subsystemsLegacy = subsystemSet{ &CpusetGroup{}, &DevicesGroup{}, &MemoryGroup{}, @@ -33,6 +33,14 @@ var ( &FreezerGroup{}, &NameGroup{GroupName: "name=systemd", Join: true}, } + subsystemsUnified = subsystemSet{ + &CpusetGroupV2{}, + &FreezerGroupV2{}, + &CpuGroupV2{}, + &MemoryGroupV2{}, + &IOGroupV2{}, + &PidsGroupV2{}, + } HugePageSizes, _ = cgroups.GetHugePageSize() ) @@ -129,6 +137,13 @@ func isIgnorableError(rootless bool, err error) bool { return errno == unix.EROFS || errno == unix.EPERM || errno == unix.EACCES } +func (m *Manager) getSubsystems() subsystemSet { + if cgroups.IsCgroup2UnifiedMode() { + return subsystemsUnified + } + return subsystemsLegacy +} + func (m *Manager) Apply(pid int) (err error) { if m.Cgroups == nil { return nil @@ -158,7 +173,7 @@ func (m *Manager) Apply(pid int) (err error) { return cgroups.EnterPid(m.Paths, pid) } - for _, sys := range subsystems { + for _, sys := range m.getSubsystems() { // TODO: Apply should, ideally, be reentrant or be broken up into a separate // create and join phase so that the cgroup hierarchy for a container can be // created then join consists of writing the process pids to cgroup.procs @@ -214,7 +229,7 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) { defer m.mu.Unlock() stats := cgroups.NewStats() for name, path := range m.Paths { - sys, err := subsystems.Get(name) + sys, err := m.getSubsystems().Get(name) if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) { continue } @@ -226,14 +241,18 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) { } func (m *Manager) Set(container *configs.Config) error { + if container.Cgroups == nil { + return nil + } + // If Paths are set, then we are just joining cgroups paths // and there is no need to set any values. - if m.Cgroups.Paths != nil { + if m.Cgroups != nil && m.Cgroups.Paths != nil { return nil } paths := m.GetPaths() - for _, sys := range subsystems { + for _, sys := range m.getSubsystems() { path := paths[sys.Name()] if err := sys.Set(path, container.Cgroups); err != nil { if m.Rootless && sys.Name() == "devices" { @@ -262,11 +281,15 @@ func (m *Manager) Set(container *configs.Config) error { // Freeze toggles the container's freezer cgroup depending on the state // provided func (m *Manager) Freeze(state configs.FreezerState) error { + if m.Cgroups == nil { + return errors.New("cannot toggle freezer: cgroups not configured for container") + } + paths := m.GetPaths() dir := paths["freezer"] prevState := m.Cgroups.Resources.Freezer m.Cgroups.Resources.Freezer = state - freezer, err := subsystems.Get("freezer") + freezer, err := m.getSubsystems().Get("freezer") if err != nil { return err } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu_v2.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu_v2.go new file mode 100644 index 00000000000..245071ae504 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu_v2.go @@ -0,0 +1,92 @@ +// +build linux + +package fs + +import ( + "bufio" + "os" + "path/filepath" + "strconv" + + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/configs" +) + +type CpuGroupV2 struct { +} + +func (s *CpuGroupV2) Name() string { + return "cpu" +} + +func (s *CpuGroupV2) Apply(d *cgroupData) error { + // We always want to join the cpu group, to allow fair cpu scheduling + // on a container basis + path, err := d.path("cpu") + if err != nil && !cgroups.IsNotFound(err) { + return err + } + return s.ApplyDir(path, d.config, d.pid) +} + +func (s *CpuGroupV2) ApplyDir(path string, cgroup *configs.Cgroup, pid int) error { + // This might happen if we have no cpu cgroup mounted. + // Just do nothing and don't fail. + if path == "" { + return nil + } + if err := os.MkdirAll(path, 0755); err != nil { + return err + } + return cgroups.WriteCgroupProc(path, pid) +} + +func (s *CpuGroupV2) Set(path string, cgroup *configs.Cgroup) error { + if cgroup.Resources.CpuWeight != 0 { + if err := writeFile(path, "cpu.weight", strconv.FormatUint(cgroup.Resources.CpuWeight, 10)); err != nil { + return err + } + } + + if cgroup.Resources.CpuMax != "" { + if err := writeFile(path, "cpu.max", cgroup.Resources.CpuMax); err != nil { + return err + } + } + + return nil +} + +func (s *CpuGroupV2) Remove(d *cgroupData) error { + return removePath(d.path("cpu")) +} + +func (s *CpuGroupV2) GetStats(path string, stats *cgroups.Stats) error { + f, err := os.Open(filepath.Join(path, "cpu.stat")) + if err != nil { + if os.IsNotExist(err) { + return nil + } + return err + } + defer f.Close() + + sc := bufio.NewScanner(f) + for sc.Scan() { + t, v, err := getCgroupParamKeyValue(sc.Text()) + if err != nil { + return err + } + switch t { + case "usage_usec": + stats.CpuStats.CpuUsage.TotalUsage = v * 1000 + + case "user_usec": + stats.CpuStats.CpuUsage.UsageInUsermode = v * 1000 + + case "system_usec": + stats.CpuStats.CpuUsage.UsageInKernelmode = v * 1000 + } + } + return nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset_v2.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset_v2.go new file mode 100644 index 00000000000..fa88cfb7d6e --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset_v2.go @@ -0,0 +1,159 @@ +// +build linux + +package fs + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/configs" + libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils" +) + +type CpusetGroupV2 struct { +} + +func (s *CpusetGroupV2) Name() string { + return "cpuset" +} + +func (s *CpusetGroupV2) Apply(d *cgroupData) error { + dir, err := d.path("cpuset") + if err != nil && !cgroups.IsNotFound(err) { + return err + } + return s.ApplyDir(dir, d.config, d.pid) +} + +func (s *CpusetGroupV2) Set(path string, cgroup *configs.Cgroup) error { + if cgroup.Resources.CpusetCpus != "" { + if err := writeFile(path, "cpuset.cpus", cgroup.Resources.CpusetCpus); err != nil { + return err + } + } + if cgroup.Resources.CpusetMems != "" { + if err := writeFile(path, "cpuset.mems", cgroup.Resources.CpusetMems); err != nil { + return err + } + } + return nil +} + +func (s *CpusetGroupV2) Remove(d *cgroupData) error { + return removePath(d.path("cpuset")) +} + +func (s *CpusetGroupV2) GetStats(path string, stats *cgroups.Stats) error { + return nil +} + +func (s *CpusetGroupV2) ApplyDir(dir string, cgroup *configs.Cgroup, pid int) error { + // This might happen if we have no cpuset cgroup mounted. + // Just do nothing and don't fail. + if dir == "" { + return nil + } + mountInfo, err := ioutil.ReadFile("/proc/self/mountinfo") + if err != nil { + return err + } + root := filepath.Dir(cgroups.GetClosestMountpointAncestor(dir, string(mountInfo))) + // 'ensureParent' start with parent because we don't want to + // explicitly inherit from parent, it could conflict with + // 'cpuset.cpu_exclusive'. + if err := s.ensureParent(filepath.Dir(dir), root); err != nil { + return err + } + if err := os.MkdirAll(dir, 0755); err != nil { + return err + } + // We didn't inherit cpuset configs from parent, but we have + // to ensure cpuset configs are set before moving task into the + // cgroup. + // The logic is, if user specified cpuset configs, use these + // specified configs, otherwise, inherit from parent. This makes + // cpuset configs work correctly with 'cpuset.cpu_exclusive', and + // keep backward compatibility. + if err := s.ensureCpusAndMems(dir, cgroup); err != nil { + return err + } + + // because we are not using d.join we need to place the pid into the procs file + // unlike the other subsystems + return cgroups.WriteCgroupProc(dir, pid) +} + +func (s *CpusetGroupV2) getSubsystemSettings(parent string) (cpus []byte, mems []byte, err error) { + if cpus, err = ioutil.ReadFile(filepath.Join(parent, "cpuset.cpus.effective")); err != nil { + return + } + if mems, err = ioutil.ReadFile(filepath.Join(parent, "cpuset.mems.effective")); err != nil { + return + } + return cpus, mems, nil +} + +// ensureParent makes sure that the parent directory of current is created +// and populated with the proper cpus and mems files copied from +// it's parent. +func (s *CpusetGroupV2) ensureParent(current, root string) error { + parent := filepath.Dir(current) + if libcontainerUtils.CleanPath(parent) == root { + return nil + } + // Avoid infinite recursion. + if parent == current { + return fmt.Errorf("cpuset: cgroup parent path outside cgroup root") + } + if err := s.ensureParent(parent, root); err != nil { + return err + } + if err := os.MkdirAll(current, 0755); err != nil { + return err + } + return s.copyIfNeeded(current, parent) +} + +// copyIfNeeded copies the cpuset.cpus and cpuset.mems from the parent +// directory to the current directory if the file's contents are 0 +func (s *CpusetGroupV2) copyIfNeeded(current, parent string) error { + var ( + err error + currentCpus, currentMems []byte + parentCpus, parentMems []byte + ) + + if currentCpus, currentMems, err = s.getSubsystemSettings(current); err != nil { + return err + } + if parentCpus, parentMems, err = s.getSubsystemSettings(parent); err != nil { + return err + } + + if s.isEmpty(currentCpus) { + if err := writeFile(current, "cpuset.cpus", string(parentCpus)); err != nil { + return err + } + } + if s.isEmpty(currentMems) { + if err := writeFile(current, "cpuset.mems", string(parentMems)); err != nil { + return err + } + } + return nil +} + +func (s *CpusetGroupV2) isEmpty(b []byte) bool { + return len(bytes.Trim(b, "\n")) == 0 +} + +func (s *CpusetGroupV2) ensureCpusAndMems(path string, cgroup *configs.Cgroup) error { + if err := s.Set(path, cgroup); err != nil { + return err + } + return s.copyIfNeeded(path, filepath.Dir(path)) +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer_v2.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer_v2.go new file mode 100644 index 00000000000..186de9ab41f --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer_v2.go @@ -0,0 +1,74 @@ +// +build linux + +package fs + +import ( + "fmt" + "strings" + "time" + + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/configs" +) + +type FreezerGroupV2 struct { +} + +func (s *FreezerGroupV2) Name() string { + return "freezer" +} + +func (s *FreezerGroupV2) Apply(d *cgroupData) error { + _, err := d.join("freezer") + if err != nil && !cgroups.IsNotFound(err) { + return err + } + return nil +} + +func (s *FreezerGroupV2) Set(path string, cgroup *configs.Cgroup) error { + var desiredState string + filename := "cgroup.freeze" + if cgroup.Resources.Freezer == configs.Frozen { + desiredState = "1" + } else { + desiredState = "0" + } + + switch cgroup.Resources.Freezer { + case configs.Frozen, configs.Thawed: + for { + // In case this loop does not exit because it doesn't get the expected + // state, let's write again this state, hoping it's going to be properly + // set this time. Otherwise, this loop could run infinitely, waiting for + // a state change that would never happen. + if err := writeFile(path, filename, desiredState); err != nil { + return err + } + + state, err := readFile(path, filename) + if err != nil { + return err + } + if strings.TrimSpace(state) == desiredState { + break + } + + time.Sleep(1 * time.Millisecond) + } + case configs.Undefined: + return nil + default: + return fmt.Errorf("Invalid argument '%s' to freezer.state", string(cgroup.Resources.Freezer)) + } + + return nil +} + +func (s *FreezerGroupV2) Remove(d *cgroupData) error { + return removePath(d.path("freezer")) +} + +func (s *FreezerGroupV2) GetStats(path string, stats *cgroups.Stats) error { + return nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/io_v2.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/io_v2.go new file mode 100644 index 00000000000..84b1829451a --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/io_v2.go @@ -0,0 +1,191 @@ +// +build linux + +package fs + +import ( + "bufio" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/configs" +) + +type IOGroupV2 struct { +} + +func (s *IOGroupV2) Name() string { + return "blkio" +} + +func (s *IOGroupV2) Apply(d *cgroupData) error { + _, err := d.join("blkio") + if err != nil && !cgroups.IsNotFound(err) { + return err + } + return nil +} + +func (s *IOGroupV2) Set(path string, cgroup *configs.Cgroup) error { + cgroupsv2 := cgroups.IsCgroup2UnifiedMode() + + if cgroup.Resources.BlkioWeight != 0 { + filename := "blkio.weight" + if cgroupsv2 { + filename = "io.bfq.weight" + } + if err := writeFile(path, filename, strconv.FormatUint(uint64(cgroup.Resources.BlkioWeight), 10)); err != nil { + return err + } + } + + if cgroup.Resources.BlkioLeafWeight != 0 { + if err := writeFile(path, "blkio.leaf_weight", strconv.FormatUint(uint64(cgroup.Resources.BlkioLeafWeight), 10)); err != nil { + return err + } + } + for _, wd := range cgroup.Resources.BlkioWeightDevice { + if err := writeFile(path, "blkio.weight_device", wd.WeightString()); err != nil { + return err + } + if err := writeFile(path, "blkio.leaf_weight_device", wd.LeafWeightString()); err != nil { + return err + } + } + for _, td := range cgroup.Resources.BlkioThrottleReadBpsDevice { + if cgroupsv2 { + if err := writeFile(path, "io.max", td.StringName("rbps")); err != nil { + return err + } + } else { + if err := writeFile(path, "blkio.throttle.read_bps_device", td.String()); err != nil { + return err + } + } + } + for _, td := range cgroup.Resources.BlkioThrottleWriteBpsDevice { + if cgroupsv2 { + if err := writeFile(path, "io.max", td.StringName("wbps")); err != nil { + return err + } + } else { + if err := writeFile(path, "blkio.throttle.write_bps_device", td.String()); err != nil { + return err + } + } + } + for _, td := range cgroup.Resources.BlkioThrottleReadIOPSDevice { + if cgroupsv2 { + if err := writeFile(path, "io.max", td.StringName("riops")); err != nil { + return err + } + } else { + if err := writeFile(path, "blkio.throttle.read_iops_device", td.String()); err != nil { + return err + } + } + } + for _, td := range cgroup.Resources.BlkioThrottleWriteIOPSDevice { + if cgroupsv2 { + if err := writeFile(path, "io.max", td.StringName("wiops")); err != nil { + return err + } + } else { + if err := writeFile(path, "blkio.throttle.write_iops_device", td.String()); err != nil { + return err + } + } + } + + return nil +} + +func (s *IOGroupV2) Remove(d *cgroupData) error { + return removePath(d.path("blkio")) +} + +func readCgroup2MapFile(path string, name string) (map[string][]string, error) { + ret := map[string][]string{} + p := filepath.Join("/sys/fs/cgroup", path, name) + f, err := os.Open(p) + if err != nil { + if os.IsNotExist(err) { + return ret, nil + } + return nil, err + } + defer f.Close() + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + parts := strings.Fields(line) + if len(parts) < 2 { + continue + } + ret[parts[0]] = parts[1:] + } + if err := scanner.Err(); err != nil { + return nil, err + } + return ret, nil +} + +func (s *IOGroupV2) getCgroupV2Stats(path string, stats *cgroups.Stats) error { + // more details on the io.stat file format: https://www.kernel.org/doc/Documentation/cgroup-v2.txt + var ioServiceBytesRecursive []cgroups.BlkioStatEntry + values, err := readCgroup2MapFile(path, "io.stat") + if err != nil { + return err + } + for k, v := range values { + d := strings.Split(k, ":") + if len(d) != 2 { + continue + } + minor, err := strconv.ParseUint(d[0], 10, 0) + if err != nil { + return err + } + major, err := strconv.ParseUint(d[1], 10, 0) + if err != nil { + return err + } + + for _, item := range v { + d := strings.Split(item, "=") + if len(d) != 2 { + continue + } + op := d[0] + + // Accommodate the cgroup v1 naming + switch op { + case "rbytes": + op = "read" + case "wbytes": + op = "write" + } + + value, err := strconv.ParseUint(d[1], 10, 0) + if err != nil { + return err + } + + entry := cgroups.BlkioStatEntry{ + Op: op, + Major: major, + Minor: minor, + Value: value, + } + ioServiceBytesRecursive = append(ioServiceBytesRecursive, entry) + } + } + stats.BlkioStats = cgroups.BlkioStats{IoServiceBytesRecursive: ioServiceBytesRecursive} + return nil +} + +func (s *IOGroupV2) GetStats(path string, stats *cgroups.Stats) error { + return s.getCgroupV2Stats(path, stats) +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory_v2.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory_v2.go new file mode 100644 index 00000000000..2ad997bcc29 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory_v2.go @@ -0,0 +1,164 @@ +// +build linux + +package fs + +import ( + "bufio" + "fmt" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/configs" +) + +type MemoryGroupV2 struct { +} + +func (s *MemoryGroupV2) Name() string { + return "memory" +} + +func (s *MemoryGroupV2) Apply(d *cgroupData) (err error) { + path, err := d.path("memory") + if err != nil && !cgroups.IsNotFound(err) { + return err + } else if path == "" { + return nil + } + if memoryAssigned(d.config) { + if _, err := os.Stat(path); os.IsNotExist(err) { + if err := os.MkdirAll(path, 0755); err != nil { + return err + } + // Only enable kernel memory accouting when this cgroup + // is created by libcontainer, otherwise we might get + // error when people use `cgroupsPath` to join an existed + // cgroup whose kernel memory is not initialized. + if err := EnableKernelMemoryAccounting(path); err != nil { + return err + } + } + } + defer func() { + if err != nil { + os.RemoveAll(path) + } + }() + + // We need to join memory cgroup after set memory limits, because + // kmem.limit_in_bytes can only be set when the cgroup is empty. + _, err = d.join("memory") + if err != nil && !cgroups.IsNotFound(err) { + return err + } + return nil +} + +func setMemoryAndSwapCgroups(path string, cgroup *configs.Cgroup) error { + if cgroup.Resources.MemorySwap != 0 { + if err := writeFile(path, "memory.swap.max", strconv.FormatInt(cgroup.Resources.MemorySwap, 10)); err != nil { + return err + } + } + if cgroup.Resources.Memory != 0 { + if err := writeFile(path, "memory.max", strconv.FormatInt(cgroup.Resources.Memory, 10)); err != nil { + return err + } + } + return nil +} + +func (s *MemoryGroupV2) Set(path string, cgroup *configs.Cgroup) error { + + if err := setMemoryAndSwapCgroups(path, cgroup); err != nil { + return err + } + + if cgroup.Resources.KernelMemory != 0 { + if err := setKernelMemory(path, cgroup.Resources.KernelMemory); err != nil { + return err + } + } + + if cgroup.Resources.MemoryReservation != 0 { + if err := writeFile(path, "memory.high", strconv.FormatInt(cgroup.Resources.MemoryReservation, 10)); err != nil { + return err + } + } + + return nil +} + +func (s *MemoryGroupV2) Remove(d *cgroupData) error { + return removePath(d.path("memory")) +} + +func (s *MemoryGroupV2) GetStats(path string, stats *cgroups.Stats) error { + // Set stats from memory.stat. + statsFile, err := os.Open(filepath.Join(path, "memory.stat")) + if err != nil { + if os.IsNotExist(err) { + return nil + } + return err + } + defer statsFile.Close() + + sc := bufio.NewScanner(statsFile) + for sc.Scan() { + t, v, err := getCgroupParamKeyValue(sc.Text()) + if err != nil { + return fmt.Errorf("failed to parse memory.stat (%q) - %v", sc.Text(), err) + } + stats.MemoryStats.Stats[t] = v + } + stats.MemoryStats.Cache = stats.MemoryStats.Stats["cache"] + + memoryUsage, err := getMemoryDataV2(path, "") + if err != nil { + return err + } + stats.MemoryStats.Usage = memoryUsage + swapUsage, err := getMemoryDataV2(path, "swap") + if err != nil { + return err + } + stats.MemoryStats.SwapUsage = swapUsage + + stats.MemoryStats.UseHierarchy = true + return nil +} + +func getMemoryDataV2(path, name string) (cgroups.MemoryData, error) { + memoryData := cgroups.MemoryData{} + + moduleName := "memory" + if name != "" { + moduleName = strings.Join([]string{"memory", name}, ".") + } + usage := strings.Join([]string{moduleName, "current"}, ".") + limit := strings.Join([]string{moduleName, "max"}, ".") + + value, err := getCgroupParamUint(path, usage) + if err != nil { + if moduleName != "memory" && os.IsNotExist(err) { + return cgroups.MemoryData{}, nil + } + return cgroups.MemoryData{}, fmt.Errorf("failed to parse %s - %v", usage, err) + } + memoryData.Usage = value + + value, err = getCgroupParamUint(path, limit) + if err != nil { + if moduleName != "memory" && os.IsNotExist(err) { + return cgroups.MemoryData{}, nil + } + return cgroups.MemoryData{}, fmt.Errorf("failed to parse %s - %v", limit, err) + } + memoryData.Limit = value + + return memoryData, nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids_v2.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids_v2.go new file mode 100644 index 00000000000..3413a2a0d18 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids_v2.go @@ -0,0 +1,107 @@ +// +build linux + +package fs + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/configs" + "golang.org/x/sys/unix" +) + +type PidsGroupV2 struct { +} + +func (s *PidsGroupV2) Name() string { + return "pids" +} + +func (s *PidsGroupV2) Apply(d *cgroupData) error { + _, err := d.join("pids") + if err != nil && !cgroups.IsNotFound(err) { + return err + } + return nil +} + +func (s *PidsGroupV2) Set(path string, cgroup *configs.Cgroup) error { + if cgroup.Resources.PidsLimit != 0 { + // "max" is the fallback value. + limit := "max" + + if cgroup.Resources.PidsLimit > 0 { + limit = strconv.FormatInt(cgroup.Resources.PidsLimit, 10) + } + + if err := writeFile(path, "pids.max", limit); err != nil { + return err + } + } + + return nil +} + +func (s *PidsGroupV2) Remove(d *cgroupData) error { + return removePath(d.path("pids")) +} + +func isNOTSUP(err error) bool { + switch err := err.(type) { + case *os.PathError: + return err.Err == unix.ENOTSUP + default: + return false + } +} + +func (s *PidsGroupV2) GetStats(path string, stats *cgroups.Stats) error { + current, err := getCgroupParamUint(path, "pids.current") + if os.IsNotExist(err) { + // if the controller is not enabled, let's read the list + // PIDs (or threads if cgroup.threads is enabled) + contents, err := ioutil.ReadFile(filepath.Join(path, "cgroup.procs")) + if err != nil && isNOTSUP(err) { + contents, err = ioutil.ReadFile(filepath.Join(path, "cgroup.threads")) + } + if err != nil { + return err + } + pids := make(map[string]string) + for _, i := range strings.Split(string(contents), "\n") { + if i != "" { + pids[i] = i + } + } + stats.PidsStats.Current = uint64(len(pids)) + stats.PidsStats.Limit = 0 + return nil + + } + if err != nil { + return fmt.Errorf("failed to parse pids.current - %s", err) + } + + maxString, err := getCgroupParamString(path, "pids.max") + if err != nil { + return fmt.Errorf("failed to parse pids.max - %s", err) + } + + // Default if pids.max == "max" is 0 -- which represents "no limit". + var max uint64 + if maxString != "max" { + max, err = parseUint(maxString, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse pids.max - unable to parse %q as a uint from Cgroup file %q", maxString, filepath.Join(path, "pids.max")) + } + } + + stats.PidsStats.Current = current + stats.PidsStats.Limit = max + return nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/utils.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/utils.go index 5ff0a161504..30922777f53 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/utils.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/utils.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io/ioutil" + "math" "path/filepath" "strconv" "strings" @@ -59,8 +60,12 @@ func getCgroupParamUint(cgroupPath, cgroupFile string) (uint64, error) { if err != nil { return 0, err } + trimmed := strings.TrimSpace(string(contents)) + if trimmed == "max" { + return math.MaxUint64, nil + } - res, err := parseUint(strings.TrimSpace(string(contents)), 10, 64) + res, err := parseUint(trimmed, 10, 64) if err != nil { return res, fmt.Errorf("unable to parse %q as a uint from Cgroup file %q", string(contents), fileName) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/BUILD b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/BUILD index 60c142d474f..3e021bbcca5 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/BUILD +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/BUILD @@ -5,6 +5,7 @@ go_library( srcs = [ "apply_nosystemd.go", "apply_systemd.go", + "unified_hierarchy.go", ], importmap = "k8s.io/kubernetes/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd", importpath = "github.com/opencontainers/runc/libcontainer/cgroups/systemd", @@ -28,7 +29,6 @@ go_library( ], "@io_bazel_rules_go//go/platform:linux": [ "//vendor/github.com/coreos/go-systemd/dbus:go_default_library", - "//vendor/github.com/coreos/go-systemd/util:go_default_library", "//vendor/github.com/godbus/dbus:go_default_library", "//vendor/github.com/opencontainers/runc/libcontainer/cgroups:go_default_library", "//vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs:go_default_library", diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go index 3bf723bf964..f274a49a3c1 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go @@ -14,7 +14,6 @@ import ( "time" systemdDbus "github.com/coreos/go-systemd/dbus" - systemdUtil "github.com/coreos/go-systemd/util" "github.com/godbus/dbus" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fs" @@ -22,7 +21,7 @@ import ( "github.com/sirupsen/logrus" ) -type Manager struct { +type LegacyManager struct { mu sync.Mutex Cgroups *configs.Cgroup Paths map[string]string @@ -50,7 +49,7 @@ func (s subsystemSet) Get(name string) (subsystem, error) { return nil, errSubsystemDoesNotExist } -var subsystems = subsystemSet{ +var legacySubsystems = subsystemSet{ &fs.CpusetGroup{}, &fs.DevicesGroup{}, &fs.MemoryGroup{}, @@ -72,11 +71,8 @@ const ( ) var ( - connLock sync.Mutex - theConn *systemdDbus.Conn - hasStartTransientUnit bool - hasStartTransientSliceUnit bool - hasDelegateSlice bool + connLock sync.Mutex + theConn *systemdDbus.Conn ) func newProp(name string, units interface{}) systemdDbus.Property { @@ -86,8 +82,23 @@ func newProp(name string, units interface{}) systemdDbus.Property { } } +// NOTE: This function comes from package github.com/coreos/go-systemd/util +// It was borrowed here to avoid a dependency on cgo. +// +// IsRunningSystemd checks whether the host was booted with systemd as its init +// system. This functions similarly to systemd's `sd_booted(3)`: internally, it +// checks whether /run/systemd/system/ exists and is a directory. +// http://www.freedesktop.org/software/systemd/man/sd_booted.html +func isRunningSystemd() bool { + fi, err := os.Lstat("/run/systemd/system") + if err != nil { + return false + } + return fi.IsDir() +} + func UseSystemd() bool { - if !systemdUtil.IsRunningSystemd() { + if !isRunningSystemd() { return false } @@ -100,82 +111,31 @@ func UseSystemd() bool { if err != nil { return false } - - // Assume we have StartTransientUnit - hasStartTransientUnit = true - - // But if we get UnknownMethod error we don't - if _, err := theConn.StartTransientUnit("test.scope", "invalid", nil, nil); err != nil { - if dbusError, ok := err.(dbus.Error); ok { - if dbusError.Name == "org.freedesktop.DBus.Error.UnknownMethod" { - hasStartTransientUnit = false - return hasStartTransientUnit - } - } - } - - // Assume we have the ability to start a transient unit as a slice - // This was broken until systemd v229, but has been back-ported on RHEL environments >= 219 - // For details, see: https://bugzilla.redhat.com/show_bug.cgi?id=1370299 - hasStartTransientSliceUnit = true - - // To ensure simple clean-up, we create a slice off the root with no hierarchy - slice := fmt.Sprintf("libcontainer_%d_systemd_test_default.slice", os.Getpid()) - if _, err := theConn.StartTransientUnit(slice, "replace", nil, nil); err != nil { - if _, ok := err.(dbus.Error); ok { - hasStartTransientSliceUnit = false - } - } - - for i := 0; i <= testSliceWait; i++ { - if _, err := theConn.StopUnit(slice, "replace", nil); err != nil { - if dbusError, ok := err.(dbus.Error); ok { - if strings.Contains(dbusError.Name, "org.freedesktop.systemd1.NoSuchUnit") { - hasStartTransientSliceUnit = false - break - } - } - } else { - break - } - time.Sleep(time.Millisecond) - } - - // Not critical because of the stop unit logic above. - theConn.StopUnit(slice, "replace", nil) - - // Assume StartTransientUnit on a slice allows Delegate - hasDelegateSlice = true - dlSlice := newProp("Delegate", true) - if _, err := theConn.StartTransientUnit(slice, "replace", []systemdDbus.Property{dlSlice}, nil); err != nil { - if dbusError, ok := err.(dbus.Error); ok { - // Starting with systemd v237, Delegate is not even a property of slices anymore, - // so the D-Bus call fails with "InvalidArgs" error. - if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") || strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.InvalidArgs") { - hasDelegateSlice = false - } - } - } - - // Not critical because of the stop unit logic above. - theConn.StopUnit(slice, "replace", nil) } - return hasStartTransientUnit + return true } func NewSystemdCgroupsManager() (func(config *configs.Cgroup, paths map[string]string) cgroups.Manager, error) { - if !systemdUtil.IsRunningSystemd() { + if !isRunningSystemd() { return nil, fmt.Errorf("systemd not running on this host, can't use systemd as a cgroups.Manager") } + if cgroups.IsCgroup2UnifiedMode() { + return func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { + return &UnifiedManager{ + Cgroups: config, + Paths: paths, + } + }, nil + } return func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { - return &Manager{ + return &LegacyManager{ Cgroups: config, Paths: paths, } }, nil } -func (m *Manager) Apply(pid int) error { +func (m *LegacyManager) Apply(pid int) error { var ( c = m.Cgroups unitName = getUnitName(c) @@ -208,10 +168,6 @@ func (m *Manager) Apply(pid int) error { // if we create a slice, the parent is defined via a Wants= if strings.HasSuffix(unitName, ".slice") { - // This was broken until systemd v229, but has been back-ported on RHEL environments >= 219 - if !hasStartTransientSliceUnit { - return fmt.Errorf("systemd version does not support ability to start a slice as transient unit") - } properties = append(properties, systemdDbus.PropWants(slice)) } else { // otherwise, we use Slice= @@ -224,12 +180,7 @@ func (m *Manager) Apply(pid int) error { } // Check if we can delegate. This is only supported on systemd versions 218 and above. - if strings.HasSuffix(unitName, ".slice") { - if hasDelegateSlice { - // systemd 237 and above no longer allows delegation on a slice - properties = append(properties, newProp("Delegate", true)) - } - } else { + if !strings.HasSuffix(unitName, ".slice") { // Assume scopes always support delegation. properties = append(properties, newProp("Delegate", true)) } @@ -310,7 +261,7 @@ func (m *Manager) Apply(pid int) error { } paths := make(map[string]string) - for _, s := range subsystems { + for _, s := range legacySubsystems { subsystemPath, err := getSubsystemPath(m.Cgroups, s.Name()) if err != nil { // Don't fail if a cgroup hierarchy was not found, just skip this subsystem @@ -325,7 +276,7 @@ func (m *Manager) Apply(pid int) error { return nil } -func (m *Manager) Destroy() error { +func (m *LegacyManager) Destroy() error { if m.Cgroups.Paths != nil { return nil } @@ -339,7 +290,7 @@ func (m *Manager) Destroy() error { return nil } -func (m *Manager) GetPaths() map[string]string { +func (m *LegacyManager) GetPaths() map[string]string { m.mu.Lock() paths := m.Paths m.mu.Unlock() @@ -351,6 +302,7 @@ func join(c *configs.Cgroup, subsystem string, pid int) (string, error) { if err != nil { return "", err } + if err := os.MkdirAll(path, 0755); err != nil { return "", err } @@ -361,7 +313,7 @@ func join(c *configs.Cgroup, subsystem string, pid int) (string, error) { } func joinCgroups(c *configs.Cgroup, pid int) error { - for _, sys := range subsystems { + for _, sys := range legacySubsystems { name := sys.Name() switch name { case "name=systemd": @@ -456,14 +408,14 @@ func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) { return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil } -func (m *Manager) Freeze(state configs.FreezerState) error { +func (m *LegacyManager) Freeze(state configs.FreezerState) error { path, err := getSubsystemPath(m.Cgroups, "freezer") if err != nil { return err } prevState := m.Cgroups.Resources.Freezer m.Cgroups.Resources.Freezer = state - freezer, err := subsystems.Get("freezer") + freezer, err := legacySubsystems.Get("freezer") if err != nil { return err } @@ -475,7 +427,7 @@ func (m *Manager) Freeze(state configs.FreezerState) error { return nil } -func (m *Manager) GetPids() ([]int, error) { +func (m *LegacyManager) GetPids() ([]int, error) { path, err := getSubsystemPath(m.Cgroups, "devices") if err != nil { return nil, err @@ -483,7 +435,7 @@ func (m *Manager) GetPids() ([]int, error) { return cgroups.GetPids(path) } -func (m *Manager) GetAllPids() ([]int, error) { +func (m *LegacyManager) GetAllPids() ([]int, error) { path, err := getSubsystemPath(m.Cgroups, "devices") if err != nil { return nil, err @@ -491,12 +443,12 @@ func (m *Manager) GetAllPids() ([]int, error) { return cgroups.GetAllPids(path) } -func (m *Manager) GetStats() (*cgroups.Stats, error) { +func (m *LegacyManager) GetStats() (*cgroups.Stats, error) { m.mu.Lock() defer m.mu.Unlock() stats := cgroups.NewStats() for name, path := range m.Paths { - sys, err := subsystems.Get(name) + sys, err := legacySubsystems.Get(name) if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) { continue } @@ -508,13 +460,13 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) { return stats, nil } -func (m *Manager) Set(container *configs.Config) error { +func (m *LegacyManager) Set(container *configs.Config) error { // If Paths are set, then we are just joining cgroups paths // and there is no need to set any values. if m.Cgroups.Paths != nil { return nil } - for _, sys := range subsystems { + for _, sys := range legacySubsystems { // Get the subsystem path, but don't error out for not found cgroups. path, err := getSubsystemPath(container.Cgroups, sys.Name()) if err != nil && !cgroups.IsNotFound(err) { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/unified_hierarchy.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/unified_hierarchy.go new file mode 100644 index 00000000000..d394e3a5a8f --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/unified_hierarchy.go @@ -0,0 +1,329 @@ +// +build linux,!static_build + +package systemd + +import ( + "fmt" + "io/ioutil" + "math" + "os" + "path/filepath" + "strings" + "sync" + "time" + + systemdDbus "github.com/coreos/go-systemd/dbus" + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/cgroups/fs" + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/sirupsen/logrus" +) + +type UnifiedManager struct { + mu sync.Mutex + Cgroups *configs.Cgroup + Paths map[string]string +} + +var unifiedSubsystems = subsystemSet{ + &fs.CpusetGroupV2{}, + &fs.FreezerGroupV2{}, + &fs.CpuGroupV2{}, + &fs.MemoryGroupV2{}, + &fs.IOGroupV2{}, + &fs.PidsGroupV2{}, +} + +func (m *UnifiedManager) Apply(pid int) error { + var ( + c = m.Cgroups + unitName = getUnitName(c) + slice = "system.slice" + properties []systemdDbus.Property + ) + + if c.Paths != nil { + paths := make(map[string]string) + for name, path := range c.Paths { + _, err := getSubsystemPath(m.Cgroups, name) + if err != nil { + // Don't fail if a cgroup hierarchy was not found, just skip this subsystem + if cgroups.IsNotFound(err) { + continue + } + return err + } + paths[name] = path + } + m.Paths = paths + return cgroups.EnterPid(m.Paths, pid) + } + + if c.Parent != "" { + slice = c.Parent + } + + properties = append(properties, systemdDbus.PropDescription("libcontainer container "+c.Name)) + + // if we create a slice, the parent is defined via a Wants= + if strings.HasSuffix(unitName, ".slice") { + properties = append(properties, systemdDbus.PropWants(slice)) + } else { + // otherwise, we use Slice= + properties = append(properties, systemdDbus.PropSlice(slice)) + } + + // only add pid if its valid, -1 is used w/ general slice creation. + if pid != -1 { + properties = append(properties, newProp("PIDs", []uint32{uint32(pid)})) + } + + // Check if we can delegate. This is only supported on systemd versions 218 and above. + if !strings.HasSuffix(unitName, ".slice") { + // Assume scopes always support delegation. + properties = append(properties, newProp("Delegate", true)) + } + + // Always enable accounting, this gets us the same behaviour as the fs implementation, + // plus the kernel has some problems with joining the memory cgroup at a later time. + properties = append(properties, + newProp("MemoryAccounting", true), + newProp("CPUAccounting", true), + newProp("BlockIOAccounting", true)) + + // Assume DefaultDependencies= will always work (the check for it was previously broken.) + properties = append(properties, + newProp("DefaultDependencies", false)) + + if c.Resources.Memory != 0 { + properties = append(properties, + newProp("MemoryLimit", uint64(c.Resources.Memory))) + } + + if c.Resources.CpuShares != 0 { + properties = append(properties, + newProp("CPUShares", c.Resources.CpuShares)) + } + + // cpu.cfs_quota_us and cpu.cfs_period_us are controlled by systemd. + if c.Resources.CpuQuota != 0 && c.Resources.CpuPeriod != 0 { + // corresponds to USEC_INFINITY in systemd + // if USEC_INFINITY is provided, CPUQuota is left unbound by systemd + // always setting a property value ensures we can apply a quota and remove it later + cpuQuotaPerSecUSec := uint64(math.MaxUint64) + if c.Resources.CpuQuota > 0 { + // systemd converts CPUQuotaPerSecUSec (microseconds per CPU second) to CPUQuota + // (integer percentage of CPU) internally. This means that if a fractional percent of + // CPU is indicated by Resources.CpuQuota, we need to round up to the nearest + // 10ms (1% of a second) such that child cgroups can set the cpu.cfs_quota_us they expect. + cpuQuotaPerSecUSec = uint64(c.Resources.CpuQuota*1000000) / c.Resources.CpuPeriod + if cpuQuotaPerSecUSec%10000 != 0 { + cpuQuotaPerSecUSec = ((cpuQuotaPerSecUSec / 10000) + 1) * 10000 + } + } + properties = append(properties, + newProp("CPUQuotaPerSecUSec", cpuQuotaPerSecUSec)) + } + + if c.Resources.BlkioWeight != 0 { + properties = append(properties, + newProp("BlockIOWeight", uint64(c.Resources.BlkioWeight))) + } + + if c.Resources.PidsLimit > 0 { + properties = append(properties, + newProp("TasksAccounting", true), + newProp("TasksMax", uint64(c.Resources.PidsLimit))) + } + + // We have to set kernel memory here, as we can't change it once + // processes have been attached to the cgroup. + if c.Resources.KernelMemory != 0 { + if err := setKernelMemory(c); err != nil { + return err + } + } + + statusChan := make(chan string, 1) + if _, err := theConn.StartTransientUnit(unitName, "replace", properties, statusChan); err == nil { + select { + case <-statusChan: + case <-time.After(time.Second): + logrus.Warnf("Timed out while waiting for StartTransientUnit(%s) completion signal from dbus. Continuing...", unitName) + } + } else if !isUnitExists(err) { + return err + } + + if err := joinCgroupsV2(c, pid); err != nil { + return err + } + + paths := make(map[string]string) + for _, s := range unifiedSubsystems { + subsystemPath, err := getSubsystemPath(m.Cgroups, s.Name()) + if err != nil { + // Don't fail if a cgroup hierarchy was not found, just skip this subsystem + if cgroups.IsNotFound(err) { + continue + } + return err + } + paths[s.Name()] = subsystemPath + } + m.Paths = paths + return nil +} + +func (m *UnifiedManager) Destroy() error { + if m.Cgroups.Paths != nil { + return nil + } + m.mu.Lock() + defer m.mu.Unlock() + theConn.StopUnit(getUnitName(m.Cgroups), "replace", nil) + if err := cgroups.RemovePaths(m.Paths); err != nil { + return err + } + m.Paths = make(map[string]string) + return nil +} + +func (m *UnifiedManager) GetPaths() map[string]string { + m.mu.Lock() + paths := m.Paths + m.mu.Unlock() + return paths +} + +func createCgroupsv2Path(path string) (Err error) { + content, err := ioutil.ReadFile("/sys/fs/cgroup/cgroup.controllers") + if err != nil { + return err + } + if !filepath.HasPrefix(path, "/sys/fs/cgroup") { + return fmt.Errorf("invalid cgroup path %s", path) + } + + res := "" + for i, c := range strings.Split(strings.TrimSpace(string(content)), " ") { + if i == 0 { + res = fmt.Sprintf("+%s", c) + } else { + res = res + fmt.Sprintf(" +%s", c) + } + } + resByte := []byte(res) + + current := "/sys/fs" + elements := strings.Split(path, "/") + for i, e := range elements[3:] { + current = filepath.Join(current, e) + if i > 0 { + if err := os.Mkdir(current, 0755); err != nil { + if !os.IsExist(err) { + return err + } + } else { + // If the directory was created, be sure it is not left around on errors. + defer func() { + if Err != nil { + os.Remove(current) + } + }() + } + } + if i < len(elements[3:])-1 { + if err := ioutil.WriteFile(filepath.Join(current, "cgroup.subtree_control"), resByte, 0755); err != nil { + return err + } + } + } + return nil +} + +func joinCgroupsV2(c *configs.Cgroup, pid int) error { + path, err := getSubsystemPath(c, "memory") + if err != nil { + return err + } + return createCgroupsv2Path(path) +} + +func (m *UnifiedManager) Freeze(state configs.FreezerState) error { + path, err := getSubsystemPath(m.Cgroups, "freezer") + if err != nil { + return err + } + prevState := m.Cgroups.Resources.Freezer + m.Cgroups.Resources.Freezer = state + freezer, err := unifiedSubsystems.Get("freezer") + if err != nil { + return err + } + err = freezer.Set(path, m.Cgroups) + if err != nil { + m.Cgroups.Resources.Freezer = prevState + return err + } + return nil +} + +func (m *UnifiedManager) GetPids() ([]int, error) { + path, err := getSubsystemPath(m.Cgroups, "devices") + if err != nil { + return nil, err + } + return cgroups.GetPids(path) +} + +func (m *UnifiedManager) GetAllPids() ([]int, error) { + path, err := getSubsystemPath(m.Cgroups, "devices") + if err != nil { + return nil, err + } + return cgroups.GetAllPids(path) +} + +func (m *UnifiedManager) GetStats() (*cgroups.Stats, error) { + m.mu.Lock() + defer m.mu.Unlock() + stats := cgroups.NewStats() + for name, path := range m.Paths { + sys, err := unifiedSubsystems.Get(name) + if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) { + continue + } + if err := sys.GetStats(path, stats); err != nil { + return nil, err + } + } + + return stats, nil +} + +func (m *UnifiedManager) Set(container *configs.Config) error { + // If Paths are set, then we are just joining cgroups paths + // and there is no need to set any values. + if m.Cgroups.Paths != nil { + return nil + } + for _, sys := range unifiedSubsystems { + // Get the subsystem path, but don't error out for not found cgroups. + path, err := getSubsystemPath(container.Cgroups, sys.Name()) + if err != nil && !cgroups.IsNotFound(err) { + return err + } + + if err := sys.Set(path, container.Cgroups); err != nil { + return err + } + } + + if m.Paths["cpu"] != "" { + if err := fs.CheckCpushares(m.Paths["cpu"], container.Cgroups.Resources.CpuShares); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go index ec79ae76723..60790f83b4e 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go @@ -11,6 +11,8 @@ import ( "path/filepath" "strconv" "strings" + "sync" + "syscall" "time" units "github.com/docker/go-units" @@ -22,6 +24,11 @@ const ( CgroupProcesses = "cgroup.procs" ) +var ( + isUnifiedOnce sync.Once + isUnified bool +) + // HugePageSizeUnitList is a list of the units used by the linux kernel when // naming the HugePage control files. // https://www.kernel.org/doc/Documentation/cgroup-v1/hugetlb.txt @@ -29,6 +36,18 @@ const ( // depends on https://github.com/docker/go-units/commit/a09cd47f892041a4fac473133d181f5aea6fa393 var HugePageSizeUnitList = []string{"B", "KB", "MB", "GB", "TB", "PB"} +// IsCgroup2UnifiedMode returns whether we are running in cgroup v2 unified mode. +func IsCgroup2UnifiedMode() bool { + isUnifiedOnce.Do(func() { + var st syscall.Statfs_t + if err := syscall.Statfs("/sys/fs/cgroup", &st); err != nil { + panic("cannot statfs cgroup root") + } + isUnified = st.Type == unix.CGROUP2_SUPER_MAGIC + }) + return isUnified +} + // https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt func FindCgroupMountpoint(cgroupPath, subsystem string) (string, error) { mnt, _, err := FindCgroupMountpointAndRoot(cgroupPath, subsystem) @@ -49,6 +68,10 @@ func FindCgroupMountpointAndRoot(cgroupPath, subsystem string) (string, string, } defer f.Close() + if IsCgroup2UnifiedMode() { + subsystem = "" + } + return findCgroupMountpointAndRootFromReader(f, cgroupPath, subsystem) } @@ -57,12 +80,12 @@ func findCgroupMountpointAndRootFromReader(reader io.Reader, cgroupPath, subsyst for scanner.Scan() { txt := scanner.Text() fields := strings.Fields(txt) - if len(fields) < 5 { + if len(fields) < 9 { continue } if strings.HasPrefix(fields[4], cgroupPath) { for _, opt := range strings.Split(fields[len(fields)-1], ",") { - if opt == subsystem { + if (subsystem == "" && fields[9] == "cgroup2") || opt == subsystem { return fields[4], fields[3], nil } } @@ -76,6 +99,19 @@ func findCgroupMountpointAndRootFromReader(reader io.Reader, cgroupPath, subsyst } func isSubsystemAvailable(subsystem string) bool { + if IsCgroup2UnifiedMode() { + controllers, err := GetAllSubsystems() + if err != nil { + return false + } + for _, c := range controllers { + if c == subsystem { + return true + } + } + return false + } + cgroups, err := ParseCgroupFile("/proc/self/cgroup") if err != nil { return false @@ -120,7 +156,7 @@ func FindCgroupMountpointDir() (string, error) { return "", fmt.Errorf("Found no fields post '-' in %q", text) } - if postSeparatorFields[0] == "cgroup" { + if postSeparatorFields[0] == "cgroup" || postSeparatorFields[0] == "cgroup2" { // Check that the mount is properly formatted. if numPostFields < 3 { return "", fmt.Errorf("Error found less than 3 fields post '-' in %q", text) @@ -193,6 +229,19 @@ func getCgroupMountsHelper(ss map[string]bool, mi io.Reader, all bool) ([]Mount, // GetCgroupMounts returns the mounts for the cgroup subsystems. // all indicates whether to return just the first instance or all the mounts. func GetCgroupMounts(all bool) ([]Mount, error) { + if IsCgroup2UnifiedMode() { + availableControllers, err := GetAllSubsystems() + if err != nil { + return nil, err + } + m := Mount{ + Mountpoint: "/sys/fs/cgroup", + Root: "/sys/fs/cgroup", + Subsystems: availableControllers, + } + return []Mount{m}, nil + } + f, err := os.Open("/proc/self/mountinfo") if err != nil { return nil, err @@ -356,6 +405,9 @@ func parseCgroupFromReader(r io.Reader) (map[string]string, error) { } func getControllerPath(subsystem string, cgroups map[string]string) (string, error) { + if IsCgroup2UnifiedMode() { + return "/", nil + } if p, ok := cgroups[subsystem]; ok { return p, nil diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/BUILD b/vendor/github.com/opencontainers/runc/libcontainer/configs/BUILD index 82b8b3cbe8d..44338e3ab19 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/BUILD +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/BUILD @@ -5,7 +5,7 @@ go_library( srcs = [ "blkio_device.go", "cgroup_linux.go", - "cgroup_windows.go", + "cgroup_unsupported.go", "config.go", "config_linux.go", "device.go", diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/blkio_device.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/blkio_device.go index e0f3ca16533..fa195bf90f8 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/blkio_device.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/blkio_device.go @@ -59,3 +59,8 @@ func NewThrottleDevice(major, minor int64, rate uint64) *ThrottleDevice { func (td *ThrottleDevice) String() string { return fmt.Sprintf("%d:%d %d", td.Major, td.Minor, td.Rate) } + +// StringName formats the struct to be writable to the cgroup specific file +func (td *ThrottleDevice) StringName(name string) string { + return fmt.Sprintf("%d:%d %s=%d", td.Major, td.Minor, name, td.Rate) +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go index e15a662f522..58ed19c9e78 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go @@ -119,4 +119,12 @@ type Resources struct { // Set class identifier for container's network packets NetClsClassid uint32 `json:"net_cls_classid_u"` + + // Used on cgroups v2: + + // CpuWeight sets a proportional bandwidth limit. + CpuWeight uint64 `json:"cpu_weight"` + + // CpuMax sets she maximum bandwidth limit (format: max period). + CpuMax string `json:"cpu_max"` } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_windows.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go similarity index 89% rename from vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_windows.go rename to vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go index d74847b0db8..c0c23d70004 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_windows.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go @@ -1,3 +1,5 @@ +// +build !linux + package configs // TODO Windows: This can ultimately be entirely factored out on Windows as diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go index 7728522fef6..24989e9f534 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go @@ -44,6 +44,7 @@ const ( Trap Allow Trace + Log ) // Operator is a comparison operator to be used when matching syscall arguments in Seccomp diff --git a/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go index d6c4ebdaa10..6ff4d96a5f5 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go @@ -19,7 +19,7 @@ import ( "syscall" // only for SysProcAttr and Signal "time" - "github.com/cyphar/filepath-securejoin" + securejoin "github.com/cyphar/filepath-securejoin" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/intelrdt" @@ -1176,7 +1176,7 @@ func (c *linuxContainer) makeCriuRestoreMountpoints(m *configs.Mount) error { if err != nil { return err } - if err := checkMountDestination(c.config.Rootfs, dest); err != nil { + if err := checkProcMount(c.config.Rootfs, dest, ""); err != nil { return err } m.Destination = dest @@ -1814,7 +1814,14 @@ func (c *linuxContainer) isPaused() (bool, error) { // A container doesn't have a freezer cgroup return false, nil } - data, err := ioutil.ReadFile(filepath.Join(fcg, "freezer.state")) + pausedState := "FROZEN" + filename := "freezer.state" + if cgroups.IsCgroup2UnifiedMode() { + filename = "cgroup.freeze" + pausedState = "1" + } + + data, err := ioutil.ReadFile(filepath.Join(fcg, filename)) if err != nil { // If freezer cgroup is not mounted, the container would just be not paused. if os.IsNotExist(err) { @@ -1822,7 +1829,7 @@ func (c *linuxContainer) isPaused() (bool, error) { } return false, newSystemErrorWithCause(err, "checking if container is paused") } - return bytes.Equal(bytes.TrimSpace(data), []byte("FROZEN")), nil + return bytes.Equal(bytes.TrimSpace(data), []byte(pausedState)), nil } func (c *linuxContainer) currentState() (*State, error) { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go index f13b226e444..10888b499be 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go @@ -13,7 +13,7 @@ import ( "strings" "time" - "github.com/cyphar/filepath-securejoin" + securejoin "github.com/cyphar/filepath-securejoin" "github.com/mrunalp/fileutils" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" @@ -197,7 +197,7 @@ func prepareBindMount(m *configs.Mount, rootfs string) error { if dest, err = securejoin.SecureJoin(rootfs, m.Destination); err != nil { return err } - if err := checkMountDestination(rootfs, dest); err != nil { + if err := checkProcMount(rootfs, dest, m.Source); err != nil { return err } // update the mount with the correct dest after symlinks are resolved. @@ -209,6 +209,80 @@ func prepareBindMount(m *configs.Mount, rootfs string) error { return nil } +func mountCgroupV1(m *configs.Mount, rootfs, mountLabel string, enableCgroupns bool) error { + binds, err := getCgroupMounts(m) + if err != nil { + return err + } + var merged []string + for _, b := range binds { + ss := filepath.Base(b.Destination) + if strings.Contains(ss, ",") { + merged = append(merged, ss) + } + } + tmpfs := &configs.Mount{ + Source: "tmpfs", + Device: "tmpfs", + Destination: m.Destination, + Flags: defaultMountFlags, + Data: "mode=755", + PropagationFlags: m.PropagationFlags, + } + if err := mountToRootfs(tmpfs, rootfs, mountLabel, enableCgroupns); err != nil { + return err + } + for _, b := range binds { + if enableCgroupns { + subsystemPath := filepath.Join(rootfs, b.Destination) + if err := os.MkdirAll(subsystemPath, 0755); err != nil { + return err + } + flags := defaultMountFlags + if m.Flags&unix.MS_RDONLY != 0 { + flags = flags | unix.MS_RDONLY + } + cgroupmount := &configs.Mount{ + Source: "cgroup", + Device: "cgroup", + Destination: subsystemPath, + Flags: flags, + Data: filepath.Base(subsystemPath), + } + if err := mountNewCgroup(cgroupmount); err != nil { + return err + } + } else { + if err := mountToRootfs(b, rootfs, mountLabel, enableCgroupns); err != nil { + return err + } + } + } + for _, mc := range merged { + for _, ss := range strings.Split(mc, ",") { + // symlink(2) is very dumb, it will just shove the path into + // the link and doesn't do any checks or relative path + // conversion. Also, don't error out if the cgroup already exists. + if err := os.Symlink(mc, filepath.Join(rootfs, m.Destination, ss)); err != nil && !os.IsExist(err) { + return err + } + } + } + return nil +} + +func mountCgroupV2(m *configs.Mount, rootfs, mountLabel string, enableCgroupns bool) error { + cgroupPath, err := securejoin.SecureJoin(rootfs, m.Destination) + if err != nil { + return err + } + if err := os.MkdirAll(cgroupPath, 0755); err != nil { + return err + } + + return unix.Mount(m.Source, cgroupPath, "cgroup2", uintptr(m.Flags), m.Data) +} + func mountToRootfs(m *configs.Mount, rootfs, mountLabel string, enableCgroupns bool) error { var ( dest = m.Destination @@ -309,62 +383,14 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string, enableCgroupns b } } case "cgroup": - binds, err := getCgroupMounts(m) - if err != nil { - return err - } - var merged []string - for _, b := range binds { - ss := filepath.Base(b.Destination) - if strings.Contains(ss, ",") { - merged = append(merged, ss) + if cgroups.IsCgroup2UnifiedMode() { + if err := mountCgroupV2(m, rootfs, mountLabel, enableCgroupns); err != nil { + return err } - } - tmpfs := &configs.Mount{ - Source: "tmpfs", - Device: "tmpfs", - Destination: m.Destination, - Flags: defaultMountFlags, - Data: "mode=755", - PropagationFlags: m.PropagationFlags, - } - if err := mountToRootfs(tmpfs, rootfs, mountLabel, enableCgroupns); err != nil { - return err - } - for _, b := range binds { - if enableCgroupns { - subsystemPath := filepath.Join(rootfs, b.Destination) - if err := os.MkdirAll(subsystemPath, 0755); err != nil { - return err - } - flags := defaultMountFlags - if m.Flags&unix.MS_RDONLY != 0 { - flags = flags | unix.MS_RDONLY - } - cgroupmount := &configs.Mount{ - Source: "cgroup", - Device: "cgroup", - Destination: subsystemPath, - Flags: flags, - Data: filepath.Base(subsystemPath), - } - if err := mountNewCgroup(cgroupmount); err != nil { - return err - } - } else { - if err := mountToRootfs(b, rootfs, mountLabel, enableCgroupns); err != nil { - return err - } - } - } - for _, mc := range merged { - for _, ss := range strings.Split(mc, ",") { - // symlink(2) is very dumb, it will just shove the path into - // the link and doesn't do any checks or relative path - // conversion. Also, don't error out if the cgroup already exists. - if err := os.Symlink(mc, filepath.Join(rootfs, m.Destination, ss)); err != nil && !os.IsExist(err) { - return err - } + } else { + + if err := mountCgroupV1(m, rootfs, mountLabel, enableCgroupns); err != nil { + return err } } if m.Flags&unix.MS_RDONLY != 0 { @@ -388,7 +414,7 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string, enableCgroupns b if dest, err = securejoin.SecureJoin(rootfs, m.Destination); err != nil { return err } - if err := checkMountDestination(rootfs, dest); err != nil { + if err := checkProcMount(rootfs, dest, m.Source); err != nil { return err } // update the mount with the correct dest after symlinks are resolved. @@ -435,12 +461,12 @@ func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) { return binds, nil } -// checkMountDestination checks to ensure that the mount destination is not over the top of /proc. +// checkProcMount checks to ensure that the mount destination is not over the top of /proc. // dest is required to be an abs path and have any symlinks resolved before calling this function. -func checkMountDestination(rootfs, dest string) error { - invalidDestinations := []string{ - "/proc", - } +// +// if source is nil, don't stat the filesystem. This is used for restore of a checkpoint. +func checkProcMount(rootfs, dest, source string) error { + const procPath = "/proc" // White list, it should be sub directories of invalid destinations validDestinations := []string{ // These entries can be bind mounted by files emulated by fuse, @@ -463,16 +489,40 @@ func checkMountDestination(rootfs, dest string) error { return nil } } - for _, invalid := range invalidDestinations { - path, err := filepath.Rel(filepath.Join(rootfs, invalid), dest) + path, err := filepath.Rel(filepath.Join(rootfs, procPath), dest) + if err != nil { + return err + } + // pass if the mount path is located outside of /proc + if strings.HasPrefix(path, "..") { + return nil + } + if path == "." { + // an empty source is pasted on restore + if source == "" { + return nil + } + // only allow a mount on-top of proc if it's source is "proc" + isproc, err := isProc(source) if err != nil { return err } - if path != "." && !strings.HasPrefix(path, "..") { - return fmt.Errorf("%q cannot be mounted because it is located inside %q", dest, invalid) + // pass if the mount is happening on top of /proc and the source of + // the mount is a proc filesystem + if isproc { + return nil } + return fmt.Errorf("%q cannot be mounted because it is not of type proc", dest) } - return nil + return fmt.Errorf("%q cannot be mounted because it is inside /proc", dest) +} + +func isProc(path string) (bool, error) { + var s unix.Statfs_t + if err := unix.Statfs(path, &s); err != nil { + return false, err + } + return s.Type == unix.PROC_SUPER_MAGIC, nil } func setupDevSymlinks(rootfs string) error { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go index ded5a6bbc8b..c3212279875 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go @@ -22,6 +22,7 @@ var actions = map[string]configs.Action{ "SCMP_ACT_TRAP": configs.Trap, "SCMP_ACT_ALLOW": configs.Allow, "SCMP_ACT_TRACE": configs.Trace, + "SCMP_ACT_LOG": configs.Log, } var archs = map[string]string{ diff --git a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go index d99f3fe640c..1b7a07118fe 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go @@ -19,6 +19,7 @@ var ( actTrap = libseccomp.ActTrap actKill = libseccomp.ActKill actTrace = libseccomp.ActTrace.SetReturnCode(int16(unix.EPERM)) + actLog = libseccomp.ActLog actErrno = libseccomp.ActErrno.SetReturnCode(int16(unix.EPERM)) ) @@ -112,6 +113,8 @@ func getAction(act configs.Action) (libseccomp.ScmpAction, error) { return actAllow, nil case configs.Trace: return actTrace, nil + case configs.Log: + return actLog, nil default: return libseccomp.ActInvalid, fmt.Errorf("invalid action, cannot use in rule") } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_64.go b/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_64.go index 11c3faafbf0..e05e30adc3b 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_64.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_64.go @@ -1,5 +1,5 @@ // +build linux -// +build arm64 amd64 mips mipsle mips64 mips64le ppc ppc64 ppc64le s390x +// +build arm64 amd64 mips mipsle mips64 mips64le ppc ppc64 ppc64le riscv64 s390x package system diff --git a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go index c96088988a6..1576f2d4ab6 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go @@ -3,33 +3,57 @@ package utils import ( - "io/ioutil" + "fmt" "os" "strconv" "golang.org/x/sys/unix" ) +// EnsureProcHandle returns whether or not the given file handle is on procfs. +func EnsureProcHandle(fh *os.File) error { + var buf unix.Statfs_t + if err := unix.Fstatfs(int(fh.Fd()), &buf); err != nil { + return fmt.Errorf("ensure %s is on procfs: %v", fh.Name(), err) + } + if buf.Type != unix.PROC_SUPER_MAGIC { + return fmt.Errorf("%s is not on procfs", fh.Name()) + } + return nil +} + +// CloseExecFrom applies O_CLOEXEC to all file descriptors currently open for +// the process (except for those below the given fd value). func CloseExecFrom(minFd int) error { - fdList, err := ioutil.ReadDir("/proc/self/fd") + fdDir, err := os.Open("/proc/self/fd") if err != nil { return err } - for _, fi := range fdList { - fd, err := strconv.Atoi(fi.Name()) + defer fdDir.Close() + + if err := EnsureProcHandle(fdDir); err != nil { + return err + } + + fdList, err := fdDir.Readdirnames(-1) + if err != nil { + return err + } + for _, fdStr := range fdList { + fd, err := strconv.Atoi(fdStr) + // Ignore non-numeric file names. if err != nil { - // ignore non-numeric file names continue } - + // Ignore descriptors lower than our specified minimum. if fd < minFd { - // ignore descriptors lower than our specified minimum continue } - - // intentionally ignore errors from unix.CloseOnExec + // Intentionally ignore errors from unix.CloseOnExec -- the cases where + // this might fail are basically file descriptors that have already + // been closed (including and especially the one that was created when + // ioutil.ReadDir did the "opendir" syscall). unix.CloseOnExec(fd) - // the cases where this might fail are basically file descriptors that have already been closed (including and especially the one that was created when ioutil.ReadDir did the "opendir" syscall) } return nil } diff --git a/vendor/modules.txt b/vendor/modules.txt index a45fb5fd73d..714b9cd3323 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -679,7 +679,7 @@ github.com/opencontainers/go-digest # github.com/opencontainers/image-spec v1.0.1 => github.com/opencontainers/image-spec v1.0.1 github.com/opencontainers/image-spec/specs-go github.com/opencontainers/image-spec/specs-go/v1 -# github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830 => github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830 +# github.com/opencontainers/runc v1.0.0-rc9 => github.com/opencontainers/runc v1.0.0-rc9 github.com/opencontainers/runc/libcontainer github.com/opencontainers/runc/libcontainer/apparmor github.com/opencontainers/runc/libcontainer/cgroups From a2117bd49d56218f035bb5f72dd34c60740ed158 Mon Sep 17 00:00:00 2001 From: Odin Ugedal Date: Sat, 5 Oct 2019 13:50:59 +0200 Subject: [PATCH 2/7] Bump dependency github.com/mrunalp/fileutils@7d4729fb36185a7c1719923406c9d40e54fb93c7 --- go.mod | 4 ++-- go.sum | 4 ++-- vendor/github.com/mrunalp/fileutils/fileutils.go | 9 +++------ vendor/modules.txt | 2 +- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index a4c37068a91..c6e6dddc721 100644 --- a/go.mod +++ b/go.mod @@ -90,7 +90,7 @@ require ( github.com/mistifyio/go-zfs v2.1.1+incompatible // indirect github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb // indirect github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect - github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058 // indirect + github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618 // indirect github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d github.com/mvdan/xurls v1.1.0 github.com/onsi/ginkgo v1.10.1 @@ -356,7 +356,7 @@ replace ( github.com/modern-go/reflect2 => github.com/modern-go/reflect2 v1.0.1 github.com/mohae/deepcopy => github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb github.com/morikuni/aec => github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c - github.com/mrunalp/fileutils => github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058 + github.com/mrunalp/fileutils => github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618 github.com/munnerz/goautoneg => github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d github.com/mvdan/xurls => github.com/mvdan/xurls v1.1.0 github.com/mwitkow/go-conntrack => github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223 diff --git a/go.sum b/go.sum index 6758f1d5211..23801cd4774 100644 --- a/go.sum +++ b/go.sum @@ -326,8 +326,8 @@ github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb h1:e+l77LJOEqXTIQih github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE= github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058 h1:A4y2IxU1GcIzlcmUlQ6yr/mrvYZhqo+HakAPwgwaa6s= -github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0= +github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618 h1:7InQ7/zrOh6SlFjaXFubv0xX0HsuC9qJsdqm7bNQpYM= +github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d h1:7PxY7LVfSZm7PEeBTyK1rj1gABdCO2mbri6GKO1cMDs= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mvdan/xurls v1.1.0 h1:OpuDelGQ1R1ueQ6sSryzi6P+1RtBpfQHM8fJwlE45ww= diff --git a/vendor/github.com/mrunalp/fileutils/fileutils.go b/vendor/github.com/mrunalp/fileutils/fileutils.go index b60cb909c5c..5a9818a24ec 100644 --- a/vendor/github.com/mrunalp/fileutils/fileutils.go +++ b/vendor/github.com/mrunalp/fileutils/fileutils.go @@ -139,19 +139,16 @@ func CopyDirectory(source string, dest string) error { return nil } - // Copy the file. - if err := CopyFile(path, filepath.Join(dest, relPath)); err != nil { - return err - } - - return nil + return CopyFile(path, filepath.Join(dest, relPath)) }) } +// Gives a number indicating the device driver to be used to access the passed device func major(device uint64) uint64 { return (device >> 8) & 0xfff } +// Gives a number that serves as a flag to the device driver for the passed device func minor(device uint64) uint64 { return (device & 0xff) | ((device >> 12) & 0xfff00) } diff --git a/vendor/modules.txt b/vendor/modules.txt index 714b9cd3323..7119affa81c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -625,7 +625,7 @@ github.com/modern-go/reflect2 github.com/mohae/deepcopy # github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c => github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c github.com/morikuni/aec -# github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058 => github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058 +# github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618 => github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618 github.com/mrunalp/fileutils # github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d => github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d github.com/munnerz/goautoneg From 47906acc96ccc23356ebc57bd50b5cc6ccd3f7a1 Mon Sep 17 00:00:00 2001 From: Odin Ugedal Date: Sat, 5 Oct 2019 13:56:58 +0200 Subject: [PATCH 3/7] Bump dependency opencontainers/selinux@v1.3.1-0.20190929122143-5215b1806f52 --- go.mod | 4 +-- go.sum | 4 +-- .../selinux/go-selinux/label/label_selinux.go | 18 ++++++---- .../selinux/go-selinux/selinux_linux.go | 33 +++++++++++++++++++ .../selinux/go-selinux/selinux_stub.go | 13 ++++++++ vendor/modules.txt | 2 +- 6 files changed, 62 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index c6e6dddc721..9aafa530f3e 100644 --- a/go.mod +++ b/go.mod @@ -99,7 +99,7 @@ require ( github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/runc v1.0.0-rc9 github.com/opencontainers/runtime-spec v1.0.0 // indirect - github.com/opencontainers/selinux v1.2.2 + github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52 github.com/pborman/uuid v1.2.0 github.com/pkg/errors v0.8.0 github.com/pmezard/go-difflib v1.0.0 @@ -369,7 +369,7 @@ replace ( github.com/opencontainers/image-spec => github.com/opencontainers/image-spec v1.0.1 github.com/opencontainers/runc => github.com/opencontainers/runc v1.0.0-rc9 github.com/opencontainers/runtime-spec => github.com/opencontainers/runtime-spec v1.0.0 - github.com/opencontainers/selinux => github.com/opencontainers/selinux v1.2.2 + github.com/opencontainers/selinux => github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52 github.com/pborman/uuid => github.com/pborman/uuid v1.2.0 github.com/pelletier/go-toml => github.com/pelletier/go-toml v1.2.0 github.com/peterbourgon/diskv => github.com/peterbourgon/diskv v2.0.1+incompatible diff --git a/go.sum b/go.sum index 23801cd4774..63543639628 100644 --- a/go.sum +++ b/go.sum @@ -349,8 +349,8 @@ github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runtime-spec v1.0.0 h1:O6L965K88AilqnxeYPks/75HLpp4IG+FjeSCI3cVdRg= github.com/opencontainers/runtime-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.2.2 h1:Kx9J6eDG5/24A6DtUquGSpJQ+m2MUTahn4FtGEe8bFg= -github.com/opencontainers/selinux v1.2.2/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs= +github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52 h1:B8hYj3NxHmjsC3T+tnlZ1UhInqUgnyF1zlGPmzNg2Qk= +github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go index 1eb9a6bf252..2730fcf4a9a 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go @@ -13,11 +13,12 @@ import ( // Valid Label Options var validOptions = map[string]bool{ - "disable": true, - "type": true, - "user": true, - "role": true, - "level": true, + "disable": true, + "type": true, + "filetype": true, + "user": true, + "role": true, + "level": true, } var ErrIncompatibleLabel = fmt.Errorf("Bad SELinux option z and Z can not be used together") @@ -51,13 +52,16 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) { return "", mountLabel, nil } if i := strings.Index(opt, ":"); i == -1 { - return "", "", fmt.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type' followed by ':' and a value", opt) + return "", "", fmt.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type, filetype' followed by ':' and a value", opt) } con := strings.SplitN(opt, ":", 2) if !validOptions[con[0]] { - return "", "", fmt.Errorf("Bad label option %q, valid options 'disable, user, role, level, type'", con[0]) + return "", "", fmt.Errorf("Bad label option %q, valid options 'disable, user, role, level, type, filetype'", con[0]) } + if con[0] == "filetype" { + mcon["type"] = con[1] + } pcon[con[0]] = con[1] if con[0] == "level" || con[0] == "user" { mcon[con[0]] = con[1] diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go index d7786c33c19..8cdf1b054ac 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go @@ -18,6 +18,8 @@ import ( "strings" "sync" "syscall" + + "golang.org/x/sys/unix" ) const ( @@ -252,6 +254,12 @@ func getSELinuxPolicyRoot() string { return filepath.Join(selinuxDir, readConfig(selinuxTypeTag)) } +func isProcHandle(fh *os.File) (bool, error) { + var buf unix.Statfs_t + err := unix.Fstatfs(int(fh.Fd()), &buf) + return buf.Type == unix.PROC_SUPER_MAGIC, err +} + func readCon(fpath string) (string, error) { if fpath == "" { return "", ErrEmptyPath @@ -263,6 +271,12 @@ func readCon(fpath string) (string, error) { } defer in.Close() + if ok, err := isProcHandle(in); err != nil { + return "", err + } else if !ok { + return "", fmt.Errorf("%s not on procfs", fpath) + } + var retval string if _, err := fmt.Fscanf(in, "%s", &retval); err != nil { return "", err @@ -345,6 +359,12 @@ func writeCon(fpath string, val string) error { } defer out.Close() + if ok, err := isProcHandle(out); err != nil { + return err + } else if !ok { + return fmt.Errorf("%s not on procfs", fpath) + } + if val != "" { _, err = out.Write([]byte(val)) } else { @@ -392,6 +412,14 @@ func SetExecLabel(label string) error { return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), label) } +/* +SetTaskLabel sets the SELinux label for the current thread, or an error. +This requires the dyntransition permission. +*/ +func SetTaskLabel(label string) error { + return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/current", syscall.Gettid()), label) +} + // SetSocketLabel takes a process label and tells the kernel to assign the // label to the next socket that gets created func SetSocketLabel(label string) error { @@ -403,6 +431,11 @@ func SocketLabel() (string, error) { return readCon(fmt.Sprintf("/proc/self/task/%d/attr/sockcreate", syscall.Gettid())) } +// PeerLabel retrieves the label of the client on the other side of a socket +func PeerLabel(fd uintptr) (string, error) { + return unix.GetsockoptString(int(fd), syscall.SOL_SOCKET, syscall.SO_PEERSEC) +} + // SetKeyLabel takes a process label and tells the kernel to assign the // label to the next kernel keyring that gets created func SetKeyLabel(label string) error { diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go index 79b005d194c..0c2e1cd38e7 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go @@ -96,6 +96,14 @@ func SetExecLabel(label string) error { return nil } +/* +SetTaskLabel sets the SELinux label for the current thread, or an error. +This requires the dyntransition permission. +*/ +func SetTaskLabel(label string) error { + return nil +} + /* SetSocketLabel sets the SELinux label that the kernel will use for any programs that are executed by the current process thread, or an error. @@ -109,6 +117,11 @@ func SocketLabel() (string, error) { return "", nil } +// PeerLabel retrieves the label of the client on the other side of a socket +func PeerLabel(fd uintptr) (string, error) { + return "", nil +} + // SetKeyLabel takes a process label and tells the kernel to assign the // label to the next kernel keyring that gets created func SetKeyLabel(label string) error { diff --git a/vendor/modules.txt b/vendor/modules.txt index 7119affa81c..3b9935c7ef5 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -698,7 +698,7 @@ github.com/opencontainers/runc/libcontainer/user github.com/opencontainers/runc/libcontainer/utils # github.com/opencontainers/runtime-spec v1.0.0 => github.com/opencontainers/runtime-spec v1.0.0 github.com/opencontainers/runtime-spec/specs-go -# github.com/opencontainers/selinux v1.2.2 => github.com/opencontainers/selinux v1.2.2 +# github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52 => github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52 github.com/opencontainers/selinux/go-selinux github.com/opencontainers/selinux/go-selinux/label # github.com/pborman/uuid v1.2.0 => github.com/pborman/uuid v1.2.0 From 6e079bfb7db81cbd1e1b983b56662435f113cd27 Mon Sep 17 00:00:00 2001 From: Odin Ugedal Date: Sat, 5 Oct 2019 14:14:29 +0200 Subject: [PATCH 4/7] Bump dependency syndtr/gocapability@v0.0.0-20180916011248-d98352740cb2 --- go.mod | 4 +- go.sum | 4 +- .../gocapability/capability/capability.go | 71 +++++++++++++++++-- .../capability/capability_linux.go | 16 ++--- .../gocapability/capability/syscall_linux.go | 2 +- vendor/modules.txt | 2 +- 6 files changed, 76 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index 9aafa530f3e..3695e268cdd 100644 --- a/go.mod +++ b/go.mod @@ -118,7 +118,7 @@ require ( github.com/spf13/viper v1.3.2 github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc github.com/stretchr/testify v1.3.0 - github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4 // indirect + github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 // indirect github.com/thecodeteam/goscaleio v0.1.0 github.com/urfave/negroni v1.0.0 // indirect github.com/vishvananda/netlink v0.0.0-20171020171820-b2de5d10e38e @@ -402,7 +402,7 @@ replace ( github.com/storageos/go-api => github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc github.com/stretchr/objx => github.com/stretchr/objx v0.2.0 github.com/stretchr/testify => github.com/stretchr/testify v1.3.0 - github.com/syndtr/gocapability => github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4 + github.com/syndtr/gocapability => github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 github.com/thecodeteam/goscaleio => github.com/thecodeteam/goscaleio v0.1.0 github.com/tmc/grpc-websocket-proxy => github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 github.com/ugorji/go/codec => github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 diff --git a/go.sum b/go.sum index 63543639628..5e364773712 100644 --- a/go.sum +++ b/go.sum @@ -413,8 +413,8 @@ github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4 h1:w58e6FAOMd+rUgOfhaBb+ZVOQIOfUkpv5AAQVmf6hsI= -github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/thecodeteam/goscaleio v0.1.0 h1:SB5tO98lawC+UK8ds/U2jyfOCH7GTcFztcF5x9gbut4= github.com/thecodeteam/goscaleio v0.1.0/go.mod h1:68sdkZAsK8bvEwBlbQnlLS+xU+hvLYM/iQ8KXej1AwM= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 h1:ndzgwNDnKIqyCvHTXaCqh9KlOWKvBry6nuXMJmonVsE= diff --git a/vendor/github.com/syndtr/gocapability/capability/capability.go b/vendor/github.com/syndtr/gocapability/capability/capability.go index c07c55794de..61a90775e59 100644 --- a/vendor/github.com/syndtr/gocapability/capability/capability.go +++ b/vendor/github.com/syndtr/gocapability/capability/capability.go @@ -60,13 +60,74 @@ type Capabilities interface { Apply(kind CapType) error } -// NewPid create new initialized Capabilities object for given pid when it -// is nonzero, or for the current pid if pid is 0 +// NewPid initializes a new Capabilities object for given pid when +// it is nonzero, or for the current process if pid is 0. +// +// Deprecated: Replace with NewPid2. For example, replace: +// +// c, err := NewPid(0) +// if err != nil { +// return err +// } +// +// with: +// +// c, err := NewPid2(0) +// if err != nil { +// return err +// } +// err = c.Load() +// if err != nil { +// return err +// } func NewPid(pid int) (Capabilities, error) { + c, err := newPid(pid) + if err != nil { + return c, err + } + err = c.Load() + return c, err +} + +// NewPid2 initializes a new Capabilities object for given pid when +// it is nonzero, or for the current process if pid is 0. This +// does not load the process's current capabilities; to do that you +// must call Load explicitly. +func NewPid2(pid int) (Capabilities, error) { return newPid(pid) } -// NewFile create new initialized Capabilities object for given named file. -func NewFile(name string) (Capabilities, error) { - return newFile(name) +// NewFile initializes a new Capabilities object for given file path. +// +// Deprecated: Replace with NewFile2. For example, replace: +// +// c, err := NewFile(path) +// if err != nil { +// return err +// } +// +// with: +// +// c, err := NewFile2(path) +// if err != nil { +// return err +// } +// err = c.Load() +// if err != nil { +// return err +// } +func NewFile(path string) (Capabilities, error) { + c, err := newFile(path) + if err != nil { + return c, err + } + err = c.Load() + return c, err +} + +// NewFile2 creates a new initialized Capabilities object for given +// file path. This does not load the process's current capabilities; +// to do that you must call Load explicitly. +func NewFile2(path string) (Capabilities, error) { + return newFile(path) } diff --git a/vendor/github.com/syndtr/gocapability/capability/capability_linux.go b/vendor/github.com/syndtr/gocapability/capability/capability_linux.go index 6d2135ac585..1567dc81040 100644 --- a/vendor/github.com/syndtr/gocapability/capability/capability_linux.go +++ b/vendor/github.com/syndtr/gocapability/capability/capability_linux.go @@ -103,21 +103,17 @@ func newPid(pid int) (c Capabilities, err error) { case linuxCapVer1: p := new(capsV1) p.hdr.version = capVers - p.hdr.pid = pid + p.hdr.pid = int32(pid) c = p case linuxCapVer2, linuxCapVer3: p := new(capsV3) p.hdr.version = capVers - p.hdr.pid = pid + p.hdr.pid = int32(pid) c = p default: err = errUnknownVers return } - err = c.Load() - if err != nil { - c = nil - } return } @@ -428,11 +424,11 @@ func (c *capsV3) Load() (err error) { } if strings.HasPrefix(line, "CapB") { fmt.Sscanf(line[4:], "nd: %08x%08x", &c.bounds[1], &c.bounds[0]) - break + continue } if strings.HasPrefix(line, "CapA") { fmt.Sscanf(line[4:], "mb: %08x%08x", &c.ambient[1], &c.ambient[0]) - break + continue } } f.Close() @@ -492,10 +488,6 @@ func (c *capsV3) Apply(kind CapType) (err error) { func newFile(path string) (c Capabilities, err error) { c = &capsFile{path: path} - err = c.Load() - if err != nil { - c = nil - } return } diff --git a/vendor/github.com/syndtr/gocapability/capability/syscall_linux.go b/vendor/github.com/syndtr/gocapability/capability/syscall_linux.go index eb7170083a3..3d2bf6927f3 100644 --- a/vendor/github.com/syndtr/gocapability/capability/syscall_linux.go +++ b/vendor/github.com/syndtr/gocapability/capability/syscall_linux.go @@ -13,7 +13,7 @@ import ( type capHeader struct { version uint32 - pid int + pid int32 } type capData struct { diff --git a/vendor/modules.txt b/vendor/modules.txt index 3b9935c7ef5..8b243be25cf 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -769,7 +769,7 @@ github.com/stretchr/objx github.com/stretchr/testify/assert github.com/stretchr/testify/mock github.com/stretchr/testify/require -# github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4 => github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4 +# github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 => github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 github.com/syndtr/gocapability/capability # github.com/thecodeteam/goscaleio v0.1.0 => github.com/thecodeteam/goscaleio v0.1.0 github.com/thecodeteam/goscaleio From b9cfb193211a85eed34532464ff4e71756d6ae77 Mon Sep 17 00:00:00 2001 From: Odin Ugedal Date: Sat, 5 Oct 2019 14:22:35 +0200 Subject: [PATCH 5/7] Rename cgroupsystemd.Manager to LegacyManager --- pkg/kubelet/cm/cgroup_manager_linux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kubelet/cm/cgroup_manager_linux.go b/pkg/kubelet/cm/cgroup_manager_linux.go index a653e67c790..2e3968f4feb 100644 --- a/pkg/kubelet/cm/cgroup_manager_linux.go +++ b/pkg/kubelet/cm/cgroup_manager_linux.go @@ -153,7 +153,7 @@ func (l *libcontainerAdapter) newManager(cgroups *libcontainerconfigs.Cgroup, pa if !cgroupsystemd.UseSystemd() { panic("systemd cgroup manager not available") } - return &cgroupsystemd.Manager{ + return &cgroupsystemd.LegacyManager{ Cgroups: cgroups, Paths: paths, }, nil From c07408380de0e430fd94df1b1d03b672b1801b6e Mon Sep 17 00:00:00 2001 From: Odin Ugedal Date: Sat, 5 Oct 2019 14:28:46 +0200 Subject: [PATCH 6/7] Bump dependency github.com/coreos/go-systemd@v19 (95778df) --- go.mod | 4 +- go.sum | 4 +- .../src/k8s.io/apiextensions-apiserver/go.sum | 4 +- staging/src/k8s.io/apiserver/go.mod | 2 +- staging/src/k8s.io/apiserver/go.sum | 4 +- staging/src/k8s.io/kube-aggregator/go.sum | 4 +- .../src/k8s.io/legacy-cloud-providers/go.sum | 2 +- staging/src/k8s.io/sample-apiserver/go.sum | 4 +- .../github.com/coreos/go-systemd/dbus/dbus.go | 6 +- .../coreos/go-systemd/dbus/methods.go | 8 +- .../coreos/go-systemd/dbus/subscription.go | 2 +- .../coreos/go-systemd/journal/journal.go | 149 +++++++++++------- vendor/modules.txt | 2 +- 13 files changed, 120 insertions(+), 75 deletions(-) diff --git a/go.mod b/go.mod index 3695e268cdd..55e5a47e524 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,7 @@ require ( github.com/containernetworking/cni v0.7.1 github.com/coredns/corefile-migration v1.0.2 github.com/coreos/etcd v3.3.15+incompatible - github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 + github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea github.com/coreos/rkt v1.30.0 // indirect github.com/cpuguy83/go-md2man v1.0.10 @@ -231,7 +231,7 @@ replace ( github.com/coreos/go-etcd => github.com/coreos/go-etcd v2.0.0+incompatible github.com/coreos/go-oidc => github.com/coreos/go-oidc v2.1.0+incompatible github.com/coreos/go-semver => github.com/coreos/go-semver v0.3.0 - github.com/coreos/go-systemd => github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 + github.com/coreos/go-systemd => github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e github.com/coreos/pkg => github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea github.com/coreos/rkt => github.com/coreos/rkt v1.30.0 github.com/cpuguy83/go-md2man => github.com/cpuguy83/go-md2man v1.0.10 diff --git a/go.sum b/go.sum index 5e364773712..b49c29d98a7 100644 --- a/go.sum +++ b/go.sum @@ -104,8 +104,8 @@ github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/rkt v1.30.0 h1:Kkt6sYeEGKxA3Y7SCrY+nHoXkWed6Jr2BBY42GqMymM= diff --git a/staging/src/k8s.io/apiextensions-apiserver/go.sum b/staging/src/k8s.io/apiextensions-apiserver/go.sum index cebf8f9ba3a..7de50625ecc 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/go.sum +++ b/staging/src/k8s.io/apiextensions-apiserver/go.sum @@ -46,8 +46,8 @@ github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHo github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= diff --git a/staging/src/k8s.io/apiserver/go.mod b/staging/src/k8s.io/apiserver/go.mod index 9466f2cf96a..3f2165809da 100644 --- a/staging/src/k8s.io/apiserver/go.mod +++ b/staging/src/k8s.io/apiserver/go.mod @@ -10,7 +10,7 @@ require ( github.com/coreos/etcd v3.3.15+incompatible github.com/coreos/go-oidc v2.1.0+incompatible github.com/coreos/go-semver v0.3.0 // indirect - github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 + github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0 github.com/emicklei/go-restful v2.9.5+incompatible diff --git a/staging/src/k8s.io/apiserver/go.sum b/staging/src/k8s.io/apiserver/go.sum index a7148bd8d2b..bb7679bf620 100644 --- a/staging/src/k8s.io/apiserver/go.sum +++ b/staging/src/k8s.io/apiserver/go.sum @@ -37,8 +37,8 @@ github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/staging/src/k8s.io/kube-aggregator/go.sum b/staging/src/k8s.io/kube-aggregator/go.sum index db23f32ccc8..b72e52bb457 100644 --- a/staging/src/k8s.io/kube-aggregator/go.sum +++ b/staging/src/k8s.io/kube-aggregator/go.sum @@ -40,8 +40,8 @@ github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHo github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= diff --git a/staging/src/k8s.io/legacy-cloud-providers/go.sum b/staging/src/k8s.io/legacy-cloud-providers/go.sum index 06ea17f062d..a89e847ef9e 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/go.sum +++ b/staging/src/k8s.io/legacy-cloud-providers/go.sum @@ -46,7 +46,7 @@ github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE55 github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/staging/src/k8s.io/sample-apiserver/go.sum b/staging/src/k8s.io/sample-apiserver/go.sum index 2cdba9d0428..175e8bbb025 100644 --- a/staging/src/k8s.io/sample-apiserver/go.sum +++ b/staging/src/k8s.io/sample-apiserver/go.sum @@ -40,8 +40,8 @@ github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHo github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= diff --git a/vendor/github.com/coreos/go-systemd/dbus/dbus.go b/vendor/github.com/coreos/go-systemd/dbus/dbus.go index 1d54810aff4..f652582e658 100644 --- a/vendor/github.com/coreos/go-systemd/dbus/dbus.go +++ b/vendor/github.com/coreos/go-systemd/dbus/dbus.go @@ -143,7 +143,7 @@ func NewUserConnection() (*Conn, error) { func NewSystemdConnection() (*Conn, error) { return NewConnection(func() (*dbus.Conn, error) { // We skip Hello when talking directly to systemd. - return dbusAuthConnection(func() (*dbus.Conn, error) { + return dbusAuthConnection(func(opts ...dbus.ConnOption) (*dbus.Conn, error) { return dbus.Dial("unix:path=/run/systemd/private") }) }) @@ -201,7 +201,7 @@ func (c *Conn) GetManagerProperty(prop string) (string, error) { return variant.String(), nil } -func dbusAuthConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { +func dbusAuthConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { conn, err := createBus() if err != nil { return nil, err @@ -221,7 +221,7 @@ func dbusAuthConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error return conn, nil } -func dbusAuthHelloConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { +func dbusAuthHelloConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { conn, err := dbusAuthConnection(createBus) if err != nil { return nil, err diff --git a/vendor/github.com/coreos/go-systemd/dbus/methods.go b/vendor/github.com/coreos/go-systemd/dbus/methods.go index 0b4207229f7..5f2790acff9 100644 --- a/vendor/github.com/coreos/go-systemd/dbus/methods.go +++ b/vendor/github.com/coreos/go-systemd/dbus/methods.go @@ -117,13 +117,13 @@ func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int, return c.startJob(ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode) } -// ReloadOrRestart attempts a reload if the unit supports it and use a restart +// ReloadOrRestartUnit attempts a reload if the unit supports it and use a restart // otherwise. func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) { return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode) } -// ReloadOrTryRestart attempts a reload if the unit supports it and use a "Try" +// ReloadOrTryRestartUnit attempts a reload if the unit supports it and use a "Try" // flavored restart otherwise. func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) { return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode) @@ -192,7 +192,7 @@ func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) { return c.getProperties(path, "org.freedesktop.systemd1.Unit") } -// GetUnitProperties takes the (escaped) unit path and returns all of its dbus object properties. +// GetUnitPathProperties takes the (escaped) unit path and returns all of its dbus object properties. func (c *Conn) GetUnitPathProperties(path dbus.ObjectPath) (map[string]interface{}, error) { return c.getProperties(path, "org.freedesktop.systemd1.Unit") } @@ -291,6 +291,8 @@ func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) { // ListUnits returns an array with all currently loaded units. Note that // units may be known by multiple names at the same time, and hence there might // be more unit names loaded than actual units behind them. +// Also note that a unit is only loaded if it is active and/or enabled. +// Units that are both disabled and inactive will thus not be returned. func (c *Conn) ListUnits() ([]UnitStatus, error) { return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store) } diff --git a/vendor/github.com/coreos/go-systemd/dbus/subscription.go b/vendor/github.com/coreos/go-systemd/dbus/subscription.go index 70e63a6f16e..f6d7a08a106 100644 --- a/vendor/github.com/coreos/go-systemd/dbus/subscription.go +++ b/vendor/github.com/coreos/go-systemd/dbus/subscription.go @@ -94,7 +94,7 @@ func (c *Conn) dispatch() { }() } -// Returns two unbuffered channels which will receive all changed units every +// SubscribeUnits returns two unbuffered channels which will receive all changed units every // interval. Deleted units are sent as nil. func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) { return c.SubscribeUnitsCustom(interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 }, nil) diff --git a/vendor/github.com/coreos/go-systemd/journal/journal.go b/vendor/github.com/coreos/go-systemd/journal/journal.go index ef85a3ba245..a0f4837a02c 100644 --- a/vendor/github.com/coreos/go-systemd/journal/journal.go +++ b/vendor/github.com/coreos/go-systemd/journal/journal.go @@ -33,7 +33,10 @@ import ( "os" "strconv" "strings" + "sync" + "sync/atomic" "syscall" + "unsafe" ) // Priority of a journal message @@ -50,19 +53,35 @@ const ( PriDebug ) -var conn net.Conn +var ( + // This can be overridden at build-time: + // https://github.com/golang/go/wiki/GcToolchainTricks#including-build-information-in-the-executable + journalSocket = "/run/systemd/journal/socket" + + // unixConnPtr atomically holds the local unconnected Unix-domain socket. + // Concrete safe pointer type: *net.UnixConn + unixConnPtr unsafe.Pointer + // onceConn ensures that unixConnPtr is initialized exactly once. + onceConn sync.Once +) func init() { - var err error - conn, err = net.Dial("unixgram", "/run/systemd/journal/socket") - if err != nil { - conn = nil - } + onceConn.Do(initConn) } -// Enabled returns true if the local systemd journal is available for logging +// Enabled checks whether the local systemd journal is available for logging. func Enabled() bool { - return conn != nil + onceConn.Do(initConn) + + if (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr)) == nil { + return false + } + + if _, err := net.Dial("unixgram", journalSocket); err != nil { + return false + } + + return true } // Send a message to the local systemd journal. vars is a map of journald @@ -73,8 +92,14 @@ func Enabled() bool { // (http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html) // for more details. vars may be nil. func Send(message string, priority Priority, vars map[string]string) error { + conn := (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr)) if conn == nil { - return journalError("could not connect to journald socket") + return errors.New("could not initialize socket to journald") + } + + socketAddr := &net.UnixAddr{ + Name: journalSocket, + Net: "unixgram", } data := new(bytes.Buffer) @@ -84,32 +109,30 @@ func Send(message string, priority Priority, vars map[string]string) error { appendVariable(data, k, v) } - _, err := io.Copy(conn, data) - if err != nil && isSocketSpaceError(err) { - file, err := tempFd() - if err != nil { - return journalError(err.Error()) - } - defer file.Close() - _, err = io.Copy(file, data) - if err != nil { - return journalError(err.Error()) - } - - rights := syscall.UnixRights(int(file.Fd())) - - /* this connection should always be a UnixConn, but better safe than sorry */ - unixConn, ok := conn.(*net.UnixConn) - if !ok { - return journalError("can't send file through non-Unix connection") - } - _, _, err = unixConn.WriteMsgUnix([]byte{}, rights, nil) - if err != nil { - return journalError(err.Error()) - } - } else if err != nil { - return journalError(err.Error()) + _, _, err := conn.WriteMsgUnix(data.Bytes(), nil, socketAddr) + if err == nil { + return nil } + if !isSocketSpaceError(err) { + return err + } + + // Large log entry, send it via tempfile and ancillary-fd. + file, err := tempFd() + if err != nil { + return err + } + defer file.Close() + _, err = io.Copy(file, data) + if err != nil { + return err + } + rights := syscall.UnixRights(int(file.Fd())) + _, _, err = conn.WriteMsgUnix([]byte{}, rights, socketAddr) + if err != nil { + return err + } + return nil } @@ -119,8 +142,8 @@ func Print(priority Priority, format string, a ...interface{}) error { } func appendVariable(w io.Writer, name, value string) { - if !validVarName(name) { - journalError("variable name contains invalid character, ignoring") + if err := validVarName(name); err != nil { + fmt.Fprintf(os.Stderr, "variable name %s contains invalid character, ignoring\n", name) } if strings.ContainsRune(value, '\n') { /* When the value contains a newline, we write: @@ -137,32 +160,42 @@ func appendVariable(w io.Writer, name, value string) { } } -func validVarName(name string) bool { - /* The variable name must be in uppercase and consist only of characters, - * numbers and underscores, and may not begin with an underscore. (from the docs) - */ - - valid := name[0] != '_' - for _, c := range name { - valid = valid && ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' +// validVarName validates a variable name to make sure journald will accept it. +// The variable name must be in uppercase and consist only of characters, +// numbers and underscores, and may not begin with an underscore: +// https://www.freedesktop.org/software/systemd/man/sd_journal_print.html +func validVarName(name string) error { + if name == "" { + return errors.New("Empty variable name") + } else if name[0] == '_' { + return errors.New("Variable name begins with an underscore") } - return valid + + for _, c := range name { + if !(('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_') { + return errors.New("Variable name contains invalid characters") + } + } + return nil } +// isSocketSpaceError checks whether the error is signaling +// an "overlarge message" condition. func isSocketSpaceError(err error) bool { opErr, ok := err.(*net.OpError) - if !ok { + if !ok || opErr == nil { return false } - sysErr, ok := opErr.Err.(syscall.Errno) - if !ok { + sysErr, ok := opErr.Err.(*os.SyscallError) + if !ok || sysErr == nil { return false } - return sysErr == syscall.EMSGSIZE || sysErr == syscall.ENOBUFS + return sysErr.Err == syscall.EMSGSIZE || sysErr.Err == syscall.ENOBUFS } +// tempFd creates a temporary, unlinked file under `/dev/shm`. func tempFd() (*os.File, error) { file, err := ioutil.TempFile("/dev/shm/", "journal.XXXXX") if err != nil { @@ -175,8 +208,18 @@ func tempFd() (*os.File, error) { return file, nil } -func journalError(s string) error { - s = "journal error: " + s - fmt.Fprintln(os.Stderr, s) - return errors.New(s) +// initConn initializes the global `unixConnPtr` socket. +// It is meant to be called exactly once, at program startup. +func initConn() { + autobind, err := net.ResolveUnixAddr("unixgram", "") + if err != nil { + return + } + + sock, err := net.ListenUnixgram("unixgram", autobind) + if err != nil { + return + } + + atomic.StorePointer(&unixConnPtr, unsafe.Pointer(sock)) } diff --git a/vendor/modules.txt b/vendor/modules.txt index 8b243be25cf..5e67ddc2ea2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -278,7 +278,7 @@ github.com/coreos/etcd/wal/walpb github.com/coreos/go-oidc # github.com/coreos/go-semver v0.3.0 => github.com/coreos/go-semver v0.3.0 github.com/coreos/go-semver/semver -# github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 => github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 +# github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e => github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e github.com/coreos/go-systemd/daemon github.com/coreos/go-systemd/dbus github.com/coreos/go-systemd/journal From 42d1238962e3aa75be1b9a55152f90cb30d4e6d5 Mon Sep 17 00:00:00 2001 From: Odin Ugedal Date: Sat, 5 Oct 2019 14:37:48 +0200 Subject: [PATCH 7/7] Bump dependency github.com/godbus/dbus@v19 (2ff6f7ffd60f) --- go.mod | 4 +- go.sum | 4 +- vendor/github.com/godbus/dbus/.travis.yml | 8 +- vendor/github.com/godbus/dbus/BUILD | 4 + vendor/github.com/godbus/dbus/README.markdown | 2 +- vendor/github.com/godbus/dbus/auth.go | 1 - .../github.com/godbus/dbus/auth_anonymous.go | 16 + vendor/github.com/godbus/dbus/call.go | 26 +- vendor/github.com/godbus/dbus/conn.go | 616 +++++++++++------- vendor/github.com/godbus/dbus/conn_darwin.go | 4 + vendor/github.com/godbus/dbus/conn_other.go | 63 +- vendor/github.com/godbus/dbus/conn_unix.go | 18 + vendor/github.com/godbus/dbus/conn_windows.go | 15 + vendor/github.com/godbus/dbus/decoder.go | 9 +- .../github.com/godbus/dbus/default_handler.go | 52 +- vendor/github.com/godbus/dbus/export.go | 17 +- vendor/github.com/godbus/dbus/go.mod | 1 + vendor/github.com/godbus/dbus/object.go | 118 +++- .../godbus/dbus/server_interfaces.go | 10 + .../godbus/dbus/transport_generic.go | 2 +- .../godbus/dbus/transport_nonce_tcp.go | 39 ++ .../github.com/godbus/dbus/transport_unix.go | 30 +- vendor/modules.txt | 2 +- 23 files changed, 768 insertions(+), 293 deletions(-) create mode 100644 vendor/github.com/godbus/dbus/auth_anonymous.go create mode 100644 vendor/github.com/godbus/dbus/conn_unix.go create mode 100644 vendor/github.com/godbus/dbus/conn_windows.go create mode 100644 vendor/github.com/godbus/dbus/go.mod create mode 100644 vendor/github.com/godbus/dbus/transport_nonce_tcp.go diff --git a/go.mod b/go.mod index 55e5a47e524..bed114e7d47 100644 --- a/go.mod +++ b/go.mod @@ -61,7 +61,7 @@ require ( github.com/go-openapi/strfmt v0.19.0 github.com/go-openapi/validate v0.19.2 github.com/go-ozzo/ozzo-validation v3.5.0+incompatible // indirect - github.com/godbus/dbus v4.1.0+incompatible // indirect + github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f // indirect github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 github.com/golang/mock v1.2.0 @@ -275,7 +275,7 @@ replace ( github.com/go-openapi/validate => github.com/go-openapi/validate v0.19.2 github.com/go-ozzo/ozzo-validation => github.com/go-ozzo/ozzo-validation v3.5.0+incompatible github.com/go-stack/stack => github.com/go-stack/stack v1.8.0 - github.com/godbus/dbus => github.com/godbus/dbus v4.1.0+incompatible + github.com/godbus/dbus => github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f github.com/gogo/protobuf => github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d github.com/golang/glog => github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/groupcache => github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 diff --git a/go.sum b/go.sum index b49c29d98a7..ebb34f0a6b3 100644 --- a/go.sum +++ b/go.sum @@ -185,8 +185,8 @@ github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2K github.com/go-ozzo/ozzo-validation v3.5.0+incompatible h1:sUy/in/P6askYr16XJgTKq/0SZhiWsdg4WZGaLsGQkM= github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4= -github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f h1:zlOR3rOlPAVvtfuxGKoghCmop5B0TRyu/ZieziZuGiM= +github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= diff --git a/vendor/github.com/godbus/dbus/.travis.yml b/vendor/github.com/godbus/dbus/.travis.yml index 2e1bbb78c39..9cd57f432b0 100644 --- a/vendor/github.com/godbus/dbus/.travis.yml +++ b/vendor/github.com/godbus/dbus/.travis.yml @@ -4,8 +4,10 @@ go_import_path: github.com/godbus/dbus sudo: true go: - - 1.6.3 - 1.7.3 + - 1.8.7 + - 1.9.5 + - 1.10.1 - tip env: @@ -38,3 +40,7 @@ addons: - dbus-x11 before_install: + +script: + - go test -v -race ./... # Run all the tests with the race detector enabled + - go vet ./... # go vet is the official Go static analyzer diff --git a/vendor/github.com/godbus/dbus/BUILD b/vendor/github.com/godbus/dbus/BUILD index 147facecc8a..b2d2a828004 100644 --- a/vendor/github.com/godbus/dbus/BUILD +++ b/vendor/github.com/godbus/dbus/BUILD @@ -4,12 +4,15 @@ go_library( name = "go_default_library", srcs = [ "auth.go", + "auth_anonymous.go", "auth_external.go", "auth_sha1.go", "call.go", "conn.go", "conn_darwin.go", "conn_other.go", + "conn_unix.go", + "conn_windows.go", "dbus.go", "decoder.go", "default_handler.go", @@ -24,6 +27,7 @@ go_library( "sig.go", "transport_darwin.go", "transport_generic.go", + "transport_nonce_tcp.go", "transport_tcp.go", "transport_unix.go", "transport_unixcred_dragonfly.go", diff --git a/vendor/github.com/godbus/dbus/README.markdown b/vendor/github.com/godbus/dbus/README.markdown index d37f4e2ed8c..fd29648752d 100644 --- a/vendor/github.com/godbus/dbus/README.markdown +++ b/vendor/github.com/godbus/dbus/README.markdown @@ -14,7 +14,7 @@ D-Bus message bus system. ### Installation -This packages requires Go 1.1. If you installed it and set up your GOPATH, just run: +This packages requires Go 1.7. If you installed it and set up your GOPATH, just run: ``` go get github.com/godbus/dbus diff --git a/vendor/github.com/godbus/dbus/auth.go b/vendor/github.com/godbus/dbus/auth.go index 98017b693ee..b0dcb54e6b5 100644 --- a/vendor/github.com/godbus/dbus/auth.go +++ b/vendor/github.com/godbus/dbus/auth.go @@ -116,7 +116,6 @@ func (conn *Conn) Auth(methods []Auth) error { return err } go conn.inWorker() - go conn.outWorker() return nil } } diff --git a/vendor/github.com/godbus/dbus/auth_anonymous.go b/vendor/github.com/godbus/dbus/auth_anonymous.go new file mode 100644 index 00000000000..75f3ad34d7a --- /dev/null +++ b/vendor/github.com/godbus/dbus/auth_anonymous.go @@ -0,0 +1,16 @@ +package dbus + +// AuthAnonymous returns an Auth that uses the ANONYMOUS mechanism. +func AuthAnonymous() Auth { + return &authAnonymous{} +} + +type authAnonymous struct{} + +func (a *authAnonymous) FirstData() (name, resp []byte, status AuthStatus) { + return []byte("ANONYMOUS"), nil, AuthOk +} + +func (a *authAnonymous) HandleData(data []byte) (resp []byte, status AuthStatus) { + return nil, AuthError +} diff --git a/vendor/github.com/godbus/dbus/call.go b/vendor/github.com/godbus/dbus/call.go index ba6e73f607a..2cb189012e7 100644 --- a/vendor/github.com/godbus/dbus/call.go +++ b/vendor/github.com/godbus/dbus/call.go @@ -1,9 +1,12 @@ package dbus import ( + "context" "errors" ) +var errSignature = errors.New("dbus: mismatched signature") + // Call represents a pending or completed method call. type Call struct { Destination string @@ -20,9 +23,25 @@ type Call struct { // Holds the response once the call is done. Body []interface{} + + // tracks context and canceler + ctx context.Context + ctxCanceler context.CancelFunc } -var errSignature = errors.New("dbus: mismatched signature") +func (c *Call) Context() context.Context { + if c.ctx == nil { + return context.Background() + } + + return c.ctx +} + +func (c *Call) ContextCancel() { + if c.ctxCanceler != nil { + c.ctxCanceler() + } +} // Store stores the body of the reply into the provided pointers. It returns // an error if the signatures of the body and retvalues don't match, or if @@ -34,3 +53,8 @@ func (c *Call) Store(retvalues ...interface{}) error { return Store(c.Body, retvalues...) } + +func (c *Call) done() { + c.Done <- c + c.ContextCancel() +} diff --git a/vendor/github.com/godbus/dbus/conn.go b/vendor/github.com/godbus/dbus/conn.go index 5720e2ebbf0..b38920baf5b 100644 --- a/vendor/github.com/godbus/dbus/conn.go +++ b/vendor/github.com/godbus/dbus/conn.go @@ -1,6 +1,7 @@ package dbus import ( + "context" "errors" "io" "os" @@ -14,7 +15,6 @@ var ( systemBusLck sync.Mutex sessionBus *Conn sessionBusLck sync.Mutex - sessionEnvLck sync.Mutex ) // ErrClosed is the error returned by calls on a closed connection. @@ -35,23 +35,13 @@ type Conn struct { unixFD bool uuid string - names []string - namesLck sync.RWMutex - - serialLck sync.Mutex - nextSerial uint32 - serialUsed map[uint32]bool - - calls map[uint32]*Call - callsLck sync.RWMutex - - handler Handler - - out chan *Message - closed bool - outLck sync.RWMutex - + handler Handler signalHandler SignalHandler + serialGen SerialGenerator + + names *nameTracker + calls *callTracker + outHandler *outputHandler eavesdropped chan<- *Message eavesdroppedLck sync.Mutex @@ -87,32 +77,31 @@ func SessionBus() (conn *Conn, err error) { } func getSessionBusAddress() (string, error) { - sessionEnvLck.Lock() - defer sessionEnvLck.Unlock() - address := os.Getenv("DBUS_SESSION_BUS_ADDRESS") - if address != "" && address != "autolaunch:" { + if address := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); address != "" && address != "autolaunch:" { + return address, nil + + } else if address := tryDiscoverDbusSessionBusAddress(); address != "" { + os.Setenv("DBUS_SESSION_BUS_ADDRESS", address) return address, nil } return getSessionBusPlatformAddress() } // SessionBusPrivate returns a new private connection to the session bus. -func SessionBusPrivate() (*Conn, error) { +func SessionBusPrivate(opts ...ConnOption) (*Conn, error) { address, err := getSessionBusAddress() if err != nil { return nil, err } - return Dial(address) + return Dial(address, opts...) } // SessionBusPrivate returns a new private connection to the session bus. +// +// Deprecated: use SessionBusPrivate with options instead. func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) { - address, err := getSessionBusAddress() - if err != nil { - return nil, err - } - return DialHandler(address, handler, signalHandler) + return SessionBusPrivate(WithHandler(handler), WithSignalHandler(signalHandler)) } // SystemBus returns a shared connection to the system bus, connecting to it if @@ -145,53 +134,93 @@ func SystemBus() (conn *Conn, err error) { } // SystemBusPrivate returns a new private connection to the system bus. -func SystemBusPrivate() (*Conn, error) { - return Dial(getSystemBusPlatformAddress()) +func SystemBusPrivate(opts ...ConnOption) (*Conn, error) { + return Dial(getSystemBusPlatformAddress(), opts...) } // SystemBusPrivateHandler returns a new private connection to the system bus, using the provided handlers. +// +// Deprecated: use SystemBusPrivate with options instead. func SystemBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) { - return DialHandler(getSystemBusPlatformAddress(), handler, signalHandler) + return SystemBusPrivate(WithHandler(handler), WithSignalHandler(signalHandler)) } // Dial establishes a new private connection to the message bus specified by address. -func Dial(address string) (*Conn, error) { +func Dial(address string, opts ...ConnOption) (*Conn, error) { tr, err := getTransport(address) if err != nil { return nil, err } - return newConn(tr, NewDefaultHandler(), NewDefaultSignalHandler()) + return newConn(tr, opts...) } // DialHandler establishes a new private connection to the message bus specified by address, using the supplied handlers. +// +// Deprecated: use Dial with options instead. func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) { - tr, err := getTransport(address) - if err != nil { - return nil, err + return Dial(address, WithSignalHandler(signalHandler)) +} + +// ConnOption is a connection option. +type ConnOption func(conn *Conn) error + +// WithHandler overrides the default handler. +func WithHandler(handler Handler) ConnOption { + return func(conn *Conn) error { + conn.handler = handler + return nil + } +} + +// WithSignalHandler overrides the default signal handler. +func WithSignalHandler(handler SignalHandler) ConnOption { + return func(conn *Conn) error { + conn.signalHandler = handler + return nil + } +} + +// WithSerialGenerator overrides the default signals generator. +func WithSerialGenerator(gen SerialGenerator) ConnOption { + return func(conn *Conn) error { + conn.serialGen = gen + return nil } - return newConn(tr, handler, signalHandler) } // NewConn creates a new private *Conn from an already established connection. -func NewConn(conn io.ReadWriteCloser) (*Conn, error) { - return NewConnHandler(conn, NewDefaultHandler(), NewDefaultSignalHandler()) +func NewConn(conn io.ReadWriteCloser, opts ...ConnOption) (*Conn, error) { + return newConn(genericTransport{conn}, opts...) } // NewConnHandler creates a new private *Conn from an already established connection, using the supplied handlers. +// +// Deprecated: use NewConn with options instead. func NewConnHandler(conn io.ReadWriteCloser, handler Handler, signalHandler SignalHandler) (*Conn, error) { - return newConn(genericTransport{conn}, handler, signalHandler) + return NewConn(genericTransport{conn}, WithHandler(handler), WithSignalHandler(signalHandler)) } // newConn creates a new *Conn from a transport. -func newConn(tr transport, handler Handler, signalHandler SignalHandler) (*Conn, error) { +func newConn(tr transport, opts ...ConnOption) (*Conn, error) { conn := new(Conn) conn.transport = tr - conn.calls = make(map[uint32]*Call) - conn.out = make(chan *Message, 10) - conn.handler = handler - conn.signalHandler = signalHandler - conn.nextSerial = 1 - conn.serialUsed = map[uint32]bool{0: true} + for _, opt := range opts { + if err := opt(conn); err != nil { + return nil, err + } + } + conn.calls = newCallTracker() + if conn.handler == nil { + conn.handler = NewDefaultHandler() + } + if conn.signalHandler == nil { + conn.signalHandler = NewDefaultSignalHandler() + } + if conn.serialGen == nil { + conn.serialGen = newSerialGenerator() + } + conn.outHandler = &outputHandler{conn: conn} + conn.names = newNameTracker() conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus") return conn, nil } @@ -206,18 +235,7 @@ func (conn *Conn) BusObject() BusObject { // and the channels passed to Eavesdrop and Signal are closed. This method must // not be called on shared connections. func (conn *Conn) Close() error { - conn.outLck.Lock() - if conn.closed { - // inWorker calls Close on read error, the read error may - // be caused by another caller calling Close to shutdown the - // dbus connection, a double-close scenario we prevent here. - conn.outLck.Unlock() - return nil - } - close(conn.out) - conn.closed = true - conn.outLck.Unlock() - + conn.outHandler.close() if term, ok := conn.signalHandler.(Terminator); ok { term.Terminate() } @@ -249,17 +267,9 @@ func (conn *Conn) Eavesdrop(ch chan<- *Message) { conn.eavesdroppedLck.Unlock() } -// getSerial returns an unused serial. +// GetSerial returns an unused serial. func (conn *Conn) getSerial() uint32 { - conn.serialLck.Lock() - defer conn.serialLck.Unlock() - n := conn.nextSerial - for conn.serialUsed[n] { - n++ - } - conn.serialUsed[n] = true - conn.nextSerial = n + 1 - return n + return conn.serialGen.GetSerial() } // Hello sends the initial org.freedesktop.DBus.Hello call. This method must be @@ -271,10 +281,7 @@ func (conn *Conn) Hello() error { if err != nil { return err } - conn.namesLck.Lock() - conn.names = make([]string, 1) - conn.names[0] = s - conn.namesLck.Unlock() + conn.names.acquireUniqueConnectionName(s) return nil } @@ -283,109 +290,48 @@ func (conn *Conn) Hello() error { func (conn *Conn) inWorker() { for { msg, err := conn.ReadMessage() - if err == nil { - conn.eavesdroppedLck.Lock() - if conn.eavesdropped != nil { - select { - case conn.eavesdropped <- msg: - default: - } - conn.eavesdroppedLck.Unlock() - continue + if err != nil { + if _, ok := err.(InvalidMessageError); !ok { + // Some read error occured (usually EOF); we can't really do + // anything but to shut down all stuff and returns errors to all + // pending replies. + conn.Close() + conn.calls.finalizeAllWithError(err) + return + } + // invalid messages are ignored + continue + } + conn.eavesdroppedLck.Lock() + if conn.eavesdropped != nil { + select { + case conn.eavesdropped <- msg: + default: } conn.eavesdroppedLck.Unlock() - dest, _ := msg.Headers[FieldDestination].value.(string) - found := false - if dest == "" { - found = true - } else { - conn.namesLck.RLock() - if len(conn.names) == 0 { - found = true - } - for _, v := range conn.names { - if dest == v { - found = true - break - } - } - conn.namesLck.RUnlock() - } - if !found { - // Eavesdropped a message, but no channel for it is registered. - // Ignore it. - continue - } - switch msg.Type { - case TypeMethodReply, TypeError: - serial := msg.Headers[FieldReplySerial].value.(uint32) - conn.callsLck.Lock() - if c, ok := conn.calls[serial]; ok { - if msg.Type == TypeError { - name, _ := msg.Headers[FieldErrorName].value.(string) - c.Err = Error{name, msg.Body} - } else { - c.Body = msg.Body - } - c.Done <- c - conn.serialLck.Lock() - delete(conn.serialUsed, serial) - conn.serialLck.Unlock() - delete(conn.calls, serial) - } - conn.callsLck.Unlock() - case TypeSignal: - iface := msg.Headers[FieldInterface].value.(string) - member := msg.Headers[FieldMember].value.(string) - // as per http://dbus.freedesktop.org/doc/dbus-specification.html , - // sender is optional for signals. - sender, _ := msg.Headers[FieldSender].value.(string) - if iface == "org.freedesktop.DBus" && sender == "org.freedesktop.DBus" { - if member == "NameLost" { - // If we lost the name on the bus, remove it from our - // tracking list. - name, ok := msg.Body[0].(string) - if !ok { - panic("Unable to read the lost name") - } - conn.namesLck.Lock() - for i, v := range conn.names { - if v == name { - conn.names = append(conn.names[:i], - conn.names[i+1:]...) - } - } - conn.namesLck.Unlock() - } else if member == "NameAcquired" { - // If we acquired the name on the bus, add it to our - // tracking list. - name, ok := msg.Body[0].(string) - if !ok { - panic("Unable to read the acquired name") - } - conn.namesLck.Lock() - conn.names = append(conn.names, name) - conn.namesLck.Unlock() - } - } - conn.handleSignal(msg) - case TypeMethodCall: - go conn.handleCall(msg) - } - } else if _, ok := err.(InvalidMessageError); !ok { - // Some read error occured (usually EOF); we can't really do - // anything but to shut down all stuff and returns errors to all - // pending replies. - conn.Close() - conn.callsLck.RLock() - for _, v := range conn.calls { - v.Err = err - v.Done <- v - } - conn.callsLck.RUnlock() - return + continue } - // invalid messages are ignored + conn.eavesdroppedLck.Unlock() + dest, _ := msg.Headers[FieldDestination].value.(string) + found := dest == "" || + !conn.names.uniqueNameIsKnown() || + conn.names.isKnownName(dest) + if !found { + // Eavesdropped a message, but no channel for it is registered. + // Ignore it. + continue + } + switch msg.Type { + case TypeError: + conn.serialGen.RetireSerial(conn.calls.handleDBusError(msg)) + case TypeMethodReply: + conn.serialGen.RetireSerial(conn.calls.handleReply(msg)) + case TypeSignal: + conn.handleSignal(msg) + case TypeMethodCall: + go conn.handleCall(msg) + } + } } @@ -395,6 +341,25 @@ func (conn *Conn) handleSignal(msg *Message) { // as per http://dbus.freedesktop.org/doc/dbus-specification.html , // sender is optional for signals. sender, _ := msg.Headers[FieldSender].value.(string) + if iface == "org.freedesktop.DBus" && sender == "org.freedesktop.DBus" { + if member == "NameLost" { + // If we lost the name on the bus, remove it from our + // tracking list. + name, ok := msg.Body[0].(string) + if !ok { + panic("Unable to read the lost name") + } + conn.names.loseName(name) + } else if member == "NameAcquired" { + // If we acquired the name on the bus, add it to our + // tracking list. + name, ok := msg.Body[0].(string) + if !ok { + panic("Unable to read the acquired name") + } + conn.names.acquireName(name) + } + } signal := &Signal{ Sender: sender, Path: msg.Headers[FieldPath].value.(ObjectPath), @@ -408,12 +373,7 @@ func (conn *Conn) handleSignal(msg *Message) { // connection. The slice is always at least one element long, the first element // being the unique name of the connection. func (conn *Conn) Names() []string { - conn.namesLck.RLock() - // copy the slice so it can't be modified - s := make([]string, len(conn.names)) - copy(s, conn.names) - conn.namesLck.RUnlock() - return s + return conn.names.listKnownNames() } // Object returns the object identified by the given destination name and path. @@ -423,24 +383,17 @@ func (conn *Conn) Object(dest string, path ObjectPath) BusObject { // outWorker runs in an own goroutine, encoding and sending messages that are // sent to conn.out. -func (conn *Conn) outWorker() { - for msg := range conn.out { - err := conn.SendMessage(msg) - conn.callsLck.RLock() - if err != nil { - if c := conn.calls[msg.serial]; c != nil { - c.Err = err - c.Done <- c - } - conn.serialLck.Lock() - delete(conn.serialUsed, msg.serial) - conn.serialLck.Unlock() - } else if msg.Type != TypeMethodCall { - conn.serialLck.Lock() - delete(conn.serialUsed, msg.serial) - conn.serialLck.Unlock() - } - conn.callsLck.RUnlock() +func (conn *Conn) sendMessage(msg *Message) { + conn.sendMessageAndIfClosed(msg, func() {}) +} + +func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) { + err := conn.outHandler.sendAndIfClosed(msg, ifClosed) + conn.calls.handleSendError(msg, err) + if err != nil { + conn.serialGen.RetireSerial(msg.serial) + } else if msg.Type != TypeMethodCall { + conn.serialGen.RetireSerial(msg.serial) } } @@ -451,8 +404,21 @@ func (conn *Conn) outWorker() { // once the call is complete. Otherwise, ch is ignored and a Call structure is // returned of which only the Err member is valid. func (conn *Conn) Send(msg *Message, ch chan *Call) *Call { - var call *Call + return conn.send(context.Background(), msg, ch) +} +// SendWithContext acts like Send but takes a context +func (conn *Conn) SendWithContext(ctx context.Context, msg *Message, ch chan *Call) *Call { + return conn.send(ctx, msg, ch) +} + +func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call { + if ctx == nil { + panic("nil context") + } + + var call *Call + ctx, canceler := context.WithCancel(ctx) msg.serial = conn.getSerial() if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 { if ch == nil { @@ -468,26 +434,23 @@ func (conn *Conn) Send(msg *Message, ch chan *Call) *Call { call.Method = iface + "." + member call.Args = msg.Body call.Done = ch - conn.callsLck.Lock() - conn.calls[msg.serial] = call - conn.callsLck.Unlock() - conn.outLck.RLock() - if conn.closed { - call.Err = ErrClosed - call.Done <- call - } else { - conn.out <- msg - } - conn.outLck.RUnlock() + call.ctx = ctx + call.ctxCanceler = canceler + conn.calls.track(msg.serial, call) + go func() { + <-ctx.Done() + conn.calls.handleSendError(msg, ctx.Err()) + }() + conn.sendMessageAndIfClosed(msg, func() { + conn.calls.handleSendError(msg, ErrClosed) + canceler() + }) } else { - conn.outLck.RLock() - if conn.closed { + canceler() + call = &Call{Err: nil} + conn.sendMessageAndIfClosed(msg, func() { call = &Call{Err: ErrClosed} - } else { - conn.out <- msg - call = &Call{Err: nil} - } - conn.outLck.RUnlock() + }) } return call } @@ -520,11 +483,7 @@ func (conn *Conn) sendError(err error, dest string, serial uint32) { if len(e.Body) > 0 { msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...)) } - conn.outLck.RLock() - if !conn.closed { - conn.out <- msg - } - conn.outLck.RUnlock() + conn.sendMessage(msg) } // sendReply creates a method reply message corresponding to the parameters and @@ -542,11 +501,7 @@ func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) { if len(values) > 0 { msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...)) } - conn.outLck.RLock() - if !conn.closed { - conn.out <- msg - } - conn.outLck.RUnlock() + conn.sendMessage(msg) } func (conn *Conn) defaultSignalAction(fn func(h *defaultSignalHandler, ch chan<- *Signal), ch chan<- *Signal) { @@ -681,3 +636,212 @@ func getKey(s, key string) string { } return "" } + +type outputHandler struct { + conn *Conn + sendLck sync.Mutex + closed struct { + isClosed bool + lck sync.RWMutex + } +} + +func (h *outputHandler) sendAndIfClosed(msg *Message, ifClosed func()) error { + h.closed.lck.RLock() + defer h.closed.lck.RUnlock() + if h.closed.isClosed { + ifClosed() + return nil + } + h.sendLck.Lock() + defer h.sendLck.Unlock() + return h.conn.SendMessage(msg) +} + +func (h *outputHandler) close() { + h.closed.lck.Lock() + defer h.closed.lck.Unlock() + h.closed.isClosed = true +} + +type serialGenerator struct { + lck sync.Mutex + nextSerial uint32 + serialUsed map[uint32]bool +} + +func newSerialGenerator() *serialGenerator { + return &serialGenerator{ + serialUsed: map[uint32]bool{0: true}, + nextSerial: 1, + } +} + +func (gen *serialGenerator) GetSerial() uint32 { + gen.lck.Lock() + defer gen.lck.Unlock() + n := gen.nextSerial + for gen.serialUsed[n] { + n++ + } + gen.serialUsed[n] = true + gen.nextSerial = n + 1 + return n +} + +func (gen *serialGenerator) RetireSerial(serial uint32) { + gen.lck.Lock() + defer gen.lck.Unlock() + delete(gen.serialUsed, serial) +} + +type nameTracker struct { + lck sync.RWMutex + unique string + names map[string]struct{} +} + +func newNameTracker() *nameTracker { + return &nameTracker{names: map[string]struct{}{}} +} +func (tracker *nameTracker) acquireUniqueConnectionName(name string) { + tracker.lck.Lock() + defer tracker.lck.Unlock() + tracker.unique = name +} +func (tracker *nameTracker) acquireName(name string) { + tracker.lck.Lock() + defer tracker.lck.Unlock() + tracker.names[name] = struct{}{} +} +func (tracker *nameTracker) loseName(name string) { + tracker.lck.Lock() + defer tracker.lck.Unlock() + delete(tracker.names, name) +} + +func (tracker *nameTracker) uniqueNameIsKnown() bool { + tracker.lck.RLock() + defer tracker.lck.RUnlock() + return tracker.unique != "" +} +func (tracker *nameTracker) isKnownName(name string) bool { + tracker.lck.RLock() + defer tracker.lck.RUnlock() + _, ok := tracker.names[name] + return ok || name == tracker.unique +} +func (tracker *nameTracker) listKnownNames() []string { + tracker.lck.RLock() + defer tracker.lck.RUnlock() + out := make([]string, 0, len(tracker.names)+1) + out = append(out, tracker.unique) + for k := range tracker.names { + out = append(out, k) + } + return out +} + +type callTracker struct { + calls map[uint32]*Call + lck sync.RWMutex +} + +func newCallTracker() *callTracker { + return &callTracker{calls: map[uint32]*Call{}} +} + +func (tracker *callTracker) track(sn uint32, call *Call) { + tracker.lck.Lock() + tracker.calls[sn] = call + tracker.lck.Unlock() +} + +func (tracker *callTracker) handleReply(msg *Message) uint32 { + serial := msg.Headers[FieldReplySerial].value.(uint32) + tracker.lck.RLock() + _, ok := tracker.calls[serial] + tracker.lck.RUnlock() + if ok { + tracker.finalizeWithBody(serial, msg.Body) + } + return serial +} + +func (tracker *callTracker) handleDBusError(msg *Message) uint32 { + serial := msg.Headers[FieldReplySerial].value.(uint32) + tracker.lck.RLock() + _, ok := tracker.calls[serial] + tracker.lck.RUnlock() + if ok { + name, _ := msg.Headers[FieldErrorName].value.(string) + tracker.finalizeWithError(serial, Error{name, msg.Body}) + } + return serial +} + +func (tracker *callTracker) handleSendError(msg *Message, err error) { + if err == nil { + return + } + tracker.lck.RLock() + _, ok := tracker.calls[msg.serial] + tracker.lck.RUnlock() + if ok { + tracker.finalizeWithError(msg.serial, err) + } +} + +// finalize was the only func that did not strobe Done +func (tracker *callTracker) finalize(sn uint32) { + tracker.lck.Lock() + defer tracker.lck.Unlock() + c, ok := tracker.calls[sn] + if ok { + delete(tracker.calls, sn) + c.ContextCancel() + } + return +} + +func (tracker *callTracker) finalizeWithBody(sn uint32, body []interface{}) { + tracker.lck.Lock() + c, ok := tracker.calls[sn] + if ok { + delete(tracker.calls, sn) + } + tracker.lck.Unlock() + if ok { + c.Body = body + c.done() + } + return +} + +func (tracker *callTracker) finalizeWithError(sn uint32, err error) { + tracker.lck.Lock() + c, ok := tracker.calls[sn] + if ok { + delete(tracker.calls, sn) + } + tracker.lck.Unlock() + if ok { + c.Err = err + c.done() + } + return +} + +func (tracker *callTracker) finalizeAllWithError(err error) { + tracker.lck.Lock() + closedCalls := make([]*Call, 0, len(tracker.calls)) + for sn := range tracker.calls { + closedCalls = append(closedCalls, tracker.calls[sn]) + } + tracker.calls = map[uint32]*Call{} + tracker.lck.Unlock() + for _, call := range closedCalls { + call.Err = err + call.done() + } +} diff --git a/vendor/github.com/godbus/dbus/conn_darwin.go b/vendor/github.com/godbus/dbus/conn_darwin.go index c015f80ce7e..6e2e4020216 100644 --- a/vendor/github.com/godbus/dbus/conn_darwin.go +++ b/vendor/github.com/godbus/dbus/conn_darwin.go @@ -31,3 +31,7 @@ func getSystemBusPlatformAddress() string { } return defaultSystemBusAddress } + +func tryDiscoverDbusSessionBusAddress() string { + return "" +} diff --git a/vendor/github.com/godbus/dbus/conn_other.go b/vendor/github.com/godbus/dbus/conn_other.go index 254c9f2ef68..289044a44d4 100644 --- a/vendor/github.com/godbus/dbus/conn_other.go +++ b/vendor/github.com/godbus/dbus/conn_other.go @@ -6,12 +6,14 @@ import ( "bytes" "errors" "fmt" + "io/ioutil" "os" "os/exec" + "os/user" + "path" + "strings" ) -const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket" - func getSessionBusPlatformAddress() (string, error) { cmd := exec.Command("dbus-launch") b, err := cmd.CombinedOutput() @@ -33,10 +35,57 @@ func getSessionBusPlatformAddress() (string, error) { return addr, nil } -func getSystemBusPlatformAddress() string { - address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS") - if address != "" { - return fmt.Sprintf("unix:path=%s", address) +// tryDiscoverDbusSessionBusAddress tries to discover an existing dbus session +// and return the value of its DBUS_SESSION_BUS_ADDRESS. +// It tries different techniques employed by different operating systems, +// returning the first valid address it finds, or an empty string. +// +// * /run/user//bus if this exists, it *is* the bus socket. present on +// Ubuntu 18.04 +// * /run/user//dbus-session: if this exists, it can be parsed for the bus +// address. present on Ubuntu 16.04 +// +// See https://dbus.freedesktop.org/doc/dbus-launch.1.html +func tryDiscoverDbusSessionBusAddress() string { + if runtimeDirectory, err := getRuntimeDirectory(); err == nil { + + if runUserBusFile := path.Join(runtimeDirectory, "bus"); fileExists(runUserBusFile) { + // if /run/user//bus exists, that file itself + // *is* the unix socket, so return its path + return fmt.Sprintf("unix:path=%s", runUserBusFile) + } + if runUserSessionDbusFile := path.Join(runtimeDirectory, "dbus-session"); fileExists(runUserSessionDbusFile) { + // if /run/user//dbus-session exists, it's a + // text file // containing the address of the socket, e.g.: + // DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-E1c73yNqrG + + if f, err := ioutil.ReadFile(runUserSessionDbusFile); err == nil { + fileContent := string(f) + + prefix := "DBUS_SESSION_BUS_ADDRESS=" + + if strings.HasPrefix(fileContent, prefix) { + address := strings.TrimRight(strings.TrimPrefix(fileContent, prefix), "\n\r") + return address + } + } + } + } + return "" +} + +func getRuntimeDirectory() (string, error) { + if currentUser, err := user.Current(); err != nil { + return "", err + } else { + return fmt.Sprintf("/run/user/%s", currentUser.Uid), nil + } +} + +func fileExists(filename string) bool { + if _, err := os.Stat(filename); !os.IsNotExist(err) { + return true + } else { + return false } - return defaultSystemBusAddress } diff --git a/vendor/github.com/godbus/dbus/conn_unix.go b/vendor/github.com/godbus/dbus/conn_unix.go new file mode 100644 index 00000000000..4cba8ae8ec3 --- /dev/null +++ b/vendor/github.com/godbus/dbus/conn_unix.go @@ -0,0 +1,18 @@ +//+build !windows,!solaris,!darwin + +package dbus + +import ( + "os" + "fmt" +) + +const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket" + +func getSystemBusPlatformAddress() string { + address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS") + if address != "" { + return fmt.Sprintf("unix:path=%s", address) + } + return defaultSystemBusAddress +} \ No newline at end of file diff --git a/vendor/github.com/godbus/dbus/conn_windows.go b/vendor/github.com/godbus/dbus/conn_windows.go new file mode 100644 index 00000000000..4291e4519cc --- /dev/null +++ b/vendor/github.com/godbus/dbus/conn_windows.go @@ -0,0 +1,15 @@ +//+build windows + +package dbus + +import "os" + +const defaultSystemBusAddress = "tcp:host=127.0.0.1,port=12434" + +func getSystemBusPlatformAddress() string { + address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS") + if address != "" { + return address + } + return defaultSystemBusAddress +} diff --git a/vendor/github.com/godbus/dbus/decoder.go b/vendor/github.com/godbus/dbus/decoder.go index ef50dcab98d..5c27d3b51f6 100644 --- a/vendor/github.com/godbus/dbus/decoder.go +++ b/vendor/github.com/godbus/dbus/decoder.go @@ -191,7 +191,14 @@ func (dec *decoder) decode(s string, depth int) interface{} { length := dec.decode("u", depth).(uint32) v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length)) // Even for empty arrays, the correct padding must be included - dec.align(alignment(typeFor(s[1:]))) + align := alignment(typeFor(s[1:])) + if len(s) > 1 && s[1] == '(' { + //Special case for arrays of structs + //structs decode as a slice of interface{} values + //but the dbus alignment does not match this + align = 8 + } + dec.align(align) spos := dec.pos for dec.pos < spos+int(length) { ev := dec.decode(s[1:], depth+1) diff --git a/vendor/github.com/godbus/dbus/default_handler.go b/vendor/github.com/godbus/dbus/default_handler.go index e81f73ac522..81dbcc7e42a 100644 --- a/vendor/github.com/godbus/dbus/default_handler.go +++ b/vendor/github.com/godbus/dbus/default_handler.go @@ -21,6 +21,8 @@ func newIntrospectIntf(h *defaultHandler) *exportedIntf { //NewDefaultHandler returns an instance of the default //call handler. This is useful if you want to implement only //one of the two handlers but not both. +// +// Deprecated: this is the default value, don't use it, it will be unexported. func NewDefaultHandler() *defaultHandler { h := &defaultHandler{ objects: make(map[ObjectPath]*exportedObj), @@ -161,6 +163,7 @@ func newExportedObject() *exportedObj { } type exportedObj struct { + mu sync.RWMutex interfaces map[string]*exportedIntf } @@ -168,19 +171,27 @@ func (obj *exportedObj) LookupInterface(name string) (Interface, bool) { if name == "" { return obj, true } + obj.mu.RLock() + defer obj.mu.RUnlock() intf, exists := obj.interfaces[name] return intf, exists } func (obj *exportedObj) AddInterface(name string, iface *exportedIntf) { + obj.mu.Lock() + defer obj.mu.Unlock() obj.interfaces[name] = iface } func (obj *exportedObj) DeleteInterface(name string) { + obj.mu.Lock() + defer obj.mu.Unlock() delete(obj.interfaces, name) } func (obj *exportedObj) LookupMethod(name string) (Method, bool) { + obj.mu.RLock() + defer obj.mu.RUnlock() for _, intf := range obj.interfaces { method, exists := intf.LookupMethod(name) if exists { @@ -220,8 +231,12 @@ func (obj *exportedIntf) isFallbackInterface() bool { //NewDefaultSignalHandler returns an instance of the default //signal handler. This is useful if you want to implement only //one of the two handlers but not both. +// +// Deprecated: this is the default value, don't use it, it will be unexported. func NewDefaultSignalHandler() *defaultSignalHandler { - return &defaultSignalHandler{} + return &defaultSignalHandler{ + closeChan: make(chan struct{}), + } } func isDefaultSignalHandler(handler SignalHandler) bool { @@ -231,32 +246,47 @@ func isDefaultSignalHandler(handler SignalHandler) bool { type defaultSignalHandler struct { sync.RWMutex - closed bool - signals []chan<- *Signal + closed bool + signals []chan<- *Signal + closeChan chan struct{} } func (sh *defaultSignalHandler) DeliverSignal(intf, name string, signal *Signal) { - go func() { - sh.RLock() - defer sh.RUnlock() - if sh.closed { + sh.RLock() + defer sh.RUnlock() + if sh.closed { + return + } + for _, ch := range sh.signals { + select { + case ch <- signal: + case <-sh.closeChan: return + default: + go func() { + select { + case ch <- signal: + case <-sh.closeChan: + return + } + }() } - for _, ch := range sh.signals { - ch <- signal - } - }() + } } func (sh *defaultSignalHandler) Init() error { sh.Lock() sh.signals = make([]chan<- *Signal, 0) + sh.closeChan = make(chan struct{}) sh.Unlock() return nil } func (sh *defaultSignalHandler) Terminate() { sh.Lock() + if !sh.closed { + close(sh.closeChan) + } sh.closed = true for _, ch := range sh.signals { close(ch) diff --git a/vendor/github.com/godbus/dbus/export.go b/vendor/github.com/godbus/dbus/export.go index aae97088152..95d0e29582d 100644 --- a/vendor/github.com/godbus/dbus/export.go +++ b/vendor/github.com/godbus/dbus/export.go @@ -170,11 +170,8 @@ func (conn *Conn) handleCall(msg *Message) { reply.Body[i] = ret[i] } reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...)) - conn.outLck.RLock() - if !conn.closed { - conn.out <- reply - } - conn.outLck.RUnlock() + + conn.sendMessage(reply) } } @@ -207,12 +204,14 @@ func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) erro if len(values) > 0 { msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...)) } - conn.outLck.RLock() - defer conn.outLck.RUnlock() - if conn.closed { + + var closed bool + conn.sendMessageAndIfClosed(msg, func() { + closed = true + }) + if closed { return ErrClosed } - conn.out <- msg return nil } diff --git a/vendor/github.com/godbus/dbus/go.mod b/vendor/github.com/godbus/dbus/go.mod new file mode 100644 index 00000000000..bdcd12598b4 --- /dev/null +++ b/vendor/github.com/godbus/dbus/go.mod @@ -0,0 +1 @@ +module github.com/godbus/dbus diff --git a/vendor/github.com/godbus/dbus/object.go b/vendor/github.com/godbus/dbus/object.go index 6d95583d767..f27ffe144a8 100644 --- a/vendor/github.com/godbus/dbus/object.go +++ b/vendor/github.com/godbus/dbus/object.go @@ -1,6 +1,7 @@ package dbus import ( + "context" "errors" "strings" ) @@ -9,7 +10,11 @@ import ( // invoked. type BusObject interface { Call(method string, flags Flags, args ...interface{}) *Call + CallWithContext(ctx context.Context, method string, flags Flags, args ...interface{}) *Call Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call + GoWithContext(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call + AddMatchSignal(iface, member string, options ...MatchOption) *Call + RemoveMatchSignal(iface, member string, options ...MatchOption) *Call GetProperty(p string) (Variant, error) Destination() string Path() ObjectPath @@ -24,16 +29,73 @@ type Object struct { // Call calls a method with (*Object).Go and waits for its reply. func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call { - return <-o.Go(method, flags, make(chan *Call, 1), args...).Done + return <-o.createCall(context.Background(), method, flags, make(chan *Call, 1), args...).Done } -// AddMatchSignal subscribes BusObject to signals from specified interface and -// method (member). -func (o *Object) AddMatchSignal(iface, member string) *Call { - return o.Call( +// CallWithContext acts like Call but takes a context +func (o *Object) CallWithContext(ctx context.Context, method string, flags Flags, args ...interface{}) *Call { + return <-o.createCall(ctx, method, flags, make(chan *Call, 1), args...).Done +} + +// MatchOption specifies option for dbus routing match rule. Options can be constructed with WithMatch* helpers. +// For full list of available options consult +// https://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-routing-match-rules +type MatchOption struct { + key string + value string +} + +// WithMatchOption creates match option with given key and value +func WithMatchOption(key, value string) MatchOption { + return MatchOption{key, value} +} + +// WithMatchObjectPath creates match option that filters events based on given path +func WithMatchObjectPath(path ObjectPath) MatchOption { + return MatchOption{"path", string(path)} +} + +func formatMatchOptions(options []MatchOption) string { + items := make([]string, 0, len(options)) + for _, option := range options { + items = append(items, option.key+"='"+option.value+"'") + } + + return strings.Join(items, ",") +} + +// AddMatchSignal subscribes BusObject to signals from specified interface, +// method (member). Additional filter rules can be added via WithMatch* option constructors. +// Note: To filter events by object path you have to specify this path via an option. +func (o *Object) AddMatchSignal(iface, member string, options ...MatchOption) *Call { + base := []MatchOption{ + {"type", "signal"}, + {"interface", iface}, + {"member", member}, + } + + options = append(base, options...) + return o.conn.BusObject().Call( "org.freedesktop.DBus.AddMatch", 0, - "type='signal',interface='"+iface+"',member='"+member+"'", + formatMatchOptions(options), + ) +} + +// RemoveMatchSignal unsubscribes BusObject from signals from specified interface, +// method (member). Additional filter rules can be added via WithMatch* option constructors +func (o *Object) RemoveMatchSignal(iface, member string, options ...MatchOption) *Call { + base := []MatchOption{ + {"type", "signal"}, + {"interface", iface}, + {"member", member}, + } + + options = append(base, options...) + return o.conn.BusObject().Call( + "org.freedesktop.DBus.RemoveMatch", + 0, + formatMatchOptions(options), ) } @@ -49,6 +111,18 @@ func (o *Object) AddMatchSignal(iface, member string) *Call { // If the method parameter contains a dot ('.'), the part before the last dot // specifies the interface on which the method is called. func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call { + return o.createCall(context.Background(), method, flags, ch, args...) +} + +// GoWithContext acts like Go but takes a context +func (o *Object) GoWithContext(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call { + return o.createCall(ctx, method, flags, ch, args...) +} + +func (o *Object) createCall(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call { + if ctx == nil { + panic("nil context") + } iface := "" i := strings.LastIndex(method, ".") if i != -1 { @@ -76,28 +150,28 @@ func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface } else if cap(ch) == 0 { panic("dbus: unbuffered channel passed to (*Object).Go") } + ctx, cancel := context.WithCancel(ctx) call := &Call{ Destination: o.dest, Path: o.path, Method: method, Args: args, Done: ch, + ctxCanceler: cancel, + ctx: ctx, } - o.conn.callsLck.Lock() - o.conn.calls[msg.serial] = call - o.conn.callsLck.Unlock() - o.conn.outLck.RLock() - if o.conn.closed { - call.Err = ErrClosed - call.Done <- call - } else { - o.conn.out <- msg - } - o.conn.outLck.RUnlock() + o.conn.calls.track(msg.serial, call) + o.conn.sendMessageAndIfClosed(msg, func() { + o.conn.calls.handleSendError(msg, ErrClosed) + cancel() + }) + go func() { + <-ctx.Done() + o.conn.calls.handleSendError(msg, ctx.Err()) + }() + return call } - o.conn.outLck.RLock() - defer o.conn.outLck.RUnlock() done := make(chan *Call, 1) call := &Call{ Err: nil, @@ -107,11 +181,9 @@ func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface call.Done <- call close(done) }() - if o.conn.closed { + o.conn.sendMessageAndIfClosed(msg, func() { call.Err = ErrClosed - return call - } - o.conn.out <- msg + }) return call } diff --git a/vendor/github.com/godbus/dbus/server_interfaces.go b/vendor/github.com/godbus/dbus/server_interfaces.go index 091948aef71..01166f0bd2a 100644 --- a/vendor/github.com/godbus/dbus/server_interfaces.go +++ b/vendor/github.com/godbus/dbus/server_interfaces.go @@ -87,3 +87,13 @@ type SignalHandler interface { type DBusError interface { DBusError() (string, []interface{}) } + +// SerialGenerator is responsible for serials generation. +// +// Different approaches for the serial generation can be used, +// maintaining a map guarded with a mutex (the standard way) or +// simply increment an atomic counter. +type SerialGenerator interface { + GetSerial() uint32 + RetireSerial(serial uint32) +} diff --git a/vendor/github.com/godbus/dbus/transport_generic.go b/vendor/github.com/godbus/dbus/transport_generic.go index 3fad859a6b8..718a1ff0219 100644 --- a/vendor/github.com/godbus/dbus/transport_generic.go +++ b/vendor/github.com/godbus/dbus/transport_generic.go @@ -11,7 +11,7 @@ var nativeEndian binary.ByteOrder func detectEndianness() binary.ByteOrder { var x uint32 = 0x01020304 - if *(*byte)(unsafe.Pointer(&x)) == 0x01 { + if *(*byte)(unsafe.Pointer(&x)) == 0x01 { return binary.BigEndian } return binary.LittleEndian diff --git a/vendor/github.com/godbus/dbus/transport_nonce_tcp.go b/vendor/github.com/godbus/dbus/transport_nonce_tcp.go new file mode 100644 index 00000000000..697739efafb --- /dev/null +++ b/vendor/github.com/godbus/dbus/transport_nonce_tcp.go @@ -0,0 +1,39 @@ +//+build !windows + +package dbus + +import ( + "errors" + "io/ioutil" + "net" +) + +func init() { + transports["nonce-tcp"] = newNonceTcpTransport +} + +func newNonceTcpTransport(keys string) (transport, error) { + host := getKey(keys, "host") + port := getKey(keys, "port") + noncefile := getKey(keys, "noncefile") + if host == "" || port == "" || noncefile == "" { + return nil, errors.New("dbus: unsupported address (must set host, port and noncefile)") + } + protocol, err := tcpFamily(keys) + if err != nil { + return nil, err + } + socket, err := net.Dial(protocol, net.JoinHostPort(host, port)) + if err != nil { + return nil, err + } + b, err := ioutil.ReadFile(noncefile) + if err != nil { + return nil, err + } + _, err = socket.Write(b) + if err != nil { + return nil, err + } + return NewConn(socket) +} diff --git a/vendor/github.com/godbus/dbus/transport_unix.go b/vendor/github.com/godbus/dbus/transport_unix.go index e56d5ca90aa..f000c6b5d45 100644 --- a/vendor/github.com/godbus/dbus/transport_unix.go +++ b/vendor/github.com/godbus/dbus/transport_unix.go @@ -31,6 +31,7 @@ func (o *oobReader) Read(b []byte) (n int, err error) { type unixTransport struct { *net.UnixConn + rdr *oobReader hasUnixFDs bool } @@ -79,10 +80,15 @@ func (t *unixTransport) ReadMessage() (*Message, error) { // To be sure that all bytes of out-of-band data are read, we use a special // reader that uses ReadUnix on the underlying connection instead of Read // and gathers the out-of-band data in a buffer. - rd := &oobReader{conn: t.UnixConn} + if t.rdr == nil { + t.rdr = &oobReader{conn: t.UnixConn} + } else { + t.rdr.oob = nil + } + // read the first 16 bytes (the part of the header that has a constant size), // from which we can figure out the length of the rest of the message - if _, err := io.ReadFull(rd, csheader[:]); err != nil { + if _, err := io.ReadFull(t.rdr, csheader[:]); err != nil { return nil, err } switch csheader[0] { @@ -104,7 +110,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) { // decode headers and look for unix fds headerdata := make([]byte, hlen+4) copy(headerdata, csheader[12:]) - if _, err := io.ReadFull(t, headerdata[4:]); err != nil { + if _, err := io.ReadFull(t.rdr, headerdata[4:]); err != nil { return nil, err } dec := newDecoder(bytes.NewBuffer(headerdata), order) @@ -122,7 +128,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) { all := make([]byte, 16+hlen+blen) copy(all, csheader[:]) copy(all[16:], headerdata[4:]) - if _, err := io.ReadFull(rd, all[16+hlen:]); err != nil { + if _, err := io.ReadFull(t.rdr, all[16+hlen:]); err != nil { return nil, err } if unixfds != 0 { @@ -130,7 +136,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) { return nil, errors.New("dbus: got unix fds on unsupported transport") } // read the fds from the OOB data - scms, err := syscall.ParseSocketControlMessage(rd.oob) + scms, err := syscall.ParseSocketControlMessage(t.rdr.oob) if err != nil { return nil, err } @@ -148,11 +154,23 @@ func (t *unixTransport) ReadMessage() (*Message, error) { // substitute the values in the message body (which are indices for the // array receiver via OOB) with the actual values for i, v := range msg.Body { - if j, ok := v.(UnixFDIndex); ok { + switch v.(type) { + case UnixFDIndex: + j := v.(UnixFDIndex) if uint32(j) >= unixfds { return nil, InvalidMessageError("invalid index for unix fd") } msg.Body[i] = UnixFD(fds[j]) + case []UnixFDIndex: + idxArray := v.([]UnixFDIndex) + fdArray := make([]UnixFD, len(idxArray)) + for k, j := range idxArray { + if uint32(j) >= unixfds { + return nil, InvalidMessageError("invalid index for unix fd") + } + fdArray[k] = UnixFD(fds[j]) + } + msg.Body[i] = fdArray } } return msg, nil diff --git a/vendor/modules.txt b/vendor/modules.txt index 5e67ddc2ea2..8b55c56a102 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -388,7 +388,7 @@ github.com/go-openapi/validate # github.com/go-ozzo/ozzo-validation v3.5.0+incompatible => github.com/go-ozzo/ozzo-validation v3.5.0+incompatible github.com/go-ozzo/ozzo-validation github.com/go-ozzo/ozzo-validation/is -# github.com/godbus/dbus v4.1.0+incompatible => github.com/godbus/dbus v4.1.0+incompatible +# github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f => github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f github.com/godbus/dbus # github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d => github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d github.com/gogo/protobuf/gogoproto