From 8b9dc69f1f8c416d6c61bbd97bb62ecb7a7cf77d Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 14 Dec 2021 22:46:38 -0800 Subject: [PATCH 1/5] kubelet/cm: speed up cgroup creation There's no need to call m.Update (which will create another instance of libcontainer cgroup manager, convert all the resources and then set them). All this is already done here, except for Set(). Signed-off-by: Kir Kolyshkin pkg/kubelet/cm: rm dup code Commit ecd6361f added setting PidsLimit to Create and Update. Commit bce9d5f2 added setting PidsLimit to m.toResources. Now, PidsLimit is assigned twice. Remove the duplicate. Fixes: bce9d5f2 Signed-off-by: Kir Kolyshkin pkg/kubelet/cm: ToSystemd: nit Remove the second condition as it can't ever be true (this was obviously written by a C programmer). Fixes: b230fb8ac407 Signed-off-by: Kir Kolyshkin pkg/kubelet/cm/cgroup_manager: simplify setting hugetlb Commit 79be8be10edba made hugetlb settings optional if cgroup v2 is used and hugetlb is not available, fixing issue 92933. Note at that time this was only needed for v2, because for v1 the resources were set one-by-one, and only for supported resources. Commit d312ef7eb6730099 switched the code to using Set from runc/libcontainer cgroups manager, and expanded the check to cgroup v1 as well. Move this check earlier, to inside m.toResources, so instead of converting all hugetlb resources from ResourceConfig to libcontainers's Resources.HugetlbLimit, and then setting it to nil, we can skip the conversion entirely if hugetlb is not supported, thus not doing the work that is not needed. Signed-off-by: Kir Kolyshkin pkg/kubelet/cm: move common code to libctCgroupConfig Instead of doing (almost) the same thing from the three different methods (Create, Update, Destroy), move the functionality to libctCgroupConfig, replacing updateSystemdCgroupInfo. The needResources bool is needed because we do not need resources during Destroy, so we skip the unneeded resource conversion. Signed-off-by: Kir Kolyshkin pkg/kubelet/cm: simplify enforceExistingCgroup 1. Move the rl == nil check to before we dereference it. 2. Remove Exists check before Update, since it is complicated, and Update will return a meaningful error anyway in case the cgroup does not exist. Signed-off-by: Kir Kolyshkin deps: update runc to 1.1.0 This updates vendored runc/libcontainer to 1.1.0, and google/cadvisor to a version updated to runc 1.1.0-rc1 (https://github.com/google/cadvisor/pull/3031). Changes in vendor are generated by (roughly): ./hack/pin-dependency.sh github.com/google/cadvisor a3b5f4f6c501d5a4ac67530bc973a05c1ebd7d8c ./hack/pin-dependency.sh github.com/opencontainers/runc v1.1.0 ./hack/update-vendor.sh ./hack/lint-dependencies.sh # And follow all its recommendations. ./hack/update-vendor.sh ./hack/update-internal-modules.sh ./hack/lint-dependencies.sh # Re-check everything again. The changes (mostly in pkg/kubelet/cm) are there to adopt changed runc 1.1 API, and simplify things a bit. In particular: 1. simplify cgroup manager instantiation, using a new, easier way of libcontainers/cgroups/manager.New; 2. replace libcontainerAdapter with a boolean variable (all it did was passing on whether systemd manager should be used); 3. trivial change due to removed cgroupfs.HugePageSizes and added cgroups.HugePageSizes(); 4. do not calculate cgroup paths in update / destroy, since libcontainer cgroup managers now calculate the paths upon creation (previously, they were doing that only in Apply, so using e.g. Set or Destroy right after creation was impossible without specifying paths). We currently still calculate cgroup paths in Exists -- this is to be addressed separately. Signed-off-by: Kir Kolyshkin --- .../github.com/bits-and-blooms/bitset/LICENSE | 31 - cmd/kubelet/app/server.go | 2 +- go.mod | 31 +- go.sum | 46 +- pkg/kubelet/cm/cgroup_manager_linux.go | 228 ++--- pkg/kubelet/cm/container_manager_linux.go | 12 +- pkg/kubelet/cm/helpers_linux.go | 4 +- pkg/kubelet/cm/helpers_unsupported.go | 2 +- .../cm/node_container_manager_linux.go | 9 +- .../cm/pod_container_manager_linux_test.go | 20 +- pkg/kubelet/cm/qos_container_manager_linux.go | 5 +- .../cm/qos_container_manager_linux_test.go | 2 +- .../kuberuntime_container_linux.go | 3 +- .../kuberuntime_container_linux_test.go | 6 +- test/e2e_node/node_container_manager_test.go | 2 +- .../bits-and-blooms/bitset/.gitignore | 26 - .../bits-and-blooms/bitset/.travis.yml | 37 - .../github.com/bits-and-blooms/bitset/LICENSE | 27 - .../bits-and-blooms/bitset/README.md | 93 -- .../bitset/azure-pipelines.yml | 39 - .../bits-and-blooms/bitset/bitset.go | 952 ------------------ .../github.com/bits-and-blooms/bitset/go.mod | 3 - .../github.com/bits-and-blooms/bitset/go.sum | 0 .../bits-and-blooms/bitset/popcnt.go | 53 - .../bits-and-blooms/bitset/popcnt_19.go | 45 - .../bits-and-blooms/bitset/popcnt_amd64.go | 68 -- .../bits-and-blooms/bitset/popcnt_amd64.s | 104 -- .../bits-and-blooms/bitset/popcnt_generic.go | 24 - .../bitset/trailing_zeros_18.go | 14 - .../bitset/trailing_zeros_19.go | 9 - .../checkpoint-restore/go-criu/v5/.gitignore | 6 +- .../checkpoint-restore/go-criu/v5/Makefile | 68 +- .../checkpoint-restore/go-criu/v5/README.md | 3 +- .../checkpoint-restore/go-criu/v5/features.go | 45 + .../checkpoint-restore/go-criu/v5/go.mod | 3 +- .../checkpoint-restore/go-criu/v5/go.sum | 24 +- .../checkpoint-restore/go-criu/v5/main.go | 14 +- .../go-criu/v5/rpc/rpc.pb.go | 221 ++-- .../go-criu/v5/rpc/rpc.proto | 239 +++++ vendor/github.com/cilium/ebpf/.gitignore | 1 + vendor/github.com/cilium/ebpf/.golangci.yaml | 1 - vendor/github.com/cilium/ebpf/ARCHITECTURE.md | 4 +- vendor/github.com/cilium/ebpf/CONTRIBUTING.md | 4 +- vendor/github.com/cilium/ebpf/Makefile | 5 +- vendor/github.com/cilium/ebpf/README.md | 62 +- vendor/github.com/cilium/ebpf/asm/func.go | 6 + .../github.com/cilium/ebpf/asm/func_string.go | 10 +- .../github.com/cilium/ebpf/asm/instruction.go | 5 + .../cilium/ebpf/attachtype_string.go | 65 ++ vendor/github.com/cilium/ebpf/collection.go | 508 +++++----- vendor/github.com/cilium/ebpf/elf_reader.go | 180 +++- .../github.com/cilium/ebpf/elf_reader_fuzz.go | 1 + vendor/github.com/cilium/ebpf/go.mod | 4 +- vendor/github.com/cilium/ebpf/go.sum | 4 +- vendor/github.com/cilium/ebpf/info.go | 36 +- .../github.com/cilium/ebpf/internal/align.go | 6 + .../cilium/ebpf/internal/btf/btf.go | 293 +++--- .../cilium/ebpf/internal/btf/btf_types.go | 11 +- .../cilium/ebpf/internal/btf/core.go | 33 +- .../cilium/ebpf/internal/btf/ext_info.go | 15 +- .../cilium/ebpf/internal/btf/fuzz.go | 1 + .../cilium/ebpf/internal/btf/info.go | 48 + .../cilium/ebpf/internal/btf/strings.go | 8 +- .../cilium/ebpf/internal/btf/syscalls.go | 31 + .../cilium/ebpf/internal/btf/types.go | 188 ++-- vendor/github.com/cilium/ebpf/internal/cpu.go | 4 +- .../cilium/ebpf/internal/ptr_32_be.go | 1 + .../cilium/ebpf/internal/ptr_32_le.go | 1 + .../github.com/cilium/ebpf/internal/ptr_64.go | 4 +- .../cilium/ebpf/internal/syscall.go | 59 ++ .../cilium/ebpf/internal/unix/types_linux.go | 16 +- .../cilium/ebpf/internal/unix/types_other.go | 14 +- .../cilium/ebpf/internal/version.go | 4 +- .../github.com/cilium/ebpf/link/freplace.go | 88 ++ vendor/github.com/cilium/ebpf/link/kprobe.go | 38 +- vendor/github.com/cilium/ebpf/link/link.go | 14 +- .../github.com/cilium/ebpf/link/perf_event.go | 7 +- .../github.com/cilium/ebpf/link/syscalls.go | 9 +- .../github.com/cilium/ebpf/link/tracepoint.go | 8 +- vendor/github.com/cilium/ebpf/link/uprobe.go | 133 ++- vendor/github.com/cilium/ebpf/linker.go | 23 +- vendor/github.com/cilium/ebpf/map.go | 95 +- vendor/github.com/cilium/ebpf/marshalers.go | 63 +- vendor/github.com/cilium/ebpf/prog.go | 123 ++- vendor/github.com/cilium/ebpf/run-tests.sh | 22 +- vendor/github.com/cilium/ebpf/syscalls.go | 94 +- vendor/github.com/cilium/ebpf/types.go | 36 +- vendor/github.com/cilium/ebpf/types_string.go | 69 +- .../containerd/console/console_windows.go | 10 +- .../containerd/console/console_zos.go | 163 +++ vendor/github.com/containerd/console/go.mod | 5 +- vendor/github.com/containerd/console/go.sum | 2 - .../github.com/containerd/console/tc_unix.go | 2 +- .../github.com/containerd/console/tc_zos.go | 26 + .../cyphar/filepath-securejoin/.travis.yml | 8 +- .../cyphar/filepath-securejoin/README.md | 20 +- .../cyphar/filepath-securejoin/VERSION | 2 +- .../cyphar/filepath-securejoin/go.mod | 3 + .../cyphar/filepath-securejoin/join.go | 25 +- .../cyphar/filepath-securejoin/vendor.conf | 1 - .../dbus/v5/{README.markdown => README.md} | 12 +- vendor/github.com/godbus/dbus/v5/auth.go | 15 +- vendor/github.com/godbus/dbus/v5/conn.go | 36 +- vendor/github.com/godbus/dbus/v5/decoder.go | 16 +- vendor/github.com/godbus/dbus/v5/encoder.go | 61 +- vendor/github.com/godbus/dbus/v5/export.go | 37 +- vendor/github.com/godbus/dbus/v5/message.go | 73 +- vendor/github.com/godbus/dbus/v5/sig.go | 66 +- .../godbus/dbus/v5/transport_generic.go | 10 +- .../godbus/dbus/v5/transport_unix.go | 24 +- .../dbus/v5/transport_unixcred_netbsd.go | 14 + .../cadvisor/container/common/helpers.go | 10 +- .../container/libcontainer/handler.go | 4 +- .../container/libcontainer/helpers.go | 11 +- vendor/github.com/google/cadvisor/fs/fs.go | 4 - vendor/github.com/google/cadvisor/fs/types.go | 9 +- .../google/cadvisor/manager/container.go | 3 +- .../google/cadvisor/manager/manager.go | 2 +- .../google/cadvisor/resctrl/utils.go | 2 +- vendor/github.com/moby/sys/mountinfo/go.mod | 4 +- vendor/github.com/moby/sys/mountinfo/go.sum | 4 +- .../moby/sys/mountinfo/mounted_linux.go | 11 +- .../moby/sys/mountinfo/mounted_unix.go | 16 +- .../moby/sys/mountinfo/mountinfo.go | 9 +- .../moby/sys/mountinfo/mountinfo_bsd.go | 9 +- .../moby/sys/mountinfo/mountinfo_linux.go | 27 +- .../sys/mountinfo/mountinfo_unsupported.go | 3 +- .../libcontainer/apparmor/apparmor_linux.go | 5 +- .../apparmor/apparmor_unsupported.go | 1 + .../libcontainer/capabilities/capabilities.go | 12 + .../capabilities/capabilities_unsupported.go | 1 + .../runc/libcontainer/cgroups/cgroups.go | 2 - .../cgroups/cgroups_unsupported.go | 3 - .../cgroups/devices/devices_emulator.go | 66 +- .../cgroups/ebpf/devicefilter/devicefilter.go | 22 +- .../libcontainer/cgroups/ebpf/ebpf_linux.go | 4 +- .../runc/libcontainer/cgroups/file.go | 60 +- .../runc/libcontainer/cgroups/fs/blkio.go | 18 +- .../runc/libcontainer/cgroups/fs/cpu.go | 22 +- .../runc/libcontainer/cgroups/fs/cpuacct.go | 46 +- .../runc/libcontainer/cgroups/fs/cpuset.go | 47 +- .../runc/libcontainer/cgroups/fs/devices.go | 13 +- .../runc/libcontainer/cgroups/fs/error.go | 15 + .../runc/libcontainer/cgroups/fs/freezer.go | 6 +- .../runc/libcontainer/cgroups/fs/fs.go | 318 ++---- .../runc/libcontainer/cgroups/fs/hugetlb.go | 17 +- .../runc/libcontainer/cgroups/fs/memory.go | 56 +- .../runc/libcontainer/cgroups/fs/name.go | 8 +- .../runc/libcontainer/cgroups/fs/net_cls.go | 6 +- .../runc/libcontainer/cgroups/fs/net_prio.go | 6 +- .../runc/libcontainer/cgroups/fs/paths.go | 186 ++++ .../libcontainer/cgroups/fs/perf_event.go | 6 +- .../runc/libcontainer/cgroups/fs/pids.go | 28 +- .../runc/libcontainer/cgroups/fs/rdma.go | 25 + .../libcontainer/cgroups/fs/unsupported.go | 3 - .../runc/libcontainer/cgroups/fs2/cpu.go | 10 +- .../runc/libcontainer/cgroups/fs2/cpuset.go | 2 - .../libcontainer/cgroups/fs2/defaultpath.go | 26 +- .../runc/libcontainer/cgroups/fs2/devices.go | 11 +- .../runc/libcontainer/cgroups/fs2/freezer.go | 18 +- .../runc/libcontainer/cgroups/fs2/fs2.go | 52 +- .../runc/libcontainer/cgroups/fs2/hugetlb.go | 10 +- .../runc/libcontainer/cgroups/fs2/io.go | 13 +- .../runc/libcontainer/cgroups/fs2/memory.go | 29 +- .../runc/libcontainer/cgroups/fs2/pids.go | 29 +- .../libcontainer/cgroups/fscommon/rdma.go | 121 +++ .../libcontainer/cgroups/fscommon/utils.go | 34 +- .../runc/libcontainer/cgroups/getallpids.go | 27 + .../runc/libcontainer/cgroups/manager/new.go | 78 ++ .../runc/libcontainer/cgroups/stats.go | 16 +- .../libcontainer/cgroups/systemd/common.go | 34 +- .../libcontainer/cgroups/systemd/cpuset.go | 28 +- .../runc/libcontainer/cgroups/systemd/dbus.go | 2 - .../cgroups/systemd/unsupported.go | 71 -- .../runc/libcontainer/cgroups/systemd/user.go | 18 +- .../runc/libcontainer/cgroups/systemd/v1.go | 139 +-- .../runc/libcontainer/cgroups/systemd/v2.go | 156 +-- .../runc/libcontainer/cgroups/utils.go | 115 ++- .../runc/libcontainer/cgroups/v1_utils.go | 19 +- .../runc/libcontainer/configs/cgroup_linux.go | 20 +- .../configs/cgroup_unsupported.go | 1 + .../runc/libcontainer/configs/config.go | 34 +- .../runc/libcontainer/configs/config_linux.go | 17 +- .../libcontainer/configs/configs_fuzzer.go | 1 + .../runc/libcontainer/configs/intelrdt.go | 3 + .../runc/libcontainer/configs/mount.go | 9 + .../configs/namespaces_syscall.go | 1 + .../configs/namespaces_syscall_unsupported.go | 1 + .../configs/namespaces_unsupported.go | 1 + .../runc/libcontainer/configs/rdma.go | 9 + .../configs/validate/validator.go | 61 +- .../runc/libcontainer/console_linux.go | 2 +- .../runc/libcontainer/container.go | 43 - .../runc/libcontainer/container_linux.go | 317 +++--- .../runc/libcontainer/criu_opts_linux.go | 1 + .../runc/libcontainer/devices/device_unix.go | 12 +- .../opencontainers/runc/libcontainer/error.go | 77 +- .../runc/libcontainer/factory.go | 14 - .../runc/libcontainer/factory_linux.go | 252 ++--- .../runc/libcontainer/generic_error.go | 92 -- .../runc/libcontainer/init_linux.go | 110 +- .../runc/libcontainer/intelrdt/intelrdt.go | 241 ++--- .../runc/libcontainer/intelrdt/mbm.go | 2 - .../runc/libcontainer/intelrdt/monitoring.go | 3 +- .../runc/libcontainer/intelrdt/stats.go | 4 +- .../runc/libcontainer/keys/keyctl.go | 8 +- .../runc/libcontainer/logs/logs.go | 80 +- .../runc/libcontainer/message_linux.go | 3 +- .../runc/libcontainer/mount_linux.go | 83 ++ .../runc/libcontainer/network_linux.go | 6 +- .../runc/libcontainer/notify_linux.go | 5 +- ...{notify_linux_v2.go => notify_v2_linux.go} | 12 +- .../runc/libcontainer/process.go | 19 +- .../runc/libcontainer/process_linux.go | 215 ++-- .../runc/libcontainer/restored_process.go | 15 +- .../runc/libcontainer/rootfs_linux.go | 250 +++-- .../runc/libcontainer/seccomp/config.go | 51 +- .../seccomp/patchbpf/enosys_linux.go | 114 ++- .../seccomp/patchbpf/enosys_unsupported.go | 1 + .../libcontainer/seccomp/seccomp_linux.go | 111 +- .../seccomp/seccomp_unsupported.go | 10 +- .../runc/libcontainer/setns_init_linux.go | 39 +- .../runc/libcontainer/stacktrace/capture.go | 27 - .../runc/libcontainer/stacktrace/frame.go | 38 - .../libcontainer/stacktrace/stacktrace.go | 5 - .../runc/libcontainer/standard_init_linux.go | 109 +- .../runc/libcontainer/state_linux.go | 8 +- .../opencontainers/runc/libcontainer/sync.go | 57 +- .../runc/libcontainer/system/linux.go | 12 +- .../runc/libcontainer/system/proc.go | 72 +- .../libcontainer/system/syscall_linux_32.go | 1 + .../libcontainer/system/syscall_linux_64.go | 1 + .../runc/libcontainer/system/xattrs_linux.go | 35 - .../runc/libcontainer/user/lookup_unix.go | 1 + .../runc/libcontainer/user/user.go | 21 +- .../runc/libcontainer/user/user_fuzzer.go | 1 + .../runc/libcontainer/userns/userns_fuzzer.go | 1 + .../libcontainer/userns/userns_unsupported.go | 1 + .../runc/libcontainer/utils/cmsg.go | 11 +- .../runc/libcontainer/utils/utils.go | 14 +- .../runc/libcontainer/utils/utils_unix.go | 5 +- .../selinux/go-selinux/label/label_linux.go | 13 +- .../selinux/go-selinux/rchcon.go | 22 + .../selinux/go-selinux/rchcon_go115.go | 21 + .../selinux/go-selinux/selinux.go | 26 +- .../selinux/go-selinux/selinux_linux.go | 286 +++--- .../selinux/go-selinux/selinux_stub.go | 14 +- .../selinux/go-selinux/xattrs_linux.go | 37 +- .../selinux/pkg/pwalk/README.md | 6 + .../opencontainers/selinux/pkg/pwalk/pwalk.go | 21 +- .../selinux/pkg/pwalkdir/README.md | 54 + .../selinux/pkg/pwalkdir/pwalkdir.go | 116 +++ .../seccomp/libseccomp-golang/.travis.yml | 57 ++ .../{SUBMITTING_PATCHES => CONTRIBUTING.md} | 92 +- .../seccomp/libseccomp-golang/Makefile | 8 +- .../libseccomp-golang/{README => README.md} | 26 +- .../seccomp/libseccomp-golang/go.mod | 3 + .../seccomp/libseccomp-golang/go.sum | 23 + .../seccomp/libseccomp-golang/seccomp.go | 305 ++++-- .../libseccomp-golang/seccomp_internal.go | 313 +++++- vendor/modules.txt | 50 +- 261 files changed, 6605 insertions(+), 5452 deletions(-) delete mode 100644 LICENSES/vendor/github.com/bits-and-blooms/bitset/LICENSE delete mode 100644 vendor/github.com/bits-and-blooms/bitset/.gitignore delete mode 100644 vendor/github.com/bits-and-blooms/bitset/.travis.yml delete mode 100644 vendor/github.com/bits-and-blooms/bitset/LICENSE delete mode 100644 vendor/github.com/bits-and-blooms/bitset/README.md delete mode 100644 vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml delete mode 100644 vendor/github.com/bits-and-blooms/bitset/bitset.go delete mode 100644 vendor/github.com/bits-and-blooms/bitset/go.mod delete mode 100644 vendor/github.com/bits-and-blooms/bitset/go.sum delete mode 100644 vendor/github.com/bits-and-blooms/bitset/popcnt.go delete mode 100644 vendor/github.com/bits-and-blooms/bitset/popcnt_19.go delete mode 100644 vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go delete mode 100644 vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s delete mode 100644 vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go delete mode 100644 vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go delete mode 100644 vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go create mode 100644 vendor/github.com/checkpoint-restore/go-criu/v5/features.go create mode 100644 vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.proto create mode 100644 vendor/github.com/cilium/ebpf/attachtype_string.go create mode 100644 vendor/github.com/cilium/ebpf/internal/align.go create mode 100644 vendor/github.com/cilium/ebpf/internal/btf/info.go create mode 100644 vendor/github.com/cilium/ebpf/internal/btf/syscalls.go create mode 100644 vendor/github.com/cilium/ebpf/link/freplace.go create mode 100644 vendor/github.com/containerd/console/console_zos.go create mode 100644 vendor/github.com/containerd/console/tc_zos.go create mode 100644 vendor/github.com/cyphar/filepath-securejoin/go.mod delete mode 100644 vendor/github.com/cyphar/filepath-securejoin/vendor.conf rename vendor/github.com/godbus/dbus/v5/{README.markdown => README.md} (81%) create mode 100644 vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups_unsupported.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/error.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/paths.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/rdma.go delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/unsupported.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/rdma.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cgroups/getallpids.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cgroups/manager/new.go delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/unsupported.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/configs/rdma.go delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/generic_error.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/mount_linux.go rename vendor/github.com/opencontainers/runc/libcontainer/{notify_linux_v2.go => notify_v2_linux.go} (87%) delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/stacktrace/frame.go delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/stacktrace/stacktrace.go delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/system/xattrs_linux.go create mode 100644 vendor/github.com/opencontainers/selinux/go-selinux/rchcon.go create mode 100644 vendor/github.com/opencontainers/selinux/go-selinux/rchcon_go115.go create mode 100644 vendor/github.com/opencontainers/selinux/pkg/pwalkdir/README.md create mode 100644 vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go create mode 100644 vendor/github.com/seccomp/libseccomp-golang/.travis.yml rename vendor/github.com/seccomp/libseccomp-golang/{SUBMITTING_PATCHES => CONTRIBUTING.md} (69%) rename vendor/github.com/seccomp/libseccomp-golang/{README => README.md} (68%) create mode 100644 vendor/github.com/seccomp/libseccomp-golang/go.mod create mode 100644 vendor/github.com/seccomp/libseccomp-golang/go.sum diff --git a/LICENSES/vendor/github.com/bits-and-blooms/bitset/LICENSE b/LICENSES/vendor/github.com/bits-and-blooms/bitset/LICENSE deleted file mode 100644 index 987cea60a4c61..0000000000000 --- a/LICENSES/vendor/github.com/bits-and-blooms/bitset/LICENSE +++ /dev/null @@ -1,31 +0,0 @@ -= vendor/github.com/bits-and-blooms/bitset licensed under: = - -Copyright (c) 2014 Will Fitzgerald. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -= vendor/github.com/bits-and-blooms/bitset/LICENSE 0d2b5d66dabaff0df8e1ffe191a21bd1 diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go index 6e2934d64663e..df00bf97e7322 100644 --- a/cmd/kubelet/app/server.go +++ b/cmd/kubelet/app/server.go @@ -603,7 +603,7 @@ func run(ctx context.Context, s *options.KubeletServer, kubeDeps *kubelet.Depend } var cgroupRoots []string - nodeAllocatableRoot := cm.NodeAllocatableRoot(s.CgroupRoot, s.CgroupsPerQOS, s.CgroupDriver) + nodeAllocatableRoot := cm.NodeAllocatableRoot(s.CgroupRoot, s.CgroupsPerQOS, s.CgroupDriver == "systemd") cgroupRoots = append(cgroupRoots, nodeAllocatableRoot) kubeletCgroup, err := cm.GetKubeletContainer(s.KubeletCgroups) if err != nil { diff --git a/go.mod b/go.mod index 8e25299162fbf..99e533b3a7932 100644 --- a/go.mod +++ b/go.mod @@ -39,12 +39,12 @@ require ( github.com/fsnotify/fsnotify v1.4.9 github.com/go-logr/logr v1.2.0 github.com/go-ozzo/ozzo-validation v3.5.0+incompatible // indirect - github.com/godbus/dbus/v5 v5.0.4 + github.com/godbus/dbus/v5 v5.0.6 github.com/gogo/protobuf v1.3.2 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da github.com/golang/mock v1.5.0 github.com/golang/protobuf v1.5.2 - github.com/google/cadvisor v0.43.0 + github.com/google/cadvisor v0.43.1-0.20220111033110-a3b5f4f6c501 github.com/google/go-cmp v0.5.5 github.com/google/gofuzz v1.1.0 github.com/google/uuid v1.1.2 @@ -62,8 +62,8 @@ require ( github.com/mvdan/xurls v1.1.0 github.com/onsi/ginkgo v1.14.0 github.com/onsi/gomega v1.10.1 - github.com/opencontainers/runc v1.0.3 - github.com/opencontainers/selinux v1.8.2 + github.com/opencontainers/runc v1.1.0 + github.com/opencontainers/selinux v1.10.0 github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.0 github.com/prometheus/client_golang v1.12.0 @@ -181,7 +181,6 @@ replace ( github.com/benbjohnson/clock => github.com/benbjohnson/clock v1.1.0 github.com/beorn7/perks => github.com/beorn7/perks v1.0.1 github.com/bgentry/speakeasy => github.com/bgentry/speakeasy v0.1.0 - github.com/bits-and-blooms/bitset => github.com/bits-and-blooms/bitset v1.2.0 github.com/bketelsen/crypt => github.com/bketelsen/crypt v0.0.4 github.com/blang/semver => github.com/blang/semver v3.5.1+incompatible github.com/boltdb/bolt => github.com/boltdb/bolt v1.3.1 @@ -190,11 +189,11 @@ replace ( github.com/cespare/xxhash => github.com/cespare/xxhash v1.1.0 github.com/cespare/xxhash/v2 => github.com/cespare/xxhash/v2 v2.1.2 github.com/chai2010/gettext-go => github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 - github.com/checkpoint-restore/go-criu/v5 => github.com/checkpoint-restore/go-criu/v5 v5.0.0 + github.com/checkpoint-restore/go-criu/v5 => github.com/checkpoint-restore/go-criu/v5 v5.3.0 github.com/chzyer/logex => github.com/chzyer/logex v1.1.10 github.com/chzyer/readline => github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e github.com/chzyer/test => github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 - github.com/cilium/ebpf => github.com/cilium/ebpf v0.6.2 + github.com/cilium/ebpf => github.com/cilium/ebpf v0.7.0 github.com/clusterhq/flocker-go => github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313 github.com/cncf/udpa/go => github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 github.com/cncf/xds/go => github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed @@ -203,8 +202,8 @@ replace ( github.com/cockroachdb/logtags => github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f github.com/container-storage-interface/spec => github.com/container-storage-interface/spec v1.5.0 github.com/containerd/cgroups => github.com/containerd/cgroups v1.0.1 - github.com/containerd/console => github.com/containerd/console v1.0.2 - github.com/containerd/containerd => github.com/containerd/containerd v1.4.11 + github.com/containerd/console => github.com/containerd/console v1.0.3 + github.com/containerd/containerd => github.com/containerd/containerd v1.4.12 github.com/containerd/continuity => github.com/containerd/continuity v0.1.0 github.com/containerd/fifo => github.com/containerd/fifo v1.0.0 github.com/containerd/go-runc => github.com/containerd/go-runc v1.0.0 @@ -217,7 +216,7 @@ replace ( github.com/coreos/go-systemd/v22 => github.com/coreos/go-systemd/v22 v22.3.2 github.com/cpuguy83/go-md2man/v2 => github.com/cpuguy83/go-md2man/v2 v2.0.0 github.com/creack/pty => github.com/creack/pty v1.1.11 - github.com/cyphar/filepath-securejoin => github.com/cyphar/filepath-securejoin v0.2.2 + github.com/cyphar/filepath-securejoin => github.com/cyphar/filepath-securejoin v0.2.3 github.com/davecgh/go-spew => github.com/davecgh/go-spew v1.1.1 github.com/daviddengcn/go-colortext => github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd github.com/dnaeon/go-vcr => github.com/dnaeon/go-vcr v1.0.1 @@ -258,7 +257,7 @@ replace ( github.com/go-openapi/swag => github.com/go-openapi/swag v0.19.14 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/v5 => github.com/godbus/dbus/v5 v5.0.4 + github.com/godbus/dbus/v5 => github.com/godbus/dbus/v5 v5.0.6 github.com/gofrs/uuid => github.com/gofrs/uuid v4.0.0+incompatible github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.2 github.com/golang/freetype => github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 @@ -268,7 +267,7 @@ replace ( github.com/golang/protobuf => github.com/golang/protobuf v1.5.2 github.com/golangplus/testing => github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e github.com/google/btree => github.com/google/btree v1.0.1 - github.com/google/cadvisor => github.com/google/cadvisor v0.43.0 + github.com/google/cadvisor => github.com/google/cadvisor v0.43.1-0.20220111033110-a3b5f4f6c501 github.com/google/cel-go => github.com/google/cel-go v0.9.0 github.com/google/cel-spec => github.com/google/cel-spec v0.6.0 github.com/google/go-cmp => github.com/google/go-cmp v0.5.5 @@ -350,7 +349,7 @@ replace ( github.com/mitchellh/mapstructure => github.com/mitchellh/mapstructure v1.4.1 github.com/moby/ipvs => github.com/moby/ipvs v1.0.1 github.com/moby/spdystream => github.com/moby/spdystream v0.2.0 - github.com/moby/sys/mountinfo => github.com/moby/sys/mountinfo v0.4.1 + github.com/moby/sys/mountinfo => github.com/moby/sys/mountinfo v0.5.0 github.com/moby/term => github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 github.com/modern-go/concurrent => github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd github.com/modern-go/reflect2 => github.com/modern-go/reflect2 v1.0.2 @@ -369,9 +368,9 @@ replace ( github.com/onsi/gomega => github.com/onsi/gomega v1.10.1 github.com/opencontainers/go-digest => github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec => github.com/opencontainers/image-spec v1.0.1 - github.com/opencontainers/runc => github.com/opencontainers/runc v1.0.3 + github.com/opencontainers/runc => github.com/opencontainers/runc v1.1.0 github.com/opencontainers/runtime-spec => github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 - github.com/opencontainers/selinux => github.com/opencontainers/selinux v1.8.2 + github.com/opencontainers/selinux => github.com/opencontainers/selinux v1.10.0 github.com/opentracing/opentracing-go => github.com/opentracing/opentracing-go v1.1.0 github.com/pascaldekloe/goe => github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c github.com/pelletier/go-toml => github.com/pelletier/go-toml v1.9.3 @@ -395,7 +394,7 @@ replace ( github.com/russross/blackfriday/v2 => github.com/russross/blackfriday/v2 v2.0.1 github.com/ryanuber/columnize => github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f github.com/sean-/seed => github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 - github.com/seccomp/libseccomp-golang => github.com/seccomp/libseccomp-golang v0.9.1 + github.com/seccomp/libseccomp-golang => github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921 github.com/sergi/go-diff => github.com/sergi/go-diff v1.1.0 github.com/shurcooL/sanitized_anchor_name => github.com/shurcooL/sanitized_anchor_name v1.0.0 github.com/sirupsen/logrus => github.com/sirupsen/logrus v1.8.1 diff --git a/go.sum b/go.sum index 35066a0d91293..a174bea4f3942 100644 --- a/go.sum +++ b/go.sum @@ -70,8 +70,6 @@ github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZx github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA= -github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= @@ -86,13 +84,13 @@ github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cb github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= -github.com/checkpoint-restore/go-criu/v5 v5.0.0 h1:TW8f/UvntYoVDMN1K2HlT82qH1rb0sOjpGw3m6Ym+i4= -github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= +github.com/checkpoint-restore/go-criu/v5 v5.3.0 h1:wpFFOoomK3389ue2lAb0Boag6XPht5QYpipxmSNL4d8= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.6.2 h1:iHsfF/t4aW4heW2YKfeHrVPGdtYTL4C4KocpM8KTSnI= -github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.7.0 h1:1k/q3ATgxSXRdrmPfH8d7YK0GfqVsEKZAX9dQZvs56k= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313 h1:eIHD9GNM3Hp7kcRW5mvcz7WTR3ETeoYYKwpgA04kaXE= github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313/go.mod h1:P1wt9Z3DP8O6W3rvwCt0REIlshg1InHImaLW0t3ObY0= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -107,10 +105,10 @@ github.com/container-storage-interface/spec v1.5.0 h1:lvKxe3uLgqQeVQcrnL2CPQKISo github.com/container-storage-interface/spec v1.5.0/go.mod h1:8K96oQNkJ7pFcC2R9Z1ynGGBB1I93kcS6PGg3SsOk8s= github.com/containerd/cgroups v1.0.1 h1:iJnMvco9XGvKUvNQkv88bE4uJXxRQH18efbKo9w5vHQ= github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= -github.com/containerd/console v1.0.2 h1:Pi6D+aZXM+oUw1czuKgH5IJ+y0jhYcwBJfx5/Ghn9dE= -github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= -github.com/containerd/containerd v1.4.11 h1:QCGOUN+i70jEEL/A6JVIbhy4f4fanzAzSR4kNG7SlcE= -github.com/containerd/containerd v1.4.11/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/containerd v1.4.12 h1:V+SHzYmhng/iju6M5nFrpTTusrhidoxKTwdwLw+u4c4= +github.com/containerd/containerd v1.4.12/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= @@ -132,8 +130,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= -github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd h1:uVsMphB1eRx7xB1njzL3fuMdWRN8HtVzoUOItHMwv5c= @@ -201,8 +199,8 @@ github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/ 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/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6 h1:mkgN1ofwASrYnJ5W6U/BxG15eXXXjirgZc7CLqkcaro= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -219,8 +217,8 @@ github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e h1:KhcknUwkWHKZ github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/cadvisor v0.43.0 h1:z0ULgYPKZ7L/c7Zjq+ZD6ltklWwYdCSvBMgSjNC/hGo= -github.com/google/cadvisor v0.43.0/go.mod h1:+RdMSbc3FVr5NYCD2dOEJy/LI0jYJ/0xJXkzWXEyiFQ= +github.com/google/cadvisor v0.43.1-0.20220111033110-a3b5f4f6c501 h1:0SFVx6FgKk/QYGEJmJku6FCtKTDHu0K7NdbuSGnikRI= +github.com/google/cadvisor v0.43.1-0.20220111033110-a3b5f4f6c501/go.mod h1:vFtK+TWeQTPT0AR+Y3lDVGl1TjQzpWEZELfHf8ZjAt4= github.com/google/cel-go v0.9.0 h1:u1hg7lcZ/XWw2d3aV1jFS30ijQQ6q0/h1C2ZBeBD1gY= github.com/google/cel-go v0.9.0/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= @@ -341,8 +339,8 @@ github.com/moby/ipvs v1.0.1 h1:aoZ7fhLTXgDbzVrAnvV+XbKOU8kOET7B3+xULDF/1o0= github.com/moby/ipvs v1.0.1/go.mod h1:2pngiyseZbIKXNv7hsKj3O9UEz30c53MT9005gt2hxQ= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM= -github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.5.0 h1:2Ks8/r6lopsxWi9m58nlwjaeSzUX9iiL1vj5qB/9ObI= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -376,12 +374,12 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= 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.3 h1:1hbqejyQWCJBvtKAfdO0b1FmaEf2z/bxnjqbARass5k= -github.com/opencontainers/runc v1.0.3/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runc v1.1.0 h1:O9+X96OcDjkmmZyfaG996kV7yq8HsoU2h1XRRQcefG8= +github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.8.2 h1:c4ca10UMgRcvZ6h0K4HtS15UaVSBEaE+iln2LVpAuGc= -github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/opencontainers/selinux v1.10.0 h1:rAiKF8hTcgLI3w0DHm6i0ylVVcOrlgR1kK99DRLDhyU= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -418,8 +416,8 @@ github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo= -github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921 h1:58EBmR2dMNL2n/FnbQewK3D14nXr0V9CObDSvMJLq+Y= +github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= diff --git a/pkg/kubelet/cm/cgroup_manager_linux.go b/pkg/kubelet/cm/cgroup_manager_linux.go index 230173690d56f..110d6a7fa30c6 100644 --- a/pkg/kubelet/cm/cgroup_manager_linux.go +++ b/pkg/kubelet/cm/cgroup_manager_linux.go @@ -28,9 +28,8 @@ import ( "time" libcontainercgroups "github.com/opencontainers/runc/libcontainer/cgroups" - cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs" - cgroupfs2 "github.com/opencontainers/runc/libcontainer/cgroups/fs2" "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" + "github.com/opencontainers/runc/libcontainer/cgroups/manager" cgroupsystemd "github.com/opencontainers/runc/libcontainer/cgroups/systemd" libcontainerconfigs "github.com/opencontainers/runc/libcontainer/configs" "k8s.io/klog/v2" @@ -42,14 +41,7 @@ import ( "k8s.io/kubernetes/pkg/kubelet/metrics" ) -// libcontainerCgroupManagerType defines how to interface with libcontainer -type libcontainerCgroupManagerType string - const ( - // libcontainerCgroupfs means use libcontainer with cgroupfs - libcontainerCgroupfs libcontainerCgroupManagerType = "cgroupfs" - // libcontainerSystemd means use libcontainer with systemd - libcontainerSystemd libcontainerCgroupManagerType = "systemd" // systemdSuffix is the cgroup name suffix for systemd systemdSuffix string = ".slice" // MemoryMin is memory.min for cgroup v2 @@ -89,7 +81,7 @@ func unescapeSystemdCgroupName(part string) string { // This function always expands the systemd name into the cgroupfs form. If only // the last part is needed, use path.Base(...) on it to discard the rest. func (cgroupName CgroupName) ToSystemd() string { - if len(cgroupName) == 0 || (len(cgroupName) == 1 && cgroupName[0] == "") { + if len(cgroupName) == 0 { return "/" } newparts := []string{} @@ -133,39 +125,6 @@ func IsSystemdStyleName(name string) bool { return strings.HasSuffix(name, systemdSuffix) } -// libcontainerAdapter provides a simplified interface to libcontainer based on libcontainer type. -type libcontainerAdapter struct { - // cgroupManagerType defines how to interface with libcontainer - cgroupManagerType libcontainerCgroupManagerType -} - -// newLibcontainerAdapter returns a configured libcontainerAdapter for specified manager. -// it does any initialization required by that manager to function. -func newLibcontainerAdapter(cgroupManagerType libcontainerCgroupManagerType) *libcontainerAdapter { - return &libcontainerAdapter{cgroupManagerType: cgroupManagerType} -} - -// newManager returns an implementation of cgroups.Manager -func (l *libcontainerAdapter) newManager(cgroups *libcontainerconfigs.Cgroup, paths map[string]string) (libcontainercgroups.Manager, error) { - switch l.cgroupManagerType { - case libcontainerCgroupfs: - if libcontainercgroups.IsCgroup2UnifiedMode() { - return cgroupfs2.NewManager(cgroups, paths["memory"], false) - } - return cgroupfs.NewManager(cgroups, paths, false), nil - case libcontainerSystemd: - // this means you asked systemd to manage cgroups, but systemd was not on the host, so all you can do is panic... - if !cgroupsystemd.IsRunningSystemd() { - panic("systemd cgroup manager not available") - } - if libcontainercgroups.IsCgroup2UnifiedMode() { - return cgroupsystemd.NewUnifiedManager(cgroups, paths["memory"], false), nil - } - return cgroupsystemd.NewLegacyManager(cgroups, paths), nil - } - return nil, fmt.Errorf("invalid cgroup manager configuration") -} - // CgroupSubsystems holds information about the mounted cgroup subsystems type CgroupSubsystems struct { // Cgroup subsystem mounts. @@ -180,34 +139,31 @@ type CgroupSubsystems struct { // cgroupManagerImpl implements the CgroupManager interface. // Its a stateless object which can be used to // update,create or delete any number of cgroups -// It uses the Libcontainer raw fs cgroup manager for cgroup management. +// It relies on runc/libcontainer cgroup managers. type cgroupManagerImpl struct { // subsystems holds information about all the // mounted cgroup subsystems on the node subsystems *CgroupSubsystems - // simplifies interaction with libcontainer and its cgroup managers - adapter *libcontainerAdapter + + // useSystemd tells if systemd cgroup manager should be used. + useSystemd bool } // Make sure that cgroupManagerImpl implements the CgroupManager interface var _ CgroupManager = &cgroupManagerImpl{} // NewCgroupManager is a factory method that returns a CgroupManager -func NewCgroupManager(cs *CgroupSubsystems, cgroupDriver string) CgroupManager { - managerType := libcontainerCgroupfs - if cgroupDriver == string(libcontainerSystemd) { - managerType = libcontainerSystemd - } +func NewCgroupManager(cs *CgroupSubsystems, useSystemd bool) CgroupManager { return &cgroupManagerImpl{ subsystems: cs, - adapter: newLibcontainerAdapter(managerType), + useSystemd: useSystemd, } } // Name converts the cgroup to the driver specific value in cgroupfs form. // This always returns a valid cgroupfs path even when systemd driver is in use! func (m *cgroupManagerImpl) Name(name CgroupName) string { - if m.adapter.cgroupManagerType == libcontainerSystemd { + if m.useSystemd { return name.ToSystemd() } return name.ToCgroupfs() @@ -215,7 +171,7 @@ func (m *cgroupManagerImpl) Name(name CgroupName) string { // CgroupName converts the literal cgroupfs name on the host to an internal identifier. func (m *cgroupManagerImpl) CgroupName(name string) CgroupName { - if m.adapter.cgroupManagerType == libcontainerSystemd { + if m.useSystemd { return ParseSystemdToCgroupName(name) } return ParseCgroupfsToCgroupName(name) @@ -237,20 +193,43 @@ func (m *cgroupManagerImpl) buildCgroupUnifiedPath(name CgroupName) string { return path.Join(cmutil.CgroupRoot, cgroupFsAdaptedName) } -// TODO(filbranden): This logic belongs in libcontainer/cgroup/systemd instead. -// It should take a libcontainerconfigs.Cgroup.Path field (rather than Name and Parent) -// and split it appropriately, using essentially the logic below. -// This was done for cgroupfs in opencontainers/runc#497 but a counterpart -// for systemd was never introduced. -func updateSystemdCgroupInfo(cgroupConfig *libcontainerconfigs.Cgroup, cgroupName CgroupName) { - dir, base := path.Split(cgroupName.ToSystemd()) +// libctCgroupConfig converts CgroupConfig to libcontainer's Cgroup config. +func (m *cgroupManagerImpl) libctCgroupConfig(in *CgroupConfig, needResources bool) *libcontainerconfigs.Cgroup { + config := &libcontainerconfigs.Cgroup{ + Systemd: m.useSystemd, + } + if needResources { + config.Resources = m.toResources(in.ResourceParameters) + } else { + config.Resources = &libcontainerconfigs.Resources{} + } + + if !config.Systemd { + // For fs cgroup manager, we can either set Path or Name and Parent. + // Setting Path is easier. + config.Path = in.Name.ToCgroupfs() + + return config + } + + // For systemd, we have to set Name and Parent, as they are needed to talk to systemd. + // Setting Path is optional as it can be deduced from Name and Parent. + + // TODO(filbranden): This logic belongs in libcontainer/cgroup/systemd instead. + // It should take a libcontainerconfigs.Cgroup.Path field (rather than Name and Parent) + // and split it appropriately, using essentially the logic below. + // This was done for cgroupfs in opencontainers/runc#497 but a counterpart + // for systemd was never introduced. + dir, base := path.Split(in.Name.ToSystemd()) if dir == "/" { dir = "-.slice" } else { dir = path.Base(dir) } - cgroupConfig.Parent = dir - cgroupConfig.Name = base + config.Parent = dir + config.Name = base + + return config } // Exists checks if all subsystem cgroups already exist @@ -311,18 +290,8 @@ func (m *cgroupManagerImpl) Destroy(cgroupConfig *CgroupConfig) error { metrics.CgroupManagerDuration.WithLabelValues("destroy").Observe(metrics.SinceInSeconds(start)) }() - cgroupPaths := m.buildCgroupPaths(cgroupConfig.Name) - - libcontainerCgroupConfig := &libcontainerconfigs.Cgroup{} - // libcontainer consumes a different field and expects a different syntax - // depending on the cgroup driver in use, so we need this conditional here. - if m.adapter.cgroupManagerType == libcontainerSystemd { - updateSystemdCgroupInfo(libcontainerCgroupConfig, cgroupConfig.Name) - } else { - libcontainerCgroupConfig.Path = cgroupConfig.Name.ToCgroupfs() - } - - manager, err := m.adapter.newManager(libcontainerCgroupConfig, cgroupPaths) + libcontainerCgroupConfig := m.libctCgroupConfig(cgroupConfig, false) + manager, err := manager.New(libcontainerCgroupConfig) if err != nil { return err } @@ -404,8 +373,34 @@ func (m *cgroupManagerImpl) toResources(resourceConfig *ResourceConfig) *libcont if resourceConfig.PidsLimit != nil { resources.PidsLimit = *resourceConfig.PidsLimit } - // if huge pages are enabled, we set them in libcontainer - // for each page size enumerated, set that value + + m.maybeSetHugetlb(resourceConfig, resources) + + // Ideally unified is used for all the resources when running on cgroup v2. + // It doesn't make difference for the memory.max limit, but for e.g. the cpu controller + // you can specify the correct setting without relying on the conversions performed by the OCI runtime. + if resourceConfig.Unified != nil && libcontainercgroups.IsCgroup2UnifiedMode() { + resources.Unified = make(map[string]string) + for k, v := range resourceConfig.Unified { + resources.Unified[k] = v + } + } + return resources +} + +func (m *cgroupManagerImpl) maybeSetHugetlb(resourceConfig *ResourceConfig, resources *libcontainerconfigs.Resources) { + // Check if hugetlb is supported. + if libcontainercgroups.IsCgroup2UnifiedMode() { + if !getSupportedUnifiedControllers().Has("hugetlb") { + klog.V(6).InfoS("Optional subsystem not supported: hugetlb") + return + } + } else if _, ok := m.subsystems.MountPoints["hugetlb"]; !ok { + klog.V(6).InfoS("Optional subsystem not supported: hugetlb") + return + } + + // For each page size enumerated, set that value. pageSizes := sets.NewString() for pageSize, limit := range resourceConfig.HugePageLimit { sizeString, err := v1helper.HugePageUnitSizeFromByteSize(pageSize) @@ -420,7 +415,7 @@ func (m *cgroupManagerImpl) toResources(resourceConfig *ResourceConfig) *libcont pageSizes.Insert(sizeString) } // for each page size omitted, limit to 0 - for _, pageSize := range cgroupfs.HugePageSizes { + for _, pageSize := range libcontainercgroups.HugePageSizes() { if pageSizes.Has(pageSize) { continue } @@ -429,16 +424,6 @@ func (m *cgroupManagerImpl) toResources(resourceConfig *ResourceConfig) *libcont Limit: uint64(0), }) } - // Ideally unified is used for all the resources when running on cgroup v2. - // It doesn't make difference for the memory.max limit, but for e.g. the cpu controller - // you can specify the correct setting without relying on the conversions performed by the OCI runtime. - if resourceConfig.Unified != nil && libcontainercgroups.IsCgroup2UnifiedMode() { - resources.Unified = make(map[string]string) - for k, v := range resourceConfig.Unified { - resources.Unified[k] = v - } - } - return resources } // Update updates the cgroup with the specified Cgroup Configuration @@ -448,48 +433,12 @@ func (m *cgroupManagerImpl) Update(cgroupConfig *CgroupConfig) error { metrics.CgroupManagerDuration.WithLabelValues("update").Observe(metrics.SinceInSeconds(start)) }() - // Extract the cgroup resource parameters - resourceConfig := cgroupConfig.ResourceParameters - resources := m.toResources(resourceConfig) - - libcontainerCgroupConfig := &libcontainerconfigs.Cgroup{ - Resources: resources, - } - - unified := libcontainercgroups.IsCgroup2UnifiedMode() - var paths map[string]string - if unified { - libcontainerCgroupConfig.Path = m.Name(cgroupConfig.Name) - } else { - paths = m.buildCgroupPaths(cgroupConfig.Name) - } - - // libcontainer consumes a different field and expects a different syntax - // depending on the cgroup driver in use, so we need this conditional here. - if m.adapter.cgroupManagerType == libcontainerSystemd { - updateSystemdCgroupInfo(libcontainerCgroupConfig, cgroupConfig.Name) - } - - if cgroupConfig.ResourceParameters != nil && cgroupConfig.ResourceParameters.PidsLimit != nil { - resources.PidsLimit = *cgroupConfig.ResourceParameters.PidsLimit - } - - if unified { - supportedControllers := getSupportedUnifiedControllers() - if !supportedControllers.Has("hugetlb") { - resources.HugetlbLimit = nil - klog.V(6).InfoS("Optional subsystem not supported: hugetlb") - } - } else if _, ok := m.subsystems.MountPoints["hugetlb"]; !ok { - resources.HugetlbLimit = nil - klog.V(6).InfoS("Optional subsystem not supported: hugetlb") - } - - manager, err := m.adapter.newManager(libcontainerCgroupConfig, paths) + libcontainerCgroupConfig := m.libctCgroupConfig(cgroupConfig, true) + manager, err := manager.New(libcontainerCgroupConfig) if err != nil { return fmt.Errorf("failed to create cgroup manager: %v", err) } - return manager.Set(resources) + return manager.Set(libcontainerCgroupConfig.Resources) } // Create creates the specified cgroup @@ -499,25 +448,8 @@ func (m *cgroupManagerImpl) Create(cgroupConfig *CgroupConfig) error { metrics.CgroupManagerDuration.WithLabelValues("create").Observe(metrics.SinceInSeconds(start)) }() - resources := m.toResources(cgroupConfig.ResourceParameters) - - libcontainerCgroupConfig := &libcontainerconfigs.Cgroup{ - Resources: resources, - } - // libcontainer consumes a different field and expects a different syntax - // depending on the cgroup driver in use, so we need this conditional here. - if m.adapter.cgroupManagerType == libcontainerSystemd { - updateSystemdCgroupInfo(libcontainerCgroupConfig, cgroupConfig.Name) - } else { - libcontainerCgroupConfig.Path = cgroupConfig.Name.ToCgroupfs() - } - - if cgroupConfig.ResourceParameters != nil && cgroupConfig.ResourceParameters.PidsLimit != nil { - libcontainerCgroupConfig.PidsLimit = *cgroupConfig.ResourceParameters.PidsLimit - } - - // get the manager with the specified cgroup configuration - manager, err := m.adapter.newManager(libcontainerCgroupConfig, nil) + libcontainerCgroupConfig := m.libctCgroupConfig(cgroupConfig, true) + manager, err := manager.New(libcontainerCgroupConfig) if err != nil { return err } @@ -534,8 +466,8 @@ func (m *cgroupManagerImpl) Create(cgroupConfig *CgroupConfig) error { // it may confuse why we call set after we do apply, but the issue is that runc // follows a similar pattern. it's needed to ensure cpu quota is set properly. - if err := m.Update(cgroupConfig); err != nil { - utilruntime.HandleError(fmt.Errorf("cgroup update failed %v", err)) + if err := manager.Set(libcontainerCgroupConfig.Resources); err != nil { + utilruntime.HandleError(fmt.Errorf("cgroup manager.Set failed: %w", err)) } return nil diff --git a/pkg/kubelet/cm/container_manager_linux.go b/pkg/kubelet/cm/container_manager_linux.go index dce1229e7acad..4b3452172856b 100644 --- a/pkg/kubelet/cm/container_manager_linux.go +++ b/pkg/kubelet/cm/container_manager_linux.go @@ -31,8 +31,7 @@ import ( "time" "github.com/opencontainers/runc/libcontainer/cgroups" - cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs" - cgroupfs2 "github.com/opencontainers/runc/libcontainer/cgroups/fs2" + "github.com/opencontainers/runc/libcontainer/cgroups/manager" "github.com/opencontainers/runc/libcontainer/configs" "k8s.io/klog/v2" "k8s.io/mount-utils" @@ -263,7 +262,7 @@ func NewContainerManager(mountUtil mount.Interface, cadvisorInterface cadvisor.I // Turn CgroupRoot from a string (in cgroupfs path format) to internal CgroupName cgroupRoot := ParseCgroupfsToCgroupName(nodeConfig.CgroupRoot) - cgroupManager := NewCgroupManager(subsystems, nodeConfig.CgroupDriver) + cgroupManager := NewCgroupManager(subsystems, nodeConfig.CgroupDriver == "systemd") // Check if Cgroup-root actually exists on the node if nodeConfig.CgroupsPerQOS { // this does default to / when enabled, but this tests against regressions. @@ -398,13 +397,10 @@ func createManager(containerName string) (cgroups.Manager, error) { Resources: &configs.Resources{ SkipDevices: true, }, + Systemd: false, } - if cgroups.IsCgroup2UnifiedMode() { - return cgroupfs2.NewManager(cg, "", false) - - } - return cgroupfs.NewManager(cg, nil, false), nil + return manager.New(cg) } type KernelTunableBehavior string diff --git a/pkg/kubelet/cm/helpers_linux.go b/pkg/kubelet/cm/helpers_linux.go index 83c80501f5d0a..f360062a15c1c 100644 --- a/pkg/kubelet/cm/helpers_linux.go +++ b/pkg/kubelet/cm/helpers_linux.go @@ -315,12 +315,12 @@ func GetPodCgroupNameSuffix(podUID types.UID) string { } // NodeAllocatableRoot returns the literal cgroup path for the node allocatable cgroup -func NodeAllocatableRoot(cgroupRoot string, cgroupsPerQOS bool, cgroupDriver string) string { +func NodeAllocatableRoot(cgroupRoot string, cgroupsPerQOS, useSystemd bool) string { nodeAllocatableRoot := ParseCgroupfsToCgroupName(cgroupRoot) if cgroupsPerQOS { nodeAllocatableRoot = NewCgroupName(nodeAllocatableRoot, defaultNodeAllocatableCgroupName) } - if libcontainerCgroupManagerType(cgroupDriver) == libcontainerSystemd { + if useSystemd { return nodeAllocatableRoot.ToSystemd() } return nodeAllocatableRoot.ToCgroupfs() diff --git a/pkg/kubelet/cm/helpers_unsupported.go b/pkg/kubelet/cm/helpers_unsupported.go index 323f4642b5840..25da985ac1498 100644 --- a/pkg/kubelet/cm/helpers_unsupported.go +++ b/pkg/kubelet/cm/helpers_unsupported.go @@ -62,7 +62,7 @@ func GetPodCgroupNameSuffix(podUID types.UID) string { } // NodeAllocatableRoot returns the literal cgroup path for the node allocatable cgroup -func NodeAllocatableRoot(cgroupRoot string, cgroupsPerQOS bool, cgroupDriver string) string { +func NodeAllocatableRoot(_ string, _, _ bool) string { return "" } diff --git a/pkg/kubelet/cm/node_container_manager_linux.go b/pkg/kubelet/cm/node_container_manager_linux.go index 3217be5987307..19993bf7ba155 100644 --- a/pkg/kubelet/cm/node_container_manager_linux.go +++ b/pkg/kubelet/cm/node_container_manager_linux.go @@ -136,6 +136,9 @@ func (cm *containerManagerImpl) enforceNodeAllocatableCgroups() error { // enforceExistingCgroup updates the limits `rl` on existing cgroup `cName` using `cgroupManager` interface. func enforceExistingCgroup(cgroupManager CgroupManager, cName CgroupName, rl v1.ResourceList) error { rp := getCgroupConfig(rl) + if rp == nil { + return fmt.Errorf("%q cgroup is not configured properly", cName) + } // Enforce MemoryQoS for cgroups of kube-reserved/system-reserved. For more information, // see https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2570-memory-qos @@ -152,13 +155,7 @@ func enforceExistingCgroup(cgroupManager CgroupManager, cName CgroupName, rl v1. Name: cName, ResourceParameters: rp, } - if cgroupConfig.ResourceParameters == nil { - return fmt.Errorf("%q cgroup is not config properly", cgroupConfig.Name) - } klog.V(4).InfoS("Enforcing limits on cgroup", "cgroupName", cName, "cpuShares", cgroupConfig.ResourceParameters.CpuShares, "memory", cgroupConfig.ResourceParameters.Memory, "pidsLimit", cgroupConfig.ResourceParameters.PidsLimit) - if !cgroupManager.Exists(cgroupConfig.Name) { - return fmt.Errorf("%q cgroup does not exist", cgroupConfig.Name) - } if err := cgroupManager.Update(cgroupConfig); err != nil { return err } diff --git a/pkg/kubelet/cm/pod_container_manager_linux_test.go b/pkg/kubelet/cm/pod_container_manager_linux_test.go index 6e505c0f21684..e1cc3c629496e 100644 --- a/pkg/kubelet/cm/pod_container_manager_linux_test.go +++ b/pkg/kubelet/cm/pod_container_manager_linux_test.go @@ -100,25 +100,27 @@ func TestIsCgroupPod(t *testing.T) { expectedUID: types.UID(""), }, } - for _, cgroupDriver := range []string{"cgroupfs", "systemd"} { + for _, useSystemd := range []bool{false, true} { pcm := &podContainerManagerImpl{ - cgroupManager: NewCgroupManager(nil, cgroupDriver), + cgroupManager: NewCgroupManager(nil, useSystemd), enforceCPULimits: true, qosContainersInfo: qosContainersInfo, } for _, testCase := range testCases { - // give the right cgroup structure based on driver - cgroupfs := testCase.input.ToCgroupfs() - if cgroupDriver == "systemd" { - cgroupfs = testCase.input.ToSystemd() + // Give the right cgroup structure based on whether systemd is enabled. + var name string + if useSystemd { + name = testCase.input.ToSystemd() + } else { + name = testCase.input.ToCgroupfs() } // check if this is a pod or not with the literal cgroupfs input - result, resultUID := pcm.IsPodCgroup(cgroupfs) + result, resultUID := pcm.IsPodCgroup(name) if result != testCase.expectedResult { - t.Errorf("Unexpected result for driver: %v, input: %v, expected: %v, actual: %v", cgroupDriver, testCase.input, testCase.expectedResult, result) + t.Errorf("Unexpected result for systemd: %v, input: %v, expected: %v, actual: %v", useSystemd, testCase.input, testCase.expectedResult, result) } if resultUID != testCase.expectedUID { - t.Errorf("Unexpected result for driver: %v, input: %v, expected: %v, actual: %v", cgroupDriver, testCase.input, testCase.expectedUID, resultUID) + t.Errorf("Unexpected result for systemd: %v, input: %v, expected: %v, actual: %v", useSystemd, testCase.input, testCase.expectedUID, resultUID) } } diff --git a/pkg/kubelet/cm/qos_container_manager_linux.go b/pkg/kubelet/cm/qos_container_manager_linux.go index bb79109b141c2..0ddd44ac2343f 100644 --- a/pkg/kubelet/cm/qos_container_manager_linux.go +++ b/pkg/kubelet/cm/qos_container_manager_linux.go @@ -23,14 +23,13 @@ import ( "sync" "time" + v1 "k8s.io/api/core/v1" "k8s.io/klog/v2" "k8s.io/apimachinery/pkg/util/wait" units "github.com/docker/go-units" libcontainercgroups "github.com/opencontainers/runc/libcontainer/cgroups" - cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs" - v1 "k8s.io/api/core/v1" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/kubernetes/pkg/api/v1/resource" v1qos "k8s.io/kubernetes/pkg/apis/core/v1/helper/qos" @@ -147,7 +146,7 @@ func (m *qosContainerManagerImpl) Start(getNodeAllocatable func() v1.ResourceLis // setHugePagesUnbounded ensures hugetlb is effectively unbounded func (m *qosContainerManagerImpl) setHugePagesUnbounded(cgroupConfig *CgroupConfig) error { hugePageLimit := map[int64]int64{} - for _, pageSize := range cgroupfs.HugePageSizes { + for _, pageSize := range libcontainercgroups.HugePageSizes() { pageSizeBytes, err := units.RAMInBytes(pageSize) if err != nil { return err diff --git a/pkg/kubelet/cm/qos_container_manager_linux_test.go b/pkg/kubelet/cm/qos_container_manager_linux_test.go index 2123623319998..749d500c31869 100644 --- a/pkg/kubelet/cm/qos_container_manager_linux_test.go +++ b/pkg/kubelet/cm/qos_container_manager_linux_test.go @@ -117,7 +117,7 @@ func createTestQOSContainerManager() (*qosContainerManagerImpl, error) { qosContainerManager := &qosContainerManagerImpl{ subsystems: subsystems, - cgroupManager: NewCgroupManager(subsystems, "cgroupfs"), + cgroupManager: NewCgroupManager(subsystems, false), cgroupRoot: cgroupRoot, qosReserved: nil, } diff --git a/pkg/kubelet/kuberuntime/kuberuntime_container_linux.go b/pkg/kubelet/kuberuntime/kuberuntime_container_linux.go index 6cb9e54729e9b..0162301415c61 100644 --- a/pkg/kubelet/kuberuntime/kuberuntime_container_linux.go +++ b/pkg/kubelet/kuberuntime/kuberuntime_container_linux.go @@ -24,7 +24,6 @@ import ( "time" libcontainercgroups "github.com/opencontainers/runc/libcontainer/cgroups" - cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" utilfeature "k8s.io/apiserver/pkg/util/feature" @@ -170,7 +169,7 @@ func GetHugepageLimitsFromResources(resources v1.ResourceRequirements) []*runtim var hugepageLimits []*runtimeapi.HugepageLimit // For each page size, limit to 0. - for _, pageSize := range cgroupfs.HugePageSizes { + for _, pageSize := range libcontainercgroups.HugePageSizes() { hugepageLimits = append(hugepageLimits, &runtimeapi.HugepageLimit{ PageSize: pageSize, Limit: uint64(0), diff --git a/pkg/kubelet/kuberuntime/kuberuntime_container_linux_test.go b/pkg/kubelet/kuberuntime/kuberuntime_container_linux_test.go index 46817e00fb0e0..44fa80d70e1ef 100644 --- a/pkg/kubelet/kuberuntime/kuberuntime_container_linux_test.go +++ b/pkg/kubelet/kuberuntime/kuberuntime_container_linux_test.go @@ -25,7 +25,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs" + libcontainercgroups "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/stretchr/testify/assert" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" @@ -366,7 +366,7 @@ func TestGetHugepageLimitsFromResources(t *testing.T) { var baseHugepage []*runtimeapi.HugepageLimit // For each page size, limit to 0. - for _, pageSize := range cgroupfs.HugePageSizes { + for _, pageSize := range libcontainercgroups.HugePageSizes() { baseHugepage = append(baseHugepage, &runtimeapi.HugepageLimit{ PageSize: pageSize, Limit: uint64(0), @@ -481,7 +481,7 @@ func TestGetHugepageLimitsFromResources(t *testing.T) { machineHugepageSupport := true for _, hugepageLimit := range test.expected { hugepageSupport := false - for _, pageSize := range cgroupfs.HugePageSizes { + for _, pageSize := range libcontainercgroups.HugePageSizes() { if pageSize == hugepageLimit.PageSize { hugepageSupport = true break diff --git a/test/e2e_node/node_container_manager_test.go b/test/e2e_node/node_container_manager_test.go index 332892fb5b65b..661a7750fd871 100644 --- a/test/e2e_node/node_container_manager_test.go +++ b/test/e2e_node/node_container_manager_test.go @@ -180,7 +180,7 @@ func runTest(f *framework.Framework) error { } // Create a cgroup manager object for manipulating cgroups. - cgroupManager := cm.NewCgroupManager(subsystems, oldCfg.CgroupDriver) + cgroupManager := cm.NewCgroupManager(subsystems, false) defer destroyTemporaryCgroupsForReservation(cgroupManager) defer func() { diff --git a/vendor/github.com/bits-and-blooms/bitset/.gitignore b/vendor/github.com/bits-and-blooms/bitset/.gitignore deleted file mode 100644 index 5c204d28b0e36..0000000000000 --- a/vendor/github.com/bits-and-blooms/bitset/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof - -target diff --git a/vendor/github.com/bits-and-blooms/bitset/.travis.yml b/vendor/github.com/bits-and-blooms/bitset/.travis.yml deleted file mode 100644 index 094aa5ce070cc..0000000000000 --- a/vendor/github.com/bits-and-blooms/bitset/.travis.yml +++ /dev/null @@ -1,37 +0,0 @@ -language: go - -sudo: false - -branches: - except: - - release - -branches: - only: - - master - - travis - -go: - - "1.11.x" - - tip - -matrix: - allow_failures: - - go: tip - -before_install: - - if [ -n "$GH_USER" ]; then git config --global github.user ${GH_USER}; fi; - - if [ -n "$GH_TOKEN" ]; then git config --global github.token ${GH_TOKEN}; fi; - - go get github.com/mattn/goveralls - -before_script: - - make deps - -script: - - make qa - -after_failure: - - cat ./target/test/report.xml - -after_success: - - if [ "$TRAVIS_GO_VERSION" = "1.11.1" ]; then $HOME/gopath/bin/goveralls -covermode=count -coverprofile=target/report/coverage.out -service=travis-ci; fi; diff --git a/vendor/github.com/bits-and-blooms/bitset/LICENSE b/vendor/github.com/bits-and-blooms/bitset/LICENSE deleted file mode 100644 index 59cab8a939be7..0000000000000 --- a/vendor/github.com/bits-and-blooms/bitset/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2014 Will Fitzgerald. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/bits-and-blooms/bitset/README.md b/vendor/github.com/bits-and-blooms/bitset/README.md deleted file mode 100644 index 97e83071e41a1..0000000000000 --- a/vendor/github.com/bits-and-blooms/bitset/README.md +++ /dev/null @@ -1,93 +0,0 @@ -# bitset - -*Go language library to map between non-negative integers and boolean values* - -[![Test](https://github.com/bits-and-blooms/bitset/workflows/Test/badge.svg)](https://github.com/willf/bitset/actions?query=workflow%3ATest) -[![Go Report Card](https://goreportcard.com/badge/github.com/willf/bitset)](https://goreportcard.com/report/github.com/willf/bitset) -[![PkgGoDev](https://pkg.go.dev/badge/github.com/bits-and-blooms/bitset?tab=doc)](https://pkg.go.dev/github.com/bits-and-blooms/bitset?tab=doc) - - -## Description - -Package bitset implements bitsets, a mapping between non-negative integers and boolean values. -It should be more efficient than map[uint] bool. - -It provides methods for setting, clearing, flipping, and testing individual integers. - -But it also provides set intersection, union, difference, complement, and symmetric operations, as well as tests to check whether any, all, or no bits are set, and querying a bitset's current length and number of positive bits. - -BitSets are expanded to the size of the largest set bit; the memory allocation is approximately Max bits, where Max is the largest set bit. BitSets are never shrunk. On creation, a hint can be given for the number of bits that will be used. - -Many of the methods, including Set, Clear, and Flip, return a BitSet pointer, which allows for chaining. - -### Example use: - -```go -package main - -import ( - "fmt" - "math/rand" - - "github.com/bits-and-blooms/bitset" -) - -func main() { - fmt.Printf("Hello from BitSet!\n") - var b bitset.BitSet - // play some Go Fish - for i := 0; i < 100; i++ { - card1 := uint(rand.Intn(52)) - card2 := uint(rand.Intn(52)) - b.Set(card1) - if b.Test(card2) { - fmt.Println("Go Fish!") - } - b.Clear(card1) - } - - // Chaining - b.Set(10).Set(11) - - for i, e := b.NextSet(0); e; i, e = b.NextSet(i + 1) { - fmt.Println("The following bit is set:", i) - } - if b.Intersection(bitset.New(100).Set(10)).Count() == 1 { - fmt.Println("Intersection works.") - } else { - fmt.Println("Intersection doesn't work???") - } -} -``` - -As an alternative to BitSets, one should check out the 'big' package, which provides a (less set-theoretical) view of bitsets. - -Package documentation is at: https://pkg.go.dev/github.com/bits-and-blooms/bitset?tab=doc - -## Memory Usage - -The memory usage of a bitset using N bits is at least N/8 bytes. The number of bits in a bitset is at least as large as one plus the greatest bit index you have accessed. Thus it is possible to run out of memory while using a bitset. If you have lots of bits, you might prefer compressed bitsets, like the [Roaring bitmaps](http://roaringbitmap.org) and its [Go implementation](https://github.com/RoaringBitmap/roaring). - -## Implementation Note - -Go 1.9 introduced a native `math/bits` library. We provide backward compatibility to Go 1.7, which might be removed. - -It is possible that a later version will match the `math/bits` return signature for counts (which is `int`, rather than our library's `unit64`). If so, the version will be bumped. - -## Installation - -```bash -go get github.com/bits-and-blooms/bitset -``` - -## Contributing - -If you wish to contribute to this project, please branch and issue a pull request against master ("[GitHub Flow](https://guides.github.com/introduction/flow/)") - -## Running all tests - -Before committing the code, please check if it passes tests, has adequate coverage, etc. -```bash -go test -go test -cover -``` diff --git a/vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml b/vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml deleted file mode 100644 index f9b295918404f..0000000000000 --- a/vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml +++ /dev/null @@ -1,39 +0,0 @@ -# Go -# Build your Go project. -# Add steps that test, save build artifacts, deploy, and more: -# https://docs.microsoft.com/azure/devops/pipelines/languages/go - -trigger: -- master - -pool: - vmImage: 'Ubuntu-16.04' - -variables: - GOBIN: '$(GOPATH)/bin' # Go binaries path - GOROOT: '/usr/local/go1.11' # Go installation path - GOPATH: '$(system.defaultWorkingDirectory)/gopath' # Go workspace path - modulePath: '$(GOPATH)/src/github.com/$(build.repository.name)' # Path to the module's code - -steps: -- script: | - mkdir -p '$(GOBIN)' - mkdir -p '$(GOPATH)/pkg' - mkdir -p '$(modulePath)' - shopt -s extglob - shopt -s dotglob - mv !(gopath) '$(modulePath)' - echo '##vso[task.prependpath]$(GOBIN)' - echo '##vso[task.prependpath]$(GOROOT)/bin' - displayName: 'Set up the Go workspace' - -- script: | - go version - go get -v -t -d ./... - if [ -f Gopkg.toml ]; then - curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh - dep ensure - fi - go build -v . - workingDirectory: '$(modulePath)' - displayName: 'Get dependencies, then build' diff --git a/vendor/github.com/bits-and-blooms/bitset/bitset.go b/vendor/github.com/bits-and-blooms/bitset/bitset.go deleted file mode 100644 index d688806a54b89..0000000000000 --- a/vendor/github.com/bits-and-blooms/bitset/bitset.go +++ /dev/null @@ -1,952 +0,0 @@ -/* -Package bitset implements bitsets, a mapping -between non-negative integers and boolean values. It should be more -efficient than map[uint] bool. - -It provides methods for setting, clearing, flipping, and testing -individual integers. - -But it also provides set intersection, union, difference, -complement, and symmetric operations, as well as tests to -check whether any, all, or no bits are set, and querying a -bitset's current length and number of positive bits. - -BitSets are expanded to the size of the largest set bit; the -memory allocation is approximately Max bits, where Max is -the largest set bit. BitSets are never shrunk. On creation, -a hint can be given for the number of bits that will be used. - -Many of the methods, including Set,Clear, and Flip, return -a BitSet pointer, which allows for chaining. - -Example use: - - import "bitset" - var b BitSet - b.Set(10).Set(11) - if b.Test(1000) { - b.Clear(1000) - } - if B.Intersection(bitset.New(100).Set(10)).Count() > 1 { - fmt.Println("Intersection works.") - } - -As an alternative to BitSets, one should check out the 'big' package, -which provides a (less set-theoretical) view of bitsets. - -*/ -package bitset - -import ( - "bufio" - "bytes" - "encoding/base64" - "encoding/binary" - "encoding/json" - "errors" - "fmt" - "io" - "strconv" -) - -// the wordSize of a bit set -const wordSize = uint(64) - -// log2WordSize is lg(wordSize) -const log2WordSize = uint(6) - -// allBits has every bit set -const allBits uint64 = 0xffffffffffffffff - -// default binary BigEndian -var binaryOrder binary.ByteOrder = binary.BigEndian - -// default json encoding base64.URLEncoding -var base64Encoding = base64.URLEncoding - -// Base64StdEncoding Marshal/Unmarshal BitSet with base64.StdEncoding(Default: base64.URLEncoding) -func Base64StdEncoding() { base64Encoding = base64.StdEncoding } - -// LittleEndian Marshal/Unmarshal Binary as Little Endian(Default: binary.BigEndian) -func LittleEndian() { binaryOrder = binary.LittleEndian } - -// A BitSet is a set of bits. The zero value of a BitSet is an empty set of length 0. -type BitSet struct { - length uint - set []uint64 -} - -// Error is used to distinguish errors (panics) generated in this package. -type Error string - -// safeSet will fixup b.set to be non-nil and return the field value -func (b *BitSet) safeSet() []uint64 { - if b.set == nil { - b.set = make([]uint64, wordsNeeded(0)) - } - return b.set -} - -// From is a constructor used to create a BitSet from an array of integers -func From(buf []uint64) *BitSet { - return &BitSet{uint(len(buf)) * 64, buf} -} - -// Bytes returns the bitset as array of integers -func (b *BitSet) Bytes() []uint64 { - return b.set -} - -// wordsNeeded calculates the number of words needed for i bits -func wordsNeeded(i uint) int { - if i > (Cap() - wordSize + 1) { - return int(Cap() >> log2WordSize) - } - return int((i + (wordSize - 1)) >> log2WordSize) -} - -// New creates a new BitSet with a hint that length bits will be required -func New(length uint) (bset *BitSet) { - defer func() { - if r := recover(); r != nil { - bset = &BitSet{ - 0, - make([]uint64, 0), - } - } - }() - - bset = &BitSet{ - length, - make([]uint64, wordsNeeded(length)), - } - - return bset -} - -// Cap returns the total possible capacity, or number of bits -func Cap() uint { - return ^uint(0) -} - -// Len returns the number of bits in the BitSet. -// Note the difference to method Count, see example. -func (b *BitSet) Len() uint { - return b.length -} - -// extendSetMaybe adds additional words to incorporate new bits if needed -func (b *BitSet) extendSetMaybe(i uint) { - if i >= b.length { // if we need more bits, make 'em - if i >= Cap() { - panic("You are exceeding the capacity") - } - nsize := wordsNeeded(i + 1) - if b.set == nil { - b.set = make([]uint64, nsize) - } else if cap(b.set) >= nsize { - b.set = b.set[:nsize] // fast resize - } else if len(b.set) < nsize { - newset := make([]uint64, nsize, 2*nsize) // increase capacity 2x - copy(newset, b.set) - b.set = newset - } - b.length = i + 1 - } -} - -// Test whether bit i is set. -func (b *BitSet) Test(i uint) bool { - if i >= b.length { - return false - } - return b.set[i>>log2WordSize]&(1<<(i&(wordSize-1))) != 0 -} - -// Set bit i to 1, the capacity of the bitset is automatically -// increased accordingly. -// If i>= Cap(), this function will panic. -// Warning: using a very large value for 'i' -// may lead to a memory shortage and a panic: the caller is responsible -// for providing sensible parameters in line with their memory capacity. -func (b *BitSet) Set(i uint) *BitSet { - b.extendSetMaybe(i) - b.set[i>>log2WordSize] |= 1 << (i & (wordSize - 1)) - return b -} - -// Clear bit i to 0 -func (b *BitSet) Clear(i uint) *BitSet { - if i >= b.length { - return b - } - b.set[i>>log2WordSize] &^= 1 << (i & (wordSize - 1)) - return b -} - -// SetTo sets bit i to value. -// If i>= Cap(), this function will panic. -// Warning: using a very large value for 'i' -// may lead to a memory shortage and a panic: the caller is responsible -// for providing sensible parameters in line with their memory capacity. -func (b *BitSet) SetTo(i uint, value bool) *BitSet { - if value { - return b.Set(i) - } - return b.Clear(i) -} - -// Flip bit at i. -// If i>= Cap(), this function will panic. -// Warning: using a very large value for 'i' -// may lead to a memory shortage and a panic: the caller is responsible -// for providing sensible parameters in line with their memory capacity. -func (b *BitSet) Flip(i uint) *BitSet { - if i >= b.length { - return b.Set(i) - } - b.set[i>>log2WordSize] ^= 1 << (i & (wordSize - 1)) - return b -} - -// FlipRange bit in [start, end). -// If end>= Cap(), this function will panic. -// Warning: using a very large value for 'end' -// may lead to a memory shortage and a panic: the caller is responsible -// for providing sensible parameters in line with their memory capacity. -func (b *BitSet) FlipRange(start, end uint) *BitSet { - if start >= end { - return b - } - - b.extendSetMaybe(end - 1) - var startWord uint = start >> log2WordSize - var endWord uint = end >> log2WordSize - b.set[startWord] ^= ^(^uint64(0) << (start & (wordSize - 1))) - for i := startWord; i < endWord; i++ { - b.set[i] = ^b.set[i] - } - b.set[endWord] ^= ^uint64(0) >> (-end & (wordSize - 1)) - return b -} - -// Shrink shrinks BitSet so that the provided value is the last possible -// set value. It clears all bits > the provided index and reduces the size -// and length of the set. -// -// Note that the parameter value is not the new length in bits: it is the -// maximal value that can be stored in the bitset after the function call. -// The new length in bits is the parameter value + 1. Thus it is not possible -// to use this function to set the length to 0, the minimal value of the length -// after this function call is 1. -// -// A new slice is allocated to store the new bits, so you may see an increase in -// memory usage until the GC runs. Normally this should not be a problem, but if you -// have an extremely large BitSet its important to understand that the old BitSet will -// remain in memory until the GC frees it. -func (b *BitSet) Shrink(lastbitindex uint) *BitSet { - length := lastbitindex + 1 - idx := wordsNeeded(length) - if idx > len(b.set) { - return b - } - shrunk := make([]uint64, idx) - copy(shrunk, b.set[:idx]) - b.set = shrunk - b.length = length - b.set[idx-1] &= (allBits >> (uint64(64) - uint64(length&(wordSize-1)))) - return b -} - -// Compact shrinks BitSet to so that we preserve all set bits, while minimizing -// memory usage. Compact calls Shrink. -func (b *BitSet) Compact() *BitSet { - idx := len(b.set) - 1 - for ; idx >= 0 && b.set[idx] == 0; idx-- { - } - newlength := uint((idx + 1) << log2WordSize) - if newlength >= b.length { - return b // nothing to do - } - if newlength > 0 { - return b.Shrink(newlength - 1) - } - // We preserve one word - return b.Shrink(63) -} - -// InsertAt takes an index which indicates where a bit should be -// inserted. Then it shifts all the bits in the set to the left by 1, starting -// from the given index position, and sets the index position to 0. -// -// Depending on the size of your BitSet, and where you are inserting the new entry, -// this method could be extremely slow and in some cases might cause the entire BitSet -// to be recopied. -func (b *BitSet) InsertAt(idx uint) *BitSet { - insertAtElement := (idx >> log2WordSize) - - // if length of set is a multiple of wordSize we need to allocate more space first - if b.isLenExactMultiple() { - b.set = append(b.set, uint64(0)) - } - - var i uint - for i = uint(len(b.set) - 1); i > insertAtElement; i-- { - // all elements above the position where we want to insert can simply by shifted - b.set[i] <<= 1 - - // we take the most significant bit of the previous element and set it as - // the least significant bit of the current element - b.set[i] |= (b.set[i-1] & 0x8000000000000000) >> 63 - } - - // generate a mask to extract the data that we need to shift left - // within the element where we insert a bit - dataMask := ^(uint64(1)< 0x40000 { - buffer.WriteString("...") - break - } - buffer.WriteString(strconv.FormatInt(int64(i), 10)) - i, e = b.NextSet(i + 1) - if e { - buffer.WriteString(",") - } - } - buffer.WriteString("}") - return buffer.String() -} - -// DeleteAt deletes the bit at the given index position from -// within the bitset -// All the bits residing on the left of the deleted bit get -// shifted right by 1 -// The running time of this operation may potentially be -// relatively slow, O(length) -func (b *BitSet) DeleteAt(i uint) *BitSet { - // the index of the slice element where we'll delete a bit - deleteAtElement := i >> log2WordSize - - // generate a mask for the data that needs to be shifted right - // within that slice element that gets modified - dataMask := ^((uint64(1) << (i & (wordSize - 1))) - 1) - - // extract the data that we'll shift right from the slice element - data := b.set[deleteAtElement] & dataMask - - // set the masked area to 0 while leaving the rest as it is - b.set[deleteAtElement] &= ^dataMask - - // shift the previously extracted data to the right and then - // set it in the previously masked area - b.set[deleteAtElement] |= (data >> 1) & dataMask - - // loop over all the consecutive slice elements to copy each - // lowest bit into the highest position of the previous element, - // then shift the entire content to the right by 1 - for i := int(deleteAtElement) + 1; i < len(b.set); i++ { - b.set[i-1] |= (b.set[i] & 1) << 63 - b.set[i] >>= 1 - } - - b.length = b.length - 1 - - return b -} - -// NextSet returns the next bit set from the specified index, -// including possibly the current index -// along with an error code (true = valid, false = no set bit found) -// for i,e := v.NextSet(0); e; i,e = v.NextSet(i + 1) {...} -// -// Users concerned with performance may want to use NextSetMany to -// retrieve several values at once. -func (b *BitSet) NextSet(i uint) (uint, bool) { - x := int(i >> log2WordSize) - if x >= len(b.set) { - return 0, false - } - w := b.set[x] - w = w >> (i & (wordSize - 1)) - if w != 0 { - return i + trailingZeroes64(w), true - } - x = x + 1 - for x < len(b.set) { - if b.set[x] != 0 { - return uint(x)*wordSize + trailingZeroes64(b.set[x]), true - } - x = x + 1 - - } - return 0, false -} - -// NextSetMany returns many next bit sets from the specified index, -// including possibly the current index and up to cap(buffer). -// If the returned slice has len zero, then no more set bits were found -// -// buffer := make([]uint, 256) // this should be reused -// j := uint(0) -// j, buffer = bitmap.NextSetMany(j, buffer) -// for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j,buffer) { -// for k := range buffer { -// do something with buffer[k] -// } -// j += 1 -// } -// -// -// It is possible to retrieve all set bits as follow: -// -// indices := make([]uint, bitmap.Count()) -// bitmap.NextSetMany(0, indices) -// -// However if bitmap.Count() is large, it might be preferable to -// use several calls to NextSetMany, for performance reasons. -func (b *BitSet) NextSetMany(i uint, buffer []uint) (uint, []uint) { - myanswer := buffer - capacity := cap(buffer) - x := int(i >> log2WordSize) - if x >= len(b.set) || capacity == 0 { - return 0, myanswer[:0] - } - skip := i & (wordSize - 1) - word := b.set[x] >> skip - myanswer = myanswer[:capacity] - size := int(0) - for word != 0 { - r := trailingZeroes64(word) - t := word & ((^word) + 1) - myanswer[size] = r + i - size++ - if size == capacity { - goto End - } - word = word ^ t - } - x++ - for idx, word := range b.set[x:] { - for word != 0 { - r := trailingZeroes64(word) - t := word & ((^word) + 1) - myanswer[size] = r + (uint(x+idx) << 6) - size++ - if size == capacity { - goto End - } - word = word ^ t - } - } -End: - if size > 0 { - return myanswer[size-1], myanswer[:size] - } - return 0, myanswer[:0] -} - -// NextClear returns the next clear bit from the specified index, -// including possibly the current index -// along with an error code (true = valid, false = no bit found i.e. all bits are set) -func (b *BitSet) NextClear(i uint) (uint, bool) { - x := int(i >> log2WordSize) - if x >= len(b.set) { - return 0, false - } - w := b.set[x] - w = w >> (i & (wordSize - 1)) - wA := allBits >> (i & (wordSize - 1)) - index := i + trailingZeroes64(^w) - if w != wA && index < b.length { - return index, true - } - x++ - for x < len(b.set) { - index = uint(x)*wordSize + trailingZeroes64(^b.set[x]) - if b.set[x] != allBits && index < b.length { - return index, true - } - x++ - } - return 0, false -} - -// ClearAll clears the entire BitSet -func (b *BitSet) ClearAll() *BitSet { - if b != nil && b.set != nil { - for i := range b.set { - b.set[i] = 0 - } - } - return b -} - -// wordCount returns the number of words used in a bit set -func (b *BitSet) wordCount() int { - return len(b.set) -} - -// Clone this BitSet -func (b *BitSet) Clone() *BitSet { - c := New(b.length) - if b.set != nil { // Clone should not modify current object - copy(c.set, b.set) - } - return c -} - -// Copy into a destination BitSet -// Returning the size of the destination BitSet -// like array copy -func (b *BitSet) Copy(c *BitSet) (count uint) { - if c == nil { - return - } - if b.set != nil { // Copy should not modify current object - copy(c.set, b.set) - } - count = c.length - if b.length < c.length { - count = b.length - } - return -} - -// Count (number of set bits). -// Also known as "popcount" or "population count". -func (b *BitSet) Count() uint { - if b != nil && b.set != nil { - return uint(popcntSlice(b.set)) - } - return 0 -} - -// Equal tests the equivalence of two BitSets. -// False if they are of different sizes, otherwise true -// only if all the same bits are set -func (b *BitSet) Equal(c *BitSet) bool { - if c == nil || b == nil { - return c == b - } - if b.length != c.length { - return false - } - if b.length == 0 { // if they have both length == 0, then could have nil set - return true - } - // testing for equality shoud not transform the bitset (no call to safeSet) - - for p, v := range b.set { - if c.set[p] != v { - return false - } - } - return true -} - -func panicIfNull(b *BitSet) { - if b == nil { - panic(Error("BitSet must not be null")) - } -} - -// Difference of base set and other set -// This is the BitSet equivalent of &^ (and not) -func (b *BitSet) Difference(compare *BitSet) (result *BitSet) { - panicIfNull(b) - panicIfNull(compare) - result = b.Clone() // clone b (in case b is bigger than compare) - l := int(compare.wordCount()) - if l > int(b.wordCount()) { - l = int(b.wordCount()) - } - for i := 0; i < l; i++ { - result.set[i] = b.set[i] &^ compare.set[i] - } - return -} - -// DifferenceCardinality computes the cardinality of the differnce -func (b *BitSet) DifferenceCardinality(compare *BitSet) uint { - panicIfNull(b) - panicIfNull(compare) - l := int(compare.wordCount()) - if l > int(b.wordCount()) { - l = int(b.wordCount()) - } - cnt := uint64(0) - cnt += popcntMaskSlice(b.set[:l], compare.set[:l]) - cnt += popcntSlice(b.set[l:]) - return uint(cnt) -} - -// InPlaceDifference computes the difference of base set and other set -// This is the BitSet equivalent of &^ (and not) -func (b *BitSet) InPlaceDifference(compare *BitSet) { - panicIfNull(b) - panicIfNull(compare) - l := int(compare.wordCount()) - if l > int(b.wordCount()) { - l = int(b.wordCount()) - } - for i := 0; i < l; i++ { - b.set[i] &^= compare.set[i] - } -} - -// Convenience function: return two bitsets ordered by -// increasing length. Note: neither can be nil -func sortByLength(a *BitSet, b *BitSet) (ap *BitSet, bp *BitSet) { - if a.length <= b.length { - ap, bp = a, b - } else { - ap, bp = b, a - } - return -} - -// Intersection of base set and other set -// This is the BitSet equivalent of & (and) -func (b *BitSet) Intersection(compare *BitSet) (result *BitSet) { - panicIfNull(b) - panicIfNull(compare) - b, compare = sortByLength(b, compare) - result = New(b.length) - for i, word := range b.set { - result.set[i] = word & compare.set[i] - } - return -} - -// IntersectionCardinality computes the cardinality of the union -func (b *BitSet) IntersectionCardinality(compare *BitSet) uint { - panicIfNull(b) - panicIfNull(compare) - b, compare = sortByLength(b, compare) - cnt := popcntAndSlice(b.set, compare.set) - return uint(cnt) -} - -// InPlaceIntersection destructively computes the intersection of -// base set and the compare set. -// This is the BitSet equivalent of & (and) -func (b *BitSet) InPlaceIntersection(compare *BitSet) { - panicIfNull(b) - panicIfNull(compare) - l := int(compare.wordCount()) - if l > int(b.wordCount()) { - l = int(b.wordCount()) - } - for i := 0; i < l; i++ { - b.set[i] &= compare.set[i] - } - for i := l; i < len(b.set); i++ { - b.set[i] = 0 - } - if compare.length > 0 { - b.extendSetMaybe(compare.length - 1) - } -} - -// Union of base set and other set -// This is the BitSet equivalent of | (or) -func (b *BitSet) Union(compare *BitSet) (result *BitSet) { - panicIfNull(b) - panicIfNull(compare) - b, compare = sortByLength(b, compare) - result = compare.Clone() - for i, word := range b.set { - result.set[i] = word | compare.set[i] - } - return -} - -// UnionCardinality computes the cardinality of the uniton of the base set -// and the compare set. -func (b *BitSet) UnionCardinality(compare *BitSet) uint { - panicIfNull(b) - panicIfNull(compare) - b, compare = sortByLength(b, compare) - cnt := popcntOrSlice(b.set, compare.set) - if len(compare.set) > len(b.set) { - cnt += popcntSlice(compare.set[len(b.set):]) - } - return uint(cnt) -} - -// InPlaceUnion creates the destructive union of base set and compare set. -// This is the BitSet equivalent of | (or). -func (b *BitSet) InPlaceUnion(compare *BitSet) { - panicIfNull(b) - panicIfNull(compare) - l := int(compare.wordCount()) - if l > int(b.wordCount()) { - l = int(b.wordCount()) - } - if compare.length > 0 { - b.extendSetMaybe(compare.length - 1) - } - for i := 0; i < l; i++ { - b.set[i] |= compare.set[i] - } - if len(compare.set) > l { - for i := l; i < len(compare.set); i++ { - b.set[i] = compare.set[i] - } - } -} - -// SymmetricDifference of base set and other set -// This is the BitSet equivalent of ^ (xor) -func (b *BitSet) SymmetricDifference(compare *BitSet) (result *BitSet) { - panicIfNull(b) - panicIfNull(compare) - b, compare = sortByLength(b, compare) - // compare is bigger, so clone it - result = compare.Clone() - for i, word := range b.set { - result.set[i] = word ^ compare.set[i] - } - return -} - -// SymmetricDifferenceCardinality computes the cardinality of the symmetric difference -func (b *BitSet) SymmetricDifferenceCardinality(compare *BitSet) uint { - panicIfNull(b) - panicIfNull(compare) - b, compare = sortByLength(b, compare) - cnt := popcntXorSlice(b.set, compare.set) - if len(compare.set) > len(b.set) { - cnt += popcntSlice(compare.set[len(b.set):]) - } - return uint(cnt) -} - -// InPlaceSymmetricDifference creates the destructive SymmetricDifference of base set and other set -// This is the BitSet equivalent of ^ (xor) -func (b *BitSet) InPlaceSymmetricDifference(compare *BitSet) { - panicIfNull(b) - panicIfNull(compare) - l := int(compare.wordCount()) - if l > int(b.wordCount()) { - l = int(b.wordCount()) - } - if compare.length > 0 { - b.extendSetMaybe(compare.length - 1) - } - for i := 0; i < l; i++ { - b.set[i] ^= compare.set[i] - } - if len(compare.set) > l { - for i := l; i < len(compare.set); i++ { - b.set[i] = compare.set[i] - } - } -} - -// Is the length an exact multiple of word sizes? -func (b *BitSet) isLenExactMultiple() bool { - return b.length%wordSize == 0 -} - -// Clean last word by setting unused bits to 0 -func (b *BitSet) cleanLastWord() { - if !b.isLenExactMultiple() { - b.set[len(b.set)-1] &= allBits >> (wordSize - b.length%wordSize) - } -} - -// Complement computes the (local) complement of a biset (up to length bits) -func (b *BitSet) Complement() (result *BitSet) { - panicIfNull(b) - result = New(b.length) - for i, word := range b.set { - result.set[i] = ^word - } - result.cleanLastWord() - return -} - -// All returns true if all bits are set, false otherwise. Returns true for -// empty sets. -func (b *BitSet) All() bool { - panicIfNull(b) - return b.Count() == b.length -} - -// None returns true if no bit is set, false otherwise. Returns true for -// empty sets. -func (b *BitSet) None() bool { - panicIfNull(b) - if b != nil && b.set != nil { - for _, word := range b.set { - if word > 0 { - return false - } - } - return true - } - return true -} - -// Any returns true if any bit is set, false otherwise -func (b *BitSet) Any() bool { - panicIfNull(b) - return !b.None() -} - -// IsSuperSet returns true if this is a superset of the other set -func (b *BitSet) IsSuperSet(other *BitSet) bool { - for i, e := other.NextSet(0); e; i, e = other.NextSet(i + 1) { - if !b.Test(i) { - return false - } - } - return true -} - -// IsStrictSuperSet returns true if this is a strict superset of the other set -func (b *BitSet) IsStrictSuperSet(other *BitSet) bool { - return b.Count() > other.Count() && b.IsSuperSet(other) -} - -// DumpAsBits dumps a bit set as a string of bits -func (b *BitSet) DumpAsBits() string { - if b.set == nil { - return "." - } - buffer := bytes.NewBufferString("") - i := len(b.set) - 1 - for ; i >= 0; i-- { - fmt.Fprintf(buffer, "%064b.", b.set[i]) - } - return buffer.String() -} - -// BinaryStorageSize returns the binary storage requirements -func (b *BitSet) BinaryStorageSize() int { - return binary.Size(uint64(0)) + binary.Size(b.set) -} - -// WriteTo writes a BitSet to a stream -func (b *BitSet) WriteTo(stream io.Writer) (int64, error) { - length := uint64(b.length) - - // Write length - err := binary.Write(stream, binaryOrder, length) - if err != nil { - return 0, err - } - - // Write set - err = binary.Write(stream, binaryOrder, b.set) - return int64(b.BinaryStorageSize()), err -} - -// ReadFrom reads a BitSet from a stream written using WriteTo -func (b *BitSet) ReadFrom(stream io.Reader) (int64, error) { - var length uint64 - - // Read length first - err := binary.Read(stream, binaryOrder, &length) - if err != nil { - return 0, err - } - newset := New(uint(length)) - - if uint64(newset.length) != length { - return 0, errors.New("unmarshalling error: type mismatch") - } - - // Read remaining bytes as set - err = binary.Read(stream, binaryOrder, newset.set) - if err != nil { - return 0, err - } - - *b = *newset - return int64(b.BinaryStorageSize()), nil -} - -// MarshalBinary encodes a BitSet into a binary form and returns the result. -func (b *BitSet) MarshalBinary() ([]byte, error) { - var buf bytes.Buffer - writer := bufio.NewWriter(&buf) - - _, err := b.WriteTo(writer) - if err != nil { - return []byte{}, err - } - - err = writer.Flush() - - return buf.Bytes(), err -} - -// UnmarshalBinary decodes the binary form generated by MarshalBinary. -func (b *BitSet) UnmarshalBinary(data []byte) error { - buf := bytes.NewReader(data) - reader := bufio.NewReader(buf) - - _, err := b.ReadFrom(reader) - - return err -} - -// MarshalJSON marshals a BitSet as a JSON structure -func (b *BitSet) MarshalJSON() ([]byte, error) { - buffer := bytes.NewBuffer(make([]byte, 0, b.BinaryStorageSize())) - _, err := b.WriteTo(buffer) - if err != nil { - return nil, err - } - - // URLEncode all bytes - return json.Marshal(base64Encoding.EncodeToString(buffer.Bytes())) -} - -// UnmarshalJSON unmarshals a BitSet from JSON created using MarshalJSON -func (b *BitSet) UnmarshalJSON(data []byte) error { - // Unmarshal as string - var s string - err := json.Unmarshal(data, &s) - if err != nil { - return err - } - - // URLDecode string - buf, err := base64Encoding.DecodeString(s) - if err != nil { - return err - } - - _, err = b.ReadFrom(bytes.NewReader(buf)) - return err -} diff --git a/vendor/github.com/bits-and-blooms/bitset/go.mod b/vendor/github.com/bits-and-blooms/bitset/go.mod deleted file mode 100644 index c43e4522b7f95..0000000000000 --- a/vendor/github.com/bits-and-blooms/bitset/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/bits-and-blooms/bitset - -go 1.14 diff --git a/vendor/github.com/bits-and-blooms/bitset/go.sum b/vendor/github.com/bits-and-blooms/bitset/go.sum deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt.go b/vendor/github.com/bits-and-blooms/bitset/popcnt.go deleted file mode 100644 index 76577a8382844..0000000000000 --- a/vendor/github.com/bits-and-blooms/bitset/popcnt.go +++ /dev/null @@ -1,53 +0,0 @@ -package bitset - -// bit population count, take from -// https://code.google.com/p/go/issues/detail?id=4988#c11 -// credit: https://code.google.com/u/arnehormann/ -func popcount(x uint64) (n uint64) { - x -= (x >> 1) & 0x5555555555555555 - x = (x>>2)&0x3333333333333333 + x&0x3333333333333333 - x += x >> 4 - x &= 0x0f0f0f0f0f0f0f0f - x *= 0x0101010101010101 - return x >> 56 -} - -func popcntSliceGo(s []uint64) uint64 { - cnt := uint64(0) - for _, x := range s { - cnt += popcount(x) - } - return cnt -} - -func popcntMaskSliceGo(s, m []uint64) uint64 { - cnt := uint64(0) - for i := range s { - cnt += popcount(s[i] &^ m[i]) - } - return cnt -} - -func popcntAndSliceGo(s, m []uint64) uint64 { - cnt := uint64(0) - for i := range s { - cnt += popcount(s[i] & m[i]) - } - return cnt -} - -func popcntOrSliceGo(s, m []uint64) uint64 { - cnt := uint64(0) - for i := range s { - cnt += popcount(s[i] | m[i]) - } - return cnt -} - -func popcntXorSliceGo(s, m []uint64) uint64 { - cnt := uint64(0) - for i := range s { - cnt += popcount(s[i] ^ m[i]) - } - return cnt -} diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go b/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go deleted file mode 100644 index fc8ff4f367c23..0000000000000 --- a/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go +++ /dev/null @@ -1,45 +0,0 @@ -// +build go1.9 - -package bitset - -import "math/bits" - -func popcntSlice(s []uint64) uint64 { - var cnt int - for _, x := range s { - cnt += bits.OnesCount64(x) - } - return uint64(cnt) -} - -func popcntMaskSlice(s, m []uint64) uint64 { - var cnt int - for i := range s { - cnt += bits.OnesCount64(s[i] &^ m[i]) - } - return uint64(cnt) -} - -func popcntAndSlice(s, m []uint64) uint64 { - var cnt int - for i := range s { - cnt += bits.OnesCount64(s[i] & m[i]) - } - return uint64(cnt) -} - -func popcntOrSlice(s, m []uint64) uint64 { - var cnt int - for i := range s { - cnt += bits.OnesCount64(s[i] | m[i]) - } - return uint64(cnt) -} - -func popcntXorSlice(s, m []uint64) uint64 { - var cnt int - for i := range s { - cnt += bits.OnesCount64(s[i] ^ m[i]) - } - return uint64(cnt) -} diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go b/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go deleted file mode 100644 index 4cf64f24ad03f..0000000000000 --- a/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go +++ /dev/null @@ -1,68 +0,0 @@ -// +build !go1.9 -// +build amd64,!appengine - -package bitset - -// *** the following functions are defined in popcnt_amd64.s - -//go:noescape - -func hasAsm() bool - -// useAsm is a flag used to select the GO or ASM implementation of the popcnt function -var useAsm = hasAsm() - -//go:noescape - -func popcntSliceAsm(s []uint64) uint64 - -//go:noescape - -func popcntMaskSliceAsm(s, m []uint64) uint64 - -//go:noescape - -func popcntAndSliceAsm(s, m []uint64) uint64 - -//go:noescape - -func popcntOrSliceAsm(s, m []uint64) uint64 - -//go:noescape - -func popcntXorSliceAsm(s, m []uint64) uint64 - -func popcntSlice(s []uint64) uint64 { - if useAsm { - return popcntSliceAsm(s) - } - return popcntSliceGo(s) -} - -func popcntMaskSlice(s, m []uint64) uint64 { - if useAsm { - return popcntMaskSliceAsm(s, m) - } - return popcntMaskSliceGo(s, m) -} - -func popcntAndSlice(s, m []uint64) uint64 { - if useAsm { - return popcntAndSliceAsm(s, m) - } - return popcntAndSliceGo(s, m) -} - -func popcntOrSlice(s, m []uint64) uint64 { - if useAsm { - return popcntOrSliceAsm(s, m) - } - return popcntOrSliceGo(s, m) -} - -func popcntXorSlice(s, m []uint64) uint64 { - if useAsm { - return popcntXorSliceAsm(s, m) - } - return popcntXorSliceGo(s, m) -} diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s b/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s deleted file mode 100644 index 666c0dcc17f5a..0000000000000 --- a/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s +++ /dev/null @@ -1,104 +0,0 @@ -// +build !go1.9 -// +build amd64,!appengine - -TEXT ·hasAsm(SB),4,$0-1 -MOVQ $1, AX -CPUID -SHRQ $23, CX -ANDQ $1, CX -MOVB CX, ret+0(FP) -RET - -#define POPCNTQ_DX_DX BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0xd2 - -TEXT ·popcntSliceAsm(SB),4,$0-32 -XORQ AX, AX -MOVQ s+0(FP), SI -MOVQ s_len+8(FP), CX -TESTQ CX, CX -JZ popcntSliceEnd -popcntSliceLoop: -BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0x16 // POPCNTQ (SI), DX -ADDQ DX, AX -ADDQ $8, SI -LOOP popcntSliceLoop -popcntSliceEnd: -MOVQ AX, ret+24(FP) -RET - -TEXT ·popcntMaskSliceAsm(SB),4,$0-56 -XORQ AX, AX -MOVQ s+0(FP), SI -MOVQ s_len+8(FP), CX -TESTQ CX, CX -JZ popcntMaskSliceEnd -MOVQ m+24(FP), DI -popcntMaskSliceLoop: -MOVQ (DI), DX -NOTQ DX -ANDQ (SI), DX -POPCNTQ_DX_DX -ADDQ DX, AX -ADDQ $8, SI -ADDQ $8, DI -LOOP popcntMaskSliceLoop -popcntMaskSliceEnd: -MOVQ AX, ret+48(FP) -RET - -TEXT ·popcntAndSliceAsm(SB),4,$0-56 -XORQ AX, AX -MOVQ s+0(FP), SI -MOVQ s_len+8(FP), CX -TESTQ CX, CX -JZ popcntAndSliceEnd -MOVQ m+24(FP), DI -popcntAndSliceLoop: -MOVQ (DI), DX -ANDQ (SI), DX -POPCNTQ_DX_DX -ADDQ DX, AX -ADDQ $8, SI -ADDQ $8, DI -LOOP popcntAndSliceLoop -popcntAndSliceEnd: -MOVQ AX, ret+48(FP) -RET - -TEXT ·popcntOrSliceAsm(SB),4,$0-56 -XORQ AX, AX -MOVQ s+0(FP), SI -MOVQ s_len+8(FP), CX -TESTQ CX, CX -JZ popcntOrSliceEnd -MOVQ m+24(FP), DI -popcntOrSliceLoop: -MOVQ (DI), DX -ORQ (SI), DX -POPCNTQ_DX_DX -ADDQ DX, AX -ADDQ $8, SI -ADDQ $8, DI -LOOP popcntOrSliceLoop -popcntOrSliceEnd: -MOVQ AX, ret+48(FP) -RET - -TEXT ·popcntXorSliceAsm(SB),4,$0-56 -XORQ AX, AX -MOVQ s+0(FP), SI -MOVQ s_len+8(FP), CX -TESTQ CX, CX -JZ popcntXorSliceEnd -MOVQ m+24(FP), DI -popcntXorSliceLoop: -MOVQ (DI), DX -XORQ (SI), DX -POPCNTQ_DX_DX -ADDQ DX, AX -ADDQ $8, SI -ADDQ $8, DI -LOOP popcntXorSliceLoop -popcntXorSliceEnd: -MOVQ AX, ret+48(FP) -RET diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go b/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go deleted file mode 100644 index 21e0ff7b4fc5c..0000000000000 --- a/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go +++ /dev/null @@ -1,24 +0,0 @@ -// +build !go1.9 -// +build !amd64 appengine - -package bitset - -func popcntSlice(s []uint64) uint64 { - return popcntSliceGo(s) -} - -func popcntMaskSlice(s, m []uint64) uint64 { - return popcntMaskSliceGo(s, m) -} - -func popcntAndSlice(s, m []uint64) uint64 { - return popcntAndSliceGo(s, m) -} - -func popcntOrSlice(s, m []uint64) uint64 { - return popcntOrSliceGo(s, m) -} - -func popcntXorSlice(s, m []uint64) uint64 { - return popcntXorSliceGo(s, m) -} diff --git a/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go b/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go deleted file mode 100644 index c52b61be9fc2b..0000000000000 --- a/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go +++ /dev/null @@ -1,14 +0,0 @@ -// +build !go1.9 - -package bitset - -var deBruijn = [...]byte{ - 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4, - 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5, - 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11, - 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6, -} - -func trailingZeroes64(v uint64) uint { - return uint(deBruijn[((v&-v)*0x03f79d71b4ca8b09)>>58]) -} diff --git a/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go b/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go deleted file mode 100644 index 36a988e714d15..0000000000000 --- a/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build go1.9 - -package bitset - -import "math/bits" - -func trailingZeroes64(v uint64) uint { - return uint(bits.TrailingZeros64(v)) -} diff --git a/vendor/github.com/checkpoint-restore/go-criu/v5/.gitignore b/vendor/github.com/checkpoint-restore/go-criu/v5/.gitignore index d99bf92cfef76..1b87ff10e6b87 100644 --- a/vendor/github.com/checkpoint-restore/go-criu/v5/.gitignore +++ b/vendor/github.com/checkpoint-restore/go-criu/v5/.gitignore @@ -1,6 +1,6 @@ test/test +test/test.coverage test/piggie/piggie -test/phaul +test/phaul/phaul +test/phaul/phaul.coverage image -rpc/rpc.proto -stats/stats.proto diff --git a/vendor/github.com/checkpoint-restore/go-criu/v5/Makefile b/vendor/github.com/checkpoint-restore/go-criu/v5/Makefile index 2c303a3c9f422..67c43a05b32b7 100644 --- a/vendor/github.com/checkpoint-restore/go-criu/v5/Makefile +++ b/vendor/github.com/checkpoint-restore/go-criu/v5/Makefile @@ -1,5 +1,12 @@ +SHELL = /bin/bash GO ?= go CC ?= gcc +COVERAGE_PATH ?= $(shell pwd)/.coverage +CRIU_FEATURE_MEM_TRACK = $(shell if criu check --feature mem_dirty_track > /dev/null; then echo 1; else echo 0; fi) +CRIU_FEATURE_LAZY_PAGES = $(shell if criu check --feature uffd-noncoop > /dev/null; then echo 1; else echo 0; fi) +CRIU_FEATURE_PIDFD_STORE = $(shell if criu check --feature pidfd_store > /dev/null; then echo 1; else echo 0; fi) + +export CRIU_FEATURE_MEM_TRACK CRIU_FEATURE_LAZY_PAGES CRIU_FEATURE_PIDFD_STORE all: build test phaul-test @@ -9,13 +16,15 @@ lint: build: $(GO) build -v ./... -TEST_BINARIES := test/test test/piggie/piggie test/phaul/phaul +TEST_PAYLOAD := test/piggie/piggie +TEST_BINARIES := test/test $(TEST_PAYLOAD) test/phaul/phaul +COVERAGE_BINARIES := test/test.coverage test/phaul/phaul.coverage test-bin: $(TEST_BINARIES) test/piggie/piggie: test/piggie/piggie.c $(CC) $^ -o $@ -test/test: test/*.go +test/test: test/main.go $(GO) build -v -o $@ $^ test: $(TEST_BINARIES) @@ -27,7 +36,7 @@ test: $(TEST_BINARIES) } rm -rf image -test/phaul/phaul: test/phaul/*.go +test/phaul/phaul: test/phaul/main.go $(GO) build -v -o $@ $^ phaul-test: $(TEST_BINARIES) @@ -37,10 +46,41 @@ phaul-test: $(TEST_BINARIES) pkill -9 piggie; \ } +test/test.coverage: test/*.go + $(GO) test \ + -covermode=count \ + -coverpkg=./... \ + -mod=vendor \ + -tags coverage \ + -buildmode=pie -c -o $@ $^ + +test/phaul/phaul.coverage: test/phaul/*.go + $(GO) test \ + -covermode=count \ + -coverpkg=./... \ + -mod=vendor \ + -tags coverage \ + -buildmode=pie -c -o $@ $^ + +coverage: $(COVERAGE_BINARIES) $(TEST_PAYLOAD) + mkdir -p $(COVERAGE_PATH) + mkdir -p image + PID=$$(test/piggie/piggie) && { \ + test/test.coverage -test.coverprofile=coverprofile.integration.$$RANDOM -test.outputdir=${COVERAGE_PATH} COVERAGE dump $$PID image && \ + test/test.coverage -test.coverprofile=coverprofile.integration.$$RANDOM -test.outputdir=${COVERAGE_PATH} COVERAGE restore image; \ + pkill -9 piggie; \ + } + rm -rf image + PID=$$(test/piggie/piggie) && { \ + test/phaul/phaul.coverage -test.coverprofile=coverprofile.integration.$$RANDOM -test.outputdir=${COVERAGE_PATH} COVERAGE $$PID; \ + pkill -9 piggie; \ + } + echo "mode: set" > .coverage/coverage.out && cat .coverage/coverprofile* | \ + grep -v mode: | sort -r | awk '{if($$1 != last) {print $$0;last=$$1}}' >> .coverage/coverage.out + clean: - @rm -f $(TEST_BINARIES) - @rm -rf image - @rm -f rpc/rpc.proto stats/stats.proto + @rm -f $(TEST_BINARIES) $(COVERAGE_BINARIES) codecov + @rm -rf image $(COVERAGE_PATH) rpc/rpc.proto: curl -sSL https://raw.githubusercontent.com/checkpoint-restore/criu/master/images/rpc.proto -o $@ @@ -49,9 +89,19 @@ stats/stats.proto: curl -sSL https://raw.githubusercontent.com/checkpoint-restore/criu/master/images/stats.proto -o $@ rpc/rpc.pb.go: rpc/rpc.proto - protoc --go_out=. $^ + protoc --go_out=. --go_opt=M$^=rpc/ $^ stats/stats.pb.go: stats/stats.proto - protoc --go_out=. $^ + protoc --go_out=. --go_opt=M$^=stats/ $^ + +vendor: + GO111MODULE=on $(GO) mod tidy + GO111MODULE=on $(GO) mod vendor + GO111MODULE=on $(GO) mod verify + +codecov: + curl -Os https://uploader.codecov.io/latest/linux/codecov + chmod +x codecov + ./codecov -f '.coverage/coverage.out' -.PHONY: build test phaul-test test-bin clean lint +.PHONY: build test phaul-test test-bin clean lint vendor coverage codecov diff --git a/vendor/github.com/checkpoint-restore/go-criu/v5/README.md b/vendor/github.com/checkpoint-restore/go-criu/v5/README.md index 390da3e98b079..a7483321b5c3f 100644 --- a/vendor/github.com/checkpoint-restore/go-criu/v5/README.md +++ b/vendor/github.com/checkpoint-restore/go-criu/v5/README.md @@ -16,7 +16,7 @@ The following example would print the version of CRIU: import ( "log" - "github.com/checkpoint/restore/go-criu/v5" + "github.com/checkpoint-restore/go-criu/v5" ) func main() { @@ -50,6 +50,7 @@ The following table shows the relation between go-criu and criu versions: | Major version | Latest release | CRIU version | | -------------- | -------------- | ------------ | +| v5             | 5.2.0         | 3.16         | | v5             | 5.0.0         | 3.15         | | v4             | 4.1.0         | 3.14         | diff --git a/vendor/github.com/checkpoint-restore/go-criu/v5/features.go b/vendor/github.com/checkpoint-restore/go-criu/v5/features.go new file mode 100644 index 0000000000000..c7127f95157a1 --- /dev/null +++ b/vendor/github.com/checkpoint-restore/go-criu/v5/features.go @@ -0,0 +1,45 @@ +package criu + +import ( + "fmt" + + "github.com/checkpoint-restore/go-criu/v5/rpc" +) + +// Feature checking in go-criu is based on the libcriu feature checking function. + +// Feature checking allows the user to check if CRIU supports +// certain features. There are CRIU features which do not depend +// on the version of CRIU but on kernel features or architecture. +// +// One example is memory tracking. Memory tracking can be disabled +// in the kernel or there are architectures which do not support +// it (aarch64 for example). By using the feature check a libcriu +// user can easily query CRIU if a certain feature is available. +// +// The features which should be checked can be marked in the +// structure 'struct criu_feature_check'. Each structure member +// that is set to true will result in CRIU checking for the +// availability of that feature in the current combination of +// CRIU/kernel/architecture. +// +// Available features will be set to true when the function +// returns successfully. Missing features will be set to false. + +func (c *Criu) FeatureCheck(features *rpc.CriuFeatures) (*rpc.CriuFeatures, error) { + resp, err := c.doSwrkWithResp( + rpc.CriuReqType_FEATURE_CHECK, + nil, + nil, + features, + ) + if err != nil { + return nil, err + } + + if resp.GetType() != rpc.CriuReqType_FEATURE_CHECK { + return nil, fmt.Errorf("Unexpected CRIU RPC response") + } + + return features, nil +} diff --git a/vendor/github.com/checkpoint-restore/go-criu/v5/go.mod b/vendor/github.com/checkpoint-restore/go-criu/v5/go.mod index 58931e5f98376..cf4fea9f05e79 100644 --- a/vendor/github.com/checkpoint-restore/go-criu/v5/go.mod +++ b/vendor/github.com/checkpoint-restore/go-criu/v5/go.mod @@ -3,7 +3,6 @@ module github.com/checkpoint-restore/go-criu/v5 go 1.13 require ( - github.com/golang/protobuf v1.4.3 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c - google.golang.org/protobuf v1.23.0 + google.golang.org/protobuf v1.27.1 ) diff --git a/vendor/github.com/checkpoint-restore/go-criu/v5/go.sum b/vendor/github.com/checkpoint-restore/go-criu/v5/go.sum index 0a5a48cde74c8..789fdcb11aa95 100644 --- a/vendor/github.com/checkpoint-restore/go-criu/v5/go.sum +++ b/vendor/github.com/checkpoint-restore/go-criu/v5/go.sum @@ -1,22 +1,10 @@ -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= diff --git a/vendor/github.com/checkpoint-restore/go-criu/v5/main.go b/vendor/github.com/checkpoint-restore/go-criu/v5/main.go index 78811c309ce26..88b1b24587afa 100644 --- a/vendor/github.com/checkpoint-restore/go-criu/v5/main.go +++ b/vendor/github.com/checkpoint-restore/go-criu/v5/main.go @@ -87,19 +87,19 @@ func (c *Criu) sendAndRecv(reqB []byte) ([]byte, int, error) { } func (c *Criu) doSwrk(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify) error { - resp, err := c.doSwrkWithResp(reqType, opts, nfy) + resp, err := c.doSwrkWithResp(reqType, opts, nfy, nil) if err != nil { return err } respType := resp.GetType() if respType != reqType { - return errors.New("unexpected responce") + return errors.New("unexpected CRIU RPC response") } return nil } -func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify) (*rpc.CriuResp, error) { +func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify, features *rpc.CriuFeatures) (*rpc.CriuResp, error) { var resp *rpc.CriuResp req := rpc.CriuReq{ @@ -111,6 +111,10 @@ func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy N opts.NotifyScripts = proto.Bool(true) } + if features != nil { + req.Features = features + } + if c.swrkCmd == nil { err := c.Prepare() if err != nil { @@ -209,7 +213,7 @@ func (c *Criu) StartPageServer(opts *rpc.CriuOpts) error { // StartPageServerChld starts the page server and returns PID and port func (c *Criu) StartPageServerChld(opts *rpc.CriuOpts) (int, int, error) { - resp, err := c.doSwrkWithResp(rpc.CriuReqType_PAGE_SERVER_CHLD, opts, nil) + resp, err := c.doSwrkWithResp(rpc.CriuReqType_PAGE_SERVER_CHLD, opts, nil, nil) if err != nil { return 0, 0, err } @@ -220,7 +224,7 @@ func (c *Criu) StartPageServerChld(opts *rpc.CriuOpts) (int, int, error) { // GetCriuVersion executes the VERSION RPC call and returns the version // as an integer. Major * 10000 + Minor * 100 + SubLevel func (c *Criu) GetCriuVersion() (int, error) { - resp, err := c.doSwrkWithResp(rpc.CriuReqType_VERSION, nil, nil) + resp, err := c.doSwrkWithResp(rpc.CriuReqType_VERSION, nil, nil, nil) if err != nil { return 0, err } diff --git a/vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.pb.go b/vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.pb.go index fa37f93cbd6df..15e33fea52fd4 100644 --- a/vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.pb.go +++ b/vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.pb.go @@ -1,13 +1,14 @@ +// SPDX-License-Identifier: MIT + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 +// protoc-gen-go v1.27.1 // protoc v3.12.4 // source: rpc/rpc.proto package rpc import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -21,10 +22,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - type CriuCgMode int32 const ( @@ -706,7 +703,9 @@ type CriuOpts struct { Tls *bool `protobuf:"varint,58,opt,name=tls" json:"tls,omitempty"` TlsNoCnVerify *bool `protobuf:"varint,59,opt,name=tls_no_cn_verify,json=tlsNoCnVerify" json:"tls_no_cn_verify,omitempty"` CgroupYard *string `protobuf:"bytes,60,opt,name=cgroup_yard,json=cgroupYard" json:"cgroup_yard,omitempty"` - PreDumpMode *CriuPreDumpMode `protobuf:"varint,61,opt,name=pre_dump_mode,json=preDumpMode,enum=CriuPreDumpMode,def=1" json:"pre_dump_mode,omitempty"` // optional bool check_mounts = 128; + PreDumpMode *CriuPreDumpMode `protobuf:"varint,61,opt,name=pre_dump_mode,json=preDumpMode,enum=CriuPreDumpMode,def=1" json:"pre_dump_mode,omitempty"` + PidfdStoreSk *int32 `protobuf:"varint,62,opt,name=pidfd_store_sk,json=pidfdStoreSk" json:"pidfd_store_sk,omitempty"` + LsmMountContext *string `protobuf:"bytes,63,opt,name=lsm_mount_context,json=lsmMountContext" json:"lsm_mount_context,omitempty"` // optional bool check_mounts = 128; } // Default values for CriuOpts fields. @@ -1169,6 +1168,20 @@ func (x *CriuOpts) GetPreDumpMode() CriuPreDumpMode { return Default_CriuOpts_PreDumpMode } +func (x *CriuOpts) GetPidfdStoreSk() int32 { + if x != nil && x.PidfdStoreSk != nil { + return *x.PidfdStoreSk + } + return 0 +} + +func (x *CriuOpts) GetLsmMountContext() string { + if x != nil && x.LsmMountContext != nil { + return *x.LsmMountContext + } + return "" +} + type CriuDumpResp struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1326,8 +1339,9 @@ type CriuFeatures struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - MemTrack *bool `protobuf:"varint,1,opt,name=mem_track,json=memTrack" json:"mem_track,omitempty"` - LazyPages *bool `protobuf:"varint,2,opt,name=lazy_pages,json=lazyPages" json:"lazy_pages,omitempty"` + MemTrack *bool `protobuf:"varint,1,opt,name=mem_track,json=memTrack" json:"mem_track,omitempty"` + LazyPages *bool `protobuf:"varint,2,opt,name=lazy_pages,json=lazyPages" json:"lazy_pages,omitempty"` + PidfdStore *bool `protobuf:"varint,3,opt,name=pidfd_store,json=pidfdStore" json:"pidfd_store,omitempty"` } func (x *CriuFeatures) Reset() { @@ -1376,6 +1390,13 @@ func (x *CriuFeatures) GetLazyPages() bool { return false } +func (x *CriuFeatures) GetPidfdStore() bool { + if x != nil && x.PidfdStore != nil { + return *x.PidfdStore + } + return false +} + type CriuReq struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1718,7 +1739,7 @@ var file_rpc_rpc_proto_rawDesc = []byte{ 0x52, 0x04, 0x63, 0x74, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0x1f, 0x0a, 0x07, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x73, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, - 0x20, 0x02, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0xba, 0x10, 0x0a, 0x09, + 0x20, 0x02, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x8c, 0x11, 0x0a, 0x09, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x6f, 0x70, 0x74, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x5f, 0x64, 0x69, 0x72, 0x5f, 0x66, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x05, 0x52, 0x0b, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x44, 0x69, 0x72, 0x46, 0x64, 0x12, 0x10, 0x0a, @@ -1850,92 +1871,100 @@ var file_rpc_rpc_proto_rawDesc = []byte{ 0x75, 0x6d, 0x70, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x3d, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x70, 0x72, 0x65, 0x5f, 0x64, 0x75, 0x6d, 0x70, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x3a, 0x06, 0x53, 0x50, 0x4c, 0x49, 0x43, 0x45, 0x52, 0x0b, 0x70, 0x72, 0x65, - 0x44, 0x75, 0x6d, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x22, 0x2c, 0x0a, 0x0e, 0x63, 0x72, 0x69, 0x75, - 0x5f, 0x64, 0x75, 0x6d, 0x70, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x22, 0x25, 0x0a, 0x11, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x72, - 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x70, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x05, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x37, 0x0a, - 0x0b, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, 0x16, 0x0a, 0x06, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x4b, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x66, - 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, 0x5f, 0x74, - 0x72, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x54, - 0x72, 0x61, 0x63, 0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x7a, 0x79, 0x5f, 0x70, 0x61, 0x67, - 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6c, 0x61, 0x7a, 0x79, 0x50, 0x61, - 0x67, 0x65, 0x73, 0x22, 0xd0, 0x01, 0x0a, 0x08, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x72, 0x65, 0x71, - 0x12, 0x22, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x0e, 0x32, 0x0e, - 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x72, 0x65, 0x71, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x12, 0x1e, 0x0a, 0x04, 0x6f, 0x70, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x6f, 0x70, 0x74, 0x73, 0x52, 0x04, - 0x6f, 0x70, 0x74, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x5f, 0x73, - 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6b, - 0x65, 0x65, 0x70, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, - 0x6b, 0x65, 0x65, 0x70, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x2a, 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x72, 0x69, - 0x75, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x08, 0x66, 0x65, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x8f, 0x03, 0x0a, 0x09, 0x63, 0x72, 0x69, 0x75, 0x5f, - 0x72, 0x65, 0x73, 0x70, 0x12, 0x22, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x02, - 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x72, 0x65, 0x71, 0x5f, 0x74, 0x79, - 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x02, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x12, 0x23, 0x0a, 0x04, 0x64, 0x75, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0f, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x64, 0x75, 0x6d, 0x70, 0x5f, 0x72, 0x65, 0x73, - 0x70, 0x52, 0x04, 0x64, 0x75, 0x6d, 0x70, 0x12, 0x2c, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, - 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x52, 0x07, 0x72, 0x65, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x24, 0x0a, 0x06, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x6e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x52, 0x06, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, 0x26, 0x0a, 0x02, 0x70, - 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x70, - 0x61, 0x67, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x52, - 0x02, 0x70, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x72, 0x5f, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x63, 0x72, 0x45, 0x72, 0x72, 0x6e, 0x6f, 0x12, 0x2a, - 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0e, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, - 0x52, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x72, - 0x5f, 0x65, 0x72, 0x72, 0x6d, 0x73, 0x67, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, - 0x72, 0x45, 0x72, 0x72, 0x6d, 0x73, 0x67, 0x12, 0x27, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xb0, 0x01, 0x0a, 0x0c, 0x63, 0x72, 0x69, - 0x75, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x6a, - 0x6f, 0x72, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x02, 0x28, 0x05, 0x52, - 0x0b, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, - 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x02, - 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, - 0x14, 0x0a, 0x05, 0x67, 0x69, 0x74, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x67, 0x69, 0x74, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x75, 0x62, 0x6c, 0x65, 0x76, 0x65, - 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x73, 0x75, 0x62, 0x6c, 0x65, 0x76, 0x65, - 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x2a, 0x5f, 0x0a, 0x0c, 0x63, - 0x72, 0x69, 0x75, 0x5f, 0x63, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x49, - 0x47, 0x4e, 0x4f, 0x52, 0x45, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x47, 0x5f, 0x4e, 0x4f, - 0x4e, 0x45, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x52, 0x4f, 0x50, 0x53, 0x10, 0x02, 0x12, - 0x08, 0x0a, 0x04, 0x53, 0x4f, 0x46, 0x54, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x55, 0x4c, - 0x4c, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x43, 0x54, 0x10, 0x05, 0x12, - 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x06, 0x2a, 0x2d, 0x0a, 0x12, - 0x63, 0x72, 0x69, 0x75, 0x5f, 0x70, 0x72, 0x65, 0x5f, 0x64, 0x75, 0x6d, 0x70, 0x5f, 0x6d, 0x6f, - 0x64, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x50, 0x4c, 0x49, 0x43, 0x45, 0x10, 0x01, 0x12, 0x0b, - 0x0a, 0x07, 0x56, 0x4d, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x10, 0x02, 0x2a, 0xd0, 0x01, 0x0a, 0x0d, - 0x63, 0x72, 0x69, 0x75, 0x5f, 0x72, 0x65, 0x71, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, - 0x05, 0x45, 0x4d, 0x50, 0x54, 0x59, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x55, 0x4d, 0x50, - 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x53, 0x54, 0x4f, 0x52, 0x45, 0x10, 0x02, 0x12, - 0x09, 0x0a, 0x05, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x52, - 0x45, 0x5f, 0x44, 0x55, 0x4d, 0x50, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x41, 0x47, 0x45, - 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x54, - 0x49, 0x46, 0x59, 0x10, 0x06, 0x12, 0x10, 0x0a, 0x0c, 0x43, 0x50, 0x55, 0x49, 0x4e, 0x46, 0x4f, - 0x5f, 0x44, 0x55, 0x4d, 0x50, 0x10, 0x07, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x50, 0x55, 0x49, 0x4e, - 0x46, 0x4f, 0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x10, 0x08, 0x12, 0x11, 0x0a, 0x0d, 0x46, 0x45, - 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x10, 0x09, 0x12, 0x0b, 0x0a, - 0x07, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x0a, 0x12, 0x0c, 0x0a, 0x08, 0x57, 0x41, - 0x49, 0x54, 0x5f, 0x50, 0x49, 0x44, 0x10, 0x0b, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x41, 0x47, 0x45, - 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x43, 0x48, 0x4c, 0x44, 0x10, 0x0c, + 0x44, 0x75, 0x6d, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x69, 0x64, 0x66, + 0x64, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x73, 0x6b, 0x18, 0x3e, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0c, 0x70, 0x69, 0x64, 0x66, 0x64, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x6b, 0x12, 0x2a, + 0x0a, 0x11, 0x6c, 0x73, 0x6d, 0x5f, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x18, 0x3f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6c, 0x73, 0x6d, 0x4d, 0x6f, + 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x2c, 0x0a, 0x0e, 0x63, 0x72, + 0x69, 0x75, 0x5f, 0x64, 0x75, 0x6d, 0x70, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x12, 0x1a, 0x0a, 0x08, + 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, + 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x22, 0x25, 0x0a, 0x11, 0x63, 0x72, 0x69, 0x75, + 0x5f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x12, 0x10, 0x0a, + 0x03, 0x70, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x05, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, + 0x37, 0x0a, 0x0b, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x6c, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x75, + 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, + 0x5f, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6d, 0x65, + 0x6d, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x7a, 0x79, 0x5f, 0x70, + 0x61, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6c, 0x61, 0x7a, 0x79, + 0x50, 0x61, 0x67, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x69, 0x64, 0x66, 0x64, 0x5f, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x70, 0x69, 0x64, 0x66, + 0x64, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0xd0, 0x01, 0x0a, 0x08, 0x63, 0x72, 0x69, 0x75, 0x5f, + 0x72, 0x65, 0x71, 0x12, 0x22, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, + 0x0e, 0x32, 0x0e, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x72, 0x65, 0x71, 0x5f, 0x74, 0x79, 0x70, + 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1e, 0x0a, 0x04, 0x6f, 0x70, 0x74, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x6f, 0x70, 0x74, + 0x73, 0x52, 0x04, 0x6f, 0x70, 0x74, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6e, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x5f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0d, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x1b, + 0x0a, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x08, 0x6b, 0x65, 0x65, 0x70, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x2a, 0x0a, 0x08, 0x66, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, + 0x63, 0x72, 0x69, 0x75, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x08, 0x66, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x8f, 0x03, 0x0a, 0x09, 0x63, 0x72, + 0x69, 0x75, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x12, 0x22, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x01, 0x20, 0x02, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x72, 0x65, 0x71, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, + 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x02, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x04, 0x64, 0x75, 0x6d, 0x70, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x64, 0x75, 0x6d, 0x70, 0x5f, + 0x72, 0x65, 0x73, 0x70, 0x52, 0x04, 0x64, 0x75, 0x6d, 0x70, 0x12, 0x2c, 0x0a, 0x07, 0x72, 0x65, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x72, + 0x69, 0x75, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x52, + 0x07, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x24, 0x0a, 0x06, 0x6e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x06, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, 0x26, + 0x0a, 0x02, 0x70, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, 0x69, + 0x75, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x6e, + 0x66, 0x6f, 0x52, 0x02, 0x70, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x72, 0x5f, 0x65, 0x72, 0x72, + 0x6e, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x63, 0x72, 0x45, 0x72, 0x72, 0x6e, + 0x6f, 0x12, 0x2a, 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x73, 0x52, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x1b, 0x0a, + 0x09, 0x63, 0x72, 0x5f, 0x65, 0x72, 0x72, 0x6d, 0x73, 0x67, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x63, 0x72, 0x45, 0x72, 0x72, 0x6d, 0x73, 0x67, 0x12, 0x27, 0x0a, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x72, + 0x69, 0x75, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xb0, 0x01, 0x0a, 0x0c, + 0x63, 0x72, 0x69, 0x75, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, + 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x02, + 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, + 0x21, 0x0a, 0x0c, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, + 0x02, 0x20, 0x02, 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x69, 0x74, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x67, 0x69, 0x74, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x75, 0x62, 0x6c, + 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x73, 0x75, 0x62, 0x6c, + 0x65, 0x76, 0x65, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x2a, 0x5f, + 0x0a, 0x0c, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x63, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x0a, + 0x0a, 0x06, 0x49, 0x47, 0x4e, 0x4f, 0x52, 0x45, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x47, + 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x52, 0x4f, 0x50, 0x53, + 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x4f, 0x46, 0x54, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, + 0x46, 0x55, 0x4c, 0x4c, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x43, 0x54, + 0x10, 0x05, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x06, 0x2a, + 0x2d, 0x0a, 0x12, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x70, 0x72, 0x65, 0x5f, 0x64, 0x75, 0x6d, 0x70, + 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x50, 0x4c, 0x49, 0x43, 0x45, 0x10, + 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x56, 0x4d, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x10, 0x02, 0x2a, 0xd0, + 0x01, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x72, 0x65, 0x71, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x12, 0x09, 0x0a, 0x05, 0x45, 0x4d, 0x50, 0x54, 0x59, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, + 0x55, 0x4d, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x53, 0x54, 0x4f, 0x52, 0x45, + 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x10, 0x03, 0x12, 0x0c, 0x0a, + 0x08, 0x50, 0x52, 0x45, 0x5f, 0x44, 0x55, 0x4d, 0x50, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x50, + 0x41, 0x47, 0x45, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, + 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x59, 0x10, 0x06, 0x12, 0x10, 0x0a, 0x0c, 0x43, 0x50, 0x55, 0x49, + 0x4e, 0x46, 0x4f, 0x5f, 0x44, 0x55, 0x4d, 0x50, 0x10, 0x07, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x50, + 0x55, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x10, 0x08, 0x12, 0x11, 0x0a, + 0x0d, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x10, 0x09, + 0x12, 0x0b, 0x0a, 0x07, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x0a, 0x12, 0x0c, 0x0a, + 0x08, 0x57, 0x41, 0x49, 0x54, 0x5f, 0x50, 0x49, 0x44, 0x10, 0x0b, 0x12, 0x14, 0x0a, 0x10, 0x50, + 0x41, 0x47, 0x45, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x43, 0x48, 0x4c, 0x44, 0x10, + 0x0c, } var ( diff --git a/vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.proto b/vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.proto new file mode 100644 index 0000000000000..61e1b24f4a472 --- /dev/null +++ b/vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.proto @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: MIT + +syntax = "proto2"; + +message criu_page_server_info { + optional string address = 1; + optional int32 port = 2; + optional int32 pid = 3; + optional int32 fd = 4; +} + +message criu_veth_pair { + required string if_in = 1; + required string if_out = 2; +}; + +message ext_mount_map { + required string key = 1; + required string val = 2; +}; + +message join_namespace { + required string ns = 1; + required string ns_file = 2; + optional string extra_opt = 3; +} + +message inherit_fd { + required string key = 1; + required int32 fd = 2; +}; + +message cgroup_root { + optional string ctrl = 1; + required string path = 2; +}; + +message unix_sk { + required uint32 inode = 1; +}; + +enum criu_cg_mode { + IGNORE = 0; + CG_NONE = 1; + PROPS = 2; + SOFT = 3; + FULL = 4; + STRICT = 5; + DEFAULT = 6; +}; + +enum criu_pre_dump_mode { + SPLICE = 1; + VM_READ = 2; +}; + +message criu_opts { + required int32 images_dir_fd = 1; + optional int32 pid = 2; /* if not set on dump, will dump requesting process */ + + optional bool leave_running = 3; + optional bool ext_unix_sk = 4; + optional bool tcp_established = 5; + optional bool evasive_devices = 6; + optional bool shell_job = 7; + optional bool file_locks = 8; + optional int32 log_level = 9 [default = 2]; + optional string log_file = 10; /* No subdirs are allowed. Consider using work-dir */ + + optional criu_page_server_info ps = 11; + + optional bool notify_scripts = 12; + + optional string root = 13; + optional string parent_img = 14; + optional bool track_mem = 15; + optional bool auto_dedup = 16; + + optional int32 work_dir_fd = 17; + optional bool link_remap = 18; + repeated criu_veth_pair veths = 19; /* DEPRECATED, use external instead */ + + optional uint32 cpu_cap = 20 [default = 0xffffffff]; + optional bool force_irmap = 21; + repeated string exec_cmd = 22; + + repeated ext_mount_map ext_mnt = 23; /* DEPRECATED, use external instead */ + optional bool manage_cgroups = 24; /* backward compatibility */ + repeated cgroup_root cg_root = 25; + + optional bool rst_sibling = 26; /* swrk only */ + repeated inherit_fd inherit_fd = 27; /* swrk only */ + + optional bool auto_ext_mnt = 28; + optional bool ext_sharing = 29; + optional bool ext_masters = 30; + + repeated string skip_mnt = 31; + repeated string enable_fs = 32; + + repeated unix_sk unix_sk_ino = 33; /* DEPRECATED, use external instead */ + + optional criu_cg_mode manage_cgroups_mode = 34; + optional uint32 ghost_limit = 35 [default = 0x100000]; + repeated string irmap_scan_paths = 36; + repeated string external = 37; + optional uint32 empty_ns = 38; + repeated join_namespace join_ns = 39; + + optional string cgroup_props = 41; + optional string cgroup_props_file = 42; + repeated string cgroup_dump_controller = 43; + + optional string freeze_cgroup = 44; + optional uint32 timeout = 45; + optional bool tcp_skip_in_flight = 46; + optional bool weak_sysctls = 47; + optional bool lazy_pages = 48; + optional int32 status_fd = 49; + optional bool orphan_pts_master = 50; + optional string config_file = 51; + optional bool tcp_close = 52; + optional string lsm_profile = 53; + optional string tls_cacert = 54; + optional string tls_cacrl = 55; + optional string tls_cert = 56; + optional string tls_key = 57; + optional bool tls = 58; + optional bool tls_no_cn_verify = 59; + optional string cgroup_yard = 60; + optional criu_pre_dump_mode pre_dump_mode = 61 [default = SPLICE]; + optional int32 pidfd_store_sk = 62; + optional string lsm_mount_context = 63; +/* optional bool check_mounts = 128; */ +} + +message criu_dump_resp { + optional bool restored = 1; +} + +message criu_restore_resp { + required int32 pid = 1; +} + +message criu_notify { + optional string script = 1; + optional int32 pid = 2; +} + +enum criu_req_type { + EMPTY = 0; + DUMP = 1; + RESTORE = 2; + CHECK = 3; + PRE_DUMP = 4; + PAGE_SERVER = 5; + + NOTIFY = 6; + + CPUINFO_DUMP = 7; + CPUINFO_CHECK = 8; + + FEATURE_CHECK = 9; + + VERSION = 10; + + WAIT_PID = 11; + PAGE_SERVER_CHLD = 12; +} + +/* + * List of features which can queried via + * CRIU_REQ_TYPE__FEATURE_CHECK + */ +message criu_features { + optional bool mem_track = 1; + optional bool lazy_pages = 2; + optional bool pidfd_store = 3; +} + +/* + * Request -- each type corresponds to must-be-there + * request arguments of respective type + */ + +message criu_req { + required criu_req_type type = 1; + + optional criu_opts opts = 2; + optional bool notify_success = 3; + + /* + * When set service won't close the connection but + * will wait for more req-s to appear. Works not + * for all request types. + */ + optional bool keep_open = 4; + /* + * 'features' can be used to query which features + * are supported by the installed criu/kernel + * via RPC. + */ + optional criu_features features = 5; + + /* 'pid' is used for WAIT_PID */ + optional uint32 pid = 6; +} + +/* + * Response -- it states whether the request was served + * and additional request-specific information + */ + +message criu_resp { + required criu_req_type type = 1; + required bool success = 2; + + optional criu_dump_resp dump = 3; + optional criu_restore_resp restore = 4; + optional criu_notify notify = 5; + optional criu_page_server_info ps = 6; + + optional int32 cr_errno = 7; + optional criu_features features = 8; + optional string cr_errmsg = 9; + optional criu_version version = 10; + + optional int32 status = 11; +} + +/* Answer for criu_req_type.VERSION requests */ +message criu_version { + required int32 major_number = 1; + required int32 minor_number = 2; + optional string gitid = 3; + optional int32 sublevel = 4; + optional int32 extra = 5; + optional string name = 6; +} diff --git a/vendor/github.com/cilium/ebpf/.gitignore b/vendor/github.com/cilium/ebpf/.gitignore index 38b15653c0f94..b46162b8ec333 100644 --- a/vendor/github.com/cilium/ebpf/.gitignore +++ b/vendor/github.com/cilium/ebpf/.gitignore @@ -5,6 +5,7 @@ *.so *.dylib *.o +!*_bpf*.o # Test binary, build with `go test -c` *.test diff --git a/vendor/github.com/cilium/ebpf/.golangci.yaml b/vendor/github.com/cilium/ebpf/.golangci.yaml index a88374197ecbc..dc62dd6d0fc72 100644 --- a/vendor/github.com/cilium/ebpf/.golangci.yaml +++ b/vendor/github.com/cilium/ebpf/.golangci.yaml @@ -24,6 +24,5 @@ linters: # Could be enabled later: # - gocyclo - # - prealloc # - maligned # - gosec diff --git a/vendor/github.com/cilium/ebpf/ARCHITECTURE.md b/vendor/github.com/cilium/ebpf/ARCHITECTURE.md index aee9c0a0d4d51..6cbb31b6481ed 100644 --- a/vendor/github.com/cilium/ebpf/ARCHITECTURE.md +++ b/vendor/github.com/cilium/ebpf/ARCHITECTURE.md @@ -57,7 +57,7 @@ Objects loading a spec will fail because the kernel is too old, or a feature is not enabled. There are multiple ways the library deals with that: -* Fallback: older kernels don't allowing naming programs and maps. The library +* Fallback: older kernels don't allow naming programs and maps. The library automatically detects support for names, and omits them during load if necessary. This works since name is primarily a debug aid. @@ -68,7 +68,7 @@ enabled. There are multiple ways the library deals with that: Once program and map objects are loaded they expose the kernel's low-level API, e.g. `NextKey`. Often this API is awkward to use in Go, so there are safer wrappers on top of the low-level API, like `MapIterator`. The low-level API is -useful as an out when our higher-level API doesn't support a particular use case. +useful when our higher-level API doesn't support a particular use case. Links --- diff --git a/vendor/github.com/cilium/ebpf/CONTRIBUTING.md b/vendor/github.com/cilium/ebpf/CONTRIBUTING.md index 72ceb43782972..0d29eae81e3ed 100644 --- a/vendor/github.com/cilium/ebpf/CONTRIBUTING.md +++ b/vendor/github.com/cilium/ebpf/CONTRIBUTING.md @@ -6,8 +6,8 @@ are welcome. Please take a look at [the architecture](ARCHITECTURE.md) to get a better understanding for the high-level goals. New features must be accompanied by tests. Before starting work on any large -feature, please [join](https://cilium.herokuapp.com/) the -[#libbpf-go](https://cilium.slack.com/messages/libbpf-go) channel on Slack to +feature, please [join](https://ebpf.io/slack) the +[#ebpf-go](https://cilium.slack.com/messages/ebpf-go) channel on Slack to discuss the design first. When submitting pull requests, consider writing details about what problem you diff --git a/vendor/github.com/cilium/ebpf/Makefile b/vendor/github.com/cilium/ebpf/Makefile index 5dd342c5b287a..0bc15c0810cbf 100644 --- a/vendor/github.com/cilium/ebpf/Makefile +++ b/vendor/github.com/cilium/ebpf/Makefile @@ -18,11 +18,14 @@ TARGETS := \ testdata/loader-clang-7 \ testdata/loader-clang-9 \ testdata/loader-$(CLANG) \ + testdata/btf_map_init \ testdata/invalid_map \ testdata/raw_tracepoint \ testdata/invalid_map_static \ - testdata/initialized_btf_map \ + testdata/invalid_btf_map_init \ testdata/strings \ + testdata/freplace \ + testdata/iproute2_map_compat \ internal/btf/testdata/relocs .PHONY: all clean docker-all docker-shell diff --git a/vendor/github.com/cilium/ebpf/README.md b/vendor/github.com/cilium/ebpf/README.md index 76c3c303bb1be..01e2fff92bbc8 100644 --- a/vendor/github.com/cilium/ebpf/README.md +++ b/vendor/github.com/cilium/ebpf/README.md @@ -2,28 +2,16 @@ [![PkgGoDev](https://pkg.go.dev/badge/github.com/cilium/ebpf)](https://pkg.go.dev/github.com/cilium/ebpf) +![HoneyGopher](.github/images/cilium-ebpf.png) + eBPF is a pure Go library that provides utilities for loading, compiling, and debugging eBPF programs. It has minimal external dependencies and is intended to be used in long running processes. -* [asm](https://pkg.go.dev/github.com/cilium/ebpf/asm) contains a basic - assembler -* [link](https://pkg.go.dev/github.com/cilium/ebpf/link) allows attaching eBPF - to various hooks -* [perf](https://pkg.go.dev/github.com/cilium/ebpf/perf) allows reading from a - `PERF_EVENT_ARRAY` -* [cmd/bpf2go](https://pkg.go.dev/github.com/cilium/ebpf/cmd/bpf2go) allows - compiling and embedding eBPF programs in Go code - The library is maintained by [Cloudflare](https://www.cloudflare.com) and -[Cilium](https://www.cilium.io). Feel free to -[join](https://cilium.herokuapp.com/) the -[#libbpf-go](https://cilium.slack.com/messages/libbpf-go) channel on Slack. - -## Current status +[Cilium](https://www.cilium.io). -The package is production ready, but **the API is explicitly unstable right -now**. Expect to update your code if you want to follow along. +See [ebpf.io](https://ebpf.io) for other projects from the eBPF ecosystem. ## Getting Started @@ -33,21 +21,37 @@ your own tools can be found under [examples/](examples/). Contributions are highly encouraged, as they highlight certain use cases of eBPF and the library, and help shape the future of the project. +## Getting Help + +Please +[join](https://ebpf.io/slack) the +[#ebpf-go](https://cilium.slack.com/messages/ebpf-go) channel on Slack if you +have questions regarding the library. + +## Packages + +This library includes the following packages: + +* [asm](https://pkg.go.dev/github.com/cilium/ebpf/asm) contains a basic + assembler, allowing you to write eBPF assembly instructions directly + within your Go code. (You don't need to use this if you prefer to write your eBPF program in C.) +* [cmd/bpf2go](https://pkg.go.dev/github.com/cilium/ebpf/cmd/bpf2go) allows + compiling and embedding eBPF programs written in C within Go code. As well as + compiling the C code, it auto-generates Go code for loading and manipulating + the eBPF program and map objects. +* [link](https://pkg.go.dev/github.com/cilium/ebpf/link) allows attaching eBPF + to various hooks +* [perf](https://pkg.go.dev/github.com/cilium/ebpf/perf) allows reading from a + `PERF_EVENT_ARRAY` +* [ringbuf](https://pkg.go.dev/github.com/cilium/ebpf/ringbuf) allows reading from a + `BPF_MAP_TYPE_RINGBUF` map + + ## Requirements * A version of Go that is [supported by upstream](https://golang.org/doc/devel/release.html#policy) -* Linux 4.9, 4.19 or 5.4 (versions in-between should work, but are not tested) - -## Useful resources - -* [eBPF.io](https://ebpf.io) (recommended) -* [Cilium eBPF documentation](https://docs.cilium.io/en/latest/bpf/#bpf-guide) - (recommended) -* [Linux documentation on - BPF](https://www.kernel.org/doc/html/latest/networking/filter.html) -* [eBPF features by Linux - version](https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md) +* Linux >= 4.9. CI is run against LTS releases. ## Regenerating Testdata @@ -60,3 +64,7 @@ The toolchain image build files are kept in [testdata/docker/](testdata/docker/) ## License MIT + +### eBPF Gopher + +The eBPF honeygopher is based on the Go gopher designed by Renee French. diff --git a/vendor/github.com/cilium/ebpf/asm/func.go b/vendor/github.com/cilium/ebpf/asm/func.go index aee2c7ac81062..bfa5d59c976ea 100644 --- a/vendor/github.com/cilium/ebpf/asm/func.go +++ b/vendor/github.com/cilium/ebpf/asm/func.go @@ -184,6 +184,12 @@ const ( FnKtimeGetCoarseNs FnImaInodeHash FnSockFromFile + FnCheckMtu + FnForEachMapElem + FnSnprintf + FnSysBpf + FnBtfFindByNameKind + FnSysClose ) // Call emits a function call. diff --git a/vendor/github.com/cilium/ebpf/asm/func_string.go b/vendor/github.com/cilium/ebpf/asm/func_string.go index a712c5da8af99..5a0e333639a36 100644 --- a/vendor/github.com/cilium/ebpf/asm/func_string.go +++ b/vendor/github.com/cilium/ebpf/asm/func_string.go @@ -171,11 +171,17 @@ func _() { _ = x[FnKtimeGetCoarseNs-160] _ = x[FnImaInodeHash-161] _ = x[FnSockFromFile-162] + _ = x[FnCheckMtu-163] + _ = x[FnForEachMapElem-164] + _ = x[FnSnprintf-165] + _ = x[FnSysBpf-166] + _ = x[FnBtfFindByNameKind-167] + _ = x[FnSysClose-168] } -const _BuiltinFunc_name = "FnUnspecFnMapLookupElemFnMapUpdateElemFnMapDeleteElemFnProbeReadFnKtimeGetNsFnTracePrintkFnGetPrandomU32FnGetSmpProcessorIdFnSkbStoreBytesFnL3CsumReplaceFnL4CsumReplaceFnTailCallFnCloneRedirectFnGetCurrentPidTgidFnGetCurrentUidGidFnGetCurrentCommFnGetCgroupClassidFnSkbVlanPushFnSkbVlanPopFnSkbGetTunnelKeyFnSkbSetTunnelKeyFnPerfEventReadFnRedirectFnGetRouteRealmFnPerfEventOutputFnSkbLoadBytesFnGetStackidFnCsumDiffFnSkbGetTunnelOptFnSkbSetTunnelOptFnSkbChangeProtoFnSkbChangeTypeFnSkbUnderCgroupFnGetHashRecalcFnGetCurrentTaskFnProbeWriteUserFnCurrentTaskUnderCgroupFnSkbChangeTailFnSkbPullDataFnCsumUpdateFnSetHashInvalidFnGetNumaNodeIdFnSkbChangeHeadFnXdpAdjustHeadFnProbeReadStrFnGetSocketCookieFnGetSocketUidFnSetHashFnSetsockoptFnSkbAdjustRoomFnRedirectMapFnSkRedirectMapFnSockMapUpdateFnXdpAdjustMetaFnPerfEventReadValueFnPerfProgReadValueFnGetsockoptFnOverrideReturnFnSockOpsCbFlagsSetFnMsgRedirectMapFnMsgApplyBytesFnMsgCorkBytesFnMsgPullDataFnBindFnXdpAdjustTailFnSkbGetXfrmStateFnGetStackFnSkbLoadBytesRelativeFnFibLookupFnSockHashUpdateFnMsgRedirectHashFnSkRedirectHashFnLwtPushEncapFnLwtSeg6StoreBytesFnLwtSeg6AdjustSrhFnLwtSeg6ActionFnRcRepeatFnRcKeydownFnSkbCgroupIdFnGetCurrentCgroupIdFnGetLocalStorageFnSkSelectReuseportFnSkbAncestorCgroupIdFnSkLookupTcpFnSkLookupUdpFnSkReleaseFnMapPushElemFnMapPopElemFnMapPeekElemFnMsgPushDataFnMsgPopDataFnRcPointerRelFnSpinLockFnSpinUnlockFnSkFullsockFnTcpSockFnSkbEcnSetCeFnGetListenerSockFnSkcLookupTcpFnTcpCheckSyncookieFnSysctlGetNameFnSysctlGetCurrentValueFnSysctlGetNewValueFnSysctlSetNewValueFnStrtolFnStrtoulFnSkStorageGetFnSkStorageDeleteFnSendSignalFnTcpGenSyncookieFnSkbOutputFnProbeReadUserFnProbeReadKernelFnProbeReadUserStrFnProbeReadKernelStrFnTcpSendAckFnSendSignalThreadFnJiffies64FnReadBranchRecordsFnGetNsCurrentPidTgidFnXdpOutputFnGetNetnsCookieFnGetCurrentAncestorCgroupIdFnSkAssignFnKtimeGetBootNsFnSeqPrintfFnSeqWriteFnSkCgroupIdFnSkAncestorCgroupIdFnRingbufOutputFnRingbufReserveFnRingbufSubmitFnRingbufDiscardFnRingbufQueryFnCsumLevelFnSkcToTcp6SockFnSkcToTcpSockFnSkcToTcpTimewaitSockFnSkcToTcpRequestSockFnSkcToUdp6SockFnGetTaskStackFnLoadHdrOptFnStoreHdrOptFnReserveHdrOptFnInodeStorageGetFnInodeStorageDeleteFnDPathFnCopyFromUserFnSnprintfBtfFnSeqPrintfBtfFnSkbCgroupClassidFnRedirectNeighFnPerCpuPtrFnThisCpuPtrFnRedirectPeerFnTaskStorageGetFnTaskStorageDeleteFnGetCurrentTaskBtfFnBprmOptsSetFnKtimeGetCoarseNsFnImaInodeHashFnSockFromFile" +const _BuiltinFunc_name = "FnUnspecFnMapLookupElemFnMapUpdateElemFnMapDeleteElemFnProbeReadFnKtimeGetNsFnTracePrintkFnGetPrandomU32FnGetSmpProcessorIdFnSkbStoreBytesFnL3CsumReplaceFnL4CsumReplaceFnTailCallFnCloneRedirectFnGetCurrentPidTgidFnGetCurrentUidGidFnGetCurrentCommFnGetCgroupClassidFnSkbVlanPushFnSkbVlanPopFnSkbGetTunnelKeyFnSkbSetTunnelKeyFnPerfEventReadFnRedirectFnGetRouteRealmFnPerfEventOutputFnSkbLoadBytesFnGetStackidFnCsumDiffFnSkbGetTunnelOptFnSkbSetTunnelOptFnSkbChangeProtoFnSkbChangeTypeFnSkbUnderCgroupFnGetHashRecalcFnGetCurrentTaskFnProbeWriteUserFnCurrentTaskUnderCgroupFnSkbChangeTailFnSkbPullDataFnCsumUpdateFnSetHashInvalidFnGetNumaNodeIdFnSkbChangeHeadFnXdpAdjustHeadFnProbeReadStrFnGetSocketCookieFnGetSocketUidFnSetHashFnSetsockoptFnSkbAdjustRoomFnRedirectMapFnSkRedirectMapFnSockMapUpdateFnXdpAdjustMetaFnPerfEventReadValueFnPerfProgReadValueFnGetsockoptFnOverrideReturnFnSockOpsCbFlagsSetFnMsgRedirectMapFnMsgApplyBytesFnMsgCorkBytesFnMsgPullDataFnBindFnXdpAdjustTailFnSkbGetXfrmStateFnGetStackFnSkbLoadBytesRelativeFnFibLookupFnSockHashUpdateFnMsgRedirectHashFnSkRedirectHashFnLwtPushEncapFnLwtSeg6StoreBytesFnLwtSeg6AdjustSrhFnLwtSeg6ActionFnRcRepeatFnRcKeydownFnSkbCgroupIdFnGetCurrentCgroupIdFnGetLocalStorageFnSkSelectReuseportFnSkbAncestorCgroupIdFnSkLookupTcpFnSkLookupUdpFnSkReleaseFnMapPushElemFnMapPopElemFnMapPeekElemFnMsgPushDataFnMsgPopDataFnRcPointerRelFnSpinLockFnSpinUnlockFnSkFullsockFnTcpSockFnSkbEcnSetCeFnGetListenerSockFnSkcLookupTcpFnTcpCheckSyncookieFnSysctlGetNameFnSysctlGetCurrentValueFnSysctlGetNewValueFnSysctlSetNewValueFnStrtolFnStrtoulFnSkStorageGetFnSkStorageDeleteFnSendSignalFnTcpGenSyncookieFnSkbOutputFnProbeReadUserFnProbeReadKernelFnProbeReadUserStrFnProbeReadKernelStrFnTcpSendAckFnSendSignalThreadFnJiffies64FnReadBranchRecordsFnGetNsCurrentPidTgidFnXdpOutputFnGetNetnsCookieFnGetCurrentAncestorCgroupIdFnSkAssignFnKtimeGetBootNsFnSeqPrintfFnSeqWriteFnSkCgroupIdFnSkAncestorCgroupIdFnRingbufOutputFnRingbufReserveFnRingbufSubmitFnRingbufDiscardFnRingbufQueryFnCsumLevelFnSkcToTcp6SockFnSkcToTcpSockFnSkcToTcpTimewaitSockFnSkcToTcpRequestSockFnSkcToUdp6SockFnGetTaskStackFnLoadHdrOptFnStoreHdrOptFnReserveHdrOptFnInodeStorageGetFnInodeStorageDeleteFnDPathFnCopyFromUserFnSnprintfBtfFnSeqPrintfBtfFnSkbCgroupClassidFnRedirectNeighFnPerCpuPtrFnThisCpuPtrFnRedirectPeerFnTaskStorageGetFnTaskStorageDeleteFnGetCurrentTaskBtfFnBprmOptsSetFnKtimeGetCoarseNsFnImaInodeHashFnSockFromFileFnCheckMtuFnForEachMapElemFnSnprintfFnSysBpfFnBtfFindByNameKindFnSysClose" -var _BuiltinFunc_index = [...]uint16{0, 8, 23, 38, 53, 64, 76, 89, 104, 123, 138, 153, 168, 178, 193, 212, 230, 246, 264, 277, 289, 306, 323, 338, 348, 363, 380, 394, 406, 416, 433, 450, 466, 481, 497, 512, 528, 544, 568, 583, 596, 608, 624, 639, 654, 669, 683, 700, 714, 723, 735, 750, 763, 778, 793, 808, 828, 847, 859, 875, 894, 910, 925, 939, 952, 958, 973, 990, 1000, 1022, 1033, 1049, 1066, 1082, 1096, 1115, 1133, 1148, 1158, 1169, 1182, 1202, 1219, 1238, 1259, 1272, 1285, 1296, 1309, 1321, 1334, 1347, 1359, 1373, 1383, 1395, 1407, 1416, 1429, 1446, 1460, 1479, 1494, 1517, 1536, 1555, 1563, 1572, 1586, 1603, 1615, 1632, 1643, 1658, 1675, 1693, 1713, 1725, 1743, 1754, 1773, 1794, 1805, 1821, 1849, 1859, 1875, 1886, 1896, 1908, 1928, 1943, 1959, 1974, 1990, 2004, 2015, 2030, 2044, 2066, 2087, 2102, 2116, 2128, 2141, 2156, 2173, 2193, 2200, 2214, 2227, 2241, 2259, 2274, 2285, 2297, 2311, 2327, 2346, 2365, 2378, 2396, 2410, 2424} +var _BuiltinFunc_index = [...]uint16{0, 8, 23, 38, 53, 64, 76, 89, 104, 123, 138, 153, 168, 178, 193, 212, 230, 246, 264, 277, 289, 306, 323, 338, 348, 363, 380, 394, 406, 416, 433, 450, 466, 481, 497, 512, 528, 544, 568, 583, 596, 608, 624, 639, 654, 669, 683, 700, 714, 723, 735, 750, 763, 778, 793, 808, 828, 847, 859, 875, 894, 910, 925, 939, 952, 958, 973, 990, 1000, 1022, 1033, 1049, 1066, 1082, 1096, 1115, 1133, 1148, 1158, 1169, 1182, 1202, 1219, 1238, 1259, 1272, 1285, 1296, 1309, 1321, 1334, 1347, 1359, 1373, 1383, 1395, 1407, 1416, 1429, 1446, 1460, 1479, 1494, 1517, 1536, 1555, 1563, 1572, 1586, 1603, 1615, 1632, 1643, 1658, 1675, 1693, 1713, 1725, 1743, 1754, 1773, 1794, 1805, 1821, 1849, 1859, 1875, 1886, 1896, 1908, 1928, 1943, 1959, 1974, 1990, 2004, 2015, 2030, 2044, 2066, 2087, 2102, 2116, 2128, 2141, 2156, 2173, 2193, 2200, 2214, 2227, 2241, 2259, 2274, 2285, 2297, 2311, 2327, 2346, 2365, 2378, 2396, 2410, 2424, 2434, 2450, 2460, 2468, 2487, 2497} func (i BuiltinFunc) String() string { if i < 0 || i >= BuiltinFunc(len(_BuiltinFunc_index)-1) { diff --git a/vendor/github.com/cilium/ebpf/asm/instruction.go b/vendor/github.com/cilium/ebpf/asm/instruction.go index e7ac0109e2dcc..64d717d156d5a 100644 --- a/vendor/github.com/cilium/ebpf/asm/instruction.go +++ b/vendor/github.com/cilium/ebpf/asm/instruction.go @@ -181,6 +181,11 @@ func (ins *Instruction) IsFunctionCall() bool { return ins.OpCode.JumpOp() == Call && ins.Src == PseudoCall } +// IsBuiltinCall returns true if the instruction is a built-in call, i.e. BPF helper call. +func (ins *Instruction) IsBuiltinCall() bool { + return ins.OpCode.JumpOp() == Call && ins.Src == R0 && ins.Dst == R0 +} + // IsConstantLoad returns true if the instruction loads a constant of the // given size. func (ins *Instruction) IsConstantLoad(size Size) bool { diff --git a/vendor/github.com/cilium/ebpf/attachtype_string.go b/vendor/github.com/cilium/ebpf/attachtype_string.go new file mode 100644 index 0000000000000..de355ed909227 --- /dev/null +++ b/vendor/github.com/cilium/ebpf/attachtype_string.go @@ -0,0 +1,65 @@ +// Code generated by "stringer -type AttachType -trimprefix Attach"; DO NOT EDIT. + +package ebpf + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[AttachNone-0] + _ = x[AttachCGroupInetIngress-0] + _ = x[AttachCGroupInetEgress-1] + _ = x[AttachCGroupInetSockCreate-2] + _ = x[AttachCGroupSockOps-3] + _ = x[AttachSkSKBStreamParser-4] + _ = x[AttachSkSKBStreamVerdict-5] + _ = x[AttachCGroupDevice-6] + _ = x[AttachSkMsgVerdict-7] + _ = x[AttachCGroupInet4Bind-8] + _ = x[AttachCGroupInet6Bind-9] + _ = x[AttachCGroupInet4Connect-10] + _ = x[AttachCGroupInet6Connect-11] + _ = x[AttachCGroupInet4PostBind-12] + _ = x[AttachCGroupInet6PostBind-13] + _ = x[AttachCGroupUDP4Sendmsg-14] + _ = x[AttachCGroupUDP6Sendmsg-15] + _ = x[AttachLircMode2-16] + _ = x[AttachFlowDissector-17] + _ = x[AttachCGroupSysctl-18] + _ = x[AttachCGroupUDP4Recvmsg-19] + _ = x[AttachCGroupUDP6Recvmsg-20] + _ = x[AttachCGroupGetsockopt-21] + _ = x[AttachCGroupSetsockopt-22] + _ = x[AttachTraceRawTp-23] + _ = x[AttachTraceFEntry-24] + _ = x[AttachTraceFExit-25] + _ = x[AttachModifyReturn-26] + _ = x[AttachLSMMac-27] + _ = x[AttachTraceIter-28] + _ = x[AttachCgroupInet4GetPeername-29] + _ = x[AttachCgroupInet6GetPeername-30] + _ = x[AttachCgroupInet4GetSockname-31] + _ = x[AttachCgroupInet6GetSockname-32] + _ = x[AttachXDPDevMap-33] + _ = x[AttachCgroupInetSockRelease-34] + _ = x[AttachXDPCPUMap-35] + _ = x[AttachSkLookup-36] + _ = x[AttachXDP-37] + _ = x[AttachSkSKBVerdict-38] + _ = x[AttachSkReuseportSelect-39] + _ = x[AttachSkReuseportSelectOrMigrate-40] + _ = x[AttachPerfEvent-41] +} + +const _AttachType_name = "NoneCGroupInetEgressCGroupInetSockCreateCGroupSockOpsSkSKBStreamParserSkSKBStreamVerdictCGroupDeviceSkMsgVerdictCGroupInet4BindCGroupInet6BindCGroupInet4ConnectCGroupInet6ConnectCGroupInet4PostBindCGroupInet6PostBindCGroupUDP4SendmsgCGroupUDP6SendmsgLircMode2FlowDissectorCGroupSysctlCGroupUDP4RecvmsgCGroupUDP6RecvmsgCGroupGetsockoptCGroupSetsockoptTraceRawTpTraceFEntryTraceFExitModifyReturnLSMMacTraceIterCgroupInet4GetPeernameCgroupInet6GetPeernameCgroupInet4GetSocknameCgroupInet6GetSocknameXDPDevMapCgroupInetSockReleaseXDPCPUMapSkLookupXDPSkSKBVerdictSkReuseportSelectSkReuseportSelectOrMigratePerfEvent" + +var _AttachType_index = [...]uint16{0, 4, 20, 40, 53, 70, 88, 100, 112, 127, 142, 160, 178, 197, 216, 233, 250, 259, 272, 284, 301, 318, 334, 350, 360, 371, 381, 393, 399, 408, 430, 452, 474, 496, 505, 526, 535, 543, 546, 558, 575, 601, 610} + +func (i AttachType) String() string { + if i >= AttachType(len(_AttachType_index)-1) { + return "AttachType(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _AttachType_name[_AttachType_index[i]:_AttachType_index[i+1]] +} diff --git a/vendor/github.com/cilium/ebpf/collection.go b/vendor/github.com/cilium/ebpf/collection.go index 17cc69492ea95..2ededc87a05c2 100644 --- a/vendor/github.com/cilium/ebpf/collection.go +++ b/vendor/github.com/cilium/ebpf/collection.go @@ -1,6 +1,7 @@ package ebpf import ( + "encoding/binary" "errors" "fmt" "io" @@ -25,6 +26,10 @@ type CollectionOptions struct { type CollectionSpec struct { Maps map[string]*MapSpec Programs map[string]*ProgramSpec + + // ByteOrder specifies whether the ELF was compiled for + // big-endian or little-endian architectures. + ByteOrder binary.ByteOrder } // Copy returns a recursive copy of the spec. @@ -34,8 +39,9 @@ func (cs *CollectionSpec) Copy() *CollectionSpec { } cpy := CollectionSpec{ - Maps: make(map[string]*MapSpec, len(cs.Maps)), - Programs: make(map[string]*ProgramSpec, len(cs.Programs)), + Maps: make(map[string]*MapSpec, len(cs.Maps)), + Programs: make(map[string]*ProgramSpec, len(cs.Programs)), + ByteOrder: cs.ByteOrder, } for name, spec := range cs.Maps { @@ -123,7 +129,7 @@ func (cs *CollectionSpec) RewriteConstants(consts map[string]interface{}) error buf := make([]byte, len(value)) copy(buf, value) - err := patchValue(buf, btf.MapValue(rodata.BTF), consts) + err := patchValue(buf, rodata.BTF.Value, consts) if err != nil { return err } @@ -134,15 +140,15 @@ func (cs *CollectionSpec) RewriteConstants(consts map[string]interface{}) error // Assign the contents of a CollectionSpec to a struct. // -// This function is a short-cut to manually checking the presence -// of maps and programs in a collection spec. Consider using bpf2go if this -// sounds useful. +// This function is a shortcut to manually checking the presence +// of maps and programs in a CollectionSpec. Consider using bpf2go +// if this sounds useful. // -// The argument to must be a pointer to a struct. A field of the +// 'to' must be a pointer to a struct. A field of the // struct is updated with values from Programs or Maps if it // has an `ebpf` tag and its type is *ProgramSpec or *MapSpec. -// The tag gives the name of the program or map as found in -// the CollectionSpec. +// The tag's value specifies the name of the program or map as +// found in the CollectionSpec. // // struct { // Foo *ebpf.ProgramSpec `ebpf:"xdp_foo"` @@ -150,42 +156,47 @@ func (cs *CollectionSpec) RewriteConstants(consts map[string]interface{}) error // Ignored int // } // -// Returns an error if any of the fields can't be found, or -// if the same map or program is assigned multiple times. +// Returns an error if any of the eBPF objects can't be found, or +// if the same MapSpec or ProgramSpec is assigned multiple times. func (cs *CollectionSpec) Assign(to interface{}) error { - valueOf := func(typ reflect.Type, name string) (reflect.Value, error) { + // Assign() only supports assigning ProgramSpecs and MapSpecs, + // so doesn't load any resources into the kernel. + getValue := func(typ reflect.Type, name string) (interface{}, error) { switch typ { + case reflect.TypeOf((*ProgramSpec)(nil)): - p := cs.Programs[name] - if p == nil { - return reflect.Value{}, fmt.Errorf("missing program %q", name) + if p := cs.Programs[name]; p != nil { + return p, nil } - return reflect.ValueOf(p), nil + return nil, fmt.Errorf("missing program %q", name) + case reflect.TypeOf((*MapSpec)(nil)): - m := cs.Maps[name] - if m == nil { - return reflect.Value{}, fmt.Errorf("missing map %q", name) + if m := cs.Maps[name]; m != nil { + return m, nil } - return reflect.ValueOf(m), nil + return nil, fmt.Errorf("missing map %q", name) + default: - return reflect.Value{}, fmt.Errorf("unsupported type %s", typ) + return nil, fmt.Errorf("unsupported type %s", typ) } } - return assignValues(to, valueOf) + return assignValues(to, getValue) } -// LoadAndAssign maps and programs into the kernel and assign them to a struct. +// LoadAndAssign loads Maps and Programs into the kernel and assigns them +// to a struct. // -// This function is a short-cut to manually checking the presence -// of maps and programs in a collection spec. Consider using bpf2go if this -// sounds useful. +// This function is a shortcut to manually checking the presence +// of maps and programs in a CollectionSpec. Consider using bpf2go +// if this sounds useful. // -// The argument to must be a pointer to a struct. A field of the -// struct is updated with values from Programs or Maps if it -// has an `ebpf` tag and its type is *Program or *Map. -// The tag gives the name of the program or map as found in -// the CollectionSpec. +// 'to' must be a pointer to a struct. A field of the struct is updated with +// a Program or Map if it has an `ebpf` tag and its type is *Program or *Map. +// The tag's value specifies the name of the program or map as found in the +// CollectionSpec. Before updating the struct, the requested objects and their +// dependent resources are loaded into the kernel and populated with values if +// specified. // // struct { // Foo *ebpf.Program `ebpf:"xdp_foo"` @@ -196,39 +207,53 @@ func (cs *CollectionSpec) Assign(to interface{}) error { // opts may be nil. // // Returns an error if any of the fields can't be found, or -// if the same map or program is assigned multiple times. +// if the same Map or Program is assigned multiple times. func (cs *CollectionSpec) LoadAndAssign(to interface{}, opts *CollectionOptions) error { - if opts == nil { - opts = &CollectionOptions{} - } - - loadMap, loadProgram, done, cleanup := lazyLoadCollection(cs, opts) - defer cleanup() + loader := newCollectionLoader(cs, opts) + defer loader.cleanup() - valueOf := func(typ reflect.Type, name string) (reflect.Value, error) { + // Support assigning Programs and Maps, lazy-loading the required objects. + assignedMaps := make(map[string]bool) + getValue := func(typ reflect.Type, name string) (interface{}, error) { switch typ { + case reflect.TypeOf((*Program)(nil)): - p, err := loadProgram(name) - if err != nil { - return reflect.Value{}, err - } - return reflect.ValueOf(p), nil + return loader.loadProgram(name) + case reflect.TypeOf((*Map)(nil)): - m, err := loadMap(name) - if err != nil { - return reflect.Value{}, err - } - return reflect.ValueOf(m), nil + assignedMaps[name] = true + return loader.loadMap(name) + default: - return reflect.Value{}, fmt.Errorf("unsupported type %s", typ) + return nil, fmt.Errorf("unsupported type %s", typ) } } - if err := assignValues(to, valueOf); err != nil { + // Load the Maps and Programs requested by the annotated struct. + if err := assignValues(to, getValue); err != nil { return err } - done() + // Populate the requested maps. Has a chance of lazy-loading other dependent maps. + if err := loader.populateMaps(); err != nil { + return err + } + + // Evaluate the loader's objects after all (lazy)loading has taken place. + for n, m := range loader.maps { + switch m.typ { + case ProgramArray: + // Require all lazy-loaded ProgramArrays to be assigned to the given object. + // Without any references, they will be closed on the first GC and all tail + // calls into them will miss. + if !assignedMaps[n] { + return fmt.Errorf("ProgramArray %s must be assigned to prevent missed tail calls", n) + } + } + } + + loader.finalize() + return nil } @@ -246,24 +271,32 @@ func NewCollection(spec *CollectionSpec) (*Collection, error) { // NewCollectionWithOptions creates a Collection from a specification. func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (*Collection, error) { - loadMap, loadProgram, done, cleanup := lazyLoadCollection(spec, &opts) - defer cleanup() + loader := newCollectionLoader(spec, &opts) + defer loader.cleanup() + // Create maps first, as their fds need to be linked into programs. for mapName := range spec.Maps { - _, err := loadMap(mapName) - if err != nil { + if _, err := loader.loadMap(mapName); err != nil { return nil, err } } for progName := range spec.Programs { - _, err := loadProgram(progName) - if err != nil { + if _, err := loader.loadProgram(progName); err != nil { return nil, err } } - maps, progs := done() + // Maps can contain Program and Map stubs, so populate them after + // all Maps and Programs have been successfully loaded. + if err := loader.populateMaps(); err != nil { + return nil, err + } + + maps, progs := loader.maps, loader.programs + + loader.finalize() + return &Collection{ progs, maps, @@ -314,113 +347,154 @@ func (hc handleCache) close() { for _, handle := range hc.btfHandles { handle.Close() } - hc.btfHandles = nil - hc.btfSpecs = nil } -func lazyLoadCollection(coll *CollectionSpec, opts *CollectionOptions) ( - loadMap func(string) (*Map, error), - loadProgram func(string) (*Program, error), - done func() (map[string]*Map, map[string]*Program), - cleanup func(), -) { - var ( - maps = make(map[string]*Map) - progs = make(map[string]*Program) - handles = newHandleCache() - skipMapsAndProgs = false - ) - - cleanup = func() { - handles.close() - - if skipMapsAndProgs { - return - } +type collectionLoader struct { + coll *CollectionSpec + opts *CollectionOptions + maps map[string]*Map + programs map[string]*Program + handles *handleCache +} - for _, m := range maps { - m.Close() - } +func newCollectionLoader(coll *CollectionSpec, opts *CollectionOptions) *collectionLoader { + if opts == nil { + opts = &CollectionOptions{} + } - for _, p := range progs { - p.Close() - } + return &collectionLoader{ + coll, + opts, + make(map[string]*Map), + make(map[string]*Program), + newHandleCache(), + } +} + +// finalize should be called when all the collectionLoader's resources +// have been successfully loaded into the kernel and populated with values. +func (cl *collectionLoader) finalize() { + cl.maps, cl.programs = nil, nil +} + +// cleanup cleans up all resources left over in the collectionLoader. +// Call finalize() when Map and Program creation/population is successful +// to prevent them from getting closed. +func (cl *collectionLoader) cleanup() { + cl.handles.close() + for _, m := range cl.maps { + m.Close() + } + for _, p := range cl.programs { + p.Close() + } +} + +func (cl *collectionLoader) loadMap(mapName string) (*Map, error) { + if m := cl.maps[mapName]; m != nil { + return m, nil + } + + mapSpec := cl.coll.Maps[mapName] + if mapSpec == nil { + return nil, fmt.Errorf("missing map %s", mapName) } - done = func() (map[string]*Map, map[string]*Program) { - skipMapsAndProgs = true - return maps, progs + m, err := newMapWithOptions(mapSpec, cl.opts.Maps, cl.handles) + if err != nil { + return nil, fmt.Errorf("map %s: %w", mapName, err) } - loadMap = func(mapName string) (*Map, error) { - if m := maps[mapName]; m != nil { - return m, nil + cl.maps[mapName] = m + return m, nil +} + +func (cl *collectionLoader) loadProgram(progName string) (*Program, error) { + if prog := cl.programs[progName]; prog != nil { + return prog, nil + } + + progSpec := cl.coll.Programs[progName] + if progSpec == nil { + return nil, fmt.Errorf("unknown program %s", progName) + } + + progSpec = progSpec.Copy() + + // Rewrite any reference to a valid map. + for i := range progSpec.Instructions { + ins := &progSpec.Instructions[i] + + if !ins.IsLoadFromMap() || ins.Reference == "" { + continue } - mapSpec := coll.Maps[mapName] - if mapSpec == nil { - return nil, fmt.Errorf("missing map %s", mapName) + if uint32(ins.Constant) != math.MaxUint32 { + // Don't overwrite maps already rewritten, users can + // rewrite programs in the spec themselves + continue } - m, err := newMapWithOptions(mapSpec, opts.Maps, handles) + m, err := cl.loadMap(ins.Reference) if err != nil { - return nil, fmt.Errorf("map %s: %w", mapName, err) + return nil, fmt.Errorf("program %s: %w", progName, err) } - maps[mapName] = m - return m, nil - } - - loadProgram = func(progName string) (*Program, error) { - if prog := progs[progName]; prog != nil { - return prog, nil + fd := m.FD() + if fd < 0 { + return nil, fmt.Errorf("map %s: %w", ins.Reference, internal.ErrClosedFd) } - - progSpec := coll.Programs[progName] - if progSpec == nil { - return nil, fmt.Errorf("unknown program %s", progName) + if err := ins.RewriteMapPtr(m.FD()); err != nil { + return nil, fmt.Errorf("program %s: map %s: %w", progName, ins.Reference, err) } + } - progSpec = progSpec.Copy() + prog, err := newProgramWithOptions(progSpec, cl.opts.Programs, cl.handles) + if err != nil { + return nil, fmt.Errorf("program %s: %w", progName, err) + } - // Rewrite any reference to a valid map. - for i := range progSpec.Instructions { - ins := &progSpec.Instructions[i] + cl.programs[progName] = prog + return prog, nil +} - if !ins.IsLoadFromMap() || ins.Reference == "" { - continue - } +func (cl *collectionLoader) populateMaps() error { + for mapName, m := range cl.maps { + mapSpec, ok := cl.coll.Maps[mapName] + if !ok { + return fmt.Errorf("missing map spec %s", mapName) + } - if uint32(ins.Constant) != math.MaxUint32 { - // Don't overwrite maps already rewritten, users can - // rewrite programs in the spec themselves - continue - } + mapSpec = mapSpec.Copy() - m, err := loadMap(ins.Reference) - if err != nil { - return nil, fmt.Errorf("program %s: %w", progName, err) - } + // Replace any object stubs with loaded objects. + for i, kv := range mapSpec.Contents { + switch v := kv.Value.(type) { + case programStub: + // loadProgram is idempotent and could return an existing Program. + prog, err := cl.loadProgram(string(v)) + if err != nil { + return fmt.Errorf("loading program %s, for map %s: %w", v, mapName, err) + } + mapSpec.Contents[i] = MapKV{kv.Key, prog} - fd := m.FD() - if fd < 0 { - return nil, fmt.Errorf("map %s: %w", ins.Reference, internal.ErrClosedFd) - } - if err := ins.RewriteMapPtr(m.FD()); err != nil { - return nil, fmt.Errorf("progam %s: map %s: %w", progName, ins.Reference, err) + case mapStub: + // loadMap is idempotent and could return an existing Map. + innerMap, err := cl.loadMap(string(v)) + if err != nil { + return fmt.Errorf("loading inner map %s, for map %s: %w", v, mapName, err) + } + mapSpec.Contents[i] = MapKV{kv.Key, innerMap} } } - prog, err := newProgramWithOptions(progSpec, opts.Programs, handles) - if err != nil { - return nil, fmt.Errorf("program %s: %w", progName, err) + // Populate and freeze the map if specified. + if err := m.finalize(mapSpec); err != nil { + return fmt.Errorf("populating map %s: %w", mapName, err) } - - progs[progName] = prog - return prog, nil } - return + return nil } // LoadCollection parses an object file and converts it to a collection. @@ -466,108 +540,81 @@ func (coll *Collection) DetachProgram(name string) *Program { return p } -// Assign the contents of a collection to a struct. -// -// Deprecated: use CollectionSpec.Assign instead. It provides the same -// functionality but creates only the maps and programs requested. -func (coll *Collection) Assign(to interface{}) error { - assignedMaps := make(map[string]struct{}) - assignedPrograms := make(map[string]struct{}) - valueOf := func(typ reflect.Type, name string) (reflect.Value, error) { - switch typ { - case reflect.TypeOf((*Program)(nil)): - p := coll.Programs[name] - if p == nil { - return reflect.Value{}, fmt.Errorf("missing program %q", name) - } - assignedPrograms[name] = struct{}{} - return reflect.ValueOf(p), nil - case reflect.TypeOf((*Map)(nil)): - m := coll.Maps[name] - if m == nil { - return reflect.Value{}, fmt.Errorf("missing map %q", name) - } - assignedMaps[name] = struct{}{} - return reflect.ValueOf(m), nil - default: - return reflect.Value{}, fmt.Errorf("unsupported type %s", typ) - } - } - - if err := assignValues(to, valueOf); err != nil { - return err - } +// structField represents a struct field containing the ebpf struct tag. +type structField struct { + reflect.StructField + value reflect.Value +} - for name := range assignedPrograms { - coll.DetachProgram(name) +// ebpfFields extracts field names tagged with 'ebpf' from a struct type. +// Keep track of visited types to avoid infinite recursion. +func ebpfFields(structVal reflect.Value, visited map[reflect.Type]bool) ([]structField, error) { + if visited == nil { + visited = make(map[reflect.Type]bool) } - for name := range assignedMaps { - coll.DetachMap(name) + structType := structVal.Type() + if structType.Kind() != reflect.Struct { + return nil, fmt.Errorf("%s is not a struct", structType) } - return nil -} - -func assignValues(to interface{}, valueOf func(reflect.Type, string) (reflect.Value, error)) error { - type structField struct { - reflect.StructField - value reflect.Value + if visited[structType] { + return nil, fmt.Errorf("recursion on type %s", structType) } - var ( - fields []structField - visitedTypes = make(map[reflect.Type]bool) - flattenStruct func(reflect.Value) error - ) + fields := make([]structField, 0, structType.NumField()) + for i := 0; i < structType.NumField(); i++ { + field := structField{structType.Field(i), structVal.Field(i)} - flattenStruct = func(structVal reflect.Value) error { - structType := structVal.Type() - if structType.Kind() != reflect.Struct { - return fmt.Errorf("%s is not a struct", structType) - } - - if visitedTypes[structType] { - return fmt.Errorf("recursion on type %s", structType) + // If the field is tagged, gather it and move on. + name := field.Tag.Get("ebpf") + if name != "" { + fields = append(fields, field) + continue } - for i := 0; i < structType.NumField(); i++ { - field := structField{structType.Field(i), structVal.Field(i)} - - name := field.Tag.Get("ebpf") - if name != "" { - fields = append(fields, field) + // If the field does not have an ebpf tag, but is a struct or a pointer + // to a struct, attempt to gather its fields as well. + var v reflect.Value + switch field.Type.Kind() { + case reflect.Ptr: + if field.Type.Elem().Kind() != reflect.Struct { continue } - var err error - switch field.Type.Kind() { - case reflect.Ptr: - if field.Type.Elem().Kind() != reflect.Struct { - continue - } - - if field.value.IsNil() { - return fmt.Errorf("nil pointer to %s", structType) - } + if field.value.IsNil() { + return nil, fmt.Errorf("nil pointer to %s", structType) + } - err = flattenStruct(field.value.Elem()) + // Obtain the destination type of the pointer. + v = field.value.Elem() - case reflect.Struct: - err = flattenStruct(field.value) + case reflect.Struct: + // Reference the value's type directly. + v = field.value - default: - continue - } + default: + continue + } - if err != nil { - return fmt.Errorf("field %s: %w", field.Name, err) - } + inner, err := ebpfFields(v, visited) + if err != nil { + return nil, fmt.Errorf("field %s: %w", field.Name, err) } - return nil + fields = append(fields, inner...) } + return fields, nil +} + +// assignValues attempts to populate all fields of 'to' tagged with 'ebpf'. +// +// getValue is called for every tagged field of 'to' and must return the value +// to be assigned to the field with the given typ and name. +func assignValues(to interface{}, + getValue func(typ reflect.Type, name string) (interface{}, error)) error { + toValue := reflect.ValueOf(to) if toValue.Type().Kind() != reflect.Ptr { return fmt.Errorf("%T is not a pointer to struct", to) @@ -577,7 +624,8 @@ func assignValues(to interface{}, valueOf func(reflect.Type, string) (reflect.Va return fmt.Errorf("nil pointer to %T", to) } - if err := flattenStruct(toValue.Elem()); err != nil { + fields, err := ebpfFields(toValue.Elem(), nil) + if err != nil { return err } @@ -587,19 +635,23 @@ func assignValues(to interface{}, valueOf func(reflect.Type, string) (reflect.Va name string } - assignedTo := make(map[elem]string) + assigned := make(map[elem]string) for _, field := range fields { - name := field.Tag.Get("ebpf") - if strings.Contains(name, ",") { + // Get string value the field is tagged with. + tag := field.Tag.Get("ebpf") + if strings.Contains(tag, ",") { return fmt.Errorf("field %s: ebpf tag contains a comma", field.Name) } - e := elem{field.Type, name} - if assignedField := assignedTo[e]; assignedField != "" { - return fmt.Errorf("field %s: %q was already assigned to %s", field.Name, name, assignedField) + // Check if the eBPF object with the requested + // type and tag was already assigned elsewhere. + e := elem{field.Type, tag} + if af := assigned[e]; af != "" { + return fmt.Errorf("field %s: object %q was already assigned to %s", field.Name, tag, af) } - value, err := valueOf(field.Type, name) + // Get the eBPF object referred to by the tag. + value, err := getValue(field.Type, tag) if err != nil { return fmt.Errorf("field %s: %w", field.Name, err) } @@ -607,9 +659,9 @@ func assignValues(to interface{}, valueOf func(reflect.Type, string) (reflect.Va if !field.value.CanSet() { return fmt.Errorf("field %s: can't set value", field.Name) } + field.value.Set(reflect.ValueOf(value)) - field.value.Set(value) - assignedTo[e] = field.Name + assigned[e] = field.Name } return nil diff --git a/vendor/github.com/cilium/ebpf/elf_reader.go b/vendor/github.com/cilium/ebpf/elf_reader.go index c2afbc36a5a9e..42010f43e5832 100644 --- a/vendor/github.com/cilium/ebpf/elf_reader.go +++ b/vendor/github.com/cilium/ebpf/elf_reader.go @@ -19,7 +19,7 @@ import ( ) // elfCode is a convenience to reduce the amount of arguments that have to -// be passed around explicitly. You should treat it's contents as immutable. +// be passed around explicitly. You should treat its contents as immutable. type elfCode struct { *internal.SafeELFFile sections map[elf.SectionIndex]*elfSection @@ -188,7 +188,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) { return nil, fmt.Errorf("load programs: %w", err) } - return &CollectionSpec{maps, progs}, nil + return &CollectionSpec{maps, progs, ec.ByteOrder}, nil } func loadLicense(sec *elf.Section) (string, error) { @@ -520,8 +520,12 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec) error { return fmt.Errorf("map %s: missing flags", mapName) } - if _, err := io.Copy(internal.DiscardZeroes{}, lr); err != nil { - return fmt.Errorf("map %s: unknown and non-zero fields in definition", mapName) + extra, err := io.ReadAll(lr) + if err != nil { + return fmt.Errorf("map %s: reading map tail: %w", mapName, err) + } + if len(extra) > 0 { + spec.Extra = *bytes.NewReader(extra) } if err := spec.clampPerfEventArraySize(); err != nil { @@ -535,6 +539,9 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec) error { return nil } +// loadBTFMaps iterates over all ELF sections marked as BTF map sections +// (like .maps) and parses them into MapSpecs. Dump the .maps section and +// any relocations with `readelf -x .maps -r `. func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec) error { for _, sec := range ec.sections { if sec.kind != btfMapSection { @@ -545,33 +552,46 @@ func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec) error { return fmt.Errorf("missing BTF") } - _, err := io.Copy(internal.DiscardZeroes{}, bufio.NewReader(sec.Open())) - if err != nil { - return fmt.Errorf("section %v: initializing BTF map definitions: %w", sec.Name, internal.ErrNotSupported) - } - - var ds btf.Datasec + // Each section must appear as a DataSec in the ELF's BTF blob. + var ds *btf.Datasec if err := ec.btf.FindType(sec.Name, &ds); err != nil { return fmt.Errorf("cannot find section '%s' in BTF: %w", sec.Name, err) } + // Open a Reader to the ELF's raw section bytes so we can assert that all + // of them are zero on a per-map (per-Var) basis. For now, the section's + // sole purpose is to receive relocations, so all must be zero. + rs := sec.Open() + for _, vs := range ds.Vars { + // BPF maps are declared as and assigned to global variables, + // so iterate over each Var in the DataSec and validate their types. v, ok := vs.Type.(*btf.Var) if !ok { return fmt.Errorf("section %v: unexpected type %s", sec.Name, vs.Type) } name := string(v.Name) + // The BTF metadata for each Var contains the full length of the map + // declaration, so read the corresponding amount of bytes from the ELF. + // This way, we can pinpoint which map declaration contains unexpected + // (and therefore unsupported) data. + _, err := io.Copy(internal.DiscardZeroes{}, io.LimitReader(rs, int64(vs.Size))) + if err != nil { + return fmt.Errorf("section %v: map %s: initializing BTF map definitions: %w", sec.Name, name, internal.ErrNotSupported) + } + if maps[name] != nil { return fmt.Errorf("section %v: map %s already exists", sec.Name, name) } + // Each Var representing a BTF map definition contains a Struct. mapStruct, ok := v.Type.(*btf.Struct) if !ok { return fmt.Errorf("expected struct, got %s", v.Type) } - mapSpec, err := mapSpecFromBTF(name, mapStruct, false, ec.btf) + mapSpec, err := mapSpecFromBTF(sec, &vs, mapStruct, ec.btf, name, false) if err != nil { return fmt.Errorf("map %v: %w", name, err) } @@ -582,32 +602,52 @@ func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec) error { maps[name] = mapSpec } + + // Drain the ELF section reader to make sure all bytes are accounted for + // with BTF metadata. + i, err := io.Copy(io.Discard, rs) + if err != nil { + return fmt.Errorf("section %v: unexpected error reading remainder of ELF section: %w", sec.Name, err) + } + if i > 0 { + return fmt.Errorf("section %v: %d unexpected remaining bytes in ELF section, invalid BTF?", sec.Name, i) + } } return nil } +// A programStub is a placeholder for a Program to be inserted at a certain map key. +// It needs to be resolved into a Program later on in the loader process. +type programStub string + +// A mapStub is a placeholder for a Map to be inserted at a certain map key. +// It needs to be resolved into a Map later on in the loader process. +type mapStub string + // mapSpecFromBTF produces a MapSpec based on a btf.Struct def representing // a BTF map definition. The name and spec arguments will be copied to the // resulting MapSpec, and inner must be true on any resursive invocations. -func mapSpecFromBTF(name string, def *btf.Struct, inner bool, spec *btf.Spec) (*MapSpec, error) { - +func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *btf.Spec, name string, inner bool) (*MapSpec, error) { var ( - key, value btf.Type - keySize, valueSize uint32 - mapType, flags, maxEntries uint32 - pinType PinType - innerMapSpec *MapSpec - err error + key, value btf.Type + keySize, valueSize uint32 + mapType MapType + flags, maxEntries uint32 + pinType PinType + innerMapSpec *MapSpec + contents []MapKV + err error ) for i, member := range def.Members { switch member.Name { case "type": - mapType, err = uintFromBTF(member.Type) + mt, err := uintFromBTF(member.Type) if err != nil { return nil, fmt.Errorf("can't get type: %w", err) } + mapType = MapType(mt) case "map_flags": flags, err = uintFromBTF(member.Type) @@ -717,7 +757,7 @@ func mapSpecFromBTF(name string, def *btf.Struct, inner bool, spec *btf.Spec) (* case *btf.Struct: // The values member pointing to an array of structs means we're expecting // a map-in-map declaration. - if MapType(mapType) != ArrayOfMaps && MapType(mapType) != HashOfMaps { + if mapType != ArrayOfMaps && mapType != HashOfMaps { return nil, errors.New("outer map needs to be an array or a hash of maps") } if inner { @@ -731,21 +771,38 @@ func mapSpecFromBTF(name string, def *btf.Struct, inner bool, spec *btf.Spec) (* // on kernels 5.2 and up) // Pass the BTF spec from the parent object, since both parent and // child must be created from the same BTF blob (on kernels that support BTF). - innerMapSpec, err = mapSpecFromBTF(name+"_inner", t, true, spec) + innerMapSpec, err = mapSpecFromBTF(es, vs, t, spec, name+"_inner", true) if err != nil { return nil, fmt.Errorf("can't parse BTF map definition of inner map: %w", err) } + case *btf.FuncProto: + // The values member contains an array of function pointers, meaning an + // autopopulated PROG_ARRAY. + if mapType != ProgramArray { + return nil, errors.New("map needs to be a program array") + } + default: return nil, fmt.Errorf("unsupported value type %q in 'values' field", t) } + contents, err = resolveBTFValuesContents(es, vs, member) + if err != nil { + return nil, fmt.Errorf("resolving values contents: %w", err) + } + default: return nil, fmt.Errorf("unrecognized field %s in BTF map definition", member.Name) } } - bm := btf.NewMap(spec, key, value) + if key == nil { + key = &btf.Void{} + } + if value == nil { + value = &btf.Void{} + } return &MapSpec{ Name: SanitizeName(name, -1), @@ -754,9 +811,10 @@ func mapSpecFromBTF(name string, def *btf.Struct, inner bool, spec *btf.Spec) (* ValueSize: valueSize, MaxEntries: maxEntries, Flags: flags, - BTF: &bm, + BTF: &btf.Map{Spec: spec, Key: key, Value: value}, Pinning: pinType, InnerMap: innerMapSpec, + Contents: contents, }, nil } @@ -793,6 +851,64 @@ func resolveBTFArrayMacro(typ btf.Type) (btf.Type, error) { return ptr.Target, nil } +// resolveBTFValuesContents resolves relocations into ELF sections belonging +// to btf.VarSecinfo's. This can be used on the 'values' member in BTF map +// definitions to extract static declarations of map contents. +func resolveBTFValuesContents(es *elfSection, vs *btf.VarSecinfo, member btf.Member) ([]MapKV, error) { + // The elements of a .values pointer array are not encoded in BTF. + // Instead, relocations are generated into each array index. + // However, it's possible to leave certain array indices empty, so all + // indices' offsets need to be checked for emitted relocations. + + // The offset of the 'values' member within the _struct_ (in bits) + // is the starting point of the array. Convert to bytes. Add VarSecinfo + // offset to get the absolute position in the ELF blob. + start := (member.OffsetBits / 8) + vs.Offset + // 'values' is encoded in BTF as a zero (variable) length struct + // member, and its contents run until the end of the VarSecinfo. + // Add VarSecinfo offset to get the absolute position in the ELF blob. + end := vs.Size + vs.Offset + // The size of an address in this section. This determines the width of + // an index in the array. + align := uint32(es.SectionHeader.Addralign) + + // Check if variable-length section is aligned. + if (end-start)%align != 0 { + return nil, errors.New("unaligned static values section") + } + elems := (end - start) / align + + if elems == 0 { + return nil, nil + } + + contents := make([]MapKV, 0, elems) + + // k is the array index, off is its corresponding ELF section offset. + for k, off := uint32(0), start; k < elems; k, off = k+1, off+align { + r, ok := es.relocations[uint64(off)] + if !ok { + continue + } + + // Relocation exists for the current offset in the ELF section. + // Emit a value stub based on the type of relocation to be replaced by + // a real fd later in the pipeline before populating the map. + // Map keys are encoded in MapKV entries, so empty array indices are + // skipped here. + switch t := elf.ST_TYPE(r.Info); t { + case elf.STT_FUNC: + contents = append(contents, MapKV{uint32(k), programStub(r.Name)}) + case elf.STT_OBJECT: + contents = append(contents, MapKV{uint32(k), mapStub(r.Name)}) + default: + return nil, fmt.Errorf("unknown relocation type %v", t) + } + } + + return contents, nil +} + func (ec *elfCode) loadDataSections(maps map[string]*MapSpec) error { for _, sec := range ec.sections { if sec.kind != dataSection { @@ -809,9 +925,9 @@ func (ec *elfCode) loadDataSections(maps map[string]*MapSpec) error { return errors.New("data sections require BTF, make sure all consts are marked as static") } - btfMap, err := ec.btf.Datasec(sec.Name) - if err != nil { - return err + var datasec *btf.Datasec + if err := ec.btf.FindType(sec.Name, &datasec); err != nil { + return fmt.Errorf("data section %s: can't get BTF: %w", sec.Name, err) } data, err := sec.Data() @@ -830,7 +946,7 @@ func (ec *elfCode) loadDataSections(maps map[string]*MapSpec) error { ValueSize: uint32(len(data)), MaxEntries: 1, Contents: []MapKV{{uint32(0), data}}, - BTF: btfMap, + BTF: &btf.Map{Spec: ec.btf, Key: &btf.Void{}, Value: datasec}, } switch sec.Name { @@ -855,6 +971,8 @@ func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) { }{ // From https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/lib/bpf/libbpf.c "socket": {SocketFilter, AttachNone, 0}, + "sk_reuseport/migrate": {SkReuseport, AttachSkReuseportSelectOrMigrate, 0}, + "sk_reuseport": {SkReuseport, AttachSkReuseportSelect, 0}, "seccomp": {SocketFilter, AttachNone, 0}, "kprobe/": {Kprobe, AttachNone, 0}, "uprobe/": {Kprobe, AttachNone, 0}, @@ -884,6 +1002,7 @@ func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) { "fmod_ret.s/": {Tracing, AttachModifyReturn, unix.BPF_F_SLEEPABLE}, "fexit.s/": {Tracing, AttachTraceFExit, unix.BPF_F_SLEEPABLE}, "sk_lookup/": {SkLookup, AttachSkLookup, 0}, + "freplace/": {Extension, AttachNone, 0}, "lsm/": {LSM, AttachLSMMac, 0}, "lsm.s/": {LSM, AttachLSMMac, unix.BPF_F_SLEEPABLE}, @@ -907,6 +1026,11 @@ func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) { "cgroup/setsockopt": {CGroupSockopt, AttachCGroupSetsockopt, 0}, "classifier": {SchedCLS, AttachNone, 0}, "action": {SchedACT, AttachNone, 0}, + + "cgroup/getsockname4": {CGroupSockAddr, AttachCgroupInet4GetSockname, 0}, + "cgroup/getsockname6": {CGroupSockAddr, AttachCgroupInet6GetSockname, 0}, + "cgroup/getpeername4": {CGroupSockAddr, AttachCgroupInet4GetPeername, 0}, + "cgroup/getpeername6": {CGroupSockAddr, AttachCgroupInet6GetPeername, 0}, } for prefix, t := range types { diff --git a/vendor/github.com/cilium/ebpf/elf_reader_fuzz.go b/vendor/github.com/cilium/ebpf/elf_reader_fuzz.go index d46d135f2fcd1..5f4e0a0ad023c 100644 --- a/vendor/github.com/cilium/ebpf/elf_reader_fuzz.go +++ b/vendor/github.com/cilium/ebpf/elf_reader_fuzz.go @@ -1,3 +1,4 @@ +//go:build gofuzz // +build gofuzz // Use with https://github.com/dvyukov/go-fuzz diff --git a/vendor/github.com/cilium/ebpf/go.mod b/vendor/github.com/cilium/ebpf/go.mod index df8139621c3e5..f5edf690ab064 100644 --- a/vendor/github.com/cilium/ebpf/go.mod +++ b/vendor/github.com/cilium/ebpf/go.mod @@ -1,9 +1,9 @@ module github.com/cilium/ebpf -go 1.15 +go 1.16 require ( github.com/frankban/quicktest v1.11.3 github.com/google/go-cmp v0.5.4 - golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c + golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 ) diff --git a/vendor/github.com/cilium/ebpf/go.sum b/vendor/github.com/cilium/ebpf/go.sum index a5039262aab0c..1ef5a4767e818 100644 --- a/vendor/github.com/cilium/ebpf/go.sum +++ b/vendor/github.com/cilium/ebpf/go.sum @@ -7,7 +7,7 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 h1:GkvMjFtXUmahfDtashnc1mnrCtuBVcwse5QV2lUk/tI= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/github.com/cilium/ebpf/info.go b/vendor/github.com/cilium/ebpf/info.go index b95131ef57262..65fa4d7d85023 100644 --- a/vendor/github.com/cilium/ebpf/info.go +++ b/vendor/github.com/cilium/ebpf/info.go @@ -12,6 +12,7 @@ import ( "time" "github.com/cilium/ebpf/internal" + "github.com/cilium/ebpf/internal/btf" ) // MapInfo describes a map. @@ -87,12 +88,16 @@ type ProgramInfo struct { Tag string // Name as supplied by user space at load time. Name string + // BTF for the program. + btf btf.ID + // IDS map ids related to program. + ids []MapID stats *programStats } func newProgramInfoFromFd(fd *internal.FD) (*ProgramInfo, error) { - info, err := bpfGetProgInfoByFD(fd) + info, err := bpfGetProgInfoByFD(fd, nil) if errors.Is(err, syscall.EINVAL) { return newProgramInfoFromProc(fd) } @@ -100,6 +105,15 @@ func newProgramInfoFromFd(fd *internal.FD) (*ProgramInfo, error) { return nil, err } + var mapIDs []MapID + if info.nr_map_ids > 0 { + mapIDs = make([]MapID, info.nr_map_ids) + info, err = bpfGetProgInfoByFD(fd, mapIDs) + if err != nil { + return nil, err + } + } + return &ProgramInfo{ Type: ProgramType(info.prog_type), id: ProgramID(info.id), @@ -107,6 +121,8 @@ func newProgramInfoFromFd(fd *internal.FD) (*ProgramInfo, error) { Tag: hex.EncodeToString(info.tag[:]), // name is available from 4.15. Name: internal.CString(info.name[:]), + btf: btf.ID(info.btf_id), + ids: mapIDs, stats: &programStats{ runtime: time.Duration(info.run_time_ns), runCount: info.run_cnt, @@ -142,6 +158,17 @@ func (pi *ProgramInfo) ID() (ProgramID, bool) { return pi.id, pi.id > 0 } +// BTFID returns the BTF ID associated with the program. +// +// Available from 5.0. +// +// The bool return value indicates whether this optional field is available and +// populated. (The field may be available but not populated if the kernel +// supports the field but the program was loaded without BTF information.) +func (pi *ProgramInfo) BTFID() (btf.ID, bool) { + return pi.btf, pi.btf > 0 +} + // RunCount returns the total number of times the program was called. // // Can return 0 if the collection of statistics is not enabled. See EnableStats(). @@ -164,6 +191,13 @@ func (pi *ProgramInfo) Runtime() (time.Duration, bool) { return time.Duration(0), false } +// MapIDs returns the maps related to the program. +// +// The bool return value indicates whether this optional field is available. +func (pi *ProgramInfo) MapIDs() ([]MapID, bool) { + return pi.ids, pi.ids != nil +} + func scanFdInfo(fd *internal.FD, fields map[string]interface{}) error { raw, err := fd.Value() if err != nil { diff --git a/vendor/github.com/cilium/ebpf/internal/align.go b/vendor/github.com/cilium/ebpf/internal/align.go new file mode 100644 index 0000000000000..8b4f2658eacbc --- /dev/null +++ b/vendor/github.com/cilium/ebpf/internal/align.go @@ -0,0 +1,6 @@ +package internal + +// Align returns 'n' updated to 'alignment' boundary. +func Align(n, alignment int) int { + return (int(n) + alignment - 1) / alignment * alignment +} diff --git a/vendor/github.com/cilium/ebpf/internal/btf/btf.go b/vendor/github.com/cilium/ebpf/internal/btf/btf.go index 5da9e11921a3b..2b5f6d226a4f5 100644 --- a/vendor/github.com/cilium/ebpf/internal/btf/btf.go +++ b/vendor/github.com/cilium/ebpf/internal/btf/btf.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "math" "os" "reflect" @@ -27,12 +26,15 @@ var ( ErrNoExtendedInfo = errors.New("no extended info") ) +// ID represents the unique ID of a BTF object. +type ID uint32 + // Spec represents decoded BTF. type Spec struct { rawTypes []rawType strings stringTable types []Type - namedTypes map[string][]namedType + namedTypes map[string][]NamedType funcInfos map[string]extInfo lineInfos map[string]extInfo coreRelos map[string]coreRelos @@ -61,15 +63,6 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) { } defer file.Close() - btfSection, btfExtSection, sectionSizes, err := findBtfSections(file) - if err != nil { - return nil, err - } - - if btfSection == nil { - return nil, fmt.Errorf("btf: %w", ErrNotFound) - } - symbols, err := file.Symbols() if err != nil { return nil, fmt.Errorf("can't read symbols: %v", err) @@ -87,10 +80,6 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) { } secName := file.Sections[symbol.Section].Name - if _, ok := sectionSizes[secName]; !ok { - continue - } - if symbol.Value > math.MaxUint32 { return nil, fmt.Errorf("section %s: symbol %s: size exceeds maximum", secName, symbol.Name) } @@ -98,24 +87,10 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) { variableOffsets[variable{secName, symbol.Name}] = uint32(symbol.Value) } - spec, err := loadNakedSpec(btfSection.Open(), file.ByteOrder, sectionSizes, variableOffsets) - if err != nil { - return nil, err - } - - if btfExtSection == nil { - return spec, nil - } - - spec.funcInfos, spec.lineInfos, spec.coreRelos, err = parseExtInfos(btfExtSection.Open(), file.ByteOrder, spec.strings) - if err != nil { - return nil, fmt.Errorf("can't read ext info: %w", err) - } - - return spec, nil + return loadSpecFromELF(file, variableOffsets) } -func findBtfSections(file *internal.SafeELFFile) (*elf.Section, *elf.Section, map[string]uint32, error) { +func loadSpecFromELF(file *internal.SafeELFFile, variableOffsets map[variable]uint32) (*Spec, error) { var ( btfSection *elf.Section btfExtSection *elf.Section @@ -134,33 +109,45 @@ func findBtfSections(file *internal.SafeELFFile) (*elf.Section, *elf.Section, ma } if sec.Size > math.MaxUint32 { - return nil, nil, nil, fmt.Errorf("section %s exceeds maximum size", sec.Name) + return nil, fmt.Errorf("section %s exceeds maximum size", sec.Name) } sectionSizes[sec.Name] = uint32(sec.Size) } } - return btfSection, btfExtSection, sectionSizes, nil -} -func loadSpecFromVmlinux(rd io.ReaderAt) (*Spec, error) { - file, err := internal.NewSafeELFFile(rd) + if btfSection == nil { + return nil, fmt.Errorf("btf: %w", ErrNotFound) + } + + spec, err := loadRawSpec(btfSection.Open(), file.ByteOrder, sectionSizes, variableOffsets) if err != nil { return nil, err } - defer file.Close() - btfSection, _, _, err := findBtfSections(file) - if err != nil { - return nil, fmt.Errorf(".BTF ELF section: %s", err) + if btfExtSection == nil { + return spec, nil } - if btfSection == nil { - return nil, fmt.Errorf("unable to find .BTF ELF section") + + spec.funcInfos, spec.lineInfos, spec.coreRelos, err = parseExtInfos(btfExtSection.Open(), file.ByteOrder, spec.strings) + if err != nil { + return nil, fmt.Errorf("can't read ext info: %w", err) } - return loadNakedSpec(btfSection.Open(), file.ByteOrder, nil, nil) + + return spec, nil +} + +// LoadRawSpec reads a blob of BTF data that isn't wrapped in an ELF file. +// +// Prefer using LoadSpecFromReader, since this function only supports a subset +// of BTF. +func LoadRawSpec(btf io.Reader, bo binary.ByteOrder) (*Spec, error) { + // This will return an error if we encounter a Datasec, since we can't fix + // it up. + return loadRawSpec(btf, bo, nil, nil) } -func loadNakedSpec(btf io.ReadSeeker, bo binary.ByteOrder, sectionSizes map[string]uint32, variableOffsets map[variable]uint32) (*Spec, error) { +func loadRawSpec(btf io.Reader, bo binary.ByteOrder, sectionSizes map[string]uint32, variableOffsets map[variable]uint32) (*Spec, error) { rawTypes, rawStrings, err := parseBTF(btf, bo) if err != nil { return nil, err @@ -217,7 +204,7 @@ func loadKernelSpec() (*Spec, error) { if err == nil { defer fh.Close() - return loadNakedSpec(fh, internal.NativeEndian, nil, nil) + return LoadRawSpec(fh, internal.NativeEndian) } // use same list of locations as libbpf @@ -241,14 +228,20 @@ func loadKernelSpec() (*Spec, error) { } defer fh.Close() - return loadSpecFromVmlinux(fh) + file, err := internal.NewSafeELFFile(fh) + if err != nil { + return nil, err + } + defer file.Close() + + return loadSpecFromELF(file, nil) } return nil, fmt.Errorf("no BTF for kernel version %s: %w", release, internal.ErrNotSupported) } -func parseBTF(btf io.ReadSeeker, bo binary.ByteOrder) ([]rawType, stringTable, error) { - rawBTF, err := ioutil.ReadAll(btf) +func parseBTF(btf io.Reader, bo binary.ByteOrder) ([]rawType, stringTable, error) { + rawBTF, err := io.ReadAll(btf) if err != nil { return nil, nil, fmt.Errorf("can't read BTF: %v", err) } @@ -357,6 +350,30 @@ func fixupDatasec(rawTypes []rawType, rawStrings stringTable, sectionSizes map[s return nil } +// Copy creates a copy of Spec. +func (s *Spec) Copy() *Spec { + types, _ := copyTypes(s.types, nil) + namedTypes := make(map[string][]NamedType) + for _, typ := range types { + if named, ok := typ.(NamedType); ok { + name := essentialName(named.TypeName()) + namedTypes[name] = append(namedTypes[name], named) + } + } + + // NB: Other parts of spec are not copied since they are immutable. + return &Spec{ + s.rawTypes, + s.strings, + types, + namedTypes, + s.funcInfos, + s.lineInfos, + s.coreRelos, + s.byteOrder, + } +} + type marshalOpts struct { ByteOrder binary.ByteOrder StripFuncLinkage bool @@ -447,36 +464,37 @@ func (s *Spec) Program(name string, length uint64) (*Program, error) { return &Program{s, length, funcInfos, lineInfos, relos}, nil } -// Datasec returns the BTF required to create maps which represent data sections. -func (s *Spec) Datasec(name string) (*Map, error) { - var datasec Datasec - if err := s.FindType(name, &datasec); err != nil { - return nil, fmt.Errorf("data section %s: can't get BTF: %w", name, err) - } - - m := NewMap(s, &Void{}, &datasec) - return &m, nil -} - // FindType searches for a type with a specific name. // -// hint determines the type of the returned Type. +// Called T a type that satisfies Type, typ must be a non-nil **T. +// On success, the address of the found type will be copied in typ. // // Returns an error wrapping ErrNotFound if no matching // type exists in spec. -func (s *Spec) FindType(name string, typ Type) error { - var ( - wanted = reflect.TypeOf(typ) - candidate Type - ) +func (s *Spec) FindType(name string, typ interface{}) error { + typValue := reflect.ValueOf(typ) + if typValue.Kind() != reflect.Ptr { + return fmt.Errorf("%T is not a pointer", typ) + } + + typPtr := typValue.Elem() + if !typPtr.CanSet() { + return fmt.Errorf("%T cannot be set", typ) + } + wanted := typPtr.Type() + if !wanted.AssignableTo(reflect.TypeOf((*Type)(nil)).Elem()) { + return fmt.Errorf("%T does not satisfy Type interface", typ) + } + + var candidate Type for _, typ := range s.namedTypes[essentialName(name)] { if reflect.TypeOf(typ) != wanted { continue } // Match against the full name, not just the essential one. - if typ.name() != name { + if typ.TypeName() != name { continue } @@ -491,15 +509,15 @@ func (s *Spec) FindType(name string, typ Type) error { return fmt.Errorf("type %s: %w", name, ErrNotFound) } - cpy, _ := copyType(candidate, nil) - value := reflect.Indirect(reflect.ValueOf(cpy)) - reflect.Indirect(reflect.ValueOf(typ)).Set(value) + typPtr.Set(reflect.ValueOf(candidate)) + return nil } // Handle is a reference to BTF loaded into the kernel. type Handle struct { - fd *internal.FD + spec *Spec + fd *internal.FD } // NewHandle loads BTF into the kernel. @@ -541,7 +559,32 @@ func NewHandle(spec *Spec) (*Handle, error) { return nil, internal.ErrorWithLog(err, logBuf, logErr) } - return &Handle{fd}, nil + return &Handle{spec.Copy(), fd}, nil +} + +// NewHandleFromID returns the BTF handle for a given id. +// +// Returns ErrNotExist, if there is no BTF with the given id. +// +// Requires CAP_SYS_ADMIN. +func NewHandleFromID(id ID) (*Handle, error) { + fd, err := internal.BPFObjGetFDByID(internal.BPF_BTF_GET_FD_BY_ID, uint32(id)) + if err != nil { + return nil, fmt.Errorf("get BTF by id: %w", err) + } + + info, err := newInfoFromFd(fd) + if err != nil { + _ = fd.Close() + return nil, fmt.Errorf("get BTF spec for handle: %w", err) + } + + return &Handle{info.BTF, fd}, nil +} + +// Spec returns the Spec that defined the BTF loaded into the kernel. +func (h *Handle) Spec() *Spec { + return h.spec } // Close destroys the handle. @@ -563,43 +606,8 @@ func (h *Handle) FD() int { // Map is the BTF for a map. type Map struct { - spec *Spec - key, value Type -} - -// NewMap returns a new Map containing the given values. -// The key and value arguments are initialized to Void if nil values are given. -func NewMap(spec *Spec, key Type, value Type) Map { - if key == nil { - key = &Void{} - } - if value == nil { - value = &Void{} - } - - return Map{ - spec: spec, - key: key, - value: value, - } -} - -// MapSpec should be a method on Map, but is a free function -// to hide it from users of the ebpf package. -func MapSpec(m *Map) *Spec { - return m.spec -} - -// MapKey should be a method on Map, but is a free function -// to hide it from users of the ebpf package. -func MapKey(m *Map) Type { - return m.key -} - -// MapValue should be a method on Map, but is a free function -// to hide it from users of the ebpf package. -func MapValue(m *Map) Type { - return m.value + Spec *Spec + Key, Value Type } // Program is the BTF information for a stream of instructions. @@ -610,68 +618,59 @@ type Program struct { coreRelos coreRelos } -// ProgramSpec returns the Spec needed for loading function and line infos into the kernel. -// -// This is a free function instead of a method to hide it from users -// of package ebpf. -func ProgramSpec(s *Program) *Spec { - return s.spec +// Spec returns the BTF spec of this program. +func (p *Program) Spec() *Spec { + return p.spec } -// ProgramAppend the information from other to the Program. -// -// This is a free function instead of a method to hide it from users -// of package ebpf. -func ProgramAppend(s, other *Program) error { - funcInfos, err := s.funcInfos.append(other.funcInfos, s.length) +// Append the information from other to the Program. +func (p *Program) Append(other *Program) error { + if other.spec != p.spec { + return fmt.Errorf("can't append program with different BTF specs") + } + + funcInfos, err := p.funcInfos.append(other.funcInfos, p.length) if err != nil { return fmt.Errorf("func infos: %w", err) } - lineInfos, err := s.lineInfos.append(other.lineInfos, s.length) + lineInfos, err := p.lineInfos.append(other.lineInfos, p.length) if err != nil { return fmt.Errorf("line infos: %w", err) } - s.funcInfos = funcInfos - s.lineInfos = lineInfos - s.coreRelos = s.coreRelos.append(other.coreRelos, s.length) - s.length += other.length + p.funcInfos = funcInfos + p.lineInfos = lineInfos + p.coreRelos = p.coreRelos.append(other.coreRelos, p.length) + p.length += other.length return nil } -// ProgramFuncInfos returns the binary form of BTF function infos. -// -// This is a free function instead of a method to hide it from users -// of package ebpf. -func ProgramFuncInfos(s *Program) (recordSize uint32, bytes []byte, err error) { - bytes, err = s.funcInfos.MarshalBinary() +// FuncInfos returns the binary form of BTF function infos. +func (p *Program) FuncInfos() (recordSize uint32, bytes []byte, err error) { + bytes, err = p.funcInfos.MarshalBinary() if err != nil { - return 0, nil, err + return 0, nil, fmt.Errorf("func infos: %w", err) } - return s.funcInfos.recordSize, bytes, nil + return p.funcInfos.recordSize, bytes, nil } -// ProgramLineInfos returns the binary form of BTF line infos. -// -// This is a free function instead of a method to hide it from users -// of package ebpf. -func ProgramLineInfos(s *Program) (recordSize uint32, bytes []byte, err error) { - bytes, err = s.lineInfos.MarshalBinary() +// LineInfos returns the binary form of BTF line infos. +func (p *Program) LineInfos() (recordSize uint32, bytes []byte, err error) { + bytes, err = p.lineInfos.MarshalBinary() if err != nil { - return 0, nil, err + return 0, nil, fmt.Errorf("line infos: %w", err) } - return s.lineInfos.recordSize, bytes, nil + return p.lineInfos.recordSize, bytes, nil } -// ProgramFixups returns the changes required to adjust the program to the target. +// Fixups returns the changes required to adjust the program to the target. // -// This is a free function instead of a method to hide it from users -// of package ebpf. -func ProgramFixups(s *Program, target *Spec) (COREFixups, error) { - if len(s.coreRelos) == 0 { +// Passing a nil target will relocate against the running kernel. +func (p *Program) Fixups(target *Spec) (COREFixups, error) { + if len(p.coreRelos) == 0 { return nil, nil } @@ -683,7 +682,7 @@ func ProgramFixups(s *Program, target *Spec) (COREFixups, error) { } } - return coreRelocate(s.spec, target, s.coreRelos) + return coreRelocate(p.spec, target, p.coreRelos) } type bpfLoadBTFAttr struct { diff --git a/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go b/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go index a5ef945120138..d98c73ca594ae 100644 --- a/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go +++ b/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go @@ -31,6 +31,8 @@ const ( // Added ~5.1 kindVar kindDatasec + // Added ~5.13 + kindFloat ) // FuncLinkage describes BTF function linkage metadata. @@ -54,7 +56,7 @@ const ( const ( btfTypeKindShift = 24 - btfTypeKindLen = 4 + btfTypeKindLen = 5 btfTypeVlenShift = 0 btfTypeVlenMask = 16 btfTypeKindFlagShift = 31 @@ -67,8 +69,8 @@ type btfType struct { /* "info" bits arrangement * bits 0-15: vlen (e.g. # of struct's members), linkage * bits 16-23: unused - * bits 24-27: kind (e.g. int, ptr, array...etc) - * bits 28-30: unused + * bits 24-28: kind (e.g. int, ptr, array...etc) + * bits 29-30: unused * bit 31: kind_flag, currently used by * struct, union and fwd */ @@ -117,6 +119,8 @@ func (k btfKind) String() string { return "Variable" case kindDatasec: return "Section" + case kindFloat: + return "Float" default: return fmt.Sprintf("Unknown (%d)", k) } @@ -260,6 +264,7 @@ func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) { data = new(btfVariable) case kindDatasec: data = make([]btfVarSecinfo, header.Vlen()) + case kindFloat: default: return nil, fmt.Errorf("type id %v: unknown kind: %v", id, header.Kind()) } diff --git a/vendor/github.com/cilium/ebpf/internal/btf/core.go b/vendor/github.com/cilium/ebpf/internal/btf/core.go index 7c888f602d0df..d02df9d50bb31 100644 --- a/vendor/github.com/cilium/ebpf/internal/btf/core.go +++ b/vendor/github.com/cilium/ebpf/internal/btf/core.go @@ -234,13 +234,13 @@ func coreRelocate(local, target *Spec, relos coreRelos) (COREFixups, error) { } localType := local.types[id] - named, ok := localType.(namedType) - if !ok || named.name() == "" { + named, ok := localType.(NamedType) + if !ok || named.TypeName() == "" { return nil, fmt.Errorf("relocate unnamed or anonymous type %s: %w", localType, ErrNotSupported) } relos := relosByID[id] - targets := target.namedTypes[named.essentialName()] + targets := target.namedTypes[essentialName(named.TypeName())] fixups, err := coreCalculateFixups(localType, targets, relos) if err != nil { return nil, fmt.Errorf("relocate %s: %w", localType, err) @@ -262,7 +262,7 @@ var errImpossibleRelocation = errors.New("impossible relocation") // // The best target is determined by scoring: the less poisoning we have to do // the better the target is. -func coreCalculateFixups(local Type, targets []namedType, relos coreRelos) ([]COREFixup, error) { +func coreCalculateFixups(local Type, targets []NamedType, relos coreRelos) ([]COREFixup, error) { localID := local.ID() local, err := copyType(local, skipQualifierAndTypedef) if err != nil { @@ -467,8 +467,8 @@ func parseCoreAccessor(accessor string) (coreAccessor, error) { return nil, fmt.Errorf("empty accessor") } - var result coreAccessor parts := strings.Split(accessor, ":") + result := make(coreAccessor, 0, len(parts)) for _, part := range parts { // 31 bits to avoid overflowing int on 32 bit platforms. index, err := strconv.ParseUint(part, 10, 31) @@ -564,7 +564,7 @@ func coreFindField(local Type, localAcc coreAccessor, target Type) (_, _ coreFie // This is an anonymous struct or union, ignore it. local = localMember.Type - localOffset += localMember.Offset + localOffset += localMember.OffsetBits localMaybeFlex = false continue } @@ -585,10 +585,10 @@ func coreFindField(local Type, localAcc coreAccessor, target Type) (_, _ coreFie local = localMember.Type localMaybeFlex = acc == len(localMembers)-1 - localOffset += localMember.Offset + localOffset += localMember.OffsetBits target = targetMember.Type targetMaybeFlex = last - targetOffset += targetMember.Offset + targetOffset += targetMember.OffsetBits case *Array: // For arrays, acc is the index in the target. @@ -639,7 +639,7 @@ func coreFindField(local Type, localAcc coreAccessor, target Type) (_, _ coreFie // coreFindMember finds a member in a composite type while handling anonymous // structs and unions. -func coreFindMember(typ composite, name Name) (Member, bool, error) { +func coreFindMember(typ composite, name string) (Member, bool, error) { if name == "" { return Member{}, false, errors.New("can't search for anonymous member") } @@ -670,7 +670,7 @@ func coreFindMember(typ composite, name Name) (Member, bool, error) { for j, member := range members { if member.Name == name { // NB: This is safe because member is a copy. - member.Offset += target.offset + member.OffsetBits += target.offset return member, j == len(members)-1, nil } @@ -685,7 +685,7 @@ func coreFindMember(typ composite, name Name) (Member, bool, error) { return Member{}, false, fmt.Errorf("anonymous non-composite type %T not allowed", member.Type) } - targets = append(targets, offsetTarget{comp, target.offset + member.Offset}) + targets = append(targets, offsetTarget{comp, target.offset + member.OffsetBits}) } } @@ -704,9 +704,9 @@ func coreFindEnumValue(local Type, localAcc coreAccessor, target Type) (localVal return nil, nil, errImpossibleRelocation } - localName := localValue.Name.essentialName() + localName := essentialName(localValue.Name) for i, targetValue := range targetEnum.Values { - if targetValue.Name.essentialName() != localName { + if essentialName(targetValue.Name) != localName { continue } @@ -813,6 +813,7 @@ func coreAreTypesCompatible(localType Type, targetType Type) error { * least one of enums should be anonymous; * - for ENUMs, check sizes, names are ignored; * - for INT, size and signedness are ignored; + * - any two FLOATs are always compatible; * - for ARRAY, dimensionality is ignored, element types are checked for * compatibility recursively; * [ NB: coreAreMembersCompatible doesn't recurse, this check is done @@ -848,16 +849,16 @@ func coreAreMembersCompatible(localType Type, targetType Type) error { } switch lv := localType.(type) { - case *Array, *Pointer: + case *Array, *Pointer, *Float: return nil case *Enum: tv := targetType.(*Enum) - return doNamesMatch(lv.name(), tv.name()) + return doNamesMatch(lv.Name, tv.Name) case *Fwd: tv := targetType.(*Fwd) - return doNamesMatch(lv.name(), tv.name()) + return doNamesMatch(lv.Name, tv.Name) case *Int: tv := targetType.(*Int) diff --git a/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go b/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go index beba1bce6980b..cdae2ec40827b 100644 --- a/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go +++ b/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "github.com/cilium/ebpf/asm" "github.com/cilium/ebpf/internal" @@ -64,7 +63,7 @@ func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (f // Of course, the .BTF.ext header has different semantics than the // .BTF ext header. We need to ignore non-null values. - _, err = io.CopyN(ioutil.Discard, r, remainder) + _, err = io.CopyN(io.Discard, r, remainder) if err != nil { return nil, nil, nil, fmt.Errorf("header padding: %v", err) } @@ -114,11 +113,16 @@ type extInfoRecord struct { } type extInfo struct { + byteOrder binary.ByteOrder recordSize uint32 records []extInfoRecord } func (ei extInfo) append(other extInfo, offset uint64) (extInfo, error) { + if other.byteOrder != ei.byteOrder { + return extInfo{}, fmt.Errorf("ext_info byte order mismatch, want %v (got %v)", ei.byteOrder, other.byteOrder) + } + if other.recordSize != ei.recordSize { return extInfo{}, fmt.Errorf("ext_info record size mismatch, want %d (got %d)", ei.recordSize, other.recordSize) } @@ -131,10 +135,14 @@ func (ei extInfo) append(other extInfo, offset uint64) (extInfo, error) { Opaque: info.Opaque, }) } - return extInfo{ei.recordSize, records}, nil + return extInfo{ei.byteOrder, ei.recordSize, records}, nil } func (ei extInfo) MarshalBinary() ([]byte, error) { + if ei.byteOrder != internal.NativeEndian { + return nil, fmt.Errorf("%s is not the native byte order", ei.byteOrder) + } + if len(ei.records) == 0 { return nil, nil } @@ -197,6 +205,7 @@ func parseExtInfo(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[st } result[secName] = extInfo{ + bo, recordSize, records, } diff --git a/vendor/github.com/cilium/ebpf/internal/btf/fuzz.go b/vendor/github.com/cilium/ebpf/internal/btf/fuzz.go index 37e043fd378c7..220b285afe008 100644 --- a/vendor/github.com/cilium/ebpf/internal/btf/fuzz.go +++ b/vendor/github.com/cilium/ebpf/internal/btf/fuzz.go @@ -1,3 +1,4 @@ +//go:build gofuzz // +build gofuzz // Use with https://github.com/dvyukov/go-fuzz diff --git a/vendor/github.com/cilium/ebpf/internal/btf/info.go b/vendor/github.com/cilium/ebpf/internal/btf/info.go new file mode 100644 index 0000000000000..6a9b5d2e0ba36 --- /dev/null +++ b/vendor/github.com/cilium/ebpf/internal/btf/info.go @@ -0,0 +1,48 @@ +package btf + +import ( + "bytes" + + "github.com/cilium/ebpf/internal" +) + +// info describes a BTF object. +type info struct { + BTF *Spec + ID ID + // Name is an identifying name for the BTF, currently only used by the + // kernel. + Name string + // KernelBTF is true if the BTf originated with the kernel and not + // userspace. + KernelBTF bool +} + +func newInfoFromFd(fd *internal.FD) (*info, error) { + // We invoke the syscall once with a empty BTF and name buffers to get size + // information to allocate buffers. Then we invoke it a second time with + // buffers to receive the data. + bpfInfo, err := bpfGetBTFInfoByFD(fd, nil, nil) + if err != nil { + return nil, err + } + + btfBuffer := make([]byte, bpfInfo.btfSize) + nameBuffer := make([]byte, bpfInfo.nameLen) + bpfInfo, err = bpfGetBTFInfoByFD(fd, btfBuffer, nameBuffer) + if err != nil { + return nil, err + } + + spec, err := loadRawSpec(bytes.NewReader(btfBuffer), internal.NativeEndian, nil, nil) + if err != nil { + return nil, err + } + + return &info{ + BTF: spec, + ID: ID(bpfInfo.id), + Name: internal.CString(nameBuffer), + KernelBTF: bpfInfo.kernelBTF != 0, + }, nil +} diff --git a/vendor/github.com/cilium/ebpf/internal/btf/strings.go b/vendor/github.com/cilium/ebpf/internal/btf/strings.go index 8782643a043ef..9876aa227c0a9 100644 --- a/vendor/github.com/cilium/ebpf/internal/btf/strings.go +++ b/vendor/github.com/cilium/ebpf/internal/btf/strings.go @@ -5,13 +5,12 @@ import ( "errors" "fmt" "io" - "io/ioutil" ) type stringTable []byte func readStringTable(r io.Reader) (stringTable, error) { - contents, err := ioutil.ReadAll(r) + contents, err := io.ReadAll(r) if err != nil { return nil, fmt.Errorf("can't read string table: %v", err) } @@ -53,8 +52,3 @@ func (st stringTable) Lookup(offset uint32) (string, error) { return string(str[:end]), nil } - -func (st stringTable) LookupName(offset uint32) (Name, error) { - str, err := st.Lookup(offset) - return Name(str), err -} diff --git a/vendor/github.com/cilium/ebpf/internal/btf/syscalls.go b/vendor/github.com/cilium/ebpf/internal/btf/syscalls.go new file mode 100644 index 0000000000000..a4f80abd011f7 --- /dev/null +++ b/vendor/github.com/cilium/ebpf/internal/btf/syscalls.go @@ -0,0 +1,31 @@ +package btf + +import ( + "fmt" + "unsafe" + + "github.com/cilium/ebpf/internal" +) + +type bpfBTFInfo struct { + btf internal.Pointer + btfSize uint32 + id uint32 + name internal.Pointer + nameLen uint32 + kernelBTF uint32 +} + +func bpfGetBTFInfoByFD(fd *internal.FD, btf, name []byte) (*bpfBTFInfo, error) { + info := bpfBTFInfo{ + btf: internal.NewSlicePointer(btf), + btfSize: uint32(len(btf)), + name: internal.NewSlicePointer(name), + nameLen: uint32(len(name)), + } + if err := internal.BPFObjGetInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info)); err != nil { + return nil, fmt.Errorf("can't get program info: %w", err) + } + + return &info, nil +} diff --git a/vendor/github.com/cilium/ebpf/internal/btf/types.go b/vendor/github.com/cilium/ebpf/internal/btf/types.go index 62aa31bcd7819..5c8e7c6e59da1 100644 --- a/vendor/github.com/cilium/ebpf/internal/btf/types.go +++ b/vendor/github.com/cilium/ebpf/internal/btf/types.go @@ -30,27 +30,26 @@ type Type interface { walk(*typeDeque) } -// namedType is a type with a name. -// -// Most named types simply embed Name. -type namedType interface { +// NamedType is a type with a name. +type NamedType interface { Type - name() string - essentialName() string -} - -// Name identifies a type. -// -// Anonymous types have an empty name. -type Name string -func (n Name) name() string { - return string(n) + // Name of the type, empty for anonymous types. + TypeName() string } -func (n Name) essentialName() string { - return essentialName(string(n)) -} +var ( + _ NamedType = (*Int)(nil) + _ NamedType = (*Struct)(nil) + _ NamedType = (*Union)(nil) + _ NamedType = (*Enum)(nil) + _ NamedType = (*Fwd)(nil) + _ NamedType = (*Func)(nil) + _ NamedType = (*Typedef)(nil) + _ NamedType = (*Var)(nil) + _ NamedType = (*Datasec)(nil) + _ NamedType = (*Float)(nil) +) // Void is the unit type of BTF. type Void struct{} @@ -72,19 +71,17 @@ const ( // Int is an integer of a given length. type Int struct { TypeID - Name + Name string // The size of the integer in bytes. Size uint32 Encoding IntEncoding - // Offset is the starting bit offset. Currently always 0. + // OffsetBits is the starting bit offset. Currently always 0. // See https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-int - Offset uint32 - Bits byte + OffsetBits uint32 + Bits byte } -var _ namedType = (*Int)(nil) - func (i *Int) String() string { var s strings.Builder @@ -110,15 +107,16 @@ func (i *Int) String() string { return s.String() } -func (i *Int) size() uint32 { return i.Size } -func (i *Int) walk(*typeDeque) {} +func (i *Int) TypeName() string { return i.Name } +func (i *Int) size() uint32 { return i.Size } +func (i *Int) walk(*typeDeque) {} func (i *Int) copy() Type { cpy := *i return &cpy } func (i *Int) isBitfield() bool { - return i.Offset > 0 + return i.OffsetBits > 0 } // Pointer is a pointer to another type. @@ -158,7 +156,7 @@ func (arr *Array) copy() Type { // Struct is a compound type of consecutive members. type Struct struct { TypeID - Name + Name string // The size of the struct including padding, in bytes Size uint32 Members []Member @@ -168,6 +166,8 @@ func (s *Struct) String() string { return fmt.Sprintf("struct#%d[%q]", s.TypeID, s.Name) } +func (s *Struct) TypeName() string { return s.Name } + func (s *Struct) size() uint32 { return s.Size } func (s *Struct) walk(tdq *typeDeque) { @@ -189,7 +189,7 @@ func (s *Struct) members() []Member { // Union is a compound type where members occupy the same memory. type Union struct { TypeID - Name + Name string // The size of the union including padding, in bytes. Size uint32 Members []Member @@ -199,6 +199,8 @@ func (u *Union) String() string { return fmt.Sprintf("union#%d[%q]", u.TypeID, u.Name) } +func (u *Union) TypeName() string { return u.Name } + func (u *Union) size() uint32 { return u.Size } func (u *Union) walk(tdq *typeDeque) { @@ -236,17 +238,17 @@ var ( // // It is not a valid Type. type Member struct { - Name + Name string Type Type - // Offset is the bit offset of this member - Offset uint32 + // OffsetBits is the bit offset of this member. + OffsetBits uint32 BitfieldSize uint32 } // Enum lists possible values. type Enum struct { TypeID - Name + Name string Values []EnumValue } @@ -254,11 +256,13 @@ func (e *Enum) String() string { return fmt.Sprintf("enum#%d[%q]", e.TypeID, e.Name) } +func (e *Enum) TypeName() string { return e.Name } + // EnumValue is part of an Enum // // Is is not a valid Type type EnumValue struct { - Name + Name string Value int32 } @@ -294,7 +298,7 @@ func (fk FwdKind) String() string { // Fwd is a forward declaration of a Type. type Fwd struct { TypeID - Name + Name string Kind FwdKind } @@ -302,6 +306,8 @@ func (f *Fwd) String() string { return fmt.Sprintf("fwd#%d[%s %q]", f.TypeID, f.Kind, f.Name) } +func (f *Fwd) TypeName() string { return f.Name } + func (f *Fwd) walk(*typeDeque) {} func (f *Fwd) copy() Type { cpy := *f @@ -311,7 +317,7 @@ func (f *Fwd) copy() Type { // Typedef is an alias of a Type. type Typedef struct { TypeID - Name + Name string Type Type } @@ -319,6 +325,8 @@ func (td *Typedef) String() string { return fmt.Sprintf("typedef#%d[%q #%d]", td.TypeID, td.Name, td.Type.ID()) } +func (td *Typedef) TypeName() string { return td.Name } + func (td *Typedef) walk(tdq *typeDeque) { tdq.push(&td.Type) } func (td *Typedef) copy() Type { cpy := *td @@ -379,7 +387,7 @@ func (r *Restrict) copy() Type { // Func is a function definition. type Func struct { TypeID - Name + Name string Type Type Linkage FuncLinkage } @@ -388,6 +396,8 @@ func (f *Func) String() string { return fmt.Sprintf("func#%d[%s %q proto=#%d]", f.TypeID, f.Linkage, f.Name, f.Type.ID()) } +func (f *Func) TypeName() string { return f.Name } + func (f *Func) walk(tdq *typeDeque) { tdq.push(&f.Type) } func (f *Func) copy() Type { cpy := *f @@ -426,14 +436,14 @@ func (fp *FuncProto) copy() Type { } type FuncParam struct { - Name + Name string Type Type } // Var is a global variable. type Var struct { TypeID - Name + Name string Type Type Linkage VarLinkage } @@ -442,6 +452,8 @@ func (v *Var) String() string { return fmt.Sprintf("var#%d[%s %q]", v.TypeID, v.Linkage, v.Name) } +func (v *Var) TypeName() string { return v.Name } + func (v *Var) walk(tdq *typeDeque) { tdq.push(&v.Type) } func (v *Var) copy() Type { cpy := *v @@ -451,7 +463,7 @@ func (v *Var) copy() Type { // Datasec is a global program section containing data. type Datasec struct { TypeID - Name + Name string Size uint32 Vars []VarSecinfo } @@ -460,6 +472,8 @@ func (ds *Datasec) String() string { return fmt.Sprintf("section#%d[%q]", ds.TypeID, ds.Name) } +func (ds *Datasec) TypeName() string { return ds.Name } + func (ds *Datasec) size() uint32 { return ds.Size } func (ds *Datasec) walk(tdq *typeDeque) { @@ -475,7 +489,7 @@ func (ds *Datasec) copy() Type { return &cpy } -// VarSecinfo describes variable in a Datasec +// VarSecinfo describes variable in a Datasec. // // It is not a valid Type. type VarSecinfo struct { @@ -484,6 +498,27 @@ type VarSecinfo struct { Size uint32 } +// Float is a float of a given length. +type Float struct { + TypeID + Name string + + // The size of the float in bytes. + Size uint32 +} + +func (f *Float) String() string { + return fmt.Sprintf("float%d#%d[%q]", f.Size*8, f.TypeID, f.Name) +} + +func (f *Float) TypeName() string { return f.Name } +func (f *Float) size() uint32 { return f.Size } +func (f *Float) walk(*typeDeque) {} +func (f *Float) copy() Type { + cpy := *f + return &cpy +} + type sizer interface { size() uint32 } @@ -565,14 +600,36 @@ func Sizeof(typ Type) (int, error) { // // Returns any errors from transform verbatim. func copyType(typ Type, transform func(Type) (Type, error)) (Type, error) { - var ( - copies = make(map[Type]Type) - work typeDeque - ) + copies := make(copier) + return typ, copies.copy(&typ, transform) +} - for t := &typ; t != nil; t = work.pop() { +// copy a slice of Types recursively. +// +// Types may form a cycle. +// +// Returns any errors from transform verbatim. +func copyTypes(types []Type, transform func(Type) (Type, error)) ([]Type, error) { + result := make([]Type, len(types)) + copy(result, types) + + copies := make(copier) + for i := range result { + if err := copies.copy(&result[i], transform); err != nil { + return nil, err + } + } + + return result, nil +} + +type copier map[Type]Type + +func (c copier) copy(typ *Type, transform func(Type) (Type, error)) error { + var work typeDeque + for t := typ; t != nil; t = work.pop() { // *t is the identity of the type. - if cpy := copies[*t]; cpy != nil { + if cpy := c[*t]; cpy != nil { *t = cpy continue } @@ -581,21 +638,21 @@ func copyType(typ Type, transform func(Type) (Type, error)) (Type, error) { if transform != nil { tf, err := transform(*t) if err != nil { - return nil, fmt.Errorf("copy %s: %w", typ, err) + return fmt.Errorf("copy %s: %w", *t, err) } cpy = tf.copy() } else { cpy = (*t).copy() } - copies[*t] = cpy + c[*t] = cpy *t = cpy // Mark any nested types for copying. cpy.walk(&work) } - return typ, nil + return nil } // typeDeque keeps track of pointers to types which still @@ -606,6 +663,10 @@ type typeDeque struct { mask uint64 } +func (dq *typeDeque) empty() bool { + return dq.read == dq.write +} + // push adds a type to the stack. func (dq *typeDeque) push(t *Type) { if dq.write-dq.read < uint64(len(dq.types)) { @@ -632,7 +693,7 @@ func (dq *typeDeque) push(t *Type) { // shift returns the first element or null. func (dq *typeDeque) shift() *Type { - if dq.read == dq.write { + if dq.empty() { return nil } @@ -645,7 +706,7 @@ func (dq *typeDeque) shift() *Type { // pop returns the last element or null. func (dq *typeDeque) pop() *Type { - if dq.read == dq.write { + if dq.empty() { return nil } @@ -674,7 +735,7 @@ func (dq *typeDeque) all() []*Type { // Returns a map of named types (so, where NameOff is non-zero) and a slice of types // indexed by TypeID. Since BTF ignores compilation units, multiple types may share // the same name. A Type may form a cyclic graph by pointing at itself. -func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type, namedTypes map[string][]namedType, err error) { +func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type, namedTypes map[string][]NamedType, err error) { type fixupDef struct { id TypeID expectedKind btfKind @@ -691,17 +752,17 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type, // work, since otherwise append might re-allocate members. members := make([]Member, 0, len(raw)) for i, btfMember := range raw { - name, err := rawStrings.LookupName(btfMember.NameOff) + name, err := rawStrings.Lookup(btfMember.NameOff) if err != nil { return nil, fmt.Errorf("can't get name for member %d: %w", i, err) } m := Member{ - Name: name, - Offset: btfMember.Offset, + Name: name, + OffsetBits: btfMember.Offset, } if kindFlag { m.BitfieldSize = btfMember.Offset >> 24 - m.Offset &= 0xffffff + m.OffsetBits &= 0xffffff } members = append(members, m) } @@ -713,7 +774,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type, types = make([]Type, 0, len(rawTypes)) types = append(types, (*Void)(nil)) - namedTypes = make(map[string][]namedType) + namedTypes = make(map[string][]NamedType) for i, raw := range rawTypes { var ( @@ -723,7 +784,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type, typ Type ) - name, err := rawStrings.LookupName(raw.NameOff) + name, err := rawStrings.Lookup(raw.NameOff) if err != nil { return nil, nil, fmt.Errorf("get name for type id %d: %w", id, err) } @@ -765,7 +826,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type, rawvals := raw.data.([]btfEnum) vals := make([]EnumValue, 0, len(rawvals)) for i, btfVal := range rawvals { - name, err := rawStrings.LookupName(btfVal.NameOff) + name, err := rawStrings.Lookup(btfVal.NameOff) if err != nil { return nil, nil, fmt.Errorf("get name for enum value %d: %s", i, err) } @@ -812,7 +873,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type, rawparams := raw.data.([]btfParam) params := make([]FuncParam, 0, len(rawparams)) for i, param := range rawparams { - name, err := rawStrings.LookupName(param.NameOff) + name, err := rawStrings.Lookup(param.NameOff) if err != nil { return nil, nil, fmt.Errorf("get name for func proto parameter %d: %s", i, err) } @@ -848,14 +909,17 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type, } typ = &Datasec{id, name, raw.SizeType, vars} + case kindFloat: + typ = &Float{id, name, raw.Size()} + default: return nil, nil, fmt.Errorf("type id %d: unknown kind: %v", id, raw.Kind()) } types = append(types, typ) - if named, ok := typ.(namedType); ok { - if name := essentialName(named.name()); name != "" { + if named, ok := typ.(NamedType); ok { + if name := essentialName(named.TypeName()); name != "" { namedTypes[name] = append(namedTypes[name], named) } } diff --git a/vendor/github.com/cilium/ebpf/internal/cpu.go b/vendor/github.com/cilium/ebpf/internal/cpu.go index d3424ba4345d1..3affa1efb9dbb 100644 --- a/vendor/github.com/cilium/ebpf/internal/cpu.go +++ b/vendor/github.com/cilium/ebpf/internal/cpu.go @@ -2,7 +2,7 @@ package internal import ( "fmt" - "io/ioutil" + "os" "strings" "sync" ) @@ -24,7 +24,7 @@ func PossibleCPUs() (int, error) { } func parseCPUsFromFile(path string) (int, error) { - spec, err := ioutil.ReadFile(path) + spec, err := os.ReadFile(path) if err != nil { return 0, err } diff --git a/vendor/github.com/cilium/ebpf/internal/ptr_32_be.go b/vendor/github.com/cilium/ebpf/internal/ptr_32_be.go index a56fbcc8e01b2..8c114ddf4763b 100644 --- a/vendor/github.com/cilium/ebpf/internal/ptr_32_be.go +++ b/vendor/github.com/cilium/ebpf/internal/ptr_32_be.go @@ -1,3 +1,4 @@ +//go:build armbe || mips || mips64p32 // +build armbe mips mips64p32 package internal diff --git a/vendor/github.com/cilium/ebpf/internal/ptr_32_le.go b/vendor/github.com/cilium/ebpf/internal/ptr_32_le.go index be2ecfca7313f..e65a61e45d34b 100644 --- a/vendor/github.com/cilium/ebpf/internal/ptr_32_le.go +++ b/vendor/github.com/cilium/ebpf/internal/ptr_32_le.go @@ -1,3 +1,4 @@ +//go:build 386 || amd64p32 || arm || mipsle || mips64p32le // +build 386 amd64p32 arm mipsle mips64p32le package internal diff --git a/vendor/github.com/cilium/ebpf/internal/ptr_64.go b/vendor/github.com/cilium/ebpf/internal/ptr_64.go index 69452dceb9a03..71a3afe307b35 100644 --- a/vendor/github.com/cilium/ebpf/internal/ptr_64.go +++ b/vendor/github.com/cilium/ebpf/internal/ptr_64.go @@ -1,5 +1,5 @@ -// +build !386,!amd64p32,!arm,!mipsle,!mips64p32le -// +build !armbe,!mips,!mips64p32 +//go:build !386 && !amd64p32 && !arm && !mipsle && !mips64p32le && !armbe && !mips && !mips64p32 +// +build !386,!amd64p32,!arm,!mipsle,!mips64p32le,!armbe,!mips,!mips64p32 package internal diff --git a/vendor/github.com/cilium/ebpf/internal/syscall.go b/vendor/github.com/cilium/ebpf/internal/syscall.go index b766e643e07af..b75037bb9d68e 100644 --- a/vendor/github.com/cilium/ebpf/internal/syscall.go +++ b/vendor/github.com/cilium/ebpf/internal/syscall.go @@ -1,6 +1,7 @@ package internal import ( + "errors" "fmt" "path/filepath" "runtime" @@ -68,6 +69,48 @@ func BPF(cmd BPFCmd, attr unsafe.Pointer, size uintptr) (uintptr, error) { return r1, err } +type BPFProgLoadAttr struct { + ProgType uint32 + InsCount uint32 + Instructions Pointer + License Pointer + LogLevel uint32 + LogSize uint32 + LogBuf Pointer + KernelVersion uint32 // since 4.1 2541517c32be + ProgFlags uint32 // since 4.11 e07b98d9bffe + ProgName BPFObjName // since 4.15 067cae47771c + ProgIfIndex uint32 // since 4.15 1f6f4cb7ba21 + ExpectedAttachType uint32 // since 4.17 5e43f899b03a + ProgBTFFd uint32 + FuncInfoRecSize uint32 + FuncInfo Pointer + FuncInfoCnt uint32 + LineInfoRecSize uint32 + LineInfo Pointer + LineInfoCnt uint32 + AttachBTFID uint32 + AttachProgFd uint32 +} + +// BPFProgLoad wraps BPF_PROG_LOAD. +func BPFProgLoad(attr *BPFProgLoadAttr) (*FD, error) { + for { + fd, err := BPF(BPF_PROG_LOAD, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + // As of ~4.20 the verifier can be interrupted by a signal, + // and returns EAGAIN in that case. + if errors.Is(err, unix.EAGAIN) { + continue + } + + if err != nil { + return nil, err + } + + return NewFD(uint32(fd)), nil + } +} + type BPFProgAttachAttr struct { TargetFd uint32 AttachBpfFd uint32 @@ -180,6 +223,22 @@ func BPFObjGetInfoByFD(fd *FD, info unsafe.Pointer, size uintptr) error { return nil } +type bpfGetFDByIDAttr struct { + id uint32 + next uint32 +} + +// BPFObjGetInfoByFD wraps BPF_*_GET_FD_BY_ID. +// +// Available from 4.13. +func BPFObjGetFDByID(cmd BPFCmd, id uint32) (*FD, error) { + attr := bpfGetFDByIDAttr{ + id: id, + } + ptr, err := BPF(cmd, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + return NewFD(uint32(ptr)), err +} + // BPFObjName is a null-terminated string made up of // 'A-Za-z0-9_' characters. type BPFObjName [unix.BPF_OBJ_NAME_LEN]byte diff --git a/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go b/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go index 0a18eaf0cf84d..9aa70fa78c2a9 100644 --- a/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go +++ b/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux package unix @@ -20,10 +21,11 @@ const ( EPERM = linux.EPERM ESRCH = linux.ESRCH ENODEV = linux.ENODEV + EBADF = linux.EBADF + E2BIG = linux.E2BIG // ENOTSUPP is not the same as ENOTSUP or EOPNOTSUP ENOTSUPP = syscall.Errno(0x20c) - EBADF = linux.EBADF BPF_F_NO_PREALLOC = linux.BPF_F_NO_PREALLOC BPF_F_NUMA_NODE = linux.BPF_F_NUMA_NODE BPF_F_RDONLY = linux.BPF_F_RDONLY @@ -35,6 +37,9 @@ const ( BPF_F_INNER_MAP = linux.BPF_F_INNER_MAP BPF_OBJ_NAME_LEN = linux.BPF_OBJ_NAME_LEN BPF_TAG_SIZE = linux.BPF_TAG_SIZE + BPF_RINGBUF_BUSY_BIT = linux.BPF_RINGBUF_BUSY_BIT + BPF_RINGBUF_DISCARD_BIT = linux.BPF_RINGBUF_DISCARD_BIT + BPF_RINGBUF_HDR_SZ = linux.BPF_RINGBUF_HDR_SZ SYS_BPF = linux.SYS_BPF F_DUPFD_CLOEXEC = linux.F_DUPFD_CLOEXEC EPOLL_CTL_ADD = linux.EPOLL_CTL_ADD @@ -69,11 +74,6 @@ type Statfs_t = linux.Statfs_t // Rlimit is a wrapper type Rlimit = linux.Rlimit -// Setrlimit is a wrapper -func Setrlimit(resource int, rlim *Rlimit) (err error) { - return linux.Setrlimit(resource, rlim) -} - // Syscall is a wrapper func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { return linux.Syscall(trap, a1, a2, a3) @@ -202,3 +202,7 @@ func KernelRelease() (string, error) { release := string(uname.Release[:end]) return release, nil } + +func Prlimit(pid, resource int, new, old *Rlimit) error { + return linux.Prlimit(pid, resource, new, old) +} diff --git a/vendor/github.com/cilium/ebpf/internal/unix/types_other.go b/vendor/github.com/cilium/ebpf/internal/unix/types_other.go index 1b06defc0a095..4f50d896ebb88 100644 --- a/vendor/github.com/cilium/ebpf/internal/unix/types_other.go +++ b/vendor/github.com/cilium/ebpf/internal/unix/types_other.go @@ -1,3 +1,4 @@ +//go:build !linux // +build !linux package unix @@ -21,6 +22,7 @@ const ( ESRCH = syscall.ESRCH ENODEV = syscall.ENODEV EBADF = syscall.Errno(0) + E2BIG = syscall.Errno(0) // ENOTSUPP is not the same as ENOTSUP or EOPNOTSUP ENOTSUPP = syscall.Errno(0x20c) @@ -35,6 +37,9 @@ const ( BPF_F_INNER_MAP = 0 BPF_OBJ_NAME_LEN = 0x10 BPF_TAG_SIZE = 0x8 + BPF_RINGBUF_BUSY_BIT = 0 + BPF_RINGBUF_DISCARD_BIT = 0 + BPF_RINGBUF_HDR_SZ = 0 SYS_BPF = 321 F_DUPFD_CLOEXEC = 0x406 EPOLLIN = 0x1 @@ -86,11 +91,6 @@ type Rlimit struct { Max uint64 } -// Setrlimit is a wrapper -func Setrlimit(resource int, rlim *Rlimit) (err error) { - return errNonLinux -} - // Syscall is a wrapper func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { return 0, 0, syscall.Errno(1) @@ -261,3 +261,7 @@ func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags func KernelRelease() (string, error) { return "", errNonLinux } + +func Prlimit(pid, resource int, new, old *Rlimit) error { + return errNonLinux +} diff --git a/vendor/github.com/cilium/ebpf/internal/version.go b/vendor/github.com/cilium/ebpf/internal/version.go index 1a678bfe65749..4915e583767a9 100644 --- a/vendor/github.com/cilium/ebpf/internal/version.go +++ b/vendor/github.com/cilium/ebpf/internal/version.go @@ -2,7 +2,7 @@ package internal import ( "fmt" - "io/ioutil" + "os" "regexp" "sync" @@ -109,7 +109,7 @@ func detectKernelVersion() (Version, error) { // Example format: Ubuntu 4.15.0-91.92-generic 4.15.18 // This method exists in the kernel itself, see d18acd15c // ("perf tools: Fix kernel version error in ubuntu"). - if pvs, err := ioutil.ReadFile("/proc/version_signature"); err == nil { + if pvs, err := os.ReadFile("/proc/version_signature"); err == nil { // If /proc/version_signature exists, failing to parse it is an error. // It only exists on Ubuntu, where the real patch level is not obtainable // through any other method. diff --git a/vendor/github.com/cilium/ebpf/link/freplace.go b/vendor/github.com/cilium/ebpf/link/freplace.go new file mode 100644 index 0000000000000..a698e1a9d30cb --- /dev/null +++ b/vendor/github.com/cilium/ebpf/link/freplace.go @@ -0,0 +1,88 @@ +package link + +import ( + "fmt" + + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/internal/btf" +) + +type FreplaceLink struct { + RawLink +} + +// AttachFreplace attaches the given eBPF program to the function it replaces. +// +// The program and name can either be provided at link time, or can be provided +// at program load time. If they were provided at load time, they should be nil +// and empty respectively here, as they will be ignored by the kernel. +// Examples: +// +// AttachFreplace(dispatcher, "function", replacement) +// AttachFreplace(nil, "", replacement) +func AttachFreplace(targetProg *ebpf.Program, name string, prog *ebpf.Program) (*FreplaceLink, error) { + if (name == "") != (targetProg == nil) { + return nil, fmt.Errorf("must provide both or neither of name and targetProg: %w", errInvalidInput) + } + if prog == nil { + return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput) + } + if prog.Type() != ebpf.Extension { + return nil, fmt.Errorf("eBPF program type %s is not an Extension: %w", prog.Type(), errInvalidInput) + } + + var ( + target int + typeID btf.TypeID + ) + if targetProg != nil { + info, err := targetProg.Info() + if err != nil { + return nil, err + } + btfID, ok := info.BTFID() + if !ok { + return nil, fmt.Errorf("could not get BTF ID for program %s: %w", info.Name, errInvalidInput) + } + btfHandle, err := btf.NewHandleFromID(btfID) + if err != nil { + return nil, err + } + defer btfHandle.Close() + + var function *btf.Func + if err := btfHandle.Spec().FindType(name, &function); err != nil { + return nil, err + } + + target = targetProg.FD() + typeID = function.ID() + } + + link, err := AttachRawLink(RawLinkOptions{ + Target: target, + Program: prog, + Attach: ebpf.AttachNone, + BTF: typeID, + }) + if err != nil { + return nil, err + } + + return &FreplaceLink{*link}, nil +} + +// Update implements the Link interface. +func (f *FreplaceLink) Update(new *ebpf.Program) error { + return fmt.Errorf("freplace update: %w", ErrNotSupported) +} + +// LoadPinnedFreplace loads a pinned iterator from a bpffs. +func LoadPinnedFreplace(fileName string, opts *ebpf.LoadPinOptions) (*FreplaceLink, error) { + link, err := LoadPinnedRawLink(fileName, TracingType, opts) + if err != nil { + return nil, err + } + + return &FreplaceLink{*link}, err +} diff --git a/vendor/github.com/cilium/ebpf/link/kprobe.go b/vendor/github.com/cilium/ebpf/link/kprobe.go index ea71d6d608a82..b6577b5a9925c 100644 --- a/vendor/github.com/cilium/ebpf/link/kprobe.go +++ b/vendor/github.com/cilium/ebpf/link/kprobe.go @@ -5,7 +5,6 @@ import ( "crypto/rand" "errors" "fmt" - "io/ioutil" "os" "path/filepath" "runtime" @@ -72,10 +71,11 @@ func (pt probeType) RetprobeBit() (uint64, error) { // given kernel symbol starts executing. See /proc/kallsyms for available // symbols. For example, printk(): // -// Kprobe("printk", prog) +// kp, err := Kprobe("printk", prog) // -// The resulting Link must be Closed during program shutdown to avoid leaking -// system resources. +// Losing the reference to the resulting Link (kp) will close the Kprobe +// and prevent further execution of prog. The Link must be Closed during +// program shutdown to avoid leaking system resources. func Kprobe(symbol string, prog *ebpf.Program) (Link, error) { k, err := kprobe(symbol, prog, false) if err != nil { @@ -95,10 +95,11 @@ func Kprobe(symbol string, prog *ebpf.Program) (Link, error) { // before the given kernel symbol exits, with the function stack left intact. // See /proc/kallsyms for available symbols. For example, printk(): // -// Kretprobe("printk", prog) +// kp, err := Kretprobe("printk", prog) // -// The resulting Link must be Closed during program shutdown to avoid leaking -// system resources. +// Losing the reference to the resulting Link (kp) will close the Kretprobe +// and prevent further execution of prog. The Link must be Closed during +// program shutdown to avoid leaking system resources. func Kretprobe(symbol string, prog *ebpf.Program) (Link, error) { k, err := kprobe(symbol, prog, true) if err != nil { @@ -157,7 +158,7 @@ func kprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) { // pmuKprobe opens a perf event based on the kprobe PMU. // Returns os.ErrNotExist if the given symbol does not exist in the kernel. func pmuKprobe(symbol string, ret bool) (*perfEvent, error) { - return pmuProbe(kprobeType, symbol, "", 0, ret) + return pmuProbe(kprobeType, symbol, "", 0, perfAllThreads, ret) } // pmuProbe opens a perf event based on a Performance Monitoring Unit. @@ -167,7 +168,7 @@ func pmuKprobe(symbol string, ret bool) (*perfEvent, error) { // 33ea4b24277b "perf/core: Implement the 'perf_uprobe' PMU" // // Returns ErrNotSupported if the kernel doesn't support perf_[k,u]probe PMU -func pmuProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*perfEvent, error) { +func pmuProbe(typ probeType, symbol, path string, offset uint64, pid int, ret bool) (*perfEvent, error) { // Getting the PMU type will fail if the kernel doesn't support // the perf_[k,u]probe PMU. et, err := getPMUEventType(typ) @@ -191,7 +192,7 @@ func pmuProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*per switch typ { case kprobeType: // Create a pointer to a NUL-terminated string for the kernel. - sp, err := unsafeStringPtr(symbol) + sp, err = unsafeStringPtr(symbol) if err != nil { return nil, err } @@ -202,7 +203,7 @@ func pmuProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*per Config: config, // Retprobe flag } case uprobeType: - sp, err := unsafeStringPtr(path) + sp, err = unsafeStringPtr(path) if err != nil { return nil, err } @@ -220,7 +221,7 @@ func pmuProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*per } } - fd, err := unix.PerfEventOpen(&attr, perfAllThreads, 0, -1, unix.PERF_FLAG_FD_CLOEXEC) + fd, err := unix.PerfEventOpen(&attr, pid, 0, -1, unix.PERF_FLAG_FD_CLOEXEC) // Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL // when trying to create a kretprobe for a missing symbol. Make sure ENOENT @@ -228,6 +229,11 @@ func pmuProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*per if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) { return nil, fmt.Errorf("symbol '%s' not found: %w", symbol, os.ErrNotExist) } + // Since at least commit cb9a19fe4aa51, ENOTSUPP is returned + // when attempting to set a uprobe on a trap instruction. + if errors.Is(err, unix.ENOTSUPP) { + return nil, fmt.Errorf("failed setting uprobe on offset %#x (possible trap insn): %w", offset, err) + } if err != nil { return nil, fmt.Errorf("opening perf event: %w", err) } @@ -246,7 +252,7 @@ func pmuProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*per // tracefsKprobe creates a Kprobe tracefs entry. func tracefsKprobe(symbol string, ret bool) (*perfEvent, error) { - return tracefsProbe(kprobeType, symbol, "", 0, ret) + return tracefsProbe(kprobeType, symbol, "", 0, perfAllThreads, ret) } // tracefsProbe creates a trace event by writing an entry to /[k,u]probe_events. @@ -255,7 +261,7 @@ func tracefsKprobe(symbol string, ret bool) (*perfEvent, error) { // Path and offset are only set in the case of uprobe(s) and are used to set // the executable/library path on the filesystem and the offset where the probe is inserted. // A perf event is then opened on the newly-created trace event and returned to the caller. -func tracefsProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*perfEvent, error) { +func tracefsProbe(typ probeType, symbol, path string, offset uint64, pid int, ret bool) (*perfEvent, error) { // Generate a random string for each trace event we attempt to create. // This value is used as the 'group' token in tracefs to allow creating // multiple kprobe trace events with the same name. @@ -288,7 +294,7 @@ func tracefsProbe(typ probeType, symbol, path string, offset uint64, ret bool) ( } // Kprobes are ephemeral tracepoints and share the same perf event type. - fd, err := openTracepointPerfEvent(tid) + fd, err := openTracepointPerfEvent(tid, pid) if err != nil { return nil, err } @@ -413,7 +419,7 @@ func probePrefix(ret bool) string { func determineRetprobeBit(typ probeType) (uint64, error) { p := filepath.Join("/sys/bus/event_source/devices/", typ.String(), "/format/retprobe") - data, err := ioutil.ReadFile(p) + data, err := os.ReadFile(p) if err != nil { return 0, err } diff --git a/vendor/github.com/cilium/ebpf/link/link.go b/vendor/github.com/cilium/ebpf/link/link.go index 16cfff415dd40..4926584696bb9 100644 --- a/vendor/github.com/cilium/ebpf/link/link.go +++ b/vendor/github.com/cilium/ebpf/link/link.go @@ -6,6 +6,7 @@ import ( "github.com/cilium/ebpf" "github.com/cilium/ebpf/internal" + "github.com/cilium/ebpf/internal/btf" ) var ErrNotSupported = internal.ErrNotSupported @@ -29,8 +30,8 @@ type Link interface { // Close frees resources. // - // The link will be broken unless it has been pinned. A link - // may continue past the lifetime of the process if Close is + // The link will be broken unless it has been successfully pinned. + // A link may continue past the lifetime of the process if Close is // not called. Close() error @@ -49,6 +50,8 @@ type RawLinkOptions struct { Program *ebpf.Program // Attach must match the attach type of Program. Attach ebpf.AttachType + // BTF is the BTF of the attachment target. + BTF btf.TypeID } // RawLinkInfo contains metadata on a link. @@ -83,9 +86,10 @@ func AttachRawLink(opts RawLinkOptions) (*RawLink, error) { } attr := bpfLinkCreateAttr{ - targetFd: uint32(opts.Target), - progFd: uint32(progFd), - attachType: opts.Attach, + targetFd: uint32(opts.Target), + progFd: uint32(progFd), + attachType: opts.Attach, + targetBTFID: uint32(opts.BTF), } fd, err := bpfLinkCreate(&attr) if err != nil { diff --git a/vendor/github.com/cilium/ebpf/link/perf_event.go b/vendor/github.com/cilium/ebpf/link/perf_event.go index 5267a47ec9bbd..7e0443a75cb0b 100644 --- a/vendor/github.com/cilium/ebpf/link/perf_event.go +++ b/vendor/github.com/cilium/ebpf/link/perf_event.go @@ -4,7 +4,6 @@ import ( "bytes" "errors" "fmt" - "io/ioutil" "os" "path/filepath" "regexp" @@ -236,7 +235,7 @@ func getPMUEventType(typ probeType) (uint64, error) { // openTracepointPerfEvent opens a tracepoint-type perf event. System-wide // [k,u]probes created by writing to /[k,u]probe_events are tracepoints // behind the scenes, and can be attached to using these perf events. -func openTracepointPerfEvent(tid uint64) (*internal.FD, error) { +func openTracepointPerfEvent(tid uint64, pid int) (*internal.FD, error) { attr := unix.PerfEventAttr{ Type: unix.PERF_TYPE_TRACEPOINT, Config: tid, @@ -245,7 +244,7 @@ func openTracepointPerfEvent(tid uint64) (*internal.FD, error) { Wakeup: 1, } - fd, err := unix.PerfEventOpen(&attr, perfAllThreads, 0, -1, unix.PERF_FLAG_FD_CLOEXEC) + fd, err := unix.PerfEventOpen(&attr, pid, 0, -1, unix.PERF_FLAG_FD_CLOEXEC) if err != nil { return nil, fmt.Errorf("opening tracepoint perf event: %w", err) } @@ -263,7 +262,7 @@ func uint64FromFile(base string, path ...string) (uint64, error) { return 0, fmt.Errorf("path '%s' attempts to escape base path '%s': %w", l, base, errInvalidInput) } - data, err := ioutil.ReadFile(p) + data, err := os.ReadFile(p) if err != nil { return 0, fmt.Errorf("reading file %s: %w", p, err) } diff --git a/vendor/github.com/cilium/ebpf/link/syscalls.go b/vendor/github.com/cilium/ebpf/link/syscalls.go index 30e8a88050723..a61499438b220 100644 --- a/vendor/github.com/cilium/ebpf/link/syscalls.go +++ b/vendor/github.com/cilium/ebpf/link/syscalls.go @@ -88,10 +88,11 @@ var haveProgAttachReplace = internal.FeatureTest("BPF_PROG_ATTACH atomic replace }) type bpfLinkCreateAttr struct { - progFd uint32 - targetFd uint32 - attachType ebpf.AttachType - flags uint32 + progFd uint32 + targetFd uint32 + attachType ebpf.AttachType + flags uint32 + targetBTFID uint32 } func bpfLinkCreate(attr *bpfLinkCreateAttr) (*internal.FD, error) { diff --git a/vendor/github.com/cilium/ebpf/link/tracepoint.go b/vendor/github.com/cilium/ebpf/link/tracepoint.go index b8ae04bf0a058..7423df86b137d 100644 --- a/vendor/github.com/cilium/ebpf/link/tracepoint.go +++ b/vendor/github.com/cilium/ebpf/link/tracepoint.go @@ -11,7 +11,11 @@ import ( // tracepoints. The top-level directory is the group, the event's subdirectory // is the name. Example: // -// Tracepoint("syscalls", "sys_enter_fork", prog) +// tp, err := Tracepoint("syscalls", "sys_enter_fork", prog) +// +// Losing the reference to the resulting Link (tp) will close the Tracepoint +// and prevent further execution of prog. The Link must be Closed during +// program shutdown to avoid leaking system resources. // // Note that attaching eBPF programs to syscalls (sys_enter_*/sys_exit_*) is // only possible as of kernel 4.14 (commit cf5f5ce). @@ -34,7 +38,7 @@ func Tracepoint(group, name string, prog *ebpf.Program) (Link, error) { return nil, err } - fd, err := openTracepointPerfEvent(tid) + fd, err := openTracepointPerfEvent(tid, perfAllThreads) if err != nil { return nil, err } diff --git a/vendor/github.com/cilium/ebpf/link/uprobe.go b/vendor/github.com/cilium/ebpf/link/uprobe.go index 2bc395ee3cd2e..59170ce0468d2 100644 --- a/vendor/github.com/cilium/ebpf/link/uprobe.go +++ b/vendor/github.com/cilium/ebpf/link/uprobe.go @@ -25,14 +25,18 @@ var ( value uint64 err error }{} + + // ErrNoSymbol indicates that the given symbol was not found + // in the ELF symbols table. + ErrNoSymbol = errors.New("not found") ) // Executable defines an executable program on the filesystem. type Executable struct { // Path of the executable on the filesystem. path string - // Parsed ELF symbols and dynamic symbols. - symbols map[string]elf.Symbol + // Parsed ELF symbols and dynamic symbols offsets. + offsets map[string]uint64 } // UprobeOptions defines additional parameters that will be used @@ -41,6 +45,9 @@ type UprobeOptions struct { // Symbol offset. Must be provided in case of external symbols (shared libs). // If set, overrides the offset eventually parsed from the executable. Offset uint64 + // Only set the uprobe on the given process ID. Useful when tracing + // shared library calls or programs that have many running instances. + PID int } // To open a new Executable, use: @@ -64,42 +71,84 @@ func OpenExecutable(path string) (*Executable, error) { return nil, fmt.Errorf("parse ELF file: %w", err) } - var ex = Executable{ - path: path, - symbols: make(map[string]elf.Symbol), + if se.Type != elf.ET_EXEC && se.Type != elf.ET_DYN { + // ELF is not an executable or a shared object. + return nil, errors.New("the given file is not an executable or a shared object") } - if err := ex.addSymbols(se.Symbols); err != nil { - return nil, err + + ex := Executable{ + path: path, + offsets: make(map[string]uint64), } - if err := ex.addSymbols(se.DynamicSymbols); err != nil { + if err := ex.load(se); err != nil { return nil, err } return &ex, nil } -func (ex *Executable) addSymbols(f func() ([]elf.Symbol, error)) error { - // elf.Symbols and elf.DynamicSymbols return ErrNoSymbols if the section is not found. - syms, err := f() +func (ex *Executable) load(f *internal.SafeELFFile) error { + syms, err := f.Symbols() if err != nil && !errors.Is(err, elf.ErrNoSymbols) { return err } + + dynsyms, err := f.DynamicSymbols() + if err != nil && !errors.Is(err, elf.ErrNoSymbols) { + return err + } + + syms = append(syms, dynsyms...) + for _, s := range syms { if elf.ST_TYPE(s.Info) != elf.STT_FUNC { // Symbol not associated with a function or other executable code. continue } - ex.symbols[s.Name] = s + + off := s.Value + + // Loop over ELF segments. + for _, prog := range f.Progs { + // Skip uninteresting segments. + if prog.Type != elf.PT_LOAD || (prog.Flags&elf.PF_X) == 0 { + continue + } + + if prog.Vaddr <= s.Value && s.Value < (prog.Vaddr+prog.Memsz) { + // If the symbol value is contained in the segment, calculate + // the symbol offset. + // + // fn symbol offset = fn symbol VA - .text VA + .text offset + // + // stackoverflow.com/a/40249502 + off = s.Value - prog.Vaddr + prog.Off + break + } + } + + ex.offsets[s.Name] = off } + return nil } -func (ex *Executable) symbol(symbol string) (*elf.Symbol, error) { - if s, ok := ex.symbols[symbol]; ok { - return &s, nil +func (ex *Executable) offset(symbol string) (uint64, error) { + if off, ok := ex.offsets[symbol]; ok { + // Symbols with location 0 from section undef are shared library calls and + // are relocated before the binary is executed. Dynamic linking is not + // implemented by the library, so mark this as unsupported for now. + // + // Since only offset values are stored and not elf.Symbol, if the value is 0, + // assume it's an external symbol. + if off == 0 { + return 0, fmt.Errorf("cannot resolve %s library call '%s', "+ + "consider providing the offset via options: %w", ex.path, symbol, ErrNotSupported) + } + return off, nil } - return nil, fmt.Errorf("symbol %s not found", symbol) + return 0, fmt.Errorf("symbol %s: %w", symbol, ErrNoSymbol) } // Uprobe attaches the given eBPF program to a perf event that fires when the @@ -112,11 +161,14 @@ func (ex *Executable) symbol(symbol string) (*elf.Symbol, error) { // When using symbols which belongs to shared libraries, // an offset must be provided via options: // -// ex.Uprobe("main", prog, &UprobeOptions{Offset: 0x123}) +// up, err := ex.Uprobe("main", prog, &UprobeOptions{Offset: 0x123}) +// +// Losing the reference to the resulting Link (up) will close the Uprobe +// and prevent further execution of prog. The Link must be Closed during +// program shutdown to avoid leaking system resources. // -// The resulting Link must be Closed during program shutdown to avoid leaking -// system resources. Functions provided by shared libraries can currently not -// be traced and will result in an ErrNotSupported. +// Functions provided by shared libraries can currently not be traced and +// will result in an ErrNotSupported. func (ex *Executable) Uprobe(symbol string, prog *ebpf.Program, opts *UprobeOptions) (Link, error) { u, err := ex.uprobe(symbol, prog, opts, false) if err != nil { @@ -141,11 +193,14 @@ func (ex *Executable) Uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti // When using symbols which belongs to shared libraries, // an offset must be provided via options: // -// ex.Uretprobe("main", prog, &UprobeOptions{Offset: 0x123}) +// up, err := ex.Uretprobe("main", prog, &UprobeOptions{Offset: 0x123}) +// +// Losing the reference to the resulting Link (up) will close the Uprobe +// and prevent further execution of prog. The Link must be Closed during +// program shutdown to avoid leaking system resources. // -// The resulting Link must be Closed during program shutdown to avoid leaking -// system resources. Functions provided by shared libraries can currently not -// be traced and will result in an ErrNotSupported. +// Functions provided by shared libraries can currently not be traced and +// will result in an ErrNotSupported. func (ex *Executable) Uretprobe(symbol string, prog *ebpf.Program, opts *UprobeOptions) (Link, error) { u, err := ex.uprobe(symbol, prog, opts, true) if err != nil { @@ -175,24 +230,20 @@ func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti if opts != nil && opts.Offset != 0 { offset = opts.Offset } else { - sym, err := ex.symbol(symbol) + off, err := ex.offset(symbol) if err != nil { - return nil, fmt.Errorf("symbol '%s' not found: %w", symbol, err) - } - - // Symbols with location 0 from section undef are shared library calls and - // are relocated before the binary is executed. Dynamic linking is not - // implemented by the library, so mark this as unsupported for now. - if sym.Section == elf.SHN_UNDEF && sym.Value == 0 { - return nil, fmt.Errorf("cannot resolve %s library call '%s', "+ - "consider providing the offset via options: %w", ex.path, symbol, ErrNotSupported) + return nil, err } + offset = off + } - offset = sym.Value + pid := perfAllThreads + if opts != nil && opts.PID != 0 { + pid = opts.PID } // Use uprobe PMU if the kernel has it available. - tp, err := pmuUprobe(symbol, ex.path, offset, ret) + tp, err := pmuUprobe(symbol, ex.path, offset, pid, ret) if err == nil { return tp, nil } @@ -201,7 +252,7 @@ func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti } // Use tracefs if uprobe PMU is missing. - tp, err = tracefsUprobe(uprobeSanitizedSymbol(symbol), ex.path, offset, ret) + tp, err = tracefsUprobe(uprobeSanitizedSymbol(symbol), ex.path, offset, pid, ret) if err != nil { return nil, fmt.Errorf("creating trace event '%s:%s' in tracefs: %w", ex.path, symbol, err) } @@ -210,13 +261,13 @@ func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti } // pmuUprobe opens a perf event based on the uprobe PMU. -func pmuUprobe(symbol, path string, offset uint64, ret bool) (*perfEvent, error) { - return pmuProbe(uprobeType, symbol, path, offset, ret) +func pmuUprobe(symbol, path string, offset uint64, pid int, ret bool) (*perfEvent, error) { + return pmuProbe(uprobeType, symbol, path, offset, pid, ret) } // tracefsUprobe creates a Uprobe tracefs entry. -func tracefsUprobe(symbol, path string, offset uint64, ret bool) (*perfEvent, error) { - return tracefsProbe(uprobeType, symbol, path, offset, ret) +func tracefsUprobe(symbol, path string, offset uint64, pid int, ret bool) (*perfEvent, error) { + return tracefsProbe(uprobeType, symbol, path, offset, pid, ret) } // uprobeSanitizedSymbol replaces every invalid characted for the tracefs api with an underscore. diff --git a/vendor/github.com/cilium/ebpf/linker.go b/vendor/github.com/cilium/ebpf/linker.go index 6c2efef9e42c8..f3b1629e70a88 100644 --- a/vendor/github.com/cilium/ebpf/linker.go +++ b/vendor/github.com/cilium/ebpf/linker.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/cilium/ebpf/asm" - "github.com/cilium/ebpf/internal/btf" ) // link resolves bpf-to-bpf calls. @@ -40,7 +39,7 @@ func link(prog *ProgramSpec, libs []*ProgramSpec) error { pending = append(pending, lib.Instructions) if prog.BTF != nil && lib.BTF != nil { - if err := btf.ProgramAppend(prog.BTF, lib.BTF); err != nil { + if err := prog.BTF.Append(lib.BTF); err != nil { return fmt.Errorf("linking BTF of %s: %w", lib.Name, err) } } @@ -136,5 +135,25 @@ func fixupJumpsAndCalls(insns asm.Instructions) error { } } + // fixupBPFCalls replaces bpf_probe_read_{kernel,user}[_str] with bpf_probe_read[_str] on older kernels + // https://github.com/libbpf/libbpf/blob/master/src/libbpf.c#L6009 + iter = insns.Iterate() + for iter.Next() { + ins := iter.Ins + if !ins.IsBuiltinCall() { + continue + } + switch asm.BuiltinFunc(ins.Constant) { + case asm.FnProbeReadKernel, asm.FnProbeReadUser: + if err := haveProbeReadKernel(); err != nil { + ins.Constant = int64(asm.FnProbeRead) + } + case asm.FnProbeReadKernelStr, asm.FnProbeReadUserStr: + if err := haveProbeReadKernel(); err != nil { + ins.Constant = int64(asm.FnProbeReadStr) + } + } + } + return nil } diff --git a/vendor/github.com/cilium/ebpf/map.go b/vendor/github.com/cilium/ebpf/map.go index f257d88c03e3c..cca387ead0192 100644 --- a/vendor/github.com/cilium/ebpf/map.go +++ b/vendor/github.com/cilium/ebpf/map.go @@ -1,6 +1,7 @@ package ebpf import ( + "bytes" "errors" "fmt" "io" @@ -65,6 +66,11 @@ type MapSpec struct { // InnerMap is used as a template for ArrayOfMaps and HashOfMaps InnerMap *MapSpec + // Extra trailing bytes found in the ELF map definition when using structs + // larger than libbpf's bpf_map_def. Must be empty before instantiating + // the MapSpec into a Map. + Extra bytes.Reader + // The BTF associated with this map. BTF *btf.Map } @@ -82,9 +88,12 @@ func (ms *MapSpec) Copy() *MapSpec { } cpy := *ms + cpy.Contents = make([]MapKV, len(ms.Contents)) copy(cpy.Contents, ms.Contents) + cpy.InnerMap = ms.InnerMap.Copy() + return &cpy } @@ -188,14 +197,24 @@ func NewMap(spec *MapSpec) (*Map, error) { // // The caller is responsible for ensuring the process' rlimit is set // sufficiently high for locking memory during map creation. This can be done -// by calling unix.Setrlimit with unix.RLIMIT_MEMLOCK prior to calling NewMapWithOptions. +// by calling rlimit.RemoveMemlock() prior to calling NewMapWithOptions. // // May return an error wrapping ErrMapIncompatible. func NewMapWithOptions(spec *MapSpec, opts MapOptions) (*Map, error) { handles := newHandleCache() defer handles.close() - return newMapWithOptions(spec, opts, handles) + m, err := newMapWithOptions(spec, opts, handles) + if err != nil { + return nil, fmt.Errorf("creating map: %w", err) + } + + err = m.finalize(spec) + if err != nil { + return nil, fmt.Errorf("populating map: %w", err) + } + + return m, nil } func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_ *Map, err error) { @@ -207,8 +226,12 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_ switch spec.Pinning { case PinByName: - if spec.Name == "" || opts.PinPath == "" { - return nil, fmt.Errorf("pin by name: missing Name or PinPath") + if spec.Name == "" { + return nil, fmt.Errorf("pin by name: missing Name") + } + + if opts.PinPath == "" { + return nil, fmt.Errorf("pin by name: missing MapOptions.PinPath") } path := filepath.Join(opts.PinPath, spec.Name) @@ -244,16 +267,19 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_ return nil, errors.New("inner maps cannot be pinned") } - template, err := createMap(spec.InnerMap, nil, opts, handles) + template, err := spec.InnerMap.createMap(nil, opts, handles) if err != nil { - return nil, err + return nil, fmt.Errorf("inner map: %w", err) } defer template.Close() + // Intentionally skip populating and freezing (finalizing) + // the inner map template since it will be removed shortly. + innerFd = template.fd } - m, err := createMap(spec, innerFd, opts, handles) + m, err := spec.createMap(innerFd, opts, handles) if err != nil { return nil, err } @@ -269,7 +295,9 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_ return m, nil } -func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *handleCache) (_ *Map, err error) { +// createMap validates the spec's properties and creates the map in the kernel +// using the given opts. It does not populate or freeze the map. +func (spec *MapSpec) createMap(inner *internal.FD, opts MapOptions, handles *handleCache) (_ *Map, err error) { closeOnError := func(closer io.Closer) { if err != nil { closer.Close() @@ -278,10 +306,16 @@ func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *hand spec = spec.Copy() + // Kernels 4.13 through 5.4 used a struct bpf_map_def that contained + // additional 'inner_map_idx' and later 'numa_node' fields. + // In order to support loading these definitions, tolerate the presence of + // extra bytes, but require them to be zeroes. + if _, err := io.Copy(internal.DiscardZeroes{}, &spec.Extra); err != nil { + return nil, errors.New("extra contains unhandled non-zero bytes, drain before creating map") + } + switch spec.Type { - case ArrayOfMaps: - fallthrough - case HashOfMaps: + case ArrayOfMaps, HashOfMaps: if err := haveNestedMaps(); err != nil { return nil, err } @@ -350,7 +384,7 @@ func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *hand var btfDisabled bool if spec.BTF != nil { - handle, err := handles.btfHandle(btf.MapSpec(spec.BTF)) + handle, err := handles.btfHandle(spec.BTF.Spec) btfDisabled = errors.Is(err, btf.ErrNotSupported) if err != nil && !btfDisabled { return nil, fmt.Errorf("load BTF: %w", err) @@ -358,15 +392,15 @@ func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *hand if handle != nil { attr.BTFFd = uint32(handle.FD()) - attr.BTFKeyTypeID = uint32(btf.MapKey(spec.BTF).ID()) - attr.BTFValueTypeID = uint32(btf.MapValue(spec.BTF).ID()) + attr.BTFKeyTypeID = uint32(spec.BTF.Key.ID()) + attr.BTFValueTypeID = uint32(spec.BTF.Value.ID()) } } fd, err := internal.BPFMapCreate(&attr) if err != nil { if errors.Is(err, unix.EPERM) { - return nil, fmt.Errorf("map create: RLIMIT_MEMLOCK may be too low: %w", err) + return nil, fmt.Errorf("map create: %w (MEMLOCK bay be too low, consider rlimit.RemoveMemlock)", err) } if btfDisabled { return nil, fmt.Errorf("map create without BTF: %w", err) @@ -380,19 +414,11 @@ func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *hand return nil, fmt.Errorf("map create: %w", err) } - if err := m.populate(spec.Contents); err != nil { - return nil, fmt.Errorf("map create: can't set initial contents: %w", err) - } - - if spec.Freeze { - if err := m.Freeze(); err != nil { - return nil, fmt.Errorf("can't freeze map: %w", err) - } - } - return m, nil } +// newMap allocates and returns a new Map structure. +// Sets the fullValueSize on per-CPU maps. func newMap(fd *internal.FD, name string, typ MapType, keySize, valueSize, maxEntries, flags uint32) (*Map, error) { m := &Map{ name, @@ -415,7 +441,7 @@ func newMap(fd *internal.FD, name string, typ MapType, keySize, valueSize, maxEn return nil, err } - m.fullValueSize = align(int(valueSize), 8) * possibleCPUs + m.fullValueSize = internal.Align(int(valueSize), 8) * possibleCPUs return m, nil } @@ -892,12 +918,21 @@ func (m *Map) Freeze() error { return nil } -func (m *Map) populate(contents []MapKV) error { - for _, kv := range contents { +// finalize populates the Map according to the Contents specified +// in spec and freezes the Map if requested by spec. +func (m *Map) finalize(spec *MapSpec) error { + for _, kv := range spec.Contents { if err := m.Put(kv.Key, kv.Value); err != nil { - return fmt.Errorf("key %v: %w", kv.Key, err) + return fmt.Errorf("putting value: key %v: %w", kv.Key, err) } } + + if spec.Freeze { + if err := m.Freeze(); err != nil { + return fmt.Errorf("freezing map: %w", err) + } + } + return nil } @@ -1212,7 +1247,7 @@ func MapGetNextID(startID MapID) (MapID, error) { // // Returns ErrNotExist, if there is no eBPF map with the given id. func NewMapFromID(id MapID) (*Map, error) { - fd, err := bpfObjGetFDByID(internal.BPF_MAP_GET_FD_BY_ID, uint32(id)) + fd, err := internal.BPFObjGetFDByID(internal.BPF_MAP_GET_FD_BY_ID, uint32(id)) if err != nil { return nil, err } diff --git a/vendor/github.com/cilium/ebpf/marshalers.go b/vendor/github.com/cilium/ebpf/marshalers.go index f2610eff9c781..e461d673d7014 100644 --- a/vendor/github.com/cilium/ebpf/marshalers.go +++ b/vendor/github.com/cilium/ebpf/marshalers.go @@ -8,6 +8,7 @@ import ( "fmt" "reflect" "runtime" + "sync" "unsafe" "github.com/cilium/ebpf/internal" @@ -39,6 +40,10 @@ func marshalPtr(data interface{}, length int) (internal.Pointer, error) { // Returns an error if the given value isn't representable in exactly // length bytes. func marshalBytes(data interface{}, length int) (buf []byte, err error) { + if data == nil { + return nil, errors.New("can't marshal a nil value") + } + switch value := data.(type) { case encoding.BinaryMarshaler: buf, err = value.MarshalBinary() @@ -77,22 +82,30 @@ func makeBuffer(dst interface{}, length int) (internal.Pointer, []byte) { return internal.NewSlicePointer(buf), buf } +var bytesReaderPool = sync.Pool{ + New: func() interface{} { + return new(bytes.Reader) + }, +} + // unmarshalBytes converts a byte buffer into an arbitrary value. // // Prefer using Map.unmarshalKey and Map.unmarshalValue if possible, since // those have special cases that allow more types to be encoded. +// +// The common int32 and int64 types are directly handled to avoid +// unnecessary heap allocations as happening in the default case. func unmarshalBytes(data interface{}, buf []byte) error { switch value := data.(type) { case unsafe.Pointer: - // This could be solved in Go 1.17 by unsafe.Slice instead. (https://github.com/golang/go/issues/19367) - // We could opt for removing unsafe.Pointer support in the lib as well. - sh := &reflect.SliceHeader{ //nolint:govet - Data: uintptr(value), - Len: len(buf), - Cap: len(buf), - } + var dst []byte + // Use unsafe.Slice when we drop support for pre1.17 (https://github.com/golang/go/issues/19367) + // We could opt for removing unsafe.Pointer support in the lib as well + sh := (*reflect.SliceHeader)(unsafe.Pointer(&dst)) + sh.Data = uintptr(value) + sh.Len = len(buf) + sh.Cap = len(buf) - dst := *(*[]byte)(unsafe.Pointer(sh)) copy(dst, buf) runtime.KeepAlive(value) return nil @@ -106,12 +119,38 @@ func unmarshalBytes(data interface{}, buf []byte) error { case *[]byte: *value = buf return nil + case *int32: + if len(buf) < 4 { + return errors.New("int32 requires 4 bytes") + } + *value = int32(internal.NativeEndian.Uint32(buf)) + return nil + case *uint32: + if len(buf) < 4 { + return errors.New("uint32 requires 4 bytes") + } + *value = internal.NativeEndian.Uint32(buf) + return nil + case *int64: + if len(buf) < 8 { + return errors.New("int64 requires 8 bytes") + } + *value = int64(internal.NativeEndian.Uint64(buf)) + return nil + case *uint64: + if len(buf) < 8 { + return errors.New("uint64 requires 8 bytes") + } + *value = internal.NativeEndian.Uint64(buf) + return nil case string: return errors.New("require pointer to string") case []byte: return errors.New("require pointer to []byte") default: - rd := bytes.NewReader(buf) + rd := bytesReaderPool.Get().(*bytes.Reader) + rd.Reset(buf) + defer bytesReaderPool.Put(rd) if err := binary.Read(rd, internal.NativeEndian, value); err != nil { return fmt.Errorf("decoding %T: %v", value, err) } @@ -142,7 +181,7 @@ func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, er return internal.Pointer{}, fmt.Errorf("per-CPU value exceeds number of CPUs") } - alignedElemLength := align(elemLength, 8) + alignedElemLength := internal.Align(elemLength, 8) buf := make([]byte, alignedElemLength*possibleCPUs) for i := 0; i < sliceLen; i++ { @@ -212,7 +251,3 @@ func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) erro reflect.ValueOf(slicePtr).Elem().Set(slice) return nil } - -func align(n, alignment int) int { - return (int(n) + alignment - 1) / alignment * alignment -} diff --git a/vendor/github.com/cilium/ebpf/prog.go b/vendor/github.com/cilium/ebpf/prog.go index 13bdb6ddad1e2..3549a3fe3f0cb 100644 --- a/vendor/github.com/cilium/ebpf/prog.go +++ b/vendor/github.com/cilium/ebpf/prog.go @@ -57,16 +57,21 @@ type ProgramSpec struct { // Name is passed to the kernel as a debug aid. Must only contain // alpha numeric and '_' characters. Name string + // Type determines at which hook in the kernel a program will run. Type ProgramType AttachType AttachType - // Name of a kernel data structure to attach to. It's interpretation - // depends on Type and AttachType. - AttachTo string + // Name of a kernel data structure or function to attach to. Its + // interpretation depends on Type and AttachType. + AttachTo string + // The program to attach to. Must be provided manually. + AttachTarget *Program Instructions asm.Instructions + // Flags is passed to the kernel and specifies additional program // load attributes. Flags uint32 + // License of the program. Some helpers are only available if // the license is deemed compatible with the GPL. // @@ -146,7 +151,7 @@ func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *handleCache) (*Program, error) { if len(spec.Instructions) == 0 { - return nil, errors.New("Instructions cannot be empty") + return nil, errors.New("instructions cannot be empty") } if spec.ByteOrder != nil && spec.ByteOrder != internal.NativeEndian { @@ -166,16 +171,16 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand kv = v.Kernel() } - attr := &bpfProgLoadAttr{ - progType: spec.Type, - progFlags: spec.Flags, - expectedAttachType: spec.AttachType, - license: internal.NewStringPointer(spec.License), - kernelVersion: kv, + attr := &internal.BPFProgLoadAttr{ + ProgType: uint32(spec.Type), + ProgFlags: spec.Flags, + ExpectedAttachType: uint32(spec.AttachType), + License: internal.NewStringPointer(spec.License), + KernelVersion: kv, } if haveObjName() == nil { - attr.progName = internal.NewBPFObjName(spec.Name) + attr.ProgName = internal.NewBPFObjName(spec.Name) } var err error @@ -190,35 +195,35 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand var btfDisabled bool var core btf.COREFixups if spec.BTF != nil { - core, err = btf.ProgramFixups(spec.BTF, targetBTF) + core, err = spec.BTF.Fixups(targetBTF) if err != nil { return nil, fmt.Errorf("CO-RE relocations: %w", err) } - handle, err := handles.btfHandle(btf.ProgramSpec(spec.BTF)) + handle, err := handles.btfHandle(spec.BTF.Spec()) btfDisabled = errors.Is(err, btf.ErrNotSupported) if err != nil && !btfDisabled { return nil, fmt.Errorf("load BTF: %w", err) } if handle != nil { - attr.progBTFFd = uint32(handle.FD()) + attr.ProgBTFFd = uint32(handle.FD()) - recSize, bytes, err := btf.ProgramLineInfos(spec.BTF) + recSize, bytes, err := spec.BTF.LineInfos() if err != nil { return nil, fmt.Errorf("get BTF line infos: %w", err) } - attr.lineInfoRecSize = recSize - attr.lineInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize)) - attr.lineInfo = internal.NewSlicePointer(bytes) + attr.LineInfoRecSize = recSize + attr.LineInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize)) + attr.LineInfo = internal.NewSlicePointer(bytes) - recSize, bytes, err = btf.ProgramFuncInfos(spec.BTF) + recSize, bytes, err = spec.BTF.FuncInfos() if err != nil { return nil, fmt.Errorf("get BTF function infos: %w", err) } - attr.funcInfoRecSize = recSize - attr.funcInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize)) - attr.funcInfo = internal.NewSlicePointer(bytes) + attr.FuncInfoRecSize = recSize + attr.FuncInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize)) + attr.FuncInfo = internal.NewSlicePointer(bytes) } } @@ -238,16 +243,41 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand } bytecode := buf.Bytes() - attr.instructions = internal.NewSlicePointer(bytecode) - attr.insCount = uint32(len(bytecode) / asm.InstructionSize) + attr.Instructions = internal.NewSlicePointer(bytecode) + attr.InsCount = uint32(len(bytecode) / asm.InstructionSize) if spec.AttachTo != "" { + if spec.AttachTarget != nil { + info, err := spec.AttachTarget.Info() + if err != nil { + return nil, fmt.Errorf("load target BTF: %w", err) + } + + btfID, ok := info.BTFID() + if !ok { + return nil, fmt.Errorf("load target BTF: no BTF info available") + } + btfHandle, err := btf.NewHandleFromID(btfID) + if err != nil { + return nil, fmt.Errorf("load target BTF: %w", err) + } + defer btfHandle.Close() + + targetBTF = btfHandle.Spec() + if err != nil { + return nil, fmt.Errorf("load target BTF: %w", err) + } + } + target, err := resolveBTFType(targetBTF, spec.AttachTo, spec.Type, spec.AttachType) if err != nil { return nil, err } if target != nil { - attr.attachBTFID = target.ID() + attr.AttachBTFID = uint32(target.ID()) + } + if spec.AttachTarget != nil { + attr.AttachProgFd = uint32(spec.AttachTarget.FD()) } } @@ -259,12 +289,12 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand var logBuf []byte if opts.LogLevel > 0 { logBuf = make([]byte, logSize) - attr.logLevel = opts.LogLevel - attr.logSize = uint32(len(logBuf)) - attr.logBuf = internal.NewSlicePointer(logBuf) + attr.LogLevel = opts.LogLevel + attr.LogSize = uint32(len(logBuf)) + attr.LogBuf = internal.NewSlicePointer(logBuf) } - fd, err := bpfProgLoad(attr) + fd, err := internal.BPFProgLoad(attr) if err == nil { return &Program{internal.CString(logBuf), fd, spec.Name, "", spec.Type}, nil } @@ -273,17 +303,20 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand if opts.LogLevel == 0 && opts.LogSize >= 0 { // Re-run with the verifier enabled to get better error messages. logBuf = make([]byte, logSize) - attr.logLevel = 1 - attr.logSize = uint32(len(logBuf)) - attr.logBuf = internal.NewSlicePointer(logBuf) + attr.LogLevel = 1 + attr.LogSize = uint32(len(logBuf)) + attr.LogBuf = internal.NewSlicePointer(logBuf) - _, logErr = bpfProgLoad(attr) + fd, logErr = internal.BPFProgLoad(attr) + if logErr == nil { + fd.Close() + } } if errors.Is(logErr, unix.EPERM) && logBuf[0] == 0 { // EPERM due to RLIMIT_MEMLOCK happens before the verifier, so we can // check that the log is empty to reduce false positives. - return nil, fmt.Errorf("load program: RLIMIT_MEMLOCK may be too low: %w", logErr) + return nil, fmt.Errorf("load program: %w (MEMLOCK bay be too low, consider rlimit.RemoveMemlock)", logErr) } err = internal.ErrorWithLog(err, logBuf, logErr) @@ -310,7 +343,7 @@ func NewProgramFromFD(fd int) (*Program, error) { // // Returns ErrNotExist, if there is no eBPF program with the given id. func NewProgramFromID(id ProgramID) (*Program, error) { - fd, err := bpfObjGetFDByID(internal.BPF_PROG_GET_FD_BY_ID, uint32(id)) + fd, err := internal.BPFObjGetFDByID(internal.BPF_PROG_GET_FD_BY_ID, uint32(id)) if err != nil { return nil, fmt.Errorf("get program by id: %w", err) } @@ -677,45 +710,44 @@ func ProgramGetNextID(startID ProgramID) (ProgramID, error) { // // Deprecated: use ProgramInfo.ID() instead. func (p *Program) ID() (ProgramID, error) { - info, err := bpfGetProgInfoByFD(p.fd) + info, err := bpfGetProgInfoByFD(p.fd, nil) if err != nil { return ProgramID(0), err } return ProgramID(info.id), nil } -func resolveBTFType(kernel *btf.Spec, name string, progType ProgramType, attachType AttachType) (btf.Type, error) { +func resolveBTFType(spec *btf.Spec, name string, progType ProgramType, attachType AttachType) (btf.Type, error) { type match struct { p ProgramType a AttachType } - var target btf.Type var typeName, featureName string switch (match{progType, attachType}) { case match{LSM, AttachLSMMac}: - target = new(btf.Func) typeName = "bpf_lsm_" + name featureName = name + " LSM hook" - case match{Tracing, AttachTraceIter}: - target = new(btf.Func) typeName = "bpf_iter_" + name featureName = name + " iterator" - + case match{Extension, AttachNone}: + typeName = name + featureName = fmt.Sprintf("freplace %s", name) default: return nil, nil } - if kernel == nil { + if spec == nil { var err error - kernel, err = btf.LoadKernelSpec() + spec, err = btf.LoadKernelSpec() if err != nil { return nil, fmt.Errorf("load kernel spec: %w", err) } } - err := kernel.FindType(typeName, target) + var target *btf.Func + err := spec.FindType(typeName, &target) if errors.Is(err, btf.ErrNotFound) { return nil, &internal.UnsupportedFeatureError{ Name: featureName, @@ -724,5 +756,6 @@ func resolveBTFType(kernel *btf.Spec, name string, progType ProgramType, attachT if err != nil { return nil, fmt.Errorf("resolve BTF for %s: %w", featureName, err) } + return target, nil } diff --git a/vendor/github.com/cilium/ebpf/run-tests.sh b/vendor/github.com/cilium/ebpf/run-tests.sh index e2437beed2a56..a079edc7e18c1 100644 --- a/vendor/github.com/cilium/ebpf/run-tests.sh +++ b/vendor/github.com/cilium/ebpf/run-tests.sh @@ -5,7 +5,7 @@ # Run all tests on a 5.4 kernel # $ ./run-tests.sh 5.4 # Run a subset of tests: -# $ ./run-tests.sh 5.4 go test ./link +# $ ./run-tests.sh 5.4 ./link set -euo pipefail @@ -48,15 +48,17 @@ if [[ "${1:-}" = "--exec-vm" ]]; then rm "${output}/fake-stdin" fi - $sudo virtme-run --kimg "${input}/bzImage" --memory 768M --pwd \ - --rwdir="${testdir}=${testdir}" \ - --rodir=/run/input="${input}" \ - --rwdir=/run/output="${output}" \ - --script-sh "PATH=\"$PATH\" \"$script\" --exec-test $cmd" \ - --qemu-opts -smp 2 # need at least two CPUs for some tests + if ! $sudo virtme-run --kimg "${input}/bzImage" --memory 768M --pwd \ + --rwdir="${testdir}=${testdir}" \ + --rodir=/run/input="${input}" \ + --rwdir=/run/output="${output}" \ + --script-sh "PATH=\"$PATH\" \"$script\" --exec-test $cmd" \ + --kopt possible_cpus=2; then # need at least two CPUs for some tests + exit 23 + fi if [[ ! -e "${output}/success" ]]; then - exit 1 + exit 42 fi $sudo rm -r "$output" @@ -74,7 +76,7 @@ elif [[ "${1:-}" = "--exec-test" ]]; then dmesg -C if ! "$@"; then dmesg - exit 1 + exit 1 # this return code is "swallowed" by qemu fi touch "/run/output/success" exit 0 @@ -108,7 +110,7 @@ else echo "No selftests found, disabling" fi -args=(-v -short -coverpkg=./... -coverprofile=coverage.out -count 1 ./...) +args=(-short -coverpkg=./... -coverprofile=coverage.out -count 1 ./...) if (( $# > 0 )); then args=("$@") fi diff --git a/vendor/github.com/cilium/ebpf/syscalls.go b/vendor/github.com/cilium/ebpf/syscalls.go index f5a38549bb7cf..f8cb5f0e0cd6f 100644 --- a/vendor/github.com/cilium/ebpf/syscalls.go +++ b/vendor/github.com/cilium/ebpf/syscalls.go @@ -1,13 +1,14 @@ package ebpf import ( + "bytes" "errors" "fmt" "os" "unsafe" + "github.com/cilium/ebpf/asm" "github.com/cilium/ebpf/internal" - "github.com/cilium/ebpf/internal/btf" "github.com/cilium/ebpf/internal/unix" ) @@ -73,30 +74,6 @@ type bpfMapInfo struct { btf_value_type_id uint32 } -type bpfProgLoadAttr struct { - progType ProgramType - insCount uint32 - instructions internal.Pointer - license internal.Pointer - logLevel uint32 - logSize uint32 - logBuf internal.Pointer - kernelVersion uint32 // since 4.1 2541517c32be - progFlags uint32 // since 4.11 e07b98d9bffe - progName internal.BPFObjName // since 4.15 067cae47771c - progIfIndex uint32 // since 4.15 1f6f4cb7ba21 - expectedAttachType AttachType // since 4.17 5e43f899b03a - progBTFFd uint32 - funcInfoRecSize uint32 - funcInfo internal.Pointer - funcInfoCnt uint32 - lineInfoRecSize uint32 - lineInfo internal.Pointer - lineInfoCnt uint32 - attachBTFID btf.TypeID - attachProgFd uint32 -} - type bpfProgInfo struct { prog_type uint32 id uint32 @@ -107,7 +84,7 @@ type bpfProgInfo struct { xlated_prog_insns internal.Pointer load_time uint64 // since 4.15 cb4d2b3f03d8 created_by_uid uint32 - nr_map_ids uint32 + nr_map_ids uint32 // since 4.15 cb4d2b3f03d8 map_ids internal.Pointer name internal.BPFObjName // since 4.15 067cae47771c ifindex uint32 @@ -145,11 +122,6 @@ type bpfProgTestRunAttr struct { duration uint32 } -type bpfGetFDByIDAttr struct { - id uint32 - next uint32 -} - type bpfMapFreezeAttr struct { mapFd uint32 } @@ -160,23 +132,6 @@ type bpfObjGetNextIDAttr struct { openFlags uint32 } -func bpfProgLoad(attr *bpfProgLoadAttr) (*internal.FD, error) { - for { - fd, err := internal.BPF(internal.BPF_PROG_LOAD, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) - // As of ~4.20 the verifier can be interrupted by a signal, - // and returns EAGAIN in that case. - if errors.Is(err, unix.EAGAIN) { - continue - } - - if err != nil { - return nil, err - } - - return internal.NewFD(uint32(fd)), nil - } -} - func bpfProgTestRun(attr *bpfProgTestRunAttr) error { _, err := internal.BPF(internal.BPF_PROG_TEST_RUN, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) return err @@ -372,6 +327,10 @@ func wrapMapError(err error) error { return internal.SyscallError(ErrNotSupported, unix.ENOTSUPP) } + if errors.Is(err, unix.E2BIG) { + return fmt.Errorf("key too big for map: %w", err) + } + return err } @@ -388,8 +347,13 @@ func bpfMapFreeze(m *internal.FD) error { return err } -func bpfGetProgInfoByFD(fd *internal.FD) (*bpfProgInfo, error) { +func bpfGetProgInfoByFD(fd *internal.FD, ids []MapID) (*bpfProgInfo, error) { var info bpfProgInfo + if len(ids) > 0 { + info.nr_map_ids = uint32(len(ids)) + info.map_ids = internal.NewPointer(unsafe.Pointer(&ids[0])) + } + if err := internal.BPFObjGetInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info)); err != nil { return nil, fmt.Errorf("can't get program info: %w", err) } @@ -471,10 +435,30 @@ var haveBatchAPI = internal.FeatureTest("map batch api", "5.6", func() error { return nil }) -func bpfObjGetFDByID(cmd internal.BPFCmd, id uint32) (*internal.FD, error) { - attr := bpfGetFDByIDAttr{ - id: id, +var haveProbeReadKernel = internal.FeatureTest("bpf_probe_read_kernel", "5.5", func() error { + insns := asm.Instructions{ + asm.Mov.Reg(asm.R1, asm.R10), + asm.Add.Imm(asm.R1, -8), + asm.Mov.Imm(asm.R2, 8), + asm.Mov.Imm(asm.R3, 0), + asm.FnProbeReadKernel.Call(), + asm.Return(), + } + buf := bytes.NewBuffer(make([]byte, 0, len(insns)*asm.InstructionSize)) + if err := insns.Marshal(buf, internal.NativeEndian); err != nil { + return err } - ptr, err := internal.BPF(cmd, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) - return internal.NewFD(uint32(ptr)), err -} + bytecode := buf.Bytes() + + fd, err := internal.BPFProgLoad(&internal.BPFProgLoadAttr{ + ProgType: uint32(Kprobe), + License: internal.NewStringPointer("GPL"), + Instructions: internal.NewSlicePointer(bytecode), + InsCount: uint32(len(bytecode) / asm.InstructionSize), + }) + if err != nil { + return internal.ErrNotSupported + } + _ = fd.Close() + return nil +}) diff --git a/vendor/github.com/cilium/ebpf/types.go b/vendor/github.com/cilium/ebpf/types.go index 441a82fe4c1c6..84b83f9f9855d 100644 --- a/vendor/github.com/cilium/ebpf/types.go +++ b/vendor/github.com/cilium/ebpf/types.go @@ -4,12 +4,17 @@ import ( "github.com/cilium/ebpf/internal/unix" ) -//go:generate stringer -output types_string.go -type=MapType,ProgramType,AttachType,PinType +//go:generate stringer -output types_string.go -type=MapType,ProgramType,PinType // MapType indicates the type map structure // that will be initialized in the kernel. type MapType uint32 +// Max returns the latest supported MapType. +func (_ MapType) Max() MapType { + return maxMapType - 1 +} + // All the various map types that can be created const ( UnspecifiedMap MapType = iota @@ -85,15 +90,28 @@ const ( SkStorage // DevMapHash - Hash-based indexing scheme for references to network devices. DevMapHash - StructOpts + // StructOpsMap - This map holds a kernel struct with its function pointer implemented in a BPF + // program. + StructOpsMap + // RingBuf - Similar to PerfEventArray, but shared across all CPUs. RingBuf + // InodeStorage - Specialized local storage map for inodes. InodeStorage + // TaskStorage - Specialized local storage map for task_struct. TaskStorage + // maxMapType - Bound enum of MapTypes, has to be last in enum. + maxMapType ) +// Deprecated: StructOpts was a typo, use StructOpsMap instead. +// +// Declared as a variable to prevent stringer from picking it up +// as an enum value. +var StructOpts MapType = StructOpsMap + // hasPerCPUValue returns true if the Map stores a value per CPU. func (mt MapType) hasPerCPUValue() bool { - return mt == PerCPUHash || mt == PerCPUArray || mt == LRUCPUHash + return mt == PerCPUHash || mt == PerCPUArray || mt == LRUCPUHash || mt == PerCPUCGroupStorage } // canStoreMap returns true if the map type accepts a map fd @@ -111,6 +129,11 @@ func (mt MapType) canStoreProgram() bool { // ProgramType of the eBPF program type ProgramType uint32 +// Max return the latest supported ProgramType. +func (_ ProgramType) Max() ProgramType { + return maxProgramType - 1 +} + // eBPF program types const ( UnspecifiedProgram ProgramType = iota @@ -144,6 +167,7 @@ const ( Extension LSM SkLookup + maxProgramType ) // AttachType of the eBPF program, needed to differentiate allowed context accesses in @@ -151,6 +175,8 @@ const ( // Will cause invalid argument (EINVAL) at program load time if set incorrectly. type AttachType uint32 +//go:generate stringer -type AttachType -trimprefix Attach + // AttachNone is an alias for AttachCGroupInetIngress for readability reasons. const AttachNone AttachType = 0 @@ -193,6 +219,10 @@ const ( AttachXDPCPUMap AttachSkLookup AttachXDP + AttachSkSKBVerdict + AttachSkReuseportSelect + AttachSkReuseportSelectOrMigrate + AttachPerfEvent ) // AttachFlags of the eBPF program used in BPF_PROG_ATTACH command diff --git a/vendor/github.com/cilium/ebpf/types_string.go b/vendor/github.com/cilium/ebpf/types_string.go index c25f7656479bf..81cbc9efde0c5 100644 --- a/vendor/github.com/cilium/ebpf/types_string.go +++ b/vendor/github.com/cilium/ebpf/types_string.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -output types_string.go -type=MapType,ProgramType,AttachType,PinType"; DO NOT EDIT. +// Code generated by "stringer -output types_string.go -type=MapType,ProgramType,PinType"; DO NOT EDIT. package ebpf @@ -34,15 +34,16 @@ func _() { _ = x[Stack-23] _ = x[SkStorage-24] _ = x[DevMapHash-25] - _ = x[StructOpts-26] + _ = x[StructOpsMap-26] _ = x[RingBuf-27] _ = x[InodeStorage-28] _ = x[TaskStorage-29] + _ = x[maxMapType-30] } -const _MapType_name = "UnspecifiedMapHashArrayProgramArrayPerfEventArrayPerCPUHashPerCPUArrayStackTraceCGroupArrayLRUHashLRUCPUHashLPMTrieArrayOfMapsHashOfMapsDevMapSockMapCPUMapXSKMapSockHashCGroupStorageReusePortSockArrayPerCPUCGroupStorageQueueStackSkStorageDevMapHashStructOptsRingBufInodeStorageTaskStorage" +const _MapType_name = "UnspecifiedMapHashArrayProgramArrayPerfEventArrayPerCPUHashPerCPUArrayStackTraceCGroupArrayLRUHashLRUCPUHashLPMTrieArrayOfMapsHashOfMapsDevMapSockMapCPUMapXSKMapSockHashCGroupStorageReusePortSockArrayPerCPUCGroupStorageQueueStackSkStorageDevMapHashStructOpsMapRingBufInodeStorageTaskStoragemaxMapType" -var _MapType_index = [...]uint16{0, 14, 18, 23, 35, 49, 59, 70, 80, 91, 98, 108, 115, 126, 136, 142, 149, 155, 161, 169, 182, 200, 219, 224, 229, 238, 248, 258, 265, 277, 288} +var _MapType_index = [...]uint16{0, 14, 18, 23, 35, 49, 59, 70, 80, 91, 98, 108, 115, 126, 136, 142, 149, 155, 161, 169, 182, 200, 219, 224, 229, 238, 248, 260, 267, 279, 290, 300} func (i MapType) String() string { if i >= MapType(len(_MapType_index)-1) { @@ -85,11 +86,12 @@ func _() { _ = x[Extension-28] _ = x[LSM-29] _ = x[SkLookup-30] + _ = x[maxProgramType-31] } -const _ProgramType_name = "UnspecifiedProgramSocketFilterKprobeSchedCLSSchedACTTracePointXDPPerfEventCGroupSKBCGroupSockLWTInLWTOutLWTXmitSockOpsSkSKBCGroupDeviceSkMsgRawTracepointCGroupSockAddrLWTSeg6LocalLircMode2SkReuseportFlowDissectorCGroupSysctlRawTracepointWritableCGroupSockoptTracingStructOpsExtensionLSMSkLookup" +const _ProgramType_name = "UnspecifiedProgramSocketFilterKprobeSchedCLSSchedACTTracePointXDPPerfEventCGroupSKBCGroupSockLWTInLWTOutLWTXmitSockOpsSkSKBCGroupDeviceSkMsgRawTracepointCGroupSockAddrLWTSeg6LocalLircMode2SkReuseportFlowDissectorCGroupSysctlRawTracepointWritableCGroupSockoptTracingStructOpsExtensionLSMSkLookupmaxProgramType" -var _ProgramType_index = [...]uint16{0, 18, 30, 36, 44, 52, 62, 65, 74, 83, 93, 98, 104, 111, 118, 123, 135, 140, 153, 167, 179, 188, 199, 212, 224, 245, 258, 265, 274, 283, 286, 294} +var _ProgramType_index = [...]uint16{0, 18, 30, 36, 44, 52, 62, 65, 74, 83, 93, 98, 104, 111, 118, 123, 135, 140, 153, 167, 179, 188, 199, 212, 224, 245, 258, 265, 274, 283, 286, 294, 308} func (i ProgramType) String() string { if i >= ProgramType(len(_ProgramType_index)-1) { @@ -97,61 +99,6 @@ func (i ProgramType) String() string { } return _ProgramType_name[_ProgramType_index[i]:_ProgramType_index[i+1]] } -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[AttachNone-0] - _ = x[AttachCGroupInetIngress-0] - _ = x[AttachCGroupInetEgress-1] - _ = x[AttachCGroupInetSockCreate-2] - _ = x[AttachCGroupSockOps-3] - _ = x[AttachSkSKBStreamParser-4] - _ = x[AttachSkSKBStreamVerdict-5] - _ = x[AttachCGroupDevice-6] - _ = x[AttachSkMsgVerdict-7] - _ = x[AttachCGroupInet4Bind-8] - _ = x[AttachCGroupInet6Bind-9] - _ = x[AttachCGroupInet4Connect-10] - _ = x[AttachCGroupInet6Connect-11] - _ = x[AttachCGroupInet4PostBind-12] - _ = x[AttachCGroupInet6PostBind-13] - _ = x[AttachCGroupUDP4Sendmsg-14] - _ = x[AttachCGroupUDP6Sendmsg-15] - _ = x[AttachLircMode2-16] - _ = x[AttachFlowDissector-17] - _ = x[AttachCGroupSysctl-18] - _ = x[AttachCGroupUDP4Recvmsg-19] - _ = x[AttachCGroupUDP6Recvmsg-20] - _ = x[AttachCGroupGetsockopt-21] - _ = x[AttachCGroupSetsockopt-22] - _ = x[AttachTraceRawTp-23] - _ = x[AttachTraceFEntry-24] - _ = x[AttachTraceFExit-25] - _ = x[AttachModifyReturn-26] - _ = x[AttachLSMMac-27] - _ = x[AttachTraceIter-28] - _ = x[AttachCgroupInet4GetPeername-29] - _ = x[AttachCgroupInet6GetPeername-30] - _ = x[AttachCgroupInet4GetSockname-31] - _ = x[AttachCgroupInet6GetSockname-32] - _ = x[AttachXDPDevMap-33] - _ = x[AttachCgroupInetSockRelease-34] - _ = x[AttachXDPCPUMap-35] - _ = x[AttachSkLookup-36] - _ = x[AttachXDP-37] -} - -const _AttachType_name = "AttachNoneAttachCGroupInetEgressAttachCGroupInetSockCreateAttachCGroupSockOpsAttachSkSKBStreamParserAttachSkSKBStreamVerdictAttachCGroupDeviceAttachSkMsgVerdictAttachCGroupInet4BindAttachCGroupInet6BindAttachCGroupInet4ConnectAttachCGroupInet6ConnectAttachCGroupInet4PostBindAttachCGroupInet6PostBindAttachCGroupUDP4SendmsgAttachCGroupUDP6SendmsgAttachLircMode2AttachFlowDissectorAttachCGroupSysctlAttachCGroupUDP4RecvmsgAttachCGroupUDP6RecvmsgAttachCGroupGetsockoptAttachCGroupSetsockoptAttachTraceRawTpAttachTraceFEntryAttachTraceFExitAttachModifyReturnAttachLSMMacAttachTraceIterAttachCgroupInet4GetPeernameAttachCgroupInet6GetPeernameAttachCgroupInet4GetSocknameAttachCgroupInet6GetSocknameAttachXDPDevMapAttachCgroupInetSockReleaseAttachXDPCPUMapAttachSkLookupAttachXDP" - -var _AttachType_index = [...]uint16{0, 10, 32, 58, 77, 100, 124, 142, 160, 181, 202, 226, 250, 275, 300, 323, 346, 361, 380, 398, 421, 444, 466, 488, 504, 521, 537, 555, 567, 582, 610, 638, 666, 694, 709, 736, 751, 765, 774} - -func (i AttachType) String() string { - if i >= AttachType(len(_AttachType_index)-1) { - return "AttachType(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _AttachType_name[_AttachType_index[i]:_AttachType_index[i+1]] -} func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. diff --git a/vendor/github.com/containerd/console/console_windows.go b/vendor/github.com/containerd/console/console_windows.go index 129a92883ddb6..787c11fe56fd9 100644 --- a/vendor/github.com/containerd/console/console_windows.go +++ b/vendor/github.com/containerd/console/console_windows.go @@ -17,10 +17,10 @@ package console import ( + "errors" "fmt" "os" - "github.com/pkg/errors" "golang.org/x/sys/windows" ) @@ -103,7 +103,7 @@ func (m *master) Reset() error { {m.err, m.errMode}, } { if err := windows.SetConsoleMode(s.fd, s.mode); err != nil { - return errors.Wrap(err, "unable to restore console mode") + return fmt.Errorf("unable to restore console mode: %w", err) } } @@ -114,7 +114,7 @@ func (m *master) Size() (WinSize, error) { var info windows.ConsoleScreenBufferInfo err := windows.GetConsoleScreenBufferInfo(m.out, &info) if err != nil { - return WinSize{}, errors.Wrap(err, "unable to get console info") + return WinSize{}, fmt.Errorf("unable to get console info: %w", err) } winsize := WinSize{ @@ -139,7 +139,7 @@ func (m *master) DisableEcho() error { mode |= windows.ENABLE_LINE_INPUT if err := windows.SetConsoleMode(m.in, mode); err != nil { - return errors.Wrap(err, "unable to set console to disable echo") + return fmt.Errorf("unable to set console to disable echo: %w", err) } return nil @@ -192,7 +192,7 @@ func makeInputRaw(fd windows.Handle, mode uint32) error { } if err := windows.SetConsoleMode(fd, mode); err != nil { - return errors.Wrap(err, "unable to set console to raw mode") + return fmt.Errorf("unable to set console to raw mode: %w", err) } return nil diff --git a/vendor/github.com/containerd/console/console_zos.go b/vendor/github.com/containerd/console/console_zos.go new file mode 100644 index 0000000000000..b348a839a03b8 --- /dev/null +++ b/vendor/github.com/containerd/console/console_zos.go @@ -0,0 +1,163 @@ +// +build zos + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "fmt" + "os" + + "golang.org/x/sys/unix" +) + +// NewPty creates a new pty pair +// The master is returned as the first console and a string +// with the path to the pty slave is returned as the second +func NewPty() (Console, string, error) { + var f File + var err error + var slave string + for i := 0;; i++ { + ptyp := fmt.Sprintf("/dev/ptyp%04d", i) + f, err = os.OpenFile(ptyp, os.O_RDWR, 0600) + if err == nil { + slave = fmt.Sprintf("/dev/ttyp%04d", i) + break + } + if os.IsNotExist(err) { + return nil, "", err + } + // else probably Resource Busy + } + m, err := newMaster(f) + if err != nil { + return nil, "", err + } + return m, slave, nil +} + +type master struct { + f File + original *unix.Termios +} + +func (m *master) Read(b []byte) (int, error) { + return m.f.Read(b) +} + +func (m *master) Write(b []byte) (int, error) { + return m.f.Write(b) +} + +func (m *master) Close() error { + return m.f.Close() +} + +func (m *master) Resize(ws WinSize) error { + return tcswinsz(m.f.Fd(), ws) +} + +func (m *master) ResizeFrom(c Console) error { + ws, err := c.Size() + if err != nil { + return err + } + return m.Resize(ws) +} + +func (m *master) Reset() error { + if m.original == nil { + return nil + } + return tcset(m.f.Fd(), m.original) +} + +func (m *master) getCurrent() (unix.Termios, error) { + var termios unix.Termios + if err := tcget(m.f.Fd(), &termios); err != nil { + return unix.Termios{}, err + } + return termios, nil +} + +func (m *master) SetRaw() error { + rawState, err := m.getCurrent() + if err != nil { + return err + } + rawState = cfmakeraw(rawState) + rawState.Oflag = rawState.Oflag | unix.OPOST + return tcset(m.f.Fd(), &rawState) +} + +func (m *master) DisableEcho() error { + rawState, err := m.getCurrent() + if err != nil { + return err + } + rawState.Lflag = rawState.Lflag &^ unix.ECHO + return tcset(m.f.Fd(), &rawState) +} + +func (m *master) Size() (WinSize, error) { + return tcgwinsz(m.f.Fd()) +} + +func (m *master) Fd() uintptr { + return m.f.Fd() +} + +func (m *master) Name() string { + return m.f.Name() +} + +// checkConsole checks if the provided file is a console +func checkConsole(f File) error { + var termios unix.Termios + if tcget(f.Fd(), &termios) != nil { + return ErrNotAConsole + } + return nil +} + +func newMaster(f File) (Console, error) { + m := &master{ + f: f, + } + t, err := m.getCurrent() + if err != nil { + return nil, err + } + m.original = &t + return m, nil +} + +// ClearONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair +// created by us acts normally. In particular, a not-very-well-known default of +// Linux unix98 ptys is that they have +onlcr by default. While this isn't a +// problem for terminal emulators, because we relay data from the terminal we +// also relay that funky line discipline. +func ClearONLCR(fd uintptr) error { + return setONLCR(fd, false) +} + +// SetONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair +// created by us acts as intended for a terminal emulator. +func SetONLCR(fd uintptr) error { + return setONLCR(fd, true) +} diff --git a/vendor/github.com/containerd/console/go.mod b/vendor/github.com/containerd/console/go.mod index 7fca0a9a3ac19..1fe5b7fecb4aa 100644 --- a/vendor/github.com/containerd/console/go.mod +++ b/vendor/github.com/containerd/console/go.mod @@ -2,7 +2,4 @@ module github.com/containerd/console go 1.13 -require ( - github.com/pkg/errors v0.9.1 - golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c -) +require golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c diff --git a/vendor/github.com/containerd/console/go.sum b/vendor/github.com/containerd/console/go.sum index 9db384d3b0066..1225630b7b601 100644 --- a/vendor/github.com/containerd/console/go.sum +++ b/vendor/github.com/containerd/console/go.sum @@ -1,4 +1,2 @@ -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/containerd/console/tc_unix.go b/vendor/github.com/containerd/console/tc_unix.go index 5cd4c550ce884..a6bf01e8d1a2b 100644 --- a/vendor/github.com/containerd/console/tc_unix.go +++ b/vendor/github.com/containerd/console/tc_unix.go @@ -1,4 +1,4 @@ -// +build darwin freebsd linux netbsd openbsd solaris +// +build darwin freebsd linux netbsd openbsd solaris zos /* Copyright The containerd Authors. diff --git a/vendor/github.com/containerd/console/tc_zos.go b/vendor/github.com/containerd/console/tc_zos.go new file mode 100644 index 0000000000000..4262eaf4cc076 --- /dev/null +++ b/vendor/github.com/containerd/console/tc_zos.go @@ -0,0 +1,26 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "golang.org/x/sys/unix" +) + +const ( + cmdTcGet = unix.TCGETS + cmdTcSet = unix.TCSETS +) diff --git a/vendor/github.com/cyphar/filepath-securejoin/.travis.yml b/vendor/github.com/cyphar/filepath-securejoin/.travis.yml index 3938f38349449..b94ff8cf92a92 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/.travis.yml +++ b/vendor/github.com/cyphar/filepath-securejoin/.travis.yml @@ -4,10 +4,12 @@ language: go go: - - 1.7.x - - 1.8.x + - 1.13.x + - 1.16.x - tip - +arch: + - AMD64 + - ppc64le os: - linux - osx diff --git a/vendor/github.com/cyphar/filepath-securejoin/README.md b/vendor/github.com/cyphar/filepath-securejoin/README.md index 49b2baa9f35cb..3624617c89b07 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/README.md +++ b/vendor/github.com/cyphar/filepath-securejoin/README.md @@ -7,6 +7,19 @@ standard library][go#20126]. The purpose of this function is to be a "secure" alternative to `filepath.Join`, and in particular it provides certain guarantees that are not provided by `filepath.Join`. +> **NOTE**: This code is *only* safe if you are not at risk of other processes +> modifying path components after you've used `SecureJoin`. If it is possible +> for a malicious process to modify path components of the resolved path, then +> you will be vulnerable to some fairly trivial TOCTOU race conditions. [There +> are some Linux kernel patches I'm working on which might allow for a better +> solution.][lwn-obeneath] +> +> In addition, with a slightly modified API it might be possible to use +> `O_PATH` and verify that the opened path is actually the resolved one -- but +> I have not done that yet. I might add it in the future as a helper function +> to help users verify the path (we can't just return `/proc/self/fd/` +> because that doesn't always work transparently for all users). + This is the function prototype: ```go @@ -16,8 +29,8 @@ func SecureJoin(root, unsafePath string) (string, error) This library **guarantees** the following: * If no error is set, the resulting string **must** be a child path of - `SecureJoin` and will not contain any symlink path components (they will all - be expanded). + `root` and will not contain any symlink path components (they will all be + expanded). * When expanding symlinks, all symlink path components **must** be resolved relative to the provided root. In particular, this can be considered a @@ -25,7 +38,7 @@ This library **guarantees** the following: these symlinks will **not** be expanded lexically (`filepath.Clean` is not called on the input before processing). -* Non-existant path components are unaffected by `SecureJoin` (similar to +* Non-existent path components are unaffected by `SecureJoin` (similar to `filepath.EvalSymlinks`'s semantics). * The returned path will always be `filepath.Clean`ed and thus not contain any @@ -57,6 +70,7 @@ func SecureJoin(root, unsafePath string) (string, error) { } ``` +[lwn-obeneath]: https://lwn.net/Articles/767547/ [go#20126]: https://github.com/golang/go/issues/20126 ### License ### diff --git a/vendor/github.com/cyphar/filepath-securejoin/VERSION b/vendor/github.com/cyphar/filepath-securejoin/VERSION index ee1372d33a29e..7179039691ce0 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/VERSION +++ b/vendor/github.com/cyphar/filepath-securejoin/VERSION @@ -1 +1 @@ -0.2.2 +0.2.3 diff --git a/vendor/github.com/cyphar/filepath-securejoin/go.mod b/vendor/github.com/cyphar/filepath-securejoin/go.mod new file mode 100644 index 0000000000000..0607c1fa060f0 --- /dev/null +++ b/vendor/github.com/cyphar/filepath-securejoin/go.mod @@ -0,0 +1,3 @@ +module github.com/cyphar/filepath-securejoin + +go 1.13 diff --git a/vendor/github.com/cyphar/filepath-securejoin/join.go b/vendor/github.com/cyphar/filepath-securejoin/join.go index c4ca3d7130057..7dd08dbbdf7b2 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/join.go +++ b/vendor/github.com/cyphar/filepath-securejoin/join.go @@ -12,39 +12,20 @@ package securejoin import ( "bytes" + "errors" "os" "path/filepath" "strings" "syscall" - - "github.com/pkg/errors" ) -// ErrSymlinkLoop is returned by SecureJoinVFS when too many symlinks have been -// evaluated in attempting to securely join the two given paths. -var ErrSymlinkLoop = errors.Wrap(syscall.ELOOP, "secure join") - // IsNotExist tells you if err is an error that implies that either the path // accessed does not exist (or path components don't exist). This is // effectively a more broad version of os.IsNotExist. func IsNotExist(err error) bool { - // If it's a bone-fide ENOENT just bail. - if os.IsNotExist(errors.Cause(err)) { - return true - } - // Check that it's not actually an ENOTDIR, which in some cases is a more // convoluted case of ENOENT (usually involving weird paths). - var errno error - switch err := errors.Cause(err).(type) { - case *os.PathError: - errno = err.Err - case *os.LinkError: - errno = err.Err - case *os.SyscallError: - errno = err.Err - } - return errno == syscall.ENOTDIR || errno == syscall.ENOENT + return errors.Is(err, os.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) || errors.Is(err, syscall.ENOENT) } // SecureJoinVFS joins the two given path components (similar to Join) except @@ -68,7 +49,7 @@ func SecureJoinVFS(root, unsafePath string, vfs VFS) (string, error) { n := 0 for unsafePath != "" { if n > 255 { - return "", ErrSymlinkLoop + return "", &os.PathError{Op: "SecureJoin", Path: root + "/" + unsafePath, Err: syscall.ELOOP} } // Next path component, p. diff --git a/vendor/github.com/cyphar/filepath-securejoin/vendor.conf b/vendor/github.com/cyphar/filepath-securejoin/vendor.conf deleted file mode 100644 index 66bb574b955bc..0000000000000 --- a/vendor/github.com/cyphar/filepath-securejoin/vendor.conf +++ /dev/null @@ -1 +0,0 @@ -github.com/pkg/errors v0.8.0 diff --git a/vendor/github.com/godbus/dbus/v5/README.markdown b/vendor/github.com/godbus/dbus/v5/README.md similarity index 81% rename from vendor/github.com/godbus/dbus/v5/README.markdown rename to vendor/github.com/godbus/dbus/v5/README.md index 1fb2eacaa15a7..5c24125838d26 100644 --- a/vendor/github.com/godbus/dbus/v5/README.markdown +++ b/vendor/github.com/godbus/dbus/v5/README.md @@ -14,14 +14,12 @@ D-Bus message bus system. ### Installation -This packages requires Go 1.7. If you installed it and set up your GOPATH, just run: +This packages requires Go 1.12 or later. It can be installed by running the command below: ``` -go get github.com/godbus/dbus +go get github.com/godbus/dbus/v5 ``` -If you want to use the subpackages, you can install them the same way. - ### Usage The complete package documentation and some simple examples are available at @@ -30,10 +28,12 @@ The complete package documentation and some simple examples are available at gives a short overview over the basic usage. #### Projects using godbus -- [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library. +- [fyne](https://github.com/fyne-io/fyne) a cross platform GUI in Go inspired by Material Design. +- [fynedesk](https://github.com/fyne-io/fynedesk) a full desktop environment for Linux/Unix using Fyne. - [go-bluetooth](https://github.com/muka/go-bluetooth) provides a bluetooth client over bluez dbus API. -- [playerbm](https://github.com/altdesktop/playerbm) a bookmark utility for media players. - [iwd](https://github.com/shibumi/iwd) go bindings for the internet wireless daemon "iwd". +- [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library. +- [playerbm](https://github.com/altdesktop/playerbm) a bookmark utility for media players. Please note that the API is considered unstable for now and may change without further notice. diff --git a/vendor/github.com/godbus/dbus/v5/auth.go b/vendor/github.com/godbus/dbus/v5/auth.go index 283487a0e3138..a59b4c0eb7659 100644 --- a/vendor/github.com/godbus/dbus/v5/auth.go +++ b/vendor/github.com/godbus/dbus/v5/auth.go @@ -53,7 +53,7 @@ type Auth interface { // bus. Auth must not be called on shared connections. func (conn *Conn) Auth(methods []Auth) error { if methods == nil { - uid := strconv.Itoa(os.Getuid()) + uid := strconv.Itoa(os.Geteuid()) methods = []Auth{AuthExternal(uid), AuthCookieSha1(uid, getHomeDir())} } in := bufio.NewReader(conn.transport) @@ -75,9 +75,9 @@ func (conn *Conn) Auth(methods []Auth) error { s = s[1:] for _, v := range s { for _, m := range methods { - if name, data, status := m.FirstData(); bytes.Equal(v, name) { + if name, _, status := m.FirstData(); bytes.Equal(v, name) { var ok bool - err = authWriteLine(conn.transport, []byte("AUTH"), v, data) + err = authWriteLine(conn.transport, []byte("AUTH"), v) if err != nil { return err } @@ -194,11 +194,14 @@ func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, boo } conn.uuid = string(s[1]) return nil, true + case state == waitingForOk && string(s[0]) == "DATA": + err = authWriteLine(conn.transport, []byte("DATA")) + if err != nil { + return err, false + } case state == waitingForOk && string(s[0]) == "REJECTED": return nil, false - case state == waitingForOk && (string(s[0]) == "DATA" || - string(s[0]) == "ERROR"): - + case state == waitingForOk && string(s[0]) == "ERROR": err = authWriteLine(conn.transport, []byte("CANCEL")) if err != nil { return err, false diff --git a/vendor/github.com/godbus/dbus/v5/conn.go b/vendor/github.com/godbus/dbus/v5/conn.go index 29fe018ad823b..76fc5cde3d26d 100644 --- a/vendor/github.com/godbus/dbus/v5/conn.go +++ b/vendor/github.com/godbus/dbus/v5/conn.go @@ -73,7 +73,7 @@ func SessionBus() (conn *Conn, err error) { return } -func getSessionBusAddress() (string, error) { +func getSessionBusAddress(autolaunch bool) (string, error) { if address := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); address != "" && address != "autolaunch:" { return address, nil @@ -81,12 +81,26 @@ func getSessionBusAddress() (string, error) { os.Setenv("DBUS_SESSION_BUS_ADDRESS", address) return address, nil } + if !autolaunch { + return "", errors.New("dbus: couldn't determine address of session bus") + } return getSessionBusPlatformAddress() } // SessionBusPrivate returns a new private connection to the session bus. func SessionBusPrivate(opts ...ConnOption) (*Conn, error) { - address, err := getSessionBusAddress() + address, err := getSessionBusAddress(true) + if err != nil { + return nil, err + } + + return Dial(address, opts...) +} + +// SessionBusPrivate returns a new private connection to the session bus. If +// the session bus is not already open, do not attempt to launch it. +func SessionBusPrivateNoAutoStartup(opts ...ConnOption) (*Conn, error) { + address, err := getSessionBusAddress(false) if err != nil { return nil, err } @@ -121,7 +135,7 @@ func SystemBus() (conn *Conn, err error) { // ConnectSessionBus connects to the session bus. func ConnectSessionBus(opts ...ConnOption) (*Conn, error) { - address, err := getSessionBusAddress() + address, err := getSessionBusAddress(true) if err != nil { return nil, err } @@ -180,7 +194,7 @@ func Dial(address string, opts ...ConnOption) (*Conn, error) { // // Deprecated: use Dial with options instead. func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) { - return Dial(address, WithSignalHandler(signalHandler)) + return Dial(address, WithHandler(handler), WithSignalHandler(signalHandler)) } // ConnOption is a connection option. @@ -478,14 +492,24 @@ func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) { conn.outInt(msg) } err := conn.outHandler.sendAndIfClosed(msg, ifClosed) - conn.calls.handleSendError(msg, err) if err != nil { - conn.serialGen.RetireSerial(msg.serial) + conn.handleSendError(msg, err) } else if msg.Type != TypeMethodCall { conn.serialGen.RetireSerial(msg.serial) } } +func (conn *Conn) handleSendError(msg *Message, err error) { + if msg.Type == TypeMethodCall { + conn.calls.handleSendError(msg, err) + } else if msg.Type == TypeMethodReply { + if _, ok := err.(FormatError); ok { + conn.sendError(err, msg.Headers[FieldDestination].value.(string), msg.Headers[FieldReplySerial].value.(uint32)) + } + } + conn.serialGen.RetireSerial(msg.serial) +} + // Send sends the given message to the message bus. You usually don't need to // use this; use the higher-level equivalents (Call / Go, Emit and Export) // instead. If msg is a method call and NoReplyExpected is not set, a non-nil diff --git a/vendor/github.com/godbus/dbus/v5/decoder.go b/vendor/github.com/godbus/dbus/v5/decoder.go index ede91575b3e86..89bfed9d1a1c5 100644 --- a/vendor/github.com/godbus/dbus/v5/decoder.go +++ b/vendor/github.com/godbus/dbus/v5/decoder.go @@ -10,14 +10,16 @@ type decoder struct { in io.Reader order binary.ByteOrder pos int + fds []int } // newDecoder returns a new decoder that reads values from in. The input is // expected to be in the given byte order. -func newDecoder(in io.Reader, order binary.ByteOrder) *decoder { +func newDecoder(in io.Reader, order binary.ByteOrder, fds []int) *decoder { dec := new(decoder) dec.in = in dec.order = order + dec.fds = fds return dec } @@ -53,7 +55,7 @@ func (dec *decoder) Decode(sig Signature) (vs []interface{}, err error) { vs = make([]interface{}, 0) s := sig.str for s != "" { - err, rem := validSingle(s, 0) + err, rem := validSingle(s, &depthCounter{}) if err != nil { return nil, err } @@ -150,7 +152,7 @@ func (dec *decoder) decode(s string, depth int) interface{} { if len(sig.str) == 0 { panic(FormatError("variant signature is empty")) } - err, rem := validSingle(sig.str, 0) + err, rem := validSingle(sig.str, &depthCounter{}) if err != nil { panic(err) } @@ -161,7 +163,11 @@ func (dec *decoder) decode(s string, depth int) interface{} { variant.value = dec.decode(sig.str, depth+1) return variant case 'h': - return UnixFDIndex(dec.decode("u", depth).(uint32)) + idx := dec.decode("u", depth).(uint32) + if int(idx) < len(dec.fds) { + return UnixFD(dec.fds[idx]) + } + return UnixFDIndex(idx) case 'a': if len(s) > 1 && s[1] == '{' { ksig := s[2:3] @@ -219,7 +225,7 @@ func (dec *decoder) decode(s string, depth int) interface{} { v := make([]interface{}, 0) s = s[1 : len(s)-1] for s != "" { - err, rem := validSingle(s, 0) + err, rem := validSingle(s, &depthCounter{}) if err != nil { panic(err) } diff --git a/vendor/github.com/godbus/dbus/v5/encoder.go b/vendor/github.com/godbus/dbus/v5/encoder.go index adfbb75c5595b..015b26cd5c495 100644 --- a/vendor/github.com/godbus/dbus/v5/encoder.go +++ b/vendor/github.com/godbus/dbus/v5/encoder.go @@ -5,28 +5,33 @@ import ( "encoding/binary" "io" "reflect" + "strings" + "unicode/utf8" ) // An encoder encodes values to the D-Bus wire format. type encoder struct { out io.Writer + fds []int order binary.ByteOrder pos int } // NewEncoder returns a new encoder that writes to out in the given byte order. -func newEncoder(out io.Writer, order binary.ByteOrder) *encoder { - return newEncoderAtOffset(out, 0, order) +func newEncoder(out io.Writer, order binary.ByteOrder, fds []int) *encoder { + enc := newEncoderAtOffset(out, 0, order, fds) + return enc } // newEncoderAtOffset returns a new encoder that writes to out in the given // byte order. Specify the offset to initialize pos for proper alignment // computation. -func newEncoderAtOffset(out io.Writer, offset int, order binary.ByteOrder) *encoder { +func newEncoderAtOffset(out io.Writer, offset int, order binary.ByteOrder, fds []int) *encoder { enc := new(encoder) enc.out = out enc.order = order enc.pos = offset + enc.fds = fds return enc } @@ -75,6 +80,9 @@ func (enc *encoder) Encode(vs ...interface{}) (err error) { // encode encodes the given value to the writer and panics on error. depth holds // the depth of the container nesting. func (enc *encoder) encode(v reflect.Value, depth int) { + if depth > 64 { + panic(FormatError("input exceeds depth limitation")) + } enc.align(alignment(v.Type())) switch v.Kind() { case reflect.Uint8: @@ -97,7 +105,14 @@ func (enc *encoder) encode(v reflect.Value, depth int) { enc.binwrite(uint16(v.Uint())) enc.pos += 2 case reflect.Int, reflect.Int32: - enc.binwrite(int32(v.Int())) + if v.Type() == unixFDType { + fd := v.Int() + idx := len(enc.fds) + enc.fds = append(enc.fds, int(fd)) + enc.binwrite(uint32(idx)) + } else { + enc.binwrite(int32(v.Int())) + } enc.pos += 4 case reflect.Uint, reflect.Uint32: enc.binwrite(uint32(v.Uint())) @@ -112,9 +127,21 @@ func (enc *encoder) encode(v reflect.Value, depth int) { enc.binwrite(v.Float()) enc.pos += 8 case reflect.String: - enc.encode(reflect.ValueOf(uint32(len(v.String()))), depth) + str := v.String() + if !utf8.ValidString(str) { + panic(FormatError("input has a not-utf8 char in string")) + } + if strings.IndexByte(str, byte(0)) != -1 { + panic(FormatError("input has a null char('\\000') in string")) + } + if v.Type() == objectPathType { + if !ObjectPath(str).IsValid() { + panic(FormatError("invalid object path")) + } + } + enc.encode(reflect.ValueOf(uint32(len(str))), depth) b := make([]byte, v.Len()+1) - copy(b, v.String()) + copy(b, str) b[len(b)-1] = 0 n, err := enc.out.Write(b) if err != nil { @@ -124,20 +151,23 @@ func (enc *encoder) encode(v reflect.Value, depth int) { case reflect.Ptr: enc.encode(v.Elem(), depth) case reflect.Slice, reflect.Array: - if depth >= 64 { - panic(FormatError("input exceeds container depth limit")) - } // Lookahead offset: 4 bytes for uint32 length (with alignment), // plus alignment for elements. n := enc.padding(0, 4) + 4 offset := enc.pos + n + enc.padding(n, alignment(v.Type().Elem())) var buf bytes.Buffer - bufenc := newEncoderAtOffset(&buf, offset, enc.order) + bufenc := newEncoderAtOffset(&buf, offset, enc.order, enc.fds) for i := 0; i < v.Len(); i++ { bufenc.encode(v.Index(i), depth+1) } + + if buf.Len() > 1<<26 { + panic(FormatError("input exceeds array size limitation")) + } + + enc.fds = bufenc.fds enc.encode(reflect.ValueOf(uint32(buf.Len())), depth) length := buf.Len() enc.align(alignment(v.Type().Elem())) @@ -146,13 +176,10 @@ func (enc *encoder) encode(v reflect.Value, depth int) { } enc.pos += length case reflect.Struct: - if depth >= 64 && v.Type() != signatureType { - panic(FormatError("input exceeds container depth limit")) - } switch t := v.Type(); t { case signatureType: str := v.Field(0) - enc.encode(reflect.ValueOf(byte(str.Len())), depth+1) + enc.encode(reflect.ValueOf(byte(str.Len())), depth) b := make([]byte, str.Len()+1) copy(b, str.String()) b[len(b)-1] = 0 @@ -176,9 +203,6 @@ func (enc *encoder) encode(v reflect.Value, depth int) { case reflect.Map: // Maps are arrays of structures, so they actually increase the depth by // 2. - if depth >= 63 { - panic(FormatError("input exceeds container depth limit")) - } if !isKeyType(v.Type().Key()) { panic(InvalidTypeError{v.Type()}) } @@ -189,12 +213,13 @@ func (enc *encoder) encode(v reflect.Value, depth int) { offset := enc.pos + n + enc.padding(n, 8) var buf bytes.Buffer - bufenc := newEncoderAtOffset(&buf, offset, enc.order) + bufenc := newEncoderAtOffset(&buf, offset, enc.order, enc.fds) for _, k := range keys { bufenc.align(8) bufenc.encode(k, depth+2) bufenc.encode(v.MapIndex(k), depth+2) } + enc.fds = bufenc.fds enc.encode(reflect.ValueOf(uint32(buf.Len())), depth) length := buf.Len() enc.align(8) diff --git a/vendor/github.com/godbus/dbus/v5/export.go b/vendor/github.com/godbus/dbus/v5/export.go index 2447b51d469d3..522334715b603 100644 --- a/vendor/github.com/godbus/dbus/v5/export.go +++ b/vendor/github.com/godbus/dbus/v5/export.go @@ -26,6 +26,27 @@ var ( } ) +func MakeNoObjectError(path ObjectPath) Error { + return Error{ + "org.freedesktop.DBus.Error.NoSuchObject", + []interface{}{fmt.Sprintf("No such object '%s'", string(path))}, + } +} + +func MakeUnknownMethodError(methodName string) Error { + return Error{ + "org.freedesktop.DBus.Error.UnknownMethod", + []interface{}{fmt.Sprintf("Unknown / invalid method '%s'", methodName)}, + } +} + +func MakeUnknownInterfaceError(ifaceName string) Error { + return Error{ + "org.freedesktop.DBus.Error.UnknownInterface", + []interface{}{fmt.Sprintf("Object does not implement the interface '%s'", ifaceName)}, + } +} + func MakeFailedError(err error) *Error { return &Error{ "org.freedesktop.DBus.Error.Failed", @@ -128,6 +149,11 @@ func (conn *Conn) handleCall(msg *Message) { ifaceName, _ := msg.Headers[FieldInterface].value.(string) sender, hasSender := msg.Headers[FieldSender].value.(string) serial := msg.serial + + if len(name) == 0 { + conn.sendError(ErrMsgUnknownMethod, sender, serial) + } + if ifaceName == "org.freedesktop.DBus.Peer" { switch name { case "Ping": @@ -135,29 +161,26 @@ func (conn *Conn) handleCall(msg *Message) { case "GetMachineId": conn.sendReply(sender, serial, conn.uuid) default: - conn.sendError(ErrMsgUnknownMethod, sender, serial) + conn.sendError(MakeUnknownMethodError(name), sender, serial) } return } - if len(name) == 0 { - conn.sendError(ErrMsgUnknownMethod, sender, serial) - } object, ok := conn.handler.LookupObject(path) if !ok { - conn.sendError(ErrMsgNoObject, sender, serial) + conn.sendError(MakeNoObjectError(path), sender, serial) return } iface, exists := object.LookupInterface(ifaceName) if !exists { - conn.sendError(ErrMsgUnknownInterface, sender, serial) + conn.sendError(MakeUnknownInterfaceError(ifaceName), sender, serial) return } m, exists := iface.LookupMethod(name) if !exists { - conn.sendError(ErrMsgUnknownMethod, sender, serial) + conn.sendError(MakeUnknownMethodError(name), sender, serial) return } args, err := conn.decodeArguments(m, sender, msg) diff --git a/vendor/github.com/godbus/dbus/v5/message.go b/vendor/github.com/godbus/dbus/v5/message.go index 6a925367ebe91..16693eb3017ea 100644 --- a/vendor/github.com/godbus/dbus/v5/message.go +++ b/vendor/github.com/godbus/dbus/v5/message.go @@ -118,11 +118,7 @@ type header struct { Variant } -// DecodeMessage tries to decode a single message in the D-Bus wire format -// from the given reader. The byte order is figured out from the first byte. -// The possibly returned error can be an error of the underlying reader, an -// InvalidMessageError or a FormatError. -func DecodeMessage(rd io.Reader) (msg *Message, err error) { +func DecodeMessageWithFDs(rd io.Reader, fds []int) (msg *Message, err error) { var order binary.ByteOrder var hlength, length uint32 var typ, flags, proto byte @@ -142,7 +138,7 @@ func DecodeMessage(rd io.Reader) (msg *Message, err error) { return nil, InvalidMessageError("invalid byte order") } - dec := newDecoder(rd, order) + dec := newDecoder(rd, order, fds) dec.pos = 1 msg = new(Message) @@ -166,7 +162,7 @@ func DecodeMessage(rd io.Reader) (msg *Message, err error) { if hlength+length+16 > 1<<27 { return nil, InvalidMessageError("message is too long") } - dec = newDecoder(io.MultiReader(bytes.NewBuffer(b), rd), order) + dec = newDecoder(io.MultiReader(bytes.NewBuffer(b), rd), order, fds) dec.pos = 12 vs, err = dec.Decode(Signature{"a(yv)"}) if err != nil { @@ -196,7 +192,7 @@ func DecodeMessage(rd io.Reader) (msg *Message, err error) { sig, _ := msg.Headers[FieldSignature].value.(Signature) if sig.str != "" { buf := bytes.NewBuffer(body) - dec = newDecoder(buf, order) + dec = newDecoder(buf, order, fds) vs, err := dec.Decode(sig) if err != nil { return nil, err @@ -207,12 +203,32 @@ func DecodeMessage(rd io.Reader) (msg *Message, err error) { return } -// EncodeTo encodes and sends a message to the given writer. The byte order must -// be either binary.LittleEndian or binary.BigEndian. If the message is not -// valid or an error occurs when writing, an error is returned. -func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) error { +// DecodeMessage tries to decode a single message in the D-Bus wire format +// from the given reader. The byte order is figured out from the first byte. +// The possibly returned error can be an error of the underlying reader, an +// InvalidMessageError or a FormatError. +func DecodeMessage(rd io.Reader) (msg *Message, err error) { + return DecodeMessageWithFDs(rd, make([]int, 0)); +} + +type nullwriter struct{} + +func (nullwriter) Write(p []byte) (cnt int, err error) { + return len(p), nil +} + +func (msg *Message) CountFds() (int, error) { + if len(msg.Body) == 0 { + return 0, nil + } + enc := newEncoder(nullwriter{}, nativeEndian, make([]int, 0)) + err := enc.Encode(msg.Body...) + return len(enc.fds), err +} + +func (msg *Message) EncodeToWithFDs(out io.Writer, order binary.ByteOrder) (fds []int, err error) { if err := msg.IsValid(); err != nil { - return err + return make([]int, 0), err } var vs [7]interface{} switch order { @@ -221,12 +237,16 @@ func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) error { case binary.BigEndian: vs[0] = byte('B') default: - return errors.New("dbus: invalid byte order") + return make([]int, 0), errors.New("dbus: invalid byte order") } body := new(bytes.Buffer) - enc := newEncoder(body, order) + fds = make([]int, 0) + enc := newEncoder(body, order, fds) if len(msg.Body) != 0 { - enc.Encode(msg.Body...) + err = enc.Encode(msg.Body...) + if err != nil { + return + } } vs[1] = msg.Type vs[2] = msg.Flags @@ -239,17 +259,28 @@ func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) error { } vs[6] = headers var buf bytes.Buffer - enc = newEncoder(&buf, order) - enc.Encode(vs[:]...) + enc = newEncoder(&buf, order, enc.fds) + err = enc.Encode(vs[:]...) + if err != nil { + return + } enc.align(8) body.WriteTo(&buf) if buf.Len() > 1<<27 { - return InvalidMessageError("message is too long") + return make([]int, 0), InvalidMessageError("message is too long") } if _, err := buf.WriteTo(out); err != nil { - return err + return make([]int, 0), err } - return nil + return enc.fds, nil +} + +// EncodeTo encodes and sends a message to the given writer. The byte order must +// be either binary.LittleEndian or binary.BigEndian. If the message is not +// valid or an error occurs when writing, an error is returned. +func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) (err error) { + _, err = msg.EncodeToWithFDs(out, order) + return err } // IsValid checks whether msg is a valid message and returns an diff --git a/vendor/github.com/godbus/dbus/v5/sig.go b/vendor/github.com/godbus/dbus/v5/sig.go index 2d326cebc0d84..41a0398129d25 100644 --- a/vendor/github.com/godbus/dbus/v5/sig.go +++ b/vendor/github.com/godbus/dbus/v5/sig.go @@ -34,7 +34,7 @@ type Signature struct { func SignatureOf(vs ...interface{}) Signature { var s string for _, v := range vs { - s += getSignature(reflect.TypeOf(v)) + s += getSignature(reflect.TypeOf(v), &depthCounter{}) } return Signature{s} } @@ -42,11 +42,19 @@ func SignatureOf(vs ...interface{}) Signature { // SignatureOfType returns the signature of the given type. It panics if the // type is not representable in D-Bus. func SignatureOfType(t reflect.Type) Signature { - return Signature{getSignature(t)} + return Signature{getSignature(t, &depthCounter{})} } // getSignature returns the signature of the given type and panics on unknown types. -func getSignature(t reflect.Type) string { +func getSignature(t reflect.Type, depth *depthCounter) (sig string) { + if !depth.Valid() { + panic("container nesting too deep") + } + defer func() { + if len(sig) > 255 { + panic("signature exceeds the length limitation") + } + }() // handle simple types first switch t.Kind() { case reflect.Uint8: @@ -74,7 +82,7 @@ func getSignature(t reflect.Type) string { case reflect.Float64: return "d" case reflect.Ptr: - return getSignature(t.Elem()) + return getSignature(t.Elem(), depth) case reflect.String: if t == objectPathType { return "o" @@ -90,17 +98,20 @@ func getSignature(t reflect.Type) string { for i := 0; i < t.NumField(); i++ { field := t.Field(i) if field.PkgPath == "" && field.Tag.Get("dbus") != "-" { - s += getSignature(t.Field(i).Type) + s += getSignature(t.Field(i).Type, depth.EnterStruct()) } } + if len(s) == 0 { + panic("empty struct") + } return "(" + s + ")" case reflect.Array, reflect.Slice: - return "a" + getSignature(t.Elem()) + return "a" + getSignature(t.Elem(), depth.EnterArray()) case reflect.Map: if !isKeyType(t.Key()) { panic(InvalidTypeError{t}) } - return "a{" + getSignature(t.Key()) + getSignature(t.Elem()) + "}" + return "a{" + getSignature(t.Key(), depth.EnterArray().EnterDictEntry()) + getSignature(t.Elem(), depth.EnterArray().EnterDictEntry()) + "}" case reflect.Interface: return "v" } @@ -118,7 +129,7 @@ func ParseSignature(s string) (sig Signature, err error) { } sig.str = s for err == nil && len(s) != 0 { - err, s = validSingle(s, 0) + err, s = validSingle(s, &depthCounter{}) } if err != nil { sig = Signature{""} @@ -144,7 +155,7 @@ func (s Signature) Empty() bool { // Single returns whether the signature represents a single, complete type. func (s Signature) Single() bool { - err, r := validSingle(s.str, 0) + err, r := validSingle(s.str, &depthCounter{}) return err != nil && r == "" } @@ -164,15 +175,38 @@ func (e SignatureError) Error() string { return fmt.Sprintf("dbus: invalid signature: %q (%s)", e.Sig, e.Reason) } +type depthCounter struct { + arrayDepth, structDepth, dictEntryDepth int +} + +func (cnt *depthCounter) Valid() bool { + return cnt.arrayDepth <= 32 && cnt.structDepth <= 32 && cnt.dictEntryDepth <= 32 +} + +func (cnt depthCounter) EnterArray() *depthCounter { + cnt.arrayDepth++ + return &cnt +} + +func (cnt depthCounter) EnterStruct() *depthCounter { + cnt.structDepth++ + return &cnt +} + +func (cnt depthCounter) EnterDictEntry() *depthCounter { + cnt.dictEntryDepth++ + return &cnt +} + // Try to read a single type from this string. If it was successful, err is nil // and rem is the remaining unparsed part. Otherwise, err is a non-nil // SignatureError and rem is "". depth is the current recursion depth which may // not be greater than 64 and should be given as 0 on the first call. -func validSingle(s string, depth int) (err error, rem string) { +func validSingle(s string, depth *depthCounter) (err error, rem string) { if s == "" { return SignatureError{Sig: s, Reason: "empty signature"}, "" } - if depth > 64 { + if !depth.Valid() { return SignatureError{Sig: s, Reason: "container nesting too deep"}, "" } switch s[0] { @@ -187,10 +221,10 @@ func validSingle(s string, depth int) (err error, rem string) { i++ rem = s[i+1:] s = s[2:i] - if err, _ = validSingle(s[:1], depth+1); err != nil { + if err, _ = validSingle(s[:1], depth.EnterArray().EnterDictEntry()); err != nil { return err, "" } - err, nr := validSingle(s[1:], depth+1) + err, nr := validSingle(s[1:], depth.EnterArray().EnterDictEntry()) if err != nil { return err, "" } @@ -199,7 +233,7 @@ func validSingle(s string, depth int) (err error, rem string) { } return nil, rem } - return validSingle(s[1:], depth+1) + return validSingle(s[1:], depth.EnterArray()) case '(': i := findMatching(s, '(', ')') if i == -1 { @@ -208,7 +242,7 @@ func validSingle(s string, depth int) (err error, rem string) { rem = s[i+1:] s = s[1:i] for err == nil && s != "" { - err, s = validSingle(s, depth+1) + err, s = validSingle(s, depth.EnterStruct()) } if err != nil { rem = "" @@ -236,7 +270,7 @@ func findMatching(s string, left, right rune) int { // typeFor returns the type of the given signature. It ignores any left over // characters and panics if s doesn't start with a valid type signature. func typeFor(s string) (t reflect.Type) { - err, _ := validSingle(s, 0) + err, _ := validSingle(s, &depthCounter{}) if err != nil { panic(err) } diff --git a/vendor/github.com/godbus/dbus/v5/transport_generic.go b/vendor/github.com/godbus/dbus/v5/transport_generic.go index 718a1ff0219a1..a08e2813ca53c 100644 --- a/vendor/github.com/godbus/dbus/v5/transport_generic.go +++ b/vendor/github.com/godbus/dbus/v5/transport_generic.go @@ -41,10 +41,12 @@ func (t genericTransport) ReadMessage() (*Message, error) { } func (t genericTransport) SendMessage(msg *Message) error { - for _, v := range msg.Body { - if _, ok := v.(UnixFD); ok { - return errors.New("dbus: unix fd passing not enabled") - } + fds, err := msg.CountFds() + if err != nil { + return err + } + if fds != 0 { + return errors.New("dbus: unix fd passing not enabled") } return msg.EncodeTo(t, nativeEndian) } diff --git a/vendor/github.com/godbus/dbus/v5/transport_unix.go b/vendor/github.com/godbus/dbus/v5/transport_unix.go index c7cd02f97fdf2..2212e7fa7f2d8 100644 --- a/vendor/github.com/godbus/dbus/v5/transport_unix.go +++ b/vendor/github.com/godbus/dbus/v5/transport_unix.go @@ -113,7 +113,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) { if _, err := io.ReadFull(t.rdr, headerdata[4:]); err != nil { return nil, err } - dec := newDecoder(bytes.NewBuffer(headerdata), order) + dec := newDecoder(bytes.NewBuffer(headerdata), order, make([]int, 0)) dec.pos = 12 vs, err := dec.Decode(Signature{"a(yv)"}) if err != nil { @@ -147,7 +147,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) { if err != nil { return nil, err } - msg, err := DecodeMessage(bytes.NewBuffer(all)) + msg, err := DecodeMessageWithFDs(bytes.NewBuffer(all), fds) if err != nil { return nil, err } @@ -179,21 +179,21 @@ func (t *unixTransport) ReadMessage() (*Message, error) { } func (t *unixTransport) SendMessage(msg *Message) error { - fds := make([]int, 0) - for i, v := range msg.Body { - if fd, ok := v.(UnixFD); ok { - msg.Body[i] = UnixFDIndex(len(fds)) - fds = append(fds, int(fd)) - } + fdcnt, err := msg.CountFds() + if err != nil { + return err } - if len(fds) != 0 { + if fdcnt != 0 { if !t.hasUnixFDs { return errors.New("dbus: unix fd passing not enabled") } - msg.Headers[FieldUnixFDs] = MakeVariant(uint32(len(fds))) - oob := syscall.UnixRights(fds...) + msg.Headers[FieldUnixFDs] = MakeVariant(uint32(fdcnt)) buf := new(bytes.Buffer) - msg.EncodeTo(buf, nativeEndian) + fds, err := msg.EncodeToWithFDs(buf, nativeEndian) + if err != nil { + return err + } + oob := syscall.UnixRights(fds...) n, oobn, err := t.UnixConn.WriteMsgUnix(buf.Bytes(), oob, nil) if err != nil { return err diff --git a/vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go b/vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go new file mode 100644 index 0000000000000..af7bafdf953b8 --- /dev/null +++ b/vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go @@ -0,0 +1,14 @@ +package dbus + +import "io" + +func (t *unixTransport) SendNullByte() error { + n, _, err := t.UnixConn.WriteMsgUnix([]byte{0}, nil, nil) + if err != nil { + return err + } + if n != 1 { + return io.ErrShortWrite + } + return nil +} diff --git a/vendor/github.com/google/cadvisor/container/common/helpers.go b/vendor/github.com/google/cadvisor/container/common/helpers.go index 03d055f93b9fc..2b232f6ac555c 100644 --- a/vendor/github.com/google/cadvisor/container/common/helpers.go +++ b/vendor/github.com/google/cadvisor/container/common/helpers.go @@ -105,7 +105,7 @@ func getSpecInternal(cgroupPaths map[string]string, machineInfoFactory info.Mach } // CPU. - cpuRoot, ok := getControllerPath(cgroupPaths, "cpu", cgroup2UnifiedMode) + cpuRoot, ok := GetControllerPath(cgroupPaths, "cpu", cgroup2UnifiedMode) if ok { if utils.FileExists(cpuRoot) { if cgroup2UnifiedMode { @@ -152,7 +152,7 @@ func getSpecInternal(cgroupPaths map[string]string, machineInfoFactory info.Mach // Cpu Mask. // This will fail for non-unified hierarchies. We'll return the whole machine mask in that case. - cpusetRoot, ok := getControllerPath(cgroupPaths, "cpuset", cgroup2UnifiedMode) + cpusetRoot, ok := GetControllerPath(cgroupPaths, "cpuset", cgroup2UnifiedMode) if ok { if utils.FileExists(cpusetRoot) { spec.HasCpu = true @@ -167,7 +167,7 @@ func getSpecInternal(cgroupPaths map[string]string, machineInfoFactory info.Mach } // Memory - memoryRoot, ok := getControllerPath(cgroupPaths, "memory", cgroup2UnifiedMode) + memoryRoot, ok := GetControllerPath(cgroupPaths, "memory", cgroup2UnifiedMode) if ok { if cgroup2UnifiedMode { if utils.FileExists(path.Join(memoryRoot, "memory.max")) { @@ -195,7 +195,7 @@ func getSpecInternal(cgroupPaths map[string]string, machineInfoFactory info.Mach } // Processes, read it's value from pids path directly - pidsRoot, ok := getControllerPath(cgroupPaths, "pids", cgroup2UnifiedMode) + pidsRoot, ok := GetControllerPath(cgroupPaths, "pids", cgroup2UnifiedMode) if ok { if utils.FileExists(pidsRoot) { spec.HasProcesses = true @@ -217,7 +217,7 @@ func getSpecInternal(cgroupPaths map[string]string, machineInfoFactory info.Mach return spec, nil } -func getControllerPath(cgroupPaths map[string]string, controllerName string, cgroup2UnifiedMode bool) (string, bool) { +func GetControllerPath(cgroupPaths map[string]string, controllerName string, cgroup2UnifiedMode bool) (string, bool) { ok := false path := "" diff --git a/vendor/github.com/google/cadvisor/container/libcontainer/handler.go b/vendor/github.com/google/cadvisor/container/libcontainer/handler.go index e599029386da6..ed4c1ae8535b6 100644 --- a/vendor/github.com/google/cadvisor/container/libcontainer/handler.go +++ b/vendor/github.com/google/cadvisor/container/libcontainer/handler.go @@ -35,6 +35,7 @@ import ( "k8s.io/klog/v2" "github.com/google/cadvisor/container" + "github.com/google/cadvisor/container/common" info "github.com/google/cadvisor/info/v1" ) @@ -169,8 +170,7 @@ func (h *Handler) GetStats() (*info.ContainerStats, error) { // file descriptors etc.) and not required a proper container's // root PID (systemd services don't have the root PID atm) if h.includedMetrics.Has(container.ProcessMetrics) { - paths := h.cgroupManager.GetPaths() - path, ok := paths["cpu"] + path, ok := common.GetControllerPath(h.cgroupManager.GetPaths(), "cpu", cgroups.IsCgroup2UnifiedMode()) if !ok { klog.V(4).Infof("Could not find cgroups CPU for container %d", h.pid) } else { diff --git a/vendor/github.com/google/cadvisor/container/libcontainer/helpers.go b/vendor/github.com/google/cadvisor/container/libcontainer/helpers.go index e0d7718c876d5..e535ad64c46b3 100644 --- a/vendor/github.com/google/cadvisor/container/libcontainer/helpers.go +++ b/vendor/github.com/google/cadvisor/container/libcontainer/helpers.go @@ -157,13 +157,14 @@ func diskStatsCopy(blkioStats []cgroups.BlkioStatEntry) (stat []info.PerDiskStat } func NewCgroupManager(name string, paths map[string]string) (cgroups.Manager, error) { + config := &configs.Cgroup{ + Name: name, + Resources: &configs.Resources{}, + } if cgroups.IsCgroup2UnifiedMode() { path := paths[""] - return fs2.NewManager(nil, path, false) + return fs2.NewManager(config, path) } - config := configs.Cgroup{ - Name: name, - } - return fs.NewManager(&config, paths, false), nil + return fs.NewManager(config, paths) } diff --git a/vendor/github.com/google/cadvisor/fs/fs.go b/vendor/github.com/google/cadvisor/fs/fs.go index f5d4e49ada91a..e1a1bc41e27e5 100644 --- a/vendor/github.com/google/cadvisor/fs/fs.go +++ b/vendor/github.com/google/cadvisor/fs/fs.go @@ -20,7 +20,6 @@ package fs import ( "bufio" - "errors" "fmt" "io/ioutil" "os" @@ -59,9 +58,6 @@ const ( // A pool for restricting the number of consecutive `du` and `find` tasks running. var pool = make(chan struct{}, maxConcurrentOps) -// ErrDeviceNotInPartitionsMap is the error resulting if a device could not be found in the partitions map. -var ErrDeviceNotInPartitionsMap = errors.New("could not find device in cached partitions map") - func init() { for i := 0; i < maxConcurrentOps; i++ { releaseToken() diff --git a/vendor/github.com/google/cadvisor/fs/types.go b/vendor/github.com/google/cadvisor/fs/types.go index 0445a17adbe31..35268ace984ea 100644 --- a/vendor/github.com/google/cadvisor/fs/types.go +++ b/vendor/github.com/google/cadvisor/fs/types.go @@ -86,8 +86,13 @@ type UsageInfo struct { Inodes uint64 } -// ErrNoSuchDevice is the error indicating the requested device does not exist. -var ErrNoSuchDevice = errors.New("cadvisor: no such device") +var ( + // ErrNoSuchDevice is the error indicating the requested device does not exist. + ErrNoSuchDevice = errors.New("cadvisor: no such device") + + // ErrDeviceNotInPartitionsMap is the error resulting if a device could not be found in the partitions map. + ErrDeviceNotInPartitionsMap = errors.New("could not find device in cached partitions map") +) type FsInfo interface { // Returns capacity and free space, in bytes, of all the ext2, ext3, ext4 filesystems on the host. diff --git a/vendor/github.com/google/cadvisor/manager/container.go b/vendor/github.com/google/cadvisor/manager/container.go index db2e2b113b189..a5f2040a6fa10 100644 --- a/vendor/github.com/google/cadvisor/manager/container.go +++ b/vendor/github.com/google/cadvisor/manager/container.go @@ -64,6 +64,7 @@ type containerInfo struct { } type containerData struct { + oomEvents uint64 handler container.ContainerHandler info containerInfo memoryCache *memory.InMemoryCache @@ -103,8 +104,6 @@ type containerData struct { // resctrlCollector updates stats for resctrl controller. resctrlCollector stats.Collector - - oomEvents uint64 } // jitter returns a time.Duration between duration and duration + maxFactor * duration, diff --git a/vendor/github.com/google/cadvisor/manager/manager.go b/vendor/github.com/google/cadvisor/manager/manager.go index ca55537c5bebd..5ef1dff8fea22 100644 --- a/vendor/github.com/google/cadvisor/manager/manager.go +++ b/vendor/github.com/google/cadvisor/manager/manager.go @@ -158,7 +158,7 @@ func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs, houskeepingConfig if cgroups.IsCgroup2UnifiedMode() { klog.Warningf("Cannot detect current cgroup on cgroup v2") } else { - selfContainer, err := cgroups.GetOwnCgroupPath("cpu") + selfContainer, err = cgroups.GetOwnCgroup("cpu") if err != nil { return nil, err } diff --git a/vendor/github.com/google/cadvisor/resctrl/utils.go b/vendor/github.com/google/cadvisor/resctrl/utils.go index f7931d22ebfac..e282167407531 100644 --- a/vendor/github.com/google/cadvisor/resctrl/utils.go +++ b/vendor/github.com/google/cadvisor/resctrl/utils.go @@ -77,7 +77,7 @@ var ( func Setup() error { var err error - rootResctrl, err = intelrdt.GetIntelRdtPath(rootContainer) + rootResctrl, err = intelrdt.Root() if err != nil { return fmt.Errorf("unable to initialize resctrl: %v", err) } diff --git a/vendor/github.com/moby/sys/mountinfo/go.mod b/vendor/github.com/moby/sys/mountinfo/go.mod index 9749ea96d9d5d..1cc3efcf74824 100644 --- a/vendor/github.com/moby/sys/mountinfo/go.mod +++ b/vendor/github.com/moby/sys/mountinfo/go.mod @@ -1,5 +1,5 @@ module github.com/moby/sys/mountinfo -go 1.14 +go 1.16 -require golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 +require golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 diff --git a/vendor/github.com/moby/sys/mountinfo/go.sum b/vendor/github.com/moby/sys/mountinfo/go.sum index 2a5be7ea84380..c257a6a29d544 100644 --- a/vendor/github.com/moby/sys/mountinfo/go.sum +++ b/vendor/github.com/moby/sys/mountinfo/go.sum @@ -1,2 +1,2 @@ -golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM= -golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/vendor/github.com/moby/sys/mountinfo/mounted_linux.go b/vendor/github.com/moby/sys/mountinfo/mounted_linux.go index bc9f6b2ad3d7f..5c9e3e30e6622 100644 --- a/vendor/github.com/moby/sys/mountinfo/mounted_linux.go +++ b/vendor/github.com/moby/sys/mountinfo/mounted_linux.go @@ -16,9 +16,6 @@ func mountedByOpenat2(path string) (bool, error) { Flags: unix.O_PATH | unix.O_CLOEXEC, }) if err != nil { - if err == unix.ENOENT { // not a mount - return false, nil - } return false, &os.PathError{Op: "openat2", Path: dir, Err: err} } fd, err := unix.Openat2(dirfd, last, &unix.OpenHow{ @@ -26,20 +23,22 @@ func mountedByOpenat2(path string) (bool, error) { Resolve: unix.RESOLVE_NO_XDEV, }) _ = unix.Close(dirfd) - switch err { + switch err { //nolint:errorlint // unix errors are bare case nil: // definitely not a mount _ = unix.Close(fd) return false, nil case unix.EXDEV: // definitely a mount return true, nil - case unix.ENOENT: // not a mount - return false, nil } // not sure return false, &os.PathError{Op: "openat2", Path: path, Err: err} } func mounted(path string) (bool, error) { + path, err := normalizePath(path) + if err != nil { + return false, err + } // Try a fast path, using openat2() with RESOLVE_NO_XDEV. mounted, err := mountedByOpenat2(path) if err == nil { diff --git a/vendor/github.com/moby/sys/mountinfo/mounted_unix.go b/vendor/github.com/moby/sys/mountinfo/mounted_unix.go index efb03978b1e30..45ddad236f341 100644 --- a/vendor/github.com/moby/sys/mountinfo/mounted_unix.go +++ b/vendor/github.com/moby/sys/mountinfo/mounted_unix.go @@ -1,9 +1,9 @@ -// +build linux freebsd,cgo openbsd,cgo +//go:build linux || (freebsd && cgo) || (openbsd && cgo) || (darwin && cgo) +// +build linux freebsd,cgo openbsd,cgo darwin,cgo package mountinfo import ( - "errors" "fmt" "os" "path/filepath" @@ -15,10 +15,6 @@ func mountedByStat(path string) (bool, error) { var st unix.Stat_t if err := unix.Lstat(path, &st); err != nil { - if err == unix.ENOENT { - // Treat ENOENT as "not mounted". - return false, nil - } return false, &os.PathError{Op: "stat", Path: path, Err: err} } dev := st.Dev @@ -49,14 +45,6 @@ func normalizePath(path string) (realPath string, err error) { } func mountedByMountinfo(path string) (bool, error) { - path, err := normalizePath(path) - if err != nil { - if errors.Is(err, unix.ENOENT) { - // treat ENOENT as "not mounted" - return false, nil - } - return false, err - } entries, err := GetMounts(SingleEntryFilter(path)) if err != nil { return false, err diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo.go b/vendor/github.com/moby/sys/mountinfo/mountinfo.go index 403a893310b40..9867a66dd85a6 100644 --- a/vendor/github.com/moby/sys/mountinfo/mountinfo.go +++ b/vendor/github.com/moby/sys/mountinfo/mountinfo.go @@ -10,11 +10,12 @@ func GetMounts(f FilterFunc) ([]*Info, error) { return parseMountTable(f) } -// Mounted determines if a specified path is a mount point. +// Mounted determines if a specified path is a mount point. In case of any +// error, false (and an error) is returned. // -// The argument must be an absolute path, with all symlinks resolved, and clean. -// One way to ensure it is to process the path using filepath.Abs followed by -// filepath.EvalSymlinks before calling this function. +// The non-existent path returns an error. If a caller is not interested +// in this particular error, it should handle it separately using e.g. +// errors.Is(err, os.ErrNotExist). func Mounted(path string) (bool, error) { // root is always mounted if path == string(os.PathSeparator) { diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_bsd.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_bsd.go index b1c12d02b51ed..d5513a26d2fa6 100644 --- a/vendor/github.com/moby/sys/mountinfo/mountinfo_bsd.go +++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_bsd.go @@ -1,4 +1,5 @@ -// +build freebsd,cgo openbsd,cgo +//go:build (freebsd && cgo) || (openbsd && cgo) || (darwin && cgo) +// +build freebsd,cgo openbsd,cgo darwin,cgo package mountinfo @@ -21,7 +22,7 @@ func parseMountTable(filter FilterFunc) ([]*Info, error) { count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT)) if count == 0 { - return nil, fmt.Errorf("Failed to call getmntinfo") + return nil, fmt.Errorf("failed to call getmntinfo") } var entries []C.struct_statfs @@ -55,6 +56,10 @@ func parseMountTable(filter FilterFunc) ([]*Info, error) { } func mounted(path string) (bool, error) { + path, err := normalizePath(path) + if err != nil { + return false, err + } // Fast path: compare st.st_dev fields. // This should always work for FreeBSD and OpenBSD. mounted, err := mountedByStat(path) diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go index f09a70fa0d9d5..59332b07bf4b1 100644 --- a/vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go +++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go @@ -52,7 +52,7 @@ func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) { numFields := len(fields) if numFields < 10 { // should be at least 10 fields - return nil, fmt.Errorf("Parsing '%s' failed: not enough fields (%d)", text, numFields) + return nil, fmt.Errorf("parsing '%s' failed: not enough fields (%d)", text, numFields) } // separator field @@ -67,7 +67,7 @@ func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) { for fields[sepIdx] != "-" { sepIdx-- if sepIdx == 5 { - return nil, fmt.Errorf("Parsing '%s' failed: missing - separator", text) + return nil, fmt.Errorf("parsing '%s' failed: missing - separator", text) } } @@ -75,46 +75,39 @@ func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) { p.Mountpoint, err = unescape(fields[4]) if err != nil { - return nil, fmt.Errorf("Parsing '%s' failed: mount point: %w", fields[4], err) + return nil, fmt.Errorf("parsing '%s' failed: mount point: %w", fields[4], err) } p.FSType, err = unescape(fields[sepIdx+1]) if err != nil { - return nil, fmt.Errorf("Parsing '%s' failed: fstype: %w", fields[sepIdx+1], err) + return nil, fmt.Errorf("parsing '%s' failed: fstype: %w", fields[sepIdx+1], err) } p.Source, err = unescape(fields[sepIdx+2]) if err != nil { - return nil, fmt.Errorf("Parsing '%s' failed: source: %w", fields[sepIdx+2], err) + return nil, fmt.Errorf("parsing '%s' failed: source: %w", fields[sepIdx+2], err) } p.VFSOptions = fields[sepIdx+3] // ignore any numbers parsing errors, as there should not be any p.ID, _ = strconv.Atoi(fields[0]) p.Parent, _ = strconv.Atoi(fields[1]) - mm := strings.Split(fields[2], ":") + mm := strings.SplitN(fields[2], ":", 3) if len(mm) != 2 { - return nil, fmt.Errorf("Parsing '%s' failed: unexpected minor:major pair %s", text, mm) + return nil, fmt.Errorf("parsing '%s' failed: unexpected major:minor pair %s", text, mm) } p.Major, _ = strconv.Atoi(mm[0]) p.Minor, _ = strconv.Atoi(mm[1]) p.Root, err = unescape(fields[3]) if err != nil { - return nil, fmt.Errorf("Parsing '%s' failed: root: %w", fields[3], err) + return nil, fmt.Errorf("parsing '%s' failed: root: %w", fields[3], err) } p.Options = fields[5] // zero or more optional fields - switch { - case sepIdx == 6: - // zero, do nothing - case sepIdx == 7: - p.Optional = fields[6] - default: - p.Optional = strings.Join(fields[6:sepIdx-1], " ") - } + p.Optional = strings.Join(fields[6:sepIdx], " ") - // Run the filter after parsing all of the fields. + // Run the filter after parsing all fields. var skip, stop bool if filter != nil { skip, stop = filter(p) diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go index d33ebca096881..95769a76dadb1 100644 --- a/vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go +++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go @@ -1,4 +1,5 @@ -// +build !windows,!linux,!freebsd,!openbsd freebsd,!cgo openbsd,!cgo +//go:build (!windows && !linux && !freebsd && !openbsd && !darwin) || (freebsd && !cgo) || (openbsd && !cgo) || (darwin && !cgo) +// +build !windows,!linux,!freebsd,!openbsd,!darwin freebsd,!cgo openbsd,!cgo darwin,!cgo package mountinfo diff --git a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go index 744d4e57054db..8b1483c7de776 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go @@ -3,7 +3,6 @@ package apparmor import ( "errors" "fmt" - "io/ioutil" "os" "sync" @@ -19,7 +18,7 @@ var ( func isEnabled() bool { checkAppArmor.Do(func() { if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil { - buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled") + buf, err := os.ReadFile("/sys/module/apparmor/parameters/enabled") appArmorEnabled = err == nil && len(buf) > 1 && buf[0] == 'Y' } }) @@ -52,7 +51,7 @@ func setProcAttr(attr, value string) error { // changeOnExec reimplements aa_change_onexec from libapparmor in Go func changeOnExec(name string) error { if err := setProcAttr("exec", "exec "+name); err != nil { - return fmt.Errorf("apparmor failed to apply profile: %s", err) + return fmt.Errorf("apparmor failed to apply profile: %w", err) } return nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_unsupported.go index 1adadafec8ec6..684248f2559ee 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_unsupported.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_unsupported.go @@ -1,3 +1,4 @@ +//go:build !linux // +build !linux package apparmor diff --git a/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities.go b/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities.go index 1099d32b14604..d38b8a7cd89a7 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux package capabilities @@ -34,6 +35,17 @@ func init() { } } +// KnownCapabilities returns the list of the known capabilities. +// Used by `runc features`. +func KnownCapabilities() []string { + list := capability.List() + res := make([]string, len(list)) + for i, c := range list { + res[i] = "CAP_" + strings.ToUpper(c.String()) + } + return res +} + // New creates a new Caps from the given Capabilities config. Unknown Capabilities // or Capabilities that are unavailable in the current environment are ignored, // printing a warning instead. diff --git a/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities_unsupported.go index a3e82ac1fd4d1..0eafa4f2c2c75 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities_unsupported.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities_unsupported.go @@ -1,3 +1,4 @@ +//go:build !linux // +build !linux package capabilities diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go index 68a346ca531ad..ba2b2266c9d02 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go @@ -1,5 +1,3 @@ -// +build linux - package cgroups import ( diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups_unsupported.go deleted file mode 100644 index 278d507e288e8..0000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups_unsupported.go +++ /dev/null @@ -1,3 +0,0 @@ -// +build !linux - -package cgroups diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/devices/devices_emulator.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/devices/devices_emulator.go index c08477cbb354a..6c61ee4c0330b 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/devices/devices_emulator.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/devices/devices_emulator.go @@ -1,5 +1,3 @@ -// +build linux - // SPDX-License-Identifier: Apache-2.0 /* * Copyright (C) 2020 Aleksa Sarai @@ -22,14 +20,13 @@ package devices import ( "bufio" + "fmt" "io" - "regexp" "sort" "strconv" + "strings" "github.com/opencontainers/runc/libcontainer/devices" - - "github.com/pkg/errors" ) // deviceMeta is a Rule without the Allow or Permissions fields, and no @@ -79,19 +76,21 @@ func (e *Emulator) IsAllowAll() bool { return e.IsBlacklist() && len(e.rules) == 0 } -var devicesListRegexp = regexp.MustCompile(`^([abc])\s+(\d+|\*):(\d+|\*)\s+([rwm]+)$`) - func parseLine(line string) (*deviceRule, error) { - matches := devicesListRegexp.FindStringSubmatch(line) - if matches == nil { - return nil, errors.Errorf("line doesn't match devices.list format") + // Input: node major:minor perms. + fields := strings.FieldsFunc(line, func(r rune) bool { + return r == ' ' || r == ':' + }) + if len(fields) != 4 { + return nil, fmt.Errorf("malformed devices.list rule %s", line) } + var ( rule deviceRule - node = matches[1] - major = matches[2] - minor = matches[3] - perms = matches[4] + node = fields[0] + major = fields[1] + minor = fields[2] + perms = fields[3] ) // Parse the node type. @@ -107,8 +106,7 @@ func parseLine(line string) (*deviceRule, error) { case "c": rule.meta.node = devices.CharDevice default: - // Should never happen! - return nil, errors.Errorf("unknown device type %q", node) + return nil, fmt.Errorf("unknown device type %q", node) } // Parse the major number. @@ -117,7 +115,7 @@ func parseLine(line string) (*deviceRule, error) { } else { val, err := strconv.ParseUint(major, 10, 32) if err != nil { - return nil, errors.Wrap(err, "parse major number") + return nil, fmt.Errorf("invalid major number: %w", err) } rule.meta.major = int64(val) } @@ -128,7 +126,7 @@ func parseLine(line string) (*deviceRule, error) { } else { val, err := strconv.ParseUint(minor, 10, 32) if err != nil { - return nil, errors.Wrap(err, "parse minor number") + return nil, fmt.Errorf("invalid minor number: %w", err) } rule.meta.minor = int64(val) } @@ -136,13 +134,12 @@ func parseLine(line string) (*deviceRule, error) { // Parse the access permissions. rule.perms = devices.Permissions(perms) if !rule.perms.IsValid() || rule.perms.IsEmpty() { - // Should never happen! - return nil, errors.Errorf("parse access mode: contained unknown modes or is empty: %q", perms) + return nil, fmt.Errorf("parse access mode: contained unknown modes or is empty: %q", perms) } return &rule, nil } -func (e *Emulator) addRule(rule deviceRule) error { +func (e *Emulator) addRule(rule deviceRule) error { //nolint:unparam if e.rules == nil { e.rules = make(map[deviceMeta]devices.Permissions) } @@ -180,7 +177,7 @@ func (e *Emulator) rmRule(rule deviceRule) error { // Only give an error if the set of permissions overlap. partialPerms := e.rules[partialMeta] if !partialPerms.Intersection(rule.perms).IsEmpty() { - return errors.Errorf("requested rule [%v %v] not supported by devices cgroupv1 (cannot punch hole in existing wildcard rule [%v %v])", rule.meta, rule.perms, partialMeta, partialPerms) + return fmt.Errorf("requested rule [%v %v] not supported by devices cgroupv1 (cannot punch hole in existing wildcard rule [%v %v])", rule.meta, rule.perms, partialMeta, partialPerms) } } @@ -212,9 +209,9 @@ func (e *Emulator) allow(rule *deviceRule) error { var err error if e.defaultAllow { - err = errors.Wrap(e.rmRule(*rule), "remove 'deny' exception") + err = wrapErr(e.rmRule(*rule), "unable to remove 'deny' exception") } else { - err = errors.Wrap(e.addRule(*rule), "add 'allow' exception") + err = wrapErr(e.addRule(*rule), "unable to add 'allow' exception") } return err } @@ -232,16 +229,16 @@ func (e *Emulator) deny(rule *deviceRule) error { var err error if e.defaultAllow { - err = errors.Wrap(e.addRule(*rule), "add 'deny' exception") + err = wrapErr(e.addRule(*rule), "unable to add 'deny' exception") } else { - err = errors.Wrap(e.rmRule(*rule), "remove 'allow' exception") + err = wrapErr(e.rmRule(*rule), "unable to remove 'allow' exception") } return err } func (e *Emulator) Apply(rule devices.Rule) error { if !rule.Type.CanCgroup() { - return errors.Errorf("cannot add rule [%#v] with non-cgroup type %q", rule, rule.Type) + return fmt.Errorf("cannot add rule [%#v] with non-cgroup type %q", rule, rule.Type) } innerRule := &deviceRule{ @@ -283,17 +280,17 @@ func EmulatorFromList(list io.Reader) (*Emulator, error) { line := s.Text() deviceRule, err := parseLine(line) if err != nil { - return nil, errors.Wrapf(err, "parsing line %q", line) + return nil, fmt.Errorf("error parsing line %q: %w", line, err) } // "devices.list" is an allow list. Note that this means that in // black-list mode, we have no idea what rules are in play. As a // result, we need to be very careful in Transition(). if err := e.allow(deviceRule); err != nil { - return nil, errors.Wrapf(err, "adding devices.list rule") + return nil, fmt.Errorf("error adding devices.list rule: %w", err) } } if err := s.Err(); err != nil { - return nil, errors.Wrap(err, "reading devices.list lines") + return nil, fmt.Errorf("error reading devices.list lines: %w", err) } return e, nil } @@ -305,7 +302,7 @@ func EmulatorFromList(list io.Reader) (*Emulator, error) { // necessary. // // This function is the sole reason for all of Emulator -- to allow us -// to figure out how to update a containers' cgroups without causing spurrious +// to figure out how to update a containers' cgroups without causing spurious // device errors (if possible). func (source *Emulator) Transition(target *Emulator) ([]*devices.Rule, error) { var transitionRules []*devices.Rule @@ -380,3 +377,10 @@ func (e *Emulator) Rules() ([]*devices.Rule, error) { defaultCgroup := &Emulator{defaultAllow: false} return defaultCgroup.Transition(e) } + +func wrapErr(err error, text string) error { + if err == nil { + return nil + } + return fmt.Errorf(text+": %w", err) +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go index 96cbca3916e50..4e69b35bcdaaf 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go @@ -7,13 +7,14 @@ package devicefilter import ( + "errors" + "fmt" "math" "strconv" "github.com/cilium/ebpf/asm" devicesemulator "github.com/opencontainers/runc/libcontainer/cgroups/devices" "github.com/opencontainers/runc/libcontainer/devices" - "github.com/pkg/errors" "golang.org/x/sys/unix" ) @@ -51,21 +52,20 @@ func DeviceFilter(rules []*devices.Rule) (asm.Instructions, string, error) { // only be one (at most) at the very start to instruct cgroupv1 to // go into allow-list mode. However we do double-check this here. if idx != 0 || rule.Allow != emu.IsBlacklist() { - return nil, "", errors.Errorf("[internal error] emulated cgroupv2 devices ruleset had bad wildcard at idx %v (%s)", idx, rule.CgroupString()) + return nil, "", fmt.Errorf("[internal error] emulated cgroupv2 devices ruleset had bad wildcard at idx %v (%s)", idx, rule.CgroupString()) } continue } if rule.Allow == p.defaultAllow { // There should be no rules which have an action equal to the // default action, the emulator removes those. - return nil, "", errors.Errorf("[internal error] emulated cgroupv2 devices ruleset had no-op rule at idx %v (%s)", idx, rule.CgroupString()) + return nil, "", fmt.Errorf("[internal error] emulated cgroupv2 devices ruleset had no-op rule at idx %v (%s)", idx, rule.CgroupString()) } if err := p.appendRule(rule); err != nil { return nil, "", err } } - insts, err := p.finalize() - return insts, license, err + return p.finalize(), license, nil } type program struct { @@ -118,13 +118,13 @@ func (p *program) appendRule(rule *devices.Rule) error { bpfType = int32(unix.BPF_DEVCG_DEV_BLOCK) default: // We do not permit 'a', nor any other types we don't know about. - return errors.Errorf("invalid type %q", string(rule.Type)) + return fmt.Errorf("invalid type %q", string(rule.Type)) } if rule.Major > math.MaxUint32 { - return errors.Errorf("invalid major %d", rule.Major) + return fmt.Errorf("invalid major %d", rule.Major) } if rule.Minor > math.MaxUint32 { - return errors.Errorf("invalid minor %d", rule.Major) + return fmt.Errorf("invalid minor %d", rule.Major) } hasMajor := rule.Major >= 0 // if not specified in OCI json, major is set to -1 hasMinor := rule.Minor >= 0 @@ -138,7 +138,7 @@ func (p *program) appendRule(rule *devices.Rule) error { case 'm': bpfAccess |= unix.BPF_DEVCG_ACC_MKNOD default: - return errors.Errorf("unknown device access %v", r) + return fmt.Errorf("unknown device access %v", r) } } // If the access is rwm, skip the check. @@ -180,7 +180,7 @@ func (p *program) appendRule(rule *devices.Rule) error { return nil } -func (p *program) finalize() (asm.Instructions, error) { +func (p *program) finalize() asm.Instructions { var v int32 if p.defaultAllow { v = 1 @@ -192,7 +192,7 @@ func (p *program) finalize() (asm.Instructions, error) { asm.Return(), ) p.blockID = -1 - return p.insts, nil + return p.insts } func acceptBlock(accept bool) asm.Instructions { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/ebpf_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/ebpf_linux.go index 6c8de80dd865f..104c74a890f81 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/ebpf_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/ebpf_linux.go @@ -1,6 +1,7 @@ package ebpf import ( + "errors" "fmt" "os" "runtime" @@ -10,7 +11,6 @@ import ( "github.com/cilium/ebpf" "github.com/cilium/ebpf/asm" "github.com/cilium/ebpf/link" - "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) @@ -134,7 +134,7 @@ func haveBpfProgReplace() bool { // not supported return } - // attach_flags test succeded. + // attach_flags test succeeded. if !errors.Is(err, unix.EBADF) { logrus.Debugf("checking for BPF_F_REPLACE: got unexpected (not EBADF or EINVAL) error: %v", err) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go index 5f6ab9fd69991..0cdaf747849f2 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go @@ -2,20 +2,27 @@ package cgroups import ( "bytes" + "errors" + "fmt" "os" + "path" + "strconv" "strings" "sync" - "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) // OpenFile opens a cgroup file in a given dir with given flags. -// It is supposed to be used for cgroup files only. +// It is supposed to be used for cgroup files only, and returns +// an error if the file is not a cgroup file. +// +// Arguments dir and file are joined together to form an absolute path +// to a file being opened. func OpenFile(dir, file string, flags int) (*os.File, error) { if dir == "" { - return nil, errors.Errorf("no directory specified for %s", file) + return nil, fmt.Errorf("no directory specified for %s", file) } return openFile(dir, file, flags) } @@ -43,7 +50,8 @@ func WriteFile(dir, file, data string) error { } defer fd.Close() if err := retryingWriteFile(fd, data); err != nil { - return errors.Wrapf(err, "failed to write %q", data) + // Having data in the error message helps in debugging. + return fmt.Errorf("failed to write %q: %w", data, err) } return nil } @@ -81,7 +89,7 @@ func prepareOpenat2() error { }) if err != nil { prepErr = &os.PathError{Op: "openat2", Path: cgroupfsDir, Err: err} - if err != unix.ENOSYS { + if err != unix.ENOSYS { //nolint:errorlint // unix errors are bare logrus.Warnf("falling back to securejoin: %s", prepErr) } else { logrus.Debug("openat2 not available, falling back to securejoin") @@ -107,8 +115,6 @@ func prepareOpenat2() error { return prepErr } -// OpenFile opens a cgroup file in a given dir with given flags. -// It is supposed to be used for cgroup files only. func openFile(dir, file string, flags int) (*os.File, error) { mode := os.FileMode(0) if TestMode && flags&os.O_WRONLY != 0 { @@ -116,34 +122,52 @@ func openFile(dir, file string, flags int) (*os.File, error) { flags |= os.O_TRUNC | os.O_CREATE mode = 0o600 } + path := path.Join(dir, file) if prepareOpenat2() != nil { - return openFallback(dir, file, flags, mode) + return openFallback(path, flags, mode) } - reldir := strings.TrimPrefix(dir, cgroupfsPrefix) - if len(reldir) == len(dir) { // non-standard path, old system? - return openFallback(dir, file, flags, mode) + relPath := strings.TrimPrefix(path, cgroupfsPrefix) + if len(relPath) == len(path) { // non-standard path, old system? + return openFallback(path, flags, mode) } - relname := reldir + "/" + file - fd, err := unix.Openat2(cgroupFd, relname, + fd, err := unix.Openat2(cgroupFd, relPath, &unix.OpenHow{ Resolve: resolveFlags, Flags: uint64(flags) | unix.O_CLOEXEC, Mode: uint64(mode), }) if err != nil { - return nil, &os.PathError{Op: "openat2", Path: dir + "/" + file, Err: err} + err = &os.PathError{Op: "openat2", Path: path, Err: err} + // Check if cgroupFd is still opened to cgroupfsDir + // (happens when this package is incorrectly used + // across the chroot/pivot_root/mntns boundary, or + // when /sys/fs/cgroup is remounted). + // + // TODO: if such usage will ever be common, amend this + // to reopen cgroupFd and retry openat2. + fdStr := strconv.Itoa(cgroupFd) + fdDest, _ := os.Readlink("/proc/self/fd/" + fdStr) + if fdDest != cgroupfsDir { + // Wrap the error so it is clear that cgroupFd + // is opened to an unexpected/wrong directory. + err = fmt.Errorf("cgroupFd %s unexpectedly opened to %s != %s: %w", + fdStr, fdDest, cgroupfsDir, err) + } + return nil, err } - return os.NewFile(uintptr(fd), cgroupfsPrefix+relname), nil + return os.NewFile(uintptr(fd), path), nil } var errNotCgroupfs = errors.New("not a cgroup file") -// openFallback is used when openat2(2) is not available. It checks the opened +// Can be changed by unit tests. +var openFallback = openAndCheck + +// openAndCheck is used when openat2(2) is not available. It checks the opened // file is on cgroupfs, returning an error otherwise. -func openFallback(dir, file string, flags int, mode os.FileMode) (*os.File, error) { - path := dir + "/" + file +func openAndCheck(path string, flags int, mode os.FileMode) (*os.File, error) { fd, err := os.OpenFile(path, flags, mode) if err != nil { return nil, err diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio.go index 88012a2f5f187..c81b6562ac50f 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio.go @@ -1,10 +1,7 @@ -// +build linux - package fs import ( "bufio" - "fmt" "os" "path/filepath" "strconv" @@ -23,8 +20,8 @@ func (s *BlkioGroup) Name() string { return "blkio" } -func (s *BlkioGroup) Apply(path string, d *cgroupData) error { - return join(path, d.pid) +func (s *BlkioGroup) Apply(path string, _ *configs.Resources, pid int) error { + return apply(path, pid) } func (s *BlkioGroup) Set(path string, r *configs.Resources) error { @@ -131,19 +128,19 @@ func getBlkioStat(dir, file string) ([]cgroups.BlkioStatEntry, error) { // skip total line continue } else { - return nil, fmt.Errorf("Invalid line found while parsing %s/%s: %s", dir, file, sc.Text()) + return nil, malformedLine(dir, file, sc.Text()) } } v, err := strconv.ParseUint(fields[0], 10, 64) if err != nil { - return nil, err + return nil, &parseError{Path: dir, File: file, Err: err} } major := v v, err = strconv.ParseUint(fields[1], 10, 64) if err != nil { - return nil, err + return nil, &parseError{Path: dir, File: file, Err: err} } minor := v @@ -155,10 +152,13 @@ func getBlkioStat(dir, file string) ([]cgroups.BlkioStatEntry, error) { } v, err = strconv.ParseUint(fields[valueField], 10, 64) if err != nil { - return nil, err + return nil, &parseError{Path: dir, File: file, Err: err} } blkioStats = append(blkioStats, cgroups.BlkioStatEntry{Major: major, Minor: minor, Op: op, Value: v}) } + if err := sc.Err(); err != nil { + return nil, &parseError{Path: dir, File: file, Err: err} + } return blkioStats, nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go index 7ca8b8a8d4080..6c79f899b4846 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go @@ -1,5 +1,3 @@ -// +build linux - package fs import ( @@ -21,24 +19,19 @@ func (s *CpuGroup) Name() string { return "cpu" } -func (s *CpuGroup) Apply(path string, d *cgroupData) error { - // This might happen if we have no cpu cgroup mounted. - // Just do nothing and don't fail. - if path == "" { - return nil - } +func (s *CpuGroup) Apply(path string, r *configs.Resources, pid int) error { if err := os.MkdirAll(path, 0o755); err != nil { return err } // We should set the real-Time group scheduling settings before moving // in the process because if the process is already in SCHED_RR mode // and no RT bandwidth is set, adding it will fail. - if err := s.SetRtSched(path, d.config.Resources); err != nil { + if err := s.SetRtSched(path, r); err != nil { return err } - // Since we are not using join(), we need to place the pid - // into the procs file unlike other subsystems. - return cgroups.WriteCgroupProc(path, d.pid) + // Since we are not using apply(), we need to place the pid + // into the procs file. + return cgroups.WriteCgroupProc(path, pid) } func (s *CpuGroup) SetRtSched(path string, r *configs.Resources) error { @@ -105,7 +98,8 @@ func (s *CpuGroup) Set(path string, r *configs.Resources) error { } func (s *CpuGroup) GetStats(path string, stats *cgroups.Stats) error { - f, err := cgroups.OpenFile(path, "cpu.stat", os.O_RDONLY) + const file = "cpu.stat" + f, err := cgroups.OpenFile(path, file, os.O_RDONLY) if err != nil { if os.IsNotExist(err) { return nil @@ -118,7 +112,7 @@ func (s *CpuGroup) GetStats(path string, stats *cgroups.Stats) error { for sc.Scan() { t, v, err := fscommon.ParseKeyValue(sc.Text()) if err != nil { - return err + return &parseError{Path: path, File: file, Err: err} } switch t { case "nr_periods": diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuacct.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuacct.go index 4fbf078494c24..d3bd7e111c7d1 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuacct.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuacct.go @@ -1,12 +1,8 @@ -// +build linux - package fs import ( "bufio" - "fmt" "os" - "path/filepath" "strconv" "strings" @@ -38,8 +34,8 @@ func (s *CpuacctGroup) Name() string { return "cpuacct" } -func (s *CpuacctGroup) Apply(path string, d *cgroupData) error { - return join(path, d.pid) +func (s *CpuacctGroup) Apply(path string, _ *configs.Resources, pid int) error { + return apply(path, pid) } func (s *CpuacctGroup) Set(_ string, _ *configs.Resources) error { @@ -85,45 +81,43 @@ func getCpuUsageBreakdown(path string) (uint64, uint64, error) { const ( userField = "user" systemField = "system" + file = cgroupCpuacctStat ) // Expected format: // user // system - data, err := cgroups.ReadFile(path, cgroupCpuacctStat) + data, err := cgroups.ReadFile(path, file) if err != nil { return 0, 0, err } + // TODO: use strings.SplitN instead. fields := strings.Fields(data) - if len(fields) < 4 { - return 0, 0, fmt.Errorf("failure - %s is expected to have at least 4 fields", filepath.Join(path, cgroupCpuacctStat)) - } - if fields[0] != userField { - return 0, 0, fmt.Errorf("unexpected field %q in %q, expected %q", fields[0], cgroupCpuacctStat, userField) - } - if fields[2] != systemField { - return 0, 0, fmt.Errorf("unexpected field %q in %q, expected %q", fields[2], cgroupCpuacctStat, systemField) + if len(fields) < 4 || fields[0] != userField || fields[2] != systemField { + return 0, 0, malformedLine(path, file, data) } if userModeUsage, err = strconv.ParseUint(fields[1], 10, 64); err != nil { - return 0, 0, err + return 0, 0, &parseError{Path: path, File: file, Err: err} } if kernelModeUsage, err = strconv.ParseUint(fields[3], 10, 64); err != nil { - return 0, 0, err + return 0, 0, &parseError{Path: path, File: file, Err: err} } return (userModeUsage * nanosecondsInSecond) / clockTicks, (kernelModeUsage * nanosecondsInSecond) / clockTicks, nil } func getPercpuUsage(path string) ([]uint64, error) { + const file = "cpuacct.usage_percpu" percpuUsage := []uint64{} - data, err := cgroups.ReadFile(path, "cpuacct.usage_percpu") + data, err := cgroups.ReadFile(path, file) if err != nil { return percpuUsage, err } + // TODO: use strings.SplitN instead. for _, value := range strings.Fields(data) { value, err := strconv.ParseUint(value, 10, 64) if err != nil { - return percpuUsage, fmt.Errorf("Unable to convert param value to uint64: %s", err) + return percpuUsage, &parseError{Path: path, File: file, Err: err} } percpuUsage = append(percpuUsage, value) } @@ -133,16 +127,17 @@ func getPercpuUsage(path string) ([]uint64, error) { func getPercpuUsageInModes(path string) ([]uint64, []uint64, error) { usageKernelMode := []uint64{} usageUserMode := []uint64{} + const file = cgroupCpuacctUsageAll - file, err := cgroups.OpenFile(path, cgroupCpuacctUsageAll, os.O_RDONLY) + fd, err := cgroups.OpenFile(path, file, os.O_RDONLY) if os.IsNotExist(err) { return usageKernelMode, usageUserMode, nil } else if err != nil { return nil, nil, err } - defer file.Close() + defer fd.Close() - scanner := bufio.NewScanner(file) + scanner := bufio.NewScanner(fd) scanner.Scan() // skipping header line for scanner.Scan() { @@ -153,19 +148,18 @@ func getPercpuUsageInModes(path string) ([]uint64, []uint64, error) { usageInKernelMode, err := strconv.ParseUint(lineFields[kernelModeColumn], 10, 64) if err != nil { - return nil, nil, fmt.Errorf("Unable to convert CPU usage in kernel mode to uint64: %s", err) + return nil, nil, &parseError{Path: path, File: file, Err: err} } usageKernelMode = append(usageKernelMode, usageInKernelMode) usageInUserMode, err := strconv.ParseUint(lineFields[userModeColumn], 10, 64) if err != nil { - return nil, nil, fmt.Errorf("Unable to convert CPU usage in user mode to uint64: %s", err) + return nil, nil, &parseError{Path: path, File: file, Err: err} } usageUserMode = append(usageUserMode, usageInUserMode) } - if err := scanner.Err(); err != nil { - return nil, nil, fmt.Errorf("Problem in reading %s line by line, %s", cgroupCpuacctUsageAll, err) + return nil, nil, &parseError{Path: path, File: file, Err: err} } return usageKernelMode, usageUserMode, nil diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go index 58a0f0406444d..550baa4275652 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go @@ -1,19 +1,17 @@ -// +build linux - package fs import ( - "fmt" + "errors" "os" "path/filepath" "strconv" "strings" + "golang.org/x/sys/unix" + "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" - "github.com/pkg/errors" - "golang.org/x/sys/unix" ) type CpusetGroup struct{} @@ -22,8 +20,8 @@ func (s *CpusetGroup) Name() string { return "cpuset" } -func (s *CpusetGroup) Apply(path string, d *cgroupData) error { - return s.ApplyDir(path, d.config.Resources, d.pid) +func (s *CpusetGroup) Apply(path string, r *configs.Resources, pid int) error { + return s.ApplyDir(path, r, pid) } func (s *CpusetGroup) Set(path string, r *configs.Resources) error { @@ -40,32 +38,32 @@ func (s *CpusetGroup) Set(path string, r *configs.Resources) error { return nil } -func getCpusetStat(path string, filename string) ([]uint16, error) { +func getCpusetStat(path string, file string) ([]uint16, error) { var extracted []uint16 - fileContent, err := fscommon.GetCgroupParamString(path, filename) + fileContent, err := fscommon.GetCgroupParamString(path, file) if err != nil { return extracted, err } if len(fileContent) == 0 { - return extracted, fmt.Errorf("%s found to be empty", filepath.Join(path, filename)) + return extracted, &parseError{Path: path, File: file, Err: errors.New("empty file")} } for _, s := range strings.Split(fileContent, ",") { - splitted := strings.SplitN(s, "-", 3) - switch len(splitted) { + sp := strings.SplitN(s, "-", 3) + switch len(sp) { case 3: - return extracted, fmt.Errorf("invalid values in %s", filepath.Join(path, filename)) + return extracted, &parseError{Path: path, File: file, Err: errors.New("extra dash")} case 2: - min, err := strconv.ParseUint(splitted[0], 10, 16) + min, err := strconv.ParseUint(sp[0], 10, 16) if err != nil { - return extracted, err + return extracted, &parseError{Path: path, File: file, Err: err} } - max, err := strconv.ParseUint(splitted[1], 10, 16) + max, err := strconv.ParseUint(sp[1], 10, 16) if err != nil { - return extracted, err + return extracted, &parseError{Path: path, File: file, Err: err} } if min > max { - return extracted, fmt.Errorf("invalid values in %s", filepath.Join(path, filename)) + return extracted, &parseError{Path: path, File: file, Err: errors.New("invalid values, min > max")} } for i := min; i <= max; i++ { extracted = append(extracted, uint16(i)) @@ -73,7 +71,7 @@ func getCpusetStat(path string, filename string) ([]uint16, error) { case 1: value, err := strconv.ParseUint(s, 10, 16) if err != nil { - return extracted, err + return extracted, &parseError{Path: path, File: file, Err: err} } extracted = append(extracted, uint16(value)) } @@ -168,9 +166,8 @@ func (s *CpusetGroup) ApplyDir(dir string, r *configs.Resources, pid int) error if err := s.ensureCpusAndMems(dir, r); 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 + // Since we are not using apply(), we need to place the pid + // into the procs file. return cgroups.WriteCgroupProc(dir, pid) } @@ -198,7 +195,7 @@ func cpusetEnsureParent(current string) error { } // Treat non-existing directory as cgroupfs as it will be created, // and the root cpuset directory obviously exists. - if err != nil && err != unix.ENOENT { + if err != nil && err != unix.ENOENT { //nolint:errorlint // unix errors are bare return &os.PathError{Op: "statfs", Path: parent, Err: err} } @@ -224,12 +221,12 @@ func cpusetCopyIfNeeded(current, parent string) error { } if isEmptyCpuset(currentCpus) { - if err := cgroups.WriteFile(current, "cpuset.cpus", string(parentCpus)); err != nil { + if err := cgroups.WriteFile(current, "cpuset.cpus", parentCpus); err != nil { return err } } if isEmptyCpuset(currentMems) { - if err := cgroups.WriteFile(current, "cpuset.mems", string(parentMems)); err != nil { + if err := cgroups.WriteFile(current, "cpuset.mems", parentMems); err != nil { return err } } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go index dcf69ce13e73a..4527a70ebfcd1 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go @@ -1,5 +1,3 @@ -// +build linux - package fs import ( @@ -15,15 +13,15 @@ import ( ) type DevicesGroup struct { - testingSkipFinalCheck bool + TestingSkipFinalCheck bool } func (s *DevicesGroup) Name() string { return "devices" } -func (s *DevicesGroup) Apply(path string, d *cgroupData) error { - if d.config.SkipDevices { +func (s *DevicesGroup) Apply(path string, r *configs.Resources, pid int) error { + if r.SkipDevices { return nil } if path == "" { @@ -31,7 +29,8 @@ func (s *DevicesGroup) Apply(path string, d *cgroupData) error { // is a hard requirement for container's security. return errSubsystemDoesNotExist } - return join(path, d.pid) + + return apply(path, pid) } func loadEmulator(path string) (*cgroupdevices.Emulator, error) { @@ -91,7 +90,7 @@ func (s *DevicesGroup) Set(path string, r *configs.Resources) error { // // This safety-check is skipped for the unit tests because we cannot // currently mock devices.list correctly. - if !s.testingSkipFinalCheck { + if !s.TestingSkipFinalCheck { currentAfter, err := loadEmulator(path) if err != nil { return err diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/error.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/error.go new file mode 100644 index 0000000000000..f2ab6f130e31e --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/error.go @@ -0,0 +1,15 @@ +package fs + +import ( + "fmt" + + "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" +) + +type parseError = fscommon.ParseError + +// malformedLine is used by all cgroupfs file parsers that expect a line +// in a particular format but get some garbage instead. +func malformedLine(path, file, line string) error { + return &parseError{Path: path, File: file, Err: fmt.Errorf("malformed line: %s", line)} +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go index 4baa2798ac9cc..987f1bf5e742f 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go @@ -1,5 +1,3 @@ -// +build linux - package fs import ( @@ -21,8 +19,8 @@ func (s *FreezerGroup) Name() string { return "freezer" } -func (s *FreezerGroup) Apply(path string, d *cgroupData) error { - return join(path, d.pid) +func (s *FreezerGroup) Apply(path string, _ *configs.Resources, pid int) error { + return apply(path, pid) } func (s *FreezerGroup) Set(path string, r *configs.Resources) (Err error) { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/fs.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/fs.go index 777b94f03569d..fb4fcc7f75bb2 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/fs.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/fs.go @@ -1,165 +1,86 @@ -// +build linux - package fs import ( + "errors" "fmt" "os" - "path/filepath" "sync" + "golang.org/x/sys/unix" + "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" - libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils" - "github.com/pkg/errors" - "golang.org/x/sys/unix" ) -var ( - subsystems = []subsystem{ - &CpusetGroup{}, - &DevicesGroup{}, - &MemoryGroup{}, - &CpuGroup{}, - &CpuacctGroup{}, - &PidsGroup{}, - &BlkioGroup{}, - &HugetlbGroup{}, - &NetClsGroup{}, - &NetPrioGroup{}, - &PerfEventGroup{}, - &FreezerGroup{}, - &NameGroup{GroupName: "name=systemd", Join: true}, - } - HugePageSizes, _ = cgroups.GetHugePageSize() -) +var subsystems = []subsystem{ + &CpusetGroup{}, + &DevicesGroup{}, + &MemoryGroup{}, + &CpuGroup{}, + &CpuacctGroup{}, + &PidsGroup{}, + &BlkioGroup{}, + &HugetlbGroup{}, + &NetClsGroup{}, + &NetPrioGroup{}, + &PerfEventGroup{}, + &FreezerGroup{}, + &RdmaGroup{}, + &NameGroup{GroupName: "name=systemd", Join: true}, +} var errSubsystemDoesNotExist = errors.New("cgroup: subsystem does not exist") +func init() { + // If using cgroups-hybrid mode then add a "" controller indicating + // it should join the cgroups v2. + if cgroups.IsCgroup2HybridMode() { + subsystems = append(subsystems, &NameGroup{GroupName: "", Join: true}) + } +} + type subsystem interface { // Name returns the name of the subsystem. Name() string - // Returns the stats, as 'stats', corresponding to the cgroup under 'path'. + // GetStats fills in the stats for the subsystem. GetStats(path string, stats *cgroups.Stats) error - // Creates and joins the cgroup represented by 'cgroupData'. - Apply(path string, c *cgroupData) error + // Apply creates and joins a cgroup, adding pid into it. Some + // subsystems use resources to pre-configure the cgroup parents + // before creating or joining it. + Apply(path string, r *configs.Resources, pid int) error // Set sets the cgroup resources. Set(path string, r *configs.Resources) error } type manager struct { - mu sync.Mutex - cgroups *configs.Cgroup - rootless bool // ignore permission-related errors - paths map[string]string -} - -func NewManager(cg *configs.Cgroup, paths map[string]string, rootless bool) cgroups.Manager { - return &manager{ - cgroups: cg, - paths: paths, - rootless: rootless, - } -} - -// The absolute path to the root of the cgroup hierarchies. -var ( - cgroupRootLock sync.Mutex - cgroupRoot string -) - -const defaultCgroupRoot = "/sys/fs/cgroup" - -func tryDefaultCgroupRoot() string { - var st, pst unix.Stat_t - - // (1) it should be a directory... - err := unix.Lstat(defaultCgroupRoot, &st) - if err != nil || st.Mode&unix.S_IFDIR == 0 { - return "" - } - - // (2) ... and a mount point ... - err = unix.Lstat(filepath.Dir(defaultCgroupRoot), &pst) - if err != nil { - return "" - } - - if st.Dev == pst.Dev { - // parent dir has the same dev -- not a mount point - return "" - } - - // (3) ... of 'tmpfs' fs type. - var fst unix.Statfs_t - err = unix.Statfs(defaultCgroupRoot, &fst) - if err != nil || fst.Type != unix.TMPFS_MAGIC { - return "" - } - - // (4) it should have at least 1 entry ... - dir, err := os.Open(defaultCgroupRoot) - if err != nil { - return "" - } - names, err := dir.Readdirnames(1) - if err != nil { - return "" - } - if len(names) < 1 { - return "" - } - // ... which is a cgroup mount point. - err = unix.Statfs(filepath.Join(defaultCgroupRoot, names[0]), &fst) - if err != nil || fst.Type != unix.CGROUP_SUPER_MAGIC { - return "" - } - - return defaultCgroupRoot + mu sync.Mutex + cgroups *configs.Cgroup + paths map[string]string } -// Gets the cgroupRoot. -func getCgroupRoot() (string, error) { - cgroupRootLock.Lock() - defer cgroupRootLock.Unlock() - - if cgroupRoot != "" { - return cgroupRoot, nil - } - - // fast path - cgroupRoot = tryDefaultCgroupRoot() - if cgroupRoot != "" { - return cgroupRoot, nil +func NewManager(cg *configs.Cgroup, paths map[string]string) (cgroups.Manager, error) { + // Some v1 controllers (cpu, cpuset, and devices) expect + // cgroups.Resources to not be nil in Apply. + if cg.Resources == nil { + return nil, errors.New("cgroup v1 manager needs configs.Resources to be set during manager creation") } - - // slow path: parse mountinfo - mi, err := cgroups.GetCgroupMounts(false) - if err != nil { - return "", err - } - if len(mi) < 1 { - return "", errors.New("no cgroup mount found in mountinfo") + if cg.Resources.Unified != nil { + return nil, cgroups.ErrV1NoUnified } - // Get the first cgroup mount (e.g. "/sys/fs/cgroup/memory"), - // use its parent directory. - root := filepath.Dir(mi[0].Mountpoint) - - if _, err := os.Stat(root); err != nil { - return "", err + if paths == nil { + var err error + paths, err = initPaths(cg) + if err != nil { + return nil, err + } } - cgroupRoot = root - return cgroupRoot, nil -} - -type cgroupData struct { - root string - innerPath string - config *configs.Cgroup - pid int + return &manager{ + cgroups: cg, + paths: paths, + }, nil } // isIgnorableError returns whether err is a permission error (in the loose @@ -171,8 +92,6 @@ func isIgnorableError(rootless bool, err error) bool { if !rootless { return false } - // TODO: rm errors.Cause once we switch to %w everywhere - err = errors.Cause(err) // Is it an ordinary EPERM? if errors.Is(err, os.ErrPermission) { return true @@ -186,56 +105,30 @@ func isIgnorableError(rootless bool, err error) bool { } func (m *manager) Apply(pid int) (err error) { - if m.cgroups == nil { - return nil - } m.mu.Lock() defer m.mu.Unlock() c := m.cgroups - if c.Resources.Unified != nil { - return cgroups.ErrV1NoUnified - } - - m.paths = make(map[string]string) - if c.Paths != nil { - cgMap, err := cgroups.ParseCgroupFile("/proc/self/cgroup") - if err != nil { - return err - } - for name, path := range c.Paths { - // XXX(kolyshkin@): why this check is needed? - if _, ok := cgMap[name]; ok { - m.paths[name] = path - } - } - return cgroups.EnterPid(m.paths, pid) - } - - d, err := getCgroupData(m.cgroups, pid) - if err != nil { - return err - } for _, sys := range subsystems { - p, err := d.path(sys.Name()) - if err != nil { - // The non-presence of the devices subsystem is - // considered fatal for security reasons. - if cgroups.IsNotFound(err) && (c.SkipDevices || sys.Name() != "devices") { - continue - } - return err + name := sys.Name() + p, ok := m.paths[name] + if !ok { + continue } - m.paths[sys.Name()] = p - if err := sys.Apply(p, d); err != nil { + if err := sys.Apply(p, c.Resources, pid); err != nil { // In the case of rootless (including euid=0 in userns), where an // explicit cgroup path hasn't been set, we don't bail on error in - // case of permission problems. Cases where limits have been set - // (and we couldn't create our own cgroup) are handled by Set. - if isIgnorableError(m.rootless, err) && m.cgroups.Path == "" { - delete(m.paths, sys.Name()) + // case of permission problems here, but do delete the path from + // the m.paths map, since it is either non-existent and could not + // be created, or the pid could not be added to it. + // + // Cases where limits for the subsystem have been set are handled + // later by Set, which fails with a friendly error (see + // if path == "" in Set). + if isIgnorableError(c.Rootless, err) && c.Path == "" { + delete(m.paths, name) continue } return err @@ -246,9 +139,6 @@ func (m *manager) Apply(pid int) (err error) { } func (m *manager) Destroy() error { - if m.cgroups == nil || m.cgroups.Paths != nil { - return nil - } m.mu.Lock() defer m.mu.Unlock() return cgroups.RemovePaths(m.paths) @@ -281,11 +171,6 @@ func (m *manager) Set(r *configs.Resources) error { 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 != nil && m.cgroups.Paths != nil { - return nil - } if r.Unified != nil { return cgroups.ErrV1NoUnified } @@ -295,10 +180,11 @@ func (m *manager) Set(r *configs.Resources) error { for _, sys := range subsystems { path := m.paths[sys.Name()] if err := sys.Set(path, r); err != nil { - if m.rootless && sys.Name() == "devices" { + // When rootless is true, errors from the device subsystem + // are ignored, as it is really not expected to work. + if m.cgroups.Rootless && sys.Name() == "devices" { continue } - // When m.rootless is true, errors from the device subsystem are ignored because it is really not expected to work. // However, errors from other subsystems are not ignored. // see @test "runc create (rootless + limits + no cgrouppath + no permission) fails with informative error" if path == "" { @@ -317,7 +203,7 @@ func (m *manager) Set(r *configs.Resources) error { // provided func (m *manager) Freeze(state configs.FreezerState) error { path := m.Path("freezer") - if m.cgroups == nil || path == "" { + if path == "" { return errors.New("cannot toggle freezer: cgroups not configured for container") } @@ -339,68 +225,6 @@ func (m *manager) GetAllPids() ([]int, error) { return cgroups.GetAllPids(m.Path("devices")) } -func getCgroupData(c *configs.Cgroup, pid int) (*cgroupData, error) { - root, err := getCgroupRoot() - if err != nil { - return nil, err - } - - if (c.Name != "" || c.Parent != "") && c.Path != "" { - return nil, errors.New("cgroup: either Path or Name and Parent should be used") - } - - // XXX: Do not remove this code. Path safety is important! -- cyphar - cgPath := libcontainerUtils.CleanPath(c.Path) - cgParent := libcontainerUtils.CleanPath(c.Parent) - cgName := libcontainerUtils.CleanPath(c.Name) - - innerPath := cgPath - if innerPath == "" { - innerPath = filepath.Join(cgParent, cgName) - } - - return &cgroupData{ - root: root, - innerPath: innerPath, - config: c, - pid: pid, - }, nil -} - -func (raw *cgroupData) path(subsystem string) (string, error) { - // If the cgroup name/path is absolute do not look relative to the cgroup of the init process. - if filepath.IsAbs(raw.innerPath) { - mnt, err := cgroups.FindCgroupMountpoint(raw.root, subsystem) - // If we didn't mount the subsystem, there is no point we make the path. - if err != nil { - return "", err - } - - // Sometimes subsystems can be mounted together as 'cpu,cpuacct'. - return filepath.Join(raw.root, filepath.Base(mnt), raw.innerPath), nil - } - - // Use GetOwnCgroupPath instead of GetInitCgroupPath, because the creating - // process could in container and shared pid namespace with host, and - // /proc/1/cgroup could point to whole other world of cgroups. - parentPath, err := cgroups.GetOwnCgroupPath(subsystem) - if err != nil { - return "", err - } - - return filepath.Join(parentPath, raw.innerPath), nil -} - -func join(path string, pid int) error { - if path == "" { - return nil - } - if err := os.MkdirAll(path, 0o755); err != nil { - return err - } - return cgroups.WriteCgroupProc(path, pid) -} - func (m *manager) GetPaths() map[string]string { m.mu.Lock() defer m.mu.Unlock() @@ -432,7 +256,7 @@ func OOMKillCount(path string) (uint64, error) { func (m *manager) OOMKillCount() (uint64, error) { c, err := OOMKillCount(m.Path("memory")) // Ignore ENOENT when rootless as it couldn't create cgroup. - if err != nil && m.rootless && os.IsNotExist(err) { + if err != nil && m.cgroups.Rootless && os.IsNotExist(err) { err = nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb.go index 3cafc5399eedc..8ddd6fdd83701 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb.go @@ -1,9 +1,6 @@ -// +build linux - package fs import ( - "fmt" "strconv" "github.com/opencontainers/runc/libcontainer/cgroups" @@ -17,8 +14,8 @@ func (s *HugetlbGroup) Name() string { return "hugetlb" } -func (s *HugetlbGroup) Apply(path string, d *cgroupData) error { - return join(path, d.pid) +func (s *HugetlbGroup) Apply(path string, _ *configs.Resources, pid int) error { + return apply(path, pid) } func (s *HugetlbGroup) Set(path string, r *configs.Resources) error { @@ -32,29 +29,29 @@ func (s *HugetlbGroup) Set(path string, r *configs.Resources) error { } func (s *HugetlbGroup) GetStats(path string, stats *cgroups.Stats) error { - hugetlbStats := cgroups.HugetlbStats{} if !cgroups.PathExists(path) { return nil } - for _, pageSize := range HugePageSizes { + hugetlbStats := cgroups.HugetlbStats{} + for _, pageSize := range cgroups.HugePageSizes() { usage := "hugetlb." + pageSize + ".usage_in_bytes" value, err := fscommon.GetCgroupParamUint(path, usage) if err != nil { - return fmt.Errorf("failed to parse %s - %v", usage, err) + return err } hugetlbStats.Usage = value maxUsage := "hugetlb." + pageSize + ".max_usage_in_bytes" value, err = fscommon.GetCgroupParamUint(path, maxUsage) if err != nil { - return fmt.Errorf("failed to parse %s - %v", maxUsage, err) + return err } hugetlbStats.MaxUsage = value failcnt := "hugetlb." + pageSize + ".failcnt" value, err = fscommon.GetCgroupParamUint(path, failcnt) if err != nil { - return fmt.Errorf("failed to parse %s - %v", failcnt, err) + return err } hugetlbStats.Failcnt = value diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go index 33946726f1508..b7c75f941385b 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go @@ -1,9 +1,8 @@ -// +build linux - package fs import ( "bufio" + "errors" "fmt" "math" "os" @@ -11,11 +10,11 @@ import ( "strconv" "strings" + "golang.org/x/sys/unix" + "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" - "github.com/pkg/errors" - "golang.org/x/sys/unix" ) const ( @@ -31,8 +30,8 @@ func (s *MemoryGroup) Name() string { return "memory" } -func (s *MemoryGroup) Apply(path string, d *cgroupData) (err error) { - return join(path, d.pid) +func (s *MemoryGroup) Apply(path string, _ *configs.Resources, pid int) error { + return apply(path, pid) } func setMemory(path string, val int64) error { @@ -56,7 +55,7 @@ func setMemory(path string, val int64) error { return err } - return errors.Errorf("unable to set memory limit to %d (current usage: %d, peak usage: %d)", val, usage, max) + return fmt.Errorf("unable to set memory limit to %d (current usage: %d, peak usage: %d)", val, usage, max) } func setSwap(path string, val int64) error { @@ -134,15 +133,15 @@ func (s *MemoryGroup) Set(path string, r *configs.Resources) error { return err } } else { - return fmt.Errorf("invalid value:%d. valid memory swappiness range is 0-100", *r.MemorySwappiness) + return fmt.Errorf("invalid memory swappiness value: %d (valid range is 0-100)", *r.MemorySwappiness) } return nil } func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error { - // Set stats from memory.stat. - statsFile, err := cgroups.OpenFile(path, "memory.stat", os.O_RDONLY) + const file = "memory.stat" + statsFile, err := cgroups.OpenFile(path, file, os.O_RDONLY) if err != nil { if os.IsNotExist(err) { return nil @@ -155,7 +154,7 @@ func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error { for sc.Scan() { t, v, err := fscommon.ParseKeyValue(sc.Text()) if err != nil { - return fmt.Errorf("failed to parse memory.stat (%q) - %v", sc.Text(), err) + return &parseError{Path: path, File: file, Err: err} } stats.MemoryStats.Stats[t] = v } @@ -220,42 +219,42 @@ func getMemoryData(path, name string) (cgroups.MemoryData, error) { // are optional in the kernel. return cgroups.MemoryData{}, nil } - return cgroups.MemoryData{}, fmt.Errorf("failed to parse %s - %v", usage, err) + return cgroups.MemoryData{}, err } memoryData.Usage = value value, err = fscommon.GetCgroupParamUint(path, maxUsage) if err != nil { - return cgroups.MemoryData{}, fmt.Errorf("failed to parse %s - %v", maxUsage, err) + return cgroups.MemoryData{}, err } memoryData.MaxUsage = value value, err = fscommon.GetCgroupParamUint(path, failcnt) if err != nil { - return cgroups.MemoryData{}, fmt.Errorf("failed to parse %s - %v", failcnt, err) + return cgroups.MemoryData{}, err } memoryData.Failcnt = value value, err = fscommon.GetCgroupParamUint(path, limit) if err != nil { - return cgroups.MemoryData{}, fmt.Errorf("failed to parse %s - %v", limit, err) + return cgroups.MemoryData{}, err } memoryData.Limit = value return memoryData, nil } -func getPageUsageByNUMA(cgroupPath string) (cgroups.PageUsageByNUMA, error) { +func getPageUsageByNUMA(path string) (cgroups.PageUsageByNUMA, error) { const ( maxColumns = math.MaxUint8 + 1 - filename = "memory.numa_stat" + file = "memory.numa_stat" ) stats := cgroups.PageUsageByNUMA{} - file, err := cgroups.OpenFile(cgroupPath, filename, os.O_RDONLY) + fd, err := cgroups.OpenFile(path, file, os.O_RDONLY) if os.IsNotExist(err) { return stats, nil } else if err != nil { return stats, err } - defer file.Close() + defer fd.Close() // File format is documented in linux/Documentation/cgroup-v1/memory.txt // and it looks like this: @@ -266,7 +265,7 @@ func getPageUsageByNUMA(cgroupPath string) (cgroups.PageUsageByNUMA, error) { // unevictable= N0= N1= ... // hierarchical_= N0= N1= ... - scanner := bufio.NewScanner(file) + scanner := bufio.NewScanner(fd) for scanner.Scan() { var field *cgroups.PageStats @@ -284,8 +283,7 @@ func getPageUsageByNUMA(cgroupPath string) (cgroups.PageUsageByNUMA, error) { } else { // The first column was already validated, // so be strict to the rest. - return stats, fmt.Errorf("malformed line %q in %s", - line, filename) + return stats, malformedLine(path, file, line) } } key, val := byNode[0], byNode[1] @@ -296,24 +294,23 @@ func getPageUsageByNUMA(cgroupPath string) (cgroups.PageUsageByNUMA, error) { } field.Total, err = strconv.ParseUint(val, 0, 64) if err != nil { - return stats, err + return stats, &parseError{Path: path, File: file, Err: err} } field.Nodes = map[uint8]uint64{} } else { // Subsequent columns: key is N, val is usage. if len(key) < 2 || key[0] != 'N' { // This is definitely an error. - return stats, fmt.Errorf("malformed line %q in %s", - line, filename) + return stats, malformedLine(path, file, line) } n, err := strconv.ParseUint(key[1:], 10, 8) if err != nil { - return cgroups.PageUsageByNUMA{}, err + return stats, &parseError{Path: path, File: file, Err: err} } usage, err := strconv.ParseUint(val, 10, 64) if err != nil { - return cgroups.PageUsageByNUMA{}, err + return stats, &parseError{Path: path, File: file, Err: err} } field.Nodes[uint8(n)] = usage @@ -321,9 +318,8 @@ func getPageUsageByNUMA(cgroupPath string) (cgroups.PageUsageByNUMA, error) { } } - err = scanner.Err() - if err != nil { - return cgroups.PageUsageByNUMA{}, err + if err := scanner.Err(); err != nil { + return cgroups.PageUsageByNUMA{}, &parseError{Path: path, File: file, Err: err} } return stats, nil diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go index 94a94b5e8d00d..b8d5d849c520a 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go @@ -1,5 +1,3 @@ -// +build linux - package fs import ( @@ -16,10 +14,10 @@ func (s *NameGroup) Name() string { return s.GroupName } -func (s *NameGroup) Apply(path string, d *cgroupData) error { +func (s *NameGroup) Apply(path string, _ *configs.Resources, pid int) error { if s.Join { - // ignore errors if the named cgroup does not exist - _ = join(path, d.pid) + // Ignore errors if the named cgroup does not exist. + _ = apply(path, pid) } return nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go index f2617aa44425b..abfd09ce83acb 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go @@ -1,5 +1,3 @@ -// +build linux - package fs import ( @@ -15,8 +13,8 @@ func (s *NetClsGroup) Name() string { return "net_cls" } -func (s *NetClsGroup) Apply(path string, d *cgroupData) error { - return join(path, d.pid) +func (s *NetClsGroup) Apply(path string, _ *configs.Resources, pid int) error { + return apply(path, pid) } func (s *NetClsGroup) Set(path string, r *configs.Resources) error { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio.go index d0ac5e66bbbbe..da74d3779899e 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio.go @@ -1,5 +1,3 @@ -// +build linux - package fs import ( @@ -13,8 +11,8 @@ func (s *NetPrioGroup) Name() string { return "net_prio" } -func (s *NetPrioGroup) Apply(path string, d *cgroupData) error { - return join(path, d.pid) +func (s *NetPrioGroup) Apply(path string, _ *configs.Resources, pid int) error { + return apply(path, pid) } func (s *NetPrioGroup) Set(path string, r *configs.Resources) error { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/paths.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/paths.go new file mode 100644 index 0000000000000..1092331b25d89 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/paths.go @@ -0,0 +1,186 @@ +package fs + +import ( + "errors" + "os" + "path/filepath" + "sync" + + "golang.org/x/sys/unix" + + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/utils" +) + +// The absolute path to the root of the cgroup hierarchies. +var ( + cgroupRootLock sync.Mutex + cgroupRoot string +) + +const defaultCgroupRoot = "/sys/fs/cgroup" + +func initPaths(cg *configs.Cgroup) (map[string]string, error) { + root, err := rootPath() + if err != nil { + return nil, err + } + + inner, err := innerPath(cg) + if err != nil { + return nil, err + } + + paths := make(map[string]string) + for _, sys := range subsystems { + name := sys.Name() + path, err := subsysPath(root, inner, name) + if err != nil { + // The non-presence of the devices subsystem + // is considered fatal for security reasons. + if cgroups.IsNotFound(err) && (cg.SkipDevices || name != "devices") { + continue + } + + return nil, err + } + paths[name] = path + } + + return paths, nil +} + +func tryDefaultCgroupRoot() string { + var st, pst unix.Stat_t + + // (1) it should be a directory... + err := unix.Lstat(defaultCgroupRoot, &st) + if err != nil || st.Mode&unix.S_IFDIR == 0 { + return "" + } + + // (2) ... and a mount point ... + err = unix.Lstat(filepath.Dir(defaultCgroupRoot), &pst) + if err != nil { + return "" + } + + if st.Dev == pst.Dev { + // parent dir has the same dev -- not a mount point + return "" + } + + // (3) ... of 'tmpfs' fs type. + var fst unix.Statfs_t + err = unix.Statfs(defaultCgroupRoot, &fst) + if err != nil || fst.Type != unix.TMPFS_MAGIC { + return "" + } + + // (4) it should have at least 1 entry ... + dir, err := os.Open(defaultCgroupRoot) + if err != nil { + return "" + } + names, err := dir.Readdirnames(1) + if err != nil { + return "" + } + if len(names) < 1 { + return "" + } + // ... which is a cgroup mount point. + err = unix.Statfs(filepath.Join(defaultCgroupRoot, names[0]), &fst) + if err != nil || fst.Type != unix.CGROUP_SUPER_MAGIC { + return "" + } + + return defaultCgroupRoot +} + +// rootPath finds and returns path to the root of the cgroup hierarchies. +func rootPath() (string, error) { + cgroupRootLock.Lock() + defer cgroupRootLock.Unlock() + + if cgroupRoot != "" { + return cgroupRoot, nil + } + + // fast path + cgroupRoot = tryDefaultCgroupRoot() + if cgroupRoot != "" { + return cgroupRoot, nil + } + + // slow path: parse mountinfo + mi, err := cgroups.GetCgroupMounts(false) + if err != nil { + return "", err + } + if len(mi) < 1 { + return "", errors.New("no cgroup mount found in mountinfo") + } + + // Get the first cgroup mount (e.g. "/sys/fs/cgroup/memory"), + // use its parent directory. + root := filepath.Dir(mi[0].Mountpoint) + + if _, err := os.Stat(root); err != nil { + return "", err + } + + cgroupRoot = root + return cgroupRoot, nil +} + +func innerPath(c *configs.Cgroup) (string, error) { + if (c.Name != "" || c.Parent != "") && c.Path != "" { + return "", errors.New("cgroup: either Path or Name and Parent should be used") + } + + // XXX: Do not remove CleanPath. Path safety is important! -- cyphar + innerPath := utils.CleanPath(c.Path) + if innerPath == "" { + cgParent := utils.CleanPath(c.Parent) + cgName := utils.CleanPath(c.Name) + innerPath = filepath.Join(cgParent, cgName) + } + + return innerPath, nil +} + +func subsysPath(root, inner, subsystem string) (string, error) { + // If the cgroup name/path is absolute do not look relative to the cgroup of the init process. + if filepath.IsAbs(inner) { + mnt, err := cgroups.FindCgroupMountpoint(root, subsystem) + // If we didn't mount the subsystem, there is no point we make the path. + if err != nil { + return "", err + } + + // Sometimes subsystems can be mounted together as 'cpu,cpuacct'. + return filepath.Join(root, filepath.Base(mnt), inner), nil + } + + // Use GetOwnCgroupPath instead of GetInitCgroupPath, because the creating + // process could in container and shared pid namespace with host, and + // /proc/1/cgroup could point to whole other world of cgroups. + parentPath, err := cgroups.GetOwnCgroupPath(subsystem) + if err != nil { + return "", err + } + + return filepath.Join(parentPath, inner), nil +} + +func apply(path string, pid int) error { + if path == "" { + return nil + } + if err := os.MkdirAll(path, 0o755); err != nil { + return err + } + return cgroups.WriteCgroupProc(path, pid) +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/perf_event.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/perf_event.go index 1a306fbe3f75c..b86955c8f31b9 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/perf_event.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/perf_event.go @@ -1,5 +1,3 @@ -// +build linux - package fs import ( @@ -13,8 +11,8 @@ func (s *PerfEventGroup) Name() string { return "perf_event" } -func (s *PerfEventGroup) Apply(path string, d *cgroupData) error { - return join(path, d.pid) +func (s *PerfEventGroup) Apply(path string, _ *configs.Resources, pid int) error { + return apply(path, pid) } func (s *PerfEventGroup) Set(_ string, _ *configs.Resources) error { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids.go index 1b08433c4502a..1f13532a5ad2d 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids.go @@ -1,10 +1,7 @@ -// +build linux - package fs import ( - "fmt" - "path/filepath" + "math" "strconv" "github.com/opencontainers/runc/libcontainer/cgroups" @@ -18,8 +15,8 @@ func (s *PidsGroup) Name() string { return "pids" } -func (s *PidsGroup) Apply(path string, d *cgroupData) error { - return join(path, d.pid) +func (s *PidsGroup) Apply(path string, _ *configs.Resources, pid int) error { + return apply(path, pid) } func (s *PidsGroup) Set(path string, r *configs.Resources) error { @@ -45,21 +42,18 @@ func (s *PidsGroup) GetStats(path string, stats *cgroups.Stats) error { } current, err := fscommon.GetCgroupParamUint(path, "pids.current") if err != nil { - return fmt.Errorf("failed to parse pids.current - %s", err) + return err } - maxString, err := fscommon.GetCgroupParamString(path, "pids.max") + max, err := fscommon.GetCgroupParamUint(path, "pids.max") if err != nil { - return fmt.Errorf("failed to parse pids.max - %s", err) + return err } - - // Default if pids.max == "max" is 0 -- which represents "no limit". - var max uint64 - if maxString != "max" { - max, err = fscommon.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")) - } + // If no limit is set, read from pids.max returns "max", which is + // converted to MaxUint64 by GetCgroupParamUint. Historically, we + // represent "no limit" for pids as 0, thus this conversion. + if max == math.MaxUint64 { + max = 0 } stats.PidsStats.Current = current diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/rdma.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/rdma.go new file mode 100644 index 0000000000000..5bbe0f35f813e --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/rdma.go @@ -0,0 +1,25 @@ +package fs + +import ( + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" + "github.com/opencontainers/runc/libcontainer/configs" +) + +type RdmaGroup struct{} + +func (s *RdmaGroup) Name() string { + return "rdma" +} + +func (s *RdmaGroup) Apply(path string, _ *configs.Resources, pid int) error { + return apply(path, pid) +} + +func (s *RdmaGroup) Set(path string, r *configs.Resources) error { + return fscommon.RdmaSet(path, r) +} + +func (s *RdmaGroup) GetStats(path string, stats *cgroups.Stats) error { + return fscommon.RdmaGetStats(path, stats) +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/unsupported.go deleted file mode 100644 index 3ef9e031586ea..0000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/unsupported.go +++ /dev/null @@ -1,3 +0,0 @@ -// +build !linux - -package fs diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpu.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpu.go index 25c47c9617e71..bbbae4d58c4ab 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpu.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpu.go @@ -1,5 +1,3 @@ -// +build linux - package fs2 import ( @@ -49,7 +47,8 @@ func setCpu(dirPath string, r *configs.Resources) error { } func statCpu(dirPath string, stats *cgroups.Stats) error { - f, err := cgroups.OpenFile(dirPath, "cpu.stat", os.O_RDONLY) + const file = "cpu.stat" + f, err := cgroups.OpenFile(dirPath, file, os.O_RDONLY) if err != nil { return err } @@ -59,7 +58,7 @@ func statCpu(dirPath string, stats *cgroups.Stats) error { for sc.Scan() { t, v, err := fscommon.ParseKeyValue(sc.Text()) if err != nil { - return err + return &parseError{Path: dirPath, File: file, Err: err} } switch t { case "usage_usec": @@ -81,5 +80,8 @@ func statCpu(dirPath string, stats *cgroups.Stats) error { stats.CpuStats.ThrottlingData.ThrottledTime = v * 1000 } } + if err := sc.Err(); err != nil { + return &parseError{Path: dirPath, File: file, Err: err} + } return nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpuset.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpuset.go index da29d7f2bbb5e..16c45bad8f08e 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpuset.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpuset.go @@ -1,5 +1,3 @@ -// +build linux - package fs2 import ( diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/defaultpath.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/defaultpath.go index ba81ce0b41be2..9c949c91f084f 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/defaultpath.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/defaultpath.go @@ -18,41 +18,37 @@ package fs2 import ( "bufio" + "errors" + "fmt" "io" "os" "path/filepath" "strings" "github.com/opencontainers/runc/libcontainer/configs" - libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils" - "github.com/pkg/errors" + "github.com/opencontainers/runc/libcontainer/utils" ) const UnifiedMountpoint = "/sys/fs/cgroup" func defaultDirPath(c *configs.Cgroup) (string, error) { if (c.Name != "" || c.Parent != "") && c.Path != "" { - return "", errors.Errorf("cgroup: either Path or Name and Parent should be used, got %+v", c) + return "", fmt.Errorf("cgroup: either Path or Name and Parent should be used, got %+v", c) } - if len(c.Paths) != 0 { - // never set by specconv - return "", errors.Errorf("cgroup: Paths is unsupported, use Path, got %+v", c) - } - - // XXX: Do not remove this code. Path safety is important! -- cyphar - cgPath := libcontainerUtils.CleanPath(c.Path) - cgParent := libcontainerUtils.CleanPath(c.Parent) - cgName := libcontainerUtils.CleanPath(c.Name) - return _defaultDirPath(UnifiedMountpoint, cgPath, cgParent, cgName) + return _defaultDirPath(UnifiedMountpoint, c.Path, c.Parent, c.Name) } func _defaultDirPath(root, cgPath, cgParent, cgName string) (string, error) { if (cgName != "" || cgParent != "") && cgPath != "" { return "", errors.New("cgroup: either Path or Name and Parent should be used") } - innerPath := cgPath + + // XXX: Do not remove CleanPath. Path safety is important! -- cyphar + innerPath := utils.CleanPath(cgPath) if innerPath == "" { + cgParent := utils.CleanPath(cgParent) + cgName := utils.CleanPath(cgName) innerPath = filepath.Join(cgParent, cgName) } if filepath.IsAbs(innerPath) { @@ -89,7 +85,7 @@ func parseCgroupFromReader(r io.Reader) (string, error) { parts = strings.SplitN(text, ":", 3) ) if len(parts) < 3 { - return "", errors.Errorf("invalid cgroup entry: %q", text) + return "", fmt.Errorf("invalid cgroup entry: %q", text) } // text is like "0::/user.slice/user-1001.slice/session-1.scope" if parts[0] == "0" && parts[1] == "" { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/devices.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/devices.go index 7c501cad8a634..0d23456072caa 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/devices.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/devices.go @@ -1,16 +1,15 @@ -// +build linux - package fs2 import ( + "fmt" + + "golang.org/x/sys/unix" + "github.com/opencontainers/runc/libcontainer/cgroups/ebpf" "github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/devices" "github.com/opencontainers/runc/libcontainer/userns" - - "github.com/pkg/errors" - "golang.org/x/sys/unix" ) func isRWM(perms devices.Permissions) bool { @@ -64,7 +63,7 @@ func setDevices(dirPath string, r *configs.Resources) error { } dirFD, err := unix.Open(dirPath, unix.O_DIRECTORY|unix.O_RDONLY, 0o600) if err != nil { - return errors.Errorf("cannot get dir FD for %s", dirPath) + return fmt.Errorf("cannot get dir FD for %s", dirPath) } defer unix.Close(dirFD) if _, err := ebpf.LoadAttachCgroupDeviceFilter(insts, license, dirFD); err != nil { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/freezer.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/freezer.go index e901f7a07b1da..8917a6411d68e 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/freezer.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/freezer.go @@ -1,19 +1,17 @@ -// +build linux - package fs2 import ( "bufio" - stdErrors "errors" + "errors" "fmt" "os" "strings" "time" + "golang.org/x/sys/unix" + "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" - "github.com/pkg/errors" - "golang.org/x/sys/unix" ) func setFreezer(dirPath string, state configs.FreezerState) error { @@ -26,7 +24,7 @@ func setFreezer(dirPath string, state configs.FreezerState) error { case configs.Thawed: stateStr = "0" default: - return errors.Errorf("invalid freezer state %q requested", state) + return fmt.Errorf("invalid freezer state %q requested", state) } fd, err := cgroups.OpenFile(dirPath, "cgroup.freeze", unix.O_RDWR) @@ -37,7 +35,7 @@ func setFreezer(dirPath string, state configs.FreezerState) error { if state != configs.Frozen { return nil } - return errors.Wrap(err, "freezer not supported") + return fmt.Errorf("freezer not supported: %w", err) } defer fd.Close() @@ -48,7 +46,7 @@ func setFreezer(dirPath string, state configs.FreezerState) error { if actualState, err := readFreezer(dirPath, fd); err != nil { return err } else if actualState != state { - return errors.Errorf(`expected "cgroup.freeze" to be in state %q but was in %q`, state, actualState) + return fmt.Errorf(`expected "cgroup.freeze" to be in state %q but was in %q`, state, actualState) } return nil } @@ -58,7 +56,7 @@ func getFreezer(dirPath string) (configs.FreezerState, error) { if err != nil { // If the kernel is too old, then we just treat the freezer as being in // an "undefined" state. - if os.IsNotExist(err) || stdErrors.Is(err, unix.ENODEV) { + if os.IsNotExist(err) || errors.Is(err, unix.ENODEV) { err = nil } return configs.Undefined, err @@ -82,7 +80,7 @@ func readFreezer(dirPath string, fd *os.File) (configs.FreezerState, error) { case "1\n": return waitFrozen(dirPath) default: - return configs.Undefined, errors.Errorf(`unknown "cgroup.freeze" state: %q`, state) + return configs.Undefined, fmt.Errorf(`unknown "cgroup.freeze" state: %q`, state) } } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/fs2.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/fs2.go index afba0ab1c88dd..492778e31051c 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/fs2.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/fs2.go @@ -1,8 +1,7 @@ -// +build linux - package fs2 import ( + "errors" "fmt" "os" "strings" @@ -10,9 +9,10 @@ import ( "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" - "github.com/pkg/errors" ) +type parseError = fscommon.ParseError + type manager struct { config *configs.Cgroup // dirPath is like "/sys/fs/cgroup/user.slice/user-1001.slice/session-1.scope" @@ -20,16 +20,12 @@ type manager struct { // controllers is content of "cgroup.controllers" file. // excludes pseudo-controllers ("devices" and "freezer"). controllers map[string]struct{} - rootless bool } // NewManager creates a manager for cgroup v2 unified hierarchy. // dirPath is like "/sys/fs/cgroup/user.slice/user-1001.slice/session-1.scope". // If dirPath is empty, it is automatically set using config. -func NewManager(config *configs.Cgroup, dirPath string, rootless bool) (cgroups.Manager, error) { - if config == nil { - config = &configs.Cgroup{} - } +func NewManager(config *configs.Cgroup, dirPath string) (cgroups.Manager, error) { if dirPath == "" { var err error dirPath, err = defaultDirPath(config) @@ -39,9 +35,8 @@ func NewManager(config *configs.Cgroup, dirPath string, rootless bool) (cgroups. } m := &manager{ - config: config, - dirPath: dirPath, - rootless: rootless, + config: config, + dirPath: dirPath, } return m, nil } @@ -53,7 +48,7 @@ func (m *manager) getControllers() error { data, err := cgroups.ReadFile(m.dirPath, "cgroup.controllers") if err != nil { - if m.rootless && m.config.Path == "" { + if m.config.Rootless && m.config.Path == "" { return nil } return err @@ -73,12 +68,12 @@ func (m *manager) Apply(pid int) error { // - "runc create (no limits + no cgrouppath + no permission) succeeds" // - "runc create (rootless + no limits + cgrouppath + no permission) fails with permission error" // - "runc create (rootless + limits + no cgrouppath + no permission) fails with informative error" - if m.rootless { + if m.config.Rootless { if m.config.Path == "" { if blNeed, nErr := needAnyControllers(m.config.Resources); nErr == nil && !blNeed { return nil } - return errors.Wrap(err, "rootless needs no limits + no cgrouppath when no permission is granted for cgroups") + return fmt.Errorf("rootless needs no limits + no cgrouppath when no permission is granted for cgroups: %w", err) } } return err @@ -123,13 +118,20 @@ func (m *manager) GetStats() (*cgroups.Stats, error) { if err := statHugeTlb(m.dirPath, st); err != nil && !os.IsNotExist(err) { errs = append(errs, err) } - if len(errs) > 0 && !m.rootless { - return st, errors.Errorf("error while statting cgroup v2: %+v", errs) + // rdma (since kernel 4.11) + if err := fscommon.RdmaGetStats(m.dirPath, st); err != nil && !os.IsNotExist(err) { + errs = append(errs, err) + } + if len(errs) > 0 && !m.config.Rootless { + return st, fmt.Errorf("error while statting cgroup v2: %+v", errs) } return st, nil } func (m *manager) Freeze(state configs.FreezerState) error { + if m.config.Resources == nil { + return errors.New("cannot toggle freezer: cgroups not configured for container") + } if err := setFreezer(m.dirPath, state); err != nil { return err } @@ -146,6 +148,9 @@ func (m *manager) Path(_ string) string { } func (m *manager) Set(r *configs.Resources) error { + if r == nil { + return nil + } if err := m.getControllers(); err != nil { return err } @@ -167,10 +172,10 @@ func (m *manager) Set(r *configs.Resources) error { } // devices (since kernel 4.15, pseudo-controller) // - // When m.rootless is true, errors from the device subsystem are ignored because it is really not expected to work. + // When rootless is true, errors from the device subsystem are ignored because it is really not expected to work. // However, errors from other subsystems are not ignored. // see @test "runc create (rootless + limits + no cgrouppath + no permission) fails with informative error" - if err := setDevices(m.dirPath, r); err != nil && !m.rootless { + if err := setDevices(m.dirPath, r); err != nil && !m.config.Rootless { return err } // cpuset (since kernel 5.0) @@ -181,6 +186,10 @@ func (m *manager) Set(r *configs.Resources) error { if err := setHugeTlb(m.dirPath, r); err != nil { return err } + // rdma (since kernel 4.11) + if err := fscommon.RdmaSet(m.dirPath, r); err != nil { + return err + } // freezer (since kernel 5.2, pseudo-controller) if err := setFreezer(m.dirPath, r.Freezer); err != nil { return err @@ -198,9 +207,8 @@ func (m *manager) setUnified(res map[string]string) error { return fmt.Errorf("unified resource %q must be a file name (no slashes)", k) } if err := cgroups.WriteFile(m.dirPath, k, v); err != nil { - errC := errors.Cause(err) // Check for both EPERM and ENOENT since O_CREAT is used by WriteFile. - if errors.Is(errC, os.ErrPermission) || errors.Is(errC, os.ErrNotExist) { + if errors.Is(err, os.ErrPermission) || errors.Is(err, os.ErrNotExist) { // Check if a controller is available, // to give more specific error if not. sk := strings.SplitN(k, ".", 2) @@ -212,7 +220,7 @@ func (m *manager) setUnified(res map[string]string) error { return fmt.Errorf("unified resource %q can't be set: controller %q not available", k, c) } } - return errors.Wrapf(err, "can't set unified resource %q", k) + return fmt.Errorf("unable to set unified resource %q: %w", k, err) } } @@ -243,7 +251,7 @@ func OOMKillCount(path string) (uint64, error) { func (m *manager) OOMKillCount() (uint64, error) { c, err := OOMKillCount(m.dirPath) - if err != nil && m.rootless && os.IsNotExist(err) { + if err != nil && m.config.Rootless && os.IsNotExist(err) { err = nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/hugetlb.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/hugetlb.go index 96390a224f108..c92a7e64af026 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/hugetlb.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/hugetlb.go @@ -1,12 +1,8 @@ -// +build linux - package fs2 import ( "strconv" - "github.com/pkg/errors" - "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" @@ -30,10 +26,8 @@ func setHugeTlb(dirPath string, r *configs.Resources) error { } func statHugeTlb(dirPath string, stats *cgroups.Stats) error { - hugePageSizes, _ := cgroups.GetHugePageSize() hugetlbStats := cgroups.HugetlbStats{} - - for _, pagesize := range hugePageSizes { + for _, pagesize := range cgroups.HugePageSizes() { value, err := fscommon.GetCgroupParamUint(dirPath, "hugetlb."+pagesize+".current") if err != nil { return err @@ -43,7 +37,7 @@ func statHugeTlb(dirPath string, stats *cgroups.Stats) error { fileName := "hugetlb." + pagesize + ".events" value, err = fscommon.GetValueByKey(dirPath, fileName, "max") if err != nil { - return errors.Wrap(err, "failed to read stats") + return err } hugetlbStats.Failcnt = value diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/io.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/io.go index fd3f0993ea0c6..b2ff7d340868c 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/io.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/io.go @@ -1,5 +1,3 @@ -// +build linux - package fs2 import ( @@ -117,13 +115,14 @@ func readCgroup2MapFile(dirPath string, name string) (map[string][]string, error ret[parts[0]] = parts[1:] } if err := scanner.Err(); err != nil { - return nil, err + return nil, &parseError{Path: dirPath, File: name, Err: err} } return ret, nil } func statIo(dirPath string, stats *cgroups.Stats) error { - values, err := readCgroup2MapFile(dirPath, "io.stat") + const file = "io.stat" + values, err := readCgroup2MapFile(dirPath, file) if err != nil { return err } @@ -136,11 +135,11 @@ func statIo(dirPath string, stats *cgroups.Stats) error { } major, err := strconv.ParseUint(d[0], 10, 64) if err != nil { - return err + return &parseError{Path: dirPath, File: file, Err: err} } minor, err := strconv.ParseUint(d[1], 10, 64) if err != nil { - return err + return &parseError{Path: dirPath, File: file, Err: err} } for _, item := range v { @@ -177,7 +176,7 @@ func statIo(dirPath string, stats *cgroups.Stats) error { value, err := strconv.ParseUint(d[1], 10, 64) if err != nil { - return err + return &parseError{Path: dirPath, File: file, Err: err} } entry := cgroups.BlkioStatEntry{ diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/memory.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/memory.go index 53e8f1e93498e..adbc4b23086a8 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/memory.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/memory.go @@ -1,19 +1,18 @@ -// +build linux - package fs2 import ( "bufio" + "errors" "math" "os" "strconv" "strings" + "golang.org/x/sys/unix" + "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" - "github.com/pkg/errors" - "golang.org/x/sys/unix" ) // numToStr converts an int64 value to a string for writing to a @@ -75,8 +74,8 @@ func setMemory(dirPath string, r *configs.Resources) error { } func statMemory(dirPath string, stats *cgroups.Stats) error { - // Set stats from memory.stat. - statsFile, err := cgroups.OpenFile(dirPath, "memory.stat", os.O_RDONLY) + const file = "memory.stat" + statsFile, err := cgroups.OpenFile(dirPath, file, os.O_RDONLY) if err != nil { return err } @@ -86,10 +85,13 @@ func statMemory(dirPath string, stats *cgroups.Stats) error { for sc.Scan() { t, v, err := fscommon.ParseKeyValue(sc.Text()) if err != nil { - return errors.Wrapf(err, "failed to parse memory.stat (%q)", sc.Text()) + return &parseError{Path: dirPath, File: file, Err: err} } stats.MemoryStats.Stats[t] = v } + if err := sc.Err(); err != nil { + return &parseError{Path: dirPath, File: file, Err: err} + } stats.MemoryStats.Cache = stats.MemoryStats.Stats["file"] // Unlike cgroup v1 which has memory.use_hierarchy binary knob, // cgroup v2 is always hierarchical. @@ -139,13 +141,13 @@ func getMemoryDataV2(path, name string) (cgroups.MemoryData, error) { // swapaccount=0 kernel boot parameter is given. return cgroups.MemoryData{}, nil } - return cgroups.MemoryData{}, errors.Wrapf(err, "failed to parse %s", usage) + return cgroups.MemoryData{}, err } memoryData.Usage = value value, err = fscommon.GetCgroupParamUint(path, limit) if err != nil { - return cgroups.MemoryData{}, errors.Wrapf(err, "failed to parse %s", limit) + return cgroups.MemoryData{}, err } memoryData.Limit = value @@ -153,7 +155,8 @@ func getMemoryDataV2(path, name string) (cgroups.MemoryData, error) { } func statsFromMeminfo(stats *cgroups.Stats) error { - f, err := os.Open("/proc/meminfo") + const file = "/proc/meminfo" + f, err := os.Open(file) if err != nil { return err } @@ -190,7 +193,7 @@ func statsFromMeminfo(stats *cgroups.Stats) error { vStr := strings.TrimSpace(strings.TrimSuffix(parts[1], " kB")) *p, err = strconv.ParseUint(vStr, 10, 64) if err != nil { - return errors.Wrap(err, "parsing /proc/meminfo "+k) + return &parseError{File: file, Err: errors.New("bad value for " + k)} } found++ @@ -199,8 +202,8 @@ func statsFromMeminfo(stats *cgroups.Stats) error { break } } - if sc.Err() != nil { - return sc.Err() + if err := sc.Err(); err != nil { + return &parseError{Path: "", File: file, Err: err} } stats.MemoryStats.SwapUsage.Usage = (swap_total - swap_free) * 1024 diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/pids.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/pids.go index e2050002d0e51..c8c4a365894ab 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/pids.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/pids.go @@ -1,17 +1,16 @@ -// +build linux - package fs2 import ( + "errors" + "math" "os" - "path/filepath" "strings" + "golang.org/x/sys/unix" + "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" - "github.com/pkg/errors" - "golang.org/x/sys/unix" ) func isPidsSet(r *configs.Resources) bool { @@ -53,22 +52,18 @@ func statPids(dirPath string, stats *cgroups.Stats) error { if os.IsNotExist(err) { return statPidsFromCgroupProcs(dirPath, stats) } - return errors.Wrap(err, "failed to parse pids.current") + return err } - maxString, err := fscommon.GetCgroupParamString(dirPath, "pids.max") + max, err := fscommon.GetCgroupParamUint(dirPath, "pids.max") if err != nil { - return errors.Wrap(err, "failed to parse pids.max") + return err } - - // Default if pids.max == "max" is 0 -- which represents "no limit". - var max uint64 - if maxString != "max" { - max, err = fscommon.ParseUint(maxString, 10, 64) - if err != nil { - return errors.Wrapf(err, "failed to parse pids.max - unable to parse %q as a uint from Cgroup file %q", - maxString, filepath.Join(dirPath, "pids.max")) - } + // If no limit is set, read from pids.max returns "max", which is + // converted to MaxUint64 by GetCgroupParamUint. Historically, we + // represent "no limit" for pids as 0, thus this conversion. + if max == math.MaxUint64 { + max = 0 } stats.PidsStats.Current = current diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/rdma.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/rdma.go new file mode 100644 index 0000000000000..d463d15ee4e40 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/rdma.go @@ -0,0 +1,121 @@ +package fscommon + +import ( + "bufio" + "errors" + "math" + "os" + "strconv" + "strings" + + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/configs" + "golang.org/x/sys/unix" +) + +// parseRdmaKV parses raw string to RdmaEntry. +func parseRdmaKV(raw string, entry *cgroups.RdmaEntry) error { + var value uint32 + + parts := strings.SplitN(raw, "=", 3) + + if len(parts) != 2 { + return errors.New("Unable to parse RDMA entry") + } + + k, v := parts[0], parts[1] + + if v == "max" { + value = math.MaxUint32 + } else { + val64, err := strconv.ParseUint(v, 10, 32) + if err != nil { + return err + } + value = uint32(val64) + } + if k == "hca_handle" { + entry.HcaHandles = value + } else if k == "hca_object" { + entry.HcaObjects = value + } + + return nil +} + +// readRdmaEntries reads and converts array of rawstrings to RdmaEntries from file. +// example entry: mlx4_0 hca_handle=2 hca_object=2000 +func readRdmaEntries(dir, file string) ([]cgroups.RdmaEntry, error) { + rdmaEntries := make([]cgroups.RdmaEntry, 0) + fd, err := cgroups.OpenFile(dir, file, unix.O_RDONLY) + if err != nil { + return nil, err + } + defer fd.Close() //nolint:errorlint + scanner := bufio.NewScanner(fd) + for scanner.Scan() { + parts := strings.SplitN(scanner.Text(), " ", 4) + if len(parts) == 3 { + entry := new(cgroups.RdmaEntry) + entry.Device = parts[0] + err = parseRdmaKV(parts[1], entry) + if err != nil { + continue + } + err = parseRdmaKV(parts[2], entry) + if err != nil { + continue + } + + rdmaEntries = append(rdmaEntries, *entry) + } + } + return rdmaEntries, scanner.Err() +} + +// RdmaGetStats returns rdma stats such as totalLimit and current entries. +func RdmaGetStats(path string, stats *cgroups.Stats) error { + currentEntries, err := readRdmaEntries(path, "rdma.current") + if err != nil { + if errors.Is(err, os.ErrNotExist) { + err = nil + } + return err + } + maxEntries, err := readRdmaEntries(path, "rdma.max") + if err != nil { + return err + } + // If device got removed between reading two files, ignore returning stats. + if len(currentEntries) != len(maxEntries) { + return nil + } + + stats.RdmaStats = cgroups.RdmaStats{ + RdmaLimit: maxEntries, + RdmaCurrent: currentEntries, + } + + return nil +} + +func createCmdString(device string, limits configs.LinuxRdma) string { + cmdString := device + if limits.HcaHandles != nil { + cmdString += " hca_handle=" + strconv.FormatUint(uint64(*limits.HcaHandles), 10) + } + if limits.HcaObjects != nil { + cmdString += " hca_object=" + strconv.FormatUint(uint64(*limits.HcaObjects), 10) + } + return cmdString +} + +// RdmaSet sets RDMA resources. +func RdmaSet(path string, r *configs.Resources) error { + for device, limits := range r.Rdma { + if err := cgroups.WriteFile(path, "rdma.max", createCmdString(device, limits)); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/utils.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/utils.go index e31146ae9dfcc..f4a51c9e56fda 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/utils.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/utils.go @@ -1,11 +1,10 @@ -// +build linux - package fscommon import ( "errors" "fmt" "math" + "path" "strconv" "strings" @@ -13,8 +12,6 @@ import ( ) var ( - ErrNotValidFormat = errors.New("line is not a valid key value format") - // Deprecated: use cgroups.OpenFile instead. OpenFile = cgroups.OpenFile // Deprecated: use cgroups.ReadFile instead. @@ -23,6 +20,19 @@ var ( WriteFile = cgroups.WriteFile ) +// ParseError records a parse error details, including the file path. +type ParseError struct { + Path string + File string + Err error +} + +func (e *ParseError) Error() string { + return "unable to parse " + path.Join(e.Path, e.File) + ": " + e.Err.Error() +} + +func (e *ParseError) Unwrap() error { return e.Err } + // ParseUint converts a string to an uint64 integer. // Negative values are returned at zero as, due to kernel bugs, // some of the memory cgroup stats can be negative. @@ -34,7 +44,7 @@ func ParseUint(s string, base, bitSize int) (uint64, error) { // 2. Handle negative values lesser than MinInt64 if intErr == nil && intValue < 0 { return 0, nil - } else if intErr != nil && intErr.(*strconv.NumError).Err == strconv.ErrRange && intValue < 0 { + } else if errors.Is(intErr, strconv.ErrRange) && intValue < 0 { return 0, nil } @@ -56,7 +66,7 @@ func ParseKeyValue(t string) (string, uint64, error) { value, err := ParseUint(parts[1], 10, 64) if err != nil { - return "", 0, fmt.Errorf("unable to convert to uint64: %v", err) + return "", 0, err } return parts[0], value, nil @@ -71,11 +81,15 @@ func GetValueByKey(path, file, key string) (uint64, error) { return 0, err } - lines := strings.Split(string(content), "\n") + lines := strings.Split(content, "\n") for _, line := range lines { arr := strings.Split(line, " ") if len(arr) == 2 && arr[0] == key { - return ParseUint(arr[1], 10, 64) + val, err := ParseUint(arr[1], 10, 64) + if err != nil { + err = &ParseError{Path: path, File: file, Err: err} + } + return val, err } } @@ -96,7 +110,7 @@ func GetCgroupParamUint(path, file string) (uint64, error) { res, err := ParseUint(contents, 10, 64) if err != nil { - return res, fmt.Errorf("unable to parse file %q", path+"/"+file) + return res, &ParseError{Path: path, File: file, Err: err} } return res, nil } @@ -115,7 +129,7 @@ func GetCgroupParamInt(path, file string) (int64, error) { res, err := strconv.ParseInt(contents, 10, 64) if err != nil { - return res, fmt.Errorf("unable to parse %q as a int from Cgroup file %q", contents, path+"/"+file) + return res, &ParseError{Path: path, File: file, Err: err} } return res, nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/getallpids.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/getallpids.go new file mode 100644 index 0000000000000..1355a5101055b --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/getallpids.go @@ -0,0 +1,27 @@ +package cgroups + +import ( + "io/fs" + "path/filepath" +) + +// GetAllPids returns all pids from the cgroup identified by path, and all its +// sub-cgroups. +func GetAllPids(path string) ([]int, error) { + var pids []int + err := filepath.WalkDir(path, func(p string, d fs.DirEntry, iErr error) error { + if iErr != nil { + return iErr + } + if !d.IsDir() { + return nil + } + cPids, err := readProcsFile(p) + if err != nil { + return err + } + pids = append(pids, cPids...) + return nil + }) + return pids, err +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/manager/new.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/manager/new.go new file mode 100644 index 0000000000000..5df120d0f09fe --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/manager/new.go @@ -0,0 +1,78 @@ +package manager + +import ( + "errors" + "fmt" + "path/filepath" + + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/cgroups/fs" + "github.com/opencontainers/runc/libcontainer/cgroups/fs2" + "github.com/opencontainers/runc/libcontainer/cgroups/systemd" + "github.com/opencontainers/runc/libcontainer/configs" +) + +// New returns the instance of a cgroup manager, which is chosen +// based on the local environment (whether cgroup v1 or v2 is used) +// and the config (whether config.Systemd is set or not). +func New(config *configs.Cgroup) (cgroups.Manager, error) { + return NewWithPaths(config, nil) +} + +// NewWithPaths is similar to New, and can be used in case cgroup paths +// are already well known, which can save some resources. +// +// For cgroup v1, the keys are controller/subsystem name, and the values +// are absolute filesystem paths to the appropriate cgroups. +// +// For cgroup v2, the only key allowed is "" (empty string), and the value +// is the unified cgroup path. +func NewWithPaths(config *configs.Cgroup, paths map[string]string) (cgroups.Manager, error) { + if config == nil { + return nil, errors.New("cgroups/manager.New: config must not be nil") + } + if config.Systemd && !systemd.IsRunningSystemd() { + return nil, errors.New("systemd not running on this host, cannot use systemd cgroups manager") + } + + // Cgroup v2 aka unified hierarchy. + if cgroups.IsCgroup2UnifiedMode() { + path, err := getUnifiedPath(paths) + if err != nil { + return nil, fmt.Errorf("manager.NewWithPaths: inconsistent paths: %w", err) + } + if config.Systemd { + return systemd.NewUnifiedManager(config, path) + } + return fs2.NewManager(config, path) + } + + // Cgroup v1. + if config.Systemd { + return systemd.NewLegacyManager(config, paths) + } + + return fs.NewManager(config, paths) +} + +// getUnifiedPath is an implementation detail of libcontainer factory. +// Historically, it saves cgroup paths as per-subsystem path map (as returned +// by cm.GetPaths(""), but with v2 we only have one single unified path +// (with "" as a key). +// +// This function converts from that map to string (using "" as a key), +// and also checks that the map itself is sane. +func getUnifiedPath(paths map[string]string) (string, error) { + if len(paths) > 1 { + return "", fmt.Errorf("expected a single path, got %+v", paths) + } + path := paths[""] + // can be empty + if path != "" { + if filepath.Clean(path) != path || !filepath.IsAbs(path) { + return "", fmt.Errorf("invalid path: %q", path) + } + } + + return path, nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go index e7f9c462635c3..40a81dd5a8606 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go @@ -1,5 +1,3 @@ -// +build linux - package cgroups type ThrottlingData struct { @@ -126,7 +124,7 @@ type BlkioStatEntry struct { } type BlkioStats struct { - // number of bytes tranferred to and from the block device + // number of bytes transferred to and from the block device IoServiceBytesRecursive []BlkioStatEntry `json:"io_service_bytes_recursive,omitempty"` IoServicedRecursive []BlkioStatEntry `json:"io_serviced_recursive,omitempty"` IoQueuedRecursive []BlkioStatEntry `json:"io_queue_recursive,omitempty"` @@ -146,6 +144,17 @@ type HugetlbStats struct { Failcnt uint64 `json:"failcnt"` } +type RdmaEntry struct { + Device string `json:"device,omitempty"` + HcaHandles uint32 `json:"hca_handles,omitempty"` + HcaObjects uint32 `json:"hca_objects,omitempty"` +} + +type RdmaStats struct { + RdmaLimit []RdmaEntry `json:"rdma_limit,omitempty"` + RdmaCurrent []RdmaEntry `json:"rdma_current,omitempty"` +} + type Stats struct { CpuStats CpuStats `json:"cpu_stats,omitempty"` CPUSetStats CPUSetStats `json:"cpuset_stats,omitempty"` @@ -154,6 +163,7 @@ type Stats struct { BlkioStats BlkioStats `json:"blkio_stats,omitempty"` // the map is in the format "size of hugepage: stats of the hugepage" HugetlbStats map[string]HugetlbStats `json:"hugetlb_stats,omitempty"` + RdmaStats RdmaStats `json:"rdma_stats,omitempty"` } func NewStats() *Stats { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/common.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/common.go index 06c6c2e95a663..98ccc51655cb1 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/common.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/common.go @@ -3,6 +3,7 @@ package systemd import ( "bufio" "context" + "errors" "fmt" "math" "os" @@ -14,11 +15,11 @@ import ( systemdDbus "github.com/coreos/go-systemd/v22/dbus" dbus "github.com/godbus/dbus/v5" + "github.com/sirupsen/logrus" + cgroupdevices "github.com/opencontainers/runc/libcontainer/cgroups/devices" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/devices" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" ) const ( @@ -92,7 +93,7 @@ func groupPrefix(ruleType devices.Type) (string, error) { case devices.CharDevice: return "char-", nil default: - return "", errors.Errorf("device type %v has no group prefix", ruleType) + return "", fmt.Errorf("device type %v has no group prefix", ruleType) } } @@ -142,9 +143,9 @@ func findDeviceGroup(ruleType devices.Type, ruleMajor int64) (string, error) { ) if n, err := fmt.Sscanf(line, "%d %s", &currMajor, &currName); err != nil || n != 2 { if err == nil { - err = errors.Errorf("wrong number of fields") + err = errors.New("wrong number of fields") } - return "", errors.Wrapf(err, "scan /proc/devices line %q", line) + return "", fmt.Errorf("scan /proc/devices line %q: %w", line, err) } if currMajor == ruleMajor { @@ -152,7 +153,7 @@ func findDeviceGroup(ruleType devices.Type, ruleMajor int64) (string, error) { } } if err := scanner.Err(); err != nil { - return "", errors.Wrap(err, "reading /proc/devices") + return "", fmt.Errorf("reading /proc/devices: %w", err) } // Couldn't find the device group. return "", nil @@ -192,12 +193,12 @@ func generateDeviceProperties(r *configs.Resources) ([]systemdDbus.Property, err configEmu := &cgroupdevices.Emulator{} for _, rule := range r.Devices { if err := configEmu.Apply(*rule); err != nil { - return nil, errors.Wrap(err, "apply rule for systemd") + return nil, fmt.Errorf("unable to apply rule for systemd: %w", err) } } // systemd doesn't support blacklists. So we log a warning, and tell // systemd to act as a deny-all whitelist. This ruleset will be replaced - // with our normal fallback code. This may result in spurrious errors, but + // with our normal fallback code. This may result in spurious errors, but // the only other option is to error out here. if configEmu.IsBlacklist() { // However, if we're dealing with an allow-all rule then we can do it. @@ -213,19 +214,19 @@ func generateDeviceProperties(r *configs.Resources) ([]systemdDbus.Property, err // whitelist which is the default for devices.Emulator. finalRules, err := configEmu.Rules() if err != nil { - return nil, errors.Wrap(err, "get simplified rules for systemd") + return nil, fmt.Errorf("unable to get simplified rules for systemd: %w", err) } var deviceAllowList []deviceAllowEntry for _, rule := range finalRules { if !rule.Allow { // Should never happen. - return nil, errors.Errorf("[internal error] cannot add deny rule to systemd DeviceAllow list: %v", *rule) + return nil, fmt.Errorf("[internal error] cannot add deny rule to systemd DeviceAllow list: %v", *rule) } switch rule.Type { case devices.BlockDevice, devices.CharDevice: default: // Should never happen. - return nil, errors.Errorf("invalid device type for DeviceAllow: %v", rule.Type) + return nil, fmt.Errorf("invalid device type for DeviceAllow: %v", rule.Type) } entry := deviceAllowEntry{ @@ -271,7 +272,7 @@ func generateDeviceProperties(r *configs.Resources) ([]systemdDbus.Property, err // "_ n:* _" rules require a device group from /proc/devices. group, err := findDeviceGroup(rule.Type, rule.Major) if err != nil { - return nil, errors.Wrapf(err, "find device '%v/%d'", rule.Type, rule.Major) + return nil, fmt.Errorf("unable to find device '%v/%d': %w", rule.Type, rule.Major, err) } if group == "" { // Couldn't find a group. @@ -350,7 +351,7 @@ func startUnit(cm *dbusConnManager, unitName string, properties []systemdDbus.Pr // Please refer to https://pkg.go.dev/github.com/coreos/go-systemd/v22/dbus#Conn.StartUnit if s != "done" { resetFailedUnit(cm, unitName) - return errors.Errorf("error creating systemd unit `%s`: got `%s`", unitName, s) + return fmt.Errorf("error creating systemd unit `%s`: got `%s`", unitName, s) } case <-timeout.C: resetFailedUnit(cm, unitName) @@ -449,10 +450,13 @@ func systemdVersionAtoi(verStr string) (int, error) { re := regexp.MustCompile(`v?([0-9]+)`) matches := re.FindStringSubmatch(verStr) if len(matches) < 2 { - return 0, errors.Errorf("can't parse version %s: incorrect number of matches %v", verStr, matches) + return 0, fmt.Errorf("can't parse version %s: incorrect number of matches %v", verStr, matches) } ver, err := strconv.Atoi(matches[1]) - return ver, errors.Wrapf(err, "can't parse version %s", verStr) + if err != nil { + return -1, fmt.Errorf("can't parse version: %w", err) + } + return ver, nil } func addCpuQuota(cm *dbusConnManager, properties *[]systemdDbus.Property, quota int64, period uint64) { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/cpuset.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/cpuset.go index 642a04e7dd949..83d10dd705fdd 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/cpuset.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/cpuset.go @@ -1,12 +1,10 @@ package systemd import ( - "encoding/binary" + "errors" + "math/big" "strconv" "strings" - - "github.com/bits-and-blooms/bitset" - "github.com/pkg/errors" ) // RangeToBits converts a text representation of a CPU mask (as written to @@ -14,7 +12,7 @@ import ( // with the corresponding bits set (as consumed by systemd over dbus as // AllowedCPUs/AllowedMemoryNodes unit property value). func RangeToBits(str string) ([]byte, error) { - bits := &bitset.BitSet{} + bits := new(big.Int) for _, r := range strings.Split(str, ",") { // allow extra spaces around @@ -36,32 +34,22 @@ func RangeToBits(str string) ([]byte, error) { if start > end { return nil, errors.New("invalid range: " + r) } - for i := uint(start); i <= uint(end); i++ { - bits.Set(i) + for i := start; i <= end; i++ { + bits.SetBit(bits, int(i), 1) } } else { val, err := strconv.ParseUint(ranges[0], 10, 32) if err != nil { return nil, err } - bits.Set(uint(val)) + bits.SetBit(bits, int(val), 1) } } - val := bits.Bytes() - if len(val) == 0 { + ret := bits.Bytes() + if len(ret) == 0 { // do not allow empty values return nil, errors.New("empty value") } - ret := make([]byte, len(val)*8) - for i := range val { - // bitset uses BigEndian internally - binary.BigEndian.PutUint64(ret[i*8:], val[len(val)-1-i]) - } - // remove upper all-zero bytes - for ret[0] == 0 { - ret = ret[1:] - } - return ret, nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/dbus.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/dbus.go index 069056455615a..3e547e282b577 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/dbus.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/dbus.go @@ -1,5 +1,3 @@ -// +build linux - package systemd import ( diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/unsupported.go deleted file mode 100644 index cb4d00c88b359..0000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/unsupported.go +++ /dev/null @@ -1,71 +0,0 @@ -// +build !linux - -package systemd - -import ( - "errors" - - "github.com/opencontainers/runc/libcontainer/cgroups" - "github.com/opencontainers/runc/libcontainer/configs" -) - -type Manager struct { - Cgroups *configs.Cgroup - Paths map[string]string -} - -func IsRunningSystemd() bool { - return false -} - -func NewSystemdCgroupsManager() (func(config *configs.Cgroup, paths map[string]string) cgroups.Manager, error) { - return nil, errors.New("Systemd not supported") -} - -func (m *Manager) Apply(pid int) error { - return errors.New("Systemd not supported") -} - -func (m *Manager) GetPids() ([]int, error) { - return nil, errors.New("Systemd not supported") -} - -func (m *Manager) GetAllPids() ([]int, error) { - return nil, errors.New("Systemd not supported") -} - -func (m *Manager) Destroy() error { - return errors.New("Systemd not supported") -} - -func (m *Manager) GetPaths() map[string]string { - return nil -} - -func (m *Manager) Path(_ string) string { - return "" -} - -func (m *Manager) GetStats() (*cgroups.Stats, error) { - return nil, errors.New("Systemd not supported") -} - -func (m *Manager) Set(container *configs.Config) error { - return errors.New("Systemd not supported") -} - -func (m *Manager) Freeze(state configs.FreezerState) error { - return errors.New("Systemd not supported") -} - -func Freeze(c *configs.Cgroup, state configs.FreezerState) error { - return errors.New("Systemd not supported") -} - -func (m *Manager) GetCgroups() (*configs.Cgroup, error) { - return nil, errors.New("Systemd not supported") -} - -func (m *Manager) Exists() bool { - return false -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/user.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/user.go index ddeaf66426388..0f50f76eee4d3 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/user.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/user.go @@ -1,10 +1,10 @@ -// +build linux - package systemd import ( "bufio" "bytes" + "errors" + "fmt" "os" "os/exec" "path/filepath" @@ -13,8 +13,8 @@ import ( systemdDbus "github.com/coreos/go-systemd/v22/dbus" dbus "github.com/godbus/dbus/v5" + "github.com/opencontainers/runc/libcontainer/userns" - "github.com/pkg/errors" ) // newUserSystemdDbus creates a connection for systemd user-instance. @@ -31,17 +31,17 @@ func newUserSystemdDbus() (*systemdDbus.Conn, error) { return systemdDbus.NewConnection(func() (*dbus.Conn, error) { conn, err := dbus.Dial(addr) if err != nil { - return nil, errors.Wrapf(err, "error while dialing %q", addr) + return nil, fmt.Errorf("error while dialing %q: %w", addr, err) } methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(uid))} err = conn.Auth(methods) if err != nil { conn.Close() - return nil, errors.Wrapf(err, "error while authenticating connection, address=%q, UID=%d", addr, uid) + return nil, fmt.Errorf("error while authenticating connection (address=%q, UID=%d): %w", addr, uid, err) } if err = conn.Hello(); err != nil { conn.Close() - return nil, errors.Wrapf(err, "error while sending Hello message, address=%q, UID=%d", addr, uid) + return nil, fmt.Errorf("error while sending Hello message (address=%q, UID=%d): %w", addr, uid, err) } return conn, nil }) @@ -57,7 +57,7 @@ func DetectUID() (int, error) { } b, err := exec.Command("busctl", "--user", "--no-pager", "status").CombinedOutput() if err != nil { - return -1, errors.Wrapf(err, "could not execute `busctl --user --no-pager status`: %q", string(b)) + return -1, fmt.Errorf("could not execute `busctl --user --no-pager status` (output: %q): %w", string(b), err) } scanner := bufio.NewScanner(bytes.NewReader(b)) for scanner.Scan() { @@ -66,7 +66,7 @@ func DetectUID() (int, error) { uidStr := strings.TrimPrefix(s, "OwnerUID=") i, err := strconv.Atoi(uidStr) if err != nil { - return -1, errors.Wrapf(err, "could not detect the OwnerUID: %s", s) + return -1, fmt.Errorf("could not detect the OwnerUID: %w", err) } return i, nil } @@ -93,7 +93,7 @@ func DetectUserDbusSessionBusAddress() (string, error) { } b, err := exec.Command("systemctl", "--user", "--no-pager", "show-environment").CombinedOutput() if err != nil { - return "", errors.Wrapf(err, "could not execute `systemctl --user --no-pager show-environment`, output=%q", string(b)) + return "", fmt.Errorf("could not execute `systemctl --user --no-pager show-environment` (output=%q): %w", string(b), err) } scanner := bufio.NewScanner(bytes.NewReader(b)) for scanner.Scan() { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v1.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v1.go index cd4720c5d447b..a74a05a5cd051 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v1.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v1.go @@ -1,5 +1,3 @@ -// +build linux - package systemd import ( @@ -26,12 +24,25 @@ type legacyManager struct { dbus *dbusConnManager } -func NewLegacyManager(cg *configs.Cgroup, paths map[string]string) cgroups.Manager { +func NewLegacyManager(cg *configs.Cgroup, paths map[string]string) (cgroups.Manager, error) { + if cg.Rootless { + return nil, errors.New("cannot use rootless systemd cgroups manager on cgroup v1") + } + if cg.Resources != nil && cg.Resources.Unified != nil { + return nil, cgroups.ErrV1NoUnified + } + if paths == nil { + var err error + paths, err = initPaths(cg) + if err != nil { + return nil, err + } + } return &legacyManager{ cgroups: cg, paths: paths, dbus: newDbusConnManager(false), - } + }, nil } type subsystem interface { @@ -59,6 +70,7 @@ var legacySubsystems = []subsystem{ &fs.NetPrioGroup{}, &fs.NetClsGroup{}, &fs.NameGroup{GroupName: "name=systemd"}, + &fs.RdmaGroup{}, } func genV1ResourcesProperties(r *configs.Resources, cm *dbusConnManager) ([]systemdDbus.Property, error) { @@ -100,6 +112,53 @@ func genV1ResourcesProperties(r *configs.Resources, cm *dbusConnManager) ([]syst return properties, nil } +// initPaths figures out and returns paths to cgroups. +func initPaths(c *configs.Cgroup) (map[string]string, error) { + slice := "system.slice" + if c.Parent != "" { + var err error + slice, err = ExpandSlice(c.Parent) + if err != nil { + return nil, err + } + } + + unit := getUnitName(c) + + paths := make(map[string]string) + for _, s := range legacySubsystems { + subsystemPath, err := getSubsystemPath(slice, unit, s.Name()) + if err != nil { + // Even if it's `not found` error, we'll return err + // because devices cgroup is hard requirement for + // container security. + if s.Name() == "devices" { + return nil, err + } + // Don't fail if a cgroup hierarchy was not found, just skip this subsystem + if cgroups.IsNotFound(err) { + continue + } + return nil, err + } + paths[s.Name()] = subsystemPath + } + + // If systemd is using cgroups-hybrid mode then add the slice path of + // this container to the paths so the following process executed with + // "runc exec" joins that cgroup as well. + if cgroups.IsCgroup2HybridMode() { + // "" means cgroup-hybrid path + cgroupsHybridPath, err := getSubsystemPath(slice, unit, "") + if err != nil && cgroups.IsNotFound(err) { + return nil, err + } + paths[""] = cgroupsHybridPath + } + + return paths, nil +} + func (m *legacyManager) Apply(pid int) error { var ( c = m.cgroups @@ -108,27 +167,8 @@ func (m *legacyManager) Apply(pid int) error { properties []systemdDbus.Property ) - if c.Resources.Unified != nil { - return cgroups.ErrV1NoUnified - } - m.mu.Lock() defer m.mu.Unlock() - if c.Paths != nil { - paths := make(map[string]string) - cgMap, err := cgroups.ParseCgroupFile("/proc/self/cgroup") - if err != nil { - return err - } - // XXX(kolyshkin@): why this check is needed? - for name, path := range c.Paths { - if _, ok := cgMap[name]; ok { - paths[name] = path - } - } - m.paths = paths - return cgroups.EnterPid(m.paths, pid) - } if c.Parent != "" { slice = c.Parent @@ -136,12 +176,14 @@ func (m *legacyManager) Apply(pid int) error { 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") { + // If we create a slice, the parent is defined via a Wants=. properties = append(properties, systemdDbus.PropWants(slice)) } else { - // otherwise, we use Slice= + // Otherwise it's a scope, which we put into a Slice=. properties = append(properties, systemdDbus.PropSlice(slice)) + // Assume scopes always support delegation (supported since systemd v218). + properties = append(properties, newProp("Delegate", true)) } // only add pid if its valid, -1 is used w/ general slice creation. @@ -149,12 +191,6 @@ func (m *legacyManager) Apply(pid int) error { 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, @@ -174,26 +210,6 @@ func (m *legacyManager) Apply(pid int) error { return err } - paths := make(map[string]string) - for _, s := range legacySubsystems { - subsystemPath, err := getSubsystemPath(m.cgroups, s.Name()) - if err != nil { - // Even if it's `not found` error, we'll return err - // because devices cgroup is hard requirement for - // container security. - if s.Name() == "devices" { - return err - } - // 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 - if err := m.joinCgroups(pid); err != nil { return err } @@ -202,9 +218,6 @@ func (m *legacyManager) Apply(pid int) error { } func (m *legacyManager) Destroy() error { - if m.cgroups.Paths != nil { - return nil - } m.mu.Lock() defer m.mu.Unlock() @@ -254,7 +267,7 @@ func (m *legacyManager) joinCgroups(pid int) error { return nil } -func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) { +func getSubsystemPath(slice, unit, subsystem string) (string, error) { mountpoint, err := cgroups.FindCgroupMountpoint("", subsystem) if err != nil { return "", err @@ -267,17 +280,7 @@ func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) { // if pid 1 is systemd 226 or later, it will be in init.scope, not the root initPath = strings.TrimSuffix(filepath.Clean(initPath), "init.scope") - slice := "system.slice" - if c.Parent != "" { - slice = c.Parent - } - - slice, err = ExpandSlice(slice) - if err != nil { - return "", err - } - - return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil + return filepath.Join(mountpoint, initPath, slice, unit), nil } func (m *legacyManager) Freeze(state configs.FreezerState) error { @@ -399,9 +402,7 @@ func (m *legacyManager) freezeBeforeSet(unitName string, r *configs.Resources) ( } func (m *legacyManager) Set(r *configs.Resources) 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 { + if r == nil { return nil } if r.Unified != nil { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v2.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v2.go index 55273b722c138..c31f0ecfd25b4 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v2.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v2.go @@ -1,10 +1,10 @@ -// +build linux - package systemd import ( + "bufio" "fmt" "math" + "os" "path/filepath" "strconv" "strings" @@ -12,29 +12,39 @@ import ( systemdDbus "github.com/coreos/go-systemd/v22/dbus" securejoin "github.com/cyphar/filepath-securejoin" + "github.com/sirupsen/logrus" + "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fs2" "github.com/opencontainers/runc/libcontainer/configs" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" ) type unifiedManager struct { mu sync.Mutex cgroups *configs.Cgroup // path is like "/sys/fs/cgroup/user.slice/user-1001.slice/session-1.scope" - path string - rootless bool - dbus *dbusConnManager + path string + dbus *dbusConnManager + fsMgr cgroups.Manager } -func NewUnifiedManager(config *configs.Cgroup, path string, rootless bool) cgroups.Manager { - return &unifiedManager{ - cgroups: config, - path: path, - rootless: rootless, - dbus: newDbusConnManager(rootless), +func NewUnifiedManager(config *configs.Cgroup, path string) (cgroups.Manager, error) { + m := &unifiedManager{ + cgroups: config, + path: path, + dbus: newDbusConnManager(config.Rootless), + } + if err := m.initPath(); err != nil { + return nil, err + } + + fsMgr, err := fs2.NewManager(config, m.path) + if err != nil { + return nil, err } + m.fsMgr = fsMgr + + return m, nil } // unifiedResToSystemdProps tries to convert from Cgroup.Resources.Unified @@ -233,12 +243,8 @@ func (m *unifiedManager) Apply(pid int) error { properties []systemdDbus.Property ) - if c.Paths != nil { - return cgroups.WriteCgroupProc(m.path, pid) - } - slice := "system.slice" - if m.rootless { + if m.cgroups.Rootless { slice = "user.slice" } if c.Parent != "" { @@ -247,12 +253,14 @@ func (m *unifiedManager) Apply(pid int) error { 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") { + // If we create a slice, the parent is defined via a Wants=. properties = append(properties, systemdDbus.PropWants(slice)) } else { - // otherwise, we use Slice= + // Otherwise it's a scope, which we put into a Slice=. properties = append(properties, systemdDbus.PropSlice(slice)) + // Assume scopes always support delegation (supported since systemd v218). + properties = append(properties, newProp("Delegate", true)) } // only add pid if its valid, -1 is used w/ general slice creation. @@ -260,12 +268,6 @@ func (m *unifiedManager) Apply(pid int) error { 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, @@ -282,22 +284,53 @@ func (m *unifiedManager) Apply(pid int) error { properties = append(properties, c.SystemdProps...) if err := startUnit(m.dbus, unitName, properties); err != nil { - return errors.Wrapf(err, "error while starting unit %q with properties %+v", unitName, properties) + return fmt.Errorf("unable to start unit %q (properties %+v): %w", unitName, properties, err) } - if err := m.initPath(); err != nil { - return err - } if err := fs2.CreateCgroupPath(m.path, m.cgroups); err != nil { return err } + + if c.OwnerUID != nil { + filesToChown, err := cgroupFilesToChown() + if err != nil { + return err + } + + for _, v := range filesToChown { + err := os.Chown(m.path+"/"+v, *c.OwnerUID, -1) + if err != nil { + return err + } + } + } + return nil } -func (m *unifiedManager) Destroy() error { - if m.cgroups.Paths != nil { - return nil +// The kernel exposes a list of files that should be chowned to the delegate +// uid in /sys/kernel/cgroup/delegate. If the file is not present +// (Linux < 4.15), use the initial values mentioned in cgroups(7). +func cgroupFilesToChown() ([]string, error) { + filesToChown := []string{"."} // the directory itself must be chowned + const cgroupDelegateFile = "/sys/kernel/cgroup/delegate" + f, err := os.Open(cgroupDelegateFile) + if err == nil { + defer f.Close() + scanner := bufio.NewScanner(f) + for scanner.Scan() { + filesToChown = append(filesToChown, scanner.Text()) + } + if err := scanner.Err(); err != nil { + return nil, fmt.Errorf("error reading %s: %w", cgroupDelegateFile, err) + } + } else { + filesToChown = append(filesToChown, "cgroup.procs", "cgroup.subtree_control", "cgroup.threads") } + return filesToChown, nil +} + +func (m *unifiedManager) Destroy() error { m.mu.Lock() defer m.mu.Unlock() @@ -307,8 +340,8 @@ func (m *unifiedManager) Destroy() error { } // systemd 239 do not remove sub-cgroups. - err := cgroups.RemovePath(m.path) - // cgroups.RemovePath has handled ErrNotExist + err := m.fsMgr.Destroy() + // fsMgr.Destroy has handled ErrNotExist if err != nil { return err } @@ -317,7 +350,6 @@ func (m *unifiedManager) Destroy() error { } func (m *unifiedManager) Path(_ string) string { - _ = m.initPath() return m.path } @@ -326,7 +358,7 @@ func (m *unifiedManager) Path(_ string) string { func (m *unifiedManager) getSliceFull() (string, error) { c := m.cgroups slice := "system.slice" - if m.rootless { + if c.Rootless { slice = "user.slice" } if c.Parent != "" { @@ -337,7 +369,7 @@ func (m *unifiedManager) getSliceFull() (string, error) { } } - if m.rootless { + if c.Rootless { // managerCG is typically "/user.slice/user-${uid}.slice/user@${uid}.service". managerCG, err := getManagerProperty(m.dbus, "ControlGroup") if err != nil { @@ -375,58 +407,36 @@ func (m *unifiedManager) initPath() error { return nil } -func (m *unifiedManager) fsManager() (cgroups.Manager, error) { - if err := m.initPath(); err != nil { - return nil, err - } - return fs2.NewManager(m.cgroups, m.path, m.rootless) -} - func (m *unifiedManager) Freeze(state configs.FreezerState) error { - fsMgr, err := m.fsManager() - if err != nil { - return err - } - return fsMgr.Freeze(state) + return m.fsMgr.Freeze(state) } func (m *unifiedManager) GetPids() ([]int, error) { - if err := m.initPath(); err != nil { - return nil, err - } return cgroups.GetPids(m.path) } func (m *unifiedManager) GetAllPids() ([]int, error) { - if err := m.initPath(); err != nil { - return nil, err - } return cgroups.GetAllPids(m.path) } func (m *unifiedManager) GetStats() (*cgroups.Stats, error) { - fsMgr, err := m.fsManager() - if err != nil { - return nil, err - } - return fsMgr.GetStats() + return m.fsMgr.GetStats() } func (m *unifiedManager) Set(r *configs.Resources) error { + if r == nil { + return nil + } properties, err := genV2ResourcesProperties(r, m.dbus) if err != nil { return err } if err := setUnitProperties(m.dbus, getUnitName(m.cgroups), properties...); err != nil { - return errors.Wrap(err, "error while setting unit properties") + return fmt.Errorf("unable to set unit properties: %w", err) } - fsMgr, err := m.fsManager() - if err != nil { - return err - } - return fsMgr.Set(r) + return m.fsMgr.Set(r) } func (m *unifiedManager) GetPaths() map[string]string { @@ -440,11 +450,7 @@ func (m *unifiedManager) GetCgroups() (*configs.Cgroup, error) { } func (m *unifiedManager) GetFreezerState() (configs.FreezerState, error) { - fsMgr, err := m.fsManager() - if err != nil { - return configs.Undefined, err - } - return fsMgr.GetFreezerState() + return m.fsMgr.GetFreezerState() } func (m *unifiedManager) Exists() bool { @@ -452,9 +458,5 @@ func (m *unifiedManager) Exists() bool { } func (m *unifiedManager) OOMKillCount() (uint64, error) { - fsMgr, err := m.fsManager() - if err != nil { - return 0, err - } - return fsMgr.OOMKillCount() + return m.fsMgr.OOMKillCount() } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go index 92606525b4d77..13ebf52abe4bf 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go @@ -1,5 +1,3 @@ -// +build linux - package cgroups import ( @@ -7,7 +5,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "os" "path/filepath" "strconv" @@ -23,11 +20,14 @@ import ( const ( CgroupProcesses = "cgroup.procs" unifiedMountpoint = "/sys/fs/cgroup" + hybridMountpoint = "/sys/fs/cgroup/unified" ) var ( isUnifiedOnce sync.Once isUnified bool + isHybridOnce sync.Once + isHybrid bool ) // IsCgroup2UnifiedMode returns whether we are running in cgroup v2 unified mode. @@ -49,6 +49,24 @@ func IsCgroup2UnifiedMode() bool { return isUnified } +// IsCgroup2HybridMode returns whether we are running in cgroup v2 hybrid mode. +func IsCgroup2HybridMode() bool { + isHybridOnce.Do(func() { + var st unix.Statfs_t + err := unix.Statfs(hybridMountpoint, &st) + if err != nil { + if os.IsNotExist(err) { + // ignore the "not found" error + isHybrid = false + return + } + panic(fmt.Sprintf("cannot statfs cgroup root: %s", err)) + } + isHybrid = st.Type == unix.CGROUP2_SUPER_MAGIC + }) + return isHybrid +} + type Mount struct { Mountpoint string Root string @@ -118,8 +136,8 @@ func GetAllSubsystems() ([]string, error) { return subsystems, nil } -func readProcsFile(file string) ([]int, error) { - f, err := os.Open(file) +func readProcsFile(dir string) ([]int, error) { + f, err := OpenFile(dir, CgroupProcesses, os.O_RDONLY) if err != nil { return nil, err } @@ -210,7 +228,7 @@ func EnterPid(cgroupPaths map[string]string, pid int) error { func rmdir(path string) error { err := unix.Rmdir(path) - if err == nil || err == unix.ENOENT { + if err == nil || err == unix.ENOENT { //nolint:errorlint // unix errors are bare return nil } return &os.PathError{Op: "rmdir", Path: path, Err: err} @@ -224,7 +242,7 @@ func RemovePath(path string) error { return nil } - infos, err := ioutil.ReadDir(path) + infos, err := os.ReadDir(path) if err != nil { if os.IsNotExist(err) { err = nil @@ -284,40 +302,61 @@ func RemovePaths(paths map[string]string) (err error) { return fmt.Errorf("Failed to remove paths: %v", paths) } -func GetHugePageSize() ([]string, error) { - dir, err := os.OpenFile("/sys/kernel/mm/hugepages", unix.O_DIRECTORY|unix.O_RDONLY, 0) - if err != nil { - return nil, err - } - files, err := dir.Readdirnames(0) - dir.Close() - if err != nil { - return nil, err - } +var ( + hugePageSizes []string + initHPSOnce sync.Once +) - return getHugePageSizeFromFilenames(files) +func HugePageSizes() []string { + initHPSOnce.Do(func() { + dir, err := os.OpenFile("/sys/kernel/mm/hugepages", unix.O_DIRECTORY|unix.O_RDONLY, 0) + if err != nil { + return + } + files, err := dir.Readdirnames(0) + dir.Close() + if err != nil { + return + } + + hugePageSizes, err = getHugePageSizeFromFilenames(files) + if err != nil { + logrus.Warn("HugePageSizes: ", err) + } + }) + + return hugePageSizes } func getHugePageSizeFromFilenames(fileNames []string) ([]string, error) { pageSizes := make([]string, 0, len(fileNames)) + var warn error for _, file := range fileNames { // example: hugepages-1048576kB val := strings.TrimPrefix(file, "hugepages-") if len(val) == len(file) { - // unexpected file name: no prefix found + // Unexpected file name: no prefix found, ignore it. continue } - // The suffix is always "kB" (as of Linux 5.9) + // The suffix is always "kB" (as of Linux 5.13). If we find + // something else, produce an error but keep going. eLen := len(val) - 2 val = strings.TrimSuffix(val, "kB") if len(val) != eLen { - logrus.Warnf("GetHugePageSize: %s: invalid filename suffix (expected \"kB\")", file) + // Highly unlikely. + if warn == nil { + warn = errors.New(file + `: invalid suffix (expected "kB")`) + } continue } size, err := strconv.Atoi(val) if err != nil { - return nil, err + // Highly unlikely. + if warn == nil { + warn = fmt.Errorf("%s: %w", file, err) + } + continue } // Model after https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/mm/hugetlb_cgroup.c?id=eff48ddeab782e35e58ccc8853f7386bbae9dec4#n574 // but in our case the size is in KB already. @@ -331,34 +370,12 @@ func getHugePageSizeFromFilenames(fileNames []string) ([]string, error) { pageSizes = append(pageSizes, val) } - return pageSizes, nil + return pageSizes, warn } // GetPids returns all pids, that were added to cgroup at path. func GetPids(dir string) ([]int, error) { - return readProcsFile(filepath.Join(dir, CgroupProcesses)) -} - -// GetAllPids returns all pids, that were added to cgroup at path and to all its -// subcgroups. -func GetAllPids(path string) ([]int, error) { - var pids []int - // collect pids from all sub-cgroups - err := filepath.Walk(path, func(p string, info os.FileInfo, iErr error) error { - if iErr != nil { - return iErr - } - if info.IsDir() || info.Name() != CgroupProcesses { - return nil - } - cPids, err := readProcsFile(p) - if err != nil { - return err - } - pids = append(pids, cPids...) - return nil - }) - return pids, err + return readProcsFile(dir) } // WriteCgroupProc writes the specified pid into the cgroup's cgroup.procs file @@ -376,7 +393,7 @@ func WriteCgroupProc(dir string, pid int) error { file, err := OpenFile(dir, CgroupProcesses, os.O_WRONLY) if err != nil { - return fmt.Errorf("failed to write %v to %v: %v", pid, CgroupProcesses, err) + return fmt.Errorf("failed to write %v: %w", pid, err) } defer file.Close() @@ -393,7 +410,7 @@ func WriteCgroupProc(dir string, pid int) error { continue } - return fmt.Errorf("failed to write %v to %v: %v", pid, CgroupProcesses, err) + return fmt.Errorf("failed to write %v: %w", pid, err) } return err } @@ -446,5 +463,5 @@ func ConvertBlkIOToIOWeightValue(blkIoWeight uint16) uint64 { if blkIoWeight == 0 { return 0 } - return uint64(1 + (uint64(blkIoWeight)-10)*9999/990) + return 1 + (uint64(blkIoWeight)-10)*9999/990 } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/v1_utils.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/v1_utils.go index 95ec9dff0284d..47c75f22b422f 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/v1_utils.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/v1_utils.go @@ -46,11 +46,8 @@ func NewNotFoundError(sub string) error { } func IsNotFound(err error) bool { - if err == nil { - return false - } - _, ok := err.(*NotFoundError) - return ok + var nfErr *NotFoundError + return errors.As(err, &nfErr) } func tryDefaultPath(cgroupPath, subsystem string) string { @@ -116,6 +113,11 @@ func FindCgroupMountpoint(cgroupPath, subsystem string) (string, error) { return "", errUnified } + // If subsystem is empty, we look for the cgroupv2 hybrid path. + if len(subsystem) == 0 { + return hybridMountpoint, nil + } + // Avoid parsing mountinfo by trying the default path first, if possible. if path := tryDefaultPath(cgroupPath, subsystem); path != "" { return path, nil @@ -154,7 +156,7 @@ func findCgroupMountpointAndRootFromMI(mounts []*mountinfo.Info, cgroupPath, sub func (m Mount) GetOwnCgroup(cgroups map[string]string) (string, error) { if len(m.Subsystems) == 0 { - return "", fmt.Errorf("no subsystem for mount") + return "", errors.New("no subsystem for mount") } return getControllerPath(m.Subsystems[0], cgroups) @@ -226,6 +228,11 @@ func GetOwnCgroupPath(subsystem string) (string, error) { return "", err } + // If subsystem is empty, we look for the cgroupv2 hybrid path. + if len(subsystem) == 0 { + return hybridMountpoint, nil + } + return getCgroupPathHelper(subsystem, cgroup) } 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 5ea9d940cef6d..2d4a8987109a6 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go @@ -28,17 +28,26 @@ type Cgroup struct { // ScopePrefix describes prefix for the scope name ScopePrefix string `json:"scope_prefix"` - // Paths represent the absolute cgroups paths to join. - // This takes precedence over Path. - Paths map[string]string - // Resources contains various cgroups settings to apply *Resources + // Systemd tells if systemd should be used to manage cgroups. + Systemd bool + // SystemdProps are any additional properties for systemd, // derived from org.systemd.property.xxx annotations. // Ignored unless systemd is used for managing cgroups. SystemdProps []systemdDbus.Property `json:"-"` + + // Rootless tells if rootless cgroups should be used. + Rootless bool + + // The host UID that should own the cgroup, or nil to accept + // the default ownership. This should only be set when the + // cgroupfs is to be mounted read/write. + // Not all cgroup manager implementations support changing + // the ownership. + OwnerUID *int `json:"owner_uid,omitempty"` } type Resources struct { @@ -117,6 +126,9 @@ type Resources struct { // Set class identifier for container's network packets NetClsClassid uint32 `json:"net_cls_classid_u"` + // Rdma resource restriction configuration + Rdma map[string]LinuxRdma `json:"rdma"` + // Used on cgroups v2: // CpuWeight sets a proportional bandwidth limit. diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go index 2a519f582d2ac..7e383020f4cd1 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go @@ -1,3 +1,4 @@ +//go:build !linux // +build !linux package configs diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go index 4281593f0b757..c1b4a0041c20b 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go @@ -7,10 +7,10 @@ import ( "os/exec" "time" + "github.com/sirupsen/logrus" + "github.com/opencontainers/runc/libcontainer/devices" "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" ) type Rlimit struct { @@ -31,10 +31,12 @@ type IDMap struct { // for syscalls. Additional architectures can be added by specifying them in // Architectures. type Seccomp struct { - DefaultAction Action `json:"default_action"` - Architectures []string `json:"architectures"` - Syscalls []*Syscall `json:"syscalls"` - DefaultErrnoRet *uint `json:"default_errno_ret"` + DefaultAction Action `json:"default_action"` + Architectures []string `json:"architectures"` + Syscalls []*Syscall `json:"syscalls"` + DefaultErrnoRet *uint `json:"default_errno_ret"` + ListenerPath string `json:"listener_path,omitempty"` + ListenerMetadata string `json:"listener_metadata,omitempty"` } // Action is taken upon rule match in Seccomp @@ -47,6 +49,9 @@ const ( Allow Trace Log + Notify + KillThread + KillProcess ) // Operator is a comparison operator to be used when matching syscall arguments in Seccomp @@ -246,6 +251,19 @@ const ( Poststop HookName = "poststop" ) +// KnownHookNames returns the known hook names. +// Used by `runc features`. +func KnownHookNames() []string { + return []string{ + string(Prestart), // deprecated + string(CreateRuntime), + string(CreateContainer), + string(StartContainer), + string(Poststart), + string(Poststop), + } +} + type Capabilities struct { // Bounding is the set of capabilities checked by the kernel. Bounding []string @@ -262,7 +280,7 @@ type Capabilities struct { func (hooks HookList) RunHooks(state *specs.State) error { for i, h := range hooks { if err := h.Run(state); err != nil { - return errors.Wrapf(err, "Running hook #%d:", i) + return fmt.Errorf("error running hook #%d: %w", i, err) } } @@ -375,7 +393,7 @@ func (c Command) Run(s *specs.State) error { go func() { err := cmd.Wait() if err != nil { - err = fmt.Errorf("error running hook: %v, stdout: %s, stderr: %s", err, stdout.String(), stderr.String()) + err = fmt.Errorf("error running hook: %w, stdout: %s, stderr: %s", err, stdout.String(), stderr.String()) } errC <- err }() diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux.go index 07da10804540d..8c02848b70ab8 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux.go @@ -1,17 +1,24 @@ package configs -import "fmt" +import "errors" + +var ( + errNoUIDMap = errors.New("User namespaces enabled, but no uid mappings found.") + errNoUserMap = errors.New("User namespaces enabled, but no user mapping found.") + errNoGIDMap = errors.New("User namespaces enabled, but no gid mappings found.") + errNoGroupMap = errors.New("User namespaces enabled, but no group mapping found.") +) // HostUID gets the translated uid for the process on host which could be // different when user namespaces are enabled. func (c Config) HostUID(containerId int) (int, error) { if c.Namespaces.Contains(NEWUSER) { if c.UidMappings == nil { - return -1, fmt.Errorf("User namespaces enabled, but no uid mappings found.") + return -1, errNoUIDMap } id, found := c.hostIDFromMapping(containerId, c.UidMappings) if !found { - return -1, fmt.Errorf("User namespaces enabled, but no user mapping found.") + return -1, errNoUserMap } return id, nil } @@ -30,11 +37,11 @@ func (c Config) HostRootUID() (int, error) { func (c Config) HostGID(containerId int) (int, error) { if c.Namespaces.Contains(NEWUSER) { if c.GidMappings == nil { - return -1, fmt.Errorf("User namespaces enabled, but no gid mappings found.") + return -1, errNoGIDMap } id, found := c.hostIDFromMapping(containerId, c.GidMappings) if !found { - return -1, fmt.Errorf("User namespaces enabled, but no group mapping found.") + return -1, errNoGroupMap } return id, nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/configs_fuzzer.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/configs_fuzzer.go index 93bf41c8defc8..bce829e290ad5 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/configs_fuzzer.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/configs_fuzzer.go @@ -1,3 +1,4 @@ +//go:build gofuzz // +build gofuzz package configs diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/intelrdt.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/intelrdt.go index 57e9f037d9797..f8d951ab8b9d3 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/intelrdt.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/intelrdt.go @@ -1,6 +1,9 @@ package configs type IntelRdt struct { + // The identity for RDT Class of Service + ClosID string `json:"closID,omitempty"` + // The schema for L3 cache id and capacity bitmask (CBM) // Format: "L3:=;=;..." L3CacheSchema string `json:"l3_cache_schema,omitempty"` diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/mount.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/mount.go index a75ff10ec9dd0..784c6182051ef 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/mount.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/mount.go @@ -1,5 +1,7 @@ package configs +import "golang.org/x/sys/unix" + const ( // EXT_COPYUP is a directive to copy up the contents of a directory when // a tmpfs is mounted over it. @@ -28,6 +30,9 @@ type Mount struct { // Relabel source if set, "z" indicates shared, "Z" indicates unshared. Relabel string `json:"relabel"` + // RecAttr represents mount properties to be applied recursively (AT_RECURSIVE), see mount_setattr(2). + RecAttr *unix.MountAttr `json:"rec_attr"` + // Extensions are additional flags that are specific to runc. Extensions int `json:"extensions"` @@ -37,3 +42,7 @@ type Mount struct { // Optional Command to be run after Source is mounted. PostmountCmds []Command `json:"postmount_cmds"` } + +func (m *Mount) IsBind() bool { + return m.Flags&unix.MS_BIND != 0 +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall.go index 2dc7adfc9660a..0516dba8d09b0 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux package configs diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall_unsupported.go index 5d9a5c81f3fd5..fbb0d49071e2e 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall_unsupported.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall_unsupported.go @@ -1,3 +1,4 @@ +//go:build !linux && !windows // +build !linux,!windows package configs diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go index cc76e2f586adc..946db30a549a5 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go @@ -1,3 +1,4 @@ +//go:build !linux // +build !linux package configs diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/rdma.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/rdma.go new file mode 100644 index 0000000000000..c69f2c8024bc1 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/rdma.go @@ -0,0 +1,9 @@ +package configs + +// LinuxRdma for Linux cgroup 'rdma' resource management (Linux 4.11) +type LinuxRdma struct { + // Maximum number of HCA handles that can be opened. Default is "no limit". + HcaHandles *uint32 `json:"hca_handles,omitempty"` + // Maximum number of HCA objects that can be created. Default is "no limit". + HcaObjects *uint32 `json:"hca_objects,omitempty"` +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go index b0254600244ba..6493124a3f26e 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go @@ -52,7 +52,7 @@ func (v *ConfigValidator) Validate(config *configs.Config) error { } for _, c := range warns { if err := c(config); err != nil { - logrus.WithError(err).Warnf("invalid configuration") + logrus.WithError(err).Warn("invalid configuration") } } return nil @@ -62,20 +62,17 @@ func (v *ConfigValidator) Validate(config *configs.Config) error { // to the container's root filesystem. func (v *ConfigValidator) rootfs(config *configs.Config) error { if _, err := os.Stat(config.Rootfs); err != nil { - if os.IsNotExist(err) { - return fmt.Errorf("rootfs (%s) does not exist", config.Rootfs) - } - return err + return fmt.Errorf("invalid rootfs: %w", err) } cleaned, err := filepath.Abs(config.Rootfs) if err != nil { - return err + return fmt.Errorf("invalid rootfs: %w", err) } if cleaned, err = filepath.EvalSymlinks(cleaned); err != nil { - return err + return fmt.Errorf("invalid rootfs: %w", err) } if filepath.Clean(config.Rootfs) != cleaned { - return fmt.Errorf("%s is not an absolute path or is a symlink", config.Rootfs) + return errors.New("invalid rootfs: not an absolute path, or a symlink") } return nil } @@ -131,6 +128,36 @@ func (v *ConfigValidator) cgroupnamespace(config *configs.Config) error { return nil } +// convertSysctlVariableToDotsSeparator can return sysctl variables in dots separator format. +// The '/' separator is also accepted in place of a '.'. +// Convert the sysctl variables to dots separator format for validation. +// More info: +// https://man7.org/linux/man-pages/man8/sysctl.8.html +// https://man7.org/linux/man-pages/man5/sysctl.d.5.html +// For example: +// Input sysctl variable "net/ipv4/conf/eno2.100.rp_filter" +// will return the converted value "net.ipv4.conf.eno2/100.rp_filter" +func convertSysctlVariableToDotsSeparator(val string) string { + if val == "" { + return val + } + firstSepIndex := strings.IndexAny(val, "./") + if firstSepIndex == -1 || val[firstSepIndex] == '.' { + return val + } + + f := func(r rune) rune { + switch r { + case '.': + return '/' + case '/': + return '.' + } + return r + } + return strings.Map(f, val) +} + // sysctl validates that the specified sysctl keys are valid or not. // /proc/sys isn't completely namespaced and depending on which namespaces // are specified, a subset of sysctls are permitted. @@ -153,6 +180,7 @@ func (v *ConfigValidator) sysctl(config *configs.Config) error { ) for s := range config.Sysctl { + s := convertSysctlVariableToDotsSeparator(s) if validSysctlMap[s] || strings.HasPrefix(s, "fs.mqueue.") { if config.Namespaces.Contains(configs.NEWIPC) { continue @@ -176,7 +204,7 @@ func (v *ConfigValidator) sysctl(config *configs.Config) error { hostnet, hostnetErr = isHostNetNS(path) }) if hostnetErr != nil { - return hostnetErr + return fmt.Errorf("invalid netns path: %w", hostnetErr) } if hostnet { return fmt.Errorf("sysctl %q not allowed in host network namespace", s) @@ -205,19 +233,16 @@ func (v *ConfigValidator) intelrdt(config *configs.Config) error { return errors.New("intelRdt is specified in config, but Intel RDT is not supported or enabled") } + if config.IntelRdt.ClosID == "." || config.IntelRdt.ClosID == ".." || strings.Contains(config.IntelRdt.ClosID, "/") { + return fmt.Errorf("invalid intelRdt.ClosID %q", config.IntelRdt.ClosID) + } + if !intelrdt.IsCATEnabled() && config.IntelRdt.L3CacheSchema != "" { return errors.New("intelRdt.l3CacheSchema is specified in config, but Intel RDT/CAT is not enabled") } if !intelrdt.IsMBAEnabled() && config.IntelRdt.MemBwSchema != "" { return errors.New("intelRdt.memBwSchema is specified in config, but Intel RDT/MBA is not enabled") } - - if intelrdt.IsCATEnabled() && config.IntelRdt.L3CacheSchema == "" { - return errors.New("Intel RDT/CAT is enabled and intelRdt is specified in config, but intelRdt.l3CacheSchema is empty") - } - if intelrdt.IsMBAEnabled() && config.IntelRdt.MemBwSchema == "" { - return errors.New("Intel RDT/MBA is enabled and intelRdt is specified in config, but intelRdt.memBwSchema is empty") - } } return nil @@ -268,10 +293,10 @@ func isHostNetNS(path string) (bool, error) { var st1, st2 unix.Stat_t if err := unix.Stat(currentProcessNetns, &st1); err != nil { - return false, fmt.Errorf("unable to stat %q: %s", currentProcessNetns, err) + return false, &os.PathError{Op: "stat", Path: currentProcessNetns, Err: err} } if err := unix.Stat(path, &st2); err != nil { - return false, fmt.Errorf("unable to stat %q: %s", path, err) + return false, &os.PathError{Op: "stat", Path: path, Err: err} } return (st1.Dev == st2.Dev) && (st1.Ino == st2.Ino), nil diff --git a/vendor/github.com/opencontainers/runc/libcontainer/console_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/console_linux.go index 7bfff026ac8ec..29b9c3b0897a4 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/console_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/console_linux.go @@ -18,7 +18,7 @@ func mountConsole(slavePath string) error { if f != nil { f.Close() } - return unix.Mount(slavePath, "/dev/console", "bind", unix.MS_BIND, "") + return mount(slavePath, "/dev/console", "", "bind", unix.MS_BIND, "") } // dupStdio opens the slavePath for the console and dups the fds to the current diff --git a/vendor/github.com/opencontainers/runc/libcontainer/container.go b/vendor/github.com/opencontainers/runc/libcontainer/container.go index ba7541c5fd68f..300c9526cf97e 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/container.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/container.go @@ -74,22 +74,12 @@ type BaseContainer interface { ID() string // Returns the current status of the container. - // - // errors: - // ContainerNotExists - Container no longer exists, - // Systemerror - System error. Status() (Status, error) // State returns the current container's state information. - // - // errors: - // SystemError - System error. State() (*State, error) // OCIState returns the current container's state information. - // - // errors: - // SystemError - System error. OCIState() (*specs.State, error) // Returns the current config of the container. @@ -97,48 +87,26 @@ type BaseContainer interface { // Returns the PIDs inside this container. The PIDs are in the namespace of the calling process. // - // errors: - // ContainerNotExists - Container no longer exists, - // Systemerror - System error. - // // Some of the returned PIDs may no longer refer to processes in the Container, unless // the Container state is PAUSED in which case every PID in the slice is valid. Processes() ([]int, error) // Returns statistics for the container. - // - // errors: - // ContainerNotExists - Container no longer exists, - // Systemerror - System error. Stats() (*Stats, error) // Set resources of container as configured // // We can use this to change resources when containers are running. // - // errors: - // SystemError - System error. Set(config configs.Config) error // Start a process inside the container. Returns error if process fails to // start. You can track process lifecycle with passed Process structure. - // - // errors: - // ContainerNotExists - Container no longer exists, - // ConfigInvalid - config is invalid, - // ContainerPaused - Container is paused, - // SystemError - System error. Start(process *Process) (err error) // Run immediately starts the process inside the container. Returns error if process // fails to start. It does not block waiting for the exec fifo after start returns but // opens the fifo after start returns. - // - // errors: - // ContainerNotExists - Container no longer exists, - // ConfigInvalid - config is invalid, - // ContainerPaused - Container is paused, - // SystemError - System error. Run(process *Process) (err error) // Destroys the container, if its in a valid state, after killing any @@ -149,25 +117,14 @@ type BaseContainer interface { // // Running containers must first be stopped using Signal(..). // Paused containers must first be resumed using Resume(..). - // - // errors: - // ContainerNotStopped - Container is still running, - // ContainerPaused - Container is paused, - // SystemError - System error. Destroy() error // Signal sends the provided signal code to the container's initial process. // // If all is specified the signal is sent to all processes in the container // including the initial process. - // - // errors: - // SystemError - System error. Signal(s os.Signal, all bool) error // Exec signals the container to exec the users process at the end of the init. - // - // errors: - // SystemError - System error. Exec() error } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go index 1484703b0c5de..f6877b7429f5d 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go @@ -1,5 +1,3 @@ -// +build linux - package libcontainer import ( @@ -8,10 +6,10 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net" "os" "os/exec" + "path" "path/filepath" "reflect" "strconv" @@ -19,21 +17,20 @@ import ( "sync" "time" - securejoin "github.com/cyphar/filepath-securejoin" - "github.com/opencontainers/runc/libcontainer/cgroups" - "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/runc/libcontainer/intelrdt" - "github.com/opencontainers/runc/libcontainer/system" - "github.com/opencontainers/runc/libcontainer/utils" - "github.com/opencontainers/runtime-spec/specs-go" - "github.com/checkpoint-restore/go-criu/v5" criurpc "github.com/checkpoint-restore/go-criu/v5/rpc" - errorsf "github.com/pkg/errors" + securejoin "github.com/cyphar/filepath-securejoin" + "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" "github.com/vishvananda/netlink/nl" "golang.org/x/sys/unix" "google.golang.org/protobuf/proto" + + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/intelrdt" + "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/runc/libcontainer/utils" ) const stdioFdCount = 3 @@ -98,48 +95,26 @@ type Container interface { // Methods below here are platform specific // Checkpoint checkpoints the running container's state to disk using the criu(8) utility. - // - // errors: - // Systemerror - System error. Checkpoint(criuOpts *CriuOpts) error // Restore restores the checkpointed container to a running state using the criu(8) utility. - // - // errors: - // Systemerror - System error. Restore(process *Process, criuOpts *CriuOpts) error // If the Container state is RUNNING or CREATED, sets the Container state to PAUSING and pauses // the execution of any user processes. Asynchronously, when the container finished being paused the // state is changed to PAUSED. // If the Container state is PAUSED, do nothing. - // - // errors: - // ContainerNotExists - Container no longer exists, - // ContainerNotRunning - Container not running or created, - // Systemerror - System error. Pause() error // If the Container state is PAUSED, resumes the execution of any user processes in the // Container before setting the Container state to RUNNING. // If the Container state is RUNNING, do nothing. - // - // errors: - // ContainerNotExists - Container no longer exists, - // ContainerNotPaused - Container is not paused, - // Systemerror - System error. Resume() error // NotifyOOM returns a read-only channel signaling when the container receives an OOM notification. - // - // errors: - // Systemerror - System error. NotifyOOM() (<-chan struct{}, error) // NotifyMemoryPressure returns a read-only channel signaling when the container reaches a given pressure level - // - // errors: - // Systemerror - System error. NotifyMemoryPressure(level PressureLevel) (<-chan struct{}, error) } @@ -184,7 +159,7 @@ func (c *linuxContainer) Processes() ([]int, error) { pids, err = c.cgroupManager.GetAllPids() if err != nil { - return nil, newSystemErrorWithCause(err, "getting all container pids from cgroups") + return nil, fmt.Errorf("unable to get all container pids: %w", err) } return pids, nil } @@ -195,11 +170,11 @@ func (c *linuxContainer) Stats() (*Stats, error) { stats = &Stats{} ) if stats.CgroupStats, err = c.cgroupManager.GetStats(); err != nil { - return stats, newSystemErrorWithCause(err, "getting container stats from cgroups") + return stats, fmt.Errorf("unable to get container cgroup stats: %w", err) } if c.intelRdtManager != nil { if stats.IntelRdtStats, err = c.intelRdtManager.GetStats(); err != nil { - return stats, newSystemErrorWithCause(err, "getting container's Intel RDT stats") + return stats, fmt.Errorf("unable to get container Intel RDT stats: %w", err) } } for _, iface := range c.config.Networks { @@ -207,7 +182,7 @@ func (c *linuxContainer) Stats() (*Stats, error) { case "veth": istats, err := getNetworkInterfaceStats(iface.HostInterfaceName) if err != nil { - return stats, newSystemErrorWithCausef(err, "getting network stats for interface %q", iface.HostInterfaceName) + return stats, fmt.Errorf("unable to get network stats for interface %q: %w", iface.HostInterfaceName, err) } stats.Interfaces = append(stats.Interfaces, istats) } @@ -223,7 +198,7 @@ func (c *linuxContainer) Set(config configs.Config) error { return err } if status == Stopped { - return newGenericError(errors.New("container not running"), ContainerNotRunning) + return ErrNotRunning } if err := c.cgroupManager.Set(config.Cgroups.Resources); err != nil { // Set configs back @@ -254,7 +229,7 @@ func (c *linuxContainer) Start(process *Process) error { c.m.Lock() defer c.m.Unlock() if c.config.Cgroups.Resources.SkipDevices { - return newGenericError(errors.New("can't start container with SkipDevices set"), ConfigInvalid) + return errors.New("can't start container with SkipDevices set") } if process.Init { if err := c.createExecFifo(); err != nil { @@ -310,7 +285,7 @@ func (c *linuxContainer) exec() error { } func readFromExecFifo(execFifo io.Reader) error { - data, err := ioutil.ReadAll(execFifo) + data, err := io.ReadAll(execFifo) if err != nil { return err } @@ -336,7 +311,7 @@ func fifoOpen(path string, block bool) openResult { } f, err := os.OpenFile(path, flags, 0) if err != nil { - return openResult{err: newSystemErrorWithCause(err, "open exec fifo for reading")} + return openResult{err: fmt.Errorf("exec fifo: %w", err)} } return openResult{file: f} } @@ -361,7 +336,7 @@ type openResult struct { func (c *linuxContainer) start(process *Process) (retErr error) { parent, err := c.newParentProcess(process) if err != nil { - return newSystemErrorWithCause(err, "creating new parent process") + return fmt.Errorf("unable to create new parent process: %w", err) } logsDone := parent.forwardChildLogs() @@ -371,13 +346,13 @@ func (c *linuxContainer) start(process *Process) (retErr error) { // runc init closing the _LIBCONTAINER_LOGPIPE log fd. err := <-logsDone if err != nil && retErr == nil { - retErr = newSystemErrorWithCause(err, "forwarding init logs") + retErr = fmt.Errorf("unable to forward init logs: %w", err) } }() } if err := parent.start(); err != nil { - return newSystemErrorWithCause(err, "starting container process") + return fmt.Errorf("unable to start container process: %w", err) } if process.Init { @@ -390,7 +365,7 @@ func (c *linuxContainer) start(process *Process) (retErr error) { if err := c.config.Hooks[configs.Poststart].RunHooks(s); err != nil { if err := ignoreTerminateErrors(parent.terminate()); err != nil { - logrus.Warn(errorsf.Wrapf(err, "Running Poststart hook")) + logrus.Warn(fmt.Errorf("error running poststart hook: %w", err)) } return err } @@ -416,11 +391,19 @@ func (c *linuxContainer) Signal(s os.Signal, all bool) error { // to avoid a PID reuse attack if status == Running || status == Created || status == Paused { if err := c.initProcess.signal(s); err != nil { - return newSystemErrorWithCause(err, "signaling init process") + return fmt.Errorf("unable to signal init: %w", err) + } + if status == Paused { + // For cgroup v1, killing a process in a frozen cgroup + // does nothing until it's thawed. Only thaw the cgroup + // for SIGKILL. + if s, ok := s.(unix.Signal); ok && s == unix.SIGKILL { + _ = c.cgroupManager.Freeze(configs.Thawed) + } } return nil } - return newGenericError(errors.New("container not running"), ContainerNotRunning) + return ErrNotRunning } func (c *linuxContainer) createExecFifo() error { @@ -472,13 +455,13 @@ func (c *linuxContainer) includeExecFifo(cmd *exec.Cmd) error { func (c *linuxContainer) newParentProcess(p *Process) (parentProcess, error) { parentInitPipe, childInitPipe, err := utils.NewSockPair("init") if err != nil { - return nil, newSystemErrorWithCause(err, "creating new init pipe") + return nil, fmt.Errorf("unable to create init pipe: %w", err) } messageSockPair := filePair{parentInitPipe, childInitPipe} parentLogPipe, childLogPipe, err := os.Pipe() if err != nil { - return nil, fmt.Errorf("Unable to create the log pipe: %s", err) + return nil, fmt.Errorf("unable to create log pipe: %w", err) } logFilePair := filePair{parentLogPipe, childLogPipe} @@ -493,7 +476,7 @@ func (c *linuxContainer) newParentProcess(p *Process) (parentProcess, error) { // that problem), but we no longer do that. However, there's no need to do // this for `runc exec` so we just keep it this way to be safe. if err := c.includeExecFifo(cmd); err != nil { - return nil, newSystemErrorWithCause(err, "including execfifo in cmd.Exec setup") + return nil, fmt.Errorf("unable to setup exec fifo: %w", err) } return c.newInitProcess(p, cmd, messageSockPair, logFilePair) } @@ -537,6 +520,33 @@ func (c *linuxContainer) commandTemplate(p *Process, childInitPipe *os.File, chi return cmd } +// shouldSendMountSources says whether the child process must setup bind mounts with +// the source pre-opened (O_PATH) in the host user namespace. +// See https://github.com/opencontainers/runc/issues/2484 +func (c *linuxContainer) shouldSendMountSources() bool { + // Passing the mount sources via SCM_RIGHTS is only necessary when + // both userns and mntns are active. + if !c.config.Namespaces.Contains(configs.NEWUSER) || + !c.config.Namespaces.Contains(configs.NEWNS) { + return false + } + + // nsexec.c send_mountsources() requires setns(mntns) capabilities + // CAP_SYS_CHROOT and CAP_SYS_ADMIN. + if c.config.RootlessEUID { + return false + } + + // We need to send sources if there are bind-mounts. + for _, m := range c.config.Mounts { + if m.IsBind() { + return true + } + } + + return false +} + func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, messageSockPair, logFilePair filePair) (*initProcess, error) { cmd.Env = append(cmd.Env, "_LIBCONTAINER_INITTYPE="+string(initStandard)) nsMaps := make(map[configs.NamespaceType]string) @@ -546,10 +556,40 @@ func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, messageSockPa } } _, sharePidns := nsMaps[configs.NEWPID] - data, err := c.bootstrapData(c.config.Namespaces.CloneFlags(), nsMaps) + data, err := c.bootstrapData(c.config.Namespaces.CloneFlags(), nsMaps, initStandard) if err != nil { return nil, err } + + if c.shouldSendMountSources() { + // Elements on this slice will be paired with mounts (see StartInitialization() and + // prepareRootfs()). This slice MUST have the same size as c.config.Mounts. + mountFds := make([]int, len(c.config.Mounts)) + for i, m := range c.config.Mounts { + if !m.IsBind() { + // Non bind-mounts do not use an fd. + mountFds[i] = -1 + continue + } + + // The fd passed here will not be used: nsexec.c will overwrite it with dup3(). We just need + // to allocate a fd so that we know the number to pass in the environment variable. The fd + // must not be closed before cmd.Start(), so we reuse messageSockPair.child because the + // lifecycle of that fd is already taken care of. + cmd.ExtraFiles = append(cmd.ExtraFiles, messageSockPair.child) + mountFds[i] = stdioFdCount + len(cmd.ExtraFiles) - 1 + } + + mountFdsJson, err := json.Marshal(mountFds) + if err != nil { + return nil, fmt.Errorf("Error creating _LIBCONTAINER_MOUNT_FDS: %w", err) + } + + cmd.Env = append(cmd.Env, + "_LIBCONTAINER_MOUNT_FDS="+string(mountFdsJson), + ) + } + init := &initProcess{ cmd: cmd, messageSockPair: messageSockPair, @@ -570,15 +610,15 @@ func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, messageSockP cmd.Env = append(cmd.Env, "_LIBCONTAINER_INITTYPE="+string(initSetns)) state, err := c.currentState() if err != nil { - return nil, newSystemErrorWithCause(err, "getting container's current state") + return nil, fmt.Errorf("unable to get container state: %w", err) } // for setns process, we don't have to set cloneflags as the process namespaces // will only be set via setns syscall - data, err := c.bootstrapData(0, state.NamespacePaths) + data, err := c.bootstrapData(0, state.NamespacePaths, initSetns) if err != nil { return nil, err } - return &setnsProcess{ + proc := &setnsProcess{ cmd: cmd, cgroupPaths: state.CgroupPaths, rootlessCgroups: c.config.RootlessCgroups, @@ -590,7 +630,29 @@ func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, messageSockP process: p, bootstrapData: data, initProcessPid: state.InitProcessPid, - }, nil + } + if len(p.SubCgroupPaths) > 0 { + if add, ok := p.SubCgroupPaths[""]; ok { + // cgroup v1: using the same path for all controllers. + // cgroup v2: the only possible way. + for k := range proc.cgroupPaths { + proc.cgroupPaths[k] = path.Join(proc.cgroupPaths[k], add) + } + // cgroup v2: do not try to join init process's cgroup + // as a fallback (see (*setnsProcess).start). + proc.initProcessPid = 0 + } else { + // Per-controller paths. + for ctrl, add := range p.SubCgroupPaths { + if val, ok := proc.cgroupPaths[ctrl]; ok { + proc.cgroupPaths[ctrl] = path.Join(val, add) + } else { + return nil, fmt.Errorf("unknown controller %s in SubCgroupPaths", ctrl) + } + } + } + } + return proc, nil } func (c *linuxContainer) newInitConfig(process *Process) *initConfig { @@ -655,7 +717,7 @@ func (c *linuxContainer) Pause() error { c: c, }) } - return newGenericError(fmt.Errorf("container not running or created: %s", status), ContainerNotRunning) + return ErrNotRunning } func (c *linuxContainer) Resume() error { @@ -666,7 +728,7 @@ func (c *linuxContainer) Resume() error { return err } if status != Paused { - return newGenericError(fmt.Errorf("container not paused"), ContainerNotPaused) + return ErrNotPaused } if err := c.cgroupManager.Freeze(configs.Thawed); err != nil { return err @@ -771,7 +833,7 @@ func (c *linuxContainer) checkCriuVersion(minVersion int) error { var err error c.criuVersion, err = criu.GetCriuVersion() if err != nil { - return fmt.Errorf("CRIU version check failed: %s", err) + return fmt.Errorf("CRIU version check failed: %w", err) } return compareCriuVersion(c.criuVersion, minVersion) @@ -781,6 +843,9 @@ const descriptorsFilename = "descriptors.json" func (c *linuxContainer) addCriuDumpMount(req *criurpc.CriuReq, m *configs.Mount) { mountDest := strings.TrimPrefix(m.Destination, c.config.Rootfs) + if dest, err := securejoin.SecureJoin(c.config.Rootfs, mountDest); err == nil { + mountDest = dest[len(c.config.Rootfs):] + } extMnt := &criurpc.ExtMountMap{ Key: proto.String(mountDest), Val: proto.String(mountDest), @@ -972,20 +1037,6 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { return err } - if criuOpts.WorkDirectory == "" { - criuOpts.WorkDirectory = filepath.Join(c.root, "criu.work") - } - - if err := os.Mkdir(criuOpts.WorkDirectory, 0o700); err != nil && !os.IsExist(err) { - return err - } - - workDir, err := os.Open(criuOpts.WorkDirectory) - if err != nil { - return err - } - defer workDir.Close() - imageDir, err := os.Open(criuOpts.ImagesDirectory) if err != nil { return err @@ -994,7 +1045,6 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { rpcOpts := criurpc.CriuOpts{ ImagesDirFd: proto.Int32(int32(imageDir.Fd())), - WorkDirFd: proto.Int32(int32(workDir.Fd())), LogLevel: proto.Int32(4), LogFile: proto.String("dump.log"), Root: proto.String(c.config.Rootfs), @@ -1012,6 +1062,19 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { LazyPages: proto.Bool(criuOpts.LazyPages), } + // if criuOpts.WorkDirectory is not set, criu default is used. + if criuOpts.WorkDirectory != "" { + if err := os.Mkdir(criuOpts.WorkDirectory, 0o700); err != nil && !os.IsExist(err) { + return err + } + workDir, err := os.Open(criuOpts.WorkDirectory) + if err != nil { + return err + } + defer workDir.Close() + rpcOpts.WorkDirFd = proto.Int32(int32(workDir.Fd())) + } + c.handleCriuConfigurationFile(&rpcOpts) // If the container is running in a network namespace and has @@ -1054,7 +1117,7 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { // append optional manage cgroups mode if criuOpts.ManageCgroupsMode != 0 { - mode := criurpc.CriuCgMode(criuOpts.ManageCgroupsMode) + mode := criuOpts.ManageCgroupsMode rpcOpts.ManageCgroupsMode = &mode } @@ -1144,7 +1207,7 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { return err } - err = ioutil.WriteFile(filepath.Join(criuOpts.ImagesDirectory, descriptorsFilename), fdsJSON, 0o600) + err = os.WriteFile(filepath.Join(criuOpts.ImagesDirectory, descriptorsFilename), fdsJSON, 0o600) if err != nil { return err } @@ -1159,6 +1222,9 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { func (c *linuxContainer) addCriuRestoreMount(req *criurpc.CriuReq, m *configs.Mount) { mountDest := strings.TrimPrefix(m.Destination, c.config.Rootfs) + if dest, err := securejoin.SecureJoin(c.config.Rootfs, mountDest); err == nil { + mountDest = dest[len(c.config.Rootfs):] + } extMnt := &criurpc.ExtMountMap{ Key: proto.String(mountDest), Val: proto.String(m.Source), @@ -1203,7 +1269,9 @@ func (c *linuxContainer) makeCriuRestoreMountpoints(m *configs.Mount) error { case "bind": // The prepareBindMount() function checks if source // exists. So it cannot be used for other filesystem types. - if err := prepareBindMount(m, c.config.Rootfs); err != nil { + // TODO: pass something else than nil? Not sure if criu is + // impacted by issue #2484 + if err := prepareBindMount(m, c.config.Rootfs, nil); err != nil { return err } default: @@ -1256,7 +1324,7 @@ func (c *linuxContainer) prepareCriuRestoreMounts(mounts []*configs.Mount) error for _, u := range umounts { _ = utils.WithProcfd(c.config.Rootfs, u, func(procfd string) error { if e := unix.Unmount(procfd, unix.MNT_DETACH); e != nil { - if e != unix.EINVAL { + if e != unix.EINVAL { //nolint:errorlint // unix errors are bare // Ignore EINVAL as it means 'target is not a mount point.' // It probably has already been unmounted. logrus.Warnf("Error during cleanup unmounting of %s (%s): %v", procfd, u, e) @@ -1282,8 +1350,8 @@ func (c *linuxContainer) prepareCriuRestoreMounts(mounts []*configs.Mount) error // set up in the order they are configured. if m.Device == "bind" { if err := utils.WithProcfd(c.config.Rootfs, m.Destination, func(procfd string) error { - if err := unix.Mount(m.Source, procfd, "", unix.MS_BIND|unix.MS_REC, ""); err != nil { - return errorsf.Wrapf(err, "unable to bind mount %q to %q (through %q)", m.Source, m.Destination, procfd) + if err := mount(m.Source, m.Destination, procfd, "", unix.MS_BIND|unix.MS_REC, ""); err != nil { + return err } return nil }); err != nil { @@ -1311,19 +1379,6 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { if err := c.checkCriuVersion(30000); err != nil { return err } - if criuOpts.WorkDirectory == "" { - criuOpts.WorkDirectory = filepath.Join(c.root, "criu.work") - } - // Since a container can be C/R'ed multiple times, - // the work directory may already exist. - if err := os.Mkdir(criuOpts.WorkDirectory, 0o700); err != nil && !os.IsExist(err) { - return err - } - workDir, err := os.Open(criuOpts.WorkDirectory) - if err != nil { - return err - } - defer workDir.Close() if criuOpts.ImagesDirectory == "" { return errors.New("invalid directory to restore checkpoint") } @@ -1346,7 +1401,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { if err != nil { return err } - err = unix.Mount(c.config.Rootfs, root, "", unix.MS_BIND|unix.MS_REC, "") + err = mount(c.config.Rootfs, root, "", "", unix.MS_BIND|unix.MS_REC, "") if err != nil { return err } @@ -1356,7 +1411,6 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { Type: &t, Opts: &criurpc.CriuOpts{ ImagesDirFd: proto.Int32(int32(imageDir.Fd())), - WorkDirFd: proto.Int32(int32(workDir.Fd())), EvasiveDevices: proto.Bool(true), LogLevel: proto.Int32(4), LogFile: proto.String("restore.log"), @@ -1383,7 +1437,26 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { } req.Opts.LsmProfile = proto.String(criuOpts.LsmProfile) } + if criuOpts.LsmMountContext != "" { + if err := c.checkCriuVersion(31600); err != nil { + return errors.New("--lsm-mount-context requires at least CRIU 3.16") + } + req.Opts.LsmMountContext = proto.String(criuOpts.LsmMountContext) + } + if criuOpts.WorkDirectory != "" { + // Since a container can be C/R'ed multiple times, + // the work directory may already exist. + if err := os.Mkdir(criuOpts.WorkDirectory, 0o700); err != nil && !os.IsExist(err) { + return err + } + workDir, err := os.Open(criuOpts.WorkDirectory) + if err != nil { + return err + } + defer workDir.Close() + req.Opts.WorkDirFd = proto.Int32(int32(workDir.Fd())) + } c.handleCriuConfigurationFile(req.Opts) if err := c.handleRestoringNamespaces(req.Opts, &extraFiles); err != nil { @@ -1432,7 +1505,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { // append optional manage cgroups mode if criuOpts.ManageCgroupsMode != 0 { - mode := criurpc.CriuCgMode(criuOpts.ManageCgroupsMode) + mode := criuOpts.ManageCgroupsMode req.Opts.ManageCgroupsMode = &mode } @@ -1440,7 +1513,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { fds []string fdJSON []byte ) - if fdJSON, err = ioutil.ReadFile(filepath.Join(criuOpts.ImagesDirectory, descriptorsFilename)); err != nil { + if fdJSON, err = os.ReadFile(filepath.Join(criuOpts.ImagesDirectory, descriptorsFilename)); err != nil { return err } @@ -1477,7 +1550,7 @@ func (c *linuxContainer) criuApplyCgroups(pid int, req *criurpc.CriuReq) error { } if err := c.cgroupManager.Set(c.config.Cgroups.Resources); err != nil { - return newSystemError(err) + return err } if cgroups.IsCgroup2UnifiedMode() { @@ -1835,7 +1908,7 @@ func (c *linuxContainer) updateState(process parentProcess) (*State, error) { } func (c *linuxContainer) saveState(s *State) (retErr error) { - tmpFile, err := ioutil.TempFile(c.root, "state-") + tmpFile, err := os.CreateTemp(c.root, "state-") if err != nil { return err } @@ -1928,9 +2001,10 @@ func (c *linuxContainer) currentState() (*State, error) { startTime, _ = c.initProcess.startTime() externalDescriptors = c.initProcess.externalDescriptors() } - intelRdtPath, err := intelrdt.GetIntelRdtPath(c.ID()) - if err != nil { - intelRdtPath = "" + + intelRdtPath := "" + if c.intelRdtManager != nil { + intelRdtPath = c.intelRdtManager.GetPath() } state := &State{ BaseState: BaseState{ @@ -1998,16 +2072,16 @@ func (c *linuxContainer) orderNamespacePaths(namespaces map[configs.NamespaceTyp if p, ok := namespaces[ns]; ok && p != "" { // check if the requested namespace is supported if !configs.IsNamespaceSupported(ns) { - return nil, newSystemError(fmt.Errorf("namespace %s is not supported", ns)) + return nil, fmt.Errorf("namespace %s is not supported", ns) } // only set to join this namespace if it exists if _, err := os.Lstat(p); err != nil { - return nil, newSystemErrorWithCausef(err, "running lstat on namespace path %q", p) + return nil, fmt.Errorf("namespace path: %w", err) } // do not allow namespace path with comma as we use it to separate // the namespace paths if strings.ContainsRune(p, ',') { - return nil, newSystemError(fmt.Errorf("invalid path %s", p)) + return nil, fmt.Errorf("invalid namespace path %s", p) } paths = append(paths, fmt.Sprintf("%s:%s", configs.NsName(ns), p)) } @@ -2039,7 +2113,7 @@ type netlinkError struct{ error } // such as one that uses nsenter package to bootstrap the container's // init process correctly, i.e. with correct namespaces, uid/gid // mapping etc. -func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string) (_ io.Reader, Err error) { +func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string, it initType) (_ io.Reader, Err error) { // create the netlink message r := nl.NewNetlinkRequest(int(InitMsg), 0) @@ -2134,6 +2208,25 @@ func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Na Value: c.config.RootlessEUID, }) + // Bind mount source to open. + if it == initStandard && c.shouldSendMountSources() { + var mounts []byte + for _, m := range c.config.Mounts { + if m.IsBind() { + if strings.IndexByte(m.Source, 0) >= 0 { + return nil, fmt.Errorf("mount source string contains null byte: %q", m.Source) + } + mounts = append(mounts, []byte(m.Source)...) + } + mounts = append(mounts, byte(0)) + } + + r.AddData(&Bytemsg{ + Type: MountSourcesAttr, + Value: mounts, + }) + } + return bytes.NewReader(r.Serialize()), nil } @@ -2144,7 +2237,7 @@ func ignoreTerminateErrors(err error) error { if err == nil { return nil } - // terminate() might return an error from ether Kill or Wait. + // terminate() might return an error from either Kill or Wait. // The (*Cmd).Wait documentation says: "If the command fails to run // or doesn't complete successfully, the error is of type *ExitError". // Filter out such errors (like "exit status 1" or "signal: killed"). @@ -2152,13 +2245,11 @@ func ignoreTerminateErrors(err error) error { if errors.As(err, &exitErr) { return nil } - // TODO: use errors.Is(err, os.ErrProcessDone) here and - // remove "process already finished" string comparison below - // once go 1.16 is minimally supported version. - + if errors.Is(err, os.ErrProcessDone) { + return nil + } s := err.Error() - if strings.Contains(s, "process already finished") || - strings.Contains(s, "Wait was already called") { + if strings.Contains(s, "Wait was already called") { return nil } return err diff --git a/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go index 0db43e74e8aad..b39476ef352ef 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go @@ -30,4 +30,5 @@ type CriuOpts struct { LazyPages bool // restore memory pages lazily using userfaultfd StatusFd int // fd for feedback when lazy server is ready LsmProfile string // LSM profile used to restore the container + LsmMountContext string // LSM mount context value to use during restore } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go index 6d5b3d09df3bd..7d8e9fc31044f 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go @@ -1,10 +1,10 @@ +//go:build !windows // +build !windows package devices import ( "errors" - "io/ioutil" "os" "path/filepath" @@ -16,8 +16,8 @@ var ErrNotADevice = errors.New("not a device node") // Testing dependencies var ( - unixLstat = unix.Lstat - ioutilReadDir = ioutil.ReadDir + unixLstat = unix.Lstat + osReadDir = os.ReadDir ) func mkDev(d *Rule) (uint64, error) { @@ -40,7 +40,7 @@ func DeviceFromPath(path, permissions string) (*Device, error) { var ( devType Type mode = stat.Mode - devNumber = uint64(stat.Rdev) + devNumber = uint64(stat.Rdev) //nolint:unconvert // Rdev is uint32 on e.g. MIPS. major = unix.Major(devNumber) minor = unix.Minor(devNumber) ) @@ -76,7 +76,7 @@ func HostDevices() ([]*Device, error) { // GetDevices recursively traverses a directory specified by path // and returns all devices found there. func GetDevices(path string) ([]*Device, error) { - files, err := ioutilReadDir(path) + files, err := osReadDir(path) if err != nil { return nil, err } @@ -103,7 +103,7 @@ func GetDevices(path string) ([]*Device, error) { } device, err := DeviceFromPath(filepath.Join(path, f.Name()), "rwm") if err != nil { - if err == ErrNotADevice { + if errors.Is(err, ErrNotADevice) { continue } if os.IsNotExist(err) { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/error.go b/vendor/github.com/opencontainers/runc/libcontainer/error.go index 21a3789ba18de..510c072264f69 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/error.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/error.go @@ -1,70 +1,13 @@ package libcontainer -import "io" - -// ErrorCode is the API error code type. -type ErrorCode int - -// API error codes. -const ( - // Factory errors - IdInUse ErrorCode = iota - InvalidIdFormat - - // Container errors - ContainerNotExists - ContainerPaused - ContainerNotStopped - ContainerNotRunning - ContainerNotPaused - - // Process errors - NoProcessOps - - // Common errors - ConfigInvalid - ConsoleExists - SystemError +import "errors" + +var ( + ErrExist = errors.New("container with given ID already exists") + ErrInvalidID = errors.New("invalid container ID format") + ErrNotExist = errors.New("container does not exist") + ErrPaused = errors.New("container paused") + ErrRunning = errors.New("container still running") + ErrNotRunning = errors.New("container not running") + ErrNotPaused = errors.New("container not paused") ) - -func (c ErrorCode) String() string { - switch c { - case IdInUse: - return "Id already in use" - case InvalidIdFormat: - return "Invalid format" - case ContainerPaused: - return "Container paused" - case ConfigInvalid: - return "Invalid configuration" - case SystemError: - return "System error" - case ContainerNotExists: - return "Container does not exist" - case ContainerNotStopped: - return "Container is not stopped" - case ContainerNotRunning: - return "Container is not running" - case ConsoleExists: - return "Console exists for process" - case ContainerNotPaused: - return "Container is not paused" - case NoProcessOps: - return "No process operations" - default: - return "Unknown error" - } -} - -// Error is the API error type. -type Error interface { - error - - // Returns an error if it failed to write the detail of the Error to w. - // The detail of the Error may include the error message and a - // representation of the stack trace. - Detail(w io.Writer) error - - // Returns the error code for this error. - Code() ErrorCode -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/factory.go b/vendor/github.com/opencontainers/runc/libcontainer/factory.go index 0986cd77e3fe0..9f9e8fc583cc1 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/factory.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/factory.go @@ -14,29 +14,15 @@ type Factory interface { // // Returns the new container with a running process. // - // errors: - // IdInUse - id is already in use by a container - // InvalidIdFormat - id has incorrect format - // ConfigInvalid - config is invalid - // Systemerror - System error - // // On error, any partially created container parts are cleaned up (the operation is atomic). Create(id string, config *configs.Config) (Container, error) // Load takes an ID for an existing container and returns the container information // from the state. This presents a read only view of the container. - // - // errors: - // Path does not exist - // System error Load(id string) (Container, error) // StartInitialization is an internal API to libcontainer used during the reexec of the // container. - // - // Errors: - // Pipe connection error - // System error StartInitialization() error // Type returns info string about factory type (e.g. lxc, libcontainer...) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go index dbd410b88f987..023d623f3709c 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go @@ -1,9 +1,8 @@ -// +build linux - package libcontainer import ( "encoding/json" + "errors" "fmt" "os" "path/filepath" @@ -13,17 +12,14 @@ import ( securejoin "github.com/cyphar/filepath-securejoin" "github.com/moby/sys/mountinfo" - "github.com/opencontainers/runc/libcontainer/cgroups" - "github.com/opencontainers/runc/libcontainer/cgroups/fs" - "github.com/opencontainers/runc/libcontainer/cgroups/fs2" - "github.com/opencontainers/runc/libcontainer/cgroups/systemd" + "golang.org/x/sys/unix" + + "github.com/opencontainers/runc/libcontainer/cgroups/manager" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/configs/validate" "github.com/opencontainers/runc/libcontainer/intelrdt" "github.com/opencontainers/runc/libcontainer/utils" - "github.com/pkg/errors" - - "golang.org/x/sys/unix" + "github.com/sirupsen/logrus" ) const ( @@ -41,7 +37,9 @@ func InitArgs(args ...string) func(*LinuxFactory) error { // Resolve relative paths to ensure that its available // after directory changes. if args[0], err = filepath.Abs(args[0]); err != nil { - return newGenericError(err, ConfigInvalid) + // The only error returned from filepath.Abs is + // the one from os.Getwd, i.e. a system error. + return err } } @@ -50,100 +48,6 @@ func InitArgs(args ...string) func(*LinuxFactory) error { } } -func getUnifiedPath(paths map[string]string) string { - path := "" - for k, v := range paths { - if path == "" { - path = v - } else if v != path { - panic(errors.Errorf("expected %q path to be unified path %q, got %q", k, path, v)) - } - } - // can be empty - if path != "" { - if filepath.Clean(path) != path || !filepath.IsAbs(path) { - panic(errors.Errorf("invalid dir path %q", path)) - } - } - - return path -} - -func systemdCgroupV2(l *LinuxFactory, rootless bool) error { - l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { - return systemd.NewUnifiedManager(config, getUnifiedPath(paths), rootless) - } - return nil -} - -// SystemdCgroups is an options func to configure a LinuxFactory to return -// containers that use systemd to create and manage cgroups. -func SystemdCgroups(l *LinuxFactory) error { - if !systemd.IsRunningSystemd() { - return fmt.Errorf("systemd not running on this host, can't use systemd as cgroups manager") - } - - if cgroups.IsCgroup2UnifiedMode() { - return systemdCgroupV2(l, false) - } - - l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { - return systemd.NewLegacyManager(config, paths) - } - - return nil -} - -// RootlessSystemdCgroups is rootless version of SystemdCgroups. -func RootlessSystemdCgroups(l *LinuxFactory) error { - if !systemd.IsRunningSystemd() { - return fmt.Errorf("systemd not running on this host, can't use systemd as cgroups manager") - } - - if !cgroups.IsCgroup2UnifiedMode() { - return fmt.Errorf("cgroup v2 not enabled on this host, can't use systemd (rootless) as cgroups manager") - } - return systemdCgroupV2(l, true) -} - -func cgroupfs2(l *LinuxFactory, rootless bool) error { - l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { - m, err := fs2.NewManager(config, getUnifiedPath(paths), rootless) - if err != nil { - panic(err) - } - return m - } - return nil -} - -func cgroupfs(l *LinuxFactory, rootless bool) error { - if cgroups.IsCgroup2UnifiedMode() { - return cgroupfs2(l, rootless) - } - l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { - return fs.NewManager(config, paths, rootless) - } - return nil -} - -// Cgroupfs is an options func to configure a LinuxFactory to return containers -// that use the native cgroups filesystem implementation to create and manage -// cgroups. -func Cgroupfs(l *LinuxFactory) error { - return cgroupfs(l, false) -} - -// RootlessCgroupfs is an options func to configure a LinuxFactory to return -// containers that use the native cgroups filesystem implementation to create -// and manage cgroups. The difference between RootlessCgroupfs and Cgroupfs is -// that RootlessCgroupfs can transparently handle permission errors that occur -// during rootless container (including euid=0 in userns) setup (while still allowing cgroup usage if -// they've been set up properly). -func RootlessCgroupfs(l *LinuxFactory) error { - return cgroupfs(l, true) -} - // IntelRdtfs is an options func to configure a LinuxFactory to return // containers that use the Intel RDT "resource control" filesystem to // create and manage Intel RDT resources (e.g., L3 cache, memory bandwidth). @@ -165,7 +69,7 @@ func TmpfsRoot(l *LinuxFactory) error { return err } if !mounted { - if err := unix.Mount("tmpfs", l.Root, "tmpfs", 0, ""); err != nil { + if err := mount("tmpfs", l.Root, "", "tmpfs", 0, ""); err != nil { return err } } @@ -186,7 +90,7 @@ func CriuPath(criupath string) func(*LinuxFactory) error { func New(root string, options ...func(*LinuxFactory) error) (Factory, error) { if root != "" { if err := os.MkdirAll(root, 0o700); err != nil { - return nil, newGenericError(err, SystemError) + return nil, err } } l := &LinuxFactory{ @@ -197,10 +101,6 @@ func New(root string, options ...func(*LinuxFactory) error) (Factory, error) { CriuPath: "criu", } - if err := Cgroupfs(l); err != nil { - return nil, err - } - for _, opt := range options { if opt == nil { continue @@ -237,37 +137,69 @@ type LinuxFactory struct { // Validator provides validation to container configurations. Validator validate.Validator - // NewCgroupsManager returns an initialized cgroups manager for a single container. - NewCgroupsManager func(config *configs.Cgroup, paths map[string]string) cgroups.Manager - // NewIntelRdtManager returns an initialized Intel RDT manager for a single container. NewIntelRdtManager func(config *configs.Config, id string, path string) intelrdt.Manager } func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, error) { if l.Root == "" { - return nil, newGenericError(fmt.Errorf("invalid root"), ConfigInvalid) + return nil, errors.New("root not set") } if err := l.validateID(id); err != nil { return nil, err } if err := l.Validator.Validate(config); err != nil { - return nil, newGenericError(err, ConfigInvalid) + return nil, err } containerRoot, err := securejoin.SecureJoin(l.Root, id) if err != nil { return nil, err } if _, err := os.Stat(containerRoot); err == nil { - return nil, newGenericError(fmt.Errorf("container with id exists: %v", id), IdInUse) + return nil, ErrExist } else if !os.IsNotExist(err) { - return nil, newGenericError(err, SystemError) + return nil, err } + + cm, err := manager.New(config.Cgroups) + if err != nil { + return nil, err + } + + // Check that cgroup does not exist or empty (no processes). + // Note for cgroup v1 this check is not thorough, as there are multiple + // separate hierarchies, while both Exists() and GetAllPids() only use + // one for "devices" controller (assuming others are the same, which is + // probably true in almost all scenarios). Checking all the hierarchies + // would be too expensive. + if cm.Exists() { + pids, err := cm.GetAllPids() + // Reading PIDs can race with cgroups removal, so ignore ENOENT and ENODEV. + if err != nil && !errors.Is(err, os.ErrNotExist) && !errors.Is(err, unix.ENODEV) { + return nil, fmt.Errorf("unable to get cgroup PIDs: %w", err) + } + if len(pids) != 0 { + // TODO: return an error. + logrus.Warnf("container's cgroup is not empty: %d process(es) found", len(pids)) + logrus.Warn("DEPRECATED: running container in a non-empty cgroup won't be supported in runc 1.2; https://github.com/opencontainers/runc/issues/3132") + } + } + + // Check that cgroup is not frozen. Do not use Exists() here + // since in cgroup v1 it only checks "devices" controller. + st, err := cm.GetFreezerState() + if err != nil { + return nil, fmt.Errorf("unable to get cgroup freezer state: %w", err) + } + if st == configs.Frozen { + return nil, errors.New("container's cgroup unexpectedly frozen") + } + if err := os.MkdirAll(containerRoot, 0o711); err != nil { - return nil, newGenericError(err, SystemError) + return nil, err } if err := os.Chown(containerRoot, unix.Geteuid(), unix.Getegid()); err != nil { - return nil, newGenericError(err, SystemError) + return nil, err } c := &linuxContainer{ id: id, @@ -278,7 +210,7 @@ func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, err criuPath: l.CriuPath, newuidmapPath: l.NewuidmapPath, newgidmapPath: l.NewgidmapPath, - cgroupManager: l.NewCgroupsManager(config.Cgroups, nil), + cgroupManager: cm, } if l.NewIntelRdtManager != nil { c.intelRdtManager = l.NewIntelRdtManager(config, id, "") @@ -289,7 +221,7 @@ func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, err func (l *LinuxFactory) Load(id string) (Container, error) { if l.Root == "" { - return nil, newGenericError(fmt.Errorf("invalid root"), ConfigInvalid) + return nil, errors.New("root not set") } // when load, we need to check id is valid or not. if err := l.validateID(id); err != nil { @@ -299,7 +231,7 @@ func (l *LinuxFactory) Load(id string) (Container, error) { if err != nil { return nil, err } - state, err := l.loadState(containerRoot, id) + state, err := l.loadState(containerRoot) if err != nil { return nil, err } @@ -308,6 +240,10 @@ func (l *LinuxFactory) Load(id string) (Container, error) { processStartTime: state.InitProcessStartTime, fds: state.ExternalDescriptors, } + cm, err := manager.NewWithPaths(state.Config.Cgroups, state.CgroupPaths) + if err != nil { + return nil, err + } c := &linuxContainer{ initProcess: r, initProcessStartTime: state.InitProcessStartTime, @@ -318,7 +254,7 @@ func (l *LinuxFactory) Load(id string) (Container, error) { criuPath: l.CriuPath, newuidmapPath: l.NewuidmapPath, newgidmapPath: l.NewgidmapPath, - cgroupManager: l.NewCgroupsManager(state.Config.Cgroups, state.CgroupPaths), + cgroupManager: cm, root: containerRoot, created: state.Created, } @@ -343,11 +279,26 @@ func (l *LinuxFactory) StartInitialization() (err error) { envInitPipe := os.Getenv("_LIBCONTAINER_INITPIPE") pipefd, err := strconv.Atoi(envInitPipe) if err != nil { - return fmt.Errorf("unable to convert _LIBCONTAINER_INITPIPE=%s to int: %s", envInitPipe, err) + err = fmt.Errorf("unable to convert _LIBCONTAINER_INITPIPE: %w", err) + logrus.Error(err) + return err } pipe := os.NewFile(uintptr(pipefd), "pipe") defer pipe.Close() + defer func() { + // We have an error during the initialization of the container's init, + // send it back to the parent process in the form of an initError. + if werr := writeSync(pipe, procError); werr != nil { + fmt.Fprintln(os.Stderr, err) + return + } + if werr := utils.WriteJSON(pipe, &initError{Message: err.Error()}); werr != nil { + fmt.Fprintln(os.Stderr, err) + return + } + }() + // Only init processes have FIFOFD. fifofd := -1 envInitType := os.Getenv("_LIBCONTAINER_INITTYPE") @@ -355,7 +306,7 @@ func (l *LinuxFactory) StartInitialization() (err error) { if it == initStandard { envFifoFd := os.Getenv("_LIBCONTAINER_FIFOFD") if fifofd, err = strconv.Atoi(envFifoFd); err != nil { - return fmt.Errorf("unable to convert _LIBCONTAINER_FIFOFD=%s to int: %s", envFifoFd, err) + return fmt.Errorf("unable to convert _LIBCONTAINER_FIFOFD: %w", err) } } @@ -363,7 +314,7 @@ func (l *LinuxFactory) StartInitialization() (err error) { if envConsole := os.Getenv("_LIBCONTAINER_CONSOLE"); envConsole != "" { console, err := strconv.Atoi(envConsole) if err != nil { - return fmt.Errorf("unable to convert _LIBCONTAINER_CONSOLE=%s to int: %s", envConsole, err) + return fmt.Errorf("unable to convert _LIBCONTAINER_CONSOLE: %w", err) } consoleSocket = os.NewFile(uintptr(console), "console-socket") defer consoleSocket.Close() @@ -372,32 +323,26 @@ func (l *LinuxFactory) StartInitialization() (err error) { logPipeFdStr := os.Getenv("_LIBCONTAINER_LOGPIPE") logPipeFd, err := strconv.Atoi(logPipeFdStr) if err != nil { - return fmt.Errorf("unable to convert _LIBCONTAINER_LOGPIPE=%s to int: %s", logPipeFdStr, err) + return fmt.Errorf("unable to convert _LIBCONTAINER_LOGPIPE: %w", err) + } + + // Get mount files (O_PATH). + mountFds, err := parseMountFds() + if err != nil { + return err } // clear the current process's environment to clean any libcontainer // specific env vars. os.Clearenv() - defer func() { - // We have an error during the initialization of the container's init, - // send it back to the parent process in the form of an initError. - if werr := utils.WriteJSON(pipe, syncT{procError}); werr != nil { - fmt.Fprintln(os.Stderr, err) - return - } - if werr := utils.WriteJSON(pipe, newSystemError(err)); werr != nil { - fmt.Fprintln(os.Stderr, err) - return - } - }() defer func() { if e := recover(); e != nil { - err = fmt.Errorf("panic from initialization: %v, %v", e, string(debug.Stack())) + err = fmt.Errorf("panic from initialization: %w, %v", e, string(debug.Stack())) } }() - i, err := newContainerInit(it, pipe, consoleSocket, fifofd, logPipeFd) + i, err := newContainerInit(it, pipe, consoleSocket, fifofd, logPipeFd, mountFds) if err != nil { return err } @@ -406,7 +351,7 @@ func (l *LinuxFactory) StartInitialization() (err error) { return i.Init() } -func (l *LinuxFactory) loadState(root, id string) (*State, error) { +func (l *LinuxFactory) loadState(root string) (*State, error) { stateFilePath, err := securejoin.SecureJoin(root, stateFilename) if err != nil { return nil, err @@ -414,21 +359,21 @@ func (l *LinuxFactory) loadState(root, id string) (*State, error) { f, err := os.Open(stateFilePath) if err != nil { if os.IsNotExist(err) { - return nil, newGenericError(fmt.Errorf("container %q does not exist", id), ContainerNotExists) + return nil, ErrNotExist } - return nil, newGenericError(err, SystemError) + return nil, err } defer f.Close() var state *State if err := json.NewDecoder(f).Decode(&state); err != nil { - return nil, newGenericError(err, SystemError) + return nil, err } return state, nil } func (l *LinuxFactory) validateID(id string) error { if !idRegex.MatchString(id) || string(os.PathSeparator)+id != utils.CleanPath(string(os.PathSeparator)+id) { - return newGenericError(fmt.Errorf("invalid id format: %v", id), InvalidIdFormat) + return ErrInvalidID } return nil @@ -451,3 +396,18 @@ func NewgidmapPath(newgidmapPath string) func(*LinuxFactory) error { return nil } } + +func parseMountFds() ([]int, error) { + fdsJson := os.Getenv("_LIBCONTAINER_MOUNT_FDS") + if fdsJson == "" { + // Always return the nil slice if no fd is present. + return nil, nil + } + + var mountFds []int + if err := json.Unmarshal([]byte(fdsJson), &mountFds); err != nil { + return nil, fmt.Errorf("Error unmarshalling _LIBCONTAINER_MOUNT_FDS: %w", err) + } + + return mountFds, nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/generic_error.go b/vendor/github.com/opencontainers/runc/libcontainer/generic_error.go deleted file mode 100644 index d185ebd898982..0000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/generic_error.go +++ /dev/null @@ -1,92 +0,0 @@ -package libcontainer - -import ( - "fmt" - "io" - "text/template" - "time" - - "github.com/opencontainers/runc/libcontainer/stacktrace" -) - -var errorTemplate = template.Must(template.New("error").Parse(`Timestamp: {{.Timestamp}} -Code: {{.ECode}} -{{if .Message }} -Message: {{.Message}} -{{end}} -Frames:{{range $i, $frame := .Stack.Frames}} ---- -{{$i}}: {{$frame.Function}} -Package: {{$frame.Package}} -File: {{$frame.File}}@{{$frame.Line}}{{end}} -`)) - -func newGenericError(err error, c ErrorCode) Error { - if le, ok := err.(Error); ok { - return le - } - gerr := &genericError{ - Timestamp: time.Now(), - Err: err, - ECode: c, - Stack: stacktrace.Capture(1), - } - if err != nil { - gerr.Message = err.Error() - } - return gerr -} - -func newSystemError(err error) Error { - return createSystemError(err, "") -} - -func newSystemErrorWithCausef(err error, cause string, v ...interface{}) Error { - return createSystemError(err, fmt.Sprintf(cause, v...)) -} - -func newSystemErrorWithCause(err error, cause string) Error { - return createSystemError(err, cause) -} - -// createSystemError creates the specified error with the correct number of -// stack frames skipped. This is only to be called by the other functions for -// formatting the error. -func createSystemError(err error, cause string) Error { - gerr := &genericError{ - Timestamp: time.Now(), - Err: err, - ECode: SystemError, - Cause: cause, - Stack: stacktrace.Capture(2), - } - if err != nil { - gerr.Message = err.Error() - } - return gerr -} - -type genericError struct { - Timestamp time.Time - ECode ErrorCode - Err error `json:"-"` - Cause string - Message string - Stack stacktrace.Stacktrace -} - -func (e *genericError) Error() string { - if e.Cause == "" { - return e.Message - } - frame := e.Stack.Frames[0] - return fmt.Sprintf("%s:%d: %s caused: %s", frame.File, frame.Line, e.Cause, e.Message) -} - -func (e *genericError) Code() ErrorCode { - return e.ECode -} - -func (e *genericError) Detail(w io.Writer) error { - return errorTemplate.Execute(w, e) -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go index c456cbe7a1509..cb862a6a5bed4 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go @@ -1,30 +1,29 @@ -// +build linux - package libcontainer import ( "bytes" "encoding/json" + "errors" "fmt" "io" - "io/ioutil" "net" "os" + "strconv" "strings" "unsafe" "github.com/containerd/console" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/sirupsen/logrus" + "github.com/vishvananda/netlink" + "golang.org/x/sys/unix" + "github.com/opencontainers/runc/libcontainer/capabilities" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/system" "github.com/opencontainers/runc/libcontainer/user" "github.com/opencontainers/runc/libcontainer/utils" - "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "github.com/vishvananda/netlink" - "golang.org/x/sys/unix" ) type initType string @@ -77,7 +76,7 @@ type initer interface { Init() error } -func newContainerInit(t initType, pipe *os.File, consoleSocket *os.File, fifoFd, logFd int) (initer, error) { +func newContainerInit(t initType, pipe *os.File, consoleSocket *os.File, fifoFd, logFd int, mountFds []int) (initer, error) { var config *initConfig if err := json.NewDecoder(pipe).Decode(&config); err != nil { return nil, err @@ -87,6 +86,11 @@ func newContainerInit(t initType, pipe *os.File, consoleSocket *os.File, fifoFd, } switch t { case initSetns: + // mountFds must be nil in this case. We don't mount while doing runc exec. + if mountFds != nil { + return nil, errors.New("mountFds must be nil. Can't mount while doing runc exec.") + } + return &linuxSetnsInit{ pipe: pipe, consoleSocket: consoleSocket, @@ -101,6 +105,7 @@ func newContainerInit(t initType, pipe *os.File, consoleSocket *os.File, fifoFd, config: config, fifoFd: fifoFd, logFd: logFd, + mountFds: mountFds, }, nil } return nil, fmt.Errorf("unknown init type %q", t) @@ -139,7 +144,7 @@ func finalizeNamespace(config *initConfig) error { // inherited are marked close-on-exec so they stay out of the // container if err := utils.CloseExecFrom(config.PassedFilesCount + 3); err != nil { - return errors.Wrap(err, "close exec fds") + return fmt.Errorf("error closing exec fds: %w", err) } // we only do chdir if it's specified @@ -158,7 +163,7 @@ func finalizeNamespace(config *initConfig) error { // to the directory, but the user running runc does not. // This is useful in cases where the cwd is also a volume that's been chowned to the container user. default: - return fmt.Errorf("chdir to cwd (%q) set in config.json failed: %v", config.Cwd, err) + return fmt.Errorf("chdir to cwd (%q) set in config.json failed: %w", config.Cwd, err) } } @@ -174,26 +179,26 @@ func finalizeNamespace(config *initConfig) error { } // drop capabilities in bounding set before changing user if err := w.ApplyBoundingSet(); err != nil { - return errors.Wrap(err, "apply bounding set") + return fmt.Errorf("unable to apply bounding set: %w", err) } // preserve existing capabilities while we change users if err := system.SetKeepCaps(); err != nil { - return errors.Wrap(err, "set keep caps") + return fmt.Errorf("unable to set keep caps: %w", err) } if err := setupUser(config); err != nil { - return errors.Wrap(err, "setup user") + return fmt.Errorf("unable to setup user: %w", err) } // Change working directory AFTER the user has been set up, if we haven't done it yet. if doChdir { if err := unix.Chdir(config.Cwd); err != nil { - return fmt.Errorf("chdir to cwd (%q) set in config.json failed: %v", config.Cwd, err) + return fmt.Errorf("chdir to cwd (%q) set in config.json failed: %w", config.Cwd, err) } } if err := system.ClearKeepCaps(); err != nil { - return errors.Wrap(err, "clear keep caps") + return fmt.Errorf("unable to clear keep caps: %w", err) } if err := w.ApplyCaps(); err != nil { - return errors.Wrap(err, "apply caps") + return fmt.Errorf("unable to apply caps: %w", err) } return nil } @@ -272,6 +277,36 @@ func syncParentHooks(pipe io.ReadWriter) error { return readSync(pipe, procResume) } +// syncParentSeccomp sends to the given pipe a JSON payload which +// indicates that the parent should pick up the seccomp fd with pidfd_getfd() +// and send it to the seccomp agent over a unix socket. It then waits for +// the parent to indicate that it is cleared to resume and closes the seccompFd. +// If the seccompFd is -1, there isn't anything to sync with the parent, so it +// returns no error. +func syncParentSeccomp(pipe io.ReadWriter, seccompFd int) error { + if seccompFd == -1 { + return nil + } + + // Tell parent. + if err := writeSyncWithFd(pipe, procSeccomp, seccompFd); err != nil { + unix.Close(seccompFd) + return err + } + + // Wait for parent to give the all-clear. + if err := readSync(pipe, procSeccompDone); err != nil { + unix.Close(seccompFd) + return fmt.Errorf("sync parent seccomp: %w", err) + } + + if err := unix.Close(seccompFd); err != nil { + return fmt.Errorf("close seccomp fd: %w", err) + } + + return nil +} + // setupUser changes the groups, gid, and uid for the user inside the container func setupUser(config *initConfig) error { // Set up defaults. @@ -325,11 +360,11 @@ func setupUser(config *initConfig) error { // Before we change to the container's user make sure that the processes // STDIO is correctly owned by the user that we are switching to. - if err := fixStdioPermissions(config, execUser); err != nil { + if err := fixStdioPermissions(execUser); err != nil { return err } - setgroups, err := ioutil.ReadFile("/proc/self/setgroups") + setgroups, err := os.ReadFile("/proc/self/setgroups") if err != nil && !os.IsNotExist(err) { return err } @@ -343,7 +378,7 @@ func setupUser(config *initConfig) error { if allowSupGroups { suppGroups := append(execUser.Sgids, addGroups...) if err := unix.Setgroups(suppGroups); err != nil { - return err + return &os.SyscallError{Syscall: "setgroups", Err: err} } } @@ -366,10 +401,10 @@ func setupUser(config *initConfig) error { // fixStdioPermissions fixes the permissions of PID 1's STDIO within the container to the specified user. // The ownership needs to match because it is created outside of the container and needs to be // localized. -func fixStdioPermissions(config *initConfig, u *user.ExecUser) error { +func fixStdioPermissions(u *user.ExecUser) error { var null unix.Stat_t if err := unix.Stat("/dev/null", &null); err != nil { - return err + return &os.PathError{Op: "stat", Path: "/dev/null", Err: err} } for _, fd := range []uintptr{ os.Stdin.Fd(), @@ -378,7 +413,7 @@ func fixStdioPermissions(config *initConfig, u *user.ExecUser) error { } { var s unix.Stat_t if err := unix.Fstat(int(fd), &s); err != nil { - return err + return &os.PathError{Op: "fstat", Path: "fd " + strconv.Itoa(int(fd)), Err: err} } // Skip chown of /dev/null if it was used as one of the STDIO fds. @@ -399,10 +434,12 @@ func fixStdioPermissions(config *initConfig, u *user.ExecUser) error { // privileged_wrt_inode_uidgid() has failed). In either case, we // are in a configuration where it's better for us to just not // touch the stdio rather than bail at this point. + + // nolint:errorlint // unix errors are bare if err == unix.EINVAL || err == unix.EPERM { continue } - return err + return &os.PathError{Op: "fchown", Path: "fd " + strconv.Itoa(int(fd)), Err: err} } } return nil @@ -456,8 +493,8 @@ func setupRoute(config *configs.Config) error { func setupRlimits(limits []configs.Rlimit, pid int) error { for _, rlimit := range limits { - if err := system.Prlimit(pid, rlimit.Type, unix.Rlimit{Max: rlimit.Hard, Cur: rlimit.Soft}); err != nil { - return fmt.Errorf("error setting rlimit type %v: %v", rlimit.Type, err) + if err := unix.Prlimit(pid, rlimit.Type, &unix.Rlimit{Max: rlimit.Hard, Cur: rlimit.Soft}, nil); err != nil { + return fmt.Errorf("error setting rlimit type %v: %w", rlimit.Type, err) } } return nil @@ -482,27 +519,12 @@ func isWaitable(pid int) (bool, error) { si := &siginfo{} _, _, e := unix.Syscall6(unix.SYS_WAITID, _P_PID, uintptr(pid), uintptr(unsafe.Pointer(si)), unix.WEXITED|unix.WNOWAIT|unix.WNOHANG, 0, 0) if e != 0 { - return false, os.NewSyscallError("waitid", e) + return false, &os.SyscallError{Syscall: "waitid", Err: e} } return si.si_pid != 0, nil } -// isNoChildren returns true if err represents a unix.ECHILD (formerly syscall.ECHILD) false otherwise -func isNoChildren(err error) bool { - switch err := err.(type) { - case unix.Errno: - if err == unix.ECHILD { - return true - } - case *os.SyscallError: - if err.Err == unix.ECHILD { - return true - } - } - return false -} - // signalAllProcesses freezes then iterates over all the processes inside the // manager's cgroups sending the signal s to them. // If s is SIGKILL then it will wait for each process to exit. @@ -548,7 +570,7 @@ func signalAllProcesses(m cgroups.Manager, s os.Signal) error { for _, p := range procs { if s != unix.SIGKILL { if ok, err := isWaitable(p.Pid); err != nil { - if !isNoChildren(err) { + if !errors.Is(err, unix.ECHILD) { logrus.Warn("signalAllProcesses: ", p.Pid, err) } continue @@ -565,7 +587,7 @@ func signalAllProcesses(m cgroups.Manager, s os.Signal) error { // to retrieve its exit code. if subreaper == 0 { if _, err := p.Wait(); err != nil { - if !isNoChildren(err) { + if !errors.Is(err, unix.ECHILD) { logrus.Warn("wait: ", err) } } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go index 3fa11b8002d38..8b6bf3ef09dc9 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go @@ -1,13 +1,11 @@ -// +build linux - package intelrdt import ( "bufio" "bytes" + "errors" "fmt" "io" - "io/ioutil" "os" "path/filepath" "strconv" @@ -15,6 +13,7 @@ import ( "sync" "github.com/moby/sys/mountinfo" + "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" ) @@ -70,7 +69,7 @@ import ( * |-- ... * |-- schemata * |-- tasks - * |-- + * |-- * |-- ... * |-- schemata * |-- tasks @@ -153,7 +152,7 @@ type Manager interface { // Returns statistics for Intel RDT GetStats() (*Stats, error) - // Destroys the Intel RDT 'container_id' group + // Destroys the Intel RDT container-specific 'container_id' group Destroy() error // Returns Intel RDT path to save in a state file and to be able to @@ -181,14 +180,10 @@ func NewManager(config *configs.Config, id string, path string) Manager { } const ( - IntelRdtTasks = "tasks" + intelRdtTasks = "tasks" ) var ( - // The absolute root path of the Intel RDT "resource control" filesystem - intelRdtRoot string - intelRdtRootLock sync.Mutex - // The flag to indicate if Intel RDT/CAT is enabled catEnabled bool // The flag to indicate if Intel RDT/MBA is enabled @@ -198,13 +193,9 @@ var ( // For Intel RDT initialization initOnce sync.Once -) -type intelRdtData struct { - root string - config *configs.Config - pid int -} + errNotFound = errors.New("Intel RDT resctrl mount point not found") +) // Check if Intel RDT sub-features are enabled in featuresInit() func featuresInit() { @@ -215,9 +206,10 @@ func featuresInit() { return } - // 2. Check if Intel RDT "resource control" filesystem is mounted - // The user guarantees to mount the filesystem - if !isIntelRdtMounted() { + // 2. Check if Intel RDT "resource control" filesystem is available. + // The user guarantees to mount the filesystem. + root, err := Root() + if err != nil { return } @@ -226,7 +218,7 @@ func featuresInit() { // selectively disabled or enabled by kernel command line // (e.g., rdt=!l3cat,mba) in 4.14 and newer kernel if flagsSet.CAT { - if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "L3")); err == nil { + if _, err := os.Stat(filepath.Join(root, "info", "L3")); err == nil { catEnabled = true } } @@ -236,15 +228,15 @@ func featuresInit() { // depends on MBA mbaEnabled = true } else if flagsSet.MBA { - if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "MB")); err == nil { + if _, err := os.Stat(filepath.Join(root, "info", "MB")); err == nil { mbaEnabled = true } } if flagsSet.MBMTotal || flagsSet.MBMLocal || flagsSet.CMT { - if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "L3_MON")); err != nil { + if _, err := os.Stat(filepath.Join(root, "info", "L3_MON")); err != nil { return } - enabledMonFeatures, err = getMonFeatures(intelRdtRoot) + enabledMonFeatures, err = getMonFeatures(root) if err != nil { return } @@ -271,7 +263,7 @@ func findIntelRdtMountpointDir(f io.Reader) (string, error) { return "", err } if len(mi) < 1 { - return "", NewNotFoundError("Intel RDT") + return "", errNotFound } // Check if MBA Software Controller is enabled through mount option "-o mba_MBps" @@ -282,10 +274,16 @@ func findIntelRdtMountpointDir(f io.Reader) (string, error) { return mi[0].Mountpoint, nil } -// Gets the root path of Intel RDT "resource control" filesystem -func getIntelRdtRoot() (string, error) { - intelRdtRootLock.Lock() - defer intelRdtRootLock.Unlock() +// For Root() use only. +var ( + intelRdtRoot string + rootMu sync.Mutex +) + +// Root returns the Intel RDT "resource control" filesystem mount point. +func Root() (string, error) { + rootMu.Lock() + defer rootMu.Unlock() if intelRdtRoot != "" { return intelRdtRoot, nil @@ -309,11 +307,6 @@ func getIntelRdtRoot() (string, error) { return intelRdtRoot, nil } -func isIntelRdtMounted() bool { - _, err := getIntelRdtRoot() - return err == nil -} - type cpuInfoFlags struct { CAT bool // Cache Allocation Technology MBA bool // Memory Bandwidth Allocation @@ -366,33 +359,15 @@ func parseCpuInfoFile(path string) (cpuInfoFlags, error) { return infoFlags, nil } -func parseUint(s string, base, bitSize int) (uint64, error) { - value, err := strconv.ParseUint(s, base, bitSize) - if err != nil { - intValue, intErr := strconv.ParseInt(s, base, bitSize) - // 1. Handle negative values greater than MinInt64 (and) - // 2. Handle negative values lesser than MinInt64 - if intErr == nil && intValue < 0 { - return 0, nil - } else if intErr != nil && intErr.(*strconv.NumError).Err == strconv.ErrRange && intValue < 0 { - return 0, nil - } - - return value, err - } - - return value, nil -} - // Gets a single uint64 value from the specified file. func getIntelRdtParamUint(path, file string) (uint64, error) { fileName := filepath.Join(path, file) - contents, err := ioutil.ReadFile(fileName) + contents, err := os.ReadFile(fileName) if err != nil { return 0, err } - res, err := parseUint(string(bytes.TrimSpace(contents)), 10, 64) + res, err := fscommon.ParseUint(string(bytes.TrimSpace(contents)), 10, 64) if err != nil { return res, fmt.Errorf("unable to parse %q as a uint from file %q", string(contents), fileName) } @@ -401,7 +376,7 @@ func getIntelRdtParamUint(path, file string) (uint64, error) { // Gets a string value from the specified file func getIntelRdtParamString(path, file string) (string, error) { - contents, err := ioutil.ReadFile(filepath.Join(path, file)) + contents, err := os.ReadFile(filepath.Join(path, file)) if err != nil { return "", err } @@ -413,29 +388,17 @@ func writeFile(dir, file, data string) error { if dir == "" { return fmt.Errorf("no such directory for %s", file) } - if err := ioutil.WriteFile(filepath.Join(dir, file), []byte(data+"\n"), 0o600); err != nil { - return fmt.Errorf("failed to write %v to %v: %v", data, file, err) + if err := os.WriteFile(filepath.Join(dir, file), []byte(data+"\n"), 0o600); err != nil { + return newLastCmdError(fmt.Errorf("intelrdt: unable to write %v: %w", data, err)) } return nil } -func getIntelRdtData(c *configs.Config, pid int) (*intelRdtData, error) { - rootPath, err := getIntelRdtRoot() - if err != nil { - return nil, err - } - return &intelRdtData{ - root: rootPath, - config: c, - pid: pid, - }, nil -} - // Get the read-only L3 cache information func getL3CacheInfo() (*L3CacheInfo, error) { l3CacheInfo := &L3CacheInfo{} - rootPath, err := getIntelRdtRoot() + rootPath, err := Root() if err != nil { return l3CacheInfo, err } @@ -465,7 +428,7 @@ func getL3CacheInfo() (*L3CacheInfo, error) { func getMemBwInfo() (*MemBwInfo, error) { memBwInfo := &MemBwInfo{} - rootPath, err := getIntelRdtRoot() + rootPath, err := Root() if err != nil { return memBwInfo, err } @@ -498,7 +461,7 @@ func getMemBwInfo() (*MemBwInfo, error) { // Get diagnostics for last filesystem operation error from file info/last_cmd_status func getLastCmdStatus() (string, error) { - rootPath, err := getIntelRdtRoot() + rootPath, err := Root() if err != nil { return "", err } @@ -515,13 +478,13 @@ func getLastCmdStatus() (string, error) { // WriteIntelRdtTasks writes the specified pid into the "tasks" file func WriteIntelRdtTasks(dir string, pid int) error { if dir == "" { - return fmt.Errorf("no such directory for %s", IntelRdtTasks) + return fmt.Errorf("no such directory for %s", intelRdtTasks) } // Don't attach any pid if -1 is specified as a pid if pid != -1 { - if err := ioutil.WriteFile(filepath.Join(dir, IntelRdtTasks), []byte(strconv.Itoa(pid)), 0o600); err != nil { - return fmt.Errorf("failed to write %v to %v: %v", pid, IntelRdtTasks, err) + if err := os.WriteFile(filepath.Join(dir, intelRdtTasks), []byte(strconv.Itoa(pid)), 0o600); err != nil { + return newLastCmdError(fmt.Errorf("intelrdt: unable to add pid %d: %w", pid, err)) } } return nil @@ -545,15 +508,19 @@ func IsMBAScEnabled() bool { return mbaScEnabled } -// Get the 'container_id' path in Intel RDT "resource control" filesystem -func GetIntelRdtPath(id string) (string, error) { - rootPath, err := getIntelRdtRoot() +// Get the path of the clos group in "resource control" filesystem that the container belongs to +func (m *intelRdtManager) getIntelRdtPath() (string, error) { + rootPath, err := Root() if err != nil { return "", err } - path := filepath.Join(rootPath, id) - return path, nil + clos := m.id + if m.config.IntelRdt != nil && m.config.IntelRdt.ClosID != "" { + clos = m.config.IntelRdt.ClosID + } + + return filepath.Join(rootPath, clos), nil } // Applies Intel RDT configuration to the process with the specified pid @@ -562,30 +529,48 @@ func (m *intelRdtManager) Apply(pid int) (err error) { if m.config.IntelRdt == nil { return nil } - d, err := getIntelRdtData(m.config, pid) - if err != nil && !IsNotFound(err) { + + path, err := m.getIntelRdtPath() + if err != nil { return err } m.mu.Lock() defer m.mu.Unlock() - path, err := d.join(m.id) - if err != nil { - return err + + if m.config.IntelRdt.ClosID != "" && m.config.IntelRdt.L3CacheSchema == "" && m.config.IntelRdt.MemBwSchema == "" { + // Check that the CLOS exists, i.e. it has been pre-configured to + // conform with the runtime spec + if _, err := os.Stat(path); err != nil { + return fmt.Errorf("clos dir not accessible (must be pre-created when l3CacheSchema and memBwSchema are empty): %w", err) + } + } + + if err := os.MkdirAll(path, 0o755); err != nil { + return newLastCmdError(err) + } + + if err := WriteIntelRdtTasks(path, pid); err != nil { + return newLastCmdError(err) } m.path = path return nil } -// Destroys the Intel RDT 'container_id' group +// Destroys the Intel RDT container-specific 'container_id' group func (m *intelRdtManager) Destroy() error { - m.mu.Lock() - defer m.mu.Unlock() - if err := os.RemoveAll(m.GetPath()); err != nil { - return err + // Don't remove resctrl group if closid has been explicitly specified. The + // group is likely externally managed, i.e. by some other entity than us. + // There are probably other containers/tasks sharing the same group. + if m.config.IntelRdt == nil || m.config.IntelRdt.ClosID == "" { + m.mu.Lock() + defer m.mu.Unlock() + if err := os.RemoveAll(m.GetPath()); err != nil { + return err + } + m.path = "" } - m.path = "" return nil } @@ -593,7 +578,7 @@ func (m *intelRdtManager) Destroy() error { // restore the object later func (m *intelRdtManager) GetPath() string { if m.path == "" { - m.path, _ = GetIntelRdtPath(m.id) + m.path, _ = m.getIntelRdtPath() } return m.path } @@ -607,9 +592,9 @@ func (m *intelRdtManager) GetStats() (*Stats, error) { m.mu.Lock() defer m.mu.Unlock() - stats := NewStats() + stats := newStats() - rootPath, err := getIntelRdtRoot() + rootPath, err := Root() if err != nil { return nil, err } @@ -620,7 +605,7 @@ func (m *intelRdtManager) GetStats() (*Stats, error) { } schemaRootStrings := strings.Split(tmpRootStrings, "\n") - // The L3 cache and memory bandwidth schemata in 'container_id' group + // The L3 cache and memory bandwidth schemata in container's clos group containerPath := m.GetPath() tmpStrings, err := getIntelRdtParamString(containerPath, "schemata") if err != nil { @@ -643,7 +628,7 @@ func (m *intelRdtManager) GetStats() (*Stats, error) { } } - // The L3 cache schema in 'container_id' group + // The L3 cache schema in container's clos group for _, schema := range schemaStrings { if strings.Contains(schema, "L3") { stats.L3CacheSchema = strings.TrimSpace(schema) @@ -666,7 +651,7 @@ func (m *intelRdtManager) GetStats() (*Stats, error) { } } - // The memory bandwidth schema in 'container_id' group + // The memory bandwidth schema in container's clos group for _, schema := range schemaStrings { if strings.Contains(schema, "MB") { stats.MemBwSchema = strings.TrimSpace(schema) @@ -736,24 +721,30 @@ func (m *intelRdtManager) Set(container *configs.Config) error { l3CacheSchema := container.IntelRdt.L3CacheSchema memBwSchema := container.IntelRdt.MemBwSchema + // TODO: verify that l3CacheSchema and/or memBwSchema match the + // existing schemata if ClosID has been specified. This is a more + // involved than reading the file and doing plain string comparison as + // the value written in does not necessarily match what gets read out + // (leading zeros, cache id ordering etc). + // Write a single joint schema string to schemata file if l3CacheSchema != "" && memBwSchema != "" { if err := writeFile(path, "schemata", l3CacheSchema+"\n"+memBwSchema); err != nil { - return NewLastCmdError(err) + return err } } // Write only L3 cache schema string to schemata file if l3CacheSchema != "" && memBwSchema == "" { if err := writeFile(path, "schemata", l3CacheSchema); err != nil { - return NewLastCmdError(err) + return err } } // Write only memory bandwidth schema string to schemata file if l3CacheSchema == "" && memBwSchema != "" { if err := writeFile(path, "schemata", memBwSchema); err != nil { - return NewLastCmdError(err) + return err } } } @@ -761,56 +752,10 @@ func (m *intelRdtManager) Set(container *configs.Config) error { return nil } -func (raw *intelRdtData) join(id string) (string, error) { - path := filepath.Join(raw.root, id) - if err := os.MkdirAll(path, 0o755); err != nil { - return "", NewLastCmdError(err) - } - - if err := WriteIntelRdtTasks(path, raw.pid); err != nil { - return "", NewLastCmdError(err) - } - return path, nil -} - -type NotFoundError struct { - ResourceControl string -} - -func (e *NotFoundError) Error() string { - return fmt.Sprintf("mountpoint for %s not found", e.ResourceControl) -} - -func NewNotFoundError(res string) error { - return &NotFoundError{ - ResourceControl: res, - } -} - -func IsNotFound(err error) bool { - if err == nil { - return false - } - _, ok := err.(*NotFoundError) - return ok -} - -type LastCmdError struct { - LastCmdStatus string - Err error -} - -func (e *LastCmdError) Error() string { - return e.Err.Error() + ", last_cmd_status: " + e.LastCmdStatus -} - -func NewLastCmdError(err error) error { - lastCmdStatus, err1 := getLastCmdStatus() +func newLastCmdError(err error) error { + status, err1 := getLastCmdStatus() if err1 == nil { - return &LastCmdError{ - LastCmdStatus: lastCmdStatus, - Err: err, - } + return fmt.Errorf("%w, last_cmd_status: %s", err, status) } return err } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/mbm.go b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/mbm.go index 0fbecdeb22810..13f31ac7a089c 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/mbm.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/mbm.go @@ -1,5 +1,3 @@ -// +build linux - package intelrdt // The flag to indicate if Intel RDT/MBM is enabled diff --git a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/monitoring.go b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/monitoring.go index 547c15470f258..82e0002efad02 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/monitoring.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/monitoring.go @@ -3,7 +3,6 @@ package intelrdt import ( "bufio" "io" - "io/ioutil" "os" "path/filepath" @@ -49,7 +48,7 @@ func parseMonFeatures(reader io.Reader) (monFeatures, error) { } func getMonitoringStats(containerPath string, stats *Stats) error { - numaFiles, err := ioutil.ReadDir(filepath.Join(containerPath, "mon_data")) + numaFiles, err := os.ReadDir(filepath.Join(containerPath, "mon_data")) if err != nil { return err } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go index 70df0d14e6cec..a5eb2541e8166 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go @@ -1,5 +1,3 @@ -// +build linux - package intelrdt type L3CacheInfo struct { @@ -54,6 +52,6 @@ type Stats struct { CMTStats *[]CMTNumaNodeStats `json:"cmt_stats,omitempty"` } -func NewStats() *Stats { +func newStats() *Stats { return &Stats{} } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go b/vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go index 4a60c34b84213..f3a6c5343fa46 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go @@ -1,13 +1,11 @@ -// +build linux - package keys import ( + "errors" + "fmt" "strconv" "strings" - "github.com/pkg/errors" - "golang.org/x/sys/unix" ) @@ -16,7 +14,7 @@ type KeySerial uint32 func JoinSessionKeyring(name string) (KeySerial, error) { sessKeyID, err := unix.KeyctlJoinSessionKeyring(name) if err != nil { - return 0, errors.Wrap(err, "create session key") + return 0, fmt.Errorf("unable to create session key: %w", err) } return KeySerial(sessKeyID), nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/logs/logs.go b/vendor/github.com/opencontainers/runc/libcontainer/logs/logs.go index 6610a1aaeeac3..95deb0d6ca7a0 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/logs/logs.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/logs/logs.go @@ -3,37 +3,28 @@ package logs import ( "bufio" "encoding/json" - "fmt" "io" - "os" - "sync" - "github.com/pkg/errors" "github.com/sirupsen/logrus" ) -var ( - configureMutex sync.Mutex - // loggingConfigured will be set once logging has been configured via invoking `ConfigureLogging`. - // Subsequent invocations of `ConfigureLogging` would be no-op - loggingConfigured = false -) - -type Config struct { - LogLevel logrus.Level - LogFormat string - LogFilePath string - LogPipeFd int - LogCaller bool -} - func ForwardLogs(logPipe io.ReadCloser) chan error { done := make(chan error, 1) s := bufio.NewScanner(logPipe) + logger := logrus.StandardLogger() + if logger.ReportCaller { + // Need a copy of the standard logger, but with ReportCaller + // turned off, as the logs are merely forwarded and their + // true source is not this file/line/function. + logNoCaller := *logrus.StandardLogger() + logNoCaller.ReportCaller = false + logger = &logNoCaller + } + go func() { for s.Scan() { - processEntry(s.Bytes()) + processEntry(s.Bytes(), logger) } if err := logPipe.Close(); err != nil { logrus.Errorf("error closing log source: %v", err) @@ -47,60 +38,19 @@ func ForwardLogs(logPipe io.ReadCloser) chan error { return done } -func processEntry(text []byte) { +func processEntry(text []byte, logger *logrus.Logger) { if len(text) == 0 { return } var jl struct { - Level string `json:"level"` - Msg string `json:"msg"` + Level logrus.Level `json:"level"` + Msg string `json:"msg"` } if err := json.Unmarshal(text, &jl); err != nil { logrus.Errorf("failed to decode %q to json: %v", text, err) return } - lvl, err := logrus.ParseLevel(jl.Level) - if err != nil { - logrus.Errorf("failed to parse log level %q: %v", jl.Level, err) - return - } - logrus.StandardLogger().Logf(lvl, jl.Msg) -} - -func ConfigureLogging(config Config) error { - configureMutex.Lock() - defer configureMutex.Unlock() - - if loggingConfigured { - return errors.New("logging has already been configured") - } - - logrus.SetLevel(config.LogLevel) - logrus.SetReportCaller(config.LogCaller) - - // XXX: while 0 is a valid fd (usually stdin), here we assume - // that we never deliberately set LogPipeFd to 0. - if config.LogPipeFd > 0 { - logrus.SetOutput(os.NewFile(uintptr(config.LogPipeFd), "logpipe")) - } else if config.LogFilePath != "" { - f, err := os.OpenFile(config.LogFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0o644) - if err != nil { - return err - } - logrus.SetOutput(f) - } - - switch config.LogFormat { - case "text": - // retain logrus's default. - case "json": - logrus.SetFormatter(new(logrus.JSONFormatter)) - default: - return fmt.Errorf("unknown log-format %q", config.LogFormat) - } - - loggingConfigured = true - return nil + logger.Log(jl.Level, jl.Msg) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/message_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/message_linux.go index e4107ce39f27d..6d1107e875d4b 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/message_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/message_linux.go @@ -1,5 +1,3 @@ -// +build linux - package libcontainer import ( @@ -23,6 +21,7 @@ const ( RootlessEUIDAttr uint16 = 27287 UidmapPathAttr uint16 = 27288 GidmapPathAttr uint16 = 27289 + MountSourcesAttr uint16 = 27290 ) type Int32msg struct { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/mount_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/mount_linux.go new file mode 100644 index 0000000000000..5f49de964ff5f --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/mount_linux.go @@ -0,0 +1,83 @@ +package libcontainer + +import ( + "strconv" + + "golang.org/x/sys/unix" +) + +// mountError holds an error from a failed mount or unmount operation. +type mountError struct { + op string + source string + target string + procfd string + flags uintptr + data string + err error +} + +// Error provides a string error representation. +func (e *mountError) Error() string { + out := e.op + " " + + if e.source != "" { + out += e.source + ":" + e.target + } else { + out += e.target + } + if e.procfd != "" { + out += " (via " + e.procfd + ")" + } + + if e.flags != uintptr(0) { + out += ", flags: 0x" + strconv.FormatUint(uint64(e.flags), 16) + } + if e.data != "" { + out += ", data: " + e.data + } + + out += ": " + e.err.Error() + return out +} + +// Unwrap returns the underlying error. +// This is a convention used by Go 1.13+ standard library. +func (e *mountError) Unwrap() error { + return e.err +} + +// mount is a simple unix.Mount wrapper. If procfd is not empty, it is used +// instead of target (and the target is only used to add context to an error). +func mount(source, target, procfd, fstype string, flags uintptr, data string) error { + dst := target + if procfd != "" { + dst = procfd + } + if err := unix.Mount(source, dst, fstype, flags, data); err != nil { + return &mountError{ + op: "mount", + source: source, + target: target, + procfd: procfd, + flags: flags, + data: data, + err: err, + } + } + return nil +} + +// unmount is a simple unix.Unmount wrapper. +func unmount(target string, flags int) error { + err := unix.Unmount(target, flags) + if err != nil { + return &mountError{ + op: "unmount", + target: target, + flags: uintptr(flags), + err: err, + } + } + return nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/network_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/network_linux.go index 12e5800fc0e68..8915548b3bc0d 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/network_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/network_linux.go @@ -1,11 +1,9 @@ -// +build linux - package libcontainer import ( "bytes" "fmt" - "io/ioutil" + "os" "path/filepath" "strconv" @@ -75,7 +73,7 @@ func getNetworkInterfaceStats(interfaceName string) (*types.NetworkInterface, er // Reads the specified statistics available under /sys/class/net//statistics func readSysfsNetworkStats(ethInterface, statsFile string) (uint64, error) { - data, err := ioutil.ReadFile(filepath.Join("/sys/class/net", ethInterface, "statistics", statsFile)) + data, err := os.ReadFile(filepath.Join("/sys/class/net", ethInterface, "statistics", statsFile)) if err != nil { return 0, err } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go index 73a6f5946558f..a8762842e8fb8 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go @@ -1,11 +1,8 @@ -// +build linux - package libcontainer import ( "errors" "fmt" - "io/ioutil" "os" "path/filepath" @@ -35,7 +32,7 @@ func registerMemoryEvent(cgDir string, evName string, arg string) (<-chan struct eventControlPath := filepath.Join(cgDir, "cgroup.event_control") data := fmt.Sprintf("%d %d %s", eventfd.Fd(), evFile.Fd(), arg) - if err := ioutil.WriteFile(eventControlPath, []byte(data), 0o700); err != nil { + if err := os.WriteFile(eventControlPath, []byte(data), 0o700); err != nil { eventfd.Close() evFile.Close() return nil, err diff --git a/vendor/github.com/opencontainers/runc/libcontainer/notify_linux_v2.go b/vendor/github.com/opencontainers/runc/libcontainer/notify_v2_linux.go similarity index 87% rename from vendor/github.com/opencontainers/runc/libcontainer/notify_linux_v2.go rename to vendor/github.com/opencontainers/runc/libcontainer/notify_v2_linux.go index dd0ec290ecf18..821536c8da024 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/notify_linux_v2.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/notify_v2_linux.go @@ -1,13 +1,11 @@ -// +build linux - package libcontainer import ( + "fmt" "path/filepath" "unsafe" "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" - "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) @@ -15,19 +13,19 @@ import ( func registerMemoryEventV2(cgDir, evName, cgEvName string) (<-chan struct{}, error) { fd, err := unix.InotifyInit() if err != nil { - return nil, errors.Wrap(err, "unable to init inotify") + return nil, fmt.Errorf("unable to init inotify: %w", err) } // watching oom kill evFd, err := unix.InotifyAddWatch(fd, filepath.Join(cgDir, evName), unix.IN_MODIFY) if err != nil { unix.Close(fd) - return nil, errors.Wrap(err, "unable to add inotify watch") + return nil, fmt.Errorf("unable to add inotify watch: %w", err) } // Because no `unix.IN_DELETE|unix.IN_DELETE_SELF` event for cgroup file system, so watching all process exited cgFd, err := unix.InotifyAddWatch(fd, filepath.Join(cgDir, cgEvName), unix.IN_MODIFY) if err != nil { unix.Close(fd) - return nil, errors.Wrap(err, "unable to add inotify watch") + return nil, fmt.Errorf("unable to add inotify watch: %w", err) } ch := make(chan struct{}) go func() { @@ -53,7 +51,7 @@ func registerMemoryEventV2(cgDir, evName, cgEvName string) (<-chan struct{}, err offset = 0 for offset <= uint32(n-unix.SizeofInotifyEvent) { rawEvent := (*unix.InotifyEvent)(unsafe.Pointer(&buffer[offset])) - offset += unix.SizeofInotifyEvent + uint32(rawEvent.Len) + offset += unix.SizeofInotifyEvent + rawEvent.Len if rawEvent.Mask&unix.IN_MODIFY != unix.IN_MODIFY { continue } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/process.go b/vendor/github.com/opencontainers/runc/libcontainer/process.go index d3e472a4fdb99..8a5d340dacddc 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/process.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/process.go @@ -1,7 +1,7 @@ package libcontainer import ( - "fmt" + "errors" "io" "math" "os" @@ -9,6 +9,8 @@ import ( "github.com/opencontainers/runc/libcontainer/configs" ) +var errInvalidProcess = errors.New("invalid process") + type processOperations interface { wait() (*os.ProcessState, error) signal(sig os.Signal) error @@ -78,13 +80,22 @@ type Process struct { ops processOperations LogLevel string + + // SubCgroupPaths specifies sub-cgroups to run the process in. + // Map keys are controller names, map values are paths (relative to + // container's top-level cgroup). + // + // If empty, the default top-level container's cgroup is used. + // + // For cgroup v2, the only key allowed is "". + SubCgroupPaths map[string]string } // Wait waits for the process to exit. // Wait releases any resources associated with the Process func (p Process) Wait() (*os.ProcessState, error) { if p.ops == nil { - return nil, newGenericError(fmt.Errorf("invalid process"), NoProcessOps) + return nil, errInvalidProcess } return p.ops.wait() } @@ -94,7 +105,7 @@ func (p Process) Pid() (int, error) { // math.MinInt32 is returned here, because it's invalid value // for the kill() system call. if p.ops == nil { - return math.MinInt32, newGenericError(fmt.Errorf("invalid process"), NoProcessOps) + return math.MinInt32, errInvalidProcess } return p.ops.pid(), nil } @@ -102,7 +113,7 @@ func (p Process) Pid() (int, error) { // Signal sends a signal to the Process. func (p Process) Signal(sig os.Signal) error { if p.ops == nil { - return newGenericError(fmt.Errorf("invalid process"), NoProcessOps) + return errInvalidProcess } return p.ops.signal(sig) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go index 80f25e334f71e..e025445d3307d 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go @@ -1,5 +1,3 @@ -// +build linux - package libcontainer import ( @@ -7,6 +5,7 @@ import ( "errors" "fmt" "io" + "net" "os" "os/exec" "path/filepath" @@ -25,10 +24,6 @@ import ( "golang.org/x/sys/unix" ) -// Synchronisation value for cgroup namespace setup. -// The same constant is defined in nsexec.c as "CREATECGROUPNS". -const createCgroupns = 0x80 - type parentProcess interface { // pid returns the pid for the running process. pid() int @@ -96,7 +91,7 @@ func (p *setnsProcess) start() (retErr error) { p.messageSockPair.child.Close() p.logFilePair.child.Close() if err != nil { - return newSystemErrorWithCause(err, "starting setns process") + return fmt.Errorf("error starting setns process: %w", err) } waitInit := initWaiter(p.messageSockPair.parent) @@ -104,7 +99,7 @@ func (p *setnsProcess) start() (retErr error) { if retErr != nil { if newOom, err := p.manager.OOMKillCount(); err == nil && newOom != oom { // Someone in this cgroup was killed, this _might_ be us. - retErr = newSystemErrorWithCause(retErr, "possibly OOM-killed") + retErr = fmt.Errorf("%w (possibly OOM-killed)", retErr) } werr := <-waitInit if werr != nil { @@ -119,7 +114,7 @@ func (p *setnsProcess) start() (retErr error) { if p.bootstrapData != nil { if _, err := io.Copy(p.messageSockPair.parent, p.bootstrapData); err != nil { - return newSystemErrorWithCause(err, "copying bootstrap data to pipe") + return fmt.Errorf("error copying bootstrap data to pipe: %w", err) } } err = <-waitInit @@ -127,14 +122,14 @@ func (p *setnsProcess) start() (retErr error) { return err } if err := p.execSetns(); err != nil { - return newSystemErrorWithCause(err, "executing setns process") + return fmt.Errorf("error executing setns process: %w", err) } - if len(p.cgroupPaths) > 0 { - if err := cgroups.EnterPid(p.cgroupPaths, p.pid()); err != nil && !p.rootlessCgroups { - // On cgroup v2 + nesting + domain controllers, EnterPid may fail with EBUSY. + for _, path := range p.cgroupPaths { + if err := cgroups.WriteCgroupProc(path, p.pid()); err != nil && !p.rootlessCgroups { + // On cgroup v2 + nesting + domain controllers, WriteCgroupProc may fail with EBUSY. // https://github.com/opencontainers/runc/issues/2356#issuecomment-621277643 // Try to join the cgroup of InitProcessPid. - if cgroups.IsCgroup2UnifiedMode() { + if cgroups.IsCgroup2UnifiedMode() && p.initProcessPid != 0 { initProcCgroupFile := fmt.Sprintf("/proc/%d/cgroup", p.initProcessPid) initCg, initCgErr := cgroups.ParseCgroupFile(initProcCgroupFile) if initCgErr == nil { @@ -148,7 +143,7 @@ func (p *setnsProcess) start() (retErr error) { } } if err != nil { - return newSystemErrorWithCausef(err, "adding pid %d to cgroups", p.pid()) + return fmt.Errorf("error adding pid %d to cgroups: %w", p.pid(), err) } } } @@ -157,17 +152,17 @@ func (p *setnsProcess) start() (retErr error) { _, err := os.Stat(p.intelRdtPath) if err == nil { if err := intelrdt.WriteIntelRdtTasks(p.intelRdtPath, p.pid()); err != nil { - return newSystemErrorWithCausef(err, "adding pid %d to Intel RDT resource control filesystem", p.pid()) + return fmt.Errorf("error adding pid %d to Intel RDT: %w", p.pid(), err) } } } // set rlimits, this has to be done here because we lose permissions // to raise the limits once we enter a user-namespace if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil { - return newSystemErrorWithCause(err, "setting rlimits for process") + return fmt.Errorf("error setting rlimits for process: %w", err) } if err := utils.WriteJSON(p.messageSockPair.parent, p.config); err != nil { - return newSystemErrorWithCause(err, "writing config to pipe") + return fmt.Errorf("error writing config to pipe: %w", err) } ierr := parseSync(p.messageSockPair.parent, func(sync *syncT) error { @@ -178,13 +173,49 @@ func (p *setnsProcess) start() (retErr error) { case procHooks: // This shouldn't happen. panic("unexpected procHooks in setns") + case procSeccomp: + if p.config.Config.Seccomp.ListenerPath == "" { + return errors.New("listenerPath is not set") + } + + seccompFd, err := recvSeccompFd(uintptr(p.pid()), uintptr(sync.Fd)) + if err != nil { + return err + } + defer unix.Close(seccompFd) + + bundle, annotations := utils.Annotations(p.config.Config.Labels) + containerProcessState := &specs.ContainerProcessState{ + Version: specs.Version, + Fds: []string{specs.SeccompFdName}, + Pid: p.cmd.Process.Pid, + Metadata: p.config.Config.Seccomp.ListenerMetadata, + State: specs.State{ + Version: specs.Version, + ID: p.config.ContainerId, + Status: specs.StateRunning, + Pid: p.initProcessPid, + Bundle: bundle, + Annotations: annotations, + }, + } + if err := sendContainerProcessState(p.config.Config.Seccomp.ListenerPath, + containerProcessState, seccompFd); err != nil { + return err + } + + // Sync with child. + if err := writeSync(p.messageSockPair.parent, procSeccompDone); err != nil { + return err + } + return nil default: - return newSystemError(errors.New("invalid JSON payload from child")) + return errors.New("invalid JSON payload from child") } }) if err := unix.Shutdown(int(p.messageSockPair.parent.Fd()), unix.SHUT_WR); err != nil { - return newSystemErrorWithCause(err, "calling shutdown on init pipe") + return &os.PathError{Op: "shutdown", Path: "(init pipe)", Err: err} } // Must be done after Shutdown so the child will exit and we can wait for it. if ierr != nil { @@ -202,16 +233,16 @@ func (p *setnsProcess) execSetns() error { status, err := p.cmd.Process.Wait() if err != nil { _ = p.cmd.Wait() - return newSystemErrorWithCause(err, "waiting on setns process to finish") + return fmt.Errorf("error waiting on setns process to finish: %w", err) } if !status.Success() { _ = p.cmd.Wait() - return newSystemError(&exec.ExitError{ProcessState: status}) + return &exec.ExitError{ProcessState: status} } var pid *pid if err := json.NewDecoder(p.messageSockPair.parent).Decode(&pid); err != nil { _ = p.cmd.Wait() - return newSystemErrorWithCause(err, "reading pid from init pipe") + return fmt.Errorf("error reading pid from init pipe: %w", err) } // Clean up the zombie parent process @@ -335,7 +366,7 @@ func (p *initProcess) start() (retErr error) { _ = p.logFilePair.child.Close() if err != nil { p.process.ops = nil - return newSystemErrorWithCause(err, "starting init process command") + return fmt.Errorf("unable to start init: %w", err) } waitInit := initWaiter(p.messageSockPair.parent) @@ -355,9 +386,9 @@ func (p *initProcess) start() (retErr error) { if logrus.GetLevel() >= logrus.DebugLevel { // Only show the original error if debug is set, // as it is not generally very useful. - retErr = newSystemErrorWithCause(retErr, oomError) + retErr = fmt.Errorf(oomError+": %w", retErr) } else { - retErr = newSystemError(errors.New(oomError)) + retErr = errors.New(oomError) } } @@ -382,15 +413,15 @@ func (p *initProcess) start() (retErr error) { // cgroup. We don't need to worry about not doing this and not being root // because we'd be using the rootless cgroup manager in that case. if err := p.manager.Apply(p.pid()); err != nil { - return newSystemErrorWithCause(err, "applying cgroup configuration for process") + return fmt.Errorf("unable to apply cgroup configuration: %w", err) } if p.intelRdtManager != nil { if err := p.intelRdtManager.Apply(p.pid()); err != nil { - return newSystemErrorWithCause(err, "applying Intel RDT configuration for process") + return fmt.Errorf("unable to apply Intel RDT configuration: %w", err) } } if _, err := io.Copy(p.messageSockPair.parent, p.bootstrapData); err != nil { - return newSystemErrorWithCause(err, "copying bootstrap data to pipe") + return fmt.Errorf("can't copy bootstrap data to pipe: %w", err) } err = <-waitInit if err != nil { @@ -399,7 +430,7 @@ func (p *initProcess) start() (retErr error) { childPid, err := p.getChildPid() if err != nil { - return newSystemErrorWithCause(err, "getting the final child's pid from pipe") + return fmt.Errorf("can't get final child's PID from pipe: %w", err) } // Save the standard descriptor names before the container process @@ -407,30 +438,23 @@ func (p *initProcess) start() (retErr error) { // we won't know at checkpoint time which file descriptor to look up. fds, err := getPipeFds(childPid) if err != nil { - return newSystemErrorWithCausef(err, "getting pipe fds for pid %d", childPid) + return fmt.Errorf("error getting pipe fds for pid %d: %w", childPid, err) } p.setExternalDescriptors(fds) - // Now it's time to setup cgroup namesapce - if p.config.Config.Namespaces.Contains(configs.NEWCGROUP) && p.config.Config.Namespaces.PathOf(configs.NEWCGROUP) == "" { - if _, err := p.messageSockPair.parent.Write([]byte{createCgroupns}); err != nil { - return newSystemErrorWithCause(err, "sending synchronization value to init process") - } - } - // Wait for our first child to exit if err := p.waitForChildExit(childPid); err != nil { - return newSystemErrorWithCause(err, "waiting for our first child to exit") + return fmt.Errorf("error waiting for our first child to exit: %w", err) } if err := p.createNetworkInterfaces(); err != nil { - return newSystemErrorWithCause(err, "creating network interfaces") + return fmt.Errorf("error creating network interfaces: %w", err) } if err := p.updateSpecState(); err != nil { - return newSystemErrorWithCause(err, "updating the spec state") + return fmt.Errorf("error updating spec state: %w", err) } if err := p.sendConfig(); err != nil { - return newSystemErrorWithCause(err, "sending config to init process") + return fmt.Errorf("error sending config to init process: %w", err) } var ( sentRun bool @@ -439,25 +463,60 @@ func (p *initProcess) start() (retErr error) { ierr := parseSync(p.messageSockPair.parent, func(sync *syncT) error { switch sync.Type { + case procSeccomp: + if p.config.Config.Seccomp.ListenerPath == "" { + return errors.New("listenerPath is not set") + } + + seccompFd, err := recvSeccompFd(uintptr(childPid), uintptr(sync.Fd)) + if err != nil { + return err + } + defer unix.Close(seccompFd) + + s, err := p.container.currentOCIState() + if err != nil { + return err + } + + // initProcessStartTime hasn't been set yet. + s.Pid = p.cmd.Process.Pid + s.Status = specs.StateCreating + containerProcessState := &specs.ContainerProcessState{ + Version: specs.Version, + Fds: []string{specs.SeccompFdName}, + Pid: s.Pid, + Metadata: p.config.Config.Seccomp.ListenerMetadata, + State: *s, + } + if err := sendContainerProcessState(p.config.Config.Seccomp.ListenerPath, + containerProcessState, seccompFd); err != nil { + return err + } + + // Sync with child. + if err := writeSync(p.messageSockPair.parent, procSeccompDone); err != nil { + return err + } case procReady: // set rlimits, this has to be done here because we lose permissions // to raise the limits once we enter a user-namespace if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil { - return newSystemErrorWithCause(err, "setting rlimits for ready process") + return fmt.Errorf("error setting rlimits for ready process: %w", err) } // call prestart and CreateRuntime hooks if !p.config.Config.Namespaces.Contains(configs.NEWNS) { // Setup cgroup before the hook, so that the prestart and CreateRuntime hook could apply cgroup permissions. if err := p.manager.Set(p.config.Config.Cgroups.Resources); err != nil { - return newSystemErrorWithCause(err, "setting cgroup config for ready process") + return fmt.Errorf("error setting cgroup config for ready process: %w", err) } if p.intelRdtManager != nil { if err := p.intelRdtManager.Set(p.config.Config); err != nil { - return newSystemErrorWithCause(err, "setting Intel RDT config for ready process") + return fmt.Errorf("error setting Intel RDT config for ready process: %w", err) } } - if p.config.Config.Hooks != nil { + if len(p.config.Config.Hooks) != 0 { s, err := p.container.currentOCIState() if err != nil { return err @@ -493,26 +552,26 @@ func (p *initProcess) start() (retErr error) { // procRun sync. state, uerr := p.container.updateState(p) if uerr != nil { - return newSystemErrorWithCause(err, "store init state") + return fmt.Errorf("unable to store init state: %w", err) } p.container.initProcessStartTime = state.InitProcessStartTime // Sync with child. if err := writeSync(p.messageSockPair.parent, procRun); err != nil { - return newSystemErrorWithCause(err, "writing syncT 'run'") + return err } sentRun = true case procHooks: // Setup cgroup before prestart hook, so that the prestart hook could apply cgroup permissions. if err := p.manager.Set(p.config.Config.Cgroups.Resources); err != nil { - return newSystemErrorWithCause(err, "setting cgroup config for procHooks process") + return fmt.Errorf("error setting cgroup config for procHooks process: %w", err) } if p.intelRdtManager != nil { if err := p.intelRdtManager.Set(p.config.Config); err != nil { - return newSystemErrorWithCause(err, "setting Intel RDT config for procHooks process") + return fmt.Errorf("error setting Intel RDT config for procHooks process: %w", err) } } - if p.config.Config.Hooks != nil { + if len(p.config.Config.Hooks) != 0 { s, err := p.container.currentOCIState() if err != nil { return err @@ -531,24 +590,24 @@ func (p *initProcess) start() (retErr error) { } // Sync with child. if err := writeSync(p.messageSockPair.parent, procResume); err != nil { - return newSystemErrorWithCause(err, "writing syncT 'resume'") + return err } sentResume = true default: - return newSystemError(errors.New("invalid JSON payload from child")) + return errors.New("invalid JSON payload from child") } return nil }) if !sentRun { - return newSystemErrorWithCause(ierr, "container init") + return fmt.Errorf("error during container init: %w", ierr) } if p.config.Config.Namespaces.Contains(configs.NEWNS) && !sentResume { - return newSystemError(errors.New("could not synchronise after executing prestart and CreateRuntime hooks with container process")) + return errors.New("could not synchronise after executing prestart and CreateRuntime hooks with container process") } if err := unix.Shutdown(int(p.messageSockPair.parent.Fd()), unix.SHUT_WR); err != nil { - return newSystemErrorWithCause(err, "shutting down init pipe") + return &os.PathError{Op: "shutdown", Path: "(init pipe)", Err: err} } // Must be done after Shutdown so the child will exit and we can wait for it. @@ -634,6 +693,46 @@ func (p *initProcess) forwardChildLogs() chan error { return logs.ForwardLogs(p.logFilePair.parent) } +func recvSeccompFd(childPid, childFd uintptr) (int, error) { + pidfd, _, errno := unix.Syscall(unix.SYS_PIDFD_OPEN, childPid, 0, 0) + if errno != 0 { + return -1, fmt.Errorf("performing SYS_PIDFD_OPEN syscall: %w", errno) + } + defer unix.Close(int(pidfd)) + + seccompFd, _, errno := unix.Syscall(unix.SYS_PIDFD_GETFD, pidfd, childFd, 0) + if errno != 0 { + return -1, fmt.Errorf("performing SYS_PIDFD_GETFD syscall: %w", errno) + } + + return int(seccompFd), nil +} + +func sendContainerProcessState(listenerPath string, state *specs.ContainerProcessState, fd int) error { + conn, err := net.Dial("unix", listenerPath) + if err != nil { + return fmt.Errorf("failed to connect with seccomp agent specified in the seccomp profile: %w", err) + } + + socket, err := conn.(*net.UnixConn).File() + if err != nil { + return fmt.Errorf("cannot get seccomp socket: %w", err) + } + defer socket.Close() + + b, err := json.Marshal(state) + if err != nil { + return fmt.Errorf("cannot marshall seccomp state: %w", err) + } + + err = utils.SendFds(socket, b, fd) + if err != nil { + return fmt.Errorf("cannot send seccomp fd to %s: %w", listenerPath, err) + } + + return nil +} + func getPipeFds(pid int) ([]string, error) { fds := make([]string, 3) @@ -694,7 +793,7 @@ func (p *Process) InitializeIO(rootuid, rootgid int) (i *IO, err error) { // change ownership of the pipes in case we are in a user namespace for _, fd := range fds { if err := unix.Fchown(int(fd), rootuid, rootgid); err != nil { - return nil, err + return nil, &os.PathError{Op: "fchown", Path: "fd " + strconv.Itoa(int(fd)), Err: err} } } return i, nil @@ -719,7 +818,7 @@ func initWaiter(r io.Reader) chan error { return } } - ch <- newSystemErrorWithCause(err, "waiting for init preliminary setup") + ch <- fmt.Errorf("waiting for init preliminary setup: %w", err) }() return ch diff --git a/vendor/github.com/opencontainers/runc/libcontainer/restored_process.go b/vendor/github.com/opencontainers/runc/libcontainer/restored_process.go index 34270e64ed470..cdffbd3aff552 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/restored_process.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/restored_process.go @@ -1,9 +1,7 @@ -// +build linux - package libcontainer import ( - "fmt" + "errors" "os" "os/exec" @@ -31,7 +29,7 @@ type restoredProcess struct { } func (p *restoredProcess) start() error { - return newGenericError(fmt.Errorf("restored process cannot be started"), SystemError) + return errors.New("restored process cannot be started") } func (p *restoredProcess) pid() int { @@ -51,7 +49,8 @@ func (p *restoredProcess) wait() (*os.ProcessState, error) { // maybe use --exec-cmd in criu err := p.cmd.Wait() if err != nil { - if _, ok := err.(*exec.ExitError); !ok { + var exitErr *exec.ExitError + if !errors.As(err, &exitErr) { return nil, err } } @@ -89,7 +88,7 @@ type nonChildProcess struct { } func (p *nonChildProcess) start() error { - return newGenericError(fmt.Errorf("restored process cannot be started"), SystemError) + return errors.New("restored process cannot be started") } func (p *nonChildProcess) pid() int { @@ -97,11 +96,11 @@ func (p *nonChildProcess) pid() int { } func (p *nonChildProcess) terminate() error { - return newGenericError(fmt.Errorf("restored process cannot be terminated"), SystemError) + return errors.New("restored process cannot be terminated") } func (p *nonChildProcess) wait() (*os.ProcessState, error) { - return nil, newGenericError(fmt.Errorf("restored process cannot be waited on"), SystemError) + return nil, errors.New("restored process cannot be waited on") } func (p *nonChildProcess) startTime() (uint64, error) { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go index f962681947547..51660f5efb92f 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go @@ -1,15 +1,14 @@ -// +build linux - package libcontainer import ( + "errors" "fmt" "io" - "io/ioutil" "os" "os/exec" "path" "path/filepath" + "strconv" "strings" "time" @@ -36,6 +35,7 @@ type mountConfig struct { cgroup2Path string rootlessCgroups bool cgroupns bool + fd *int } // needsSetupDev returns true if /dev needs to be set up. @@ -51,10 +51,14 @@ func needsSetupDev(config *configs.Config) bool { // prepareRootfs sets up the devices, mount points, and filesystems for use // inside a new mount namespace. It doesn't set anything as ro. You must call // finalizeRootfs after this function to finish setting up the rootfs. -func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) { +func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig, mountFds []int) (err error) { config := iConfig.Config if err := prepareRoot(config); err != nil { - return newSystemErrorWithCause(err, "preparing rootfs") + return fmt.Errorf("error preparing rootfs: %w", err) + } + + if mountFds != nil && len(mountFds) != len(config.Mounts) { + return fmt.Errorf("malformed mountFds slice. Expected size: %v, got: %v. Slice: %v", len(config.Mounts), len(mountFds), mountFds) } mountConfig := &mountConfig{ @@ -65,32 +69,39 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) { cgroupns: config.Namespaces.Contains(configs.NEWCGROUP), } setupDev := needsSetupDev(config) - for _, m := range config.Mounts { + for i, m := range config.Mounts { for _, precmd := range m.PremountCmds { if err := mountCmd(precmd); err != nil { - return newSystemErrorWithCause(err, "running premount command") + return fmt.Errorf("error running premount command: %w", err) } } + + // Just before the loop we checked that if not empty, len(mountFds) == len(config.Mounts). + // Therefore, we can access mountFds[i] without any concerns. + if mountFds != nil && mountFds[i] != -1 { + mountConfig.fd = &mountFds[i] + } + if err := mountToRootfs(m, mountConfig); err != nil { - return newSystemErrorWithCausef(err, "mounting %q to rootfs at %q", m.Source, m.Destination) + return fmt.Errorf("error mounting %q to rootfs at %q: %w", m.Source, m.Destination, err) } for _, postcmd := range m.PostmountCmds { if err := mountCmd(postcmd); err != nil { - return newSystemErrorWithCause(err, "running postmount command") + return fmt.Errorf("error running postmount command: %w", err) } } } if setupDev { if err := createDevices(config); err != nil { - return newSystemErrorWithCause(err, "creating device nodes") + return fmt.Errorf("error creating device nodes: %w", err) } if err := setupPtmx(config); err != nil { - return newSystemErrorWithCause(err, "setting up ptmx") + return fmt.Errorf("error setting up ptmx: %w", err) } if err := setupDevSymlinks(config.Rootfs); err != nil { - return newSystemErrorWithCause(err, "setting up /dev symlinks") + return fmt.Errorf("error setting up /dev symlinks: %w", err) } } @@ -112,7 +123,7 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) { // operation not being perfectly split). if err := unix.Chdir(config.Rootfs); err != nil { - return newSystemErrorWithCausef(err, "changing dir to %q", config.Rootfs) + return &os.PathError{Op: "chdir", Path: config.Rootfs, Err: err} } s := iConfig.SpecState @@ -130,12 +141,12 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) { err = chroot() } if err != nil { - return newSystemErrorWithCause(err, "jailing process inside rootfs") + return fmt.Errorf("error jailing process inside rootfs: %w", err) } if setupDev { if err := reOpenDevNull(); err != nil { - return newSystemErrorWithCause(err, "reopening /dev/null inside container") + return fmt.Errorf("error reopening /dev/null inside container: %w", err) } } @@ -161,7 +172,7 @@ func finalizeRootfs(config *configs.Config) (err error) { } if m.Device == "tmpfs" || utils.CleanPath(m.Destination) == "/dev" { if err := remountReadonly(m); err != nil { - return newSystemErrorWithCausef(err, "remounting %q as readonly", m.Destination) + return err } } } @@ -169,7 +180,7 @@ func finalizeRootfs(config *configs.Config) (err error) { // set rootfs ( / ) as readonly if config.Readonlyfs { if err := setReadonly(); err != nil { - return newSystemErrorWithCause(err, "setting rootfs as readonly") + return fmt.Errorf("error setting rootfs as readonly: %w", err) } } @@ -183,14 +194,14 @@ func finalizeRootfs(config *configs.Config) (err error) { // /tmp has to be mounted as private to allow MS_MOVE to work in all situations func prepareTmp(topTmpDir string) (string, error) { - tmpdir, err := ioutil.TempDir(topTmpDir, "runctop") + tmpdir, err := os.MkdirTemp(topTmpDir, "runctop") if err != nil { return "", err } - if err := unix.Mount(tmpdir, tmpdir, "bind", unix.MS_BIND, ""); err != nil { + if err := mount(tmpdir, tmpdir, "", "bind", unix.MS_BIND, ""); err != nil { return "", err } - if err := unix.Mount("", tmpdir, "", uintptr(unix.MS_PRIVATE), ""); err != nil { + if err := mount("", tmpdir, "", "", uintptr(unix.MS_PRIVATE), ""); err != nil { return "", err } return tmpdir, nil @@ -206,13 +217,18 @@ func mountCmd(cmd configs.Command) error { command.Env = cmd.Env command.Dir = cmd.Dir if out, err := command.CombinedOutput(); err != nil { - return fmt.Errorf("%#v failed: %s: %v", cmd, string(out), err) + return fmt.Errorf("%#v failed: %s: %w", cmd, string(out), err) } return nil } -func prepareBindMount(m *configs.Mount, rootfs string) error { - stat, err := os.Stat(m.Source) +func prepareBindMount(m *configs.Mount, rootfs string, mountFd *int) error { + source := m.Source + if mountFd != nil { + source = "/proc/self/fd/" + strconv.Itoa(*mountFd) + } + + stat, err := os.Stat(source) if err != nil { // error out if the source of a bind mount does not exist as we will be // unable to bind anything to it. @@ -226,7 +242,7 @@ func prepareBindMount(m *configs.Mount, rootfs string) error { if dest, err = securejoin.SecureJoin(rootfs, m.Destination); err != nil { return err } - if err := checkProcMount(rootfs, dest, m.Source); err != nil { + if err := checkProcMount(rootfs, dest, source); err != nil { return err } if err := createIfNotExists(dest, stat.IsDir()); err != nil { @@ -256,9 +272,11 @@ func mountCgroupV1(m *configs.Mount, c *mountConfig) error { Data: "mode=755", PropagationFlags: m.PropagationFlags, } + if err := mountToRootfs(tmpfs, c); err != nil { return err } + for _, b := range binds { if c.cgroupns { subsystemPath := filepath.Join(c.root, b.Destination) @@ -278,7 +296,7 @@ func mountCgroupV1(m *configs.Mount, c *mountConfig) error { data = cgroups.CgroupNamePrefix + data source = "systemd" } - return unix.Mount(source, procfd, "cgroup", uintptr(flags), data) + return mount(source, b.Destination, procfd, "cgroup", uintptr(flags), data) }); err != nil { return err } @@ -310,9 +328,9 @@ func mountCgroupV2(m *configs.Mount, c *mountConfig) error { return err } return utils.WithProcfd(c.root, m.Destination, func(procfd string) error { - if err := unix.Mount(m.Source, procfd, "cgroup2", uintptr(m.Flags), m.Data); err != nil { + if err := mount(m.Source, m.Destination, procfd, "cgroup2", uintptr(m.Flags), m.Data); err != nil { // when we are in UserNS but CgroupNS is not unshared, we cannot mount cgroup2 (#2158) - if err == unix.EPERM || err == unix.EBUSY { + if errors.Is(err, unix.EPERM) || errors.Is(err, unix.EBUSY) { src := fs2.UnifiedMountpoint if c.cgroupns && c.cgroup2Path != "" { // Emulate cgroupns by bind-mounting @@ -320,8 +338,8 @@ func mountCgroupV2(m *configs.Mount, c *mountConfig) error { // the whole /sys/fs/cgroup. src = c.cgroup2Path } - err = unix.Mount(src, procfd, "", uintptr(m.Flags)|unix.MS_BIND, "") - if err == unix.ENOENT && c.rootlessCgroups { + err = mount(src, m.Destination, procfd, "", uintptr(m.Flags)|unix.MS_BIND, "") + if c.rootlessCgroups && errors.Is(err, unix.ENOENT) { err = nil } } @@ -335,12 +353,12 @@ func doTmpfsCopyUp(m *configs.Mount, rootfs, mountLabel string) (Err error) { // Set up a scratch dir for the tmpfs on the host. tmpdir, err := prepareTmp("/tmp") if err != nil { - return newSystemErrorWithCause(err, "tmpcopyup: failed to setup tmpdir") + return fmt.Errorf("tmpcopyup: failed to setup tmpdir: %w", err) } defer cleanupTmp(tmpdir) - tmpDir, err := ioutil.TempDir(tmpdir, "runctmpdir") + tmpDir, err := os.MkdirTemp(tmpdir, "runctmpdir") if err != nil { - return newSystemErrorWithCause(err, "tmpcopyup: failed to create tmpdir") + return fmt.Errorf("tmpcopyup: failed to create tmpdir: %w", err) } defer os.RemoveAll(tmpDir) @@ -348,15 +366,15 @@ func doTmpfsCopyUp(m *configs.Mount, rootfs, mountLabel string) (Err error) { // m.Destination since we are going to mount *on the host*. oldDest := m.Destination m.Destination = tmpDir - err = mountPropagate(m, "/", mountLabel) + err = mountPropagate(m, "/", mountLabel, nil) m.Destination = oldDest if err != nil { return err } defer func() { if Err != nil { - if err := unix.Unmount(tmpDir, unix.MNT_DETACH); err != nil { - logrus.Warnf("tmpcopyup: failed to unmount tmpdir on error: %v", err) + if err := unmount(tmpDir, unix.MNT_DETACH); err != nil { + logrus.Warnf("tmpcopyup: %v", err) } } }() @@ -369,8 +387,8 @@ func doTmpfsCopyUp(m *configs.Mount, rootfs, mountLabel string) (Err error) { return fmt.Errorf("tmpcopyup: failed to copy %s to %s (%s): %w", m.Destination, procfd, tmpDir, err) } // Now move the mount into the container. - if err := unix.Mount(tmpDir, procfd, "", unix.MS_MOVE, ""); err != nil { - return fmt.Errorf("tmpcopyup: failed to move mount %s to %s (%s): %w", tmpDir, procfd, m.Destination, err) + if err := mount(tmpDir, m.Destination, procfd, "", unix.MS_MOVE, ""); err != nil { + return fmt.Errorf("tmpcopyup: failed to move mount: %w", err) } return nil }) @@ -379,6 +397,7 @@ func doTmpfsCopyUp(m *configs.Mount, rootfs, mountLabel string) (Err error) { func mountToRootfs(m *configs.Mount, c *mountConfig) error { rootfs := c.root mountLabel := c.label + mountFd := c.fd dest, err := securejoin.SecureJoin(rootfs, m.Destination) if err != nil { return err @@ -402,12 +421,12 @@ func mountToRootfs(m *configs.Mount, c *mountConfig) error { return err } // Selinux kernels do not support labeling of /proc or /sys - return mountPropagate(m, rootfs, "") + return mountPropagate(m, rootfs, "", nil) case "mqueue": if err := os.MkdirAll(dest, 0o755); err != nil { return err } - if err := mountPropagate(m, rootfs, ""); err != nil { + if err := mountPropagate(m, rootfs, "", nil); err != nil { return err } return label.SetFileLabel(dest, mountLabel) @@ -422,11 +441,13 @@ func mountToRootfs(m *configs.Mount, c *mountConfig) error { if m.Extensions&configs.EXT_COPYUP == configs.EXT_COPYUP { err = doTmpfsCopyUp(m, rootfs, mountLabel) } else { - err = mountPropagate(m, rootfs, mountLabel) + err = mountPropagate(m, rootfs, mountLabel, nil) } + if err != nil { return err } + if stat != nil { if err = os.Chmod(dest, stat.Mode()); err != nil { return err @@ -434,17 +455,17 @@ func mountToRootfs(m *configs.Mount, c *mountConfig) error { } return nil case "bind": - if err := prepareBindMount(m, rootfs); err != nil { + if err := prepareBindMount(m, rootfs, mountFd); err != nil { return err } - if err := mountPropagate(m, rootfs, mountLabel); err != nil { + if err := mountPropagate(m, rootfs, mountLabel, mountFd); err != nil { return err } // bind mount won't change mount options, we need remount to make mount options effective. // first check that we have non-default options required before attempting a remount if m.Flags&^(unix.MS_REC|unix.MS_REMOUNT|unix.MS_BIND) != 0 { // only remount if unique mount options are set - if err := remount(m, rootfs); err != nil { + if err := remount(m, rootfs, mountFd); err != nil { return err } } @@ -470,7 +491,10 @@ func mountToRootfs(m *configs.Mount, c *mountConfig) error { if err := os.MkdirAll(dest, 0o755); err != nil { return err } - return mountPropagate(m, rootfs, mountLabel) + return mountPropagate(m, rootfs, mountLabel, mountFd) + } + if err := setRecAttr(m, rootfs); err != nil { + return err } return nil } @@ -570,7 +594,7 @@ func checkProcMount(rootfs, dest, source string) error { func isProc(path string) (bool, error) { var s unix.Statfs_t if err := unix.Statfs(path, &s); err != nil { - return false, err + return false, &os.PathError{Op: "statfs", Path: path, Err: err} } return s.Type == unix.PROC_SUPER_MAGIC, nil } @@ -593,7 +617,7 @@ func setupDevSymlinks(rootfs string) error { dst = filepath.Join(rootfs, link[1]) ) if err := os.Symlink(src, dst); err != nil && !os.IsExist(err) { - return fmt.Errorf("symlink %s %s %s", src, dst, err) + return err } } return nil @@ -607,20 +631,24 @@ func reOpenDevNull() error { var stat, devNullStat unix.Stat_t file, err := os.OpenFile("/dev/null", os.O_RDWR, 0) if err != nil { - return fmt.Errorf("Failed to open /dev/null - %s", err) + return err } defer file.Close() //nolint: errcheck if err := unix.Fstat(int(file.Fd()), &devNullStat); err != nil { - return err + return &os.PathError{Op: "fstat", Path: file.Name(), Err: err} } for fd := 0; fd < 3; fd++ { if err := unix.Fstat(fd, &stat); err != nil { - return err + return &os.PathError{Op: "fstat", Path: "fd " + strconv.Itoa(fd), Err: err} } if stat.Rdev == devNullStat.Rdev { // Close and re-open the fd. if err := unix.Dup3(int(file.Fd()), fd, 0); err != nil { - return err + return &os.PathError{ + Op: "dup3", + Path: "fd " + strconv.Itoa(int(file.Fd())), + Err: err, + } } } } @@ -658,7 +686,7 @@ func bindMountDeviceNode(rootfs, dest string, node *devices.Device) error { _ = f.Close() } return utils.WithProcfd(rootfs, dest, func(procfd string) error { - return unix.Mount(node.Path, procfd, "bind", unix.MS_BIND, "") + return mount(node.Path, dest, procfd, "bind", unix.MS_BIND, "") }) } @@ -679,9 +707,9 @@ func createDeviceNode(rootfs string, node *devices.Device, bind bool) error { return bindMountDeviceNode(rootfs, dest, node) } if err := mknodDevice(dest, node); err != nil { - if os.IsExist(err) { + if errors.Is(err, os.ErrExist) { return nil - } else if os.IsPermission(err) { + } else if errors.Is(err, os.ErrPermission) { return bindMountDeviceNode(rootfs, dest, node) } return err @@ -706,9 +734,9 @@ func mknodDevice(dest string, node *devices.Device) error { return err } if err := unix.Mknod(dest, uint32(fileMode), int(dev)); err != nil { - return err + return &os.PathError{Op: "mknod", Path: dest, Err: err} } - return unix.Chown(dest, int(node.Uid), int(node.Gid)) + return os.Chown(dest, int(node.Uid), int(node.Gid)) } // Get the parent mount point of directory passed in as argument. Also return @@ -755,7 +783,7 @@ func rootfsParentMountPrivate(rootfs string) error { // shared. Secondly when we bind mount rootfs it will propagate to // parent namespace and we don't want that to happen. if sharedMount { - return unix.Mount("", parentMount, "", unix.MS_PRIVATE, "") + return mount("", parentMount, "", "", unix.MS_PRIVATE, "") } return nil @@ -766,7 +794,7 @@ func prepareRoot(config *configs.Config) error { if config.RootPropagation != 0 { flag = config.RootPropagation } - if err := unix.Mount("", "/", "", uintptr(flag), ""); err != nil { + if err := mount("", "/", "", "", uintptr(flag), ""); err != nil { return err } @@ -777,13 +805,13 @@ func prepareRoot(config *configs.Config) error { return err } - return unix.Mount(config.Rootfs, config.Rootfs, "bind", unix.MS_BIND|unix.MS_REC, "") + return mount(config.Rootfs, config.Rootfs, "", "bind", unix.MS_BIND|unix.MS_REC, "") } func setReadonly() error { flags := uintptr(unix.MS_BIND | unix.MS_REMOUNT | unix.MS_RDONLY) - err := unix.Mount("", "/", "", flags, "") + err := mount("", "/", "", "", flags, "") if err == nil { return nil } @@ -792,7 +820,7 @@ func setReadonly() error { return &os.PathError{Op: "statfs", Path: "/", Err: err} } flags |= uintptr(s.Flags) - return unix.Mount("", "/", "", flags, "") + return mount("", "/", "", "", flags, "") } func setupPtmx(config *configs.Config) error { @@ -801,7 +829,7 @@ func setupPtmx(config *configs.Config) error { return err } if err := os.Symlink("pts/ptmx", ptmx); err != nil { - return fmt.Errorf("symlink dev ptmx %s", err) + return err } return nil } @@ -817,23 +845,23 @@ func pivotRoot(rootfs string) error { oldroot, err := unix.Open("/", unix.O_DIRECTORY|unix.O_RDONLY, 0) if err != nil { - return err + return &os.PathError{Op: "open", Path: "/", Err: err} } defer unix.Close(oldroot) //nolint: errcheck newroot, err := unix.Open(rootfs, unix.O_DIRECTORY|unix.O_RDONLY, 0) if err != nil { - return err + return &os.PathError{Op: "open", Path: rootfs, Err: err} } defer unix.Close(newroot) //nolint: errcheck // Change to the new root so that the pivot_root actually acts on it. if err := unix.Fchdir(newroot); err != nil { - return err + return &os.PathError{Op: "fchdir", Path: "fd " + strconv.Itoa(newroot), Err: err} } if err := unix.PivotRoot(".", "."); err != nil { - return fmt.Errorf("pivot_root %s", err) + return &os.PathError{Op: "pivot_root", Path: ".", Err: err} } // Currently our "." is oldroot (according to the current kernel code). @@ -842,7 +870,7 @@ func pivotRoot(rootfs string) error { // pivot_root(2). if err := unix.Fchdir(oldroot); err != nil { - return err + return &os.PathError{Op: "fchdir", Path: "fd " + strconv.Itoa(oldroot), Err: err} } // Make oldroot rslave to make sure our unmounts don't propagate to the @@ -850,17 +878,17 @@ func pivotRoot(rootfs string) error { // known to cause issues due to races where we still have a reference to a // mount while a process in the host namespace are trying to operate on // something they think has no mounts (devicemapper in particular). - if err := unix.Mount("", ".", "", unix.MS_SLAVE|unix.MS_REC, ""); err != nil { + if err := mount("", ".", "", "", unix.MS_SLAVE|unix.MS_REC, ""); err != nil { return err } - // Preform the unmount. MNT_DETACH allows us to unmount /proc/self/cwd. - if err := unix.Unmount(".", unix.MNT_DETACH); err != nil { + // Perform the unmount. MNT_DETACH allows us to unmount /proc/self/cwd. + if err := unmount(".", unix.MNT_DETACH); err != nil { return err } // Switch back to our shiny new root. if err := unix.Chdir("/"); err != nil { - return fmt.Errorf("chdir / %s", err) + return &os.PathError{Op: "chdir", Path: "/", Err: err} } return nil } @@ -899,8 +927,8 @@ func msMoveRoot(rootfs string) error { for _, info := range mountinfos { p := info.Mountpoint // Be sure umount events are not propagated to the host. - if err := unix.Mount("", p, "", unix.MS_SLAVE|unix.MS_REC, ""); err != nil { - if err == unix.ENOENT { + if err := mount("", p, "", "", unix.MS_SLAVE|unix.MS_REC, ""); err != nil { + if errors.Is(err, unix.ENOENT) { // If the mountpoint doesn't exist that means that we've // already blasted away some parent directory of the mountpoint // and so we don't care about this error. @@ -908,13 +936,13 @@ func msMoveRoot(rootfs string) error { } return err } - if err := unix.Unmount(p, unix.MNT_DETACH); err != nil { - if err != unix.EINVAL && err != unix.EPERM { + if err := unmount(p, unix.MNT_DETACH); err != nil { + if !errors.Is(err, unix.EINVAL) && !errors.Is(err, unix.EPERM) { return err } else { // If we have not privileges for umounting (e.g. rootless), then // cover the path. - if err := unix.Mount("tmpfs", p, "tmpfs", 0, ""); err != nil { + if err := mount("tmpfs", p, "", "tmpfs", 0, ""); err != nil { return err } } @@ -922,7 +950,7 @@ func msMoveRoot(rootfs string) error { } // Move the rootfs on top of "/" in our mount namespace. - if err := unix.Mount(rootfs, "/", "", unix.MS_MOVE, ""); err != nil { + if err := mount(rootfs, "/", "", "", unix.MS_MOVE, ""); err != nil { return err } return chroot() @@ -930,9 +958,12 @@ func msMoveRoot(rootfs string) error { func chroot() error { if err := unix.Chroot("."); err != nil { - return err + return &os.PathError{Op: "chroot", Path: ".", Err: err} + } + if err := unix.Chdir("/"); err != nil { + return &os.PathError{Op: "chdir", Path: "/", Err: err} } - return unix.Chdir("/") + return nil } // createIfNotExists creates a file or a directory only if it does not already exist. @@ -957,11 +988,11 @@ func createIfNotExists(path string, isDir bool) error { // readonlyPath will make a path read only. func readonlyPath(path string) error { - if err := unix.Mount(path, path, "", unix.MS_BIND|unix.MS_REC, ""); err != nil { - if os.IsNotExist(err) { + if err := mount(path, path, "", "", unix.MS_BIND|unix.MS_REC, ""); err != nil { + if errors.Is(err, os.ErrNotExist) { return nil } - return &os.PathError{Op: "bind-mount", Path: path, Err: err} + return err } var s unix.Statfs_t @@ -970,8 +1001,8 @@ func readonlyPath(path string) error { } flags := uintptr(s.Flags) & (unix.MS_NOSUID | unix.MS_NODEV | unix.MS_NOEXEC) - if err := unix.Mount(path, path, "", flags|unix.MS_BIND|unix.MS_REMOUNT|unix.MS_RDONLY, ""); err != nil { - return &os.PathError{Op: "bind-mount-ro", Path: path, Err: err} + if err := mount(path, path, "", "", flags|unix.MS_BIND|unix.MS_REMOUNT|unix.MS_RDONLY, ""); err != nil { + return err } return nil @@ -991,14 +1022,12 @@ func remountReadonly(m *configs.Mount) error { // nosuid, etc.). So, let's use that case so that we can do // this re-mount without failing in a userns. flags |= unix.MS_REMOUNT | unix.MS_BIND | unix.MS_RDONLY - if err := unix.Mount("", dest, "", uintptr(flags), ""); err != nil { - switch err { - case unix.EBUSY: + if err := mount("", dest, "", "", uintptr(flags), ""); err != nil { + if errors.Is(err, unix.EBUSY) { time.Sleep(100 * time.Millisecond) continue - default: - return err } + return err } return nil } @@ -1011,9 +1040,9 @@ func remountReadonly(m *configs.Mount) error { // For files, maskPath bind mounts /dev/null over the top of the specified path. // For directories, maskPath mounts read-only tmpfs over the top of the specified path. func maskPath(path string, mountLabel string) error { - if err := unix.Mount("/dev/null", path, "", unix.MS_BIND, ""); err != nil && !os.IsNotExist(err) { - if err == unix.ENOTDIR { - return unix.Mount("tmpfs", path, "tmpfs", unix.MS_RDONLY, label.FormatMountLabel("", mountLabel)) + if err := mount("/dev/null", path, "", "", unix.MS_BIND, ""); err != nil && !errors.Is(err, os.ErrNotExist) { + if errors.Is(err, unix.ENOTDIR) { + return mount("tmpfs", path, "", "tmpfs", unix.MS_RDONLY, label.FormatMountLabel("", mountLabel)) } return err } @@ -1024,33 +1053,38 @@ func maskPath(path string, mountLabel string) error { // For e.g. net.ipv4.ip_forward translated to /proc/sys/net/ipv4/ip_forward. func writeSystemProperty(key, value string) error { keyPath := strings.Replace(key, ".", "/", -1) - return ioutil.WriteFile(path.Join("/proc/sys", keyPath), []byte(value), 0o644) + return os.WriteFile(path.Join("/proc/sys", keyPath), []byte(value), 0o644) } -func remount(m *configs.Mount, rootfs string) error { +func remount(m *configs.Mount, rootfs string, mountFd *int) error { + source := m.Source + if mountFd != nil { + source = "/proc/self/fd/" + strconv.Itoa(*mountFd) + } + return utils.WithProcfd(rootfs, m.Destination, func(procfd string) error { flags := uintptr(m.Flags | unix.MS_REMOUNT) - err := unix.Mount(m.Source, procfd, m.Device, flags, "") + err := mount(source, m.Destination, procfd, m.Device, flags, "") if err == nil { return nil } // Check if the source has ro flag... var s unix.Statfs_t - if err := unix.Statfs(m.Source, &s); err != nil { - return &os.PathError{Op: "statfs", Path: m.Source, Err: err} + if err := unix.Statfs(source, &s); err != nil { + return &os.PathError{Op: "statfs", Path: source, Err: err} } if s.Flags&unix.MS_RDONLY != unix.MS_RDONLY { return err } // ... and retry the mount with ro flag set. flags |= unix.MS_RDONLY - return unix.Mount(m.Source, procfd, m.Device, flags, "") + return mount(source, m.Destination, procfd, m.Device, flags, "") }) } // Do the mount operation followed by additional mounts required to take care // of propagation flags. This will always be scoped inside the container rootfs. -func mountPropagate(m *configs.Mount, rootfs string, mountLabel string) error { +func mountPropagate(m *configs.Mount, rootfs string, mountLabel string, mountFd *int) error { var ( data = label.FormatMountLabel(m.Data, mountLabel) flags = m.Flags @@ -1067,17 +1101,22 @@ func mountPropagate(m *configs.Mount, rootfs string, mountLabel string) error { // mutating underneath us, we verify that we are actually going to mount // inside the container with WithProcfd() -- mounting through a procfd // mounts on the target. + source := m.Source + if mountFd != nil { + source = "/proc/self/fd/" + strconv.Itoa(*mountFd) + } + if err := utils.WithProcfd(rootfs, m.Destination, func(procfd string) error { - return unix.Mount(m.Source, procfd, m.Device, uintptr(flags), data) + return mount(source, m.Destination, procfd, m.Device, uintptr(flags), data) }); err != nil { - return fmt.Errorf("mount through procfd: %w", err) + return err } // We have to apply mount propagation flags in a separate WithProcfd() call // because the previous call invalidates the passed procfd -- the mount // target needs to be re-opened. if err := utils.WithProcfd(rootfs, m.Destination, func(procfd string) error { for _, pflag := range m.PropagationFlags { - if err := unix.Mount("", procfd, "", uintptr(pflag), ""); err != nil { + if err := mount("", m.Destination, procfd, "", uintptr(pflag), ""); err != nil { return err } } @@ -1087,3 +1126,12 @@ func mountPropagate(m *configs.Mount, rootfs string, mountLabel string) error { } return nil } + +func setRecAttr(m *configs.Mount, rootfs string) error { + if m.RecAttr == nil { + return nil + } + return utils.WithProcfd(rootfs, m.Destination, func(procfd string) error { + return unix.MountSetattr(-1, procfd, unix.AT_RECURSIVE, m.RecAttr) + }) +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go index b54b7eead3b7d..d0c9bb71fb0ef 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go @@ -2,6 +2,7 @@ package seccomp import ( "fmt" + "sort" "github.com/opencontainers/runc/libcontainer/configs" ) @@ -16,13 +17,36 @@ var operators = map[string]configs.Operator{ "SCMP_CMP_MASKED_EQ": configs.MaskEqualTo, } +// KnownOperators returns the list of the known operations. +// Used by `runc features`. +func KnownOperators() []string { + var res []string + for k := range operators { + res = append(res, k) + } + sort.Strings(res) + return res +} + var actions = map[string]configs.Action{ - "SCMP_ACT_KILL": configs.Kill, - "SCMP_ACT_ERRNO": configs.Errno, - "SCMP_ACT_TRAP": configs.Trap, - "SCMP_ACT_ALLOW": configs.Allow, - "SCMP_ACT_TRACE": configs.Trace, - "SCMP_ACT_LOG": configs.Log, + "SCMP_ACT_KILL": configs.Kill, + "SCMP_ACT_ERRNO": configs.Errno, + "SCMP_ACT_TRAP": configs.Trap, + "SCMP_ACT_ALLOW": configs.Allow, + "SCMP_ACT_TRACE": configs.Trace, + "SCMP_ACT_LOG": configs.Log, + "SCMP_ACT_NOTIFY": configs.Notify, +} + +// KnownActions returns the list of the known actions. +// Used by `runc features`. +func KnownActions() []string { + var res []string + for k := range actions { + res = append(res, k) + } + sort.Strings(res) + return res } var archs = map[string]string{ @@ -44,6 +68,17 @@ var archs = map[string]string{ "SCMP_ARCH_S390X": "s390x", } +// KnownArchs returns the list of the known archs. +// Used by `runc features`. +func KnownArchs() []string { + var res []string + for k := range archs { + res = append(res, k) + } + sort.Strings(res) + return res +} + // ConvertStringToOperator converts a string into a Seccomp comparison operator. // Comparison operators use the names they are assigned by Libseccomp's header. // Attempting to convert a string that is not a valid operator results in an @@ -56,9 +91,7 @@ func ConvertStringToOperator(in string) (configs.Operator, error) { } // ConvertStringToAction converts a string into a Seccomp rule match action. -// Actions use the names they are assigned in Libseccomp's header, though some -// (notable, SCMP_ACT_TRACE) are not available in this implementation and will -// return errors. +// Actions use the names they are assigned in Libseccomp's header. // Attempting to convert a string that is not a valid action results in an // error. func ConvertStringToAction(in string) (configs.Action, error) { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/patchbpf/enosys_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/patchbpf/enosys_linux.go index 3c6ef7a4c6a5e..dfb8a0a8e5928 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/patchbpf/enosys_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/patchbpf/enosys_linux.go @@ -1,23 +1,25 @@ -// +build linux,cgo,seccomp +//go:build cgo && seccomp +// +build cgo,seccomp package patchbpf import ( "bytes" "encoding/binary" + "errors" + "fmt" "io" "os" "runtime" "unsafe" - "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/runc/libcontainer/utils" - - "github.com/pkg/errors" libseccomp "github.com/seccomp/libseccomp-golang" "github.com/sirupsen/logrus" "golang.org/x/net/bpf" "golang.org/x/sys/unix" + + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/utils" ) // #cgo pkg-config: libseccomp @@ -41,6 +43,11 @@ const uintptr_t C_SET_MODE_FILTER = SECCOMP_SET_MODE_FILTER; #endif const uintptr_t C_FILTER_FLAG_LOG = SECCOMP_FILTER_FLAG_LOG; +#ifndef SECCOMP_FILTER_FLAG_NEW_LISTENER +# define SECCOMP_FILTER_FLAG_NEW_LISTENER (1UL << 3) +#endif +const uintptr_t C_FILTER_FLAG_NEW_LISTENER = SECCOMP_FILTER_FLAG_NEW_LISTENER; + // We use the AUDIT_ARCH_* values because those are the ones used by the kernel // and SCMP_ARCH_* sometimes has fake values (such as SCMP_ARCH_X32). But we // use so we get libseccomp's fallback definitions of AUDIT_ARCH_*. @@ -85,17 +92,16 @@ loop: // seccomp_export_bpf outputs the program in *host* endian-ness. var insn unix.SockFilter if err := binary.Read(rdr, utils.NativeEndian, &insn); err != nil { - switch err { - case io.EOF: + if errors.Is(err, io.EOF) { // Parsing complete. break loop - case io.ErrUnexpectedEOF: + } + if errors.Is(err, io.ErrUnexpectedEOF) { // Parsing stopped mid-instruction. - return nil, errors.Wrap(err, "program parsing halted mid-instruction") - default: - // All other errors. - return nil, errors.Wrap(err, "parsing instructions") + return nil, fmt.Errorf("program parsing halted mid-instruction: %w", err) } + // All other errors. + return nil, fmt.Errorf("error parsing instructions: %w", err) } program = append(program, bpf.RawInstruction{ Op: insn.Code, @@ -110,7 +116,7 @@ loop: func disassembleFilter(filter *libseccomp.ScmpFilter) ([]bpf.Instruction, error) { rdr, wtr, err := os.Pipe() if err != nil { - return nil, errors.Wrap(err, "creating scratch pipe") + return nil, fmt.Errorf("error creating scratch pipe: %w", err) } defer wtr.Close() defer rdr.Close() @@ -124,23 +130,23 @@ func disassembleFilter(filter *libseccomp.ScmpFilter) ([]bpf.Instruction, error) }() if err := filter.ExportBPF(wtr); err != nil { - return nil, errors.Wrap(err, "exporting BPF") + return nil, fmt.Errorf("error exporting BPF: %w", err) } // Close so that the reader actually gets EOF. _ = wtr.Close() if copyErr := <-errChan; copyErr != nil { - return nil, errors.Wrap(copyErr, "reading from ExportBPF pipe") + return nil, fmt.Errorf("error reading from ExportBPF pipe: %w", copyErr) } // Parse the instructions. rawProgram, err := parseProgram(readerBuffer) if err != nil { - return nil, errors.Wrap(err, "parsing generated BPF filter") + return nil, fmt.Errorf("parsing generated BPF filter: %w", err) } program, ok := bpf.Disassemble(rawProgram) if !ok { - return nil, errors.Errorf("could not disassemble entire BPF filter") + return nil, errors.New("could not disassemble entire BPF filter") } return program, nil } @@ -155,7 +161,7 @@ func archToNative(arch libseccomp.ScmpArch) (nativeArch, error) { // Convert to actual native architecture. arch, err := libseccomp.GetNativeArch() if err != nil { - return invalidArch, errors.Wrap(err, "get native arch") + return invalidArch, fmt.Errorf("unable to get native arch: %w", err) } return archToNative(arch) case libseccomp.ArchX86: @@ -192,7 +198,7 @@ func archToNative(arch libseccomp.ScmpArch) (nativeArch, error) { case libseccomp.ArchS390X: return nativeArch(C.C_AUDIT_ARCH_S390X), nil default: - return invalidArch, errors.Errorf("unknown architecture: %v", arch) + return invalidArch, fmt.Errorf("unknown architecture: %v", arch) } } @@ -209,7 +215,7 @@ func findLastSyscalls(config *configs.Seccomp) (lastSyscallMap, error) { for _, ociArch := range config.Architectures { arch, err := libseccomp.GetArchFromString(ociArch) if err != nil { - return nil, errors.Wrap(err, "validating seccomp architecture") + return nil, fmt.Errorf("unable to validate seccomp architecture: %w", err) } // Map native architecture to a real architecture value to avoid @@ -217,7 +223,7 @@ func findLastSyscalls(config *configs.Seccomp) (lastSyscallMap, error) { if arch == libseccomp.ArchNative { nativeArch, err := libseccomp.GetNativeArch() if err != nil { - return nil, errors.Wrap(err, "get native arch") + return nil, fmt.Errorf("unable to get native architecture: %w", err) } arch = nativeArch } @@ -225,7 +231,7 @@ func findLastSyscalls(config *configs.Seccomp) (lastSyscallMap, error) { // Figure out native architecture representation of the architecture. nativeArch, err := archToNative(arch) if err != nil { - return nil, errors.Wrapf(err, "cannot map architecture %v to AUDIT_ARCH_ constant", arch) + return nil, fmt.Errorf("cannot map architecture %v to AUDIT_ARCH_ constant: %w", arch, err) } if _, ok := lastSyscalls[nativeArch]; !ok { @@ -370,7 +376,7 @@ func generateEnosysStub(lastSyscalls lastSyscallMap) ([]bpf.Instruction, error) }, }, sectionTail...) default: - return nil, errors.Errorf("unknown amd64 native architecture %#x", scmpArch) + return nil, fmt.Errorf("unknown amd64 native architecture %#x", scmpArch) } } @@ -378,16 +384,16 @@ func generateEnosysStub(lastSyscalls lastSyscallMap) ([]bpf.Instruction, error) case 2: // x32 and x86_64 are a unique case, we can't handle any others. if uint32(nativeArch) != uint32(C.C_AUDIT_ARCH_X86_64) { - return nil, errors.Errorf("unknown architecture overlap on native arch %#x", nativeArch) + return nil, fmt.Errorf("unknown architecture overlap on native arch %#x", nativeArch) } x32sysno, ok := maxSyscalls[libseccomp.ArchX32] if !ok { - return nil, errors.Errorf("missing %v in overlapping x86_64 arch: %v", libseccomp.ArchX32, maxSyscalls) + return nil, fmt.Errorf("missing %v in overlapping x86_64 arch: %v", libseccomp.ArchX32, maxSyscalls) } x86sysno, ok := maxSyscalls[libseccomp.ArchAMD64] if !ok { - return nil, errors.Errorf("missing %v in overlapping x86_64 arch: %v", libseccomp.ArchAMD64, maxSyscalls) + return nil, fmt.Errorf("missing %v in overlapping x86_64 arch: %v", libseccomp.ArchAMD64, maxSyscalls) } // The x32 ABI indicates that a syscall is being made by an x32 @@ -448,7 +454,7 @@ func generateEnosysStub(lastSyscalls lastSyscallMap) ([]bpf.Instruction, error) }...) } default: - return nil, errors.Errorf("invalid number of architecture overlaps: %v", len(maxSyscalls)) + return nil, fmt.Errorf("invalid number of architecture overlaps: %v", len(maxSyscalls)) } // Prepend this section to the tail. @@ -517,7 +523,7 @@ func generateEnosysStub(lastSyscalls lastSyscallMap) ([]bpf.Instruction, error) func assemble(program []bpf.Instruction) ([]unix.SockFilter, error) { rawProgram, err := bpf.Assemble(program) if err != nil { - return nil, errors.Wrap(err, "assembling program") + return nil, fmt.Errorf("error assembling program: %w", err) } // Convert to []unix.SockFilter for unix.SockFilter. @@ -547,11 +553,11 @@ func generatePatch(config *configs.Seccomp) ([]bpf.Instruction, error) { lastSyscalls, err := findLastSyscalls(config) if err != nil { - return nil, errors.Wrap(err, "finding last syscalls for -ENOSYS stub") + return nil, fmt.Errorf("error finding last syscalls for -ENOSYS stub: %w", err) } stubProgram, err := generateEnosysStub(lastSyscalls) if err != nil { - return nil, errors.Wrap(err, "generating -ENOSYS stub") + return nil, fmt.Errorf("error generating -ENOSYS stub: %w", err) } return stubProgram, nil } @@ -559,12 +565,12 @@ func generatePatch(config *configs.Seccomp) ([]bpf.Instruction, error) { func enosysPatchFilter(config *configs.Seccomp, filter *libseccomp.ScmpFilter) ([]unix.SockFilter, error) { program, err := disassembleFilter(filter) if err != nil { - return nil, errors.Wrap(err, "disassembling original filter") + return nil, fmt.Errorf("error disassembling original filter: %w", err) } patch, err := generatePatch(config) if err != nil { - return nil, errors.Wrap(err, "generating patch for filter") + return nil, fmt.Errorf("error generating patch for filter: %w", err) } fullProgram := append(patch, program...) @@ -576,49 +582,61 @@ func enosysPatchFilter(config *configs.Seccomp, filter *libseccomp.ScmpFilter) ( fprog, err := assemble(fullProgram) if err != nil { - return nil, errors.Wrap(err, "assembling modified filter") + return nil, fmt.Errorf("error assembling modified filter: %w", err) } return fprog, nil } -func filterFlags(filter *libseccomp.ScmpFilter) (flags uint, noNewPrivs bool, err error) { +func filterFlags(config *configs.Seccomp, filter *libseccomp.ScmpFilter) (flags uint, noNewPrivs bool, err error) { // Ignore the error since pre-2.4 libseccomp is treated as API level 0. - apiLevel, _ := libseccomp.GetApi() + apiLevel, _ := libseccomp.GetAPI() noNewPrivs, err = filter.GetNoNewPrivsBit() if err != nil { - return 0, false, errors.Wrap(err, "fetch no_new_privs filter bit") + return 0, false, fmt.Errorf("unable to fetch no_new_privs filter bit: %w", err) } if apiLevel >= 3 { if logBit, err := filter.GetLogBit(); err != nil { - return 0, false, errors.Wrap(err, "fetch SECCOMP_FILTER_FLAG_LOG bit") + return 0, false, fmt.Errorf("unable to fetch SECCOMP_FILTER_FLAG_LOG bit: %w", err) } else if logBit { flags |= uint(C.C_FILTER_FLAG_LOG) } } // TODO: Support seccomp flags not yet added to libseccomp-golang... + + for _, call := range config.Syscalls { + if call.Action == configs.Notify { + flags |= uint(C.C_FILTER_FLAG_NEW_LISTENER) + break + } + } + return } -func sysSeccompSetFilter(flags uint, filter []unix.SockFilter) (err error) { +func sysSeccompSetFilter(flags uint, filter []unix.SockFilter) (fd int, err error) { fprog := unix.SockFprog{ Len: uint16(len(filter)), Filter: &filter[0], } + fd = -1 // only return a valid fd when C_FILTER_FLAG_NEW_LISTENER is set // If no seccomp flags were requested we can use the old-school prctl(2). if flags == 0 { err = unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, uintptr(unsafe.Pointer(&fprog)), 0, 0) } else { - _, _, errno := unix.RawSyscall(unix.SYS_SECCOMP, + fdptr, _, errno := unix.RawSyscall(unix.SYS_SECCOMP, uintptr(C.C_SET_MODE_FILTER), uintptr(flags), uintptr(unsafe.Pointer(&fprog))) if errno != 0 { err = errno } + if flags&uint(C.C_FILTER_FLAG_NEW_LISTENER) != 0 { + fd = int(fdptr) + } } runtime.KeepAlive(filter) runtime.KeepAlive(fprog) @@ -630,17 +648,17 @@ func sysSeccompSetFilter(flags uint, filter []unix.SockFilter) (err error) { // patches said filter to handle -ENOSYS in a much nicer manner than the // default libseccomp default action behaviour, and loads the patched filter // into the kernel for the current process. -func PatchAndLoad(config *configs.Seccomp, filter *libseccomp.ScmpFilter) error { +func PatchAndLoad(config *configs.Seccomp, filter *libseccomp.ScmpFilter) (int, error) { // Generate a patched filter. fprog, err := enosysPatchFilter(config, filter) if err != nil { - return errors.Wrap(err, "patching filter") + return -1, fmt.Errorf("error patching filter: %w", err) } // Get the set of libseccomp flags set. - seccompFlags, noNewPrivs, err := filterFlags(filter) + seccompFlags, noNewPrivs, err := filterFlags(config, filter) if err != nil { - return errors.Wrap(err, "fetch seccomp filter flags") + return -1, fmt.Errorf("unable to fetch seccomp filter flags: %w", err) } // Set no_new_privs if it was requested, though in runc we handle @@ -648,13 +666,15 @@ func PatchAndLoad(config *configs.Seccomp, filter *libseccomp.ScmpFilter) error if noNewPrivs { logrus.Warnf("potentially misconfigured filter -- setting no_new_privs in seccomp path") if err := unix.Prctl(unix.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil { - return errors.Wrap(err, "enable no_new_privs bit") + return -1, fmt.Errorf("error enabling no_new_privs bit: %w", err) } } // Finally, load the filter. - if err := sysSeccompSetFilter(seccompFlags, fprog); err != nil { - return errors.Wrap(err, "loading seccomp filter") + fd, err := sysSeccompSetFilter(seccompFlags, fprog) + if err != nil { + return -1, fmt.Errorf("error loading seccomp filter: %w", err) } - return nil + + return fd, nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/patchbpf/enosys_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/patchbpf/enosys_unsupported.go index 682131e49cc69..d23167ae3571b 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/patchbpf/enosys_unsupported.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/patchbpf/enosys_unsupported.go @@ -1,3 +1,4 @@ +//go:build !linux || !cgo || !seccomp // +build !linux !cgo !seccomp package patchbpf 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 f80118f2c9bc5..f177b7f05f2fd 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go @@ -1,4 +1,5 @@ -// +build linux,cgo,seccomp +//go:build cgo && seccomp +// +build cgo,seccomp package seccomp @@ -6,19 +7,16 @@ import ( "errors" "fmt" - "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/runc/libcontainer/seccomp/patchbpf" - libseccomp "github.com/seccomp/libseccomp-golang" + "github.com/sirupsen/logrus" "golang.org/x/sys/unix" + + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/seccomp/patchbpf" ) var ( - actAllow = libseccomp.ActAllow - actTrap = libseccomp.ActTrap - actKill = libseccomp.ActKill actTrace = libseccomp.ActTrace.SetReturnCode(int16(unix.EPERM)) - actLog = libseccomp.ActLog actErrno = libseccomp.ActErrno.SetReturnCode(int16(unix.EPERM)) ) @@ -27,77 +25,118 @@ const ( syscallMaxArguments int = 6 ) -// Filters given syscalls in a container, preventing them from being used -// Started in the container init process, and carried over to all child processes -// Setns calls, however, require a separate invocation, as they are not children -// of the init until they join the namespace -func InitSeccomp(config *configs.Seccomp) error { +// InitSeccomp installs the seccomp filters to be used in the container as +// specified in config. +// Returns the seccomp file descriptor if any of the filters include a +// SCMP_ACT_NOTIFY action, otherwise returns -1. +func InitSeccomp(config *configs.Seccomp) (int, error) { if config == nil { - return errors.New("cannot initialize Seccomp - nil config passed") + return -1, errors.New("cannot initialize Seccomp - nil config passed") } defaultAction, err := getAction(config.DefaultAction, config.DefaultErrnoRet) if err != nil { - return errors.New("error initializing seccomp - invalid default action") + return -1, errors.New("error initializing seccomp - invalid default action") + } + + // Ignore the error since pre-2.4 libseccomp is treated as API level 0. + apiLevel, _ := libseccomp.GetAPI() + for _, call := range config.Syscalls { + if call.Action == configs.Notify { + if apiLevel < 6 { + return -1, fmt.Errorf("seccomp notify unsupported: API level: got %d, want at least 6. Please try with libseccomp >= 2.5.0 and Linux >= 5.7", apiLevel) + } + + // We can't allow the write syscall to notify to the seccomp agent. + // After InitSeccomp() is called, we need to syncParentSeccomp() to write the seccomp fd plain + // number, so the parent sends it to the seccomp agent. If we use SCMP_ACT_NOTIFY on write, we + // never can write the seccomp fd to the parent and therefore the seccomp agent never receives + // the seccomp fd and runc is hang during initialization. + // + // Note that read()/close(), that are also used in syncParentSeccomp(), _can_ use SCMP_ACT_NOTIFY. + // Because we write the seccomp fd on the pipe to the parent, the parent is able to proceed and + // send the seccomp fd to the agent (it is another process and not subject to the seccomp + // filter). We will be blocked on read()/close() inside syncParentSeccomp() but if the seccomp + // agent allows those syscalls to proceed, initialization works just fine and the agent can + // handle future read()/close() syscalls as it wanted. + if call.Name == "write" { + return -1, errors.New("SCMP_ACT_NOTIFY cannot be used for the write syscall") + } + } + } + + // See comment on why write is not allowed. The same reason applies, as this can mean handling write too. + if defaultAction == libseccomp.ActNotify { + return -1, errors.New("SCMP_ACT_NOTIFY cannot be used as default action") } filter, err := libseccomp.NewFilter(defaultAction) if err != nil { - return fmt.Errorf("error creating filter: %s", err) + return -1, fmt.Errorf("error creating filter: %w", err) } // Add extra architectures for _, arch := range config.Architectures { scmpArch, err := libseccomp.GetArchFromString(arch) if err != nil { - return fmt.Errorf("error validating Seccomp architecture: %s", err) + return -1, fmt.Errorf("error validating Seccomp architecture: %w", err) } if err := filter.AddArch(scmpArch); err != nil { - return fmt.Errorf("error adding architecture to seccomp filter: %s", err) + return -1, fmt.Errorf("error adding architecture to seccomp filter: %w", err) } } // Unset no new privs bit if err := filter.SetNoNewPrivsBit(false); err != nil { - return fmt.Errorf("error setting no new privileges: %s", err) + return -1, fmt.Errorf("error setting no new privileges: %w", err) } // Add a rule for each syscall for _, call := range config.Syscalls { if call == nil { - return errors.New("encountered nil syscall while initializing Seccomp") + return -1, errors.New("encountered nil syscall while initializing Seccomp") } + if err := matchCall(filter, call, defaultAction); err != nil { - return err + return -1, err } } - if err := patchbpf.PatchAndLoad(config, filter); err != nil { - return fmt.Errorf("error loading seccomp filter into kernel: %s", err) + + seccompFd, err := patchbpf.PatchAndLoad(config, filter) + if err != nil { + return -1, fmt.Errorf("error loading seccomp filter into kernel: %w", err) } - return nil + + return seccompFd, nil } // Convert Libcontainer Action to Libseccomp ScmpAction func getAction(act configs.Action, errnoRet *uint) (libseccomp.ScmpAction, error) { switch act { case configs.Kill: - return actKill, nil + return libseccomp.ActKill, nil case configs.Errno: if errnoRet != nil { return libseccomp.ActErrno.SetReturnCode(int16(*errnoRet)), nil } return actErrno, nil case configs.Trap: - return actTrap, nil + return libseccomp.ActTrap, nil case configs.Allow: - return actAllow, nil + return libseccomp.ActAllow, nil case configs.Trace: if errnoRet != nil { return libseccomp.ActTrace.SetReturnCode(int16(*errnoRet)), nil } return actTrace, nil case configs.Log: - return actLog, nil + return libseccomp.ActLog, nil + case configs.Notify: + return libseccomp.ActNotify, nil + case configs.KillThread: + return libseccomp.ActKillThread, nil + case configs.KillProcess: + return libseccomp.ActKillProcess, nil default: return libseccomp.ActInvalid, errors.New("invalid action, cannot use in rule") } @@ -162,17 +201,18 @@ func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall, defAct libs return nil } - // If we can't resolve the syscall, assume it's not supported on this kernel - // Ignore it, don't error out + // If we can't resolve the syscall, assume it is not supported + // by this kernel. Warn about it, don't error out. callNum, err := libseccomp.GetSyscallFromName(call.Name) if err != nil { + logrus.Debugf("unknown seccomp syscall %q ignored", call.Name) return nil } // Unconditional match - just add the rule if len(call.Args) == 0 { if err := filter.AddRule(callNum, callAct); err != nil { - return fmt.Errorf("error adding seccomp filter rule for syscall %s: %s", call.Name, err) + return fmt.Errorf("error adding seccomp filter rule for syscall %s: %w", call.Name, err) } } else { // If two or more arguments have the same condition, @@ -183,7 +223,7 @@ func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall, defAct libs for _, cond := range call.Args { newCond, err := getCondition(cond) if err != nil { - return fmt.Errorf("error creating seccomp syscall condition for syscall %s: %s", call.Name, err) + return fmt.Errorf("error creating seccomp syscall condition for syscall %s: %w", call.Name, err) } argCounts[cond.Index] += 1 @@ -206,14 +246,14 @@ func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall, defAct libs condArr := []libseccomp.ScmpCondition{cond} if err := filter.AddRuleConditional(callNum, callAct, condArr); err != nil { - return fmt.Errorf("error adding seccomp rule for syscall %s: %s", call.Name, err) + return fmt.Errorf("error adding seccomp rule for syscall %s: %w", call.Name, err) } } } else { // No conditions share same argument // Use new, proper behavior if err := filter.AddRuleConditional(callNum, callAct, conditions); err != nil { - return fmt.Errorf("error adding seccomp rule for syscall %s: %s", call.Name, err) + return fmt.Errorf("error adding seccomp rule for syscall %s: %w", call.Name, err) } } } @@ -225,3 +265,6 @@ func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall, defAct libs func Version() (uint, uint, uint) { return libseccomp.GetLibraryVersion() } + +// Enabled is true if seccomp support is compiled in. +const Enabled = true diff --git a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_unsupported.go index 8b7973e9a13bc..be2b324e057e1 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_unsupported.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_unsupported.go @@ -1,3 +1,4 @@ +//go:build !linux || !cgo || !seccomp // +build !linux !cgo !seccomp package seccomp @@ -11,14 +12,17 @@ import ( var ErrSeccompNotEnabled = errors.New("seccomp: config provided but seccomp not supported") // InitSeccomp does nothing because seccomp is not supported. -func InitSeccomp(config *configs.Seccomp) error { +func InitSeccomp(config *configs.Seccomp) (int, error) { if config != nil { - return ErrSeccompNotEnabled + return -1, ErrSeccompNotEnabled } - return nil + return -1, nil } // Version returns major, minor, and micro. func Version() (uint, uint, uint) { return 0, 0, 0 } + +// Enabled is true if seccomp support is compiled in. +const Enabled = false diff --git a/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go index 2d7e5814e8af8..09ab552b3d125 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go @@ -1,19 +1,19 @@ -// +build linux - package libcontainer import ( + "errors" + "fmt" "os" - "runtime" + "strconv" + + "github.com/opencontainers/selinux/go-selinux" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" "github.com/opencontainers/runc/libcontainer/apparmor" "github.com/opencontainers/runc/libcontainer/keys" "github.com/opencontainers/runc/libcontainer/seccomp" "github.com/opencontainers/runc/libcontainer/system" - "github.com/opencontainers/selinux/go-selinux" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" ) // linuxSetnsInit performs the container's initialization for running a new process @@ -30,9 +30,6 @@ func (l *linuxSetnsInit) getSessionRingName() string { } func (l *linuxSetnsInit) Init() error { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - if !l.config.Config.NoNewKeyring { if err := selinux.SetKeyLabel(l.config.ProcessLabel); err != nil { return err @@ -44,8 +41,8 @@ func (l *linuxSetnsInit) Init() error { // don't bail on ENOSYS. // // TODO(cyphar): And we should have logging here too. - if errors.Cause(err) != unix.ENOSYS { - return errors.Wrap(err, "join session keyring") + if !errors.Is(err, unix.ENOSYS) { + return fmt.Errorf("unable to join session keyring: %w", err) } } } @@ -70,7 +67,12 @@ func (l *linuxSetnsInit) Init() error { // do this before dropping capabilities; otherwise do it as late as possible // just before execve so as few syscalls take place after it as possible. if l.config.Config.Seccomp != nil && !l.config.NoNewPrivileges { - if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil { + seccompFd, err := seccomp.InitSeccomp(l.config.Config.Seccomp) + if err != nil { + return err + } + + if err := syncParentSeccomp(l.pipe, seccompFd); err != nil { return err } } @@ -84,14 +86,19 @@ func (l *linuxSetnsInit) Init() error { // place afterward (reducing the amount of syscalls that users need to // enable in their seccomp profiles). if l.config.Config.Seccomp != nil && l.config.NoNewPrivileges { - if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil { - return newSystemErrorWithCause(err, "init seccomp") + seccompFd, err := seccomp.InitSeccomp(l.config.Config.Seccomp) + if err != nil { + return fmt.Errorf("unable to init seccomp: %w", err) + } + + if err := syncParentSeccomp(l.pipe, seccompFd); err != nil { + return err } } logrus.Debugf("setns_init: about to exec") // Close the log pipe fd so the parent's ForwardLogs can exit. if err := unix.Close(l.logFd); err != nil { - return newSystemErrorWithCause(err, "closing log pipe fd") + return &os.PathError{Op: "close log pipe", Path: "fd " + strconv.Itoa(l.logFd), Err: err} } return system.Execv(l.config.Args[0], l.config.Args[0:], os.Environ()) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go b/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go deleted file mode 100644 index bfb89157b46f4..0000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go +++ /dev/null @@ -1,27 +0,0 @@ -package stacktrace - -import "runtime" - -// Capture captures a stacktrace for the current calling go program -// -// skip is the number of frames to skip -func Capture(userSkip int) Stacktrace { - var ( - skip = userSkip + 1 // add one for our own function - frames []Frame - prevPc uintptr - ) - for i := skip; ; i++ { - pc, file, line, ok := runtime.Caller(i) - // detect if caller is repeated to avoid loop, gccgo - // currently runs into a loop without this check - if !ok || pc == prevPc { - break - } - frames = append(frames, NewFrame(pc, file, line)) - prevPc = pc - } - return Stacktrace{ - Frames: frames, - } -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/frame.go b/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/frame.go deleted file mode 100644 index 0d590d9a542b2..0000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/frame.go +++ /dev/null @@ -1,38 +0,0 @@ -package stacktrace - -import ( - "path/filepath" - "runtime" - "strings" -) - -// NewFrame returns a new stack frame for the provided information -func NewFrame(pc uintptr, file string, line int) Frame { - fn := runtime.FuncForPC(pc) - if fn == nil { - return Frame{} - } - pack, name := parseFunctionName(fn.Name()) - return Frame{ - Line: line, - File: filepath.Base(file), - Package: pack, - Function: name, - } -} - -func parseFunctionName(name string) (string, string) { - i := strings.LastIndex(name, ".") - if i == -1 { - return "", name - } - return name[:i], name[i+1:] -} - -// Frame contains all the information for a stack frame within a go program -type Frame struct { - File string - Function string - Package string - Line int -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/stacktrace.go b/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/stacktrace.go deleted file mode 100644 index 5e8b58d2d28b5..0000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/stacktrace.go +++ /dev/null @@ -1,5 +0,0 @@ -package stacktrace - -type Stacktrace struct { - Frames []Frame -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go index 98c4860541e97..585a04fa08060 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go @@ -1,23 +1,22 @@ -// +build linux - package libcontainer import ( + "errors" + "fmt" "os" "os/exec" - "runtime" "strconv" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/selinux/go-selinux" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" + "github.com/opencontainers/runc/libcontainer/apparmor" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/keys" "github.com/opencontainers/runc/libcontainer/seccomp" "github.com/opencontainers/runc/libcontainer/system" - "github.com/opencontainers/runtime-spec/specs-go" - "github.com/opencontainers/selinux/go-selinux" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" ) type linuxStandardInit struct { @@ -26,6 +25,7 @@ type linuxStandardInit struct { parentPid int fifoFd int logFd int + mountFds []int config *initConfig } @@ -46,8 +46,6 @@ func (l *linuxStandardInit) getSessionRingParams() (string, uint32, uint32) { } func (l *linuxStandardInit) Init() error { - runtime.LockOSThread() - defer runtime.UnlockOSThread() if !l.config.Config.NoNewKeyring { if err := selinux.SetKeyLabel(l.config.ProcessLabel); err != nil { return err @@ -65,15 +63,15 @@ func (l *linuxStandardInit) Init() error { // // TODO(cyphar): Log this so people know what's going on, once we // have proper logging in 'runc init'. - if errors.Cause(err) != unix.ENOSYS { - return errors.Wrap(err, "join session keyring") + if !errors.Is(err, unix.ENOSYS) { + return fmt.Errorf("unable to join session keyring: %w", err) } } else { - // Make session keyring searcheable. If we've gotten this far we + // Make session keyring searchable. If we've gotten this far we // bail on any error -- we don't want to have a keyring with bad // permissions. if err := keys.ModKeyringPerm(sessKeyId, keepperms, newperms); err != nil { - return errors.Wrap(err, "mod keyring permissions") + return fmt.Errorf("unable to mod keyring permissions: %w", err) } } } @@ -87,9 +85,23 @@ func (l *linuxStandardInit) Init() error { // initialises the labeling system selinux.GetEnabled() - if err := prepareRootfs(l.pipe, l.config); err != nil { + + // We don't need the mountFds after prepareRootfs() nor if it fails. + err := prepareRootfs(l.pipe, l.config, l.mountFds) + for _, m := range l.mountFds { + if m == -1 { + continue + } + + if err := unix.Close(m); err != nil { + return fmt.Errorf("Unable to close mountFds fds: %w", err) + } + } + + if err != nil { return err } + // Set up the console. This has to be done *before* we finalize the rootfs, // but *after* we've given the user the chance to set up all of the mounts // they wanted. @@ -98,7 +110,7 @@ func (l *linuxStandardInit) Init() error { return err } if err := system.Setctty(); err != nil { - return errors.Wrap(err, "setctty") + return &os.SyscallError{Syscall: "ioctl(setctty)", Err: err} } } @@ -111,52 +123,57 @@ func (l *linuxStandardInit) Init() error { if hostname := l.config.Config.Hostname; hostname != "" { if err := unix.Sethostname([]byte(hostname)); err != nil { - return errors.Wrap(err, "sethostname") + return &os.SyscallError{Syscall: "sethostname", Err: err} } } if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil { - return errors.Wrap(err, "apply apparmor profile") + return fmt.Errorf("unable to apply apparmor profile: %w", err) } for key, value := range l.config.Config.Sysctl { if err := writeSystemProperty(key, value); err != nil { - return errors.Wrapf(err, "write sysctl key %s", key) + return err } } for _, path := range l.config.Config.ReadonlyPaths { if err := readonlyPath(path); err != nil { - return errors.Wrapf(err, "readonly path %s", path) + return fmt.Errorf("can't make %q read-only: %w", path, err) } } for _, path := range l.config.Config.MaskPaths { if err := maskPath(path, l.config.Config.MountLabel); err != nil { - return errors.Wrapf(err, "mask path %s", path) + return fmt.Errorf("can't mask path %s: %w", path, err) } } pdeath, err := system.GetParentDeathSignal() if err != nil { - return errors.Wrap(err, "get pdeath signal") + return fmt.Errorf("can't get pdeath signal: %w", err) } if l.config.NoNewPrivileges { if err := unix.Prctl(unix.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil { - return errors.Wrap(err, "set nonewprivileges") + return &os.SyscallError{Syscall: "prctl(SET_NO_NEW_PRIVS)", Err: err} } } // Tell our parent that we're ready to Execv. This must be done before the // Seccomp rules have been applied, because we need to be able to read and // write to a socket. if err := syncParentReady(l.pipe); err != nil { - return errors.Wrap(err, "sync ready") + return fmt.Errorf("sync ready: %w", err) } if err := selinux.SetExecLabel(l.config.ProcessLabel); err != nil { - return errors.Wrap(err, "set process label") + return fmt.Errorf("can't set process label: %w", err) } defer selinux.SetExecLabel("") //nolint: errcheck // Without NoNewPrivileges seccomp is a privileged operation, so we need to // do this before dropping capabilities; otherwise do it as late as possible // just before execve so as few syscalls take place after it as possible. if l.config.Config.Seccomp != nil && !l.config.NoNewPrivileges { - if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil { + seccompFd, err := seccomp.InitSeccomp(l.config.Config.Seccomp) + if err != nil { + return err + } + + if err := syncParentSeccomp(l.pipe, seccompFd); err != nil { return err } } @@ -166,7 +183,7 @@ func (l *linuxStandardInit) Init() error { // finalizeNamespace can change user/group which clears the parent death // signal, so we restore it here. if err := pdeath.Restore(); err != nil { - return errors.Wrap(err, "restore pdeath signal") + return fmt.Errorf("can't restore pdeath signal: %w", err) } // Compare the parent from the initial start of the init process and make // sure that it did not change. if the parent changes that means it died @@ -181,26 +198,43 @@ func (l *linuxStandardInit) Init() error { if err != nil { return err } + // Set seccomp as close to execve as possible, so as few syscalls take + // place afterward (reducing the amount of syscalls that users need to + // enable in their seccomp profiles). However, this needs to be done + // before closing the pipe since we need it to pass the seccompFd to + // the parent. + if l.config.Config.Seccomp != nil && l.config.NoNewPrivileges { + seccompFd, err := seccomp.InitSeccomp(l.config.Config.Seccomp) + if err != nil { + return fmt.Errorf("unable to init seccomp: %w", err) + } + + if err := syncParentSeccomp(l.pipe, seccompFd); err != nil { + return err + } + } // Close the pipe to signal that we have completed our init. logrus.Debugf("init: closing the pipe to signal completion") _ = l.pipe.Close() // Close the log pipe fd so the parent's ForwardLogs can exit. if err := unix.Close(l.logFd); err != nil { - return newSystemErrorWithCause(err, "closing log pipe fd") + return &os.PathError{Op: "close log pipe", Path: "fd " + strconv.Itoa(l.logFd), Err: err} } // Wait for the FIFO to be opened on the other side before exec-ing the // user process. We open it through /proc/self/fd/$fd, because the fd that // was given to us was an O_PATH fd to the fifo itself. Linux allows us to // re-open an O_PATH fd through /proc. - fd, err := unix.Open("/proc/self/fd/"+strconv.Itoa(l.fifoFd), unix.O_WRONLY|unix.O_CLOEXEC, 0) + fifoPath := "/proc/self/fd/" + strconv.Itoa(l.fifoFd) + fd, err := unix.Open(fifoPath, unix.O_WRONLY|unix.O_CLOEXEC, 0) if err != nil { - return newSystemErrorWithCause(err, "open exec fifo") + return &os.PathError{Op: "open exec fifo", Path: fifoPath, Err: err} } if _, err := unix.Write(fd, []byte("0")); err != nil { - return newSystemErrorWithCause(err, "write 0 exec fifo") + return &os.PathError{Op: "write exec fifo", Path: fifoPath, Err: err} } + // Close the O_PATH fifofd fd before exec because the kernel resets // dumpable in the wrong order. This has been fixed in newer kernels, but // we keep this to ensure CVE-2016-9962 doesn't re-emerge on older kernels. @@ -208,14 +242,6 @@ func (l *linuxStandardInit) Init() error { // since been resolved. // https://github.com/torvalds/linux/blob/v4.9/fs/exec.c#L1290-L1318 _ = unix.Close(l.fifoFd) - // Set seccomp as close to execve as possible, so as few syscalls take - // place afterward (reducing the amount of syscalls that users need to - // enable in their seccomp profiles). - if l.config.Config.Seccomp != nil && l.config.NoNewPrivileges { - if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil { - return newSystemErrorWithCause(err, "init seccomp") - } - } s := l.config.SpecState s.Pid = unix.Getpid() @@ -224,8 +250,5 @@ func (l *linuxStandardInit) Init() error { return err } - if err := system.Exec(name, l.config.Args[0:], os.Environ()); err != nil { - return newSystemErrorWithCause(err, "exec user process") - } - return nil + return system.Exec(name, l.config.Args[0:], os.Environ()) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go index 43c040c8573eb..aa6259b157d49 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go @@ -1,5 +1,3 @@ -// +build linux - package libcontainer import ( @@ -117,7 +115,7 @@ func (r *runningState) transition(s containerState) error { switch s.(type) { case *stoppedState: if r.c.runType() == Running { - return newGenericError(fmt.Errorf("container still running"), ContainerNotStopped) + return ErrRunning } r.c.state = s return nil @@ -132,7 +130,7 @@ func (r *runningState) transition(s containerState) error { func (r *runningState) destroy() error { if r.c.runType() == Running { - return newGenericError(fmt.Errorf("container is not destroyed"), ContainerNotStopped) + return ErrRunning } return destroy(r.c) } @@ -190,7 +188,7 @@ func (p *pausedState) destroy() error { } return destroy(p.c) } - return newGenericError(fmt.Errorf("container is paused"), ContainerPaused) + return ErrPaused } // restoredState is the same as the running state but also has associated checkpoint diff --git a/vendor/github.com/opencontainers/runc/libcontainer/sync.go b/vendor/github.com/opencontainers/runc/libcontainer/sync.go index ac88ad22a8ff6..c9a23ef3a760d 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/sync.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/sync.go @@ -13,7 +13,7 @@ type syncType string // Constants that are used for synchronisation between the parent and child // during container setup. They come in pairs (with procError being a generic -// response which is followed by a &genericError). +// response which is followed by an &initError). // // [ child ] <-> [ parent ] // @@ -22,40 +22,65 @@ type syncType string // // procReady --> [final setup] // <-- procRun +// +// procSeccomp --> [pick up seccomp fd with pidfd_getfd()] +// <-- procSeccompDone const ( - procError syncType = "procError" - procReady syncType = "procReady" - procRun syncType = "procRun" - procHooks syncType = "procHooks" - procResume syncType = "procResume" + procError syncType = "procError" + procReady syncType = "procReady" + procRun syncType = "procRun" + procHooks syncType = "procHooks" + procResume syncType = "procResume" + procSeccomp syncType = "procSeccomp" + procSeccompDone syncType = "procSeccompDone" ) type syncT struct { Type syncType `json:"type"` + Fd int `json:"fd"` +} + +// initError is used to wrap errors for passing them via JSON, +// as encoding/json can't unmarshal into error type. +type initError struct { + Message string `json:"message,omitempty"` +} + +func (i initError) Error() string { + return i.Message } // writeSync is used to write to a synchronisation pipe. An error is returned // if there was a problem writing the payload. func writeSync(pipe io.Writer, sync syncType) error { - return utils.WriteJSON(pipe, syncT{sync}) + return writeSyncWithFd(pipe, sync, -1) +} + +// writeSyncWithFd is used to write to a synchronisation pipe. An error is +// returned if there was a problem writing the payload. +func writeSyncWithFd(pipe io.Writer, sync syncType, fd int) error { + if err := utils.WriteJSON(pipe, syncT{sync, fd}); err != nil { + return fmt.Errorf("writing syncT %q: %w", string(sync), err) + } + return nil } // readSync is used to read from a synchronisation pipe. An error is returned -// if we got a genericError, the pipe was closed, or we got an unexpected flag. +// if we got an initError, the pipe was closed, or we got an unexpected flag. func readSync(pipe io.Reader, expected syncType) error { var procSync syncT if err := json.NewDecoder(pipe).Decode(&procSync); err != nil { - if err == io.EOF { + if errors.Is(err, io.EOF) { return errors.New("parent closed synchronisation channel") } - return fmt.Errorf("failed reading error from parent: %v", err) + return fmt.Errorf("failed reading error from parent: %w", err) } if procSync.Type == procError { - var ierr genericError + var ierr initError if err := json.NewDecoder(pipe).Decode(&ierr); err != nil { - return fmt.Errorf("failed reading error from parent: %v", err) + return fmt.Errorf("failed reading error from parent: %w", err) } return &ierr @@ -74,17 +99,17 @@ func parseSync(pipe io.Reader, fn func(*syncT) error) error { for { var sync syncT if err := dec.Decode(&sync); err != nil { - if err == io.EOF { + if errors.Is(err, io.EOF) { break } return err } // We handle this case outside fn for cleanliness reasons. - var ierr *genericError + var ierr *initError if sync.Type == procError { - if err := dec.Decode(&ierr); err != nil && err != io.EOF { - return newSystemErrorWithCause(err, "decoding proc error from init") + if err := dec.Decode(&ierr); err != nil && !errors.Is(err, io.EOF) { + return fmt.Errorf("error decoding proc error from init: %w", err) } if ierr != nil { return ierr diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go b/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go index b9fd0832d569e..e1d6eb18034c3 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go @@ -1,8 +1,10 @@ +//go:build linux // +build linux package system import ( + "os" "os/exec" "unsafe" @@ -42,19 +44,11 @@ func Exec(cmd string, args []string, env []string) error { for { err := unix.Exec(cmd, args, env) if err != unix.EINTR { //nolint:errorlint // unix errors are bare - return err + return &os.PathError{Op: "exec", Path: cmd, Err: err} } } } -func Prlimit(pid, resource int, limit unix.Rlimit) error { - _, _, err := unix.RawSyscall6(unix.SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(&limit)), uintptr(unsafe.Pointer(&limit)), 0, 0) - if err != 0 { - return err - } - return nil -} - func SetParentDeathSignal(sig uintptr) error { if err := unix.Prctl(unix.PR_SET_PDEATHSIG, sig, 0, 0, 0); err != nil { return err diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/proc.go b/vendor/github.com/opencontainers/runc/libcontainer/system/proc.go index d0407cfe42a6d..774443ec9d29e 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/proc.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/system/proc.go @@ -2,7 +2,7 @@ package system import ( "fmt" - "io/ioutil" + "os" "path/filepath" "strconv" "strings" @@ -19,6 +19,8 @@ const ( // Only values for Linux 3.14 and later are listed here Stopped State = 'T' TracingStop State = 't' Zombie State = 'Z' + Parked State = 'P' + Idle State = 'I' ) // String forms of the state from proc(5)'s documentation for @@ -39,6 +41,10 @@ func (s State) String() string { return "tracing stop" case Zombie: return "zombie" + case Parked: + return "parked" + case Idle: + return "idle" // kernel thread default: return fmt.Sprintf("unknown (%c)", s) } @@ -48,9 +54,6 @@ func (s State) String() string { // described in proc(5) with names based on the /proc/[pid]/status // fields. type Stat_t struct { - // PID is the process ID. - PID uint - // Name is the command run by the process. Name string @@ -64,7 +67,7 @@ type Stat_t struct { // Stat returns a Stat_t instance for the specified process. func Stat(pid int) (stat Stat_t, err error) { - bytes, err := ioutil.ReadFile(filepath.Join("/proc", strconv.Itoa(pid), "stat")) + bytes, err := os.ReadFile(filepath.Join("/proc", strconv.Itoa(pid), "stat")) if err != nil { return stat, err } @@ -72,32 +75,53 @@ func Stat(pid int) (stat Stat_t, err error) { } func parseStat(data string) (stat Stat_t, err error) { - // From proc(5), field 2 could contain space and is inside `(` and `)`. - // The following is an example: + // Example: // 89653 (gunicorn: maste) S 89630 89653 89653 0 -1 4194560 29689 28896 0 3 146 32 76 19 20 0 1 0 2971844 52965376 3920 18446744073709551615 1 1 0 0 0 0 0 16781312 137447943 0 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0 - i := strings.LastIndex(data, ")") - if i <= 2 || i >= len(data)-1 { - return stat, fmt.Errorf("invalid stat data: %q", data) + // The fields are space-separated, see full description in proc(5). + // + // We are only interested in: + // * field 2: process name. It is the only field enclosed into + // parenthesis, as it can contain spaces (and parenthesis) inside. + // * field 3: process state, a single character (%c) + // * field 22: process start time, a long unsigned integer (%llu). + + // 1. Look for the first '(' and the last ')' first, what's in between is Name. + // We expect at least 20 fields and a space after the last one. + + const minAfterName = 20*2 + 1 // the min field is '0 '. + + first := strings.IndexByte(data, '(') + if first < 0 || first+minAfterName >= len(data) { + return stat, fmt.Errorf("invalid stat data (no comm or too short): %q", data) } - parts := strings.SplitN(data[:i], "(", 2) - if len(parts) != 2 { - return stat, fmt.Errorf("invalid stat data: %q", data) + last := strings.LastIndexByte(data, ')') + if last <= first || last+minAfterName >= len(data) { + return stat, fmt.Errorf("invalid stat data (no comm or too short): %q", data) } - stat.Name = parts[1] - _, err = fmt.Sscanf(parts[0], "%d", &stat.PID) + stat.Name = data[first+1 : last] + + // 2. Remove fields 1 and 2 and a space after. State is right after. + data = data[last+2:] + stat.State = State(data[0]) + + // 3. StartTime is field 22, data is at field 3 now, so we need to skip 19 spaces. + skipSpaces := 22 - 3 + for first = 0; skipSpaces > 0 && first < len(data); first++ { + if data[first] == ' ' { + skipSpaces-- + } + } + // Now first points to StartTime; look for space right after. + i := strings.IndexByte(data[first:], ' ') + if i < 0 { + return stat, fmt.Errorf("invalid stat data (too short): %q", data) + } + stat.StartTime, err = strconv.ParseUint(data[first:first+i], 10, 64) if err != nil { - return stat, err + return stat, fmt.Errorf("invalid stat data (bad start time): %w", err) } - // parts indexes should be offset by 3 from the field number given - // proc(5), because parts is zero-indexed and we've removed fields - // one (PID) and two (Name) in the paren-split. - parts = strings.Split(data[i+2:], " ") - var state int - fmt.Sscanf(parts[3-3], "%c", &state) //nolint:staticcheck // "3-3" is more readable in this context. - stat.State = State(state) - fmt.Sscanf(parts[22-3], "%d", &stat.StartTime) return stat, nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_32.go b/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_32.go index c5ca5d86235b9..1acc5cb03d03e 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_32.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_32.go @@ -1,3 +1,4 @@ +//go:build linux && (386 || arm) // +build linux // +build 386 arm 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 e05e30adc3bad..1ed0dba17093e 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,3 +1,4 @@ +//go:build linux && (arm64 || amd64 || mips || mipsle || mips64 || mips64le || ppc || ppc64 || ppc64le || riscv64 || s390x) // +build linux // +build arm64 amd64 mips mipsle mips64 mips64le ppc ppc64 ppc64le riscv64 s390x diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/xattrs_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/system/xattrs_linux.go deleted file mode 100644 index a6823fc99b2c8..0000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/xattrs_linux.go +++ /dev/null @@ -1,35 +0,0 @@ -package system - -import "golang.org/x/sys/unix" - -// Returns a []byte slice if the xattr is set and nil otherwise -// Requires path and its attribute as arguments -func Lgetxattr(path string, attr string) ([]byte, error) { - var sz int - // Start with a 128 length byte array - dest := make([]byte, 128) - sz, errno := unix.Lgetxattr(path, attr, dest) - - switch { - case errno == unix.ENODATA: - return nil, errno - case errno == unix.ENOTSUP: - return nil, errno - case errno == unix.ERANGE: - // 128 byte array might just not be good enough, - // A dummy buffer is used to get the real size - // of the xattrs on disk - sz, errno = unix.Lgetxattr(path, attr, []byte{}) - if errno != nil { - return nil, errno - } - dest = make([]byte, sz) - sz, errno = unix.Lgetxattr(path, attr, dest) - if errno != nil { - return nil, errno - } - case errno != nil: - return nil, errno - } - return dest[:sz], nil -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go index 967717a1b1c5a..f95c1409fce03 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go @@ -1,3 +1,4 @@ +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build darwin dragonfly freebsd linux netbsd openbsd solaris package user diff --git a/vendor/github.com/opencontainers/runc/libcontainer/user/user.go b/vendor/github.com/opencontainers/runc/libcontainer/user/user.go index cc7a106be5db9..2473c5eaddcee 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/user/user.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/user/user.go @@ -120,7 +120,7 @@ func ParsePasswdFileFilter(path string, filter func(User) bool) ([]User, error) func ParsePasswdFilter(r io.Reader, filter func(User) bool) ([]User, error) { if r == nil { - return nil, fmt.Errorf("nil source for passwd-formatted data") + return nil, errors.New("nil source for passwd-formatted data") } var ( @@ -178,7 +178,7 @@ func ParseGroupFileFilter(path string, filter func(Group) bool) ([]Group, error) func ParseGroupFilter(r io.Reader, filter func(Group) bool) ([]Group, error) { if r == nil { - return nil, fmt.Errorf("nil source for group-formatted data") + return nil, errors.New("nil source for group-formatted data") } rd := bufio.NewReader(r) out := []Group{} @@ -339,7 +339,7 @@ func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) ( if userArg == "" { userArg = strconv.Itoa(user.Uid) } - return nil, fmt.Errorf("unable to find user %s: %v", userArg, err) + return nil, fmt.Errorf("unable to find user %s: %w", userArg, err) } var matchedUserName string @@ -355,7 +355,7 @@ func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) ( if uidErr != nil { // Not numeric. - return nil, fmt.Errorf("unable to find user %s: %v", userArg, ErrNoPasswdEntries) + return nil, fmt.Errorf("unable to find user %s: %w", userArg, ErrNoPasswdEntries) } user.Uid = uidArg @@ -390,7 +390,7 @@ func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) ( return g.Name == groupArg }) if err != nil && group != nil { - return nil, fmt.Errorf("unable to find groups for spec %v: %v", matchedUserName, err) + return nil, fmt.Errorf("unable to find groups for spec %v: %w", matchedUserName, err) } // Only start modifying user.Gid if it is in explicit form. @@ -404,7 +404,7 @@ func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) ( if gidErr != nil { // Not numeric. - return nil, fmt.Errorf("unable to find group %s: %v", groupArg, ErrNoGroupEntries) + return nil, fmt.Errorf("unable to find group %s: %w", groupArg, ErrNoGroupEntries) } user.Gid = gidArg @@ -445,7 +445,7 @@ func GetAdditionalGroups(additionalGroups []string, group io.Reader) ([]int, err return false }) if err != nil { - return nil, fmt.Errorf("Unable to find additional groups %v: %v", additionalGroups, err) + return nil, fmt.Errorf("Unable to find additional groups %v: %w", additionalGroups, err) } } @@ -468,7 +468,8 @@ func GetAdditionalGroups(additionalGroups []string, group io.Reader) ([]int, err if !found { gid, err := strconv.ParseInt(ag, 10, 64) if err != nil { - return nil, fmt.Errorf("Unable to find group %s", ag) + // Not a numeric ID either. + return nil, fmt.Errorf("Unable to find group %s: %w", ag, ErrNoGroupEntries) } // Ensure gid is inside gid range. if gid < minID || gid > maxID { @@ -521,7 +522,7 @@ func ParseSubIDFileFilter(path string, filter func(SubID) bool) ([]SubID, error) func ParseSubIDFilter(r io.Reader, filter func(SubID) bool) ([]SubID, error) { if r == nil { - return nil, fmt.Errorf("nil source for subid-formatted data") + return nil, errors.New("nil source for subid-formatted data") } var ( @@ -574,7 +575,7 @@ func ParseIDMapFileFilter(path string, filter func(IDMap) bool) ([]IDMap, error) func ParseIDMapFilter(r io.Reader, filter func(IDMap) bool) ([]IDMap, error) { if r == nil { - return nil, fmt.Errorf("nil source for idmap-formatted data") + return nil, errors.New("nil source for idmap-formatted data") } var ( diff --git a/vendor/github.com/opencontainers/runc/libcontainer/user/user_fuzzer.go b/vendor/github.com/opencontainers/runc/libcontainer/user/user_fuzzer.go index 8c9bb5df39c2a..e018eae614e38 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/user/user_fuzzer.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/user/user_fuzzer.go @@ -1,3 +1,4 @@ +//go:build gofuzz // +build gofuzz package user diff --git a/vendor/github.com/opencontainers/runc/libcontainer/userns/userns_fuzzer.go b/vendor/github.com/opencontainers/runc/libcontainer/userns/userns_fuzzer.go index 529f8eaea2f51..1e00ab8b5050e 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/userns/userns_fuzzer.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/userns/userns_fuzzer.go @@ -1,3 +1,4 @@ +//go:build gofuzz // +build gofuzz package userns diff --git a/vendor/github.com/opencontainers/runc/libcontainer/userns/userns_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/userns/userns_unsupported.go index f45bb0c31560a..f35c13a10e026 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/userns/userns_unsupported.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/userns/userns_unsupported.go @@ -1,3 +1,4 @@ +//go:build !linux // +build !linux package userns diff --git a/vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go b/vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go index c8a9364d54d77..7ef9da21fd2dd 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go @@ -1,5 +1,3 @@ -// +build linux - package utils /* @@ -88,6 +86,11 @@ func SendFd(socket *os.File, name string, fd uintptr) error { if len(name) >= MaxNameLen { return fmt.Errorf("sendfd: filename too long: %s", name) } - oob := unix.UnixRights(int(fd)) - return unix.Sendmsg(int(socket.Fd()), []byte(name), oob, nil, 0) + return SendFds(socket, []byte(name), int(fd)) +} + +// SendFds sends a list of files descriptor and msg over the given AF_UNIX socket. +func SendFds(socket *os.File, msg []byte, fds ...int) error { + oob := unix.UnixRights(fds...) + return unix.Sendmsg(int(socket.Fd()), msg, oob, nil, 0) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go index cd78f23e1bd0e..6b9fc343522a5 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go @@ -11,7 +11,7 @@ import ( "strings" "unsafe" - "github.com/cyphar/filepath-securejoin" + securejoin "github.com/cyphar/filepath-securejoin" "golang.org/x/sys/unix" ) @@ -33,16 +33,6 @@ func init() { } } -// ResolveRootfs ensures that the current working directory is -// not a symlink and returns the absolute path to the rootfs -func ResolveRootfs(uncleanRootfs string) (string, error) { - rootfs, err := filepath.Abs(uncleanRootfs) - if err != nil { - return "", err - } - return filepath.EvalSymlinks(rootfs) -} - // ExitStatus returns the correct exit status for a process based on if it // was signaled or exited cleanly func ExitStatus(status unix.WaitStatus) int { @@ -120,7 +110,7 @@ func WithProcfd(root, unsafePath string, fn func(procfd string) error) error { unsafePath = stripRoot(root, unsafePath) path, err := securejoin.SecureJoin(root, unsafePath) if err != nil { - return fmt.Errorf("resolving path inside rootfs failed: %v", err) + return fmt.Errorf("resolving path inside rootfs failed: %w", err) } // Open the target path. 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 1576f2d4ab635..220d0b4393798 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package utils @@ -14,7 +15,7 @@ import ( 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) + return fmt.Errorf("ensure %s is on procfs: %w", fh.Name(), err) } if buf.Type != unix.PROC_SUPER_MAGIC { return fmt.Errorf("%s is not on procfs", fh.Name()) @@ -52,7 +53,7 @@ func CloseExecFrom(minFd int) error { // 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). + // os.ReadDir did the "opendir" syscall). unix.CloseOnExec(fd) } return nil diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go index b3d142d8c5bf7..12de0ae5d65ed 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go @@ -1,12 +1,13 @@ package label import ( + "errors" + "fmt" "os" "os/user" "strings" "github.com/opencontainers/selinux/go-selinux" - "github.com/pkg/errors" ) // Valid Label Options @@ -53,11 +54,11 @@ func InitLabels(options []string) (plabel string, mlabel string, retErr error) { return "", selinux.PrivContainerMountLabel(), nil } if i := strings.Index(opt, ":"); i == -1 { - return "", "", errors.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type, filetype' 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 "", "", errors.Errorf("Bad label option %q, valid options 'disable, user, role, level, type, filetype'", 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] @@ -102,9 +103,11 @@ func SetFileCreateLabel(fileLabel string) error { return selinux.SetFSCreateLabel(fileLabel) } -// Relabel changes the label of path to the filelabel string. +// Relabel changes the label of path and all the entries beneath the path. // It changes the MCS label to s0 if shared is true. // This will allow all containers to share the content. +// +// The path itself is guaranteed to be relabeled last. func Relabel(path string, fileLabel string, shared bool) error { if !selinux.GetEnabled() || fileLabel == "" { return nil @@ -151,7 +154,7 @@ func Relabel(path string, fileLabel string, shared bool) error { path = strings.TrimSuffix(path, "/") } if exclude_paths[path] { - return errors.Errorf("SELinux relabeling of %s is not allowed", path) + return fmt.Errorf("SELinux relabeling of %s is not allowed", path) } if shared { diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/rchcon.go b/vendor/github.com/opencontainers/selinux/go-selinux/rchcon.go new file mode 100644 index 0000000000000..897ecbac41cee --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/go-selinux/rchcon.go @@ -0,0 +1,22 @@ +// +build linux,go1.16 + +package selinux + +import ( + "errors" + "io/fs" + "os" + + "github.com/opencontainers/selinux/pkg/pwalkdir" +) + +func rchcon(fpath, label string) error { + return pwalkdir.Walk(fpath, func(p string, _ fs.DirEntry, _ error) error { + e := setFileLabel(p, label) + // Walk a file tree can race with removal, so ignore ENOENT. + if errors.Is(e, os.ErrNotExist) { + return nil + } + return e + }) +} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/rchcon_go115.go b/vendor/github.com/opencontainers/selinux/go-selinux/rchcon_go115.go new file mode 100644 index 0000000000000..2c8b033ce058b --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/go-selinux/rchcon_go115.go @@ -0,0 +1,21 @@ +// +build linux,!go1.16 + +package selinux + +import ( + "errors" + "os" + + "github.com/opencontainers/selinux/pkg/pwalk" +) + +func rchcon(fpath, label string) error { + return pwalk.Walk(fpath, func(p string, _ os.FileInfo, _ error) error { + e := setFileLabel(p, label) + // Walk a file tree can race with removal, so ignore ENOENT. + if errors.Is(e, os.ErrNotExist) { + return nil + } + return e + }) +} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go index b336ebad3abb9..5a59d151f6759 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go @@ -1,7 +1,7 @@ package selinux import ( - "github.com/pkg/errors" + "errors" ) const ( @@ -38,6 +38,8 @@ var ( // CategoryRange allows the upper bound on the category range to be adjusted CategoryRange = DefaultCategoryRange + + privContainerMountLabel string ) // Context is a representation of the SELinux label broken into 4 parts @@ -59,16 +61,30 @@ func ClassIndex(class string) (int, error) { return classIndex(class) } -// SetFileLabel sets the SELinux label for this path or returns an error. +// SetFileLabel sets the SELinux label for this path, following symlinks, +// or returns an error. func SetFileLabel(fpath string, label string) error { return setFileLabel(fpath, label) } -// FileLabel returns the SELinux label for this path or returns an error. +// LsetFileLabel sets the SELinux label for this path, not following symlinks, +// or returns an error. +func LsetFileLabel(fpath string, label string) error { + return lSetFileLabel(fpath, label) +} + +// FileLabel returns the SELinux label for this path, following symlinks, +// or returns an error. func FileLabel(fpath string) (string, error) { return fileLabel(fpath) } +// LfileLabel returns the SELinux label for this path, not following symlinks, +// or returns an error. +func LfileLabel(fpath string) (string, error) { + return lFileLabel(fpath) +} + // SetFSCreateLabel tells the kernel what label to use for all file system objects // created by this task. // Set the label to an empty string to return to the default label. Calls to SetFSCreateLabel @@ -253,6 +269,8 @@ func CopyLevel(src, dest string) (string, error) { // Chcon changes the fpath file object to the SELinux label label. // If fpath is a directory and recurse is true, then Chcon walks the // directory tree setting the label. +// +// The fpath itself is guaranteed to be relabeled last. func Chcon(fpath string, label string, recurse bool) error { return chcon(fpath, label, recurse) } @@ -280,5 +298,7 @@ func GetDefaultContextWithLevel(user, level, scon string) (string, error) { // PrivContainerMountLabel returns mount label for privileged containers func PrivContainerMountLabel() string { + // Make sure label is initialized. + _ = label("") return privContainerMountLabel } 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 a91a116f8481f..ee602ab96ddc4 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go @@ -5,20 +5,18 @@ import ( "bytes" "crypto/rand" "encoding/binary" + "errors" "fmt" "io" "io/ioutil" + "math/big" "os" "path" "path/filepath" - "regexp" "strconv" "strings" "sync" - "github.com/bits-and-blooms/bitset" - "github.com/opencontainers/selinux/pkg/pwalk" - "github.com/pkg/errors" "golang.org/x/sys/unix" ) @@ -35,8 +33,6 @@ const ( xattrNameSelinux = "security.selinux" ) -var policyRoot = filepath.Join(selinuxDir, readConfig(selinuxTypeTag)) - type selinuxState struct { enabledSet bool enabled bool @@ -48,7 +44,7 @@ type selinuxState struct { type level struct { sens uint - cats *bitset.BitSet + cats *big.Int } type mlsRange struct { @@ -71,7 +67,6 @@ const ( ) var ( - assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`) readOnlyFileLabel string state = selinuxState{ mcsList: make(map[string]bool), @@ -80,8 +75,24 @@ var ( // for attrPath() attrPathOnce sync.Once haveThreadSelf bool + + // for policyRoot() + policyRootOnce sync.Once + policyRootVal string + + // for label() + loadLabelsOnce sync.Once + labels map[string]string ) +func policyRoot() string { + policyRootOnce.Do(func() { + policyRootVal = filepath.Join(selinuxDir, readConfig(selinuxTypeTag)) + }) + + return policyRootVal +} + func (s *selinuxState) setEnable(enabled bool) bool { s.Lock() defer s.Unlock() @@ -120,7 +131,7 @@ func verifySELinuxfsMount(mnt string) bool { if err == nil { break } - if err == unix.EAGAIN || err == unix.EINTR { + if err == unix.EAGAIN || err == unix.EINTR { //nolint:errorlint // unix errors are bare continue } return false @@ -223,7 +234,7 @@ func readConfig(target string) string { scanner := bufio.NewScanner(in) for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) + line := bytes.TrimSpace(scanner.Bytes()) if len(line) == 0 { // Skip blank lines continue @@ -232,11 +243,12 @@ func readConfig(target string) string { // Skip comments continue } - if groups := assignRegex.FindStringSubmatch(line); groups != nil { - key, val := strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) - if key == target { - return strings.Trim(val, "\"") - } + fields := bytes.SplitN(line, []byte{'='}, 2) + if len(fields) != 2 { + continue + } + if bytes.Equal(fields[0], []byte(target)) { + return string(bytes.Trim(fields[1], `"`)) } } return "" @@ -250,12 +262,12 @@ func isProcHandle(fh *os.File) error { if err == nil { break } - if err != unix.EINTR { - return errors.Wrapf(err, "statfs(%q) failed", fh.Name()) + if err != unix.EINTR { //nolint:errorlint // unix errors are bare + return &os.PathError{Op: "fstatfs", Path: fh.Name(), Err: err} } } if buf.Type != unix.PROC_SUPER_MAGIC { - return errors.Errorf("file %q is not on procfs", fh.Name()) + return fmt.Errorf("file %q is not on procfs", fh.Name()) } return nil @@ -275,12 +287,15 @@ func readCon(fpath string) (string, error) { if err := isProcHandle(in); err != nil { return "", err } + return readConFd(in) +} - var retval string - if _, err := fmt.Fscanf(in, "%s", &retval); err != nil { +func readConFd(in *os.File) (string, error) { + data, err := ioutil.ReadAll(in) + if err != nil { return "", err } - return strings.Trim(retval, "\x00"), nil + return string(bytes.TrimSuffix(data, []byte{0})), nil } // classIndex returns the int index for an object class in the loaded policy, @@ -301,8 +316,9 @@ func classIndex(class string) (int, error) { return index, nil } -// setFileLabel sets the SELinux label for this path or returns an error. -func setFileLabel(fpath string, label string) error { +// lSetFileLabel sets the SELinux label for this path, not following symlinks, +// or returns an error. +func lSetFileLabel(fpath string, label string) error { if fpath == "" { return ErrEmptyPath } @@ -311,23 +327,61 @@ func setFileLabel(fpath string, label string) error { if err == nil { break } - if err != unix.EINTR { - return errors.Wrapf(err, "failed to set file label on %s", fpath) + if err != unix.EINTR { //nolint:errorlint // unix errors are bare + return &os.PathError{Op: "lsetxattr", Path: fpath, Err: err} + } + } + + return nil +} + +// setFileLabel sets the SELinux label for this path, following symlinks, +// or returns an error. +func setFileLabel(fpath string, label string) error { + if fpath == "" { + return ErrEmptyPath + } + for { + err := unix.Setxattr(fpath, xattrNameSelinux, []byte(label), 0) + if err == nil { + break + } + if err != unix.EINTR { //nolint:errorlint // unix errors are bare + return &os.PathError{Op: "setxattr", Path: fpath, Err: err} } } return nil } -// fileLabel returns the SELinux label for this path or returns an error. +// fileLabel returns the SELinux label for this path, following symlinks, +// or returns an error. func fileLabel(fpath string) (string, error) { if fpath == "" { return "", ErrEmptyPath } + label, err := getxattr(fpath, xattrNameSelinux) + if err != nil { + return "", &os.PathError{Op: "getxattr", Path: fpath, Err: err} + } + // Trim the NUL byte at the end of the byte buffer, if present. + if len(label) > 0 && label[len(label)-1] == '\x00' { + label = label[:len(label)-1] + } + return string(label), nil +} + +// lFileLabel returns the SELinux label for this path, not following symlinks, +// or returns an error. +func lFileLabel(fpath string) (string, error) { + if fpath == "" { + return "", ErrEmptyPath + } + label, err := lgetxattr(fpath, xattrNameSelinux) if err != nil { - return "", err + return "", &os.PathError{Op: "lgetxattr", Path: fpath, Err: err} } // Trim the NUL byte at the end of the byte buffer, if present. if len(label) > 0 && label[len(label)-1] == '\x00' { @@ -390,7 +444,7 @@ func writeCon(fpath, val string) error { _, err = out.Write(nil) } if err != nil { - return errors.Wrapf(err, "failed to set %s on procfs", fpath) + return err } return nil } @@ -440,8 +494,8 @@ func computeCreateContext(source string, target string, class string) (string, e } // catsToBitset stores categories in a bitset. -func catsToBitset(cats string) (*bitset.BitSet, error) { - bitset := &bitset.BitSet{} +func catsToBitset(cats string) (*big.Int, error) { + bitset := new(big.Int) catlist := strings.Split(cats, ",") for _, r := range catlist { @@ -456,14 +510,14 @@ func catsToBitset(cats string) (*bitset.BitSet, error) { return nil, err } for i := catstart; i <= catend; i++ { - bitset.Set(i) + bitset.SetBit(bitset, int(i), 1) } } else { cat, err := parseLevelItem(ranges[0], category) if err != nil { return nil, err } - bitset.Set(cat) + bitset.SetBit(bitset, int(cat), 1) } } @@ -489,13 +543,13 @@ func (l *level) parseLevel(levelStr string) error { lvl := strings.SplitN(levelStr, ":", 2) sens, err := parseLevelItem(lvl[0], sensitivity) if err != nil { - return errors.Wrap(err, "failed to parse sensitivity") + return fmt.Errorf("failed to parse sensitivity: %w", err) } l.sens = sens if len(lvl) > 1 { cats, err := catsToBitset(lvl[1]) if err != nil { - return errors.Wrap(err, "failed to parse categories") + return fmt.Errorf("failed to parse categories: %w", err) } l.cats = cats } @@ -513,14 +567,14 @@ func rangeStrToMLSRange(rangeStr string) (*mlsRange, error) { case 2: mlsRange.high = &level{} if err := mlsRange.high.parseLevel(levelSlice[1]); err != nil { - return nil, errors.Wrapf(err, "failed to parse high level %q", levelSlice[1]) + return nil, fmt.Errorf("failed to parse high level %q: %w", levelSlice[1], err) } fallthrough // rangeStr that is single level, e.g. s6:c0,c3,c5,c30.c1023 case 1: mlsRange.low = &level{} if err := mlsRange.low.parseLevel(levelSlice[0]); err != nil { - return nil, errors.Wrapf(err, "failed to parse low level %q", levelSlice[0]) + return nil, fmt.Errorf("failed to parse low level %q: %w", levelSlice[0], err) } } @@ -533,37 +587,30 @@ func rangeStrToMLSRange(rangeStr string) (*mlsRange, error) { // bitsetToStr takes a category bitset and returns it in the // canonical selinux syntax -func bitsetToStr(c *bitset.BitSet) string { +func bitsetToStr(c *big.Int) string { var str string - i, e := c.NextSet(0) - len := 0 - for e { - if len == 0 { + + length := 0 + for i := int(c.TrailingZeroBits()); i < c.BitLen(); i++ { + if c.Bit(i) == 0 { + continue + } + if length == 0 { if str != "" { str += "," } - str += "c" + strconv.Itoa(int(i)) - } - - next, e := c.NextSet(i + 1) - if e { - // consecutive cats - if next == i+1 { - len++ - i = next - continue - } + str += "c" + strconv.Itoa(i) } - if len == 1 { - str += ",c" + strconv.Itoa(int(i)) - } else if len > 1 { - str += ".c" + strconv.Itoa(int(i)) + if c.Bit(i+1) == 1 { + length++ + continue } - if !e { - break + if length == 1 { + str += ",c" + strconv.Itoa(i) + } else if length > 1 { + str += ".c" + strconv.Itoa(i) } - len = 0 - i = next + length = 0 } return str @@ -576,13 +623,16 @@ func (l1 *level) equal(l2 *level) bool { if l1.sens != l2.sens { return false } - return l1.cats.Equal(l2.cats) + if l2.cats == nil || l1.cats == nil { + return l2.cats == l1.cats + } + return l1.cats.Cmp(l2.cats) == 0 } // String returns an mlsRange as a string. func (m mlsRange) String() string { low := "s" + strconv.Itoa(int(m.low.sens)) - if m.low.cats != nil && m.low.cats.Count() > 0 { + if m.low.cats != nil && m.low.cats.BitLen() > 0 { low += ":" + bitsetToStr(m.low.cats) } @@ -591,7 +641,7 @@ func (m mlsRange) String() string { } high := "s" + strconv.Itoa(int(m.high.sens)) - if m.high.cats != nil && m.high.cats.Count() > 0 { + if m.high.cats != nil && m.high.cats.BitLen() > 0 { high += ":" + bitsetToStr(m.high.cats) } @@ -641,10 +691,12 @@ func calculateGlbLub(sourceRange, targetRange string) (string, error) { /* find the intersecting categories */ if s.low.cats != nil && t.low.cats != nil { - outrange.low.cats = s.low.cats.Intersection(t.low.cats) + outrange.low.cats = new(big.Int) + outrange.low.cats.And(s.low.cats, t.low.cats) } if s.high.cats != nil && t.high.cats != nil { - outrange.high.cats = s.high.cats.Intersection(t.high.cats) + outrange.high.cats = new(big.Int) + outrange.high.cats.And(s.high.cats, t.high.cats) } return outrange.String(), nil @@ -665,11 +717,7 @@ func readWriteCon(fpath string, val string) (string, error) { return "", err } - var retval string - if _, err := fmt.Fscanf(f, "%s", &retval); err != nil { - return "", err - } - return strings.Trim(retval, "\x00"), nil + return readConFd(f) } // setExecLabel sets the SELinux label that the kernel will use for any programs @@ -697,17 +745,21 @@ func socketLabel() (string, error) { // 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), unix.SOL_SOCKET, unix.SO_PEERSEC) + label, err := unix.GetsockoptString(int(fd), unix.SOL_SOCKET, unix.SO_PEERSEC) + if err != nil { + return "", &os.PathError{Op: "getsockopt", Path: "fd " + strconv.Itoa(int(fd)), Err: err} + } + return label, 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 { err := writeCon("/proc/self/attr/keycreate", label) - if os.IsNotExist(errors.Cause(err)) { + if errors.Is(err, os.ErrNotExist) { return nil } - if label == "" && os.IsPermission(errors.Cause(err)) { + if label == "" && errors.Is(err, os.ErrPermission) { return nil } return err @@ -720,10 +772,10 @@ func keyLabel() (string, error) { // get returns the Context as a string func (c Context) get() string { - if c["level"] != "" { - return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"]) + if level := c["level"]; level != "" { + return c["user"] + ":" + c["role"] + ":" + c["type"] + ":" + level } - return fmt.Sprintf("%s:%s:%s", c["user"], c["role"], c["type"]) + return c["user"] + ":" + c["role"] + ":" + c["type"] } // newContext creates a new Context struct from the specified label @@ -784,7 +836,7 @@ func enforceMode() int { // setEnforceMode sets the current SELinux mode Enforcing, Permissive. // Disabled is not valid, since this needs to be set at boot time. func setEnforceMode(mode int) error { - return ioutil.WriteFile(selinuxEnforcePath(), []byte(strconv.Itoa(mode)), 0644) + return ioutil.WriteFile(selinuxEnforcePath(), []byte(strconv.Itoa(mode)), 0o644) } // defaultEnforceMode returns the systems default SELinux mode Enforcing, @@ -888,24 +940,21 @@ func openContextFile() (*os.File, error) { if f, err := os.Open(contextFile); err == nil { return f, nil } - lxcPath := filepath.Join(policyRoot, "/contexts/lxc_contexts") - return os.Open(lxcPath) + return os.Open(filepath.Join(policyRoot(), "/contexts/lxc_contexts")) } -var labels, privContainerMountLabel = loadLabels() - -func loadLabels() (map[string]string, string) { - labels := make(map[string]string) +func loadLabels() { + labels = make(map[string]string) in, err := openContextFile() if err != nil { - return labels, "" + return } defer in.Close() scanner := bufio.NewScanner(in) for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) + line := bytes.TrimSpace(scanner.Bytes()) if len(line) == 0 { // Skip blank lines continue @@ -914,38 +963,47 @@ func loadLabels() (map[string]string, string) { // Skip comments continue } - if groups := assignRegex.FindStringSubmatch(line); groups != nil { - key, val := strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) - labels[key] = strings.Trim(val, "\"") + fields := bytes.SplitN(line, []byte{'='}, 2) + if len(fields) != 2 { + continue } + key, val := bytes.TrimSpace(fields[0]), bytes.TrimSpace(fields[1]) + labels[string(key)] = string(bytes.Trim(val, `"`)) } con, _ := NewContext(labels["file"]) con["level"] = fmt.Sprintf("s0:c%d,c%d", maxCategory-2, maxCategory-1) - reserveLabel(con.get()) - return labels, con.get() + privContainerMountLabel = con.get() + reserveLabel(privContainerMountLabel) +} + +func label(key string) string { + loadLabelsOnce.Do(func() { + loadLabels() + }) + return labels[key] } // kvmContainerLabels returns the default processLabel and mountLabel to be used // for kvm containers by the calling process. func kvmContainerLabels() (string, string) { - processLabel := labels["kvm_process"] + processLabel := label("kvm_process") if processLabel == "" { - processLabel = labels["process"] + processLabel = label("process") } - return addMcs(processLabel, labels["file"]) + return addMcs(processLabel, label("file")) } // initContainerLabels returns the default processLabel and file labels to be // used for containers running an init system like systemd by the calling process. func initContainerLabels() (string, string) { - processLabel := labels["init_process"] + processLabel := label("init_process") if processLabel == "" { - processLabel = labels["process"] + processLabel = label("process") } - return addMcs(processLabel, labels["file"]) + return addMcs(processLabel, label("file")) } // containerLabels returns an allocated processLabel and fileLabel to be used for @@ -955,9 +1013,9 @@ func containerLabels() (processLabel string, fileLabel string) { return "", "" } - processLabel = labels["process"] - fileLabel = labels["file"] - readOnlyFileLabel = labels["ro_file"] + processLabel = label("process") + fileLabel = label("file") + readOnlyFileLabel = label("ro_file") if processLabel == "" || fileLabel == "" { return "", fileLabel @@ -985,7 +1043,7 @@ func addMcs(processLabel, fileLabel string) (string, string) { // securityCheckContext validates that the SELinux label is understood by the kernel func securityCheckContext(val string) error { - return ioutil.WriteFile(path.Join(getSelinuxMountPoint(), "context"), []byte(val), 0644) + return ioutil.WriteFile(path.Join(getSelinuxMountPoint(), "context"), []byte(val), 0o644) } // copyLevel returns a label with the MLS/MCS level from src label replaced on @@ -1023,7 +1081,7 @@ func badPrefix(fpath string) error { badPrefixes := []string{"/usr"} for _, prefix := range badPrefixes { if strings.HasPrefix(fpath, prefix) { - return errors.Errorf("relabeling content in %s is not allowed", prefix) + return fmt.Errorf("relabeling content in %s is not allowed", prefix) } } return nil @@ -1044,17 +1102,10 @@ func chcon(fpath string, label string, recurse bool) error { } if !recurse { - return SetFileLabel(fpath, label) + return setFileLabel(fpath, label) } - return pwalk.Walk(fpath, func(p string, info os.FileInfo, err error) error { - e := SetFileLabel(p, label) - // Walk a file tree can race with removal, so ignore ENOENT - if os.IsNotExist(errors.Cause(e)) { - return nil - } - return e - }) + return rchcon(fpath, label) } // dupSecOpt takes an SELinux process label and returns security options that @@ -1072,7 +1123,8 @@ func dupSecOpt(src string) ([]string, error) { con["type"] == "" { return nil, nil } - dup := []string{"user:" + con["user"], + dup := []string{ + "user:" + con["user"], "role:" + con["role"], "type:" + con["type"], } @@ -1140,9 +1192,8 @@ func findUserInContext(context Context, r io.Reader, verifier func(string) error return outConn, nil } } - if err := scanner.Err(); err != nil { - return "", errors.Wrap(err, "failed to scan for context") + return "", fmt.Errorf("failed to scan for context: %w", err) } return "", nil @@ -1155,7 +1206,7 @@ func getDefaultContextFromReaders(c *defaultSECtx) (string, error) { context, err := newContext(c.scon) if err != nil { - return "", errors.Wrapf(err, "failed to create label for %s", c.scon) + return "", fmt.Errorf("failed to create label for %s: %w", c.scon, err) } // set so the verifier validates the matched context with the provided user and level. @@ -1180,19 +1231,18 @@ func getDefaultContextFromReaders(c *defaultSECtx) (string, error) { return conn, nil } - return "", errors.Wrapf(ErrContextMissing, "context not found: %q", c.scon) + return "", fmt.Errorf("context %q not found: %w", c.scon, ErrContextMissing) } func getDefaultContextWithLevel(user, level, scon string) (string, error) { - userPath := filepath.Join(policyRoot, selinuxUsersDir, user) - defaultPath := filepath.Join(policyRoot, defaultContexts) - + userPath := filepath.Join(policyRoot(), selinuxUsersDir, user) fu, err := os.Open(userPath) if err != nil { return "", err } defer fu.Close() + defaultPath := filepath.Join(policyRoot(), defaultContexts) fd, err := os.Open(defaultPath) if err != nil { return "", err 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 b7218a0b6a85c..78743b020c923 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go @@ -2,8 +2,6 @@ package selinux -const privContainerMountLabel = "" - func setDisabled() { } @@ -19,10 +17,18 @@ func setFileLabel(fpath string, label string) error { return nil } +func lSetFileLabel(fpath string, label string) error { + return nil +} + func fileLabel(fpath string) (string, error) { return "", nil } +func lFileLabel(fpath string) (string, error) { + return "", nil +} + func setFSCreateLabel(label string) error { return nil } @@ -152,3 +158,7 @@ func disableSecOpt() []string { func getDefaultContextWithLevel(user, level, scon string) (string, error) { return "", nil } + +func label(_ string) string { + return "" +} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go index 117c255be2015..9e473ca168f11 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go @@ -10,7 +10,7 @@ func lgetxattr(path, attr string) ([]byte, error) { // Start with a 128 length byte array dest := make([]byte, 128) sz, errno := doLgetxattr(path, attr, dest) - for errno == unix.ERANGE { + for errno == unix.ERANGE { //nolint:errorlint // unix errors are bare // Buffer too small, use zero-sized buffer to get the actual size sz, errno = doLgetxattr(path, attr, []byte{}) if errno != nil { @@ -31,7 +31,40 @@ func lgetxattr(path, attr string) ([]byte, error) { func doLgetxattr(path, attr string, dest []byte) (int, error) { for { sz, err := unix.Lgetxattr(path, attr, dest) - if err != unix.EINTR { + if err != unix.EINTR { //nolint:errorlint // unix errors are bare + return sz, err + } + } +} + +// getxattr returns a []byte slice containing the value of +// an extended attribute attr set for path. +func getxattr(path, attr string) ([]byte, error) { + // Start with a 128 length byte array + dest := make([]byte, 128) + sz, errno := dogetxattr(path, attr, dest) + for errno == unix.ERANGE { //nolint:errorlint // unix errors are bare + // Buffer too small, use zero-sized buffer to get the actual size + sz, errno = dogetxattr(path, attr, []byte{}) + if errno != nil { + return nil, errno + } + + dest = make([]byte, sz) + sz, errno = dogetxattr(path, attr, dest) + } + if errno != nil { + return nil, errno + } + + return dest[:sz], nil +} + +// dogetxattr is a wrapper that retries on EINTR +func dogetxattr(path, attr string, dest []byte) (int, error) { + for { + sz, err := unix.Getxattr(path, attr, dest) + if err != unix.EINTR { //nolint:errorlint // unix errors are bare return sz, err } } diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md b/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md index 16c4dfd3ecc7e..7e78dce0156b2 100644 --- a/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md +++ b/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md @@ -8,6 +8,12 @@ By default, it utilizes 2\*runtime.NumCPU() goroutines for callbacks. This can be changed by using WalkN function which has the additional parameter, specifying the number of goroutines (concurrency). +### pwalk vs pwalkdir + +This package is deprecated in favor of +[pwalkdir](https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalkdir), +which is faster, but requires at least Go 1.16. + ### Caveats Please note the following limitations of this code: diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go index 437b12b3e289c..202c80da59c3b 100644 --- a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go +++ b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go @@ -1,12 +1,11 @@ package pwalk import ( + "fmt" "os" "path/filepath" "runtime" "sync" - - "github.com/pkg/errors" ) type WalkFunc = filepath.WalkFunc @@ -20,7 +19,7 @@ type WalkFunc = filepath.WalkFunc // // Note that this implementation only supports primitive error handling: // -// - no errors are ever passed to WalkFn; +// - no errors are ever passed to walkFn; // // - once a walkFn returns any error, all further processing stops // and the error is returned to the caller of Walk; @@ -42,7 +41,7 @@ func Walk(root string, walkFn WalkFunc) error { func WalkN(root string, walkFn WalkFunc, num int) error { // make sure limit is sensible if num < 1 { - return errors.Errorf("walk(%q): num must be > 0", root) + return fmt.Errorf("walk(%q): num must be > 0", root) } files := make(chan *walkArgs, 2*num) @@ -52,6 +51,9 @@ func WalkN(root string, walkFn WalkFunc, num int) error { var ( err error wg sync.WaitGroup + + rootLen = len(root) + rootEntry *walkArgs ) wg.Add(1) go func() { @@ -60,6 +62,11 @@ func WalkN(root string, walkFn WalkFunc, num int) error { close(files) return err } + if len(p) == rootLen { + // Root entry is processed separately below. + rootEntry = &walkArgs{path: p, info: &info} + return nil + } // add a file to the queue unless a callback sent an error select { case e := <-errCh: @@ -93,10 +100,14 @@ func WalkN(root string, walkFn WalkFunc, num int) error { wg.Wait() + if err == nil { + err = walkFn(rootEntry.path, *rootEntry.info, nil) + } + return err } -// walkArgs holds the arguments that were passed to the Walk or WalkLimit +// walkArgs holds the arguments that were passed to the Walk or WalkN // functions. type walkArgs struct { path string diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/README.md b/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/README.md new file mode 100644 index 0000000000000..068ac400565bc --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/README.md @@ -0,0 +1,54 @@ +## pwalkdir: parallel implementation of filepath.WalkDir + +This is a wrapper for [filepath.WalkDir](https://pkg.go.dev/path/filepath#WalkDir) +which may speed it up by calling multiple callback functions (WalkDirFunc) +in parallel, utilizing goroutines. + +By default, it utilizes 2\*runtime.NumCPU() goroutines for callbacks. +This can be changed by using WalkN function which has the additional +parameter, specifying the number of goroutines (concurrency). + +### pwalk vs pwalkdir + +This package is very similar to +[pwalk](https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalkdir), +but utilizes `filepath.WalkDir` (added to Go 1.16), which does not call stat(2) +on every entry and is therefore faster (up to 3x, depending on usage scenario). + +Users who are OK with requiring Go 1.16+ should switch to this +implementation. + +### Caveats + +Please note the following limitations of this code: + +* Unlike filepath.WalkDir, the order of calls is non-deterministic; + +* Only primitive error handling is supported: + + * fs.SkipDir is not supported; + + * no errors are ever passed to WalkDirFunc; + + * once any error is returned from any walkDirFunc instance, no more calls + to WalkDirFunc are made, and the error is returned to the caller of WalkDir; + + * if more than one WalkDirFunc instance will return an error, only one + of such errors will be propagated to and returned by WalkDir, others + will be silently discarded. + +### Documentation + +For the official documentation, see +https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalkdir + +### Benchmarks + +For a WalkDirFunc that consists solely of the return statement, this +implementation is about 15% slower than the standard library's +filepath.WalkDir. + +Otherwise (if a WalkDirFunc is actually doing something) this is usually +faster, except when the WalkDirN(..., 1) is used. Run `go test -bench .` +to see how different operations can benefit from it, as well as how the +level of paralellism affects the speed. diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go b/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go new file mode 100644 index 0000000000000..a5796b2c4f1c5 --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go @@ -0,0 +1,116 @@ +//go:build go1.16 +// +build go1.16 + +package pwalkdir + +import ( + "fmt" + "io/fs" + "path/filepath" + "runtime" + "sync" +) + +// Walk is a wrapper for filepath.WalkDir which can call multiple walkFn +// in parallel, allowing to handle each item concurrently. A maximum of +// twice the runtime.NumCPU() walkFn will be called at any one time. +// If you want to change the maximum, use WalkN instead. +// +// The order of calls is non-deterministic. +// +// Note that this implementation only supports primitive error handling: +// +// - no errors are ever passed to walkFn; +// +// - once a walkFn returns any error, all further processing stops +// and the error is returned to the caller of Walk; +// +// - filepath.SkipDir is not supported; +// +// - if more than one walkFn instance will return an error, only one +// of such errors will be propagated and returned by Walk, others +// will be silently discarded. +func Walk(root string, walkFn fs.WalkDirFunc) error { + return WalkN(root, walkFn, runtime.NumCPU()*2) +} + +// WalkN is a wrapper for filepath.WalkDir which can call multiple walkFn +// in parallel, allowing to handle each item concurrently. A maximum of +// num walkFn will be called at any one time. +// +// Please see Walk documentation for caveats of using this function. +func WalkN(root string, walkFn fs.WalkDirFunc, num int) error { + // make sure limit is sensible + if num < 1 { + return fmt.Errorf("walk(%q): num must be > 0", root) + } + + files := make(chan *walkArgs, 2*num) + errCh := make(chan error, 1) // Get the first error, ignore others. + + // Start walking a tree asap. + var ( + err error + wg sync.WaitGroup + + rootLen = len(root) + rootEntry *walkArgs + ) + wg.Add(1) + go func() { + err = filepath.WalkDir(root, func(p string, entry fs.DirEntry, err error) error { + if err != nil { + close(files) + return err + } + if len(p) == rootLen { + // Root entry is processed separately below. + rootEntry = &walkArgs{path: p, entry: entry} + return nil + } + // Add a file to the queue unless a callback sent an error. + select { + case e := <-errCh: + close(files) + return e + default: + files <- &walkArgs{path: p, entry: entry} + return nil + } + }) + if err == nil { + close(files) + } + wg.Done() + }() + + wg.Add(num) + for i := 0; i < num; i++ { + go func() { + for file := range files { + if e := walkFn(file.path, file.entry, nil); e != nil { + select { + case errCh <- e: // sent ok + default: // buffer full + } + } + } + wg.Done() + }() + } + + wg.Wait() + + if err == nil { + err = walkFn(rootEntry.path, rootEntry.entry, nil) + } + + return err +} + +// walkArgs holds the arguments that were passed to the Walk or WalkN +// functions. +type walkArgs struct { + path string + entry fs.DirEntry +} diff --git a/vendor/github.com/seccomp/libseccomp-golang/.travis.yml b/vendor/github.com/seccomp/libseccomp-golang/.travis.yml new file mode 100644 index 0000000000000..5240d46228058 --- /dev/null +++ b/vendor/github.com/seccomp/libseccomp-golang/.travis.yml @@ -0,0 +1,57 @@ +# Travis CI configuration for libseccomp-golang + +# https://docs.travis-ci.com/user/reference/bionic +# https://wiki.ubuntu.com/Releases + +dist: bionic +sudo: false + +notifications: + email: + on_success: always + on_failure: always + +arch: + - amd64 + +os: + - linux + +language: go + +jobs: + include: + - name: "last libseccomp 2.5.0" + env: + - SECCOMP_VER=2.5.0 + - SECCOMP_SHA256SUM=1ffa7038d2720ad191919816db3479295a4bcca1ec14e02f672539f4983014f3 + - name: "compat libseccomp 2.4.4" + env: + - SECCOMP_VER=2.4.4 + - SECCOMP_SHA256SUM=4e79738d1ef3c9b7ca9769f1f8b8d84fc17143c2c1c432e53b9c64787e0ff3eb + - name: "compat libseccomp 2.2.1" + env: + - SECCOMP_VER=2.2.1 + - SECCOMP_SHA256SUM=0ba1789f54786c644af54cdffc9fd0dd0a8bb2b2ee153933f658855d2851a740 + +addons: + apt: + packages: + - build-essential + - astyle + - golint + - gperf + +install: + - go get -u golang.org/x/lint/golint + +# run all of the tests independently, fail if any of the tests error +script: + - wget https://github.com/seccomp/libseccomp/releases/download/v$SECCOMP_VER/libseccomp-$SECCOMP_VER.tar.gz + - echo $SECCOMP_SHA256SUM libseccomp-$SECCOMP_VER.tar.gz | sha256sum -c + - tar xf libseccomp-$SECCOMP_VER.tar.gz + - pushd libseccomp-$SECCOMP_VER && ./configure --prefix=/opt/libseccomp-$SECCOMP_VER && make && sudo make install && popd + - make check-syntax + - make lint + - PKG_CONFIG_PATH=/opt/libseccomp-$SECCOMP_VER/lib/pkgconfig LD_LIBRARY_PATH=/opt/libseccomp-$SECCOMP_VER/lib make vet + - PKG_CONFIG_PATH=/opt/libseccomp-$SECCOMP_VER/lib/pkgconfig LD_LIBRARY_PATH=/opt/libseccomp-$SECCOMP_VER/lib make test diff --git a/vendor/github.com/seccomp/libseccomp-golang/SUBMITTING_PATCHES b/vendor/github.com/seccomp/libseccomp-golang/CONTRIBUTING.md similarity index 69% rename from vendor/github.com/seccomp/libseccomp-golang/SUBMITTING_PATCHES rename to vendor/github.com/seccomp/libseccomp-golang/CONTRIBUTING.md index 744e5cd64f2f1..d6862cbd5f9f5 100644 --- a/vendor/github.com/seccomp/libseccomp-golang/SUBMITTING_PATCHES +++ b/vendor/github.com/seccomp/libseccomp-golang/CONTRIBUTING.md @@ -8,11 +8,11 @@ to the rules described here, but by following the instructions below you should have a much easier time getting your work merged with the upstream project. -* Test Your Code +## Test Your Code Using Existing Tests -There are two possible tests you can run to verify your code. The first test -is used to check the formatting and coding style of your changes, you can run -the test with the following command: +There are two possible tests you can run to verify your code. The first +test is used to check the formatting and coding style of your changes, you +can run the test with the following command: # make check-syntax @@ -27,30 +27,13 @@ with the following command: ... if there are any faults or errors they will be displayed. -* Generate the Patch(es) +## Add New Tests for New Functionality -Depending on how you decided to work with the libseccomp code base and what -tools you are using there are different ways to generate your patch(es). -However, regardless of what tools you use, you should always generate your -patches using the "unified" diff/patch format and the patches should always -apply to the libseccomp source tree using the following command from the top -directory of the libseccomp sources: +Any submissions which add functionality, or significantly change the existing +code, should include additional tests to verify the proper operation of the +proposed changes. - # patch -p1 < changes.patch - -If you are not using git, stacked git (stgit), or some other tool which can -generate patch files for you automatically, you may find the following command -helpful in generating patches, where "libseccomp.orig/" is the unmodified -source code directory and "libseccomp/" is the source code directory with your -changes: - - # diff -purN libseccomp-golang.orig/ libseccomp-golang/ - -When in doubt please generate your patch and try applying it to an unmodified -copy of the libseccomp sources; if it fails for you, it will fail for the rest -of us. - -* Explain Your Work +## Explain Your Work At the top of every patch you should include a description of the problem you are trying to solve, how you solved it, and why you chose the solution you @@ -59,7 +42,7 @@ if you can describe/include a reproducer for the problem in the description as well as instructions on how to test for the bug and verify that it has been fixed. -* Sign Your Work +## Sign Your Work The sign-off is a simple line at the end of the patch description, which certifies that you wrote it or otherwise have the right to pass it on as an @@ -97,16 +80,49 @@ your real name, saying: Signed-off-by: Random J Developer -* Email Your Patch(es) +You can add this to your commit description in `git` with `git commit -s` + +## Post Your Patches Upstream + +The libseccomp project accepts both GitHub pull requests and patches sent via +the mailing list. GitHub pull requests are preferred. This sections below +explain how to contribute via either method. Please read each step and perform +all steps that apply to your chosen contribution method. + +### Submitting via Email + +Depending on how you decided to work with the libseccomp code base and what +tools you are using there are different ways to generate your patch(es). +However, regardless of what tools you use, you should always generate your +patches using the "unified" diff/patch format and the patches should always +apply to the libseccomp source tree using the following command from the top +directory of the libseccomp sources: + + # patch -p1 < changes.patch + +If you are not using git, stacked git (stgit), or some other tool which can +generate patch files for you automatically, you may find the following command +helpful in generating patches, where "libseccomp.orig/" is the unmodified +source code directory and "libseccomp/" is the source code directory with your +changes: + + # diff -purN libseccomp.orig/ libseccomp/ + +When in doubt please generate your patch and try applying it to an unmodified +copy of the libseccomp sources; if it fails for you, it will fail for the rest +of us. Finally, you will need to email your patches to the mailing list so they can -be reviewed and potentially merged into the main libseccomp-golang repository. -When sending patches to the mailing list it is important to send your email in -text form, no HTML mail please, and ensure that your email client does not -mangle your patches. It should be possible to save your raw email to disk and -apply it directly to the libseccomp source code; if that fails then you likely -have a problem with your email client. When in doubt try a test first by -sending yourself an email with your patch and attempting to apply the emailed -patch to the libseccomp-golang repository; if it fails for you, it will fail -for the rest of us trying to test your patch and include it in the main -libseccomp-golang repository. +be reviewed and potentially merged into the main libseccomp repository. When +sending patches to the mailing list it is important to send your email in text +form, no HTML mail please, and ensure that your email client does not mangle +your patches. It should be possible to save your raw email to disk and apply +it directly to the libseccomp source code; if that fails then you likely have +a problem with your email client. When in doubt try a test first by sending +yourself an email with your patch and attempting to apply the emailed patch to +the libseccomp repository; if it fails for you, it will fail for the rest of +us trying to test your patch and include it in the main libseccomp repository. + +### Submitting via GitHub + +See [this guide](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request) if you've never done this before. diff --git a/vendor/github.com/seccomp/libseccomp-golang/Makefile b/vendor/github.com/seccomp/libseccomp-golang/Makefile index 1ff4cc898599b..38cfa852cd6ad 100644 --- a/vendor/github.com/seccomp/libseccomp-golang/Makefile +++ b/vendor/github.com/seccomp/libseccomp-golang/Makefile @@ -18,8 +18,14 @@ fix-syntax: vet: go vet -v +# Previous bugs have made the tests freeze until the timeout. Golang default +# timeout for tests is 10 minutes, which is too long, considering current tests +# can be executed in less than 1 second. Reduce the timeout, so problems can +# be noticed earlier in the CI. +TEST_TIMEOUT=10s + test: - go test -v + go test -v -timeout $(TEST_TIMEOUT) lint: @$(if $(shell which golint),true,$(error "install golint and include it in your PATH")) diff --git a/vendor/github.com/seccomp/libseccomp-golang/README b/vendor/github.com/seccomp/libseccomp-golang/README.md similarity index 68% rename from vendor/github.com/seccomp/libseccomp-golang/README rename to vendor/github.com/seccomp/libseccomp-golang/README.md index 66839a4668559..806a5ddf29b7e 100644 --- a/vendor/github.com/seccomp/libseccomp-golang/README +++ b/vendor/github.com/seccomp/libseccomp-golang/README.md @@ -1,7 +1,8 @@ -libseccomp-golang: Go Language Bindings for the libseccomp Project +![libseccomp Golang Bindings](https://github.com/seccomp/libseccomp-artwork/blob/main/logo/libseccomp-color_text.png) =============================================================================== https://github.com/seccomp/libseccomp-golang -https://github.com/seccomp/libseccomp + +[![Build Status](https://img.shields.io/travis/seccomp/libseccomp-golang/main.svg)](https://travis-ci.org/seccomp/libseccomp-golang) The libseccomp library provides an easy to use, platform independent, interface to the Linux Kernel's syscall filtering mechanism. The libseccomp API is @@ -12,40 +13,39 @@ be familiar to, and easily adopted by, application developers. The libseccomp-golang library provides a Go based interface to the libseccomp library. -* Online Resources +## Online Resources The library source repository currently lives on GitHub at the following URLs: - -> https://github.com/seccomp/libseccomp-golang - -> https://github.com/seccomp/libseccomp +* https://github.com/seccomp/libseccomp-golang +* https://github.com/seccomp/libseccomp The project mailing list is currently hosted on Google Groups at the URL below, please note that a Google account is not required to subscribe to the mailing list. - -> https://groups.google.com/d/forum/libseccomp +* https://groups.google.com/d/forum/libseccomp Documentation is also available at: - -> https://godoc.org/github.com/seccomp/libseccomp-golang +* https://godoc.org/github.com/seccomp/libseccomp-golang -* Installing the package +## Installing the package The libseccomp-golang bindings require at least Go v1.2.1 and GCC v4.8.4; earlier versions may yield unpredictable results. If you meet these requirements you can install this package using the command below: - $ go get github.com/seccomp/libseccomp-golang + # go get github.com/seccomp/libseccomp-golang -* Testing the Library +## Testing the Library A number of tests and lint related recipes are provided in the Makefile, if you want to run the standard regression tests, you can excute the following: - $ make check + # make check In order to execute the 'make lint' recipe the 'golint' tool is needed, it can be found at: - -> https://github.com/golang/lint - +* https://github.com/golang/lint diff --git a/vendor/github.com/seccomp/libseccomp-golang/go.mod b/vendor/github.com/seccomp/libseccomp-golang/go.mod new file mode 100644 index 0000000000000..6384b3769bd18 --- /dev/null +++ b/vendor/github.com/seccomp/libseccomp-golang/go.mod @@ -0,0 +1,3 @@ +module github.com/seccomp/libseccomp-golang + +go 1.14 diff --git a/vendor/github.com/seccomp/libseccomp-golang/go.sum b/vendor/github.com/seccomp/libseccomp-golang/go.sum new file mode 100644 index 0000000000000..72ae16111490f --- /dev/null +++ b/vendor/github.com/seccomp/libseccomp-golang/go.sum @@ -0,0 +1,23 @@ +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7 h1:EBZoQjiKKPaLbPrbpssUfuHtwM6KV/vb4U85g/cigFY= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200313205530-4303120df7d8 h1:gkI/wGGwpcG5W4hLCzZNGxA4wzWBGGDStRI1MrjDl2Q= +golang.org/x/tools v0.0.0-20200313205530-4303120df7d8/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/github.com/seccomp/libseccomp-golang/seccomp.go b/vendor/github.com/seccomp/libseccomp-golang/seccomp.go index a3cc53822ce62..e9b92e2219ade 100644 --- a/vendor/github.com/seccomp/libseccomp-golang/seccomp.go +++ b/vendor/github.com/seccomp/libseccomp-golang/seccomp.go @@ -20,6 +20,13 @@ import ( // C wrapping code +// To compile libseccomp-golang against a specific version of libseccomp: +// cd ../libseccomp && mkdir -p prefix +// ./configure --prefix=$PWD/prefix && make && make install +// cd ../libseccomp-golang +// PKG_CONFIG_PATH=$PWD/../libseccomp/prefix/lib/pkgconfig/ make +// LD_PRELOAD=$PWD/../libseccomp/prefix/lib/libseccomp.so.2.5.0 PKG_CONFIG_PATH=$PWD/../libseccomp/prefix/lib/pkgconfig/ make test + // #cgo pkg-config: libseccomp // #include // #include @@ -34,19 +41,25 @@ type VersionError struct { minimum string } +func init() { + // This forces the cgo libseccomp to initialize its internal API support state, + // which is necessary on older versions of libseccomp in order to work + // correctly. + GetAPI() +} + func (e VersionError) Error() string { - format := "Libseccomp version too low: " + messageStr := "" if e.message != "" { - format += e.message + ": " + messageStr = e.message + ": " } - format += "minimum supported is " + minimumStr := "" if e.minimum != "" { - format += e.minimum + ": " + minimumStr = e.minimum } else { - format += "2.2.0: " + minimumStr = "2.2.0" } - format += "detected %d.%d.%d" - return fmt.Sprintf(format, verMajor, verMinor, verMicro) + return fmt.Sprintf("Libseccomp version too low: %sminimum supported is %s: detected %d.%d.%d", messageStr, minimumStr, verMajor, verMinor, verMicro) } // ScmpArch represents a CPU architecture. Seccomp can restrict syscalls on a @@ -69,9 +82,61 @@ type ScmpCondition struct { Operand2 uint64 `json:"operand_two,omitempty"` } -// ScmpSyscall represents a Linux System Call +// Seccomp userspace notification structures associated with filters that use the ActNotify action. + +// ScmpSyscall identifies a Linux System Call by its number. type ScmpSyscall int32 +// ScmpFd represents a file-descriptor used for seccomp userspace notifications. +type ScmpFd int32 + +// ScmpNotifData describes the system call context that triggered a notification. +// +// Syscall: the syscall number +// Arch: the filter architecture +// InstrPointer: address of the instruction that triggered a notification +// Args: arguments (up to 6) for the syscall +// +type ScmpNotifData struct { + Syscall ScmpSyscall `json:"syscall,omitempty"` + Arch ScmpArch `json:"arch,omitempty"` + InstrPointer uint64 `json:"instr_pointer,omitempty"` + Args []uint64 `json:"args,omitempty"` +} + +// ScmpNotifReq represents a seccomp userspace notification. See NotifReceive() for +// info on how to pull such a notification. +// +// ID: notification ID +// Pid: process that triggered the notification event +// Flags: filter flags (see seccomp(2)) +// Data: system call context that triggered the notification +// +type ScmpNotifReq struct { + ID uint64 `json:"id,omitempty"` + Pid uint32 `json:"pid,omitempty"` + Flags uint32 `json:"flags,omitempty"` + Data ScmpNotifData `json:"data,omitempty"` +} + +// ScmpNotifResp represents a seccomp userspace notification response. See NotifRespond() +// for info on how to push such a response. +// +// ID: notification ID (must match the corresponding ScmpNotifReq ID) +// Error: must be 0 if no error occurred, or an error constant from package +// syscall (e.g., syscall.EPERM, etc). In the latter case, it's used +// as an error return from the syscall that created the notification. +// Val: return value for the syscall that created the notification. Only +// relevant if Error is 0. +// Flags: userspace notification response flag (e.g., NotifRespFlagContinue) +// +type ScmpNotifResp struct { + ID uint64 `json:"id,omitempty"` + Error int32 `json:"error,omitempty"` + Val uint64 `json:"val,omitempty"` + Flags uint32 `json:"flags,omitempty"` +} + // Exported Constants const ( @@ -117,6 +182,10 @@ const ( ArchS390 ScmpArch = iota // ArchS390X represents 64-bit System z/390 syscalls ArchS390X ScmpArch = iota + // ArchPARISC represents 32-bit PA-RISC + ArchPARISC ScmpArch = iota + // ArchPARISC64 represents 64-bit PA-RISC + ArchPARISC64 ScmpArch = iota ) const ( @@ -125,10 +194,14 @@ const ( // ActInvalid is a placeholder to ensure uninitialized ScmpAction // variables are invalid ActInvalid ScmpAction = iota - // ActKill kills the process + // ActKill kills the thread that violated the rule. It is the same as ActKillThread. + // All other threads from the same thread group will continue to execute. ActKill ScmpAction = iota // ActTrap throws SIGSYS ActTrap ScmpAction = iota + // ActNotify triggers a userspace notification. This action is only usable when + // libseccomp API level 6 or higher is supported. + ActNotify ScmpAction = iota // ActErrno causes the syscall to return a negative error code. This // code can be set with the SetReturnCode method ActErrno ScmpAction = iota @@ -141,6 +214,14 @@ const ( // This action is only usable when libseccomp API level 3 or higher is // supported. ActLog ScmpAction = iota + // ActKillThread kills the thread that violated the rule. It is the same as ActKill. + // All other threads from the same thread group will continue to execute. + ActKillThread ScmpAction = iota + // ActKillProcess kills the process that violated the rule. + // All threads in the thread group are also terminated. + // This action is only usable when libseccomp API level 3 or higher is + // supported. + ActKillProcess ScmpAction = iota ) const ( @@ -172,6 +253,21 @@ const ( CompareMaskedEqual ScmpCompareOp = iota ) +var ( + // ErrSyscallDoesNotExist represents an error condition where + // libseccomp is unable to resolve the syscall + ErrSyscallDoesNotExist = fmt.Errorf("could not resolve syscall name") +) + +const ( + // Userspace notification response flags + + // NotifRespFlagContinue tells the kernel to continue executing the system + // call that triggered the notification. Must only be used when the notication + // response's error is 0. + NotifRespFlagContinue uint32 = 1 +) + // Helpers for types // GetArchFromString returns an ScmpArch constant from a string representing an @@ -214,6 +310,10 @@ func GetArchFromString(arch string) (ScmpArch, error) { return ArchS390, nil case "s390x": return ArchS390X, nil + case "parisc": + return ArchPARISC, nil + case "parisc64": + return ArchPARISC64, nil default: return ArchInvalid, fmt.Errorf("cannot convert unrecognized string %q", arch) } @@ -254,6 +354,10 @@ func (a ScmpArch) String() string { return "s390" case ArchS390X: return "s390x" + case ArchPARISC: + return "parisc" + case ArchPARISC64: + return "parisc64" case ArchNative: return "native" case ArchInvalid: @@ -290,8 +394,10 @@ func (a ScmpCompareOp) String() string { // String returns a string representation of a seccomp match action func (a ScmpAction) String() string { switch a & 0xFFFF { - case ActKill: - return "Action: Kill Process" + case ActKill, ActKillThread: + return "Action: Kill thread" + case ActKillProcess: + return "Action: Kill process" case ActTrap: return "Action: Send SIGSYS" case ActErrno: @@ -299,6 +405,8 @@ func (a ScmpAction) String() string { case ActTrace: return fmt.Sprintf("Action: Notify tracing processes with code %d", (a >> 16)) + case ActNotify: + return "Action: Notify userspace" case ActLog: return "Action: Log system call" case ActAllow: @@ -334,23 +442,23 @@ func GetLibraryVersion() (major, minor, micro uint) { return verMajor, verMinor, verMicro } -// GetApi returns the API level supported by the system. +// GetAPI returns the API level supported by the system. // Returns a positive int containing the API level, or 0 with an error if the // API level could not be detected due to the library being older than v2.4.0. // See the seccomp_api_get(3) man page for details on available API levels: -// https://github.com/seccomp/libseccomp/blob/master/doc/man/man3/seccomp_api_get.3 -func GetApi() (uint, error) { - return getApi() +// https://github.com/seccomp/libseccomp/blob/main/doc/man/man3/seccomp_api_get.3 +func GetAPI() (uint, error) { + return getAPI() } -// SetApi forcibly sets the API level. General use of this function is strongly +// SetAPI forcibly sets the API level. General use of this function is strongly // discouraged. // Returns an error if the API level could not be set. An error is always // returned if the library is older than v2.4.0 // See the seccomp_api_get(3) man page for details on available API levels: -// https://github.com/seccomp/libseccomp/blob/master/doc/man/man3/seccomp_api_get.3 -func SetApi(api uint) error { - return setApi(api) +// https://github.com/seccomp/libseccomp/blob/main/doc/man/man3/seccomp_api_get.3 +func SetAPI(api uint) error { + return setAPI(api) } // Syscall functions @@ -375,7 +483,7 @@ func (s ScmpSyscall) GetNameByArch(arch ScmpArch) (string, error) { cString := C.seccomp_syscall_resolve_num_arch(arch.toNative(), C.int(s)) if cString == nil { - return "", fmt.Errorf("could not resolve syscall name for %#x", int32(s)) + return "", ErrSyscallDoesNotExist } defer C.free(unsafe.Pointer(cString)) @@ -398,7 +506,7 @@ func GetSyscallFromName(name string) (ScmpSyscall, error) { result := C.seccomp_syscall_resolve_name(cString) if result == scmpError { - return 0, fmt.Errorf("could not resolve name to syscall: %q", name) + return 0, ErrSyscallDoesNotExist } return ScmpSyscall(result), nil @@ -422,7 +530,7 @@ func GetSyscallFromNameByArch(name string, arch ScmpArch) (ScmpSyscall, error) { result := C.seccomp_syscall_resolve_name_arch(arch.toNative(), cString) if result == scmpError { - return 0, fmt.Errorf("could not resolve name to syscall: %q on %v", name, arch) + return 0, ErrSyscallDoesNotExist } return ScmpSyscall(result), nil @@ -495,11 +603,10 @@ type ScmpFilter struct { lock sync.Mutex } -// NewFilter creates and returns a new filter context. -// Accepts a default action to be taken for syscalls which match no rules in -// the filter. -// Returns a reference to a valid filter context, or nil and an error if the -// filter context could not be created or an invalid default action was given. +// NewFilter creates and returns a new filter context. Accepts a default action to be +// taken for syscalls which match no rules in the filter. +// Returns a reference to a valid filter context, or nil and an error +// if the filter context could not be created or an invalid default action was given. func NewFilter(defaultAction ScmpAction) (*ScmpFilter, error) { if err := ensureSupportedVersion(); err != nil { return nil, err @@ -519,8 +626,8 @@ func NewFilter(defaultAction ScmpAction) (*ScmpFilter, error) { filter.valid = true runtime.SetFinalizer(filter, filterFinalizer) - // Enable TSync so all goroutines will receive the same rules - // If the kernel does not support TSYNC, allow us to continue without error + // Enable TSync so all goroutines will receive the same rules. + // If the kernel does not support TSYNC, allow us to continue without error. if err := filter.setFilterAttr(filterAttrTsync, 0x1); err != nil && err != syscall.ENOTSUP { filter.Release() return nil, fmt.Errorf("could not create filter - error setting tsync bit: %v", err) @@ -552,9 +659,8 @@ func (f *ScmpFilter) Reset(defaultAction ScmpAction) error { return errBadFilter } - retCode := C.seccomp_reset(f.filterCtx, defaultAction.toNative()) - if retCode != 0 { - return syscall.Errno(-1 * retCode) + if retCode := C.seccomp_reset(f.filterCtx, defaultAction.toNative()); retCode != 0 { + return errRc(retCode) } return nil @@ -600,11 +706,12 @@ func (f *ScmpFilter) Merge(src *ScmpFilter) error { } // Merge the filters - retCode := C.seccomp_merge(f.filterCtx, src.filterCtx) - if syscall.Errno(-1*retCode) == syscall.EINVAL { - return fmt.Errorf("filters could not be merged due to a mismatch in attributes or invalid filter") - } else if retCode != 0 { - return syscall.Errno(-1 * retCode) + if retCode := C.seccomp_merge(f.filterCtx, src.filterCtx); retCode != 0 { + e := errRc(retCode) + if e == syscall.EINVAL { + return fmt.Errorf("filters could not be merged due to a mismatch in attributes or invalid filter") + } + return e } src.valid = false @@ -633,12 +740,13 @@ func (f *ScmpFilter) IsArchPresent(arch ScmpArch) (bool, error) { return false, errBadFilter } - retCode := C.seccomp_arch_exist(f.filterCtx, arch.toNative()) - if syscall.Errno(-1*retCode) == syscall.EEXIST { - // -EEXIST is "arch not present" - return false, nil - } else if retCode != 0 { - return false, syscall.Errno(-1 * retCode) + if retCode := C.seccomp_arch_exist(f.filterCtx, arch.toNative()); retCode != 0 { + e := errRc(retCode) + if e == syscall.EEXIST { + // -EEXIST is "arch not present" + return false, nil + } + return false, e } return true, nil @@ -661,9 +769,10 @@ func (f *ScmpFilter) AddArch(arch ScmpArch) error { // Libseccomp returns -EEXIST if the specified architecture is already // present. Succeed silently in this case, as it's not fatal, and the // architecture is present already. - retCode := C.seccomp_arch_add(f.filterCtx, arch.toNative()) - if retCode != 0 && syscall.Errno(-1*retCode) != syscall.EEXIST { - return syscall.Errno(-1 * retCode) + if retCode := C.seccomp_arch_add(f.filterCtx, arch.toNative()); retCode != 0 { + if e := errRc(retCode); e != syscall.EEXIST { + return e + } } return nil @@ -686,9 +795,10 @@ func (f *ScmpFilter) RemoveArch(arch ScmpArch) error { // Similar to AddArch, -EEXIST is returned if the arch is not present // Succeed silently in that case, this is not fatal and the architecture // is not present in the filter after RemoveArch - retCode := C.seccomp_arch_remove(f.filterCtx, arch.toNative()) - if retCode != 0 && syscall.Errno(-1*retCode) != syscall.EEXIST { - return syscall.Errno(-1 * retCode) + if retCode := C.seccomp_arch_remove(f.filterCtx, arch.toNative()); retCode != 0 { + if e := errRc(retCode); e != syscall.EEXIST { + return e + } } return nil @@ -705,7 +815,7 @@ func (f *ScmpFilter) Load() error { } if retCode := C.seccomp_load(f.filterCtx); retCode != 0 { - return syscall.Errno(-1 * retCode) + return errRc(retCode) } return nil @@ -764,8 +874,9 @@ func (f *ScmpFilter) GetNoNewPrivsBit() (bool, error) { func (f *ScmpFilter) GetLogBit() (bool, error) { log, err := f.getFilterAttr(filterAttrLog) if err != nil { - api, apiErr := getApi() - if (apiErr != nil && api == 0) || (apiErr == nil && api < 3) { + // Ignore error, if not supported returns apiLevel == 0 + apiLevel, _ := GetAPI() + if apiLevel < 3 { return false, fmt.Errorf("getting the log bit is only supported in libseccomp 2.4.0 and newer with API level 3 or higher") } @@ -779,6 +890,30 @@ func (f *ScmpFilter) GetLogBit() (bool, error) { return true, nil } +// GetSSB returns the current state the SSB bit will be set to on the filter +// being loaded, or an error if an issue was encountered retrieving the value. +// The SSB bit tells the kernel that a seccomp user is not interested in enabling +// Speculative Store Bypass mitigation. +// The SSB bit is only usable when libseccomp API level 4 or higher is +// supported. +func (f *ScmpFilter) GetSSB() (bool, error) { + ssb, err := f.getFilterAttr(filterAttrSSB) + if err != nil { + api, apiErr := getAPI() + if (apiErr != nil && api == 0) || (apiErr == nil && api < 4) { + return false, fmt.Errorf("getting the SSB flag is only supported in libseccomp 2.5.0 and newer with API level 4 or higher") + } + + return false, err + } + + if ssb == 0 { + return false, nil + } + + return true, nil +} + // SetBadArchAction sets the default action taken on a syscall for an // architecture not in the filter, or an error if an issue was encountered // setting the value. @@ -818,8 +953,9 @@ func (f *ScmpFilter) SetLogBit(state bool) error { err := f.setFilterAttr(filterAttrLog, toSet) if err != nil { - api, apiErr := getApi() - if (apiErr != nil && api == 0) || (apiErr == nil && api < 3) { + // Ignore error, if not supported returns apiLevel == 0 + apiLevel, _ := GetAPI() + if apiLevel < 3 { return fmt.Errorf("setting the log bit is only supported in libseccomp 2.4.0 and newer with API level 3 or higher") } } @@ -827,6 +963,28 @@ func (f *ScmpFilter) SetLogBit(state bool) error { return err } +// SetSSB sets the state of the SSB bit, which will be applied on filter +// load, or an error if an issue was encountered setting the value. +// The SSB bit is only usable when libseccomp API level 4 or higher is +// supported. +func (f *ScmpFilter) SetSSB(state bool) error { + var toSet C.uint32_t = 0x0 + + if state { + toSet = 0x1 + } + + err := f.setFilterAttr(filterAttrSSB, toSet) + if err != nil { + api, apiErr := getAPI() + if (apiErr != nil && api == 0) || (apiErr == nil && api < 4) { + return fmt.Errorf("setting the SSB flag is only supported in libseccomp 2.5.0 and newer with API level 4 or higher") + } + } + + return err +} + // SetSyscallPriority sets a syscall's priority. // This provides a hint to the filter generator in libseccomp about the // importance of this syscall. High-priority syscalls are placed @@ -842,7 +1000,7 @@ func (f *ScmpFilter) SetSyscallPriority(call ScmpSyscall, priority uint8) error if retCode := C.seccomp_syscall_priority(f.filterCtx, C.int(call), C.uint8_t(priority)); retCode != 0 { - return syscall.Errno(-1 * retCode) + return errRc(retCode) } return nil @@ -907,7 +1065,7 @@ func (f *ScmpFilter) ExportPFC(file *os.File) error { } if retCode := C.seccomp_export_pfc(f.filterCtx, C.int(fd)); retCode != 0 { - return syscall.Errno(-1 * retCode) + return errRc(retCode) } return nil @@ -928,8 +1086,41 @@ func (f *ScmpFilter) ExportBPF(file *os.File) error { } if retCode := C.seccomp_export_bpf(f.filterCtx, C.int(fd)); retCode != 0 { - return syscall.Errno(-1 * retCode) + return errRc(retCode) } return nil } + +// Userspace Notification API + +// GetNotifFd returns the userspace notification file descriptor associated with the given +// filter context. Such a file descriptor is only valid after the filter has been loaded +// and only when the filter uses the ActNotify action. The file descriptor can be used to +// retrieve and respond to notifications associated with the filter (see NotifReceive(), +// NotifRespond(), and NotifIDValid()). +func (f *ScmpFilter) GetNotifFd() (ScmpFd, error) { + return f.getNotifFd() +} + +// NotifReceive retrieves a seccomp userspace notification from a filter whose ActNotify +// action has triggered. The caller is expected to process the notification and return a +// response via NotifRespond(). Each invocation of this function returns one +// notification. As multiple notifications may be pending at any time, this function is +// normally called within a polling loop. +func NotifReceive(fd ScmpFd) (*ScmpNotifReq, error) { + return notifReceive(fd) +} + +// NotifRespond responds to a notification retrieved via NotifReceive(). The response Id +// must match that of the corresponding notification retrieved via NotifReceive(). +func NotifRespond(fd ScmpFd, scmpResp *ScmpNotifResp) error { + return notifRespond(fd, scmpResp) +} + +// NotifIDValid checks if a notification is still valid. An return value of nil means the +// notification is still valid. Otherwise the notification is not valid. This can be used +// to mitigate time-of-check-time-of-use (TOCTOU) attacks as described in seccomp_notify_id_valid(2). +func NotifIDValid(fd ScmpFd, id uint64) error { + return notifIDValid(fd, id) +} diff --git a/vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go b/vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go index 4e36b27ae8065..8dc7b296f3bc2 100644 --- a/vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go +++ b/vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go @@ -14,6 +14,13 @@ import ( // Get the seccomp header in scope // Need stdlib.h for free() on cstrings +// To compile libseccomp-golang against a specific version of libseccomp: +// cd ../libseccomp && mkdir -p prefix +// ./configure --prefix=$PWD/prefix && make && make install +// cd ../libseccomp-golang +// PKG_CONFIG_PATH=$PWD/../libseccomp/prefix/lib/pkgconfig/ make +// LD_PRELOAD=$PWD/../libseccomp/prefix/lib/libseccomp.so.2.5.0 PKG_CONFIG_PATH=$PWD/../libseccomp/prefix/lib/pkgconfig/ make test + // #cgo pkg-config: libseccomp /* #include @@ -50,6 +57,14 @@ const uint32_t C_ARCH_BAD = ARCH_BAD; #define SCMP_ARCH_S390X ARCH_BAD #endif +#ifndef SCMP_ARCH_PARISC +#define SCMP_ARCH_PARISC ARCH_BAD +#endif + +#ifndef SCMP_ARCH_PARISC64 +#define SCMP_ARCH_PARISC64 ARCH_BAD +#endif + const uint32_t C_ARCH_NATIVE = SCMP_ARCH_NATIVE; const uint32_t C_ARCH_X86 = SCMP_ARCH_X86; const uint32_t C_ARCH_X86_64 = SCMP_ARCH_X86_64; @@ -67,17 +82,34 @@ const uint32_t C_ARCH_PPC64 = SCMP_ARCH_PPC64; const uint32_t C_ARCH_PPC64LE = SCMP_ARCH_PPC64LE; const uint32_t C_ARCH_S390 = SCMP_ARCH_S390; const uint32_t C_ARCH_S390X = SCMP_ARCH_S390X; +const uint32_t C_ARCH_PARISC = SCMP_ARCH_PARISC; +const uint32_t C_ARCH_PARISC64 = SCMP_ARCH_PARISC64; #ifndef SCMP_ACT_LOG #define SCMP_ACT_LOG 0x7ffc0000U #endif +#ifndef SCMP_ACT_KILL_PROCESS +#define SCMP_ACT_KILL_PROCESS 0x80000000U +#endif + +#ifndef SCMP_ACT_KILL_THREAD +#define SCMP_ACT_KILL_THREAD 0x00000000U +#endif + +#ifndef SCMP_ACT_NOTIFY +#define SCMP_ACT_NOTIFY 0x7fc00000U +#endif + const uint32_t C_ACT_KILL = SCMP_ACT_KILL; +const uint32_t C_ACT_KILL_PROCESS = SCMP_ACT_KILL_PROCESS; +const uint32_t C_ACT_KILL_THREAD = SCMP_ACT_KILL_THREAD; const uint32_t C_ACT_TRAP = SCMP_ACT_TRAP; const uint32_t C_ACT_ERRNO = SCMP_ACT_ERRNO(0); const uint32_t C_ACT_TRACE = SCMP_ACT_TRACE(0); const uint32_t C_ACT_LOG = SCMP_ACT_LOG; const uint32_t C_ACT_ALLOW = SCMP_ACT_ALLOW; +const uint32_t C_ACT_NOTIFY = SCMP_ACT_NOTIFY; // The libseccomp SCMP_FLTATR_CTL_LOG member of the scmp_filter_attr enum was // added in v2.4.0 @@ -85,12 +117,16 @@ const uint32_t C_ACT_ALLOW = SCMP_ACT_ALLOW; (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 4) #define SCMP_FLTATR_CTL_LOG _SCMP_FLTATR_MIN #endif +#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 5 +#define SCMP_FLTATR_CTL_SSB _SCMP_FLTATR_MIN +#endif const uint32_t C_ATTRIBUTE_DEFAULT = (uint32_t)SCMP_FLTATR_ACT_DEFAULT; const uint32_t C_ATTRIBUTE_BADARCH = (uint32_t)SCMP_FLTATR_ACT_BADARCH; const uint32_t C_ATTRIBUTE_NNP = (uint32_t)SCMP_FLTATR_CTL_NNP; const uint32_t C_ATTRIBUTE_TSYNC = (uint32_t)SCMP_FLTATR_CTL_TSYNC; const uint32_t C_ATTRIBUTE_LOG = (uint32_t)SCMP_FLTATR_CTL_LOG; +const uint32_t C_ATTRIBUTE_SSB = (uint32_t)SCMP_FLTATR_CTL_SSB; const int C_CMP_NE = (int)SCMP_CMP_NE; const int C_CMP_LT = (int)SCMP_CMP_LT; @@ -179,6 +215,51 @@ void add_struct_arg_cmp( return; } + +// The seccomp notify API functions were added in v2.5.0 +#if (SCMP_VER_MAJOR < 2) || \ + (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 5) + +struct seccomp_data { + int nr; + __u32 arch; + __u64 instruction_pointer; + __u64 args[6]; +}; + +struct seccomp_notif { + __u64 id; + __u32 pid; + __u32 flags; + struct seccomp_data data; +}; + +struct seccomp_notif_resp { + __u64 id; + __s64 val; + __s32 error; + __u32 flags; +}; + +int seccomp_notify_alloc(struct seccomp_notif **req, struct seccomp_notif_resp **resp) { + return -EOPNOTSUPP; +} +int seccomp_notify_fd(const scmp_filter_ctx ctx) { + return -EOPNOTSUPP; +} +void seccomp_notify_free(struct seccomp_notif *req, struct seccomp_notif_resp *resp) { +} +int seccomp_notify_id_valid(int fd, uint64_t id) { + return -EOPNOTSUPP; +} +int seccomp_notify_receive(int fd, struct seccomp_notif *req) { + return -EOPNOTSUPP; +} +int seccomp_notify_respond(int fd, struct seccomp_notif_resp *resp) { + return -EOPNOTSUPP; +} + +#endif */ import "C" @@ -193,6 +274,7 @@ const ( filterAttrNNP scmpFilterAttr = iota filterAttrTsync scmpFilterAttr = iota filterAttrLog scmpFilterAttr = iota + filterAttrSSB scmpFilterAttr = iota ) const ( @@ -200,10 +282,10 @@ const ( scmpError C.int = -1 // Comparison boundaries to check for architecture validity archStart ScmpArch = ArchNative - archEnd ScmpArch = ArchS390X + archEnd ScmpArch = ArchPARISC64 // Comparison boundaries to check for action validity actionStart ScmpAction = ActKill - actionEnd ScmpAction = ActLog + actionEnd ScmpAction = ActKillProcess // Comparison boundaries to check for comparison operator validity compareOpStart ScmpCompareOp = CompareNotEqual compareOpEnd ScmpCompareOp = CompareMaskedEqual @@ -236,7 +318,7 @@ func ensureSupportedVersion() error { } // Get the API level -func getApi() (uint, error) { +func getAPI() (uint, error) { api := C.seccomp_api_get() if api == 0 { return 0, fmt.Errorf("API level operations are not supported") @@ -246,9 +328,9 @@ func getApi() (uint, error) { } // Set the API level -func setApi(api uint) error { +func setAPI(api uint) error { if retCode := C.seccomp_api_set(C.uint(api)); retCode != 0 { - if syscall.Errno(-1*retCode) == syscall.EOPNOTSUPP { + if errRc(retCode) == syscall.EOPNOTSUPP { return fmt.Errorf("API level operations are not supported") } @@ -265,6 +347,10 @@ func filterFinalizer(f *ScmpFilter) { f.Release() } +func errRc(rc C.int) error { + return syscall.Errno(-1 * rc) +} + // Get a raw filter attribute func (f *ScmpFilter) getFilterAttr(attr scmpFilterAttr) (C.uint32_t, error) { f.lock.Lock() @@ -278,7 +364,7 @@ func (f *ScmpFilter) getFilterAttr(attr scmpFilterAttr) (C.uint32_t, error) { retCode := C.seccomp_attr_get(f.filterCtx, attr.toNative(), &attribute) if retCode != 0 { - return 0x0, syscall.Errno(-1 * retCode) + return 0x0, errRc(retCode) } return attribute, nil @@ -295,7 +381,7 @@ func (f *ScmpFilter) setFilterAttr(attr scmpFilterAttr, value C.uint32_t) error retCode := C.seccomp_attr_set(f.filterCtx, attr.toNative(), value) if retCode != 0 { - return syscall.Errno(-1 * retCode) + return errRc(retCode) } return nil @@ -316,14 +402,17 @@ func (f *ScmpFilter) addRuleWrapper(call ScmpSyscall, action ScmpAction, exact b retCode = C.seccomp_rule_add_array(f.filterCtx, action.toNative(), C.int(call), length, cond) } - if syscall.Errno(-1*retCode) == syscall.EFAULT { - return fmt.Errorf("unrecognized syscall %#x", int32(call)) - } else if syscall.Errno(-1*retCode) == syscall.EPERM { - return fmt.Errorf("requested action matches default action of filter") - } else if syscall.Errno(-1*retCode) == syscall.EINVAL { - return fmt.Errorf("two checks on same syscall argument") - } else if retCode != 0 { - return syscall.Errno(-1 * retCode) + if retCode != 0 { + switch e := errRc(retCode); e { + case syscall.EFAULT: + return fmt.Errorf("unrecognized syscall %#x", int32(call)) + case syscall.EPERM: + return fmt.Errorf("requested action matches default action of filter") + case syscall.EINVAL: + return fmt.Errorf("two checks on same syscall argument") + default: + return e + } } return nil @@ -443,6 +532,10 @@ func archFromNative(a C.uint32_t) (ScmpArch, error) { return ArchS390, nil case C.C_ARCH_S390X: return ArchS390X, nil + case C.C_ARCH_PARISC: + return ArchPARISC, nil + case C.C_ARCH_PARISC64: + return ArchPARISC64, nil default: return 0x0, fmt.Errorf("unrecognized architecture %#x", uint32(a)) } @@ -483,6 +576,10 @@ func (a ScmpArch) toNative() C.uint32_t { return C.C_ARCH_S390 case ArchS390X: return C.C_ARCH_S390X + case ArchPARISC: + return C.C_ARCH_PARISC + case ArchPARISC64: + return C.C_ARCH_PARISC64 case ArchNative: return C.C_ARCH_NATIVE default: @@ -517,6 +614,10 @@ func actionFromNative(a C.uint32_t) (ScmpAction, error) { switch a & 0xFFFF0000 { case C.C_ACT_KILL: return ActKill, nil + case C.C_ACT_KILL_PROCESS: + return ActKillProcess, nil + case C.C_ACT_KILL_THREAD: + return ActKillThread, nil case C.C_ACT_TRAP: return ActTrap, nil case C.C_ACT_ERRNO: @@ -527,6 +628,8 @@ func actionFromNative(a C.uint32_t) (ScmpAction, error) { return ActLog, nil case C.C_ACT_ALLOW: return ActAllow, nil + case C.C_ACT_NOTIFY: + return ActNotify, nil default: return 0x0, fmt.Errorf("unrecognized action %#x", uint32(a)) } @@ -537,6 +640,10 @@ func (a ScmpAction) toNative() C.uint32_t { switch a & 0xFFFF { case ActKill: return C.C_ACT_KILL + case ActKillProcess: + return C.C_ACT_KILL_PROCESS + case ActKillThread: + return C.C_ACT_KILL_THREAD case ActTrap: return C.C_ACT_TRAP case ActErrno: @@ -547,6 +654,8 @@ func (a ScmpAction) toNative() C.uint32_t { return C.C_ACT_LOG case ActAllow: return C.C_ACT_ALLOW + case ActNotify: + return C.C_ACT_NOTIFY default: return 0x0 } @@ -565,7 +674,181 @@ func (a scmpFilterAttr) toNative() uint32 { return uint32(C.C_ATTRIBUTE_TSYNC) case filterAttrLog: return uint32(C.C_ATTRIBUTE_LOG) + case filterAttrSSB: + return uint32(C.C_ATTRIBUTE_SSB) default: return 0x0 } } + +func (a ScmpSyscall) toNative() C.uint32_t { + return C.uint32_t(a) +} + +func syscallFromNative(a C.int) ScmpSyscall { + return ScmpSyscall(a) +} + +func notifReqFromNative(req *C.struct_seccomp_notif) (*ScmpNotifReq, error) { + scmpArgs := make([]uint64, 6) + for i := 0; i < len(scmpArgs); i++ { + scmpArgs[i] = uint64(req.data.args[i]) + } + + arch, err := archFromNative(req.data.arch) + if err != nil { + return nil, err + } + + scmpData := ScmpNotifData{ + Syscall: syscallFromNative(req.data.nr), + Arch: arch, + InstrPointer: uint64(req.data.instruction_pointer), + Args: scmpArgs, + } + + scmpReq := &ScmpNotifReq{ + ID: uint64(req.id), + Pid: uint32(req.pid), + Flags: uint32(req.flags), + Data: scmpData, + } + + return scmpReq, nil +} + +func (scmpResp *ScmpNotifResp) toNative(resp *C.struct_seccomp_notif_resp) { + resp.id = C.__u64(scmpResp.ID) + resp.val = C.__s64(scmpResp.Val) + resp.error = (C.__s32(scmpResp.Error) * -1) // kernel requires a negated value + resp.flags = C.__u32(scmpResp.Flags) +} + +// Userspace Notification API +// Calls to C.seccomp_notify* hidden from seccomp.go + +func (f *ScmpFilter) getNotifFd() (ScmpFd, error) { + f.lock.Lock() + defer f.lock.Unlock() + + if !f.valid { + return -1, errBadFilter + } + + // Ignore error, if not supported returns apiLevel == 0 + apiLevel, _ := GetAPI() + if apiLevel < 6 { + return -1, fmt.Errorf("seccomp notification requires API level >= 6; current level = %d", apiLevel) + } + + fd := C.seccomp_notify_fd(f.filterCtx) + + return ScmpFd(fd), nil +} + +func notifReceive(fd ScmpFd) (*ScmpNotifReq, error) { + var req *C.struct_seccomp_notif + var resp *C.struct_seccomp_notif_resp + + // Ignore error, if not supported returns apiLevel == 0 + apiLevel, _ := GetAPI() + if apiLevel < 6 { + return nil, fmt.Errorf("seccomp notification requires API level >= 6; current level = %d", apiLevel) + } + + // we only use the request here; the response is unused + if retCode := C.seccomp_notify_alloc(&req, &resp); retCode != 0 { + return nil, errRc(retCode) + } + + defer func() { + C.seccomp_notify_free(req, resp) + }() + + for { + retCode, errno := C.seccomp_notify_receive(C.int(fd), req) + if retCode == 0 { + break + } + + if errno == syscall.EINTR { + continue + } + + if errno == syscall.ENOENT { + return nil, errno + } + + return nil, errRc(retCode) + } + + return notifReqFromNative(req) +} + +func notifRespond(fd ScmpFd, scmpResp *ScmpNotifResp) error { + var req *C.struct_seccomp_notif + var resp *C.struct_seccomp_notif_resp + + // Ignore error, if not supported returns apiLevel == 0 + apiLevel, _ := GetAPI() + if apiLevel < 6 { + return fmt.Errorf("seccomp notification requires API level >= 6; current level = %d", apiLevel) + } + + // we only use the reponse here; the request is discarded + if retCode := C.seccomp_notify_alloc(&req, &resp); retCode != 0 { + return errRc(retCode) + } + + defer func() { + C.seccomp_notify_free(req, resp) + }() + + scmpResp.toNative(resp) + + for { + retCode, errno := C.seccomp_notify_respond(C.int(fd), resp) + if retCode == 0 { + break + } + + if errno == syscall.EINTR { + continue + } + + if errno == syscall.ENOENT { + return errno + } + + return errRc(retCode) + } + + return nil +} + +func notifIDValid(fd ScmpFd, id uint64) error { + // Ignore error, if not supported returns apiLevel == 0 + apiLevel, _ := GetAPI() + if apiLevel < 6 { + return fmt.Errorf("seccomp notification requires API level >= 6; current level = %d", apiLevel) + } + + for { + retCode, errno := C.seccomp_notify_id_valid(C.int(fd), C.uint64_t(id)) + if retCode == 0 { + break + } + + if errno == syscall.EINTR { + continue + } + + if errno == syscall.ENOENT { + return errno + } + + return errRc(retCode) + } + + return nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 46f7a038d0b69..ad58af5b13b0b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -150,8 +150,6 @@ github.com/aws/aws-sdk-go/service/sts github.com/aws/aws-sdk-go/service/sts/stsiface # github.com/beorn7/perks v1.0.1 => github.com/beorn7/perks v1.0.1 github.com/beorn7/perks/quantile -# github.com/bits-and-blooms/bitset v1.2.0 => github.com/bits-and-blooms/bitset v1.2.0 -github.com/bits-and-blooms/bitset # github.com/blang/semver v3.5.1+incompatible => github.com/blang/semver v3.5.1+incompatible ## explicit github.com/blang/semver @@ -164,10 +162,10 @@ github.com/chai2010/gettext-go/gettext github.com/chai2010/gettext-go/gettext/mo github.com/chai2010/gettext-go/gettext/plural github.com/chai2010/gettext-go/gettext/po -# github.com/checkpoint-restore/go-criu/v5 v5.0.0 => github.com/checkpoint-restore/go-criu/v5 v5.0.0 +# github.com/checkpoint-restore/go-criu/v5 v5.3.0 => github.com/checkpoint-restore/go-criu/v5 v5.3.0 github.com/checkpoint-restore/go-criu/v5 github.com/checkpoint-restore/go-criu/v5/rpc -# github.com/cilium/ebpf v0.6.2 => github.com/cilium/ebpf v0.6.2 +# github.com/cilium/ebpf v0.7.0 => github.com/cilium/ebpf v0.7.0 github.com/cilium/ebpf github.com/cilium/ebpf/asm github.com/cilium/ebpf/internal @@ -182,9 +180,9 @@ github.com/clusterhq/flocker-go github.com/container-storage-interface/spec/lib/go/csi # github.com/containerd/cgroups v1.0.1 => github.com/containerd/cgroups v1.0.1 github.com/containerd/cgroups/stats/v1 -# github.com/containerd/console v1.0.2 => github.com/containerd/console v1.0.2 +# github.com/containerd/console v1.0.3 => github.com/containerd/console v1.0.3 github.com/containerd/console -# github.com/containerd/containerd v1.4.11 => github.com/containerd/containerd v1.4.11 +# github.com/containerd/containerd v1.4.12 => github.com/containerd/containerd v1.4.12 github.com/containerd/containerd/api/services/containers/v1 github.com/containerd/containerd/api/services/tasks/v1 github.com/containerd/containerd/api/services/version/v1 @@ -213,7 +211,7 @@ github.com/coreos/go-systemd/v22/util # github.com/cpuguy83/go-md2man/v2 v2.0.0 => github.com/cpuguy83/go-md2man/v2 v2.0.0 ## explicit github.com/cpuguy83/go-md2man/v2/md2man -# github.com/cyphar/filepath-securejoin v0.2.2 => github.com/cyphar/filepath-securejoin v0.2.2 +# github.com/cyphar/filepath-securejoin v0.2.3 => github.com/cyphar/filepath-securejoin v0.2.3 github.com/cyphar/filepath-securejoin # github.com/davecgh/go-spew v1.1.1 => github.com/davecgh/go-spew v1.1.1 ## explicit @@ -271,7 +269,7 @@ github.com/go-openapi/swag ## explicit github.com/go-ozzo/ozzo-validation github.com/go-ozzo/ozzo-validation/is -# github.com/godbus/dbus/v5 v5.0.4 => github.com/godbus/dbus/v5 v5.0.4 +# github.com/godbus/dbus/v5 v5.0.6 => github.com/godbus/dbus/v5 v5.0.6 ## explicit github.com/godbus/dbus/v5 # github.com/gofrs/uuid v4.0.0+incompatible => github.com/gofrs/uuid v4.0.0+incompatible @@ -324,7 +322,7 @@ github.com/golang/protobuf/ptypes/timestamp github.com/golang/protobuf/ptypes/wrappers # github.com/google/btree v1.0.1 => github.com/google/btree v1.0.1 github.com/google/btree -# github.com/google/cadvisor v0.43.0 => github.com/google/cadvisor v0.43.0 +# github.com/google/cadvisor v0.43.1-0.20220111033110-a3b5f4f6c501 => github.com/google/cadvisor v0.43.1-0.20220111033110-a3b5f4f6c501 ## explicit github.com/google/cadvisor/accelerators github.com/google/cadvisor/cache/memory @@ -520,7 +518,7 @@ github.com/moby/ipvs # github.com/moby/spdystream v0.2.0 => github.com/moby/spdystream v0.2.0 github.com/moby/spdystream github.com/moby/spdystream/spdy -# github.com/moby/sys/mountinfo v0.4.1 => github.com/moby/sys/mountinfo v0.4.1 +# github.com/moby/sys/mountinfo v0.5.0 => github.com/moby/sys/mountinfo v0.5.0 github.com/moby/sys/mountinfo # github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 => github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 github.com/moby/term @@ -597,7 +595,7 @@ github.com/onsi/gomega/matchers/support/goraph/util github.com/onsi/gomega/types # github.com/opencontainers/go-digest v1.0.0 => github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/go-digest -# github.com/opencontainers/runc v1.0.3 => github.com/opencontainers/runc v1.0.3 +# github.com/opencontainers/runc v1.1.0 => github.com/opencontainers/runc v1.1.0 ## explicit github.com/opencontainers/runc/libcontainer github.com/opencontainers/runc/libcontainer/apparmor @@ -609,6 +607,7 @@ github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter github.com/opencontainers/runc/libcontainer/cgroups/fs github.com/opencontainers/runc/libcontainer/cgroups/fs2 github.com/opencontainers/runc/libcontainer/cgroups/fscommon +github.com/opencontainers/runc/libcontainer/cgroups/manager github.com/opencontainers/runc/libcontainer/cgroups/systemd github.com/opencontainers/runc/libcontainer/configs github.com/opencontainers/runc/libcontainer/configs/validate @@ -618,7 +617,6 @@ github.com/opencontainers/runc/libcontainer/keys github.com/opencontainers/runc/libcontainer/logs github.com/opencontainers/runc/libcontainer/seccomp github.com/opencontainers/runc/libcontainer/seccomp/patchbpf -github.com/opencontainers/runc/libcontainer/stacktrace github.com/opencontainers/runc/libcontainer/system github.com/opencontainers/runc/libcontainer/user github.com/opencontainers/runc/libcontainer/userns @@ -626,11 +624,12 @@ github.com/opencontainers/runc/libcontainer/utils github.com/opencontainers/runc/types # github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 => github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 github.com/opencontainers/runtime-spec/specs-go -# github.com/opencontainers/selinux v1.8.2 => github.com/opencontainers/selinux v1.8.2 +# github.com/opencontainers/selinux v1.10.0 => github.com/opencontainers/selinux v1.10.0 ## explicit github.com/opencontainers/selinux/go-selinux github.com/opencontainers/selinux/go-selinux/label github.com/opencontainers/selinux/pkg/pwalk +github.com/opencontainers/selinux/pkg/pwalkdir # github.com/peterbourgon/diskv v2.0.1+incompatible => github.com/peterbourgon/diskv v2.0.1+incompatible github.com/peterbourgon/diskv # github.com/pkg/errors v0.9.1 => github.com/pkg/errors v0.9.1 @@ -673,7 +672,7 @@ github.com/rubiojr/go-vhd/vhd github.com/russross/blackfriday # github.com/russross/blackfriday/v2 v2.0.1 => github.com/russross/blackfriday/v2 v2.0.1 github.com/russross/blackfriday/v2 -# github.com/seccomp/libseccomp-golang v0.9.1 => github.com/seccomp/libseccomp-golang v0.9.1 +# github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921 => github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921 github.com/seccomp/libseccomp-golang # github.com/shurcooL/sanitized_anchor_name v1.0.0 => github.com/shurcooL/sanitized_anchor_name v1.0.0 github.com/shurcooL/sanitized_anchor_name @@ -2454,7 +2453,6 @@ sigs.k8s.io/yaml # github.com/benbjohnson/clock => github.com/benbjohnson/clock v1.1.0 # github.com/beorn7/perks => github.com/beorn7/perks v1.0.1 # github.com/bgentry/speakeasy => github.com/bgentry/speakeasy v0.1.0 -# github.com/bits-and-blooms/bitset => github.com/bits-and-blooms/bitset v1.2.0 # github.com/bketelsen/crypt => github.com/bketelsen/crypt v0.0.4 # github.com/blang/semver => github.com/blang/semver v3.5.1+incompatible # github.com/boltdb/bolt => github.com/boltdb/bolt v1.3.1 @@ -2463,11 +2461,11 @@ sigs.k8s.io/yaml # github.com/cespare/xxhash => github.com/cespare/xxhash v1.1.0 # github.com/cespare/xxhash/v2 => github.com/cespare/xxhash/v2 v2.1.2 # github.com/chai2010/gettext-go => github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 -# github.com/checkpoint-restore/go-criu/v5 => github.com/checkpoint-restore/go-criu/v5 v5.0.0 +# github.com/checkpoint-restore/go-criu/v5 => github.com/checkpoint-restore/go-criu/v5 v5.3.0 # github.com/chzyer/logex => github.com/chzyer/logex v1.1.10 # github.com/chzyer/readline => github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e # github.com/chzyer/test => github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 -# github.com/cilium/ebpf => github.com/cilium/ebpf v0.6.2 +# github.com/cilium/ebpf => github.com/cilium/ebpf v0.7.0 # github.com/clusterhq/flocker-go => github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313 # github.com/cncf/udpa/go => github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 # github.com/cncf/xds/go => github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed @@ -2476,8 +2474,8 @@ sigs.k8s.io/yaml # github.com/cockroachdb/logtags => github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f # github.com/container-storage-interface/spec => github.com/container-storage-interface/spec v1.5.0 # github.com/containerd/cgroups => github.com/containerd/cgroups v1.0.1 -# github.com/containerd/console => github.com/containerd/console v1.0.2 -# github.com/containerd/containerd => github.com/containerd/containerd v1.4.11 +# github.com/containerd/console => github.com/containerd/console v1.0.3 +# github.com/containerd/containerd => github.com/containerd/containerd v1.4.12 # github.com/containerd/continuity => github.com/containerd/continuity v0.1.0 # github.com/containerd/fifo => github.com/containerd/fifo v1.0.0 # github.com/containerd/go-runc => github.com/containerd/go-runc v1.0.0 @@ -2490,7 +2488,7 @@ sigs.k8s.io/yaml # github.com/coreos/go-systemd/v22 => github.com/coreos/go-systemd/v22 v22.3.2 # github.com/cpuguy83/go-md2man/v2 => github.com/cpuguy83/go-md2man/v2 v2.0.0 # github.com/creack/pty => github.com/creack/pty v1.1.11 -# github.com/cyphar/filepath-securejoin => github.com/cyphar/filepath-securejoin v0.2.2 +# github.com/cyphar/filepath-securejoin => github.com/cyphar/filepath-securejoin v0.2.3 # github.com/davecgh/go-spew => github.com/davecgh/go-spew v1.1.1 # github.com/daviddengcn/go-colortext => github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd # github.com/dnaeon/go-vcr => github.com/dnaeon/go-vcr v1.0.1 @@ -2531,7 +2529,7 @@ sigs.k8s.io/yaml # github.com/go-openapi/swag => github.com/go-openapi/swag v0.19.14 # 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/v5 => github.com/godbus/dbus/v5 v5.0.4 +# github.com/godbus/dbus/v5 => github.com/godbus/dbus/v5 v5.0.6 # github.com/gofrs/uuid => github.com/gofrs/uuid v4.0.0+incompatible # github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.2 # github.com/golang/freetype => github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 @@ -2541,7 +2539,7 @@ sigs.k8s.io/yaml # github.com/golang/protobuf => github.com/golang/protobuf v1.5.2 # github.com/golangplus/testing => github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e # github.com/google/btree => github.com/google/btree v1.0.1 -# github.com/google/cadvisor => github.com/google/cadvisor v0.43.0 +# github.com/google/cadvisor => github.com/google/cadvisor v0.43.1-0.20220111033110-a3b5f4f6c501 # github.com/google/cel-go => github.com/google/cel-go v0.9.0 # github.com/google/cel-spec => github.com/google/cel-spec v0.6.0 # github.com/google/go-cmp => github.com/google/go-cmp v0.5.5 @@ -2623,7 +2621,7 @@ sigs.k8s.io/yaml # github.com/mitchellh/mapstructure => github.com/mitchellh/mapstructure v1.4.1 # github.com/moby/ipvs => github.com/moby/ipvs v1.0.1 # github.com/moby/spdystream => github.com/moby/spdystream v0.2.0 -# github.com/moby/sys/mountinfo => github.com/moby/sys/mountinfo v0.4.1 +# github.com/moby/sys/mountinfo => github.com/moby/sys/mountinfo v0.5.0 # github.com/moby/term => github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 # github.com/modern-go/concurrent => github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd # github.com/modern-go/reflect2 => github.com/modern-go/reflect2 v1.0.2 @@ -2642,9 +2640,9 @@ sigs.k8s.io/yaml # github.com/onsi/gomega => github.com/onsi/gomega v1.10.1 # github.com/opencontainers/go-digest => github.com/opencontainers/go-digest v1.0.0 # github.com/opencontainers/image-spec => github.com/opencontainers/image-spec v1.0.1 -# github.com/opencontainers/runc => github.com/opencontainers/runc v1.0.3 +# github.com/opencontainers/runc => github.com/opencontainers/runc v1.1.0 # github.com/opencontainers/runtime-spec => github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 -# github.com/opencontainers/selinux => github.com/opencontainers/selinux v1.8.2 +# github.com/opencontainers/selinux => github.com/opencontainers/selinux v1.10.0 # github.com/opentracing/opentracing-go => github.com/opentracing/opentracing-go v1.1.0 # github.com/pascaldekloe/goe => github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c # github.com/pelletier/go-toml => github.com/pelletier/go-toml v1.9.3 @@ -2668,7 +2666,7 @@ sigs.k8s.io/yaml # github.com/russross/blackfriday/v2 => github.com/russross/blackfriday/v2 v2.0.1 # github.com/ryanuber/columnize => github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f # github.com/sean-/seed => github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 -# github.com/seccomp/libseccomp-golang => github.com/seccomp/libseccomp-golang v0.9.1 +# github.com/seccomp/libseccomp-golang => github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921 # github.com/sergi/go-diff => github.com/sergi/go-diff v1.1.0 # github.com/shurcooL/sanitized_anchor_name => github.com/shurcooL/sanitized_anchor_name v1.0.0 # github.com/sirupsen/logrus => github.com/sirupsen/logrus v1.8.1 From 7dcb5c1f6c935d01bb66f7c0f3f5efd52fba9955 Mon Sep 17 00:00:00 2001 From: Elana Hashman Date: Fri, 4 Feb 2022 15:26:34 -0800 Subject: [PATCH 2/5] Replace cadvisor with cadvisor#2974 for testing --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 99e533b3a7932..d6b6dffea7c5c 100644 --- a/go.mod +++ b/go.mod @@ -267,7 +267,7 @@ replace ( github.com/golang/protobuf => github.com/golang/protobuf v1.5.2 github.com/golangplus/testing => github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e github.com/google/btree => github.com/google/btree v1.0.1 - github.com/google/cadvisor => github.com/google/cadvisor v0.43.1-0.20220111033110-a3b5f4f6c501 + github.com/google/cadvisor => github.com/bwplotka/cadvisor v0.42.1-0.20220127113621-0d76a7d092f5 github.com/google/cel-go => github.com/google/cel-go v0.9.0 github.com/google/cel-spec => github.com/google/cel-spec v0.6.0 github.com/google/go-cmp => github.com/google/go-cmp v0.5.5 From 83de9d3d3c0aec2b465e5901fcf6dbf15ce72880 Mon Sep 17 00:00:00 2001 From: Elana Hashman Date: Fri, 4 Feb 2022 16:50:02 -0800 Subject: [PATCH 3/5] Bump prometheus/client_golang to experimental version --- go.mod | 4 ++-- staging/src/k8s.io/component-base/go.mod | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d6b6dffea7c5c..638328c6ba8c6 100644 --- a/go.mod +++ b/go.mod @@ -66,7 +66,7 @@ require ( github.com/opencontainers/selinux v1.10.0 github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.0 - github.com/prometheus/client_golang v1.12.0 + github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.32.1 github.com/quobyte/api v0.1.8 @@ -380,7 +380,7 @@ replace ( github.com/pmezard/go-difflib => github.com/pmezard/go-difflib v1.0.0 github.com/posener/complete => github.com/posener/complete v1.1.1 github.com/pquerna/cachecontrol => github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 - github.com/prometheus/client_golang => github.com/prometheus/client_golang v1.12.0 + github.com/prometheus/client_golang => github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b github.com/prometheus/client_model => github.com/prometheus/client_model v0.2.0 github.com/prometheus/common => github.com/prometheus/common v0.32.1 github.com/prometheus/procfs => github.com/prometheus/procfs v0.7.3 diff --git a/staging/src/k8s.io/component-base/go.mod b/staging/src/k8s.io/component-base/go.mod index 63c6d422dcf5b..1fbfa5af5ddcf 100644 --- a/staging/src/k8s.io/component-base/go.mod +++ b/staging/src/k8s.io/component-base/go.mod @@ -11,7 +11,7 @@ require ( github.com/google/go-cmp v0.5.5 github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 - github.com/prometheus/client_golang v1.12.0 + github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.32.1 github.com/prometheus/procfs v0.7.3 @@ -40,3 +40,7 @@ replace ( k8s.io/client-go => ../client-go k8s.io/component-base => ../component-base ) + +replace github.com/prometheus/common => github.com/prometheus/common v0.32.1 + +replace github.com/prometheus/client_golang => github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b From 477358e0e7b66a829c6b0b535e2d6f7f90291f5d Mon Sep 17 00:00:00 2001 From: Elana Hashman Date: Thu, 10 Feb 2022 14:22:16 -0800 Subject: [PATCH 4/5] Update vendor --- go.sum | 8 +- .../src/k8s.io/apiextensions-apiserver/go.sum | 4 +- staging/src/k8s.io/apiserver/go.sum | 4 +- staging/src/k8s.io/cloud-provider/go.sum | 4 +- staging/src/k8s.io/component-base/go.mod | 4 - staging/src/k8s.io/component-base/go.sum | 4 +- staging/src/k8s.io/controller-manager/go.sum | 4 +- staging/src/k8s.io/kube-aggregator/go.sum | 4 +- .../src/k8s.io/kube-controller-manager/go.sum | 2 +- staging/src/k8s.io/kube-proxy/go.sum | 2 +- staging/src/k8s.io/kube-scheduler/go.sum | 2 +- staging/src/k8s.io/kubectl/go.sum | 2 +- staging/src/k8s.io/kubelet/go.sum | 2 +- .../src/k8s.io/legacy-cloud-providers/go.sum | 4 +- .../src/k8s.io/pod-security-admission/go.sum | 4 +- staging/src/k8s.io/sample-apiserver/go.sum | 4 +- .../google/cadvisor/info/v2/container.go | 2 +- .../metrics/{prometheus.go => container.go} | 286 ++++--- .../google/cadvisor/metrics/fake.go | 760 ++++++++++++++++++ .../{prometheus_machine.go => machine.go} | 97 +-- .../google/cadvisor/metrics/metrics.go | 33 + .../cadvisor/metrics/prometheus_fake.go | 758 ----------------- .../client_golang/prometheus/cache/cache.go | 302 +++++++ .../client_golang/prometheus/collector.go | 8 + .../client_golang/prometheus/desc.go | 4 +- .../prometheus/go_collector_go117.go | 32 +- .../prometheus/internal/metric.go | 28 +- .../client_golang/prometheus/metric.go | 16 - .../client_golang/prometheus/promhttp/http.go | 8 +- .../client_golang/prometheus/registry.go | 101 ++- .../prometheus/testutil/testutil.go | 11 +- .../client_golang/prometheus/value.go | 44 +- .../client_golang/prometheus/wrap.go | 3 +- vendor/modules.txt | 9 +- 34 files changed, 1572 insertions(+), 988 deletions(-) rename vendor/github.com/google/cadvisor/metrics/{prometheus.go => container.go} (91%) create mode 100644 vendor/github.com/google/cadvisor/metrics/fake.go rename vendor/github.com/google/cadvisor/metrics/{prometheus_machine.go => machine.go} (82%) delete mode 100644 vendor/github.com/google/cadvisor/metrics/prometheus_fake.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/cache/cache.go diff --git a/go.sum b/go.sum index a174bea4f3942..a6ee15bb46478 100644 --- a/go.sum +++ b/go.sum @@ -75,6 +75,8 @@ github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdn github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/bwplotka/cadvisor v0.42.1-0.20220127113621-0d76a7d092f5 h1:qsbyj9LqSTULV4qyzwrJ/ngRUgiEwhJCbNCM1l7EmTo= +github.com/bwplotka/cadvisor v0.42.1-0.20220127113621-0d76a7d092f5/go.mod h1:TsLSsztaeSYE4689JMAMT1FY8zOS4hSo1KIrqp/kHBI= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= @@ -217,8 +219,6 @@ github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e h1:KhcknUwkWHKZ github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/cadvisor v0.43.1-0.20220111033110-a3b5f4f6c501 h1:0SFVx6FgKk/QYGEJmJku6FCtKTDHu0K7NdbuSGnikRI= -github.com/google/cadvisor v0.43.1-0.20220111033110-a3b5f4f6c501/go.mod h1:vFtK+TWeQTPT0AR+Y3lDVGl1TjQzpWEZELfHf8ZjAt4= github.com/google/cel-go v0.9.0 h1:u1hg7lcZ/XWw2d3aV1jFS30ijQQ6q0/h1C2ZBeBD1gY= github.com/google/cel-go v0.9.0/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= @@ -393,8 +393,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 h1:0XM1XL/OFFJjXsYXlG30spTkV/E9+gmd5GD1w2HE8xM= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b h1:g2Tda73CH6x7ISOwfeQhVxpFoNL+w6My8MLjFuv0bds= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= diff --git a/staging/src/k8s.io/apiextensions-apiserver/go.sum b/staging/src/k8s.io/apiextensions-apiserver/go.sum index 935470b54dff3..161a8fd3632bf 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/go.sum +++ b/staging/src/k8s.io/apiextensions-apiserver/go.sum @@ -411,8 +411,8 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b h1:g2Tda73CH6x7ISOwfeQhVxpFoNL+w6My8MLjFuv0bds= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= diff --git a/staging/src/k8s.io/apiserver/go.sum b/staging/src/k8s.io/apiserver/go.sum index 3fe1f54b93206..004b673f965e8 100644 --- a/staging/src/k8s.io/apiserver/go.sum +++ b/staging/src/k8s.io/apiserver/go.sum @@ -398,8 +398,8 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b h1:g2Tda73CH6x7ISOwfeQhVxpFoNL+w6My8MLjFuv0bds= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= diff --git a/staging/src/k8s.io/cloud-provider/go.sum b/staging/src/k8s.io/cloud-provider/go.sum index 6ce59bd17ece4..d5c09a312fd33 100644 --- a/staging/src/k8s.io/cloud-provider/go.sum +++ b/staging/src/k8s.io/cloud-provider/go.sum @@ -393,8 +393,8 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b h1:g2Tda73CH6x7ISOwfeQhVxpFoNL+w6My8MLjFuv0bds= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= diff --git a/staging/src/k8s.io/component-base/go.mod b/staging/src/k8s.io/component-base/go.mod index 1fbfa5af5ddcf..a868e9424eb4b 100644 --- a/staging/src/k8s.io/component-base/go.mod +++ b/staging/src/k8s.io/component-base/go.mod @@ -40,7 +40,3 @@ replace ( k8s.io/client-go => ../client-go k8s.io/component-base => ../component-base ) - -replace github.com/prometheus/common => github.com/prometheus/common v0.32.1 - -replace github.com/prometheus/client_golang => github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b diff --git a/staging/src/k8s.io/component-base/go.sum b/staging/src/k8s.io/component-base/go.sum index f4619d59a2d94..d4dd4091df036 100644 --- a/staging/src/k8s.io/component-base/go.sum +++ b/staging/src/k8s.io/component-base/go.sum @@ -330,8 +330,8 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b h1:g2Tda73CH6x7ISOwfeQhVxpFoNL+w6My8MLjFuv0bds= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= diff --git a/staging/src/k8s.io/controller-manager/go.sum b/staging/src/k8s.io/controller-manager/go.sum index 37037fabe2277..85aff3e18a273 100644 --- a/staging/src/k8s.io/controller-manager/go.sum +++ b/staging/src/k8s.io/controller-manager/go.sum @@ -482,8 +482,8 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b h1:g2Tda73CH6x7ISOwfeQhVxpFoNL+w6My8MLjFuv0bds= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= diff --git a/staging/src/k8s.io/kube-aggregator/go.sum b/staging/src/k8s.io/kube-aggregator/go.sum index 70970c3a82e90..b489720fb5adc 100644 --- a/staging/src/k8s.io/kube-aggregator/go.sum +++ b/staging/src/k8s.io/kube-aggregator/go.sum @@ -391,8 +391,8 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b h1:g2Tda73CH6x7ISOwfeQhVxpFoNL+w6My8MLjFuv0bds= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= diff --git a/staging/src/k8s.io/kube-controller-manager/go.sum b/staging/src/k8s.io/kube-controller-manager/go.sum index 487b1f5607052..f2ce6538390f9 100644 --- a/staging/src/k8s.io/kube-controller-manager/go.sum +++ b/staging/src/k8s.io/kube-controller-manager/go.sum @@ -348,7 +348,7 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= diff --git a/staging/src/k8s.io/kube-proxy/go.sum b/staging/src/k8s.io/kube-proxy/go.sum index 478e210171530..cdb86578ff052 100644 --- a/staging/src/k8s.io/kube-proxy/go.sum +++ b/staging/src/k8s.io/kube-proxy/go.sum @@ -309,7 +309,7 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= diff --git a/staging/src/k8s.io/kube-scheduler/go.sum b/staging/src/k8s.io/kube-scheduler/go.sum index 478e210171530..cdb86578ff052 100644 --- a/staging/src/k8s.io/kube-scheduler/go.sum +++ b/staging/src/k8s.io/kube-scheduler/go.sum @@ -309,7 +309,7 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= diff --git a/staging/src/k8s.io/kubectl/go.sum b/staging/src/k8s.io/kubectl/go.sum index 370606b6227d9..8c7822c011d1b 100644 --- a/staging/src/k8s.io/kubectl/go.sum +++ b/staging/src/k8s.io/kubectl/go.sum @@ -400,7 +400,7 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= diff --git a/staging/src/k8s.io/kubelet/go.sum b/staging/src/k8s.io/kubelet/go.sum index 173b68ad3be62..fade5f050366e 100644 --- a/staging/src/k8s.io/kubelet/go.sum +++ b/staging/src/k8s.io/kubelet/go.sum @@ -309,7 +309,7 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= diff --git a/staging/src/k8s.io/legacy-cloud-providers/go.sum b/staging/src/k8s.io/legacy-cloud-providers/go.sum index 9c13ea4e939f5..e547db7e7ee77 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/go.sum +++ b/staging/src/k8s.io/legacy-cloud-providers/go.sum @@ -395,8 +395,8 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b h1:g2Tda73CH6x7ISOwfeQhVxpFoNL+w6My8MLjFuv0bds= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= diff --git a/staging/src/k8s.io/pod-security-admission/go.sum b/staging/src/k8s.io/pod-security-admission/go.sum index 86a8d0aed7982..1626d3e59d308 100644 --- a/staging/src/k8s.io/pod-security-admission/go.sum +++ b/staging/src/k8s.io/pod-security-admission/go.sum @@ -390,8 +390,8 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b h1:g2Tda73CH6x7ISOwfeQhVxpFoNL+w6My8MLjFuv0bds= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= diff --git a/staging/src/k8s.io/sample-apiserver/go.sum b/staging/src/k8s.io/sample-apiserver/go.sum index 2e00ba966e568..53cadccac9685 100644 --- a/staging/src/k8s.io/sample-apiserver/go.sum +++ b/staging/src/k8s.io/sample-apiserver/go.sum @@ -390,8 +390,8 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b h1:g2Tda73CH6x7ISOwfeQhVxpFoNL+w6My8MLjFuv0bds= +github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= diff --git a/vendor/github.com/google/cadvisor/info/v2/container.go b/vendor/github.com/google/cadvisor/info/v2/container.go index 4ee3b81793917..da386bd5d3f7d 100644 --- a/vendor/github.com/google/cadvisor/info/v2/container.go +++ b/vendor/github.com/google/cadvisor/info/v2/container.go @@ -270,7 +270,7 @@ type RequestOptions struct { // Whether to include stats for child subcontainers. Recursive bool `json:"recursive"` // Update stats if they are older than MaxAge - // nil indicates no update, and 0 will always trigger an update. + // nil and 0 indicates always update. MaxAge *time.Duration `json:"max_age"` } diff --git a/vendor/github.com/google/cadvisor/metrics/prometheus.go b/vendor/github.com/google/cadvisor/metrics/container.go similarity index 91% rename from vendor/github.com/google/cadvisor/metrics/prometheus.go rename to vendor/github.com/google/cadvisor/metrics/container.go index 04c8d27e8f7bc..59158ba67f585 100644 --- a/vendor/github.com/google/cadvisor/metrics/prometheus.go +++ b/vendor/github.com/google/cadvisor/metrics/container.go @@ -17,18 +17,33 @@ package metrics import ( "fmt" "regexp" + "sort" "strconv" "time" "github.com/google/cadvisor/container" info "github.com/google/cadvisor/info/v1" v2 "github.com/google/cadvisor/info/v2" + "github.com/prometheus/client_golang/prometheus/cache" "github.com/prometheus/client_golang/prometheus" "k8s.io/klog/v2" "k8s.io/utils/clock" ) +const ( + // ContainerLabelPrefix is the prefix added to all container labels. + ContainerLabelPrefix = "container_label_" + // ContainerEnvPrefix is the prefix added to all env variable labels. + ContainerEnvPrefix = "container_env_" + // LabelID is the name of the id label. + LabelID = "id" + // LabelName is the name of the name label. + LabelName = "name" + // LabelImage is the name of the image label. + LabelImage = "image" +) + // asFloat64 converts a uint64 into a float64. func asFloat64(v uint64) float64 { return float64(v) } @@ -83,40 +98,33 @@ type containerMetric struct { getValues func(s *info.ContainerStats) metricValues } -func (cm *containerMetric) desc(baseLabels []string) *prometheus.Desc { - return prometheus.NewDesc(cm.name, cm.help, append(baseLabels, cm.extraLabels...), nil) -} - // ContainerLabelsFunc defines all base labels and their values attached to // each metric exported by cAdvisor. type ContainerLabelsFunc func(*info.ContainerInfo) map[string]string -// PrometheusCollector implements prometheus.Collector. -type PrometheusCollector struct { +// ContainerCollector allows updating prometheus cache.CachedTGatherer based on +// container data. +type ContainerCollector struct { infoProvider infoProvider - errors prometheus.Gauge containerMetrics []containerMetric containerLabelsFunc ContainerLabelsFunc includedMetrics container.MetricSet - opts v2.RequestOptions } -// NewPrometheusCollector returns a new PrometheusCollector. The passed +// NewContainerCollector returns a new ContainerCollector. The passed // ContainerLabelsFunc specifies which base labels will be attached to all // exported metrics. If left to nil, the DefaultContainerLabels function // will be used instead. -func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetrics container.MetricSet, now clock.Clock, opts v2.RequestOptions) *PrometheusCollector { +// TODO(bwplotka): Instead of basing on infoProvider which needs to converts state from watchers, +// instrument metrics cache updates directly in resource manager, whenever event occurs. +// This will make update process more CPU efficient. +func NewContainerCollector(i infoProvider, f ContainerLabelsFunc, includedMetrics container.MetricSet, now clock.Clock) *ContainerCollector { if f == nil { f = DefaultContainerLabels } - c := &PrometheusCollector{ + c := &ContainerCollector{ infoProvider: i, containerLabelsFunc: f, - errors: prometheus.NewGauge(prometheus.GaugeOpts{ - Namespace: "container", - Name: "scrape_error", - Help: "1 if there was an error while getting container metrics, 0 otherwise", - }), containerMetrics: []containerMetric{ { name: "container_last_seen", @@ -131,7 +139,6 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri }, }, includedMetrics: includedMetrics, - opts: opts, } if includedMetrics.Has(container.CpuUsageMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ @@ -1771,50 +1778,32 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri return c } -var ( - versionInfoDesc = prometheus.NewDesc("cadvisor_version_info", "A metric with a constant '1' value labeled by kernel version, OS version, docker version, cadvisor version & cadvisor revision.", []string{"kernelVersion", "osVersion", "dockerVersion", "cadvisorVersion", "cadvisorRevision"}, nil) - startTimeDesc = prometheus.NewDesc("container_start_time_seconds", "Start time of the container since unix epoch in seconds.", nil, nil) - cpuPeriodDesc = prometheus.NewDesc("container_spec_cpu_period", "CPU period of the container.", nil, nil) - cpuQuotaDesc = prometheus.NewDesc("container_spec_cpu_quota", "CPU quota of the container.", nil, nil) - cpuSharesDesc = prometheus.NewDesc("container_spec_cpu_shares", "CPU share of the container.", nil, nil) -) - -// Describe describes all the metrics ever exported by cadvisor. It -// implements prometheus.PrometheusCollector. -func (c *PrometheusCollector) Describe(ch chan<- *prometheus.Desc) { - c.errors.Describe(ch) - for _, cm := range c.containerMetrics { - ch <- cm.desc([]string{}) +// Collect fetches latest statistics about containers in form of prometheus cache inserts. +// Based on option it +// * ask the latest from provided services. +// * uses either docker or name ID. +func (c *ContainerCollector) Collect(opts v2.RequestOptions, inserts []cache.Insert) []cache.Insert { + errorsGauge := 0 + inserts, err := c.collectVersionInfo(inserts) + if err != nil { + errorsGauge = 1 + klog.Warningf("Couldn't get version info: %s", err) + } + inserts, err = c.collectContainersInfo(opts, inserts) + if err != nil { + errorsGauge = 1 + klog.Warningf("Couldn't get containers: %s", err) } - ch <- startTimeDesc - ch <- cpuPeriodDesc - ch <- cpuQuotaDesc - ch <- cpuSharesDesc - ch <- versionInfoDesc -} -// Collect fetches the stats from all containers and delivers them as -// Prometheus metrics. It implements prometheus.PrometheusCollector. -func (c *PrometheusCollector) Collect(ch chan<- prometheus.Metric) { - c.errors.Set(0) - c.collectVersionInfo(ch) - c.collectContainersInfo(ch) - c.errors.Collect(ch) + // TODO(bwplotka): Consider moving this to normal metric or returning error directly instead of metric. + return append(inserts, cache.Insert{ + Key: cache.Key{FQName: "container_scrape_error"}, + Help: "1 if there was an error while getting container metrics, 0 otherwise", + ValueType: prometheus.GaugeValue, + Value: float64(errorsGauge), + }) } -const ( - // ContainerLabelPrefix is the prefix added to all container labels. - ContainerLabelPrefix = "container_label_" - // ContainerEnvPrefix is the prefix added to all env variable labels. - ContainerEnvPrefix = "container_env_" - // LabelID is the name of the id label. - LabelID = "id" - // LabelName is the name of the name label. - LabelName = "name" - // LabelImage is the name of the image label. - LabelImage = "image" -) - // DefaultContainerLabels implements ContainerLabelsFunc. It exports the // container name, first alias, image name as well as all its env and label // values. @@ -1863,25 +1852,35 @@ func BaseContainerLabels(whiteList []string) func(container *info.ContainerInfo) } } -func (c *PrometheusCollector) collectContainersInfo(ch chan<- prometheus.Metric) { - containers, err := c.infoProvider.GetRequestedContainersInfo("/", c.opts) +func (c *ContainerCollector) collectContainersInfo(opts v2.RequestOptions, inserts []cache.Insert) ([]cache.Insert, error) { + containers, err := c.infoProvider.GetRequestedContainersInfo("/", opts) if err != nil { - c.errors.Set(1) - klog.Warningf("Couldn't get containers: %s", err) - return + return nil, err } - rawLabels := map[string]struct{}{} + + rawLabelsDup := map[string]struct{}{} for _, container := range containers { for l := range c.containerLabelsFunc(container) { - rawLabels[l] = struct{}{} + rawLabelsDup[l] = struct{}{} } } + rawLabels := make([]string, 0, len(rawLabelsDup)) + for r := range rawLabelsDup { + rawLabels = append(rawLabels, r) + } + sort.Strings(rawLabels) + + values := make([]string, 0, len(rawLabels)) + labels := make([]string, 0, len(rawLabels)) + + clabels := make([]string, 0, len(rawLabels)) + cvalues := make([]string, 0, len(rawLabels)) for _, cont := range containers { - values := make([]string, 0, len(rawLabels)) - labels := make([]string, 0, len(rawLabels)) + values := values[:0] + labels := labels[:0] containerLabels := c.containerLabelsFunc(cont) - for l := range rawLabels { + for _, l := range rawLabels { duplicate := false sl := sanitizeLabelName(l) for _, x := range labels { @@ -1896,31 +1895,83 @@ func (c *PrometheusCollector) collectContainersInfo(ch chan<- prometheus.Metric) } } - // Container spec - desc := prometheus.NewDesc("container_start_time_seconds", "Start time of the container since unix epoch in seconds.", labels, nil) - ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, float64(cont.Spec.CreationTime.Unix()), values...) + // Container spec. + inserts = append(inserts, cache.Insert{ + Key: cache.Key{ + FQName: "container_start_time_seconds", + LabelNames: labels, + LabelValues: values, + }, + Help: "Start time of the container since unix epoch in seconds.", + ValueType: prometheus.GaugeValue, + Value: float64(cont.Spec.CreationTime.Unix()), + }) if cont.Spec.HasCpu { - desc = prometheus.NewDesc("container_spec_cpu_period", "CPU period of the container.", labels, nil) - ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, float64(cont.Spec.Cpu.Period), values...) + inserts = append(inserts, cache.Insert{ + Key: cache.Key{ + FQName: "container_spec_cpu_period", + LabelNames: labels, + LabelValues: values, + }, + Help: "CPU period of the container.", + ValueType: prometheus.GaugeValue, + Value: float64(cont.Spec.Cpu.Period), + }) if cont.Spec.Cpu.Quota != 0 { - desc = prometheus.NewDesc("container_spec_cpu_quota", "CPU quota of the container.", labels, nil) - ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, float64(cont.Spec.Cpu.Quota), values...) + inserts = append(inserts, cache.Insert{ + Key: cache.Key{ + FQName: "container_spec_cpu_quota", + LabelNames: labels, + LabelValues: values, + }, + Help: "CPU quota of the container.", + ValueType: prometheus.GaugeValue, + Value: float64(cont.Spec.Cpu.Quota), + }) } - desc := prometheus.NewDesc("container_spec_cpu_shares", "CPU share of the container.", labels, nil) - ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, float64(cont.Spec.Cpu.Limit), values...) - + inserts = append(inserts, cache.Insert{ + Key: cache.Key{ + FQName: "container_spec_cpu_shares", + LabelNames: labels, + LabelValues: values, + }, + Help: "CPU share of the container.", + ValueType: prometheus.GaugeValue, + Value: float64(cont.Spec.Cpu.Limit), + }) } if cont.Spec.HasMemory { - desc := prometheus.NewDesc("container_spec_memory_limit_bytes", "Memory limit for the container.", labels, nil) - ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, specMemoryValue(cont.Spec.Memory.Limit), values...) - desc = prometheus.NewDesc("container_spec_memory_swap_limit_bytes", "Memory swap limit for the container.", labels, nil) - ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, specMemoryValue(cont.Spec.Memory.SwapLimit), values...) - desc = prometheus.NewDesc("container_spec_memory_reservation_limit_bytes", "Memory reservation limit for the container.", labels, nil) - ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, specMemoryValue(cont.Spec.Memory.Reservation), values...) + inserts = append(inserts, cache.Insert{ + Key: cache.Key{ + FQName: "container_spec_memory_limit_bytes", + LabelNames: labels, + LabelValues: values, + }, + Help: "Memory limit for the container.", + ValueType: prometheus.GaugeValue, + Value: specMemoryValue(cont.Spec.Memory.Limit), + }, cache.Insert{ + Key: cache.Key{ + FQName: "container_spec_memory_swap_limit_bytes", + LabelNames: labels, + LabelValues: values, + }, + Help: "Memory swap limit for the container.", + ValueType: prometheus.GaugeValue, + Value: specMemoryValue(cont.Spec.Memory.SwapLimit), + }, cache.Insert{ + Key: cache.Key{ + FQName: "container_spec_memory_reservation_limit_bytes", + LabelNames: labels, + LabelValues: values, + }, + Help: "Memory reservation limit for the container.", + ValueType: prometheus.GaugeValue, + Value: specMemoryValue(cont.Spec.Memory.Reservation), + }) } - // Now for the actual metrics if len(cont.Stats) == 0 { continue } @@ -1929,41 +1980,78 @@ func (c *PrometheusCollector) collectContainersInfo(ch chan<- prometheus.Metric) if cm.condition != nil && !cm.condition(cont.Spec) { continue } - desc := cm.desc(labels) for _, metricValue := range cm.getValues(stats) { - ch <- prometheus.NewMetricWithTimestamp( - metricValue.timestamp, - prometheus.MustNewConstMetric(desc, cm.valueType, float64(metricValue.value), append(values, metricValue.labels...)...), - ) + labels = append(labels, cm.extraLabels...) + values = append(values, metricValue.labels...) + + inserts = append(inserts, cache.Insert{ + Key: cache.Key{ + FQName: cm.name, + LabelNames: labels, + LabelValues: values, + }, + Help: cm.help, + ValueType: cm.valueType, + Value: metricValue.value, + Timestamp: &metricValue.timestamp, + }) + + labels = labels[:len(labels)-len(cm.extraLabels)] + values = values[:len(values)-len(metricValue.labels)] } } if c.includedMetrics.Has(container.AppMetrics) { - for metricLabel, v := range stats.CustomMetrics { + metricLabels := make([]string, 0, len(stats.CustomMetrics)) + for metricLabel := range stats.CustomMetrics { + metricLabels = append(metricLabels, metricLabel) + } + sort.Strings(metricLabels) + + for _, metricLabel := range metricLabels { + v := stats.CustomMetrics[metricLabel] for _, metric := range v { - clabels := make([]string, len(rawLabels), len(rawLabels)+len(metric.Labels)) - cvalues := make([]string, len(rawLabels), len(rawLabels)+len(metric.Labels)) + clabels = clabels[:len(rawLabels)] + cvalues = cvalues[:len(rawLabels)] copy(clabels, labels) copy(cvalues, values) for label, value := range metric.Labels { clabels = append(clabels, sanitizeLabelName("app_"+label)) cvalues = append(cvalues, value) } - desc := prometheus.NewDesc(metricLabel, "Custom application metric.", clabels, nil) - ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, float64(metric.FloatValue), cvalues...) + + inserts = append(inserts, cache.Insert{ + Key: cache.Key{ + FQName: metricLabel, + LabelNames: clabels, + LabelValues: cvalues, + }, + Help: "Custom application metric.", + ValueType: prometheus.GaugeValue, + Value: metric.FloatValue, + }) } } } } + return inserts, nil } -func (c *PrometheusCollector) collectVersionInfo(ch chan<- prometheus.Metric) { +func (c *ContainerCollector) collectVersionInfo(inserts []cache.Insert) ([]cache.Insert, error) { versionInfo, err := c.infoProvider.GetVersionInfo() if err != nil { - c.errors.Set(1) - klog.Warningf("Couldn't get version info: %s", err) - return + return nil, err } - ch <- prometheus.MustNewConstMetric(versionInfoDesc, prometheus.GaugeValue, 1, []string{versionInfo.KernelVersion, versionInfo.ContainerOsVersion, versionInfo.DockerVersion, versionInfo.CadvisorVersion, versionInfo.CadvisorRevision}...) + inserts = append(inserts, cache.Insert{ + Key: cache.Key{ + FQName: "cadvisor_version_info", + LabelNames: []string{"kernelVersion", "osVersion", "dockerVersion", "cadvisorVersion", "cadvisorRevision"}, + LabelValues: []string{versionInfo.KernelVersion, versionInfo.ContainerOsVersion, versionInfo.DockerVersion, versionInfo.CadvisorVersion, versionInfo.CadvisorRevision}, + }, + Help: "A metric with a constant '1' value labeled by kernel version, OS version, docker version, cadvisor version & cadvisor revision.", + ValueType: prometheus.GaugeValue, + Value: 1, + }) + return inserts, nil } // Size after which we consider memory to be "unlimited". This is not diff --git a/vendor/github.com/google/cadvisor/metrics/fake.go b/vendor/github.com/google/cadvisor/metrics/fake.go new file mode 100644 index 0000000000000..377c56f206717 --- /dev/null +++ b/vendor/github.com/google/cadvisor/metrics/fake.go @@ -0,0 +1,760 @@ +// Copyright 2020 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metrics + +import ( + "errors" + "time" + + info "github.com/google/cadvisor/info/v1" + v2 "github.com/google/cadvisor/info/v2" +) + +type testSubcontainersInfoProvider struct{} + +func (p testSubcontainersInfoProvider) GetVersionInfo() (*info.VersionInfo, error) { + return &info.VersionInfo{ + KernelVersion: "4.1.6-200.fc22.x86_64", + ContainerOsVersion: "Fedora 22 (Twenty Two)", + DockerVersion: "1.8.1", + CadvisorVersion: "0.16.0", + CadvisorRevision: "abcdef", + }, nil +} + +func (p testSubcontainersInfoProvider) GetMachineInfo() (*info.MachineInfo, error) { + return &info.MachineInfo{ + Timestamp: time.Unix(1395066363, 0), + NumCores: 4, + NumPhysicalCores: 1, + NumSockets: 1, + MemoryCapacity: 1024, + MemoryByType: map[string]*info.MemoryInfo{ + "Non-volatile-RAM": {Capacity: 2168421613568, DimmCount: 8}, + "Unbuffered-DDR4": {Capacity: 412316860416, DimmCount: 12}, + }, + NVMInfo: info.NVMInfo{ + MemoryModeCapacity: 429496729600, + AppDirectModeCapacity: 1735166787584, + }, + MachineID: "machine-id-test", + SystemUUID: "system-uuid-test", + BootID: "boot-id-test", + Topology: []info.Node{ + { + Id: 0, + Memory: 33604804608, + HugePages: []info.HugePagesInfo{ + { + PageSize: uint64(1048576), + NumPages: uint64(0), + }, + { + PageSize: uint64(2048), + NumPages: uint64(0), + }, + }, + Cores: []info.Core{ + { + Id: 0, + Threads: []int{0, 1}, + Caches: []info.Cache{ + { + Size: 32768, + Type: "Data", + Level: 1, + }, + { + Size: 32768, + Type: "Instruction", + Level: 1, + }, + { + Size: 262144, + Type: "Unified", + Level: 2, + }, + }, + }, + { + Id: 1, + Threads: []int{2, 3}, + Caches: []info.Cache{ + { + Size: 32764, + Type: "Data", + Level: 1, + }, + { + Size: 32764, + Type: "Instruction", + Level: 1, + }, + { + Size: 262148, + Type: "Unified", + Level: 2, + }, + }, + }, + + { + Id: 2, + Threads: []int{4, 5}, + Caches: []info.Cache{ + { + Size: 32768, + Type: "Data", + Level: 1, + }, + { + Size: 32768, + Type: "Instruction", + Level: 1, + }, + { + Size: 262144, + Type: "Unified", + Level: 2, + }, + }, + }, + { + Id: 3, + Threads: []int{6, 7}, + Caches: []info.Cache{ + { + Size: 32764, + Type: "Data", + Level: 1, + }, + { + Size: 32764, + Type: "Instruction", + Level: 1, + }, + { + Size: 262148, + Type: "Unified", + Level: 2, + }, + }, + }, + }, + }, + { + Id: 1, + Memory: 33604804606, + HugePages: []info.HugePagesInfo{ + { + PageSize: uint64(1048576), + NumPages: uint64(2), + }, + { + PageSize: uint64(2048), + NumPages: uint64(4), + }, + }, + Cores: []info.Core{ + { + Id: 4, + Threads: []int{8, 9}, + Caches: []info.Cache{ + { + Size: 32768, + Type: "Data", + Level: 1, + }, + { + Size: 32768, + Type: "Instruction", + Level: 1, + }, + { + Size: 262144, + Type: "Unified", + Level: 2, + }, + }, + }, + { + Id: 5, + Threads: []int{10, 11}, + Caches: []info.Cache{ + { + Size: 32764, + Type: "Data", + Level: 1, + }, + { + Size: 32764, + Type: "Instruction", + Level: 1, + }, + { + Size: 262148, + Type: "Unified", + Level: 2, + }, + }, + }, + { + Id: 6, + Threads: []int{12, 13}, + Caches: []info.Cache{ + { + Size: 32768, + Type: "Data", + Level: 1, + }, + { + Size: 32768, + Type: "Instruction", + Level: 1, + }, + { + Size: 262144, + Type: "Unified", + Level: 2, + }, + }, + }, + { + Id: 7, + Threads: []int{14, 15}, + Caches: []info.Cache{ + { + Size: 32764, + Type: "Data", + Level: 1, + }, + { + Size: 32764, + Type: "Instruction", + Level: 1, + }, + { + Size: 262148, + Type: "Unified", + Level: 2, + }, + }, + }, + }, + Caches: []info.Cache{ + { + Size: 8388608, + Type: "Unified", + Level: 3, + }, + }, + }, + }, + }, nil +} + +func genContainerInfo(name string) *info.ContainerInfo { + return &info.ContainerInfo{ + ContainerReference: info.ContainerReference{ + Name: name, + Aliases: []string{name +"alias"}, + }, + Spec: info.ContainerSpec{ + Image: "test", + HasCpu: true, + Cpu: info.CpuSpec{ + Limit: 1000, + Period: 100000, + Quota: 10000, + }, + Memory: info.MemorySpec{ + Limit: 2048, + Reservation: 1024, + SwapLimit: 4096, + }, + HasHugetlb: true, + HasProcesses: true, + Processes: info.ProcessSpec{ + Limit: 100, + }, + CreationTime: time.Unix(1257894000, 0), + Labels: map[string]string{ + "foo.label": "bar", + }, + Envs: map[string]string{ + "foo+env": "prod", + }, + }, + Stats: []*info.ContainerStats{ + { + Timestamp: time.Unix(1395066363, 0), + Cpu: info.CpuStats{ + Usage: info.CpuUsage{ + Total: 1, + PerCpu: []uint64{2, 3, 4, 5}, + User: 6, + System: 7, + }, + CFS: info.CpuCFS{ + Periods: 723, + ThrottledPeriods: 18, + ThrottledTime: 1724314000, + }, + Schedstat: info.CpuSchedstat{ + RunTime: 53643567, + RunqueueTime: 479424566378, + RunPeriods: 984285, + }, + LoadAverage: 2, + }, + Memory: info.MemoryStats{ + Usage: 8, + MaxUsage: 8, + WorkingSet: 9, + ContainerData: info.MemoryStatsMemoryData{ + Pgfault: 10, + Pgmajfault: 11, + NumaStats: info.MemoryNumaStats{ + File: map[uint8]uint64{0: 16649, 1: 10000}, + Anon: map[uint8]uint64{0: 10000, 1: 7109}, + Unevictable: map[uint8]uint64{0: 8900, 1: 10000}, + }, + }, + HierarchicalData: info.MemoryStatsMemoryData{ + Pgfault: 12, + Pgmajfault: 13, + NumaStats: info.MemoryNumaStats{ + File: map[uint8]uint64{0: 36649, 1: 10000}, + Anon: map[uint8]uint64{0: 20000, 1: 7109}, + Unevictable: map[uint8]uint64{0: 8900, 1: 20000}, + }, + }, + Cache: 14, + RSS: 15, + MappedFile: 16, + Swap: 8192, + }, + Hugetlb: map[string]info.HugetlbStats{ + "2Mi": { + Usage: 4, + MaxUsage: 10, + Failcnt: 1, + }, + "1Gi": { + Usage: 0, + MaxUsage: 0, + Failcnt: 0, + }, + }, + Network: info.NetworkStats{ + InterfaceStats: info.InterfaceStats{ + Name: "eth0", + RxBytes: 14, + RxPackets: 15, + RxErrors: 16, + RxDropped: 17, + TxBytes: 18, + TxPackets: 19, + TxErrors: 20, + TxDropped: 21, + }, + Interfaces: []info.InterfaceStats{ + { + Name: "eth0", + RxBytes: 14, + RxPackets: 15, + RxErrors: 16, + RxDropped: 17, + TxBytes: 18, + TxPackets: 19, + TxErrors: 20, + TxDropped: 21, + }, + }, + Tcp: info.TcpStat{ + Established: 13, + SynSent: 0, + SynRecv: 0, + FinWait1: 0, + FinWait2: 0, + TimeWait: 0, + Close: 0, + CloseWait: 0, + LastAck: 0, + Listen: 3, + Closing: 0, + }, + Tcp6: info.TcpStat{ + Established: 11, + SynSent: 0, + SynRecv: 0, + FinWait1: 0, + FinWait2: 0, + TimeWait: 0, + Close: 0, + CloseWait: 0, + LastAck: 0, + Listen: 3, + Closing: 0, + }, + TcpAdvanced: info.TcpAdvancedStat{ + TCPFullUndo: 2361, + TCPMD5NotFound: 0, + TCPDSACKRecv: 83680, + TCPSackShifted: 2, + TCPSackShiftFallback: 298, + PFMemallocDrop: 0, + EstabResets: 37, + InSegs: 140370590, + TCPPureAcks: 24251339, + TCPDSACKOldSent: 15633, + IPReversePathFilter: 0, + TCPFastOpenPassiveFail: 0, + InCsumErrors: 0, + TCPRenoFailures: 43414, + TCPMemoryPressuresChrono: 0, + TCPDeferAcceptDrop: 0, + TW: 10436427, + TCPSpuriousRTOs: 0, + TCPDSACKIgnoredNoUndo: 71885, + RtoMax: 120000, + ActiveOpens: 11038621, + EmbryonicRsts: 0, + RcvPruned: 0, + TCPLossProbeRecovery: 401, + TCPHPHits: 56096478, + TCPPartialUndo: 3, + TCPAbortOnMemory: 0, + AttemptFails: 48997, + RetransSegs: 462961, + SyncookiesFailed: 0, + OfoPruned: 0, + TCPAbortOnLinger: 0, + TCPAbortFailed: 0, + TCPRenoReorder: 839, + TCPRcvCollapsed: 0, + TCPDSACKIgnoredOld: 0, + TCPReqQFullDrop: 0, + OutOfWindowIcmps: 0, + TWKilled: 0, + TCPLossProbes: 88648, + TCPRenoRecoveryFail: 394, + TCPFastOpenCookieReqd: 0, + TCPHPAcks: 21490641, + TCPSACKReneging: 0, + TCPTSReorder: 3, + TCPSlowStartRetrans: 290832, + MaxConn: -1, + SyncookiesRecv: 0, + TCPSackFailures: 60, + DelayedACKLocked: 90, + TCPDSACKOfoSent: 1, + TCPSynRetrans: 988, + TCPDSACKOfoRecv: 10, + TCPSACKDiscard: 0, + TCPMD5Unexpected: 0, + TCPSackMerged: 6, + RtoMin: 200, + CurrEstab: 22, + TCPTimeWaitOverflow: 0, + ListenOverflows: 0, + DelayedACKs: 503975, + TCPLossUndo: 61374, + TCPOrigDataSent: 130698387, + TCPBacklogDrop: 0, + TCPReqQFullDoCookies: 0, + TCPFastOpenPassive: 0, + PAWSActive: 0, + OutRsts: 91699, + TCPSackRecoveryFail: 2, + DelayedACKLost: 18843, + TCPAbortOnData: 8, + TCPMinTTLDrop: 0, + PruneCalled: 0, + TWRecycled: 0, + ListenDrops: 0, + TCPAbortOnTimeout: 0, + SyncookiesSent: 0, + TCPSACKReorder: 11, + TCPDSACKUndo: 33, + TCPMD5Failure: 0, + TCPLostRetransmit: 0, + TCPAbortOnClose: 7, + TCPFastOpenListenOverflow: 0, + OutSegs: 211580512, + InErrs: 31, + TCPTimeouts: 27422, + TCPLossFailures: 729, + TCPSackRecovery: 159, + RtoAlgorithm: 1, + PassiveOpens: 59, + LockDroppedIcmps: 0, + TCPRenoRecovery: 3519, + TCPFACKReorder: 0, + TCPFastRetrans: 11794, + TCPRetransFail: 0, + TCPMemoryPressures: 0, + TCPFastOpenActive: 0, + TCPFastOpenActiveFail: 0, + PAWSEstab: 0, + }, + Udp: info.UdpStat{ + Listen: 0, + Dropped: 0, + RxQueued: 0, + TxQueued: 0, + }, + Udp6: info.UdpStat{ + Listen: 0, + Dropped: 0, + RxQueued: 0, + TxQueued: 0, + }, + }, + DiskIo: info.DiskIoStats{ + IoServiceBytes: []info.PerDiskStats{{ + Device: "/dev/sdb", + Major: 8, + Minor: 0, + Stats: map[string]uint64{ + "Async": 1, + "Discard": 2, + "Read": 3, + "Sync": 4, + "Total": 5, + "Write": 6, + }, + }}, + }, + Filesystem: []info.FsStats{ + { + Device: "sda1", + InodesFree: 524288, + Inodes: 2097152, + Limit: 22, + Usage: 23, + ReadsCompleted: 24, + ReadsMerged: 25, + SectorsRead: 26, + ReadTime: 27, + WritesCompleted: 28, + WritesMerged: 39, + SectorsWritten: 40, + WriteTime: 41, + IoInProgress: 42, + IoTime: 43, + WeightedIoTime: 44, + }, + { + Device: "sda2", + InodesFree: 262144, + Inodes: 2097152, + Limit: 37, + Usage: 38, + ReadsCompleted: 39, + ReadsMerged: 40, + SectorsRead: 41, + ReadTime: 42, + WritesCompleted: 43, + WritesMerged: 44, + SectorsWritten: 45, + WriteTime: 46, + IoInProgress: 47, + IoTime: 48, + WeightedIoTime: 49, + }, + }, + Accelerators: []info.AcceleratorStats{ + { + Make: "nvidia", + Model: "tesla-p100", + ID: "GPU-deadbeef-1234-5678-90ab-feedfacecafe", + MemoryTotal: 20304050607, + MemoryUsed: 2030405060, + DutyCycle: 12, + }, + { + Make: "nvidia", + Model: "tesla-k80", + ID: "GPU-deadbeef-0123-4567-89ab-feedfacecafe", + MemoryTotal: 10203040506, + MemoryUsed: 1020304050, + DutyCycle: 6, + }, + }, + Processes: info.ProcessStats{ + ProcessCount: 1, + FdCount: 5, + SocketCount: 3, + ThreadsCurrent: 5, + ThreadsMax: 100, + Ulimits: []info.UlimitSpec{ + { + Name: "max_open_files", + SoftLimit: 16384, + HardLimit: 16384, + }, + }, + }, + TaskStats: info.LoadStats{ + NrSleeping: 50, + NrRunning: 51, + NrStopped: 52, + NrUninterruptible: 53, + NrIoWait: 54, + }, + CustomMetrics: map[string][]info.MetricVal{ + "container_custom_app_metric_1": { + { + FloatValue: float64(1.1), + Timestamp: time.Now(), + Label: "testlabel_1_1_1", + Labels: map[string]string{"test_label": "1_1", "test_label_2": "2_1"}, + }, + { + FloatValue: float64(1.2), + Timestamp: time.Now(), + Label: "testlabel_1_1_2", + Labels: map[string]string{"test_label": "1_2", "test_label_2": "2_2"}, + }, + }, + "container_custom_app_metric_2": { + { + FloatValue: float64(2), + Timestamp: time.Now(), + Label: "testlabel2", + Labels: map[string]string{"test_label": "test_value"}, + }, + }, + "container_custom_app_metric_3": { + { + FloatValue: float64(3), + Timestamp: time.Now(), + Label: "testlabel3", + Labels: map[string]string{"test_label": "test_value"}, + }, + }, + }, + PerfStats: []info.PerfStat{ + { + PerfValue: info.PerfValue{ + ScalingRatio: 1.0, + Value: 123, + Name: "instructions", + }, + Cpu: 0, + }, + { + PerfValue: info.PerfValue{ + ScalingRatio: 0.5, + Value: 456, + Name: "instructions", + }, + Cpu: 1, + }, + { + PerfValue: info.PerfValue{ + ScalingRatio: 0.66666666666, + Value: 321, + Name: "instructions_retired", + }, + Cpu: 0, + }, + { + PerfValue: info.PerfValue{ + ScalingRatio: 0.33333333333, + Value: 789, + Name: "instructions_retired", + }, + Cpu: 1, + }, + }, + PerfUncoreStats: []info.PerfUncoreStat{ + { + PerfValue: info.PerfValue{ + ScalingRatio: 1.0, + Value: 1231231512.0, + Name: "cas_count_read", + }, + Socket: 0, + PMU: "uncore_imc_0", + }, + { + PerfValue: info.PerfValue{ + ScalingRatio: 1.0, + Value: 1111231331.0, + Name: "cas_count_read", + }, + Socket: 1, + PMU: "uncore_imc_0", + }, + }, + ReferencedMemory: 1234, + Resctrl: info.ResctrlStats{ + MemoryBandwidth: []info.MemoryBandwidthStats{ + { + TotalBytes: 4512312, + LocalBytes: 2390393, + }, + { + TotalBytes: 2173713, + LocalBytes: 1231233, + }, + }, + Cache: []info.CacheStats{ + { + LLCOccupancy: 162626, + }, + { + LLCOccupancy: 213777, + }, + }, + }, + CpuSet: info.CPUSetStats{MemoryMigrate: 1}, + }, + }, + } +} + +func (p testSubcontainersInfoProvider) GetRequestedContainersInfo(string, v2.RequestOptions) (map[string]*info.ContainerInfo, error) { + return map[string]*info.ContainerInfo{"testcontainer": genContainerInfo("testcontainer")}, nil +} + +type erroringSubcontainersInfoProvider struct { + successfulProvider testSubcontainersInfoProvider + shouldFail bool +} + +func (p *erroringSubcontainersInfoProvider) GetVersionInfo() (*info.VersionInfo, error) { + if p.shouldFail { + return nil, errors.New("Oops 1") + } + return p.successfulProvider.GetVersionInfo() +} + +func (p *erroringSubcontainersInfoProvider) GetMachineInfo() (*info.MachineInfo, error) { + if p.shouldFail { + return nil, errors.New("Oops 2") + } + return p.successfulProvider.GetMachineInfo() +} + +func (p *erroringSubcontainersInfoProvider) GetRequestedContainersInfo( + a string, opt v2.RequestOptions) (map[string]*info.ContainerInfo, error) { + if p.shouldFail { + return map[string]*info.ContainerInfo{}, errors.New("Oops 3") + } + return p.successfulProvider.GetRequestedContainersInfo(a, opt) +} diff --git a/vendor/github.com/google/cadvisor/metrics/prometheus_machine.go b/vendor/github.com/google/cadvisor/metrics/machine.go similarity index 82% rename from vendor/github.com/google/cadvisor/metrics/prometheus_machine.go rename to vendor/github.com/google/cadvisor/metrics/machine.go index f60cdc2883c25..c3edc10877d36 100644 --- a/vendor/github.com/google/cadvisor/metrics/prometheus_machine.go +++ b/vendor/github.com/google/cadvisor/metrics/machine.go @@ -17,7 +17,9 @@ package metrics import ( "strconv" + v2 "github.com/google/cadvisor/info/v2" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/cache" "github.com/google/cadvisor/container" info "github.com/google/cadvisor/info/v1" @@ -56,27 +58,17 @@ type machineMetric struct { getValues func(machineInfo *info.MachineInfo) metricValues } -func (metric *machineMetric) desc(baseLabels []string) *prometheus.Desc { - return prometheus.NewDesc(metric.name, metric.help, append(baseLabels, metric.extraLabels...), nil) -} - -// PrometheusMachineCollector implements prometheus.Collector. -type PrometheusMachineCollector struct { +// MachineCollector allows updating prometheus cache.CachedTGatherer based on +// machine data. +type MachineCollector struct { infoProvider infoProvider - errors prometheus.Gauge machineMetrics []machineMetric } -// NewPrometheusMachineCollector returns a new PrometheusCollector. -func NewPrometheusMachineCollector(i infoProvider, includedMetrics container.MetricSet) *PrometheusMachineCollector { - c := &PrometheusMachineCollector{ - +// NewMachineCollector returns a new MachineCollector. +func NewMachineCollector(i infoProvider, includedMetrics container.MetricSet) *MachineCollector { + c := &MachineCollector{ infoProvider: i, - errors: prometheus.NewGauge(prometheus.GaugeOpts{ - Namespace: "machine", - Name: "scrape_error", - Help: "1 if there was an error while getting machine metrics, 0 otherwise.", - }), machineMetrics: []machineMetric{ { name: "machine_cpu_physical_cores", @@ -196,56 +188,65 @@ func NewPrometheusMachineCollector(i infoProvider, includedMetrics container.Met return c } -// Describe describes all the machine metrics ever exported by cadvisor. It -// implements prometheus.PrometheusCollector. -func (collector *PrometheusMachineCollector) Describe(ch chan<- *prometheus.Desc) { - collector.errors.Describe(ch) - for _, metric := range collector.machineMetrics { - ch <- metric.desc([]string{}) +// Collect fetches latest statistics about machines in form of prometheus cache inserts. +func (c *MachineCollector) Collect(_ v2.RequestOptions, inserts []cache.Insert) []cache.Insert { + errorsGauge := 0 + inserts, err := c.collectMachineInfo(inserts) + if err != nil { + errorsGauge = 1 + klog.Warningf("Couldn't get machine info: %s", err) } -} -// Collect fetches information about machine and delivers them as -// Prometheus metrics. It implements prometheus.PrometheusCollector. -func (collector *PrometheusMachineCollector) Collect(ch chan<- prometheus.Metric) { - collector.errors.Set(0) - collector.collectMachineInfo(ch) - collector.errors.Collect(ch) + // TODO(bwplotka): Consider moving this to normal metric or returning error directly instead of metric. + return append(inserts, cache.Insert{ + Key: cache.Key{FQName: "machine_scrape_error"}, + Help: "1 if there was an error while getting machine metrics, 0 otherwise", + ValueType: prometheus.GaugeValue, + Value: float64(errorsGauge), + }) } -func (collector *PrometheusMachineCollector) collectMachineInfo(ch chan<- prometheus.Metric) { - machineInfo, err := collector.infoProvider.GetMachineInfo() +func (c *MachineCollector) collectMachineInfo(inserts []cache.Insert) ([]cache.Insert, error) { + machineInfo, err := c.infoProvider.GetMachineInfo() if err != nil { - collector.errors.Set(1) - klog.Warningf("Couldn't get machine info: %s", err) - return + return nil, err } + labels := make([]string, len(baseLabelsNames)) + copy(labels, baseLabelsNames) baseLabelsValues := []string{machineInfo.MachineID, machineInfo.SystemUUID, machineInfo.BootID} + values := make([]string, len(baseLabelsValues)) + copy(values, baseLabelsValues) - for _, metric := range collector.machineMetrics { + for _, metric := range c.machineMetrics { if metric.condition != nil && !metric.condition(machineInfo) { continue } for _, metricValue := range metric.getValues(machineInfo) { - labelValues := make([]string, len(baseLabelsValues)) - copy(labelValues, baseLabelsValues) - if len(metric.extraLabels) != 0 { - labelValues = append(labelValues, metricValue.labels...) - } - - prometheusMetric := prometheus.MustNewConstMetric(metric.desc(baseLabelsNames), - metric.valueType, metricValue.value, labelValues...) + labels = append(labels, metric.extraLabels...) + values = append(values, metricValue.labels...) + + inserts = append(inserts, cache.Insert{ + Key: cache.Key{ + FQName: metric.name, + LabelNames: labels, + LabelValues: values, + }, + Help: metric.help, + ValueType: metric.valueType, + Value: metricValue.value, + }) - if metricValue.timestamp.IsZero() { - ch <- prometheusMetric - } else { - ch <- prometheus.NewMetricWithTimestamp(metricValue.timestamp, prometheusMetric) + if !metricValue.timestamp.IsZero() { + inserts[len(inserts)-1].Timestamp = &metricValue.timestamp } - } + labels = labels[:len(labels)-len(metric.extraLabels)] + values = values[:len(values)-len(metricValue.labels)] + } } + return inserts, nil } func getMemoryByType(machineInfo *info.MachineInfo, property string) metricValues { diff --git a/vendor/github.com/google/cadvisor/metrics/metrics.go b/vendor/github.com/google/cadvisor/metrics/metrics.go index f314f631d7cdc..f5b60888b4873 100644 --- a/vendor/github.com/google/cadvisor/metrics/metrics.go +++ b/vendor/github.com/google/cadvisor/metrics/metrics.go @@ -19,6 +19,7 @@ import ( info "github.com/google/cadvisor/info/v1" v2 "github.com/google/cadvisor/info/v2" + "github.com/prometheus/client_golang/prometheus/cache" ) // metricValue describes a single metric value for a given set of label values @@ -40,3 +41,35 @@ type infoProvider interface { // GetMachineInfo provides information about the machine. GetMachineInfo() (*info.MachineInfo, error) } + +type CollectFn func(opts v2.RequestOptions, inserts []cache.Insert) []cache.Insert + +type CachedGatherer struct { + *cache.CachedTGatherer + buf []cache.Insert + + collectFns []CollectFn + + lastUpdate time.Time +} + +func NewCachedGatherer(cfs ...CollectFn) *CachedGatherer { + return &CachedGatherer{ + CachedTGatherer: cache.NewCachedTGatherer(), + collectFns: cfs, + } +} + +func (c *CachedGatherer) Update(opts v2.RequestOptions) { + if opts.MaxAge == nil || time.Since(c.lastUpdate) > *opts.MaxAge { + c.lastUpdate = time.Now() + + c.buf = c.buf[:0] + for _, collect := range c.collectFns { + c.buf = collect(opts, c.buf) + } + if err := c.CachedTGatherer.Update(true, c.buf, nil); err != nil { + panic(err) // Programmatic error. + } + } +} diff --git a/vendor/github.com/google/cadvisor/metrics/prometheus_fake.go b/vendor/github.com/google/cadvisor/metrics/prometheus_fake.go deleted file mode 100644 index 822b3f82c9776..0000000000000 --- a/vendor/github.com/google/cadvisor/metrics/prometheus_fake.go +++ /dev/null @@ -1,758 +0,0 @@ -// Copyright 2020 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metrics - -import ( - "errors" - "time" - - info "github.com/google/cadvisor/info/v1" - v2 "github.com/google/cadvisor/info/v2" -) - -type testSubcontainersInfoProvider struct{} - -func (p testSubcontainersInfoProvider) GetVersionInfo() (*info.VersionInfo, error) { - return &info.VersionInfo{ - KernelVersion: "4.1.6-200.fc22.x86_64", - ContainerOsVersion: "Fedora 22 (Twenty Two)", - DockerVersion: "1.8.1", - CadvisorVersion: "0.16.0", - CadvisorRevision: "abcdef", - }, nil -} - -func (p testSubcontainersInfoProvider) GetMachineInfo() (*info.MachineInfo, error) { - return &info.MachineInfo{ - Timestamp: time.Unix(1395066363, 0), - NumCores: 4, - NumPhysicalCores: 1, - NumSockets: 1, - MemoryCapacity: 1024, - MemoryByType: map[string]*info.MemoryInfo{ - "Non-volatile-RAM": {Capacity: 2168421613568, DimmCount: 8}, - "Unbuffered-DDR4": {Capacity: 412316860416, DimmCount: 12}, - }, - NVMInfo: info.NVMInfo{ - MemoryModeCapacity: 429496729600, - AppDirectModeCapacity: 1735166787584, - }, - MachineID: "machine-id-test", - SystemUUID: "system-uuid-test", - BootID: "boot-id-test", - Topology: []info.Node{ - { - Id: 0, - Memory: 33604804608, - HugePages: []info.HugePagesInfo{ - { - PageSize: uint64(1048576), - NumPages: uint64(0), - }, - { - PageSize: uint64(2048), - NumPages: uint64(0), - }, - }, - Cores: []info.Core{ - { - Id: 0, - Threads: []int{0, 1}, - Caches: []info.Cache{ - { - Size: 32768, - Type: "Data", - Level: 1, - }, - { - Size: 32768, - Type: "Instruction", - Level: 1, - }, - { - Size: 262144, - Type: "Unified", - Level: 2, - }, - }, - }, - { - Id: 1, - Threads: []int{2, 3}, - Caches: []info.Cache{ - { - Size: 32764, - Type: "Data", - Level: 1, - }, - { - Size: 32764, - Type: "Instruction", - Level: 1, - }, - { - Size: 262148, - Type: "Unified", - Level: 2, - }, - }, - }, - - { - Id: 2, - Threads: []int{4, 5}, - Caches: []info.Cache{ - { - Size: 32768, - Type: "Data", - Level: 1, - }, - { - Size: 32768, - Type: "Instruction", - Level: 1, - }, - { - Size: 262144, - Type: "Unified", - Level: 2, - }, - }, - }, - { - Id: 3, - Threads: []int{6, 7}, - Caches: []info.Cache{ - { - Size: 32764, - Type: "Data", - Level: 1, - }, - { - Size: 32764, - Type: "Instruction", - Level: 1, - }, - { - Size: 262148, - Type: "Unified", - Level: 2, - }, - }, - }, - }, - }, - { - Id: 1, - Memory: 33604804606, - HugePages: []info.HugePagesInfo{ - { - PageSize: uint64(1048576), - NumPages: uint64(2), - }, - { - PageSize: uint64(2048), - NumPages: uint64(4), - }, - }, - Cores: []info.Core{ - { - Id: 4, - Threads: []int{8, 9}, - Caches: []info.Cache{ - { - Size: 32768, - Type: "Data", - Level: 1, - }, - { - Size: 32768, - Type: "Instruction", - Level: 1, - }, - { - Size: 262144, - Type: "Unified", - Level: 2, - }, - }, - }, - { - Id: 5, - Threads: []int{10, 11}, - Caches: []info.Cache{ - { - Size: 32764, - Type: "Data", - Level: 1, - }, - { - Size: 32764, - Type: "Instruction", - Level: 1, - }, - { - Size: 262148, - Type: "Unified", - Level: 2, - }, - }, - }, - { - Id: 6, - Threads: []int{12, 13}, - Caches: []info.Cache{ - { - Size: 32768, - Type: "Data", - Level: 1, - }, - { - Size: 32768, - Type: "Instruction", - Level: 1, - }, - { - Size: 262144, - Type: "Unified", - Level: 2, - }, - }, - }, - { - Id: 7, - Threads: []int{14, 15}, - Caches: []info.Cache{ - { - Size: 32764, - Type: "Data", - Level: 1, - }, - { - Size: 32764, - Type: "Instruction", - Level: 1, - }, - { - Size: 262148, - Type: "Unified", - Level: 2, - }, - }, - }, - }, - Caches: []info.Cache{ - { - Size: 8388608, - Type: "Unified", - Level: 3, - }, - }, - }, - }, - }, nil -} - -func (p testSubcontainersInfoProvider) GetRequestedContainersInfo(string, v2.RequestOptions) (map[string]*info.ContainerInfo, error) { - return map[string]*info.ContainerInfo{ - "testcontainer": { - ContainerReference: info.ContainerReference{ - Name: "testcontainer", - Aliases: []string{"testcontaineralias"}, - }, - Spec: info.ContainerSpec{ - Image: "test", - HasCpu: true, - Cpu: info.CpuSpec{ - Limit: 1000, - Period: 100000, - Quota: 10000, - }, - Memory: info.MemorySpec{ - Limit: 2048, - Reservation: 1024, - SwapLimit: 4096, - }, - HasHugetlb: true, - HasProcesses: true, - Processes: info.ProcessSpec{ - Limit: 100, - }, - CreationTime: time.Unix(1257894000, 0), - Labels: map[string]string{ - "foo.label": "bar", - }, - Envs: map[string]string{ - "foo+env": "prod", - }, - }, - Stats: []*info.ContainerStats{ - { - Timestamp: time.Unix(1395066363, 0), - Cpu: info.CpuStats{ - Usage: info.CpuUsage{ - Total: 1, - PerCpu: []uint64{2, 3, 4, 5}, - User: 6, - System: 7, - }, - CFS: info.CpuCFS{ - Periods: 723, - ThrottledPeriods: 18, - ThrottledTime: 1724314000, - }, - Schedstat: info.CpuSchedstat{ - RunTime: 53643567, - RunqueueTime: 479424566378, - RunPeriods: 984285, - }, - LoadAverage: 2, - }, - Memory: info.MemoryStats{ - Usage: 8, - MaxUsage: 8, - WorkingSet: 9, - ContainerData: info.MemoryStatsMemoryData{ - Pgfault: 10, - Pgmajfault: 11, - NumaStats: info.MemoryNumaStats{ - File: map[uint8]uint64{0: 16649, 1: 10000}, - Anon: map[uint8]uint64{0: 10000, 1: 7109}, - Unevictable: map[uint8]uint64{0: 8900, 1: 10000}, - }, - }, - HierarchicalData: info.MemoryStatsMemoryData{ - Pgfault: 12, - Pgmajfault: 13, - NumaStats: info.MemoryNumaStats{ - File: map[uint8]uint64{0: 36649, 1: 10000}, - Anon: map[uint8]uint64{0: 20000, 1: 7109}, - Unevictable: map[uint8]uint64{0: 8900, 1: 20000}, - }, - }, - Cache: 14, - RSS: 15, - MappedFile: 16, - Swap: 8192, - }, - Hugetlb: map[string]info.HugetlbStats{ - "2Mi": { - Usage: 4, - MaxUsage: 10, - Failcnt: 1, - }, - "1Gi": { - Usage: 0, - MaxUsage: 0, - Failcnt: 0, - }, - }, - Network: info.NetworkStats{ - InterfaceStats: info.InterfaceStats{ - Name: "eth0", - RxBytes: 14, - RxPackets: 15, - RxErrors: 16, - RxDropped: 17, - TxBytes: 18, - TxPackets: 19, - TxErrors: 20, - TxDropped: 21, - }, - Interfaces: []info.InterfaceStats{ - { - Name: "eth0", - RxBytes: 14, - RxPackets: 15, - RxErrors: 16, - RxDropped: 17, - TxBytes: 18, - TxPackets: 19, - TxErrors: 20, - TxDropped: 21, - }, - }, - Tcp: info.TcpStat{ - Established: 13, - SynSent: 0, - SynRecv: 0, - FinWait1: 0, - FinWait2: 0, - TimeWait: 0, - Close: 0, - CloseWait: 0, - LastAck: 0, - Listen: 3, - Closing: 0, - }, - Tcp6: info.TcpStat{ - Established: 11, - SynSent: 0, - SynRecv: 0, - FinWait1: 0, - FinWait2: 0, - TimeWait: 0, - Close: 0, - CloseWait: 0, - LastAck: 0, - Listen: 3, - Closing: 0, - }, - TcpAdvanced: info.TcpAdvancedStat{ - TCPFullUndo: 2361, - TCPMD5NotFound: 0, - TCPDSACKRecv: 83680, - TCPSackShifted: 2, - TCPSackShiftFallback: 298, - PFMemallocDrop: 0, - EstabResets: 37, - InSegs: 140370590, - TCPPureAcks: 24251339, - TCPDSACKOldSent: 15633, - IPReversePathFilter: 0, - TCPFastOpenPassiveFail: 0, - InCsumErrors: 0, - TCPRenoFailures: 43414, - TCPMemoryPressuresChrono: 0, - TCPDeferAcceptDrop: 0, - TW: 10436427, - TCPSpuriousRTOs: 0, - TCPDSACKIgnoredNoUndo: 71885, - RtoMax: 120000, - ActiveOpens: 11038621, - EmbryonicRsts: 0, - RcvPruned: 0, - TCPLossProbeRecovery: 401, - TCPHPHits: 56096478, - TCPPartialUndo: 3, - TCPAbortOnMemory: 0, - AttemptFails: 48997, - RetransSegs: 462961, - SyncookiesFailed: 0, - OfoPruned: 0, - TCPAbortOnLinger: 0, - TCPAbortFailed: 0, - TCPRenoReorder: 839, - TCPRcvCollapsed: 0, - TCPDSACKIgnoredOld: 0, - TCPReqQFullDrop: 0, - OutOfWindowIcmps: 0, - TWKilled: 0, - TCPLossProbes: 88648, - TCPRenoRecoveryFail: 394, - TCPFastOpenCookieReqd: 0, - TCPHPAcks: 21490641, - TCPSACKReneging: 0, - TCPTSReorder: 3, - TCPSlowStartRetrans: 290832, - MaxConn: -1, - SyncookiesRecv: 0, - TCPSackFailures: 60, - DelayedACKLocked: 90, - TCPDSACKOfoSent: 1, - TCPSynRetrans: 988, - TCPDSACKOfoRecv: 10, - TCPSACKDiscard: 0, - TCPMD5Unexpected: 0, - TCPSackMerged: 6, - RtoMin: 200, - CurrEstab: 22, - TCPTimeWaitOverflow: 0, - ListenOverflows: 0, - DelayedACKs: 503975, - TCPLossUndo: 61374, - TCPOrigDataSent: 130698387, - TCPBacklogDrop: 0, - TCPReqQFullDoCookies: 0, - TCPFastOpenPassive: 0, - PAWSActive: 0, - OutRsts: 91699, - TCPSackRecoveryFail: 2, - DelayedACKLost: 18843, - TCPAbortOnData: 8, - TCPMinTTLDrop: 0, - PruneCalled: 0, - TWRecycled: 0, - ListenDrops: 0, - TCPAbortOnTimeout: 0, - SyncookiesSent: 0, - TCPSACKReorder: 11, - TCPDSACKUndo: 33, - TCPMD5Failure: 0, - TCPLostRetransmit: 0, - TCPAbortOnClose: 7, - TCPFastOpenListenOverflow: 0, - OutSegs: 211580512, - InErrs: 31, - TCPTimeouts: 27422, - TCPLossFailures: 729, - TCPSackRecovery: 159, - RtoAlgorithm: 1, - PassiveOpens: 59, - LockDroppedIcmps: 0, - TCPRenoRecovery: 3519, - TCPFACKReorder: 0, - TCPFastRetrans: 11794, - TCPRetransFail: 0, - TCPMemoryPressures: 0, - TCPFastOpenActive: 0, - TCPFastOpenActiveFail: 0, - PAWSEstab: 0, - }, - Udp: info.UdpStat{ - Listen: 0, - Dropped: 0, - RxQueued: 0, - TxQueued: 0, - }, - Udp6: info.UdpStat{ - Listen: 0, - Dropped: 0, - RxQueued: 0, - TxQueued: 0, - }, - }, - DiskIo: info.DiskIoStats{ - IoServiceBytes: []info.PerDiskStats{{ - Device: "/dev/sdb", - Major: 8, - Minor: 0, - Stats: map[string]uint64{ - "Async": 1, - "Discard": 2, - "Read": 3, - "Sync": 4, - "Total": 5, - "Write": 6, - }, - }}, - }, - Filesystem: []info.FsStats{ - { - Device: "sda1", - InodesFree: 524288, - Inodes: 2097152, - Limit: 22, - Usage: 23, - ReadsCompleted: 24, - ReadsMerged: 25, - SectorsRead: 26, - ReadTime: 27, - WritesCompleted: 28, - WritesMerged: 39, - SectorsWritten: 40, - WriteTime: 41, - IoInProgress: 42, - IoTime: 43, - WeightedIoTime: 44, - }, - { - Device: "sda2", - InodesFree: 262144, - Inodes: 2097152, - Limit: 37, - Usage: 38, - ReadsCompleted: 39, - ReadsMerged: 40, - SectorsRead: 41, - ReadTime: 42, - WritesCompleted: 43, - WritesMerged: 44, - SectorsWritten: 45, - WriteTime: 46, - IoInProgress: 47, - IoTime: 48, - WeightedIoTime: 49, - }, - }, - Accelerators: []info.AcceleratorStats{ - { - Make: "nvidia", - Model: "tesla-p100", - ID: "GPU-deadbeef-1234-5678-90ab-feedfacecafe", - MemoryTotal: 20304050607, - MemoryUsed: 2030405060, - DutyCycle: 12, - }, - { - Make: "nvidia", - Model: "tesla-k80", - ID: "GPU-deadbeef-0123-4567-89ab-feedfacecafe", - MemoryTotal: 10203040506, - MemoryUsed: 1020304050, - DutyCycle: 6, - }, - }, - Processes: info.ProcessStats{ - ProcessCount: 1, - FdCount: 5, - SocketCount: 3, - ThreadsCurrent: 5, - ThreadsMax: 100, - Ulimits: []info.UlimitSpec{ - { - Name: "max_open_files", - SoftLimit: 16384, - HardLimit: 16384, - }, - }, - }, - TaskStats: info.LoadStats{ - NrSleeping: 50, - NrRunning: 51, - NrStopped: 52, - NrUninterruptible: 53, - NrIoWait: 54, - }, - CustomMetrics: map[string][]info.MetricVal{ - "container_custom_app_metric_1": { - { - FloatValue: float64(1.1), - Timestamp: time.Now(), - Label: "testlabel_1_1_1", - Labels: map[string]string{"test_label": "1_1", "test_label_2": "2_1"}, - }, - { - FloatValue: float64(1.2), - Timestamp: time.Now(), - Label: "testlabel_1_1_2", - Labels: map[string]string{"test_label": "1_2", "test_label_2": "2_2"}, - }, - }, - "container_custom_app_metric_2": { - { - FloatValue: float64(2), - Timestamp: time.Now(), - Label: "testlabel2", - Labels: map[string]string{"test_label": "test_value"}, - }, - }, - "container_custom_app_metric_3": { - { - FloatValue: float64(3), - Timestamp: time.Now(), - Label: "testlabel3", - Labels: map[string]string{"test_label": "test_value"}, - }, - }, - }, - PerfStats: []info.PerfStat{ - { - PerfValue: info.PerfValue{ - ScalingRatio: 1.0, - Value: 123, - Name: "instructions", - }, - Cpu: 0, - }, - { - PerfValue: info.PerfValue{ - ScalingRatio: 0.5, - Value: 456, - Name: "instructions", - }, - Cpu: 1, - }, - { - PerfValue: info.PerfValue{ - ScalingRatio: 0.66666666666, - Value: 321, - Name: "instructions_retired", - }, - Cpu: 0, - }, - { - PerfValue: info.PerfValue{ - ScalingRatio: 0.33333333333, - Value: 789, - Name: "instructions_retired", - }, - Cpu: 1, - }, - }, - PerfUncoreStats: []info.PerfUncoreStat{ - { - PerfValue: info.PerfValue{ - ScalingRatio: 1.0, - Value: 1231231512.0, - Name: "cas_count_read", - }, - Socket: 0, - PMU: "uncore_imc_0", - }, - { - PerfValue: info.PerfValue{ - ScalingRatio: 1.0, - Value: 1111231331.0, - Name: "cas_count_read", - }, - Socket: 1, - PMU: "uncore_imc_0", - }, - }, - ReferencedMemory: 1234, - Resctrl: info.ResctrlStats{ - MemoryBandwidth: []info.MemoryBandwidthStats{ - { - TotalBytes: 4512312, - LocalBytes: 2390393, - }, - { - TotalBytes: 2173713, - LocalBytes: 1231233, - }, - }, - Cache: []info.CacheStats{ - { - LLCOccupancy: 162626, - }, - { - LLCOccupancy: 213777, - }, - }, - }, - CpuSet: info.CPUSetStats{MemoryMigrate: 1}, - }, - }, - }, - }, nil -} - -type erroringSubcontainersInfoProvider struct { - successfulProvider testSubcontainersInfoProvider - shouldFail bool -} - -func (p *erroringSubcontainersInfoProvider) GetVersionInfo() (*info.VersionInfo, error) { - if p.shouldFail { - return nil, errors.New("Oops 1") - } - return p.successfulProvider.GetVersionInfo() -} - -func (p *erroringSubcontainersInfoProvider) GetMachineInfo() (*info.MachineInfo, error) { - if p.shouldFail { - return nil, errors.New("Oops 2") - } - return p.successfulProvider.GetMachineInfo() -} - -func (p *erroringSubcontainersInfoProvider) GetRequestedContainersInfo( - a string, opt v2.RequestOptions) (map[string]*info.ContainerInfo, error) { - if p.shouldFail { - return map[string]*info.ContainerInfo{}, errors.New("Oops 3") - } - return p.successfulProvider.GetRequestedContainersInfo(a, opt) -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/cache/cache.go b/vendor/github.com/prometheus/client_golang/prometheus/cache/cache.go new file mode 100644 index 0000000000000..ad219355990dc --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/cache/cache.go @@ -0,0 +1,302 @@ +// Copyright 2022 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cache + +import ( + "errors" + "fmt" + "sort" + "sync" + "time" + + "github.com/cespare/xxhash/v2" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/model" + + //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. + "github.com/golang/protobuf/proto" + "github.com/prometheus/client_golang/prometheus/internal" + dto "github.com/prometheus/client_model/go" +) + +var _ prometheus.TransactionalGatherer = &CachedTGatherer{} + +var separatorByteSlice = []byte{model.SeparatorByte} // For convenient use with xxhash. + +// CachedTGatherer is a transactional gatherer that allows maintaining a set of metrics which +// change less frequently than scrape time, yet label values and values change over time. +// +// If you happen to use NewDesc, NewConstMetric or MustNewConstMetric inside Collector.Collect routine, consider +// using CachedTGatherer instead. +// +// Use CachedTGatherer with classic Registry using NewMultiTRegistry and ToTransactionalGatherer helpers. +// NOTE(bwplotka): Experimental, API and behaviour can change. +type CachedTGatherer struct { + metricFamiliesByName map[string]*family + mMu sync.RWMutex + + desiredTouchState bool +} + +func NewCachedTGatherer() *CachedTGatherer { + return &CachedTGatherer{ + desiredTouchState: true, + metricFamiliesByName: map[string]*family{}, + } +} + +type family struct { + *dto.MetricFamily + + metricsByHash map[uint64]*metric + touchState bool + needsRebuild bool +} + +type metric struct { + *dto.Metric + touchState bool +} + +// normalizeMetricFamilies returns a MetricFamily slice with empty +// MetricFamilies pruned and the remaining MetricFamilies sorted by name within +// the slice, with the contained Metrics sorted within each MetricFamily. +func normalizeMetricFamilies(metricFamiliesByName map[string]*family) []*dto.MetricFamily { + names := make([]string, 0, len(metricFamiliesByName)) + for name, mf := range metricFamiliesByName { + if len(mf.Metric) > 0 { + names = append(names, name) + } + } + sort.Strings(names) + result := make([]*dto.MetricFamily, 0, len(names)) + for _, name := range names { + result = append(result, metricFamiliesByName[name].MetricFamily) + } + return result +} + +// Gather implements TransactionalGatherer interface. +func (c *CachedTGatherer) Gather() (_ []*dto.MetricFamily, done func(), err error) { + c.mMu.RLock() + return normalizeMetricFamilies(c.metricFamiliesByName), c.mMu.RUnlock, nil +} + +type Key struct { + FQName string // __name__ + + // Label names can be unsorted, we will be sorting them later. The only implication is cachability if + // consumer provide non-deterministic order of those. + LabelNames []string + LabelValues []string +} + +func (k Key) isValid() error { + if k.FQName == "" { + return errors.New("FQName cannot be empty") + } + if len(k.LabelNames) != len(k.LabelValues) { + return errors.New("new metric: label name has different length than values") + } + + return nil +} + +// hash returns unique hash for this key. +func (k Key) hash() uint64 { + h := xxhash.New() + h.WriteString(k.FQName) + h.Write(separatorByteSlice) + + for i := range k.LabelNames { + h.WriteString(k.LabelNames[i]) + h.Write(separatorByteSlice) + h.WriteString(k.LabelValues[i]) + h.Write(separatorByteSlice) + } + return h.Sum64() +} + +// Insert represents record to set in cache. +type Insert struct { + Key + + Help string + ValueType prometheus.ValueType + Value float64 + + // Timestamp is optional. Pass nil for no explicit timestamp. + Timestamp *time.Time +} + +// Update goes through inserts and deletions and updates current cache in concurrency safe manner. +// If reset is set to true, all inserts and deletions are working on empty cache. In such case +// this implementation tries to reuse memory from existing cached item when possible. +// +// Update reuses insert struct memory, so after use, Insert slice and its elements cannot be reused +// outside of this method. +// TODO(bwplotka): Lack of copying can pose memory safety problems if insert variables are reused. Consider copying if value +// is different. Yet it gives significant allocation gains. +func (c *CachedTGatherer) Update(reset bool, inserts []Insert, deletions []Key) error { + c.mMu.Lock() + defer c.mMu.Unlock() + + errs := prometheus.MultiError{} + for i := range inserts { + // TODO(bwplotka): Validate more about this insert? + if err := inserts[i].isValid(); err != nil { + errs.Append(err) + continue + } + + // Update metric family. + mf, ok := c.metricFamiliesByName[inserts[i].FQName] + if !ok { + mf = &family{ + MetricFamily: &dto.MetricFamily{}, + metricsByHash: map[uint64]*metric{}, + } + mf.Name = &inserts[i].FQName + } + if reset { + mf.touchState = c.desiredTouchState + } + + mf.Type = inserts[i].ValueType.ToDTO() + mf.Help = &inserts[i].Help + + c.metricFamiliesByName[inserts[i].FQName] = mf + + // Update metric pointer. + hSum := inserts[i].hash() + m, ok := mf.metricsByHash[hSum] + if !ok { + m = &metric{ + Metric: &dto.Metric{Label: make([]*dto.LabelPair, 0, len(inserts[i].LabelNames))}, + } + for j := range inserts[i].LabelNames { + m.Label = append(m.Label, &dto.LabelPair{ + Name: &inserts[i].LabelNames[j], + Value: &inserts[i].LabelValues[j], + }) + } + sort.Sort(internal.LabelPairSorter(m.Label)) + mf.needsRebuild = true + } + if reset { + m.touchState = c.desiredTouchState + } + + switch inserts[i].ValueType { + case prometheus.CounterValue: + v := m.Counter + if v == nil { + v = &dto.Counter{} + } + v.Value = &inserts[i].Value + m.Counter = v + m.Gauge = nil + m.Untyped = nil + case prometheus.GaugeValue: + v := m.Gauge + if v == nil { + v = &dto.Gauge{} + } + v.Value = &inserts[i].Value + m.Counter = nil + m.Gauge = v + m.Untyped = nil + case prometheus.UntypedValue: + v := m.Untyped + if v == nil { + v = &dto.Untyped{} + } + v.Value = &inserts[i].Value + m.Counter = nil + m.Gauge = nil + m.Untyped = v + default: + return fmt.Errorf("unsupported value type %v", inserts[i].ValueType) + } + + m.TimestampMs = nil + if inserts[i].Timestamp != nil { + m.TimestampMs = proto.Int64(inserts[i].Timestamp.Unix()*1000 + int64(inserts[i].Timestamp.Nanosecond()/1000000)) + } + mf.metricsByHash[hSum] = m + } + + for _, del := range deletions { + if err := del.isValid(); err != nil { + errs.Append(err) + continue + } + + mf, ok := c.metricFamiliesByName[del.FQName] + if !ok { + continue + } + + hSum := del.hash() + if _, ok := mf.metricsByHash[hSum]; !ok { + continue + } + + if len(mf.metricsByHash) == 1 { + delete(c.metricFamiliesByName, del.FQName) + continue + } + + mf.needsRebuild = true + delete(mf.metricsByHash, hSum) + } + + if reset { + // Trading off-time instead of memory allocated for otherwise needed replacement map. + for name, mf := range c.metricFamiliesByName { + if mf.touchState != c.desiredTouchState { + delete(c.metricFamiliesByName, name) + continue + } + for hash, m := range mf.metricsByHash { + if m.touchState != c.desiredTouchState { + delete(mf.metricsByHash, hash) + continue + } + } + if len(mf.metricsByHash) == 0 { + delete(c.metricFamiliesByName, name) + } + } + + // Avoid resetting state by flipping what we will expect in the next update. + c.desiredTouchState = !c.desiredTouchState + } + + for _, mf := range c.metricFamiliesByName { + if !mf.needsRebuild { + continue + } + + mf.Metric = mf.Metric[:0] + for _, m := range mf.metricsByHash { + mf.Metric = append(mf.Metric, m.Metric) + } + sort.Sort(internal.MetricSorter(mf.Metric)) + + mf.needsRebuild = false + } + + return errs.MaybeUnwrap() +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collector.go b/vendor/github.com/prometheus/client_golang/prometheus/collector.go index 1e839650d4d93..ac1ca3cf5ffb8 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/collector.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/collector.go @@ -118,3 +118,11 @@ func (c *selfCollector) Describe(ch chan<- *Desc) { func (c *selfCollector) Collect(ch chan<- Metric) { ch <- c.self } + +// collectorMetric is a metric that is also a collector. +// Because of selfCollector, most (if not all) Metrics in +// this package are also collectors. +type collectorMetric interface { + Metric + Collector +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/desc.go b/vendor/github.com/prometheus/client_golang/prometheus/desc.go index 4bb816ab75ac9..ee81107c87a93 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/desc.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/desc.go @@ -20,6 +20,8 @@ import ( "strings" "github.com/cespare/xxhash/v2" + "github.com/prometheus/client_golang/prometheus/internal" + //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. "github.com/golang/protobuf/proto" "github.com/prometheus/common/model" @@ -154,7 +156,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * Value: proto.String(v), }) } - sort.Sort(labelPairSorter(d.constLabelPairs)) + sort.Sort(internal.LabelPairSorter(d.constLabelPairs)) return d } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/go_collector_go117.go b/vendor/github.com/prometheus/client_golang/prometheus/go_collector_go117.go index d534742435781..5046840390bd4 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/go_collector_go117.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/go_collector_go117.go @@ -32,9 +32,10 @@ type goCollector struct { base baseGoCollector // rm... fields all pertain to the runtime/metrics package. + rmSampleMu sync.Mutex rmSampleBuf []metrics.Sample rmSampleMap map[string]*metrics.Sample - rmMetrics []Metric + rmMetrics []collectorMetric // With Go 1.17, the runtime/metrics package was introduced. // From that point on, metric names produced by the runtime/metrics @@ -58,7 +59,7 @@ func NewGoCollector() Collector { } // Generate a Desc and ValueType for each runtime/metrics metric. - metricSet := make([]Metric, 0, len(descriptions)) + metricSet := make([]collectorMetric, 0, len(descriptions)) sampleBuf := make([]metrics.Sample, 0, len(descriptions)) sampleMap := make(map[string]*metrics.Sample, len(descriptions)) for i := range descriptions { @@ -76,7 +77,7 @@ func NewGoCollector() Collector { sampleBuf = append(sampleBuf, metrics.Sample{Name: d.Name}) sampleMap[d.Name] = &sampleBuf[len(sampleBuf)-1] - var m Metric + var m collectorMetric if d.Kind == metrics.KindFloat64Histogram { _, hasSum := rmExactSumMap[d.Name] m = newBatchHistogram( @@ -130,9 +131,19 @@ func (c *goCollector) Collect(ch chan<- Metric) { // Collect base non-memory metrics. c.base.Collect(ch) + // Collect must be thread-safe, so prevent concurrent use of + // rmSampleBuf. Just read into rmSampleBuf but write all the data + // we get into our Metrics or MemStats. + // + // Note that we cannot simply read and then clone rmSampleBuf + // because we'd need to perform a deep clone of it, which is likely + // not worth it. + c.rmSampleMu.Lock() + // Populate runtime/metrics sample buffer. metrics.Read(c.rmSampleBuf) + // Update all our metrics from rmSampleBuf. for i, sample := range c.rmSampleBuf { // N.B. switch on concrete type because it's significantly more efficient // than checking for the Counter and Gauge interface implementations. In @@ -146,22 +157,29 @@ func (c *goCollector) Collect(ch chan<- Metric) { if v1 > v0 { m.Add(unwrapScalarRMValue(sample.Value) - m.get()) } - m.Collect(ch) case *gauge: m.Set(unwrapScalarRMValue(sample.Value)) - m.Collect(ch) case *batchHistogram: m.update(sample.Value.Float64Histogram(), c.exactSumFor(sample.Name)) - m.Collect(ch) default: panic("unexpected metric type") } } - // ms is a dummy MemStats that we populate ourselves so that we can // populate the old metrics from it. var ms runtime.MemStats memStatsFromRM(&ms, c.rmSampleMap) + + c.rmSampleMu.Unlock() + + // Export all the metrics to ch. + // At this point we must not access rmSampleBuf or rmSampleMap, because + // a concurrent caller could use it. It's safe to Collect all our Metrics, + // however, because they're updated in a thread-safe way while MemStats + // is local to this call of Collect. + for _, m := range c.rmMetrics { + m.Collect(ch) + } for _, i := range c.msMetrics { ch <- MustNewConstMetric(i.desc, i.valType, i.eval(&ms)) } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go b/vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go index 351c26e1aedb4..6515c114804f6 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go @@ -19,18 +19,34 @@ import ( dto "github.com/prometheus/client_model/go" ) -// metricSorter is a sortable slice of *dto.Metric. -type metricSorter []*dto.Metric +// LabelPairSorter implements sort.Interface. It is used to sort a slice of +// dto.LabelPair pointers. +type LabelPairSorter []*dto.LabelPair -func (s metricSorter) Len() int { +func (s LabelPairSorter) Len() int { return len(s) } -func (s metricSorter) Swap(i, j int) { +func (s LabelPairSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s metricSorter) Less(i, j int) bool { +func (s LabelPairSorter) Less(i, j int) bool { + return s[i].GetName() < s[j].GetName() +} + +// MetricSorter is a sortable slice of *dto.Metric. +type MetricSorter []*dto.Metric + +func (s MetricSorter) Len() int { + return len(s) +} + +func (s MetricSorter) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s MetricSorter) Less(i, j int) bool { if len(s[i].Label) != len(s[j].Label) { // This should not happen. The metrics are // inconsistent. However, we have to deal with the fact, as @@ -68,7 +84,7 @@ func (s metricSorter) Less(i, j int) bool { // the slice, with the contained Metrics sorted within each MetricFamily. func NormalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily { for _, mf := range metricFamiliesByName { - sort.Sort(metricSorter(mf.Metric)) + sort.Sort(MetricSorter(mf.Metric)) } names := make([]string, 0, len(metricFamiliesByName)) for name, mf := range metricFamiliesByName { diff --git a/vendor/github.com/prometheus/client_golang/prometheus/metric.go b/vendor/github.com/prometheus/client_golang/prometheus/metric.go index dc121910a5207..118a54e84f0a0 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/metric.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/metric.go @@ -115,22 +115,6 @@ func BuildFQName(namespace, subsystem, name string) string { return name } -// labelPairSorter implements sort.Interface. It is used to sort a slice of -// dto.LabelPair pointers. -type labelPairSorter []*dto.LabelPair - -func (s labelPairSorter) Len() int { - return len(s) -} - -func (s labelPairSorter) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -func (s labelPairSorter) Less(i, j int) bool { - return s[i].GetName() < s[j].GetName() -} - type invalidMetric struct { desc *Desc err error diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go index d86d0cf4b0e98..b463a747fc9c5 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go @@ -84,6 +84,10 @@ func Handler() http.Handler { // instrumentation. Use the InstrumentMetricHandler function to apply the same // kind of instrumentation as it is used by the Handler function. func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { + return HandlerForTransactional(prometheus.ToTransactionalGatherer(reg), opts) +} + +func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerOpts) http.Handler { var ( inFlightSem chan struct{} errCnt = prometheus.NewCounterVec( @@ -113,6 +117,7 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { h := http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) { if inFlightSem != nil { + // TODO(bwplotka): Implement single-flight which is essential for blocking TransactionalGatherer. select { case inFlightSem <- struct{}{}: // All good, carry on. defer func() { <-inFlightSem }() @@ -123,7 +128,8 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { return } } - mfs, err := reg.Gather() + mfs, done, err := reg.Gather() + defer done() if err != nil { if opts.ErrorLog != nil { opts.ErrorLog.Println("error gathering metrics:", err) diff --git a/vendor/github.com/prometheus/client_golang/prometheus/registry.go b/vendor/github.com/prometheus/client_golang/prometheus/registry.go index 383a7f5941a52..5046f7e2f9c60 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/registry.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/registry.go @@ -407,6 +407,14 @@ func (r *Registry) MustRegister(cs ...Collector) { // Gather implements Gatherer. func (r *Registry) Gather() ([]*dto.MetricFamily, error) { + r.mtx.RLock() + + if len(r.collectorsByID) == 0 && len(r.uncheckedCollectors) == 0 { + // Fast path. + r.mtx.RUnlock() + return nil, nil + } + var ( checkedMetricChan = make(chan Metric, capMetricChan) uncheckedMetricChan = make(chan Metric, capMetricChan) @@ -416,7 +424,6 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) { registeredDescIDs map[uint64]struct{} // Only used for pedantic checks ) - r.mtx.RLock() goroutineBudget := len(r.collectorsByID) + len(r.uncheckedCollectors) metricFamiliesByName := make(map[string]*dto.MetricFamily, len(r.dimHashesByName)) checkedCollectors := make(chan Collector, len(r.collectorsByID)) @@ -884,11 +891,11 @@ func checkMetricConsistency( h.Write(separatorByteSlice) // Make sure label pairs are sorted. We depend on it for the consistency // check. - if !sort.IsSorted(labelPairSorter(dtoMetric.Label)) { + if !sort.IsSorted(internal.LabelPairSorter(dtoMetric.Label)) { // We cannot sort dtoMetric.Label in place as it is immutable by contract. copiedLabels := make([]*dto.LabelPair, len(dtoMetric.Label)) copy(copiedLabels, dtoMetric.Label) - sort.Sort(labelPairSorter(copiedLabels)) + sort.Sort(internal.LabelPairSorter(copiedLabels)) dtoMetric.Label = copiedLabels } for _, lp := range dtoMetric.Label { @@ -935,7 +942,7 @@ func checkDescConsistency( metricFamily.GetName(), dtoMetric, desc, ) } - sort.Sort(labelPairSorter(lpsFromDesc)) + sort.Sort(internal.LabelPairSorter(lpsFromDesc)) for i, lpFromDesc := range lpsFromDesc { lpFromMetric := dtoMetric.Label[i] if lpFromDesc.GetName() != lpFromMetric.GetName() || @@ -948,3 +955,89 @@ func checkDescConsistency( } return nil } + +var _ TransactionalGatherer = &MultiTRegistry{} + +// MultiTRegistry is a TransactionalGatherer that joins gathered metrics from multiple +// transactional gatherers. +// +// It is caller responsibility to ensure two registries have mutually exclusive metric families, +// no deduplication will happen. +type MultiTRegistry struct { + tGatherers []TransactionalGatherer +} + +// NewMultiTRegistry creates MultiTRegistry. +func NewMultiTRegistry(tGatherers ...TransactionalGatherer) *MultiTRegistry { + return &MultiTRegistry{ + tGatherers: tGatherers, + } +} + +// Gather implements TransactionalGatherer interface. +func (r *MultiTRegistry) Gather() (mfs []*dto.MetricFamily, done func(), err error) { + errs := MultiError{} + + dFns := make([]func(), 0, len(r.tGatherers)) + // TODO(bwplotka): Implement concurrency for those? + for _, g := range r.tGatherers { + // TODO(bwplotka): Check for duplicates? + m, d, err := g.Gather() + errs.Append(err) + + mfs = append(mfs, m...) + dFns = append(dFns, d) + } + + // TODO(bwplotka): Consider sort in place, given metric family in gather is sorted already. + sort.Slice(mfs, func(i, j int) bool { + return *mfs[i].Name < *mfs[j].Name + }) + return mfs, func() { + for _, d := range dFns { + d() + } + }, errs.MaybeUnwrap() +} + +// TransactionalGatherer represents transactional gatherer that can be triggered to notify gatherer that memory +// used by metric family is no longer used by a caller. This allows implementations with cache. +type TransactionalGatherer interface { + // Gather returns metrics in a lexicographically sorted slice + // of uniquely named MetricFamily protobufs. Gather ensures that the + // returned slice is valid and self-consistent so that it can be used + // for valid exposition. As an exception to the strict consistency + // requirements described for metric.Desc, Gather will tolerate + // different sets of label names for metrics of the same metric family. + // + // Even if an error occurs, Gather attempts to gather as many metrics as + // possible. Hence, if a non-nil error is returned, the returned + // MetricFamily slice could be nil (in case of a fatal error that + // prevented any meaningful metric collection) or contain a number of + // MetricFamily protobufs, some of which might be incomplete, and some + // might be missing altogether. The returned error (which might be a + // MultiError) explains the details. Note that this is mostly useful for + // debugging purposes. If the gathered protobufs are to be used for + // exposition in actual monitoring, it is almost always better to not + // expose an incomplete result and instead disregard the returned + // MetricFamily protobufs in case the returned error is non-nil. + // + // Important: done is expected to be triggered (even if the error occurs!) + // once caller does not need returned slice of dto.MetricFamily. + Gather() (_ []*dto.MetricFamily, done func(), err error) +} + +// ToTransactionalGatherer transforms Gatherer to transactional one with noop as done function. +func ToTransactionalGatherer(g Gatherer) TransactionalGatherer { + return &noTransactionGatherer{g: g} +} + +type noTransactionGatherer struct { + g Gatherer +} + +// Gather implements TransactionalGatherer interface. +func (g *noTransactionGatherer) Gather() (_ []*dto.MetricFamily, done func(), err error) { + mfs, err := g.g.Gather() + return mfs, func() {}, err +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/testutil/testutil.go b/vendor/github.com/prometheus/client_golang/prometheus/testutil/testutil.go index 9af60ce1d21a3..bf95beaf7ccd2 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/testutil/testutil.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/testutil/testutil.go @@ -167,7 +167,16 @@ func CollectAndCompare(c prometheus.Collector, expected io.Reader, metricNames . // exposition format. If any metricNames are provided, only metrics with those // names are compared. func GatherAndCompare(g prometheus.Gatherer, expected io.Reader, metricNames ...string) error { - got, err := g.Gather() + return TransactionalGatherAndCompare(prometheus.ToTransactionalGatherer(g), expected, metricNames...) +} + +// TransactionalGatherAndCompare gathers all metrics from the provided Gatherer and compares +// it to an expected output read from the provided Reader in the Prometheus text +// exposition format. If any metricNames are provided, only metrics with those +// names are compared. +func TransactionalGatherAndCompare(g prometheus.TransactionalGatherer, expected io.Reader, metricNames ...string) error { + got, done, err := g.Gather() + defer done() if err != nil { return fmt.Errorf("gathering metrics failed: %s", err) } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/value.go b/vendor/github.com/prometheus/client_golang/prometheus/value.go index b4e0ae11cb4b1..9f106952d8815 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/value.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/value.go @@ -21,6 +21,7 @@ import ( //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. "github.com/golang/protobuf/proto" + "github.com/prometheus/client_golang/prometheus/internal" "google.golang.org/protobuf/types/known/timestamppb" dto "github.com/prometheus/client_model/go" @@ -38,6 +39,23 @@ const ( UntypedValue ) +var ( + CounterMetricTypePtr = func() *dto.MetricType { d := dto.MetricType_COUNTER; return &d }() + GaugeMetricTypePtr = func() *dto.MetricType { d := dto.MetricType_GAUGE; return &d }() + UntypedMetricTypePtr = func() *dto.MetricType { d := dto.MetricType_UNTYPED; return &d }() +) + +func (v ValueType) ToDTO() *dto.MetricType { + switch v { + case CounterValue: + return CounterMetricTypePtr + case GaugeValue: + return GaugeMetricTypePtr + default: + return UntypedMetricTypePtr + } +} + // valueFunc is a generic metric for simple values retrieved on collect time // from a function. It implements Metric and Collector. Its effective type is // determined by ValueType. This is a low-level building block used by the @@ -91,11 +109,15 @@ func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil { return nil, err } + + metric := &dto.Metric{} + if err := populateMetric(valueType, value, MakeLabelPairs(desc, labelValues), nil, metric); err != nil { + return nil, err + } + return &constMetric{ - desc: desc, - valType: valueType, - val: value, - labelPairs: MakeLabelPairs(desc, labelValues), + desc: desc, + metric: metric, }, nil } @@ -110,10 +132,8 @@ func MustNewConstMetric(desc *Desc, valueType ValueType, value float64, labelVal } type constMetric struct { - desc *Desc - valType ValueType - val float64 - labelPairs []*dto.LabelPair + desc *Desc + metric *dto.Metric } func (m *constMetric) Desc() *Desc { @@ -121,7 +141,11 @@ func (m *constMetric) Desc() *Desc { } func (m *constMetric) Write(out *dto.Metric) error { - return populateMetric(m.valType, m.val, m.labelPairs, nil, out) + out.Label = m.metric.Label + out.Counter = m.metric.Counter + out.Gauge = m.metric.Gauge + out.Untyped = m.metric.Untyped + return nil } func populateMetric( @@ -170,7 +194,7 @@ func MakeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair { }) } labelPairs = append(labelPairs, desc.constLabelPairs...) - sort.Sort(labelPairSorter(labelPairs)) + sort.Sort(internal.LabelPairSorter(labelPairs)) return labelPairs } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/wrap.go b/vendor/github.com/prometheus/client_golang/prometheus/wrap.go index 74ee93280fed1..c29f94b72cb12 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/wrap.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/wrap.go @@ -20,6 +20,7 @@ import ( //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. "github.com/golang/protobuf/proto" + "github.com/prometheus/client_golang/prometheus/internal" dto "github.com/prometheus/client_model/go" ) @@ -182,7 +183,7 @@ func (m *wrappingMetric) Write(out *dto.Metric) error { Value: proto.String(lv), }) } - sort.Sort(labelPairSorter(out.Label)) + sort.Sort(internal.LabelPairSorter(out.Label)) return nil } diff --git a/vendor/modules.txt b/vendor/modules.txt index ad58af5b13b0b..77ff6d45acc0f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -322,7 +322,7 @@ github.com/golang/protobuf/ptypes/timestamp github.com/golang/protobuf/ptypes/wrappers # github.com/google/btree v1.0.1 => github.com/google/btree v1.0.1 github.com/google/btree -# github.com/google/cadvisor v0.43.1-0.20220111033110-a3b5f4f6c501 => github.com/google/cadvisor v0.43.1-0.20220111033110-a3b5f4f6c501 +# github.com/google/cadvisor v0.43.1-0.20220111033110-a3b5f4f6c501 => github.com/bwplotka/cadvisor v0.42.1-0.20220127113621-0d76a7d092f5 ## explicit github.com/google/cadvisor/accelerators github.com/google/cadvisor/cache/memory @@ -641,9 +641,10 @@ github.com/pmezard/go-difflib/difflib # github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 => github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 github.com/pquerna/cachecontrol github.com/pquerna/cachecontrol/cacheobject -# github.com/prometheus/client_golang v1.12.0 => github.com/prometheus/client_golang v1.12.0 +# github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b => github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b ## explicit github.com/prometheus/client_golang/prometheus +github.com/prometheus/client_golang/prometheus/cache github.com/prometheus/client_golang/prometheus/internal github.com/prometheus/client_golang/prometheus/promhttp github.com/prometheus/client_golang/prometheus/testutil @@ -2539,7 +2540,7 @@ sigs.k8s.io/yaml # github.com/golang/protobuf => github.com/golang/protobuf v1.5.2 # github.com/golangplus/testing => github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e # github.com/google/btree => github.com/google/btree v1.0.1 -# github.com/google/cadvisor => github.com/google/cadvisor v0.43.1-0.20220111033110-a3b5f4f6c501 +# github.com/google/cadvisor => github.com/bwplotka/cadvisor v0.42.1-0.20220127113621-0d76a7d092f5 # github.com/google/cel-go => github.com/google/cel-go v0.9.0 # github.com/google/cel-spec => github.com/google/cel-spec v0.6.0 # github.com/google/go-cmp => github.com/google/go-cmp v0.5.5 @@ -2652,7 +2653,7 @@ sigs.k8s.io/yaml # github.com/pmezard/go-difflib => github.com/pmezard/go-difflib v1.0.0 # github.com/posener/complete => github.com/posener/complete v1.1.1 # github.com/pquerna/cachecontrol => github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 -# github.com/prometheus/client_golang => github.com/prometheus/client_golang v1.12.0 +# github.com/prometheus/client_golang => github.com/prometheus/client_golang v1.12.1-0.20220126194218-961f8ca5e65b # github.com/prometheus/client_model => github.com/prometheus/client_model v0.2.0 # github.com/prometheus/common => github.com/prometheus/common v0.32.1 # github.com/prometheus/procfs => github.com/prometheus/procfs v0.7.3 From ae4c22068873e8d58dcf26ab6b5af2df116aac7b Mon Sep 17 00:00:00 2001 From: Elana Hashman Date: Thu, 28 Oct 2021 13:06:59 -0700 Subject: [PATCH 5/5] Use BlockingRegistry for cAdvisor container metrics --- hack/verify-prometheus-imports.sh | 1 + pkg/kubelet/server/server.go | 18 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/hack/verify-prometheus-imports.sh b/hack/verify-prometheus-imports.sh index 8b92336c63fb9..d212094884298 100755 --- a/hack/verify-prometheus-imports.sh +++ b/hack/verify-prometheus-imports.sh @@ -37,6 +37,7 @@ source "${KUBE_ROOT}/hack/lib/util.sh" # See: https://github.com/kubernetes/kubernetes/issues/89267 allowed_prometheus_importers=( ./cluster/images/etcd-version-monitor/etcd-version-monitor.go + ./pkg/kubelet/server/server.go ./pkg/volume/util/operationexecutor/operation_generator_test.go ./staging/src/k8s.io/component-base/metrics/collector.go ./staging/src/k8s.io/component-base/metrics/collector_test.go diff --git a/pkg/kubelet/server/server.go b/pkg/kubelet/server/server.go index aff9fe0c3cd84..5df29f569efb5 100644 --- a/pkg/kubelet/server/server.go +++ b/pkg/kubelet/server/server.go @@ -33,6 +33,8 @@ import ( "time" "github.com/emicklei/go-restful" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" cadvisormetrics "github.com/google/cadvisor/container" cadvisorapi "github.com/google/cadvisor/info/v1" cadvisorv2 "github.com/google/cadvisor/info/v2" @@ -356,7 +358,7 @@ func (s *Server) InstallDefaultHandlers() { s.restfulCont.Handle(metricsPath, legacyregistry.Handler()) // cAdvisor metrics are exposed under the secured handler as well - r := compbasemetrics.NewKubeRegistry() + r := prometheus.NewRegistry() includedMetrics := cadvisormetrics.MetricSet{ cadvisormetrics.CpuUsageMetrics: struct{}{}, @@ -375,15 +377,13 @@ func (s *Server) InstallDefaultHandlers() { includedMetrics[cadvisormetrics.AcceleratorUsageMetrics] = struct{}{} } - cadvisorOpts := cadvisorv2.RequestOptions{ - IdType: cadvisorv2.TypeName, - Count: 1, - Recursive: true, - } - r.RawMustRegister(metrics.NewPrometheusCollector(prometheusHostAdapter{s.host}, containerPrometheusLabelsFunc(s.host), includedMetrics, clock.RealClock{}, cadvisorOpts)) - r.RawMustRegister(metrics.NewPrometheusMachineCollector(prometheusHostAdapter{s.host}, includedMetrics)) + container := metrics.NewContainerCollector(prometheusHostAdapter{s.host}, containerPrometheusLabelsFunc(s.host), includedMetrics, clock.RealClock{}) + machine := metrics.NewMachineCollector(prometheusHostAdapter{s.host}, includedMetrics) + nameTypeCache := metrics.NewCachedGatherer(container.Collect, machine.Collect) + nameTypeGatherer := prometheus.NewMultiTRegistry(prometheus.ToTransactionalGatherer(r), nameTypeCache) + s.restfulCont.Handle(cadvisorMetricsPath, - compbasemetrics.HandlerFor(r, compbasemetrics.HandlerOpts{ErrorHandling: compbasemetrics.ContinueOnError}), + promhttp.HandlerForTransactional(nameTypeGatherer, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError}), ) s.addMetricsBucketMatcher("metrics/resource")