From d8de5c7bd070cdc19337c666b3339df557a22134 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Apr 2026 15:49:54 +0000 Subject: [PATCH] Bump github.com/opencontainers/runc from 1.2.3 to 1.3.0 Bumps [github.com/opencontainers/runc](https://github.com/opencontainers/runc) from 1.2.3 to 1.3.0. - [Release notes](https://github.com/opencontainers/runc/releases) - [Changelog](https://github.com/opencontainers/runc/blob/main/CHANGELOG.md) - [Commits](https://github.com/opencontainers/runc/compare/v1.2.3...v1.3.0) --- updated-dependencies: - dependency-name: github.com/opencontainers/runc dependency-version: 1.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 20 +- go.sum | 48 +- vendor/cyphar.com/go-pathrs/.golangci.yml | 2 +- vendor/cyphar.com/go-pathrs/doc.go | 2 +- vendor/cyphar.com/go-pathrs/handle_linux.go | 10 +- .../go-pathrs/internal/fdutils/fd_linux.go | 2 +- .../internal/libpathrs/error_unix.go | 2 +- .../internal/libpathrs/libpathrs_linux.go | 6 +- .../go-pathrs/procfs/procfs_linux.go | 15 +- vendor/cyphar.com/go-pathrs/root_linux.go | 30 +- vendor/cyphar.com/go-pathrs/utils_linux.go | 2 +- .../checkpoint-restore/go-criu/v6/.gitignore | 13 - .../go-criu/v6/.golangci.yml | 10 - .../checkpoint-restore/go-criu/v7/.gitignore | 18 + .../go-criu/v7/.golangci.yml | 22 + .../go-criu/{v6 => v7}/LICENSE | 0 .../checkpoint-restore/go-criu/v7/MAINTAINERS | 4 + .../go-criu/{v6 => v7}/Makefile | 15 +- .../go-criu/{v6 => v7}/README.md | 23 +- .../checkpoint-restore/go-criu/v7/codecov.yml | 2 + .../go-criu/{v6 => v7}/features.go | 6 +- .../go-criu/{v6 => v7}/main.go | 42 +- .../go-criu/{v6 => v7}/notify.go | 0 .../go-criu/{v6 => v7}/rpc/rpc.pb.go | 551 ++++++++++-------- .../go-criu/{v6 => v7}/rpc/rpc.proto | 9 +- .../coreos/go-systemd/v22/dbus/dbus.go | 7 +- .../coreos/go-systemd/v22/dbus/methods.go | 287 +++------ .../coreos/go-systemd/v22/dbus/set.go | 17 +- .../go-systemd/v22/dbus/subscription.go | 36 +- .../go-systemd/v22/dbus/subscription_set.go | 16 +- .../cpuguy83/go-md2man/v2/md2man/md2man.go | 1 + .../cpuguy83/go-md2man/v2/md2man/roff.go | 26 +- .../cyphar/filepath-securejoin/CHANGELOG.md | 88 ++- .../cyphar/filepath-securejoin/VERSION | 2 +- .../pathrs-lite/internal/fd/openat2_linux.go | 4 +- .../gocompat/gocompat_atomic_go119.go | 19 + .../gocompat/gocompat_atomic_unsupported.go | 48 ++ .../internal/gopathrs/lookup_linux.go | 9 +- .../internal/gopathrs/openat2_linux.go | 1 + .../internal/linux/openat2_linux.go | 16 +- .../opencontainers/cgroups/cgroups.go | 5 + .../opencontainers/cgroups/config_linux.go | 4 +- .../opencontainers/cgroups/fs/cpuacct.go | 12 +- .../opencontainers/cgroups/fs/fs.go | 29 + .../opencontainers/cgroups/fs/pids.go | 27 +- .../opencontainers/cgroups/fs2/fs2.go | 13 + .../opencontainers/cgroups/fs2/io.go | 19 +- .../opencontainers/cgroups/fs2/pids.go | 20 +- .../opencontainers/cgroups/stats.go | 4 + .../opencontainers/cgroups/systemd/common.go | 15 + .../opencontainers/cgroups/systemd/dbus.go | 26 +- .../opencontainers/cgroups/systemd/v1.go | 32 +- .../opencontainers/cgroups/systemd/v2.go | 25 +- .../runc/internal/linux/eintr.go | 28 + .../runc/internal/linux/linux.go | 96 ++- .../runc/internal/pathrs/mkdirall.go | 51 ++ .../internal/pathrs/mkdirall_pathrslite.go | 30 +- .../runc/internal/pathrs/path.go | 82 +++ .../runc/internal/pathrs/root_pathrslite.go | 13 +- .../runc/libcontainer/apparmor/apparmor.go | 22 +- .../libcontainer/apparmor/apparmor_linux.go | 10 +- .../libcontainer/capabilities/capabilities.go | 15 +- .../runc/libcontainer/cmd_clone.go | 37 ++ .../runc/libcontainer/configs/config.go | 93 +-- .../runc/libcontainer/configs/doc.go | 2 + .../runc/libcontainer/configs/intelrdt.go | 7 + .../runc/libcontainer/configs/memorypolicy.go | 33 ++ .../runc/libcontainer/configs/mount_linux.go | 18 +- .../libcontainer/configs/namespaces_linux.go | 5 +- .../runc/libcontainer/configs/netdevices.go | 7 + .../runc/libcontainer/configs/network.go | 44 +- .../runc/libcontainer/configs/validate/doc.go | 2 + .../libcontainer/configs/validate/intelrdt.go | 41 ++ .../libcontainer/configs/validate/rootless.go | 2 +- .../configs/validate/validator.go | 106 +++- .../runc/libcontainer/console_linux.go | 12 +- .../runc/libcontainer/container_linux.go | 84 ++- .../runc/libcontainer/criu_linux.go | 35 +- .../runc/libcontainer/devices/device_unix.go | 2 +- .../exeseal/cloned_binary_linux.go | 2 +- .../runc/libcontainer/factory_linux.go | 10 +- .../runc/libcontainer/init_linux.go | 30 +- .../runc/libcontainer/intelrdt/intelrdt.go | 151 +++-- .../runc/libcontainer/intelrdt/stats.go | 3 + .../internal/userns/userns_maps_linux.go | 2 +- .../internal/userns/usernsfd_linux.go | 2 +- .../runc/libcontainer/logs/logs.go | 35 +- .../runc/libcontainer/mount_linux.go | 9 +- .../runc/libcontainer/network_linux.go | 132 +++++ .../runc/libcontainer/notify_linux.go | 4 +- .../runc/libcontainer/process_linux.go | 359 +++++++++--- .../runc/libcontainer/rootfs_linux.go | 241 ++++---- .../runc/libcontainer/seccomp/config.go | 25 +- .../seccomp/patchbpf/enosys_linux.go | 11 + .../runc/libcontainer/setns_init_linux.go | 42 +- .../runc/libcontainer/standard_init_linux.go | 41 +- .../runc/libcontainer/state_linux.go | 3 +- .../opencontainers/runc/libcontainer/sync.go | 2 +- .../runc/libcontainer/sync_unix.go | 16 +- .../runc/libcontainer/system/linux.go | 9 - .../runc/libcontainer/system/rlimit_linux.go | 2 - .../runc/libcontainer/utils/cmsg.go | 12 +- .../runc/libcontainer/utils/utils.go | 73 +-- .../runc/libcontainer/utils/utils_unix.go | 24 +- .../opencontainers/runc/types/events.go | 21 +- .../runtime-spec/specs-go/config.go | 166 +++++- .../specs-go/features/features.go | 24 + .../runtime-spec/specs-go/version.go | 4 +- .../seccomp/libseccomp-golang/.golangci.yml | 10 +- .../seccomp/libseccomp-golang/CHANGELOG | 15 + .../seccomp/libseccomp-golang/seccomp.go | 242 ++++++-- .../libseccomp-golang/seccomp_internal.go | 78 ++- vendor/modules.txt | 34 +- 113 files changed, 2898 insertions(+), 1475 deletions(-) delete mode 100644 vendor/github.com/checkpoint-restore/go-criu/v6/.gitignore delete mode 100644 vendor/github.com/checkpoint-restore/go-criu/v6/.golangci.yml create mode 100644 vendor/github.com/checkpoint-restore/go-criu/v7/.gitignore create mode 100644 vendor/github.com/checkpoint-restore/go-criu/v7/.golangci.yml rename vendor/github.com/checkpoint-restore/go-criu/{v6 => v7}/LICENSE (100%) create mode 100644 vendor/github.com/checkpoint-restore/go-criu/v7/MAINTAINERS rename vendor/github.com/checkpoint-restore/go-criu/{v6 => v7}/Makefile (78%) rename vendor/github.com/checkpoint-restore/go-criu/{v6 => v7}/README.md (89%) create mode 100644 vendor/github.com/checkpoint-restore/go-criu/v7/codecov.yml rename vendor/github.com/checkpoint-restore/go-criu/{v6 => v7}/features.go (91%) rename vendor/github.com/checkpoint-restore/go-criu/{v6 => v7}/main.go (84%) rename vendor/github.com/checkpoint-restore/go-criu/{v6 => v7}/notify.go (100%) rename vendor/github.com/checkpoint-restore/go-criu/{v6 => v7}/rpc/rpc.pb.go (69%) rename vendor/github.com/checkpoint-restore/go-criu/{v6 => v7}/rpc/rpc.proto (94%) create mode 100644 vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_atomic_go119.go create mode 100644 vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_atomic_unsupported.go create mode 100644 vendor/github.com/opencontainers/runc/internal/linux/eintr.go create mode 100644 vendor/github.com/opencontainers/runc/internal/pathrs/mkdirall.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/cmd_clone.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/configs/doc.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/configs/memorypolicy.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/configs/netdevices.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/configs/validate/doc.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/configs/validate/intelrdt.go diff --git a/go.mod b/go.mod index daac5892c3..c816b306be 100644 --- a/go.mod +++ b/go.mod @@ -48,14 +48,14 @@ require ( github.com/mattn/go-shellwords v1.0.12 github.com/moby/sys/user v0.4.0 github.com/open-policy-agent/opa v0.70.0 - github.com/opencontainers/cgroups v0.0.4 - github.com/opencontainers/runc v1.3.3 - github.com/opencontainers/runtime-spec v1.2.1 + github.com/opencontainers/cgroups v0.0.6 + github.com/opencontainers/runc v1.4.2 + github.com/opencontainers/runtime-spec v1.3.0 github.com/pelletier/go-toml v1.9.5 github.com/pkg/errors v0.9.1 github.com/samber/lo v1.52.0 github.com/sirupsen/logrus v1.9.3 - github.com/urfave/cli v1.22.16 + github.com/urfave/cli v1.22.17 github.com/urfave/cli/v2 v2.27.6 github.com/vishvananda/netlink v1.3.1 github.com/vishvananda/netns v0.0.5 @@ -70,21 +70,21 @@ require ( ) require ( - cyphar.com/go-pathrs v0.2.1 // indirect + cyphar.com/go-pathrs v0.2.4 // indirect github.com/OneOfOne/xxhash v1.2.8 // indirect github.com/agnivade/levenshtein v1.2.0 // indirect github.com/akavel/rsrc v0.10.2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/checkpoint-restore/go-criu/v6 v6.3.0 // indirect + github.com/checkpoint-restore/go-criu/v7 v7.2.0 // indirect github.com/cilium/ebpf v0.17.3 // indirect github.com/containerd/continuity v0.4.5 // indirect github.com/containerd/fifo v1.1.0 // indirect github.com/containerd/protobuild v0.3.0 // indirect github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect - github.com/cyphar/filepath-securejoin v0.6.0 // indirect + github.com/coreos/go-systemd/v22 v22.7.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect + github.com/cyphar/filepath-securejoin v0.6.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/docker/cli v29.2.0+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect @@ -126,7 +126,7 @@ require ( github.com/prometheus/procfs v0.15.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/seccomp/libseccomp-golang v0.10.0 // indirect + github.com/seccomp/libseccomp-golang v0.11.1 // indirect github.com/tchap/go-patricia/v2 v2.3.2 // indirect github.com/vbatts/tar-split v0.11.5 // indirect github.com/veraison/go-cose v1.1.0 // indirect diff --git a/go.sum b/go.sum index fc784d110f..7d13a377a5 100644 --- a/go.sum +++ b/go.sum @@ -335,13 +335,13 @@ cloud.google.com/go/vpcaccess v1.8.6/go.mod h1:61yymNplV1hAbo8+kBOFO7Vs+4ZHYI244 cloud.google.com/go/webrisk v1.11.1/go.mod h1:+9SaepGg2lcp1p0pXuHyz3R2Yi2fHKKb4c1Q9y0qbtA= cloud.google.com/go/websecurityscanner v1.7.6/go.mod h1:ucaaTO5JESFn5f2pjdX01wGbQ8D6h79KHrmO2uGZeiY= cloud.google.com/go/workflows v1.14.2/go.mod h1:5nqKjMD+MsJs41sJhdVrETgvD5cOK3hUcAs8ygqYvXQ= -cyphar.com/go-pathrs v0.2.1 h1:9nx1vOgwVvX1mNBWDu93+vaceedpbsDqo+XuBGL40b8= -cyphar.com/go-pathrs v0.2.1/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc= +cyphar.com/go-pathrs v0.2.4 h1:iD/mge36swa1UFKdINkr1Frkpp6wZsy3YYEildj9cLY= +cyphar.com/go-pathrs v0.2.4/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2/go.mod h1:dppbR7CwXD4pgtV9t3wD1812RaLDcBjtblcDF5f1vI0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.0/go.mod h1:p2puVVSKjQ84Qb1gzw2XHLs34WQyHTYFZLaVxypAFYs= @@ -410,8 +410,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/checkpoint-restore/go-criu/v6 v6.3.0 h1:mIdrSO2cPNWQY1truPg6uHLXyKHk3Z5Odx4wjKOASzA= -github.com/checkpoint-restore/go-criu/v6 v6.3.0/go.mod h1:rrRTN/uSwY2X+BPRl/gkulo9gsKOSAeVp9/K2tv7xZI= +github.com/checkpoint-restore/go-criu/v7 v7.2.0 h1:qGiWA4App1gGlEfIJ68WR9jbezV9J7yZdjzglezcqKo= +github.com/checkpoint-restore/go-criu/v7 v7.2.0/go.mod h1:u0LCWLg0w4yqqu14aXhiB4YD3a1qd8EcCEg7vda5dwo= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -477,14 +477,13 @@ github.com/containerd/ttrpc v1.2.7 h1:qIrroQvuOL9HQ1X6KHe2ohc7p+HP/0VE6XPU7elJRq github.com/containerd/ttrpc v1.2.7/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o= github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++dYSw40= github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= -github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA= +github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w= +github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= +github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.6.0 h1:BtGB77njd6SVO6VztOHfPxKitJvd/VPT+OFBFMOi1Is= -github.com/cyphar/filepath-securejoin v0.6.0/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc= +github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE= +github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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= @@ -590,7 +589,6 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-yaml v1.9.8/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE= github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFTWckfng= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -769,7 +767,6 @@ github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/josephspurrier/goversioninfo v1.5.0 h1:9TJtORoyf4YMoWSOo/cXFN9A/lB3PniJ91OxIH6e7Zg= github.com/josephspurrier/goversioninfo v1.5.0/go.mod h1:6MoTvFZ6GKJkzcdLnU5T/RGYUbHQbKpYeNP0AgQLd2o= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= @@ -862,16 +859,16 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/open-policy-agent/opa v0.70.0 h1:B3cqCN2iQAyKxK6+GI+N40uqkin+wzIrM7YA60t9x1U= github.com/open-policy-agent/opa v0.70.0/go.mod h1:Y/nm5NY0BX0BqjBriKUiV81sCl8XOjjvqQG7dXrggtI= -github.com/opencontainers/cgroups v0.0.4 h1:XVj8P/IHVms/j+7eh8ggdkTLAxjz84ZzuFyGoE28DR4= -github.com/opencontainers/cgroups v0.0.4/go.mod h1:s8lktyhlGUqM7OSRL5P7eAW6Wb+kWPNvt4qvVfzA5vs= +github.com/opencontainers/cgroups v0.0.6 h1:tfZFWTIIGaUUFImTyuTg+Mr5x8XRiSdZESgEBW7UxuI= +github.com/opencontainers/cgroups v0.0.6/go.mod h1:oWVzJsKK0gG9SCRBfTpnn16WcGEqDI8PAcpMGbqWxcs= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= -github.com/opencontainers/runc v1.3.3 h1:qlmBbbhu+yY0QM7jqfuat7M1H3/iXjju3VkP9lkFQr4= -github.com/opencontainers/runc v1.3.3/go.mod h1:D7rL72gfWxVs9cJ2/AayxB0Hlvn9g0gaF1R7uunumSI= -github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww= -github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runc v1.4.2 h1:/AEjjXuVH9lTRl9ZyUFQj7oWBM7Xv00qFV6Vx9q5N3o= +github.com/opencontainers/runc v1.4.2/go.mod h1:ufk5PTTsy5pnGBAvTh50e+eqGk01pYH2YcVxh557Qlk= +github.com/opencontainers/runtime-spec v1.3.0 h1:YZupQUdctfhpZy3TM39nN9Ika5CBWT5diQ8ibYCRkxg= +github.com/opencontainers/runtime-spec v1.3.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.13.0 h1:Zza88GWezyT7RLql12URvoxsbLfjFx988+LGaWfbL84= github.com/opencontainers/selinux v1.13.0/go.mod h1:XxWTed+A/s5NNq4GmYScVy+9jzXhGBVEOAyucdRUY8s= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= @@ -922,8 +919,8 @@ github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfF github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw= github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= -github.com/seccomp/libseccomp-golang v0.10.0 h1:aA4bp+/Zzi0BnWZ2F1wgNBs5gTpm+na2rWM6M9YjLpY= -github.com/seccomp/libseccomp-golang v0.10.0/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/seccomp/libseccomp-golang v0.11.1 h1:wuk4ZjSx6kyQII4rj6G6fvVzRHQaSiPvccJazDagu4g= +github.com/seccomp/libseccomp-golang v0.11.1/go.mod h1:5m1Lk8E9OwgZTTVz4bBOer7JuazaBa+xTkM895tDiWc= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -931,8 +928,6 @@ github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY52 github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= -github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -961,8 +956,8 @@ github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vl github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= -github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ= -github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po= +github.com/urfave/cli v1.22.17 h1:SYzXoiPfQjHBbkYxbew5prZHS1TOLT3ierW8SYLqtVQ= +github.com/urfave/cli v1.22.17/go.mod h1:b0ht0aqgH/6pBYzzxURyrM4xXNgsoT/n2ZzwQiEhNVo= github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g= github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts= @@ -1426,7 +1421,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/cyphar.com/go-pathrs/.golangci.yml b/vendor/cyphar.com/go-pathrs/.golangci.yml index 2778a3268e..a28cbd2a4f 100644 --- a/vendor/cyphar.com/go-pathrs/.golangci.yml +++ b/vendor/cyphar.com/go-pathrs/.golangci.yml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: MPL-2.0 # # libpathrs: safe path resolution on Linux -# Copyright (C) 2019-2025 Aleksa Sarai # Copyright (C) 2019-2025 SUSE LLC +# Copyright (C) 2026 Aleksa Sarai # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/vendor/cyphar.com/go-pathrs/doc.go b/vendor/cyphar.com/go-pathrs/doc.go index a7ee4bc487..c3b4eedd0f 100644 --- a/vendor/cyphar.com/go-pathrs/doc.go +++ b/vendor/cyphar.com/go-pathrs/doc.go @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 /* * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai * Copyright (C) 2019-2025 SUSE LLC + * Copyright (C) 2026 Aleksa Sarai * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/vendor/cyphar.com/go-pathrs/handle_linux.go b/vendor/cyphar.com/go-pathrs/handle_linux.go index 3221ef6738..6ed0b7af7a 100644 --- a/vendor/cyphar.com/go-pathrs/handle_linux.go +++ b/vendor/cyphar.com/go-pathrs/handle_linux.go @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MPL-2.0 /* * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai * Copyright (C) 2019-2025 SUSE LLC + * Copyright (C) 2026 Aleksa Sarai * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -30,11 +30,9 @@ import ( // you can try to use [Root.Open] or [Root.OpenFile]. // // It is critical that perform all relevant operations through this [Handle] -// (rather than fetching the file descriptor yourself with [Handle.IntoRaw]), +// (rather than fetching the underlying [os.File] yourself with [Handle.IntoFile]), // because the security properties of libpathrs depend on users doing all // relevant filesystem operations through libpathrs. -// -// [os.File]: https://pkg.go.dev/os#File type Handle struct { inner *os.File } @@ -43,7 +41,7 @@ type Handle struct { // handle will be copied by this method, so the original handle should still be // freed by the caller. // -// This is effectively the inverse operation of [Handle.IntoRaw], and is used +// This is effectively the inverse operation of [Handle.IntoFile], and is used // for "deserialising" pathrs root handles. func HandleFromFile(file *os.File) (*Handle, error) { newFile, err := fdutils.DupFile(file) @@ -92,8 +90,6 @@ func (h *Handle) OpenFile(flags int) (*os.File, error) { // calling [Handle.Close] will also close any copies of the returned [os.File]. // If you want to get an independent copy, use [Handle.Clone] followed by // [Handle.IntoFile] on the cloned [Handle]. -// -// [os.File]: https://pkg.go.dev/os#File func (h *Handle) IntoFile() *os.File { // TODO: Figure out if we really don't want to make a copy. // TODO: We almost certainly want to clear r.inner here, but we can't do diff --git a/vendor/cyphar.com/go-pathrs/internal/fdutils/fd_linux.go b/vendor/cyphar.com/go-pathrs/internal/fdutils/fd_linux.go index 41aea3e4b3..418b298149 100644 --- a/vendor/cyphar.com/go-pathrs/internal/fdutils/fd_linux.go +++ b/vendor/cyphar.com/go-pathrs/internal/fdutils/fd_linux.go @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MPL-2.0 /* * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai * Copyright (C) 2019-2025 SUSE LLC + * Copyright (C) 2026 Aleksa Sarai * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/vendor/cyphar.com/go-pathrs/internal/libpathrs/error_unix.go b/vendor/cyphar.com/go-pathrs/internal/libpathrs/error_unix.go index c9f416de01..8f610ca564 100644 --- a/vendor/cyphar.com/go-pathrs/internal/libpathrs/error_unix.go +++ b/vendor/cyphar.com/go-pathrs/internal/libpathrs/error_unix.go @@ -5,8 +5,8 @@ // SPDX-License-Identifier: MPL-2.0 /* * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai * Copyright (C) 2019-2025 SUSE LLC + * Copyright (C) 2026 Aleksa Sarai * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/vendor/cyphar.com/go-pathrs/internal/libpathrs/libpathrs_linux.go b/vendor/cyphar.com/go-pathrs/internal/libpathrs/libpathrs_linux.go index c07b80e307..d54497a5b7 100644 --- a/vendor/cyphar.com/go-pathrs/internal/libpathrs/libpathrs_linux.go +++ b/vendor/cyphar.com/go-pathrs/internal/libpathrs/libpathrs_linux.go @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MPL-2.0 /* * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai * Copyright (C) 2019-2025 SUSE LLC + * Copyright (C) 2026 Aleksa Sarai * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -100,7 +100,7 @@ func InRootReadlink(rootFd uintptr, path string) (string, error) { size := 128 for { linkBuf := make([]byte, size) - n := C.pathrs_inroot_readlink(C.int(rootFd), cPath, C.cast_ptr(unsafe.Pointer(&linkBuf[0])), C.ulong(len(linkBuf))) + n := C.pathrs_inroot_readlink(C.int(rootFd), cPath, C.cast_ptr(unsafe.Pointer(&linkBuf[0])), C.size_t(len(linkBuf))) switch { case int(n) < C.__PATHRS_MAX_ERR_VALUE: return "", fetchError(n) @@ -301,7 +301,7 @@ func ProcReadlinkat(procRootFd int, base ProcBase, path string) (string, error) linkBuf := make([]byte, size) n := C.pathrs_proc_readlinkat( C.int(procRootFd), cBase, cPath, - C.cast_ptr(unsafe.Pointer(&linkBuf[0])), C.ulong(len(linkBuf))) + C.cast_ptr(unsafe.Pointer(&linkBuf[0])), C.size_t(len(linkBuf))) switch { case int(n) < C.__PATHRS_MAX_ERR_VALUE: return "", fetchError(n) diff --git a/vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go b/vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go index 5533c427cb..915e9ccdb5 100644 --- a/vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go +++ b/vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MPL-2.0 /* * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai * Copyright (C) 2019-2025 SUSE LLC + * Copyright (C) 2026 Aleksa Sarai * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -56,16 +56,15 @@ var ( // *before* you call wait(2)or any equivalent method that could reap // zombies). func ProcPid(pid int) ProcBase { - if pid < 0 || pid >= 1<<31 { + if pid < 0 || uint64(pid) >= 1<<31 { panic("invalid ProcBasePid value") // TODO: should this be an error? } - return ProcBase{inner: libpathrs.ProcPid(uint32(pid))} + pid32 := uint32(pid) //nolint:gosec // G115 false positive + return ProcBase{inner: libpathrs.ProcPid(pid32)} } // ThreadCloser is a callback that needs to be called when you are done // operating on an [os.File] fetched using [Handle.OpenThreadSelf]. -// -// [os.File]: https://pkg.go.dev/os#File type ThreadCloser func() // Handle is a wrapper around an *os.File handle to "/proc", which can be @@ -181,8 +180,6 @@ func (proc *Handle) OpenRoot(path string, flags int) (*os.File, error) { // Unlike [Handle.OpenThreadSelf], this method does not involve locking // the goroutine to the current OS thread and so is simpler to use and // theoretically has slightly less overhead. -// -// [runtime.LockOSThread]: https://pkg.go.dev/runtime#LockOSThread func (proc *Handle) OpenSelf(path string, flags int) (*os.File, error) { file, closer, err := proc.open(ProcSelf, path, flags) if closer != nil { @@ -228,10 +225,6 @@ func (proc *Handle) OpenPid(pid int, path string, flags int) (*os.File, error) { // callback MUST be called AFTER you have finished using the returned // [os.File]. This callback is completely separate to [os.File.Close], so it // must be called regardless of how you close the handle. -// -// [runtime.LockOSThread]: https://pkg.go.dev/runtime#LockOSThread -// [os.File]: https://pkg.go.dev/os#File -// [os.File.Close]: https://pkg.go.dev/os#File.Close func (proc *Handle) OpenThreadSelf(path string, flags int) (*os.File, ThreadCloser, error) { return proc.open(ProcThreadSelf, path, flags) } diff --git a/vendor/cyphar.com/go-pathrs/root_linux.go b/vendor/cyphar.com/go-pathrs/root_linux.go index edc9e4c87f..5bc2e90717 100644 --- a/vendor/cyphar.com/go-pathrs/root_linux.go +++ b/vendor/cyphar.com/go-pathrs/root_linux.go @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MPL-2.0 /* * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai * Copyright (C) 2019-2025 SUSE LLC + * Copyright (C) 2026 Aleksa Sarai * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -54,8 +54,6 @@ func OpenRoot(path string) (*Root, error) { // still be closed by the caller. // // This is effectively the inverse operation of [Root.IntoFile]. -// -// [os.File]: https://pkg.go.dev/os#File func RootFromFile(file *os.File) (*Root, error) { newFile, err := fdutils.DupFile(file) if err != nil { @@ -109,8 +107,6 @@ func (r *Root) ResolveNoFollow(path string) (*Handle, error) { // ergonomic to use. // // This is effectively equivalent to [os.Open]. -// -// [os.Open]: https://pkg.go.dev/os#Open func (r *Root) Open(path string) (*os.File, error) { return r.OpenFile(path, os.O_RDONLY) } @@ -127,8 +123,6 @@ func (r *Root) Open(path string) (*os.File, error) { // // This is effectively equivalent to [os.OpenFile], except that os.O_CREAT is // not supported. -// -// [os.OpenFile]: https://pkg.go.dev/os#OpenFile func (r *Root) OpenFile(path string, flags int) (*os.File, error) { return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (*os.File, error) { fd, err := libpathrs.InRootOpen(rootFd, path, flags) @@ -145,8 +139,6 @@ func (r *Root) OpenFile(path string, flags int) (*os.File, error) { // // Unlike [os.Create], if the file already exists an error is created rather // than the file being opened and truncated. -// -// [os.Create]: https://pkg.go.dev/os#Create func (r *Root) Create(path string, flags int, mode os.FileMode) (*os.File, error) { unixMode, err := toUnixMode(mode, false) if err != nil { @@ -194,8 +186,6 @@ func (r *Root) RemoveFile(path string) error { // directory tree. // // This is effectively equivalent to [os.Remove]. -// -// [os.Remove]: https://pkg.go.dev/os#Remove func (r *Root) Remove(path string) error { // In order to match os.Remove's implementation we need to also do both // syscalls unconditionally and adjust the error based on whether @@ -219,8 +209,6 @@ func (r *Root) Remove(path string) error { // RemoveAll recursively deletes a path and all of its children. // // This is effectively equivalent to [os.RemoveAll]. -// -// [os.RemoveAll]: https://pkg.go.dev/os#RemoveAll func (r *Root) RemoveAll(path string) error { _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { err := libpathrs.InRootRemoveAll(rootFd, path) @@ -233,8 +221,6 @@ func (r *Root) RemoveAll(path string) error { // mode is used for the new directory (the process's umask applies). // // This is effectively equivalent to [os.Mkdir]. -// -// [os.Mkdir]: https://pkg.go.dev/os#Mkdir func (r *Root) Mkdir(path string, mode os.FileMode) error { unixMode, err := toUnixMode(mode, false) if err != nil { @@ -253,8 +239,6 @@ func (r *Root) Mkdir(path string, mode os.FileMode) error { // directories created by this function (the process's umask applies). // // This is effectively equivalent to [os.MkdirAll]. -// -// [os.MkdirAll]: https://pkg.go.dev/os#MkdirAll func (r *Root) MkdirAll(path string, mode os.FileMode) (*Handle, error) { unixMode, err := toUnixMode(mode, false) if err != nil { @@ -278,9 +262,7 @@ func (r *Root) MkdirAll(path string, mode os.FileMode) (*Handle, error) { // directory tree. The provided mode is used for the new directory (the // process's umask applies). // -// This is effectively equivalent to [unix.Mknod]. -// -// [unix.Mknod]: https://pkg.go.dev/golang.org/x/sys/unix#Mknod +// This is effectively equivalent to [golang.org/x/sys/unix.Mknod]. func (r *Root) Mknod(path string, mode os.FileMode, dev uint64) error { unixMode, err := toUnixMode(mode, true) if err != nil { @@ -298,8 +280,6 @@ func (r *Root) Mknod(path string, mode os.FileMode, dev uint64) error { // created at path and is a link to target. // // This is effectively equivalent to [os.Symlink]. -// -// [os.Symlink]: https://pkg.go.dev/os#Symlink func (r *Root) Symlink(path, target string) error { _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { err := libpathrs.InRootSymlink(rootFd, path, target) @@ -314,8 +294,6 @@ func (r *Root) Symlink(path, target string) error { // host). // // This is effectively equivalent to [os.Link]. -// -// [os.Link]: https://pkg.go.dev/os#Link func (r *Root) Hardlink(path, target string) error { _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { err := libpathrs.InRootHardlink(rootFd, path, target) @@ -327,8 +305,6 @@ func (r *Root) Hardlink(path, target string) error { // Readlink returns the target of a symlink with a [Root]'s directory tree. // // This is effectively equivalent to [os.Readlink]. -// -// [os.Readlink]: https://pkg.go.dev/os#Readlink func (r *Root) Readlink(path string) (string, error) { return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (string, error) { return libpathrs.InRootReadlink(rootFd, path) @@ -345,8 +321,6 @@ func (r *Root) Readlink(path string) (string, error) { // calling [Root.Close] will also close any copies of the returned [os.File]. // If you want to get an independent copy, use [Root.Clone] followed by // [Root.IntoFile] on the cloned [Root]. -// -// [os.File]: https://pkg.go.dev/os#File func (r *Root) IntoFile() *os.File { // TODO: Figure out if we really don't want to make a copy. // TODO: We almost certainly want to clear r.inner here, but we can't do diff --git a/vendor/cyphar.com/go-pathrs/utils_linux.go b/vendor/cyphar.com/go-pathrs/utils_linux.go index 2208d608f8..b4e7e08e7d 100644 --- a/vendor/cyphar.com/go-pathrs/utils_linux.go +++ b/vendor/cyphar.com/go-pathrs/utils_linux.go @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MPL-2.0 /* * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai * Copyright (C) 2019-2025 SUSE LLC + * Copyright (C) 2026 Aleksa Sarai * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/vendor/github.com/checkpoint-restore/go-criu/v6/.gitignore b/vendor/github.com/checkpoint-restore/go-criu/v6/.gitignore deleted file mode 100644 index 5518060133..0000000000 --- a/vendor/github.com/checkpoint-restore/go-criu/v6/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -test/test -test/test.coverage -test/piggie/piggie -test/phaul/phaul -test/phaul/phaul.coverage -test/loop/loop -test/crit/crit-test -test/crit/test-imgs -image -scripts/*.h -scripts/expected.go -scripts/output.go -crit/bin diff --git a/vendor/github.com/checkpoint-restore/go-criu/v6/.golangci.yml b/vendor/github.com/checkpoint-restore/go-criu/v6/.golangci.yml deleted file mode 100644 index c4515109b1..0000000000 --- a/vendor/github.com/checkpoint-restore/go-criu/v6/.golangci.yml +++ /dev/null @@ -1,10 +0,0 @@ -linters: - presets: - - bugs - - performance - - unused - - format - -linters-settings: - exhaustive: - default-signifies-exhaustive: true diff --git a/vendor/github.com/checkpoint-restore/go-criu/v7/.gitignore b/vendor/github.com/checkpoint-restore/go-criu/v7/.gitignore new file mode 100644 index 0000000000..eb1b08bc47 --- /dev/null +++ b/vendor/github.com/checkpoint-restore/go-criu/v7/.gitignore @@ -0,0 +1,18 @@ +test/test +test/test.coverage +test/piggie/piggie +test/phaul/phaul +test/phaul/phaul.coverage +test/loop/loop +test/mmapper/mmapper +test/crit/crit-test +test/crit/test-imgs +test/crit/crit-test.coverage +test/.coverage/ +image +scripts/magic-gen/*.h +scripts/magic-gen/expected.go +scripts/magic-gen/output.go +crit/bin +crit/test-imgs/ +__pycache__ diff --git a/vendor/github.com/checkpoint-restore/go-criu/v7/.golangci.yml b/vendor/github.com/checkpoint-restore/go-criu/v7/.golangci.yml new file mode 100644 index 0000000000..a0d20be214 --- /dev/null +++ b/vendor/github.com/checkpoint-restore/go-criu/v7/.golangci.yml @@ -0,0 +1,22 @@ +linters: + presets: + - bugs + - performance + - unused + - format + disable: + - musttag + enable: + - whitespace + - misspell + - dupl + - gosimple + - stylecheck + +linters-settings: + exhaustive: + default-signifies-exhaustive: true + gosec: + excludes: + # https://github.com/securego/gosec/issues/1185 + - G115 diff --git a/vendor/github.com/checkpoint-restore/go-criu/v6/LICENSE b/vendor/github.com/checkpoint-restore/go-criu/v7/LICENSE similarity index 100% rename from vendor/github.com/checkpoint-restore/go-criu/v6/LICENSE rename to vendor/github.com/checkpoint-restore/go-criu/v7/LICENSE diff --git a/vendor/github.com/checkpoint-restore/go-criu/v7/MAINTAINERS b/vendor/github.com/checkpoint-restore/go-criu/v7/MAINTAINERS new file mode 100644 index 0000000000..4611c33bfb --- /dev/null +++ b/vendor/github.com/checkpoint-restore/go-criu/v7/MAINTAINERS @@ -0,0 +1,4 @@ +Adrian Reber +Kir Kolyshkin +Prajwal S N +Radostin Stoyanov diff --git a/vendor/github.com/checkpoint-restore/go-criu/v6/Makefile b/vendor/github.com/checkpoint-restore/go-criu/v7/Makefile similarity index 78% rename from vendor/github.com/checkpoint-restore/go-criu/v6/Makefile rename to vendor/github.com/checkpoint-restore/go-criu/v7/Makefile index 0c2916001e..12e064237a 100644 --- a/vendor/github.com/checkpoint-restore/go-criu/v6/Makefile +++ b/vendor/github.com/checkpoint-restore/go-criu/v7/Makefile @@ -18,9 +18,6 @@ test: build coverage: $(MAKE) -C test coverage -codecov: - $(MAKE) -C test codecov - rpc/rpc.proto: curl -sSL https://raw.githubusercontent.com/checkpoint-restore/criu/master/images/rpc.proto -o $@ @@ -34,8 +31,12 @@ stats/stats.pb.go: stats/stats.proto protoc --go_out=. --go_opt=M$^=stats/ $^ vendor: - GO111MODULE=on $(GO) mod tidy - GO111MODULE=on $(GO) mod vendor - GO111MODULE=on $(GO) mod verify + $(GO) mod tidy + $(GO) mod vendor + $(GO) mod verify + +clean: + $(MAKE) -C crit/ clean + $(MAKE) -C test/ clean -.PHONY: build test lint vendor coverage codecov +.PHONY: build test lint vendor coverage clean diff --git a/vendor/github.com/checkpoint-restore/go-criu/v6/README.md b/vendor/github.com/checkpoint-restore/go-criu/v7/README.md similarity index 89% rename from vendor/github.com/checkpoint-restore/go-criu/v6/README.md rename to vendor/github.com/checkpoint-restore/go-criu/v7/README.md index d186cb8960..14a08eb7c0 100644 --- a/vendor/github.com/checkpoint-restore/go-criu/v6/README.md +++ b/vendor/github.com/checkpoint-restore/go-criu/v7/README.md @@ -1,23 +1,27 @@ + +# go-criu -- Go bindings for CRIU + [![test](https://github.com/checkpoint-restore/go-criu/workflows/ci/badge.svg?branch=master)](https://github.com/checkpoint-restore/go-criu/actions?query=workflow%3Aci) [![verify](https://github.com/checkpoint-restore/go-criu/workflows/verify/badge.svg?branch=master)](https://github.com/checkpoint-restore/go-criu/actions?query=workflow%3Averify) [![Go Reference](https://pkg.go.dev/badge/github.com/checkpoint-restore/go-criu.svg)](https://pkg.go.dev/github.com/checkpoint-restore/go-criu) -## go-criu -- Go bindings for CRIU - This repository provides Go bindings for [CRIU](https://criu.org/). The code is based on the Go-based PHaul implementation from the CRIU repository. -For easier inclusion into other Go projects, the CRIU Go bindings have been moved to this repository. +For easier inclusion into other Go projects, the CRIU Go bindings have been +moved to this repository. + +## CRIU -### CRIU The Go bindings provide an easy way to use the CRIU RPC calls from Go without the need to set up all the infrastructure to make the actual RPC connection to CRIU. The following example would print the version of CRIU: + ```go import ( "log" - "github.com/checkpoint-restore/go-criu/v6" + "github.com/checkpoint-restore/go-criu/v7" ) func main() { @@ -37,12 +41,12 @@ or to just check if at least a certain CRIU version is installed: result, err := c.IsCriuAtLeast(31100) ``` -### CRIT +## CRIT The `crit` package provides bindings to decode, encode, and manipulate CRIU image files natively within Go. It also provides a CLI tool similar to the original CRIT Python tool. To get started with this, see the docs -at https://criu.org/CRIT_(Go_library). +at [CRIT (Go library)](https://criu.org/CRIT_%28Go_library%29). ## Releases @@ -58,7 +62,9 @@ The following table shows the relation between go-criu and criu versions: | Major version | Latest release | CRIU version | | -------------- | -------------- | ------------ | -| v6             | 6.2.0         | 3.17         | +| v7             | 7.2.0         | 3.19         | +| v7             | 7.0.0         | 3.18         | +| v6             | 6.3.0         | 3.17         | | v5             | 5.3.0         | 3.16         | | v5             | 5.0.0         | 3.15         | | v4             | 4.1.0         | 3.14         | @@ -75,6 +81,7 @@ break-up larger PRs into smaller ones - it's easier to review smaller code changes. But only if those smaller ones make sense as stand-alone PRs. Regardless of the type of PR, all PRs should include: + * well documented code changes * additional testcases. Ideally, they should fail w/o your code change applied * documentation changes diff --git a/vendor/github.com/checkpoint-restore/go-criu/v7/codecov.yml b/vendor/github.com/checkpoint-restore/go-criu/v7/codecov.yml new file mode 100644 index 0000000000..b52d0c4968 --- /dev/null +++ b/vendor/github.com/checkpoint-restore/go-criu/v7/codecov.yml @@ -0,0 +1,2 @@ +ignore: + - "test" diff --git a/vendor/github.com/checkpoint-restore/go-criu/v6/features.go b/vendor/github.com/checkpoint-restore/go-criu/v7/features.go similarity index 91% rename from vendor/github.com/checkpoint-restore/go-criu/v6/features.go rename to vendor/github.com/checkpoint-restore/go-criu/v7/features.go index 4e779d95bc..c62e69e064 100644 --- a/vendor/github.com/checkpoint-restore/go-criu/v6/features.go +++ b/vendor/github.com/checkpoint-restore/go-criu/v7/features.go @@ -1,9 +1,9 @@ package criu import ( - "fmt" + "errors" - "github.com/checkpoint-restore/go-criu/v6/rpc" + "github.com/checkpoint-restore/go-criu/v7/rpc" ) // Feature checking in go-criu is based on the libcriu feature checking function. @@ -38,7 +38,7 @@ func (c *Criu) FeatureCheck(features *rpc.CriuFeatures) (*rpc.CriuFeatures, erro } if resp.GetType() != rpc.CriuReqType_FEATURE_CHECK { - return nil, fmt.Errorf("Unexpected CRIU RPC response") + return nil, errors.New("unexpected CRIU RPC response") } return features, nil diff --git a/vendor/github.com/checkpoint-restore/go-criu/v6/main.go b/vendor/github.com/checkpoint-restore/go-criu/v7/main.go similarity index 84% rename from vendor/github.com/checkpoint-restore/go-criu/v6/main.go rename to vendor/github.com/checkpoint-restore/go-criu/v7/main.go index 2e099c859c..8f29d2ee2d 100644 --- a/vendor/github.com/checkpoint-restore/go-criu/v6/main.go +++ b/vendor/github.com/checkpoint-restore/go-criu/v7/main.go @@ -8,7 +8,7 @@ import ( "strconv" "syscall" - "github.com/checkpoint-restore/go-criu/v6/rpc" + "github.com/checkpoint-restore/go-criu/v7/rpc" "google.golang.org/protobuf/proto" ) @@ -61,13 +61,19 @@ func (c *Criu) Prepare() error { } // Cleanup cleans up -func (c *Criu) Cleanup() { +func (c *Criu) Cleanup() error { + var errs []error if c.swrkCmd != nil { - c.swrkSk.Close() + if err := c.swrkSk.Close(); err != nil { + errs = append(errs, err) + } c.swrkSk = nil - _ = c.swrkCmd.Wait() + if err := c.swrkCmd.Wait(); err != nil { + errs = append(errs, fmt.Errorf("criu swrk failed: %w", err)) + } c.swrkCmd = nil } + return errors.Join(errs...) } func (c *Criu) sendAndRecv(reqB []byte) ([]byte, int, error) { @@ -99,9 +105,7 @@ func (c *Criu) doSwrk(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify) e return nil } -func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify, features *rpc.CriuFeatures) (*rpc.CriuResp, error) { - var resp *rpc.CriuResp - +func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify, features *rpc.CriuFeatures) (resp *rpc.CriuResp, retErr error) { req := rpc.CriuReq{ Type: &reqType, Opts: opts, @@ -121,7 +125,13 @@ func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy N return nil, err } - defer c.Cleanup() + defer func() { + // append any cleanup errors to the returned error + err := c.Cleanup() + if err != nil { + retErr = errors.Join(retErr, err) + } + }() } for { @@ -218,7 +228,7 @@ func (c *Criu) StartPageServerChld(opts *rpc.CriuOpts) (int, int, error) { return 0, 0, err } - return int(resp.Ps.GetPid()), int(resp.Ps.GetPort()), nil + return int(resp.GetPs().GetPid()), int(resp.GetPs().GetPort()), nil } // GetCriuVersion executes the VERSION RPC call and returns the version @@ -230,22 +240,22 @@ func (c *Criu) GetCriuVersion() (int, error) { } if resp.GetType() != rpc.CriuReqType_VERSION { - return 0, fmt.Errorf("Unexpected CRIU RPC response") + return 0, errors.New("unexpected CRIU RPC response") } - version := int(*resp.GetVersion().MajorNumber) * 10000 - version += int(*resp.GetVersion().MinorNumber) * 100 - if resp.GetVersion().Sublevel != nil { - version += int(*resp.GetVersion().Sublevel) + version := resp.GetVersion().GetMajorNumber() * 10000 + version += resp.GetVersion().GetMinorNumber() * 100 + if resp.GetVersion().GetSublevel() != 0 { + version += resp.GetVersion().GetSublevel() } - if resp.GetVersion().Gitid != nil { + if resp.GetVersion().GetGitid() != "" { // taken from runc: if it is a git release -> increase minor by 1 version -= (version % 100) version += 100 } - return version, nil + return int(version), nil } // IsCriuAtLeast checks if the version is at least the same diff --git a/vendor/github.com/checkpoint-restore/go-criu/v6/notify.go b/vendor/github.com/checkpoint-restore/go-criu/v7/notify.go similarity index 100% rename from vendor/github.com/checkpoint-restore/go-criu/v6/notify.go rename to vendor/github.com/checkpoint-restore/go-criu/v7/notify.go diff --git a/vendor/github.com/checkpoint-restore/go-criu/v6/rpc/rpc.pb.go b/vendor/github.com/checkpoint-restore/go-criu/v7/rpc/rpc.pb.go similarity index 69% rename from vendor/github.com/checkpoint-restore/go-criu/v6/rpc/rpc.pb.go rename to vendor/github.com/checkpoint-restore/go-criu/v7/rpc/rpc.pb.go index 67bd8593e8..730496b04f 100644 --- a/vendor/github.com/checkpoint-restore/go-criu/v6/rpc/rpc.pb.go +++ b/vendor/github.com/checkpoint-restore/go-criu/v7/rpc/rpc.pb.go @@ -2,8 +2,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 -// protoc v3.19.4 +// protoc-gen-go v1.30.0 +// protoc v4.23.4 // source: rpc/rpc.proto package rpc @@ -98,6 +98,7 @@ type CriuNetworkLockMethod int32 const ( CriuNetworkLockMethod_IPTABLES CriuNetworkLockMethod = 1 CriuNetworkLockMethod_NFTABLES CriuNetworkLockMethod = 2 + CriuNetworkLockMethod_SKIP CriuNetworkLockMethod = 3 ) // Enum value maps for CriuNetworkLockMethod. @@ -105,10 +106,12 @@ var ( CriuNetworkLockMethod_name = map[int32]string{ 1: "IPTABLES", 2: "NFTABLES", + 3: "SKIP", } CriuNetworkLockMethod_value = map[string]int32{ "IPTABLES": 1, "NFTABLES": 2, + "SKIP": 3, } ) @@ -703,8 +706,9 @@ type CriuOpts struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ImagesDirFd *int32 `protobuf:"varint,1,req,name=images_dir_fd,json=imagesDirFd" json:"images_dir_fd,omitempty"` - Pid *int32 `protobuf:"varint,2,opt,name=pid" json:"pid,omitempty"` // if not set on dump, will dump requesting process + ImagesDirFd *int32 `protobuf:"varint,1,req,name=images_dir_fd,json=imagesDirFd,def=-1" json:"images_dir_fd,omitempty"` + ImagesDir *string `protobuf:"bytes,68,opt,name=images_dir,json=imagesDir" json:"images_dir,omitempty"` // used only if images_dir_fd == -1 + Pid *int32 `protobuf:"varint,2,opt,name=pid" json:"pid,omitempty"` // if not set on dump, will dump requesting process LeaveRunning *bool `protobuf:"varint,3,opt,name=leave_running,json=leaveRunning" json:"leave_running,omitempty"` ExtUnixSk *bool `protobuf:"varint,4,opt,name=ext_unix_sk,json=extUnixSk" json:"ext_unix_sk,omitempty"` TcpEstablished *bool `protobuf:"varint,5,opt,name=tcp_established,json=tcpEstablished" json:"tcp_established,omitempty"` @@ -766,11 +770,17 @@ type CriuOpts struct { 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"` NetworkLock *CriuNetworkLockMethod `protobuf:"varint,64,opt,name=network_lock,json=networkLock,enum=CriuNetworkLockMethod,def=1" json:"network_lock,omitempty"` - MntnsCompatMode *bool `protobuf:"varint,65,opt,name=mntns_compat_mode,json=mntnsCompatMode" json:"mntns_compat_mode,omitempty"` // optional bool check_mounts = 128; + MntnsCompatMode *bool `protobuf:"varint,65,opt,name=mntns_compat_mode,json=mntnsCompatMode" json:"mntns_compat_mode,omitempty"` + SkipFileRwxCheck *bool `protobuf:"varint,66,opt,name=skip_file_rwx_check,json=skipFileRwxCheck" json:"skip_file_rwx_check,omitempty"` + Unprivileged *bool `protobuf:"varint,67,opt,name=unprivileged" json:"unprivileged,omitempty"` + LeaveStopped *bool `protobuf:"varint,69,opt,name=leave_stopped,json=leaveStopped" json:"leave_stopped,omitempty"` + DisplayStats *bool `protobuf:"varint,70,opt,name=display_stats,json=displayStats" json:"display_stats,omitempty"` + LogToStderr *bool `protobuf:"varint,71,opt,name=log_to_stderr,json=logToStderr" json:"log_to_stderr,omitempty"` // optional bool check_mounts = 128; } // Default values for CriuOpts fields. const ( + Default_CriuOpts_ImagesDirFd = int32(-1) Default_CriuOpts_LogLevel = int32(2) Default_CriuOpts_CpuCap = uint32(4294967295) Default_CriuOpts_GhostLimit = uint32(1048576) @@ -814,7 +824,14 @@ func (x *CriuOpts) GetImagesDirFd() int32 { if x != nil && x.ImagesDirFd != nil { return *x.ImagesDirFd } - return 0 + return Default_CriuOpts_ImagesDirFd +} + +func (x *CriuOpts) GetImagesDir() string { + if x != nil && x.ImagesDir != nil { + return *x.ImagesDir + } + return "" } func (x *CriuOpts) GetPid() int32 { @@ -1258,6 +1275,41 @@ func (x *CriuOpts) GetMntnsCompatMode() bool { return false } +func (x *CriuOpts) GetSkipFileRwxCheck() bool { + if x != nil && x.SkipFileRwxCheck != nil { + return *x.SkipFileRwxCheck + } + return false +} + +func (x *CriuOpts) GetUnprivileged() bool { + if x != nil && x.Unprivileged != nil { + return *x.Unprivileged + } + return false +} + +func (x *CriuOpts) GetLeaveStopped() bool { + if x != nil && x.LeaveStopped != nil { + return *x.LeaveStopped + } + return false +} + +func (x *CriuOpts) GetDisplayStats() bool { + if x != nil && x.DisplayStats != nil { + return *x.DisplayStats + } + return false +} + +func (x *CriuOpts) GetLogToStderr() bool { + if x != nil && x.LogToStderr != nil { + return *x.LogToStderr + } + return false +} + type CriuDumpResp struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1407,7 +1459,6 @@ func (x *CriuNotify) GetPid() int32 { return 0 } -// // List of features which can queried via // CRIU_REQ_TYPE__FEATURE_CHECK type CriuFeatures struct { @@ -1481,12 +1532,10 @@ type CriuReq struct { Type *CriuReqType `protobuf:"varint,1,req,name=type,enum=CriuReqType" json:"type,omitempty"` Opts *CriuOpts `protobuf:"bytes,2,opt,name=opts" json:"opts,omitempty"` NotifySuccess *bool `protobuf:"varint,3,opt,name=notify_success,json=notifySuccess" json:"notify_success,omitempty"` - // // When set service won't close the connection but // will wait for more req-s to appear. Works not // for all request types. KeepOpen *bool `protobuf:"varint,4,opt,name=keep_open,json=keepOpen" json:"keep_open,omitempty"` - // // 'features' can be used to query which features // are supported by the installed criu/kernel // via RPC. @@ -1815,244 +1864,258 @@ 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, 0x80, 0x12, 0x0a, 0x09, - 0x63, 0x72, 0x69, 0x75, 0x5f, 0x6f, 0x70, 0x74, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x69, 0x6d, 0x61, + 0x20, 0x02, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0xe4, 0x13, 0x0a, 0x09, + 0x63, 0x72, 0x69, 0x75, 0x5f, 0x6f, 0x70, 0x74, 0x73, 0x12, 0x26, 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, - 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, - 0x23, 0x0a, 0x0d, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x75, 0x6e, - 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x1e, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x5f, 0x75, 0x6e, 0x69, 0x78, - 0x5f, 0x73, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x65, 0x78, 0x74, 0x55, 0x6e, - 0x69, 0x78, 0x53, 0x6b, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x63, 0x70, 0x5f, 0x65, 0x73, 0x74, 0x61, - 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x74, - 0x63, 0x70, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x27, 0x0a, - 0x0f, 0x65, 0x76, 0x61, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x65, 0x76, 0x61, 0x73, 0x69, 0x76, 0x65, 0x44, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x5f, - 0x6a, 0x6f, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x73, 0x68, 0x65, 0x6c, 0x6c, - 0x4a, 0x6f, 0x62, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, - 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x4c, 0x6f, 0x63, - 0x6b, 0x73, 0x12, 0x1e, 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x05, 0x3a, 0x01, 0x32, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x4c, 0x65, 0x76, - 0x65, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x26, 0x0a, - 0x02, 0x70, 0x73, 0x18, 0x0b, 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, 0x25, 0x0a, 0x0e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x5f, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6e, - 0x6f, 0x74, 0x69, 0x66, 0x79, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x12, 0x12, 0x0a, 0x04, - 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x74, - 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6d, 0x67, 0x18, 0x0e, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x6d, 0x67, 0x12, - 0x1b, 0x0a, 0x09, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x5f, 0x6d, 0x65, 0x6d, 0x18, 0x0f, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x08, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, - 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x64, 0x75, 0x70, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x09, 0x61, 0x75, 0x74, 0x6f, 0x44, 0x65, 0x64, 0x75, 0x70, 0x12, 0x1e, 0x0a, 0x0b, 0x77, - 0x6f, 0x72, 0x6b, 0x5f, 0x64, 0x69, 0x72, 0x5f, 0x66, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x44, 0x69, 0x72, 0x46, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, - 0x69, 0x6e, 0x6b, 0x5f, 0x72, 0x65, 0x6d, 0x61, 0x70, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x6d, 0x61, 0x70, 0x12, 0x25, 0x0a, 0x05, 0x76, 0x65, - 0x74, 0x68, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x72, 0x69, 0x75, - 0x5f, 0x76, 0x65, 0x74, 0x68, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x52, 0x05, 0x76, 0x65, 0x74, 0x68, - 0x73, 0x12, 0x23, 0x0a, 0x07, 0x63, 0x70, 0x75, 0x5f, 0x63, 0x61, 0x70, 0x18, 0x14, 0x20, 0x01, - 0x28, 0x0d, 0x3a, 0x0a, 0x34, 0x32, 0x39, 0x34, 0x39, 0x36, 0x37, 0x32, 0x39, 0x35, 0x52, 0x06, - 0x63, 0x70, 0x75, 0x43, 0x61, 0x70, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, - 0x69, 0x72, 0x6d, 0x61, 0x70, 0x18, 0x15, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, 0x6f, 0x72, - 0x63, 0x65, 0x49, 0x72, 0x6d, 0x61, 0x70, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x78, 0x65, 0x63, 0x5f, - 0x63, 0x6d, 0x64, 0x18, 0x16, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x65, 0x78, 0x65, 0x63, 0x43, - 0x6d, 0x64, 0x12, 0x27, 0x0a, 0x07, 0x65, 0x78, 0x74, 0x5f, 0x6d, 0x6e, 0x74, 0x18, 0x17, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x65, 0x78, 0x74, 0x5f, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, - 0x6d, 0x61, 0x70, 0x52, 0x06, 0x65, 0x78, 0x74, 0x4d, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x6d, - 0x61, 0x6e, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x18, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x43, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x73, 0x12, 0x25, 0x0a, 0x07, 0x63, 0x67, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x19, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x72, 0x6f, 0x6f, - 0x74, 0x52, 0x06, 0x63, 0x67, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x73, 0x74, - 0x5f, 0x73, 0x69, 0x62, 0x6c, 0x69, 0x6e, 0x67, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, - 0x72, 0x73, 0x74, 0x53, 0x69, 0x62, 0x6c, 0x69, 0x6e, 0x67, 0x12, 0x2a, 0x0a, 0x0a, 0x69, 0x6e, - 0x68, 0x65, 0x72, 0x69, 0x74, 0x5f, 0x66, 0x64, 0x18, 0x1b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, - 0x2e, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x5f, 0x66, 0x64, 0x52, 0x09, 0x69, 0x6e, 0x68, - 0x65, 0x72, 0x69, 0x74, 0x46, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x65, - 0x78, 0x74, 0x5f, 0x6d, 0x6e, 0x74, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x61, 0x75, - 0x74, 0x6f, 0x45, 0x78, 0x74, 0x4d, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x5f, - 0x73, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, - 0x78, 0x74, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, - 0x5f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x73, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, - 0x65, 0x78, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x6b, - 0x69, 0x70, 0x5f, 0x6d, 0x6e, 0x74, 0x18, 0x1f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x73, 0x6b, - 0x69, 0x70, 0x4d, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, - 0x66, 0x73, 0x18, 0x20, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x46, 0x73, 0x12, 0x28, 0x0a, 0x0b, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x73, 0x6b, 0x5f, 0x69, 0x6e, - 0x6f, 0x18, 0x21, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x73, - 0x6b, 0x52, 0x09, 0x75, 0x6e, 0x69, 0x78, 0x53, 0x6b, 0x49, 0x6e, 0x6f, 0x12, 0x3d, 0x0a, 0x13, - 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x5f, 0x6d, - 0x6f, 0x64, 0x65, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x63, 0x72, 0x69, 0x75, - 0x5f, 0x63, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x52, 0x11, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, - 0x43, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x67, - 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0d, - 0x3a, 0x07, 0x31, 0x30, 0x34, 0x38, 0x35, 0x37, 0x36, 0x52, 0x0a, 0x67, 0x68, 0x6f, 0x73, 0x74, - 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x69, 0x72, 0x6d, 0x61, 0x70, 0x5f, 0x73, - 0x63, 0x61, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x24, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x0e, 0x69, 0x72, 0x6d, 0x61, 0x70, 0x53, 0x63, 0x61, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, - 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x25, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x65, - 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x6e, 0x73, 0x18, 0x26, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x65, - 0x6d, 0x70, 0x74, 0x79, 0x4e, 0x73, 0x12, 0x28, 0x0a, 0x07, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x6e, - 0x73, 0x18, 0x27, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x06, 0x6a, 0x6f, 0x69, 0x6e, 0x4e, 0x73, - 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x73, - 0x18, 0x29, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x72, - 0x6f, 0x70, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x72, - 0x6f, 0x70, 0x73, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x2a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, - 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x72, 0x6f, 0x70, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x12, - 0x34, 0x0a, 0x16, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x64, 0x75, 0x6d, 0x70, 0x5f, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x18, 0x2b, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x14, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x75, 0x6d, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x5f, - 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x2c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x72, - 0x65, 0x65, 0x7a, 0x65, 0x43, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, - 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x2d, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x74, 0x69, 0x6d, - 0x65, 0x6f, 0x75, 0x74, 0x12, 0x2b, 0x0a, 0x12, 0x74, 0x63, 0x70, 0x5f, 0x73, 0x6b, 0x69, 0x70, - 0x5f, 0x69, 0x6e, 0x5f, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x18, 0x2e, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0f, 0x74, 0x63, 0x70, 0x53, 0x6b, 0x69, 0x70, 0x49, 0x6e, 0x46, 0x6c, 0x69, 0x67, 0x68, - 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x65, 0x61, 0x6b, 0x5f, 0x73, 0x79, 0x73, 0x63, 0x74, 0x6c, - 0x73, 0x18, 0x2f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x77, 0x65, 0x61, 0x6b, 0x53, 0x79, 0x73, - 0x63, 0x74, 0x6c, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x7a, 0x79, 0x5f, 0x70, 0x61, 0x67, - 0x65, 0x73, 0x18, 0x30, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6c, 0x61, 0x7a, 0x79, 0x50, 0x61, - 0x67, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x66, 0x64, - 0x18, 0x31, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x46, 0x64, - 0x12, 0x2a, 0x0a, 0x11, 0x6f, 0x72, 0x70, 0x68, 0x61, 0x6e, 0x5f, 0x70, 0x74, 0x73, 0x5f, 0x6d, - 0x61, 0x73, 0x74, 0x65, 0x72, 0x18, 0x32, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6f, 0x72, 0x70, - 0x68, 0x61, 0x6e, 0x50, 0x74, 0x73, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x33, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1b, 0x0a, - 0x09, 0x74, 0x63, 0x70, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x18, 0x34, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x08, 0x74, 0x63, 0x70, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x73, - 0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x35, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x6c, 0x73, 0x6d, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x74, - 0x6c, 0x73, 0x5f, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x18, 0x36, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x74, 0x6c, 0x73, 0x43, 0x61, 0x63, 0x65, 0x72, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x6c, - 0x73, 0x5f, 0x63, 0x61, 0x63, 0x72, 0x6c, 0x18, 0x37, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, - 0x6c, 0x73, 0x43, 0x61, 0x63, 0x72, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x6c, 0x73, 0x5f, 0x63, - 0x65, 0x72, 0x74, 0x18, 0x38, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x6c, 0x73, 0x43, 0x65, - 0x72, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x6c, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x39, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x6c, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x74, - 0x6c, 0x73, 0x18, 0x3a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x74, 0x6c, 0x73, 0x12, 0x27, 0x0a, - 0x10, 0x74, 0x6c, 0x73, 0x5f, 0x6e, 0x6f, 0x5f, 0x63, 0x6e, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, - 0x79, 0x18, 0x3b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x74, 0x6c, 0x73, 0x4e, 0x6f, 0x43, 0x6e, - 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x5f, 0x79, 0x61, 0x72, 0x64, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x59, 0x61, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0d, 0x70, 0x72, 0x65, 0x5f, 0x64, - 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, 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, 0x12, 0x46, 0x0a, 0x0c, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x40, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x19, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, - 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x3a, 0x08, 0x49, 0x50, 0x54, - 0x41, 0x42, 0x4c, 0x45, 0x53, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x6f, - 0x63, 0x6b, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x6e, 0x74, 0x6e, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x70, - 0x61, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x41, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6d, - 0x6e, 0x74, 0x6e, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x74, 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, 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, + 0x3a, 0x02, 0x2d, 0x31, 0x52, 0x0b, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x44, 0x69, 0x72, 0x46, + 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x5f, 0x64, 0x69, 0x72, 0x18, + 0x44, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x44, 0x69, 0x72, + 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x70, + 0x69, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x5f, 0x72, 0x75, 0x6e, 0x6e, + 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6c, 0x65, 0x61, 0x76, 0x65, + 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x1e, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x5f, 0x75, + 0x6e, 0x69, 0x78, 0x5f, 0x73, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x65, 0x78, + 0x74, 0x55, 0x6e, 0x69, 0x78, 0x53, 0x6b, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x63, 0x70, 0x5f, 0x65, + 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0e, 0x74, 0x63, 0x70, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, + 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x76, 0x61, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x65, 0x76, 0x61, 0x73, 0x69, + 0x76, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x68, 0x65, + 0x6c, 0x6c, 0x5f, 0x6a, 0x6f, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x73, 0x68, + 0x65, 0x6c, 0x6c, 0x4a, 0x6f, 0x62, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6c, + 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x66, 0x69, 0x6c, 0x65, + 0x4c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x1e, 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, + 0x65, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x3a, 0x01, 0x32, 0x52, 0x08, 0x6c, 0x6f, 0x67, + 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x5f, 0x66, 0x69, 0x6c, + 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x46, 0x69, 0x6c, 0x65, + 0x12, 0x26, 0x0a, 0x02, 0x70, 0x73, 0x18, 0x0b, 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, 0x25, 0x0a, 0x0e, 0x6e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x5f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0d, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x12, + 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, + 0x6f, 0x6f, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6d, + 0x67, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, + 0x6d, 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x5f, 0x6d, 0x65, 0x6d, 0x18, + 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x6d, 0x12, + 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x64, 0x75, 0x70, 0x18, 0x10, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x09, 0x61, 0x75, 0x74, 0x6f, 0x44, 0x65, 0x64, 0x75, 0x70, 0x12, 0x1e, + 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x64, 0x69, 0x72, 0x5f, 0x66, 0x64, 0x18, 0x11, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x44, 0x69, 0x72, 0x46, 0x64, 0x12, 0x1d, + 0x0a, 0x0a, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x72, 0x65, 0x6d, 0x61, 0x70, 0x18, 0x12, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x6d, 0x61, 0x70, 0x12, 0x25, 0x0a, + 0x05, 0x76, 0x65, 0x74, 0x68, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, + 0x72, 0x69, 0x75, 0x5f, 0x76, 0x65, 0x74, 0x68, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x52, 0x05, 0x76, + 0x65, 0x74, 0x68, 0x73, 0x12, 0x23, 0x0a, 0x07, 0x63, 0x70, 0x75, 0x5f, 0x63, 0x61, 0x70, 0x18, + 0x14, 0x20, 0x01, 0x28, 0x0d, 0x3a, 0x0a, 0x34, 0x32, 0x39, 0x34, 0x39, 0x36, 0x37, 0x32, 0x39, + 0x35, 0x52, 0x06, 0x63, 0x70, 0x75, 0x43, 0x61, 0x70, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x6f, 0x72, + 0x63, 0x65, 0x5f, 0x69, 0x72, 0x6d, 0x61, 0x70, 0x18, 0x15, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, + 0x66, 0x6f, 0x72, 0x63, 0x65, 0x49, 0x72, 0x6d, 0x61, 0x70, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x78, + 0x65, 0x63, 0x5f, 0x63, 0x6d, 0x64, 0x18, 0x16, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x65, 0x78, + 0x65, 0x63, 0x43, 0x6d, 0x64, 0x12, 0x27, 0x0a, 0x07, 0x65, 0x78, 0x74, 0x5f, 0x6d, 0x6e, 0x74, + 0x18, 0x17, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x65, 0x78, 0x74, 0x5f, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x52, 0x06, 0x65, 0x78, 0x74, 0x4d, 0x6e, 0x74, 0x12, 0x25, + 0x0a, 0x0e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, + 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x43, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x25, 0x0a, 0x07, 0x63, 0x67, 0x5f, 0x72, 0x6f, 0x6f, 0x74, + 0x18, 0x19, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, + 0x72, 0x6f, 0x6f, 0x74, 0x52, 0x06, 0x63, 0x67, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1f, 0x0a, 0x0b, + 0x72, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x62, 0x6c, 0x69, 0x6e, 0x67, 0x18, 0x1a, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0a, 0x72, 0x73, 0x74, 0x53, 0x69, 0x62, 0x6c, 0x69, 0x6e, 0x67, 0x12, 0x2a, 0x0a, + 0x0a, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x5f, 0x66, 0x64, 0x18, 0x1b, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0b, 0x2e, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x5f, 0x66, 0x64, 0x52, 0x09, + 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x46, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x61, 0x75, 0x74, + 0x6f, 0x5f, 0x65, 0x78, 0x74, 0x5f, 0x6d, 0x6e, 0x74, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x45, 0x78, 0x74, 0x4d, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x65, + 0x78, 0x74, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0a, 0x65, 0x78, 0x74, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x1f, 0x0a, 0x0b, + 0x65, 0x78, 0x74, 0x5f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x73, 0x18, 0x1e, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x19, 0x0a, + 0x08, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x6d, 0x6e, 0x74, 0x18, 0x1f, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x07, 0x73, 0x6b, 0x69, 0x70, 0x4d, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x5f, 0x66, 0x73, 0x18, 0x20, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x46, 0x73, 0x12, 0x28, 0x0a, 0x0b, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x73, 0x6b, + 0x5f, 0x69, 0x6e, 0x6f, 0x18, 0x21, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x75, 0x6e, 0x69, + 0x78, 0x5f, 0x73, 0x6b, 0x52, 0x09, 0x75, 0x6e, 0x69, 0x78, 0x53, 0x6b, 0x49, 0x6e, 0x6f, 0x12, + 0x3d, 0x0a, 0x13, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x73, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x63, + 0x72, 0x69, 0x75, 0x5f, 0x63, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x52, 0x11, 0x6d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x43, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x28, + 0x0a, 0x0b, 0x67, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x23, 0x20, + 0x01, 0x28, 0x0d, 0x3a, 0x07, 0x31, 0x30, 0x34, 0x38, 0x35, 0x37, 0x36, 0x52, 0x0a, 0x67, 0x68, + 0x6f, 0x73, 0x74, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x69, 0x72, 0x6d, 0x61, + 0x70, 0x5f, 0x73, 0x63, 0x61, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x24, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0e, 0x69, 0x72, 0x6d, 0x61, 0x70, 0x53, 0x63, 0x61, 0x6e, 0x50, 0x61, 0x74, + 0x68, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x25, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x12, 0x19, + 0x0a, 0x08, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x6e, 0x73, 0x18, 0x26, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x07, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x4e, 0x73, 0x12, 0x28, 0x0a, 0x07, 0x6a, 0x6f, 0x69, + 0x6e, 0x5f, 0x6e, 0x73, 0x18, 0x27, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6a, 0x6f, 0x69, + 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x06, 0x6a, 0x6f, 0x69, + 0x6e, 0x4e, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x72, + 0x6f, 0x70, 0x73, 0x18, 0x29, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x50, 0x72, 0x6f, 0x70, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x2a, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0f, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x72, 0x6f, 0x70, 0x73, 0x46, 0x69, + 0x6c, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x64, 0x75, 0x6d, + 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x18, 0x2b, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x14, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x75, 0x6d, 0x70, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x65, 0x65, + 0x7a, 0x65, 0x5f, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x2c, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x43, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x18, 0x0a, + 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x2d, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, + 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x2b, 0x0a, 0x12, 0x74, 0x63, 0x70, 0x5f, 0x73, + 0x6b, 0x69, 0x70, 0x5f, 0x69, 0x6e, 0x5f, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x18, 0x2e, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0f, 0x74, 0x63, 0x70, 0x53, 0x6b, 0x69, 0x70, 0x49, 0x6e, 0x46, 0x6c, + 0x69, 0x67, 0x68, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x65, 0x61, 0x6b, 0x5f, 0x73, 0x79, 0x73, + 0x63, 0x74, 0x6c, 0x73, 0x18, 0x2f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x77, 0x65, 0x61, 0x6b, + 0x53, 0x79, 0x73, 0x63, 0x74, 0x6c, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x7a, 0x79, 0x5f, + 0x70, 0x61, 0x67, 0x65, 0x73, 0x18, 0x30, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6c, 0x61, 0x7a, + 0x79, 0x50, 0x61, 0x67, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x5f, 0x66, 0x64, 0x18, 0x31, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x46, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x6f, 0x72, 0x70, 0x68, 0x61, 0x6e, 0x5f, 0x70, 0x74, + 0x73, 0x5f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x18, 0x32, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, + 0x6f, 0x72, 0x70, 0x68, 0x61, 0x6e, 0x50, 0x74, 0x73, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x12, + 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x33, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x69, 0x6c, 0x65, + 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x63, 0x70, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x18, 0x34, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x08, 0x74, 0x63, 0x70, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x12, 0x1f, 0x0a, + 0x0b, 0x6c, 0x73, 0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x35, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x73, 0x6d, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x1d, + 0x0a, 0x0a, 0x74, 0x6c, 0x73, 0x5f, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x18, 0x36, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x74, 0x6c, 0x73, 0x43, 0x61, 0x63, 0x65, 0x72, 0x74, 0x12, 0x1b, 0x0a, + 0x09, 0x74, 0x6c, 0x73, 0x5f, 0x63, 0x61, 0x63, 0x72, 0x6c, 0x18, 0x37, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x74, 0x6c, 0x73, 0x43, 0x61, 0x63, 0x72, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x6c, + 0x73, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x18, 0x38, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x6c, + 0x73, 0x43, 0x65, 0x72, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x6c, 0x73, 0x5f, 0x6b, 0x65, 0x79, + 0x18, 0x39, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x6c, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x74, 0x6c, 0x73, 0x18, 0x3a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x74, 0x6c, 0x73, + 0x12, 0x27, 0x0a, 0x10, 0x74, 0x6c, 0x73, 0x5f, 0x6e, 0x6f, 0x5f, 0x63, 0x6e, 0x5f, 0x76, 0x65, + 0x72, 0x69, 0x66, 0x79, 0x18, 0x3b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x74, 0x6c, 0x73, 0x4e, + 0x6f, 0x43, 0x6e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x5f, 0x79, 0x61, 0x72, 0x64, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x59, 0x61, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0d, 0x70, 0x72, + 0x65, 0x5f, 0x64, 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, 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, 0x12, 0x46, 0x0a, + 0x0c, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x40, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x3a, 0x08, + 0x49, 0x50, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x53, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x4c, 0x6f, 0x63, 0x6b, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x6e, 0x74, 0x6e, 0x73, 0x5f, 0x63, + 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x41, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0f, 0x6d, 0x6e, 0x74, 0x6e, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x4d, 0x6f, 0x64, + 0x65, 0x12, 0x2d, 0x0a, 0x13, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x72, + 0x77, 0x78, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x42, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, + 0x73, 0x6b, 0x69, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x77, 0x78, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x12, 0x22, 0x0a, 0x0c, 0x75, 0x6e, 0x70, 0x72, 0x69, 0x76, 0x69, 0x6c, 0x65, 0x67, 0x65, 0x64, + 0x18, 0x43, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x6e, 0x70, 0x72, 0x69, 0x76, 0x69, 0x6c, + 0x65, 0x67, 0x65, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x5f, 0x73, 0x74, + 0x6f, 0x70, 0x70, 0x65, 0x64, 0x18, 0x45, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6c, 0x65, 0x61, + 0x76, 0x65, 0x53, 0x74, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x69, 0x73, + 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x46, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x22, + 0x0a, 0x0d, 0x6c, 0x6f, 0x67, 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x18, + 0x47, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6c, 0x6f, 0x67, 0x54, 0x6f, 0x53, 0x74, 0x64, 0x65, + 0x72, 0x72, 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, - 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, 0x36, 0x0a, 0x18, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, - 0x0c, 0x0a, 0x08, 0x49, 0x50, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x53, 0x10, 0x01, 0x12, 0x0c, 0x0a, - 0x08, 0x4e, 0x46, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x53, 0x10, 0x02, 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, 0xe5, 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, 0x12, 0x13, 0x0a, - 0x0f, 0x53, 0x49, 0x4e, 0x47, 0x4c, 0x45, 0x5f, 0x50, 0x52, 0x45, 0x5f, 0x44, 0x55, 0x4d, 0x50, - 0x10, 0x0d, + 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, 0x40, 0x0a, 0x18, 0x63, 0x72, 0x69, 0x75, 0x5f, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x12, 0x0c, 0x0a, 0x08, 0x49, 0x50, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x53, 0x10, + 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x46, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x53, 0x10, 0x02, 0x12, + 0x08, 0x0a, 0x04, 0x53, 0x4b, 0x49, 0x50, 0x10, 0x03, 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, 0xe5, 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, 0x12, 0x13, 0x0a, 0x0f, 0x53, + 0x49, 0x4e, 0x47, 0x4c, 0x45, 0x5f, 0x50, 0x52, 0x45, 0x5f, 0x44, 0x55, 0x4d, 0x50, 0x10, 0x0d, } var ( diff --git a/vendor/github.com/checkpoint-restore/go-criu/v6/rpc/rpc.proto b/vendor/github.com/checkpoint-restore/go-criu/v7/rpc/rpc.proto similarity index 94% rename from vendor/github.com/checkpoint-restore/go-criu/v6/rpc/rpc.proto rename to vendor/github.com/checkpoint-restore/go-criu/v7/rpc/rpc.proto index a6cc5da487..1a4722a9ce 100644 --- a/vendor/github.com/checkpoint-restore/go-criu/v6/rpc/rpc.proto +++ b/vendor/github.com/checkpoint-restore/go-criu/v7/rpc/rpc.proto @@ -52,6 +52,7 @@ enum criu_cg_mode { enum criu_network_lock_method { IPTABLES = 1; NFTABLES = 2; + SKIP = 3; }; enum criu_pre_dump_mode { @@ -60,7 +61,8 @@ enum criu_pre_dump_mode { }; message criu_opts { - required int32 images_dir_fd = 1; + required int32 images_dir_fd = 1 [default = -1]; + optional string images_dir = 68; /* used only if images_dir_fd == -1 */ optional int32 pid = 2; /* if not set on dump, will dump requesting process */ optional bool leave_running = 3; @@ -138,6 +140,11 @@ message criu_opts { optional string lsm_mount_context = 63; optional criu_network_lock_method network_lock = 64 [default = IPTABLES]; optional bool mntns_compat_mode = 65; + optional bool skip_file_rwx_check = 66; + optional bool unprivileged = 67; + optional bool leave_stopped = 69; + optional bool display_stats = 70; + optional bool log_to_stderr = 71; /* optional bool check_mounts = 128; */ } diff --git a/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go b/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go index 147f756fe2..e966c156d4 100644 --- a/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go +++ b/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go @@ -12,7 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Integration with the systemd D-Bus API. See http://www.freedesktop.org/wiki/Software/systemd/dbus/ +// Package dbus provides integration with the systemd D-Bus API. +// See http://www.freedesktop.org/wiki/Software/systemd/dbus/ package dbus import ( @@ -94,7 +95,7 @@ type Conn struct { sigobj dbus.BusObject jobListener struct { - jobs map[dbus.ObjectPath]chan<- string + jobs map[dbus.ObjectPath][]chan<- string sync.Mutex } subStateSubscriber struct { @@ -206,7 +207,7 @@ func NewConnection(dialBus func() (*dbus.Conn, error)) (*Conn, error) { } c.subStateSubscriber.ignore = make(map[dbus.ObjectPath]int64) - c.jobListener.jobs = make(map[dbus.ObjectPath]chan<- string) + c.jobListener.jobs = make(map[dbus.ObjectPath][]chan<- string) // Setup the listeners on jobs so that we can get completions c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, diff --git a/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go b/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go index 074148cb4d..490248b861 100644 --- a/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go +++ b/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go @@ -24,15 +24,15 @@ import ( "github.com/godbus/dbus/v5" ) -// Who can be used to specify which process to kill in the unit via the KillUnitWithTarget API +// Who specifies which process to send a signal to via the [Conn.KillUnitWithTarget]. type Who string const ( - // All sends the signal to all processes in the unit + // All sends the signal to all processes in the unit. All Who = "all" - // Main sends the signal to the main process of the unit + // Main sends the signal to the main process of the unit. Main Who = "main" - // Control sends the signal to the control process of the unit + // Control sends the signal to the control process of the unit. Control Who = "control" ) @@ -41,17 +41,17 @@ func (c *Conn) jobComplete(signal *dbus.Signal) { var job dbus.ObjectPath var unit string var result string - dbus.Store(signal.Body, &id, &job, &unit, &result) + + _ = dbus.Store(signal.Body, &id, &job, &unit, &result) c.jobListener.Lock() - out, ok := c.jobListener.jobs[job] - if ok { + for _, out := range c.jobListener.jobs[job] { out <- result - delete(c.jobListener.jobs, job) } + delete(c.jobListener.jobs, job) c.jobListener.Unlock() } -func (c *Conn) startJob(ctx context.Context, ch chan<- string, job string, args ...interface{}) (int, error) { +func (c *Conn) startJob(ctx context.Context, ch chan<- string, job string, args ...any) (int, error) { if ch != nil { c.jobListener.Lock() defer c.jobListener.Unlock() @@ -64,7 +64,7 @@ func (c *Conn) startJob(ctx context.Context, ch chan<- string, job string, args } if ch != nil { - c.jobListener.jobs[p] = ch + c.jobListener.jobs[p] = append(c.jobListener.jobs[p], ch) } // ignore error since 0 is fine if conversion fails @@ -102,6 +102,10 @@ func (c *Conn) StartUnit(name string, mode string, ch chan<- string) (int, error // has been removed too. skipped indicates that a job was skipped because it // didn't apply to the units current state. // +// Important: It is the caller's responsibility to unblock the provided channel write, +// either by reading from the channel or by using a buffered channel. Until the write +// is unblocked, the Conn object cannot handle other jobs. +// // If no error occurs, the ID of the underlying systemd job will be returned. There // does exist the possibility for no error to be returned, but for the returned job // ID to be 0. In this case, the actual underlying ID is not 0 and this datapoint @@ -189,22 +193,30 @@ func (c *Conn) StartTransientUnit(name string, mode string, properties []Propert // unique. mode is the same as in StartUnitContext, properties contains properties // of the unit. func (c *Conn) StartTransientUnitContext(ctx context.Context, name string, mode string, properties []Property, ch chan<- string) (int, error) { - return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0)) + return c.StartTransientUnitAux(ctx, name, mode, properties, make([]PropertyCollection, 0), ch) +} + +// StartTransientUnitAux is the same as StartTransientUnitContext but allows passing +// auxiliary units in the aux parameter. +func (c *Conn) StartTransientUnitAux(ctx context.Context, name string, mode string, properties []Property, aux []PropertyCollection, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, aux) } -// Deprecated: use KillUnitContext instead. +// Deprecated: use [Conn.KillUnitWithTarget] instead. func (c *Conn) KillUnit(name string, signal int32) { c.KillUnitContext(context.Background(), name, signal) } // KillUnitContext takes the unit name and a UNIX signal number to send. // All of the unit's processes are killed. +// +// Deprecated: use [Conn.KillUnitWithTarget] instead, with target argument set to [All]. func (c *Conn) KillUnitContext(ctx context.Context, name string, signal int32) { - c.KillUnitWithTarget(ctx, name, All, signal) + _ = c.KillUnitWithTarget(ctx, name, All, signal) } -// KillUnitWithTarget is like KillUnitContext, but allows you to specify which -// process in the unit to send the signal to. +// KillUnitWithTarget sends a signal to the specified unit. +// The target argument can be one of [All], [Main], or [Control]. func (c *Conn) KillUnitWithTarget(ctx context.Context, name string, target Who, signal int32) error { return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.KillUnit", 0, name, string(target), signal).Store() } @@ -240,7 +252,7 @@ func (c *Conn) SystemStateContext(ctx context.Context) (*Property, error) { } // getProperties takes the unit path and returns all of its dbus object properties, for the given dbus interface. -func (c *Conn) getProperties(ctx context.Context, path dbus.ObjectPath, dbusInterface string) (map[string]interface{}, error) { +func (c *Conn) getProperties(ctx context.Context, path dbus.ObjectPath, dbusInterface string) (map[string]any, error) { var err error var props map[string]dbus.Variant @@ -254,7 +266,7 @@ func (c *Conn) getProperties(ctx context.Context, path dbus.ObjectPath, dbusInte return nil, err } - out := make(map[string]interface{}, len(props)) + out := make(map[string]any, len(props)) for k, v := range props { out[k] = v.Value() } @@ -263,36 +275,36 @@ func (c *Conn) getProperties(ctx context.Context, path dbus.ObjectPath, dbusInte } // Deprecated: use GetUnitPropertiesContext instead. -func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) { +func (c *Conn) GetUnitProperties(unit string) (map[string]any, error) { return c.GetUnitPropertiesContext(context.Background(), unit) } // GetUnitPropertiesContext takes the (unescaped) unit name and returns all of // its dbus object properties. -func (c *Conn) GetUnitPropertiesContext(ctx context.Context, unit string) (map[string]interface{}, error) { +func (c *Conn) GetUnitPropertiesContext(ctx context.Context, unit string) (map[string]any, error) { path := unitPath(unit) return c.getProperties(ctx, path, "org.freedesktop.systemd1.Unit") } // Deprecated: use GetUnitPathPropertiesContext instead. -func (c *Conn) GetUnitPathProperties(path dbus.ObjectPath) (map[string]interface{}, error) { +func (c *Conn) GetUnitPathProperties(path dbus.ObjectPath) (map[string]any, error) { return c.GetUnitPathPropertiesContext(context.Background(), path) } // GetUnitPathPropertiesContext takes the (escaped) unit path and returns all // of its dbus object properties. -func (c *Conn) GetUnitPathPropertiesContext(ctx context.Context, path dbus.ObjectPath) (map[string]interface{}, error) { +func (c *Conn) GetUnitPathPropertiesContext(ctx context.Context, path dbus.ObjectPath) (map[string]any, error) { return c.getProperties(ctx, path, "org.freedesktop.systemd1.Unit") } // Deprecated: use GetAllPropertiesContext instead. -func (c *Conn) GetAllProperties(unit string) (map[string]interface{}, error) { +func (c *Conn) GetAllProperties(unit string) (map[string]any, error) { return c.GetAllPropertiesContext(context.Background(), unit) } // GetAllPropertiesContext takes the (unescaped) unit name and returns all of // its dbus object properties. -func (c *Conn) GetAllPropertiesContext(ctx context.Context, unit string) (map[string]interface{}, error) { +func (c *Conn) GetAllPropertiesContext(ctx context.Context, unit string) (map[string]any, error) { path := unitPath(unit) return c.getProperties(ctx, path, "") } @@ -331,20 +343,20 @@ func (c *Conn) GetServiceProperty(service string, propertyName string) (*Propert return c.GetServicePropertyContext(context.Background(), service, propertyName) } -// GetServiceProperty returns property for given service name and property name. +// GetServicePropertyContext returns property for given service name and property name. func (c *Conn) GetServicePropertyContext(ctx context.Context, service string, propertyName string) (*Property, error) { return c.getProperty(ctx, service, "org.freedesktop.systemd1.Service", propertyName) } // Deprecated: use GetUnitTypePropertiesContext instead. -func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]interface{}, error) { +func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]any, error) { return c.GetUnitTypePropertiesContext(context.Background(), unit, unitType) } // GetUnitTypePropertiesContext returns the extra properties for a unit, specific to the unit type. // Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope. // Returns "dbus.Error: Unknown interface" error if the unitType is not the correct type of the unit. -func (c *Conn) GetUnitTypePropertiesContext(ctx context.Context, unit string, unitType string) (map[string]interface{}, error) { +func (c *Conn) GetUnitTypePropertiesContext(ctx context.Context, unit string, unitType string) (map[string]any, error) { path := unitPath(unit) return c.getProperties(ctx, path, "org.freedesktop.systemd1."+unitType) } @@ -389,32 +401,35 @@ type UnitStatus struct { JobPath dbus.ObjectPath // The job object path } -type storeFunc func(retvalues ...interface{}) error +type storeFunc func(retvalues ...any) error -func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) { - result := make([][]interface{}, 0) - err := f(&result) - if err != nil { - return nil, err +// convertSlice converts a []any result into a slice of the target type T +// using dbus.Store to handle the type conversion. +func convertSlice[T any](result []any) ([]T, error) { + converted := make([]T, len(result)) + convertedInterface := make([]any, len(converted)) + for i := range converted { + convertedInterface[i] = &converted[i] } - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] + err := dbus.Store(result, convertedInterface...) + if err != nil { + return nil, err } - status := make([]UnitStatus, len(result)) - statusInterface := make([]interface{}, len(status)) - for i := range status { - statusInterface[i] = &status[i] - } + return converted, nil +} - err = dbus.Store(resultInterface, statusInterface...) +// storeSlice fetches D-Bus array results via the provided storeFunc +// and converts them into a slice of the target type T. +func storeSlice[T any](f storeFunc) ([]T, error) { + var result []any + err := f(&result) if err != nil { return nil, err } - return status, nil + return convertSlice[T](result) } // GetUnitByPID returns the unit object path of the unit a process ID @@ -451,7 +466,7 @@ func (c *Conn) ListUnits() ([]UnitStatus, error) { // Also note that a unit is only loaded if it is active and/or enabled. // Units that are both disabled and inactive will thus not be returned. func (c *Conn) ListUnitsContext(ctx context.Context) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnits", 0).Store) + return storeSlice[UnitStatus](c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnits", 0).Store) } // Deprecated: use ListUnitsFilteredContext instead. @@ -462,7 +477,7 @@ func (c *Conn) ListUnitsFiltered(states []string) ([]UnitStatus, error) { // ListUnitsFilteredContext returns an array with units filtered by state. // It takes a list of units' statuses to filter. func (c *Conn) ListUnitsFilteredContext(ctx context.Context, states []string) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsFiltered", 0, states).Store) + return storeSlice[UnitStatus](c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsFiltered", 0, states).Store) } // Deprecated: use ListUnitsByPatternsContext instead. @@ -475,7 +490,7 @@ func (c *Conn) ListUnitsByPatterns(states []string, patterns []string) ([]UnitSt // Note that units may be known by multiple names at the same time, // and hence there might be more unit names loaded than actual units behind them. func (c *Conn) ListUnitsByPatternsContext(ctx context.Context, states []string, patterns []string) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsByPatterns", 0, states, patterns).Store) + return storeSlice[UnitStatus](c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsByPatterns", 0, states, patterns).Store) } // Deprecated: use ListUnitsByNamesContext instead. @@ -490,7 +505,7 @@ func (c *Conn) ListUnitsByNames(units []string) ([]UnitStatus, error) { // // Requires systemd v230 or higher. func (c *Conn) ListUnitsByNamesContext(ctx context.Context, units []string) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store) + return storeSlice[UnitStatus](c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store) } type UnitFile struct { @@ -498,40 +513,14 @@ type UnitFile struct { Type string } -func (c *Conn) listUnitFilesInternal(f storeFunc) ([]UnitFile, error) { - result := make([][]interface{}, 0) - err := f(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - files := make([]UnitFile, len(result)) - fileInterface := make([]interface{}, len(files)) - for i := range files { - fileInterface[i] = &files[i] - } - - err = dbus.Store(resultInterface, fileInterface...) - if err != nil { - return nil, err - } - - return files, nil -} - // Deprecated: use ListUnitFilesContext instead. func (c *Conn) ListUnitFiles() ([]UnitFile, error) { return c.ListUnitFilesContext(context.Background()) } -// ListUnitFiles returns an array of all available units on disk. +// ListUnitFilesContext returns an array of all available units on disk. func (c *Conn) ListUnitFilesContext(ctx context.Context) ([]UnitFile, error) { - return c.listUnitFilesInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store) + return storeSlice[UnitFile](c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store) } // Deprecated: use ListUnitFilesByPatternsContext instead. @@ -541,7 +530,7 @@ func (c *Conn) ListUnitFilesByPatterns(states []string, patterns []string) ([]Un // ListUnitFilesByPatternsContext returns an array of all available units on disk matched the patterns. func (c *Conn) ListUnitFilesByPatternsContext(ctx context.Context, states []string, patterns []string) ([]UnitFile, error) { - return c.listUnitFilesInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitFilesByPatterns", 0, states, patterns).Store) + return storeSlice[UnitFile](c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitFilesByPatterns", 0, states, patterns).Store) } type LinkUnitFileChange EnableUnitFileChange @@ -569,29 +558,7 @@ func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUn // or unlink), the file name of the symlink and the destination of the // symlink. func (c *Conn) LinkUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) { - result := make([][]interface{}, 0) - err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]LinkUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return nil, err - } - - return changes, nil + return storeSlice[LinkUnitFileChange](c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store) } // Deprecated: use EnableUnitFilesContext instead. @@ -617,25 +584,14 @@ func (c *Conn) EnableUnitFiles(files []string, runtime bool, force bool) (bool, // symlink. func (c *Conn) EnableUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) { var carries_install_info bool + var result []any - result := make([][]interface{}, 0) err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.EnableUnitFiles", 0, files, runtime, force).Store(&carries_install_info, &result) if err != nil { return false, nil, err } - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]EnableUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) + changes, err := convertSlice[EnableUnitFileChange](result) if err != nil { return false, nil, err } @@ -667,29 +623,7 @@ func (c *Conn) DisableUnitFiles(files []string, runtime bool) ([]DisableUnitFile // symlink or unlink), the file name of the symlink and the destination of the // symlink. func (c *Conn) DisableUnitFilesContext(ctx context.Context, files []string, runtime bool) ([]DisableUnitFileChange, error) { - result := make([][]interface{}, 0) - err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]DisableUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return nil, err - } - - return changes, nil + return storeSlice[DisableUnitFileChange](c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store) } type DisableUnitFileChange struct { @@ -713,29 +647,7 @@ func (c *Conn) MaskUnitFiles(files []string, runtime bool, force bool) ([]MaskUn // runtime only (true, /run/systemd/..), or persistently (false, // /etc/systemd/..). func (c *Conn) MaskUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) ([]MaskUnitFileChange, error) { - result := make([][]interface{}, 0) - err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.MaskUnitFiles", 0, files, runtime, force).Store(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]MaskUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return nil, err - } - - return changes, nil + return storeSlice[MaskUnitFileChange](c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.MaskUnitFiles", 0, files, runtime, force).Store) } type MaskUnitFileChange struct { @@ -757,29 +669,7 @@ func (c *Conn) UnmaskUnitFiles(files []string, runtime bool) ([]UnmaskUnitFileCh // for runtime only (true, /run/systemd/..), or persistently (false, // /etc/systemd/..). func (c *Conn) UnmaskUnitFilesContext(ctx context.Context, files []string, runtime bool) ([]UnmaskUnitFileChange, error) { - result := make([][]interface{}, 0) - err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.UnmaskUnitFiles", 0, files, runtime).Store(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]UnmaskUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return nil, err - } - - return changes, nil + return storeSlice[UnmaskUnitFileChange](c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.UnmaskUnitFiles", 0, files, runtime).Store) } type UnmaskUnitFileChange struct { @@ -825,40 +715,21 @@ func (c *Conn) ListJobs() ([]JobStatus, error) { // ListJobsContext returns an array with all currently queued jobs. func (c *Conn) ListJobsContext(ctx context.Context) ([]JobStatus, error) { - return c.listJobsInternal(ctx) + return storeSlice[JobStatus](c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListJobs", 0).Store) } -func (c *Conn) listJobsInternal(ctx context.Context) ([]JobStatus, error) { - result := make([][]interface{}, 0) - if err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListJobs", 0).Store(&result); err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - status := make([]JobStatus, len(result)) - statusInterface := make([]interface{}, len(status)) - for i := range status { - statusInterface[i] = &status[i] - } - - if err := dbus.Store(resultInterface, statusInterface...); err != nil { - return nil, err - } - - return status, nil -} - -// Freeze the cgroup associated with the unit. -// Note that FreezeUnit and ThawUnit are only supported on systems running with cgroup v2. +// FreezeUnit freezes the cgroup associated with the unit. +// Note that FreezeUnit and [Conn.ThawUnit] are only supported on systems running with cgroup v2. func (c *Conn) FreezeUnit(ctx context.Context, unit string) error { return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.FreezeUnit", 0, unit).Store() } -// Unfreeze the cgroup associated with the unit. +// ThawUnit unfreezes the cgroup associated with the unit. func (c *Conn) ThawUnit(ctx context.Context, unit string) error { return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ThawUnit", 0, unit).Store() } + +// AttachProcessesToUnit moves existing processes, identified by pids, into an existing systemd unit. +func (c *Conn) AttachProcessesToUnit(ctx context.Context, unit, subcgroup string, pids []uint32) error { + return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.AttachProcessesToUnit", 0, unit, subcgroup, pids).Store() +} diff --git a/vendor/github.com/coreos/go-systemd/v22/dbus/set.go b/vendor/github.com/coreos/go-systemd/v22/dbus/set.go index 17c5d48565..c0b8fde1fc 100644 --- a/vendor/github.com/coreos/go-systemd/v22/dbus/set.go +++ b/vendor/github.com/coreos/go-systemd/v22/dbus/set.go @@ -14,28 +14,43 @@ package dbus +import ( + "sync" +) + type set struct { data map[string]bool + mu sync.Mutex } func (s *set) Add(value string) { + s.mu.Lock() + defer s.mu.Unlock() s.data[value] = true } func (s *set) Remove(value string) { + s.mu.Lock() + defer s.mu.Unlock() delete(s.data, value) } func (s *set) Contains(value string) (exists bool) { + s.mu.Lock() + defer s.mu.Unlock() _, exists = s.data[value] return } func (s *set) Length() int { + s.mu.Lock() + defer s.mu.Unlock() return len(s.data) } func (s *set) Values() (values []string) { + s.mu.Lock() + defer s.mu.Unlock() for val := range s.data { values = append(values, val) } @@ -43,5 +58,5 @@ func (s *set) Values() (values []string) { } func newSet() *set { - return &set{make(map[string]bool)} + return &set{data: make(map[string]bool)} } diff --git a/vendor/github.com/coreos/go-systemd/v22/dbus/subscription.go b/vendor/github.com/coreos/go-systemd/v22/dbus/subscription.go index 7e370fea21..fe06f2fceb 100644 --- a/vendor/github.com/coreos/go-systemd/v22/dbus/subscription.go +++ b/vendor/github.com/coreos/go-systemd/v22/dbus/subscription.go @@ -15,6 +15,7 @@ package dbus import ( + "context" "errors" "log" "time" @@ -70,7 +71,7 @@ func (c *Conn) dispatch() { switch signal.Name { case "org.freedesktop.systemd1.Manager.JobRemoved": unitName := signal.Body[2].(string) - c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath) + _ = c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath) case "org.freedesktop.systemd1.Manager.UnitNew": unitPath = signal.Body[1].(dbus.ObjectPath) case "org.freedesktop.DBus.Properties.PropertiesChanged": @@ -94,16 +95,26 @@ func (c *Conn) dispatch() { }() } -// SubscribeUnits returns two unbuffered channels which will receive all changed units every -// interval. Deleted units are sent as nil. +// Deprecated: use SubscribeUnitsContext instead. func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) { - return c.SubscribeUnitsCustom(interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 }, nil) + return c.SubscribeUnitsContext(context.Background(), interval) +} + +// SubscribeUnitsContext returns two unbuffered channels which will receive all changed units every +// interval. Deleted units are sent as nil. +func (c *Conn) SubscribeUnitsContext(ctx context.Context, interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) { + return c.SubscribeUnitsCustomContext(ctx, interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 }, nil) } -// SubscribeUnitsCustom is like SubscribeUnits but lets you specify the buffer +// Deprecated: use SubscribeUnitsCustomContext instead. +func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool, filterUnit func(string) bool) (<-chan map[string]*UnitStatus, <-chan error) { + return c.SubscribeUnitsCustomContext(context.Background(), interval, buffer, isChanged, filterUnit) +} + +// SubscribeUnitsCustomContext is like [Conn.SubscribeUnitsContext] but lets you specify the buffer // size of the channels, the comparison function for detecting changes and a filter // function for cutting down on the noise that your channel receives. -func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool, filterUnit func(string) bool) (<-chan map[string]*UnitStatus, <-chan error) { +func (c *Conn) SubscribeUnitsCustomContext(ctx context.Context, interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool, filterUnit func(string) bool) (<-chan map[string]*UnitStatus, <-chan error) { old := make(map[string]*UnitStatus) statusChan := make(chan map[string]*UnitStatus, buffer) errChan := make(chan error, buffer) @@ -112,7 +123,7 @@ func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChange for { timerChan := time.After(interval) - units, err := c.ListUnits() + units, err := c.ListUnitsContext(ctx) if err == nil { cur := make(map[string]*UnitStatus) for i := range units { @@ -145,7 +156,14 @@ func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChange errChan <- err } - <-timerChan + select { + case <-timerChan: + continue + case <-ctx.Done(): + close(statusChan) + close(errChan) + return + } } }() @@ -262,7 +280,7 @@ func (c *Conn) shouldIgnore(path dbus.ObjectPath) bool { return ok && t >= time.Now().UnixNano() } -func (c *Conn) updateIgnore(path dbus.ObjectPath, info map[string]interface{}) { +func (c *Conn) updateIgnore(path dbus.ObjectPath, info map[string]any) { loadState, ok := info["LoadState"].(string) if !ok { return diff --git a/vendor/github.com/coreos/go-systemd/v22/dbus/subscription_set.go b/vendor/github.com/coreos/go-systemd/v22/dbus/subscription_set.go index 5b408d5847..173ca37287 100644 --- a/vendor/github.com/coreos/go-systemd/v22/dbus/subscription_set.go +++ b/vendor/github.com/coreos/go-systemd/v22/dbus/subscription_set.go @@ -15,6 +15,7 @@ package dbus import ( + "context" "time" ) @@ -29,19 +30,24 @@ func (s *SubscriptionSet) filter(unit string) bool { return !s.Contains(unit) } -// Subscribe starts listening for dbus events for all of the units in the set. +// SubscribeContext starts listening for dbus events for all of the units in the set. // Returns channels identical to conn.SubscribeUnits. -func (s *SubscriptionSet) Subscribe() (<-chan map[string]*UnitStatus, <-chan error) { +func (s *SubscriptionSet) SubscribeContext(ctx context.Context) (<-chan map[string]*UnitStatus, <-chan error) { // TODO: Make fully evented by using systemd 209 with properties changed values - return s.conn.SubscribeUnitsCustom(time.Second, 0, + return s.conn.SubscribeUnitsCustomContext(ctx, time.Second, 0, mismatchUnitStatus, func(unit string) bool { return s.filter(unit) }, ) } +// Deprecated: use SubscribeContext instead. +func (s *SubscriptionSet) Subscribe() (<-chan map[string]*UnitStatus, <-chan error) { + return s.SubscribeContext(context.Background()) +} + // NewSubscriptionSet returns a new subscription set. -func (conn *Conn) NewSubscriptionSet() *SubscriptionSet { - return &SubscriptionSet{newSet(), conn} +func (c *Conn) NewSubscriptionSet() *SubscriptionSet { + return &SubscriptionSet{newSet(), c} } // mismatchUnitStatus returns true if the provided UnitStatus objects diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go index 62d91b77d5..5673f5c0bc 100644 --- a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go +++ b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go @@ -1,3 +1,4 @@ +// Package md2man aims in converting markdown into roff (man pages). package md2man import ( diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go index 9d6c473fdc..4f1070fc5b 100644 --- a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go +++ b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go @@ -47,13 +47,13 @@ const ( tableStart = "\n.TS\nallbox;\n" tableEnd = ".TE\n" tableCellStart = "T{\n" - tableCellEnd = "\nT}\n" + tableCellEnd = "\nT}" tablePreprocessor = `'\" t` ) // NewRoffRenderer creates a new blackfriday Renderer for generating roff documents // from markdown -func NewRoffRenderer() *roffRenderer { // nolint: golint +func NewRoffRenderer() *roffRenderer { return &roffRenderer{} } @@ -104,7 +104,7 @@ func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering node.Parent.Prev.Type == blackfriday.Heading && node.Parent.Prev.FirstChild != nil && bytes.EqualFold(node.Parent.Prev.FirstChild.Literal, []byte("NAME")) { - before, after, found := bytes.Cut(node.Literal, []byte(" - ")) + before, after, found := bytesCut(node.Literal, []byte(" - ")) escapeSpecialChars(w, before) if found { out(w, ` \- `) @@ -316,9 +316,8 @@ func (r *roffRenderer) handleTableCell(w io.Writer, node *blackfriday.Node, ente } else if nodeLiteralSize(node) > 30 { end = tableCellEnd } - if node.Next == nil && end != tableCellEnd { - // Last cell: need to carriage return if we are at the end of the - // header row and content isn't wrapped in a "tablecell" + if node.Next == nil { + // Last cell: need to carriage return if we are at the end of the header row. end += crTag } out(w, end) @@ -356,7 +355,7 @@ func countColumns(node *blackfriday.Node) int { } func out(w io.Writer, output string) { - io.WriteString(w, output) // nolint: errcheck + io.WriteString(w, output) //nolint:errcheck } func escapeSpecialChars(w io.Writer, text []byte) { @@ -395,7 +394,7 @@ func escapeSpecialCharsLine(w io.Writer, text []byte) { i++ } if i > org { - w.Write(text[org:i]) // nolint: errcheck + w.Write(text[org:i]) //nolint:errcheck } // escape a character @@ -403,6 +402,15 @@ func escapeSpecialCharsLine(w io.Writer, text []byte) { break } - w.Write([]byte{'\\', text[i]}) // nolint: errcheck + w.Write([]byte{'\\', text[i]}) //nolint:errcheck } } + +// bytesCut is a copy of [bytes.Cut] to provide compatibility with go1.17 +// and older. We can remove this once we drop support for go1.17 and older. +func bytesCut(s, sep []byte) (before, after []byte, found bool) { + if i := bytes.Index(s, sep); i >= 0 { + return s[:i], s[i+len(sep):], true + } + return s, nil, false +} diff --git a/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md b/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md index 734cf61e32..6d016d05c0 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md +++ b/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md @@ -6,49 +6,39 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ## -## [0.6.0] - 2025-11-03 ## +## [0.6.1] - 2025-11-19 ## -> By the Power of Greyskull! +> At last up jumped the cunning spider, and fiercely held her fast. + +### Fixed ### +- Our logic for deciding whether to use `openat2(2)` or fallback to an `O_PATH` + resolver would cache the result to avoid doing needless test runs of + `openat2(2)`. However, this causes issues when `pathrs-lite` is being used by + a program that applies new seccomp-bpf filters onto itself -- if the filter + denies `openat2(2)` then we would return that error rather than falling back + to the `O_PATH` resolver. To resolve this issue, we no longer cache the + result if `openat2(2)` was successful, only if there was an error. +- A file descriptor leak in our `openat2` wrapper (when doing the necessary + `dup` for `RESOLVE_IN_ROOT`) has been removed. -While quite small code-wise, this release marks a very key point in the -development of filepath-securejoin. - -filepath-securejoin was originally intended (back in 2017) to simply be a -single-purpose library that would take some common code used in container -runtimes (specifically, Docker's `FollowSymlinksInScope`) and make it more -general-purpose (with the eventual goals of it ending up in the Go stdlib). - -Of course, I quickly discovered that this problem was actually far more -complicated to solve when dealing with racing attackers, which lead to me -developing `openat2(2)` and [libpathrs][]. I had originally planned for -libpathrs to completely replace filepath-securejoin "once it was ready" but in -the interim we needed to fix several race attacks in runc as part of security -advisories. Obviously we couldn't require the usage of a pre-0.1 Rust library -in runc so it was necessary to port bits of libpathrs into filepath-securejoin. -(Ironically the first prototypes of libpathrs were originally written in Go and -then rewritten to Rust, so the code in filepath-securejoin is actually Go code -that was rewritten to Rust then re-rewritten to Go.) - -It then became clear that pure-Go libraries will likely not be willing to -require CGo for all of their builds, so it was necessary to accept that -filepath-securejoin will need to stay. As such, in v0.5.0 we provided more -pure-Go implementations of features from libpathrs but moved them into -`pathrs-lite` subpackage to clarify what purpose these helpers serve. - -This release finally closes the loop and makes it so that pathrs-lite can -transparently use libpathrs (via a `libpathrs` build-tag). This means that -upstream libraries can use the pure Go version if they prefer, but downstreams -(either downstream library users or even downstream distributions) are able to -migrate to libpathrs for all usages of pathrs-lite in an entire Go binary. - -I should make it clear that I do not plan to port the rest of libpathrs to Go, -as I do not wish to maintain two copies of the same codebase. pathrs-lite -already provides the core essentials necessary to operate on paths safely for -most modern systems. Users who want additional hardening or more ergonomic APIs -are free to use [`cyphar.com/go-pathrs`][go-pathrs] (libpathrs's Go bindings). +## [0.5.2] - 2025-11-19 ## -[libpathrs]: https://github.com/cyphar/libpathrs -[go-pathrs]: https://cyphar.com/go-pathrs +> "Will you walk into my parlour?" said a spider to a fly. + +### Fixed ### +- Our logic for deciding whether to use `openat2(2)` or fallback to an `O_PATH` + resolver would cache the result to avoid doing needless test runs of + `openat2(2)`. However, this causes issues when `pathrs-lite` is being used by + a program that applies new seccomp-bpf filters onto itself -- if the filter + denies `openat2(2)` then we would return that error rather than falling back + to the `O_PATH` resolver. To resolve this issue, we no longer cache the + result if `openat2(2)` was successful, only if there was an error. +- A file descriptor leak in our `openat2` wrapper (when doing the necessary + `dup` for `RESOLVE_IN_ROOT`) has been removed. + +## [0.6.0] - 2025-11-03 ## + +> By the Power of Greyskull! ### Breaking ### - The deprecated `MkdirAll`, `MkdirAllHandle`, `OpenInRoot`, `OpenatInRoot` and @@ -56,12 +46,12 @@ are free to use [`cyphar.com/go-pathrs`][go-pathrs] (libpathrs's Go bindings). directly. ### Added ### -- `pathrs-lite` now has support for using [libpathrs][libpathrs] as a backend. - This is opt-in and can be enabled at build time with the `libpathrs` build - tag. The intention is to allow for downstream libraries and other projects to - make use of the pure-Go `github.com/cyphar/filepath-securejoin/pathrs-lite` - package and distributors can then opt-in to using `libpathrs` for the entire - binary if they wish. +- `pathrs-lite` now has support for using libpathrs as a backend. This is + opt-in and can be enabled at build time with the `libpathrs` build tag. The + intention is to allow for downstream libraries and other projects to make use + of the pure-Go `github.com/cyphar/filepath-securejoin/pathrs-lite` package + and distributors can then opt-in to using `libpathrs` for the entire binary + if they wish. ## [0.5.1] - 2025-10-31 ## @@ -440,8 +430,10 @@ This is our first release of `github.com/cyphar/filepath-securejoin`, containing a full implementation with a coverage of 93.5% (the only missing cases are the error cases, which are hard to mocktest at the moment). -[Unreleased]: https://github.com/cyphar/filepath-securejoin/compare/v0.6.0...HEAD -[0.6.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.5.1...v0.6.0 +[Unreleased]: https://github.com/cyphar/filepath-securejoin/compare/v0.6.1...HEAD +[0.6.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.6.0...v0.6.1 +[0.6.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.5.0...v0.6.0 +[0.5.2]: https://github.com/cyphar/filepath-securejoin/compare/v0.5.1...v0.5.2 [0.5.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.5.0...v0.5.1 [0.5.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.4.1...v0.5.0 [0.4.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.4.0...v0.4.1 diff --git a/vendor/github.com/cyphar/filepath-securejoin/VERSION b/vendor/github.com/cyphar/filepath-securejoin/VERSION index a918a2aa18..ee6cdce3c2 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/VERSION +++ b/vendor/github.com/cyphar/filepath-securejoin/VERSION @@ -1 +1 @@ -0.6.0 +0.6.1 diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/fd/openat2_linux.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/fd/openat2_linux.go index 3e937fe3c1..63863647d5 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/fd/openat2_linux.go +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/fd/openat2_linux.go @@ -39,7 +39,9 @@ const scopedLookupMaxRetries = 128 // Openat2 is an [Fd]-based wrapper around unix.Openat2, but with some retry // logic in case of EAGAIN errors. -func Openat2(dir Fd, path string, how *unix.OpenHow) (*os.File, error) { +// +// NOTE: This is a variable so that the lookup tests can force openat2 to fail. +var Openat2 = func(dir Fd, path string, how *unix.OpenHow) (*os.File, error) { dirFd, fullPath := prepareAt(dir, path) // Make sure we always set O_CLOEXEC. how.Flags |= unix.O_CLOEXEC diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_atomic_go119.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_atomic_go119.go new file mode 100644 index 0000000000..ac93cb045e --- /dev/null +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_atomic_go119.go @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: BSD-3-Clause + +//go:build linux && go1.19 + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gocompat + +import ( + "sync/atomic" +) + +// A Bool is an atomic boolean value. +// The zero value is false. +// +// Bool must not be copied after first use. +type Bool = atomic.Bool diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_atomic_unsupported.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_atomic_unsupported.go new file mode 100644 index 0000000000..21b5b29ada --- /dev/null +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_atomic_unsupported.go @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: BSD-3-Clause + +//go:build linux && !go1.19 + +// Copyright (C) 2024-2025 SUSE LLC. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gocompat + +import ( + "sync/atomic" +) + +// noCopy may be added to structs which must not be copied +// after the first use. +// +// See https://golang.org/issues/8005#issuecomment-190753527 +// for details. +// +// Note that it must not be embedded, due to the Lock and Unlock methods. +type noCopy struct{} + +// Lock is a no-op used by -copylocks checker from `go vet`. +func (*noCopy) Lock() {} + +// b32 returns a uint32 0 or 1 representing b. +func b32(b bool) uint32 { + if b { + return 1 + } + return 0 +} + +// A Bool is an atomic boolean value. +// The zero value is false. +// +// Bool must not be copied after first use. +type Bool struct { + _ noCopy + v uint32 +} + +// Load atomically loads and returns the value stored in x. +func (x *Bool) Load() bool { return atomic.LoadUint32(&x.v) != 0 } + +// Store atomically stores val into x. +func (x *Bool) Store(val bool) { atomic.StoreUint32(&x.v, b32(val)) } diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/lookup_linux.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/lookup_linux.go index 56480f0cee..ad233f1405 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/lookup_linux.go +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/lookup_linux.go @@ -193,8 +193,13 @@ func lookupInRoot(root fd.Fd, unsafePath string, partial bool) (Handle *os.File, // managed open, along with the remaining path components not opened. // Try to use openat2 if possible. - if linux.HasOpenat2() { - return lookupOpenat2(root, unsafePath, partial) + // + // NOTE: If openat2(2) works normally but fails for this lookup, it is + // probably not a good idea to fall-back to the O_PATH resolver. An + // attacker could find a bug in the O_PATH resolver and uncontionally + // falling back to the O_PATH resolver would form a downgrade attack. + if handle, remainingPath, err := lookupOpenat2(root, unsafePath, partial); err == nil || linux.HasOpenat2() { + return handle, remainingPath, err } // Get the "actual" root path from /proc/self/fd. This is necessary if the diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/openat2_linux.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/openat2_linux.go index b80ecd0895..9c5c268f66 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/openat2_linux.go +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/openat2_linux.go @@ -41,6 +41,7 @@ func openat2(dir fd.Fd, path string, how *unix.OpenHow) (*os.File, error) { if err != nil { return nil, err } + _ = file.Close() file = newFile } } diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/linux/openat2_linux.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/linux/openat2_linux.go index 399609dc36..dc5f65cef7 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/linux/openat2_linux.go +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/linux/openat2_linux.go @@ -17,15 +17,27 @@ import ( "github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat" ) +// sawOpenat2Error stores whether we have seen an error from HasOpenat2. This +// is a one-way toggle, so as soon as we see an error we "lock" into that mode. +// We cannot use sync.OnceValue to store the success/fail state once because it +// is possible for the program we are running in to apply a seccomp-bpf filter +// and thus disable openat2 during execution. +var sawOpenat2Error gocompat.Bool + // HasOpenat2 returns whether openat2(2) is supported on the running kernel. -var HasOpenat2 = gocompat.SyncOnceValue(func() bool { +var HasOpenat2 = func() bool { + if sawOpenat2Error.Load() { + return false + } + fd, err := unix.Openat2(unix.AT_FDCWD, ".", &unix.OpenHow{ Flags: unix.O_PATH | unix.O_CLOEXEC, Resolve: unix.RESOLVE_NO_SYMLINKS | unix.RESOLVE_IN_ROOT, }) if err != nil { + sawOpenat2Error.Store(true) // doesn't matter if we race here return false } _ = unix.Close(fd) return true -}) +} diff --git a/vendor/github.com/opencontainers/cgroups/cgroups.go b/vendor/github.com/opencontainers/cgroups/cgroups.go index 1f127550c0..5a97bd36b7 100644 --- a/vendor/github.com/opencontainers/cgroups/cgroups.go +++ b/vendor/github.com/opencontainers/cgroups/cgroups.go @@ -29,6 +29,11 @@ type Manager interface { // can be used to merely create a cgroup. Apply(pid int) error + // AddPid adds a process with a given pid to an existing cgroup. + // The subcgroup argument is either empty, or a path relative to + // a cgroup under under the manager's cgroup. + AddPid(subcgroup string, pid int) error + // GetPids returns the PIDs of all processes inside the cgroup. GetPids() ([]int, error) diff --git a/vendor/github.com/opencontainers/cgroups/config_linux.go b/vendor/github.com/opencontainers/cgroups/config_linux.go index 9bc58a3789..3d29d938bf 100644 --- a/vendor/github.com/opencontainers/cgroups/config_linux.go +++ b/vendor/github.com/opencontainers/cgroups/config_linux.go @@ -90,8 +90,8 @@ type Resources struct { // Cgroup's SCHED_IDLE value. CPUIdle *int64 `json:"cpu_idle,omitempty"` - // Process limit; set <= `0' to disable limit. - PidsLimit int64 `json:"pids_limit,omitempty"` + // Process limit; set < `0' to disable limit. `nil` means "keep current limit". + PidsLimit *int64 `json:"pids_limit,omitempty"` // Specifies per cgroup weight, range is from 10 to 1000. BlkioWeight uint16 `json:"blkio_weight,omitempty"` diff --git a/vendor/github.com/opencontainers/cgroups/fs/cpuacct.go b/vendor/github.com/opencontainers/cgroups/fs/cpuacct.go index 391a023c75..bde25b0759 100644 --- a/vendor/github.com/opencontainers/cgroups/fs/cpuacct.go +++ b/vendor/github.com/opencontainers/cgroups/fs/cpuacct.go @@ -129,12 +129,16 @@ func getPercpuUsageInModes(path string) ([]uint64, []uint64, error) { defer fd.Close() scanner := bufio.NewScanner(fd) - scanner.Scan() // skipping header line + scanner.Scan() // Read header line. + const want = "cpu user system" + if hdr := scanner.Text(); !strings.HasPrefix(hdr, want) { + return nil, nil, malformedLine(path, file, hdr) + } for scanner.Scan() { - // Each line is: cpu user system - fields := strings.SplitN(scanner.Text(), " ", 3) - if len(fields) != 3 { + // Each line is: cpu user system. Keep N at 4 to ignore extra fields. + fields := strings.SplitN(scanner.Text(), " ", 4) + if len(fields) < 3 { continue } diff --git a/vendor/github.com/opencontainers/cgroups/fs/fs.go b/vendor/github.com/opencontainers/cgroups/fs/fs.go index 23a8fb8742..625931193e 100644 --- a/vendor/github.com/opencontainers/cgroups/fs/fs.go +++ b/vendor/github.com/opencontainers/cgroups/fs/fs.go @@ -4,6 +4,8 @@ import ( "errors" "fmt" "os" + "path" + "strings" "sync" "golang.org/x/sys/unix" @@ -139,6 +141,33 @@ func (m *Manager) Apply(pid int) (retErr error) { return retErr } +// AddPid adds a process with a given pid to an existing cgroup. +// The subcgroup argument is either empty, or a path relative to +// a cgroup under under the manager's cgroup. +func (m *Manager) AddPid(subcgroup string, pid int) (retErr error) { + m.mu.Lock() + defer m.mu.Unlock() + + c := m.cgroups + + for _, dir := range m.paths { + path := path.Join(dir, subcgroup) + if !strings.HasPrefix(path, dir) { + return fmt.Errorf("bad sub cgroup path: %s", subcgroup) + } + + if err := cgroups.WriteCgroupProc(path, pid); err != nil { + if isIgnorableError(c.Rootless, err) && c.Path == "" { + retErr = cgroups.ErrRootless + continue + } + return err + } + } + + return retErr +} + func (m *Manager) Destroy() error { m.mu.Lock() defer m.mu.Unlock() diff --git a/vendor/github.com/opencontainers/cgroups/fs/pids.go b/vendor/github.com/opencontainers/cgroups/fs/pids.go index 9319761e6a..36bd339af8 100644 --- a/vendor/github.com/opencontainers/cgroups/fs/pids.go +++ b/vendor/github.com/opencontainers/cgroups/fs/pids.go @@ -19,19 +19,24 @@ func (s *PidsGroup) Apply(path string, _ *cgroups.Resources, pid int) error { } func (s *PidsGroup) Set(path string, r *cgroups.Resources) error { - if r.PidsLimit != 0 { - // "max" is the fallback value. - limit := "max" - - if r.PidsLimit > 0 { - limit = strconv.FormatInt(r.PidsLimit, 10) - } - - if err := cgroups.WriteFile(path, "pids.max", limit); err != nil { - return err - } + if r.PidsLimit == nil { + return nil } + // "max" is the fallback value. + val := "max" + if limit := *r.PidsLimit; limit > 0 { + val = strconv.FormatInt(limit, 10) + } else if limit == 0 { + // systemd doesn't support setting pids.max to "0", so when setting + // TasksMax we need to remap it to "1". We do the same thing here to + // avoid flip-flop behaviour between the fs and systemd drivers. In + // practice, the pids cgroup behaviour is basically identical. + val = "1" + } + if err := cgroups.WriteFile(path, "pids.max", val); err != nil { + return err + } return nil } diff --git a/vendor/github.com/opencontainers/cgroups/fs2/fs2.go b/vendor/github.com/opencontainers/cgroups/fs2/fs2.go index c5d5a1f8ec..356d087985 100644 --- a/vendor/github.com/opencontainers/cgroups/fs2/fs2.go +++ b/vendor/github.com/opencontainers/cgroups/fs2/fs2.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "os" + "path/filepath" "strings" "github.com/opencontainers/cgroups" @@ -83,6 +84,18 @@ func (m *Manager) Apply(pid int) error { return nil } +// AddPid adds a process with a given pid to an existing cgroup. +// The subcgroup argument is either empty, or a path relative to +// a cgroup under under the manager's cgroup. +func (m *Manager) AddPid(subcgroup string, pid int) error { + path := filepath.Join(m.dirPath, subcgroup) + if !strings.HasPrefix(path, m.dirPath) { + return fmt.Errorf("bad sub cgroup path: %s", subcgroup) + } + + return cgroups.WriteCgroupProc(path, pid) +} + func (m *Manager) GetPids() ([]int, error) { return cgroups.GetPids(m.dirPath) } diff --git a/vendor/github.com/opencontainers/cgroups/fs2/io.go b/vendor/github.com/opencontainers/cgroups/fs2/io.go index 0f6ef7fea5..3c6dcc3bf2 100644 --- a/vendor/github.com/opencontainers/cgroups/fs2/io.go +++ b/vendor/github.com/opencontainers/cgroups/fs2/io.go @@ -165,11 +165,22 @@ func statIo(dirPath string, stats *cgroups.Stats) error { case "wios": op = "Write" targetTable = &parsedStats.IoServicedRecursive + + case "cost.usage": + op = "Count" + targetTable = &parsedStats.IoCostUsage + case "cost.wait": + op = "Count" + targetTable = &parsedStats.IoCostWait + case "cost.indebt": + op = "Count" + targetTable = &parsedStats.IoCostIndebt + case "cost.indelay": + op = "Count" + targetTable = &parsedStats.IoCostIndelay + default: - // Skip over entries we cannot map to cgroupv1 stats for now. - // In the future we should expand the stats struct to include - // them. - logrus.Debugf("cgroupv2 io stats: skipping over unmappable %s entry", item) + logrus.Debugf("cgroupv2 io stats: unknown entry %s", item) continue } diff --git a/vendor/github.com/opencontainers/cgroups/fs2/pids.go b/vendor/github.com/opencontainers/cgroups/fs2/pids.go index 9b82b90115..f932259ad5 100644 --- a/vendor/github.com/opencontainers/cgroups/fs2/pids.go +++ b/vendor/github.com/opencontainers/cgroups/fs2/pids.go @@ -4,6 +4,7 @@ import ( "errors" "math" "os" + "strconv" "strings" "golang.org/x/sys/unix" @@ -13,19 +14,26 @@ import ( ) func isPidsSet(r *cgroups.Resources) bool { - return r.PidsLimit != 0 + return r.PidsLimit != nil } func setPids(dirPath string, r *cgroups.Resources) error { if !isPidsSet(r) { return nil } - if val := numToStr(r.PidsLimit); val != "" { - if err := cgroups.WriteFile(dirPath, "pids.max", val); err != nil { - return err - } + val := "max" + if limit := *r.PidsLimit; limit > 0 { + val = strconv.FormatInt(limit, 10) + } else if limit == 0 { + // systemd doesn't support setting pids.max to "0", so when setting + // TasksMax we need to remap it to "1". We do the same thing here to + // avoid flip-flop behaviour between the fs and systemd drivers. In + // practice, the pids cgroup behaviour is basically identical. + val = "1" + } + if err := cgroups.WriteFile(dirPath, "pids.max", val); err != nil { + return err } - return nil } diff --git a/vendor/github.com/opencontainers/cgroups/stats.go b/vendor/github.com/opencontainers/cgroups/stats.go index 6cd6253ee0..01701333ab 100644 --- a/vendor/github.com/opencontainers/cgroups/stats.go +++ b/vendor/github.com/opencontainers/cgroups/stats.go @@ -159,6 +159,10 @@ type BlkioStats struct { IoTimeRecursive []BlkioStatEntry `json:"io_time_recursive,omitempty"` SectorsRecursive []BlkioStatEntry `json:"sectors_recursive,omitempty"` PSI *PSIStats `json:"psi,omitempty"` + IoCostUsage []BlkioStatEntry `json:"io_cost_usage,omitempty"` + IoCostWait []BlkioStatEntry `json:"io_cost_wait,omitempty"` + IoCostIndebt []BlkioStatEntry `json:"io_cost_indebt,omitempty"` + IoCostIndelay []BlkioStatEntry `json:"io_cost_indelay,omitempty"` } type HugetlbStats struct { diff --git a/vendor/github.com/opencontainers/cgroups/systemd/common.go b/vendor/github.com/opencontainers/cgroups/systemd/common.go index 875a589e3d..537defbf2d 100644 --- a/vendor/github.com/opencontainers/cgroups/systemd/common.go +++ b/vendor/github.com/opencontainers/cgroups/systemd/common.go @@ -6,6 +6,7 @@ import ( "fmt" "math" "os" + "path" "strconv" "strings" "sync" @@ -208,6 +209,20 @@ func stopUnit(cm *dbusConnManager, unitName string) error { return nil } +func addPid(cm *dbusConnManager, unitName, subcgroup string, pid int) error { + absSubcgroup := subcgroup + if !path.IsAbs(absSubcgroup) { + absSubcgroup = "/" + subcgroup + } + if absSubcgroup != path.Clean(absSubcgroup) { + return fmt.Errorf("bad sub cgroup path: %s", subcgroup) + } + + return cm.retryOnDisconnect(func(c *systemdDbus.Conn) error { + return c.AttachProcessesToUnit(context.TODO(), unitName, absSubcgroup, []uint32{uint32(pid)}) + }) +} + func resetFailedUnit(cm *dbusConnManager, name string) error { return cm.retryOnDisconnect(func(c *systemdDbus.Conn) error { return c.ResetFailedUnitContext(context.TODO(), name) diff --git a/vendor/github.com/opencontainers/cgroups/systemd/dbus.go b/vendor/github.com/opencontainers/cgroups/systemd/dbus.go index bb87ae83ae..c492372a7a 100644 --- a/vendor/github.com/opencontainers/cgroups/systemd/dbus.go +++ b/vendor/github.com/opencontainers/cgroups/systemd/dbus.go @@ -4,10 +4,13 @@ import ( "context" "errors" "fmt" + "math/rand/v2" "sync" + "time" systemdDbus "github.com/coreos/go-systemd/v22/dbus" dbus "github.com/godbus/dbus/v5" + "golang.org/x/sys/unix" ) var ( @@ -64,10 +67,27 @@ func (d *dbusConnManager) getConnection() (*systemdDbus.Conn, error) { } func (d *dbusConnManager) newConnection() (*systemdDbus.Conn, error) { - if dbusRootless { - return newUserSystemdDbus() + newDbusConn := func() (*systemdDbus.Conn, error) { + if dbusRootless { + return newUserSystemdDbus() + } + return systemdDbus.NewWithContext(context.TODO()) + } + + var err error + for retry := range 7 { + var conn *systemdDbus.Conn + conn, err = newDbusConn() + if !errors.Is(err, unix.EAGAIN) { + return conn, err + } + // Exponential backoff (100ms * 2^attempt + ~12.5% jitter). + // At most we would expect 15 seconds of delay with 7 attempts. + delay := 100 * time.Millisecond << retry + delay += time.Duration(rand.Int64N(1 + (delay.Milliseconds() >> 3))) + time.Sleep(delay) } - return systemdDbus.NewWithContext(context.TODO()) + return nil, fmt.Errorf("dbus connection failed after several retries: %w", err) } // resetConnection resets the connection to its initial state diff --git a/vendor/github.com/opencontainers/cgroups/systemd/v1.go b/vendor/github.com/opencontainers/cgroups/systemd/v1.go index b8959adbfa..96e69bb860 100644 --- a/vendor/github.com/opencontainers/cgroups/systemd/v1.go +++ b/vendor/github.com/opencontainers/cgroups/systemd/v1.go @@ -2,6 +2,7 @@ package systemd import ( "errors" + "math" "os" "path/filepath" "strings" @@ -97,9 +98,17 @@ func genV1ResourcesProperties(r *cgroups.Resources, cm *dbusConnManager) ([]syst newProp("BlockIOWeight", uint64(r.BlkioWeight))) } - if r.PidsLimit > 0 || r.PidsLimit == -1 { + if r.PidsLimit != nil { + var tasksMax uint64 + if limit := *r.PidsLimit; limit < 0 { + tasksMax = math.MaxUint64 // "infinity" + } else if limit == 0 { + tasksMax = 1 // systemd does not accept "0" for TasksMax + } else { + tasksMax = uint64(limit) + } properties = append(properties, - newProp("TasksMax", uint64(r.PidsLimit))) + newProp("TasksMax", tasksMax)) } err = addCpuset(cm, &properties, r.CpusetCpus, r.CpusetMems) @@ -215,6 +224,25 @@ func (m *LegacyManager) Apply(pid int) error { return nil } +// AddPid adds a process with a given pid to an existing cgroup. +// The subcgroup argument is either empty, or a path relative to +// a cgroup under under the manager's cgroup. +func (m *LegacyManager) AddPid(subcgroup string, pid int) error { + m.mu.Lock() + defer m.mu.Unlock() + + if err := addPid(m.dbus, getUnitName(m.cgroups), subcgroup, pid); err != nil { + return err + } + + // Since systemd only joins controllers it knows, use cgroupfs for the rest. + fsMgr, err := fs.NewManager(m.cgroups, m.paths) + if err != nil { + return err + } + return fsMgr.AddPid(subcgroup, pid) +} + func (m *LegacyManager) Destroy() error { m.mu.Lock() defer m.mu.Unlock() diff --git a/vendor/github.com/opencontainers/cgroups/systemd/v2.go b/vendor/github.com/opencontainers/cgroups/systemd/v2.go index 636b9cb01b..f76c93e844 100644 --- a/vendor/github.com/opencontainers/cgroups/systemd/v2.go +++ b/vendor/github.com/opencontainers/cgroups/systemd/v2.go @@ -176,6 +176,9 @@ func unifiedResToSystemdProps(cm *dbusConnManager, res map[string]string) (props return nil, fmt.Errorf("unified resource %q value conversion error: %w", k, err) } } + if num == 0 { + num = 1 // systemd does not accept "0" for TasksMax + } props = append(props, newProp("TasksMax", num)) @@ -256,9 +259,17 @@ func genV2ResourcesProperties(dirPath string, r *cgroups.Resources, cm *dbusConn addCPUQuota(cm, &properties, &r.CpuQuota, r.CpuPeriod) - if r.PidsLimit > 0 || r.PidsLimit == -1 { + if r.PidsLimit != nil { + var tasksMax uint64 + if limit := *r.PidsLimit; limit < 0 { + tasksMax = math.MaxUint64 // "infinity" + } else if limit == 0 { + tasksMax = 1 // systemd does not accept "0" for TasksMax + } else { + tasksMax = uint64(limit) + } properties = append(properties, - newProp("TasksMax", uint64(r.PidsLimit))) + newProp("TasksMax", tasksMax)) } err = addCpuset(cm, &properties, r.CpusetCpus, r.CpusetMems) @@ -383,6 +394,16 @@ func cgroupFilesToChown() ([]string, error) { return filesToChown, nil } +// AddPid adds a process with a given pid to an existing cgroup. +// The subcgroup argument is either empty, or a path relative to +// a cgroup under under the manager's cgroup. +func (m *UnifiedManager) AddPid(subcgroup string, pid int) error { + m.mu.Lock() + defer m.mu.Unlock() + + return addPid(m.dbus, getUnitName(m.cgroups), subcgroup, pid) +} + func (m *UnifiedManager) Destroy() error { m.mu.Lock() defer m.mu.Unlock() diff --git a/vendor/github.com/opencontainers/runc/internal/linux/eintr.go b/vendor/github.com/opencontainers/runc/internal/linux/eintr.go new file mode 100644 index 0000000000..36a6e3e29e --- /dev/null +++ b/vendor/github.com/opencontainers/runc/internal/linux/eintr.go @@ -0,0 +1,28 @@ +package linux + +import ( + "errors" + + "golang.org/x/sys/unix" +) + +// retryOnEINTR takes a function that returns an error and calls it +// until the error returned is not EINTR. +func retryOnEINTR(fn func() error) error { + for { + err := fn() + if !errors.Is(err, unix.EINTR) { + return err + } + } +} + +// retryOnEINTR2 is like retryOnEINTR, but it returns 2 values. +func retryOnEINTR2[T any](fn func() (T, error)) (T, error) { + for { + val, err := fn() + if !errors.Is(err, unix.EINTR) { + return val, err + } + } +} diff --git a/vendor/github.com/opencontainers/runc/internal/linux/linux.go b/vendor/github.com/opencontainers/runc/internal/linux/linux.go index f9e6753427..1371315932 100644 --- a/vendor/github.com/opencontainers/runc/internal/linux/linux.go +++ b/vendor/github.com/opencontainers/runc/internal/linux/linux.go @@ -2,16 +2,110 @@ package linux import ( "os" + "unsafe" "golang.org/x/sys/unix" ) +// Dup3 wraps [unix.Dup3]. +func Dup3(oldfd, newfd, flags int) error { + err := retryOnEINTR(func() error { + return unix.Dup3(oldfd, newfd, flags) + }) + return os.NewSyscallError("dup3", err) +} + +// Exec wraps [unix.Exec]. +func Exec(cmd string, args, env []string) error { + err := retryOnEINTR(func() error { + return unix.Exec(cmd, args, env) + }) + if err != nil { + return &os.PathError{Op: "exec", Path: cmd, Err: err} + } + return nil +} + +// Getwd wraps [unix.Getwd]. +func Getwd() (wd string, err error) { + wd, err = retryOnEINTR2(unix.Getwd) + return wd, os.NewSyscallError("getwd", err) +} + +// Open wraps [unix.Open]. +func Open(path string, mode int, perm uint32) (fd int, err error) { + fd, err = retryOnEINTR2(func() (int, error) { + return unix.Open(path, mode, perm) + }) + if err != nil { + return -1, &os.PathError{Op: "open", Path: path, Err: err} + } + return fd, nil +} + +// Openat wraps [unix.Openat]. +func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { + fd, err = retryOnEINTR2(func() (int, error) { + return unix.Openat(dirfd, path, mode, perm) + }) + if err != nil { + return -1, &os.PathError{Op: "openat", Path: path, Err: err} + } + return fd, nil +} + +// Recvfrom wraps [unix.Recvfrom]. +func Recvfrom(fd int, p []byte, flags int) (n int, from unix.Sockaddr, err error) { + err = retryOnEINTR(func() error { + n, from, err = unix.Recvfrom(fd, p, flags) + return err + }) + if err != nil { + return 0, nil, os.NewSyscallError("recvfrom", err) + } + return n, from, err +} + +// SchedSetaffinity wraps sched_setaffinity syscall without unix.CPUSet size limitation. +func SchedSetaffinity(pid int, buf []byte) error { + err := retryOnEINTR(func() error { + _, _, errno := unix.Syscall( + unix.SYS_SCHED_SETAFFINITY, + uintptr(pid), + uintptr(len(buf)), + uintptr((unsafe.Pointer)(&buf[0]))) + if errno != 0 { + return errno + } + return nil + }) + return os.NewSyscallError("sched_setaffinity", err) +} + +// Sendmsg wraps [unix.Sendmsg]. +func Sendmsg(fd int, p, oob []byte, to unix.Sockaddr, flags int) error { + err := retryOnEINTR(func() error { + return unix.Sendmsg(fd, p, oob, to, flags) + }) + return os.NewSyscallError("sendmsg", err) +} + +// SetMempolicy wraps set_mempolicy. +func SetMempolicy(mode int, mask *unix.CPUSet) error { + err := retryOnEINTR(func() error { + return unix.SetMemPolicy(mode, mask) + }) + return os.NewSyscallError("set_mempolicy", err) +} + // Readlinkat wraps [unix.Readlinkat]. func Readlinkat(dir *os.File, path string) (string, error) { size := 4096 for { linkBuf := make([]byte, size) - n, err := unix.Readlinkat(int(dir.Fd()), path, linkBuf) + n, err := retryOnEINTR2(func() (int, error) { + return unix.Readlinkat(int(dir.Fd()), path, linkBuf) + }) if err != nil { return "", &os.PathError{Op: "readlinkat", Path: dir.Name() + "/" + path, Err: err} } diff --git a/vendor/github.com/opencontainers/runc/internal/pathrs/mkdirall.go b/vendor/github.com/opencontainers/runc/internal/pathrs/mkdirall.go new file mode 100644 index 0000000000..3a896f4841 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/internal/pathrs/mkdirall.go @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright (C) 2024-2025 Aleksa Sarai + * Copyright (C) 2024-2025 SUSE LLC + * + * 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 pathrs + +import ( + "fmt" + "os" + "path/filepath" +) + +// MkdirAllParentInRoot is like [MkdirAllInRoot] except that it only creates +// the parent directory of the target path, returning the trailing component so +// the caller has more flexibility around constructing the final inode. +// +// Callers need to be very careful operating on the trailing path, as trivial +// mistakes like following symlinks can cause security bugs. Most people +// should probably just use [MkdirAllInRoot] or [CreateInRoot]. +func MkdirAllParentInRoot(root, unsafePath string, mode os.FileMode) (*os.File, string, error) { + // MkdirAllInRoot also does hallucinateUnsafePath, but we need to do it + // here first because when we split unsafePath into (dir, file) components + // we want to be doing so with the hallucinated path (so that trailing + // dangling symlinks are treated correctly). + unsafePath, err := hallucinateUnsafePath(root, unsafePath) + if err != nil { + return nil, "", fmt.Errorf("failed to construct hallucinated target path: %w", err) + } + + dirPath, filename := filepath.Split(unsafePath) + if filepath.Join("/", filename) == "/" { + return nil, "", fmt.Errorf("create parent dir in root subpath %q has bad trailing component %q", unsafePath, filename) + } + + dirFd, err := MkdirAllInRoot(root, dirPath, mode) + return dirFd, filename, err +} diff --git a/vendor/github.com/opencontainers/runc/internal/pathrs/mkdirall_pathrslite.go b/vendor/github.com/opencontainers/runc/internal/pathrs/mkdirall_pathrslite.go index a9a0157c68..c2578e051f 100644 --- a/vendor/github.com/opencontainers/runc/internal/pathrs/mkdirall_pathrslite.go +++ b/vendor/github.com/opencontainers/runc/internal/pathrs/mkdirall_pathrslite.go @@ -21,14 +21,13 @@ package pathrs import ( "fmt" "os" - "path/filepath" "github.com/cyphar/filepath-securejoin/pathrs-lite" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) -// MkdirAllInRootOpen attempts to make +// MkdirAllInRoot attempts to make // // path, _ := securejoin.SecureJoin(root, unsafePath) // os.MkdirAll(path, mode) @@ -49,19 +48,10 @@ import ( // handling if unsafePath has already been scoped within the rootfs (this is // needed for a lot of runc callers and fixing this would require reworking a // lot of path logic). -func MkdirAllInRootOpen(root, unsafePath string, mode os.FileMode) (*os.File, error) { - // If the path is already "within" the root, get the path relative to the - // root and use that as the unsafe path. This is necessary because a lot of - // MkdirAllInRootOpen callers have already done SecureJoin, and refactoring - // all of them to stop using these SecureJoin'd paths would require a fair - // amount of work. - // TODO(cyphar): Do the refactor to libpathrs once it's ready. - if IsLexicallyInRoot(root, unsafePath) { - subPath, err := filepath.Rel(root, unsafePath) - if err != nil { - return nil, err - } - unsafePath = subPath +func MkdirAllInRoot(root, unsafePath string, mode os.FileMode) (*os.File, error) { + unsafePath, err := hallucinateUnsafePath(root, unsafePath) + if err != nil { + return nil, fmt.Errorf("failed to construct hallucinated target path: %w", err) } // Check for any silly mode bits. @@ -87,13 +77,3 @@ func MkdirAllInRootOpen(root, unsafePath string, mode os.FileMode) (*os.File, er return pathrs.MkdirAllHandle(rootDir, unsafePath, mode) }) } - -// MkdirAllInRoot is a wrapper around MkdirAllInRootOpen which closes the -// returned handle, for callers that don't need to use it. -func MkdirAllInRoot(root, unsafePath string, mode os.FileMode) error { - f, err := MkdirAllInRootOpen(root, unsafePath, mode) - if err == nil { - _ = f.Close() - } - return err -} diff --git a/vendor/github.com/opencontainers/runc/internal/pathrs/path.go b/vendor/github.com/opencontainers/runc/internal/pathrs/path.go index 1ee7c795d5..77be989241 100644 --- a/vendor/github.com/opencontainers/runc/internal/pathrs/path.go +++ b/vendor/github.com/opencontainers/runc/internal/pathrs/path.go @@ -19,7 +19,11 @@ package pathrs import ( + "os" + "path/filepath" "strings" + + securejoin "github.com/cyphar/filepath-securejoin" ) // IsLexicallyInRoot is shorthand for strings.HasPrefix(path+"/", root+"/"), @@ -32,3 +36,81 @@ func IsLexicallyInRoot(root, path string) bool { path = strings.TrimRight(path, "/") return strings.HasPrefix(path+"/", root+"/") } + +// LexicallyCleanPath makes a path safe for use with filepath.Join. This is +// done by not only cleaning the path, but also (if the path is relative) +// adding a leading '/' and cleaning it (then removing the leading '/'). This +// ensures that a path resulting from prepending another path will always +// resolve to lexically be a subdirectory of the prefixed path. This is all +// done lexically, so paths that include symlinks won't be safe as a result of +// using CleanPath. +func LexicallyCleanPath(path string) string { + // Deal with empty strings nicely. + if path == "" { + return "" + } + + // Ensure that all paths are cleaned (especially problematic ones like + // "/../../../../../" which can cause lots of issues). + + if filepath.IsAbs(path) { + return filepath.Clean(path) + } + + // If the path isn't absolute, we need to do more processing to fix paths + // such as "../../../..//some/path". We also shouldn't convert absolute + // paths to relative ones. + path = filepath.Clean(string(os.PathSeparator) + path) + // This can't fail, as (by definition) all paths are relative to root. + path, _ = filepath.Rel(string(os.PathSeparator), path) + + return path +} + +// LexicallyStripRoot returns the passed path, stripping the root path if it +// was (lexicially) inside it. Note that both passed paths will always be +// treated as absolute, and the returned path will also always be absolute. In +// addition, the paths are cleaned before stripping the root. +func LexicallyStripRoot(root, path string) string { + // Make the paths clean and absolute. + root, path = LexicallyCleanPath("/"+root), LexicallyCleanPath("/"+path) + switch { + case path == root: + path = "/" + case root == "/": + // do nothing + default: + path = strings.TrimPrefix(path, root+"/") + } + return LexicallyCleanPath("/" + path) +} + +// hallucinateUnsafePath creates a new unsafePath which has all symlinks +// (including dangling symlinks) fully resolved and any non-existent components +// treated as though they are real. This is effectively just a wrapper around +// [securejoin.SecureJoin] that strips the root. This path *IS NOT* safe to use +// as-is, you *MUST* operate on the returned path with pathrs-lite. +// +// The reason for this methods is that in previous runc versions, we would +// tolerate nonsense paths with dangling symlinks as path components. +// pathrs-lite does not support this, so instead we have to emulate this +// behaviour by doing SecureJoin *purely to get a semi-reasonable path to use* +// and then we use pathrs-lite to operate on the path safely. +// +// It would be quite difficult to emulate this in a race-free way in +// pathrs-lite, so instead we use [securejoin.SecureJoin] to simply produce a +// new candidate path for operations like [MkdirAllInRoot] so they can then +// operate on the new unsafePath as if it was what the user requested. +// +// If unsafePath is already lexically inside root, it is stripped before +// re-resolving it (this is done to ensure compatibility with legacy callers +// within runc that call SecureJoin before calling into pathrs). +func hallucinateUnsafePath(root, unsafePath string) (string, error) { + unsafePath = LexicallyStripRoot(root, unsafePath) + weirdPath, err := securejoin.SecureJoin(root, unsafePath) + if err != nil { + return "", err + } + unsafePath = LexicallyStripRoot(root, weirdPath) + return unsafePath, nil +} diff --git a/vendor/github.com/opencontainers/runc/internal/pathrs/root_pathrslite.go b/vendor/github.com/opencontainers/runc/internal/pathrs/root_pathrslite.go index 899af27036..51db77440d 100644 --- a/vendor/github.com/opencontainers/runc/internal/pathrs/root_pathrslite.go +++ b/vendor/github.com/opencontainers/runc/internal/pathrs/root_pathrslite.go @@ -19,12 +19,12 @@ package pathrs import ( - "fmt" "os" - "path/filepath" "github.com/cyphar/filepath-securejoin/pathrs-lite" "golang.org/x/sys/unix" + + "github.com/opencontainers/runc/internal/linux" ) // OpenInRoot opens the given path inside the root with the provided flags. It @@ -48,12 +48,7 @@ func OpenInRoot(root, subpath string, flags int) (*os.File, error) { // include it in the passed flags. The fileMode argument uses unix.* mode bits, // *not* os.FileMode. func CreateInRoot(root, subpath string, flags int, fileMode uint32) (*os.File, error) { - dir, filename := filepath.Split(subpath) - if filepath.Join("/", filename) == "/" { - return nil, fmt.Errorf("create in root subpath %q has bad trailing component %q", subpath, filename) - } - - dirFd, err := MkdirAllInRootOpen(root, dir, 0o755) + dirFd, filename, err := MkdirAllParentInRoot(root, subpath, 0o755) if err != nil { return nil, err } @@ -64,7 +59,7 @@ func CreateInRoot(root, subpath string, flags int, fileMode uint32) (*os.File, e // trailing symlinks, so this is safe to do. libpathrs's Root::create_file // works the same way. flags |= unix.O_CREAT | unix.O_NOFOLLOW - fd, err := unix.Openat(int(dirFd.Fd()), filename, flags, fileMode) + fd, err := linux.Openat(int(dirFd.Fd()), filename, flags, fileMode) if err != nil { return nil, err } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go b/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go index 4b03d4c715..e2a26488e0 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go @@ -2,15 +2,17 @@ package apparmor import "errors" -var ( - // IsEnabled returns true if apparmor is enabled for the host. - IsEnabled = isEnabled +// IsEnabled returns true if apparmor is enabled for the host. +func IsEnabled() bool { + return isEnabled() +} - // ApplyProfile will apply the profile with the specified name to the process after - // the next exec. It is only supported on Linux and produces an ErrApparmorNotEnabled - // on other platforms. - ApplyProfile = applyProfile +// ApplyProfile will apply the profile with the specified name to the process +// after the next exec. It is only supported on Linux and produces an +// [ErrApparmorNotEnabled] on other platforms. +func ApplyProfile(name string) error { + return applyProfile(name) +} - // ErrApparmorNotEnabled indicates that AppArmor is not enabled or not supported. - ErrApparmorNotEnabled = errors.New("apparmor: config provided but apparmor not supported") -) +// ErrApparmorNotEnabled indicates that AppArmor is not enabled or not supported. +var ErrApparmorNotEnabled = errors.New("apparmor: config provided but apparmor not supported") 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 a3a8e93258..9bb4fb2cd2 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go @@ -9,7 +9,6 @@ import ( "golang.org/x/sys/unix" "github.com/opencontainers/runc/internal/pathrs" - "github.com/opencontainers/runc/libcontainer/utils" ) var ( @@ -29,7 +28,7 @@ func isEnabled() bool { } func setProcAttr(attr, value string) error { - attr = utils.CleanPath(attr) + attr = pathrs.LexicallyCleanPath(attr) attrSubPath := "attr/apparmor/" + attr if _, err := os.Stat("/proc/self/" + attrSubPath); errors.Is(err, os.ErrNotExist) { // fall back to the old convention @@ -50,7 +49,7 @@ func setProcAttr(attr, value string) error { return err } -// changeOnExec reimplements aa_change_onexec from libapparmor in Go +// 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: %w", err) @@ -58,9 +57,8 @@ func changeOnExec(name string) error { return nil } -// applyProfile will apply the profile with the specified name to the process after -// the next exec. It is only supported on Linux and produces an error on other -// platforms. +// applyProfile will apply the profile with the specified name to the process +// after the next exec. func applyProfile(name string) error { if name == "" { return nil diff --git a/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities.go b/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities.go index 379e66c66c..b5963a3281 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities.go @@ -5,7 +5,8 @@ package capabilities import ( "errors" "fmt" - "sort" + "maps" + "slices" "strings" "sync" "syscall" @@ -67,7 +68,7 @@ func New(capConfig *configs.Capabilities) (*Caps, error) { return nil, err } if len(unknownCaps) > 0 { - logrus.Warn("ignoring unknown or unavailable capabilities: ", mapKeys(unknownCaps)) + logrus.Warn("ignoring unknown or unavailable capabilities: ", slices.Sorted(maps.Keys(unknownCaps))) } return &c, nil } @@ -88,16 +89,6 @@ func capSlice(caps []string, unknownCaps map[string]struct{}) []capability.Cap { return out } -// mapKeys returns the keys of input in sorted order -func mapKeys(input map[string]struct{}) []string { - keys := make([]string, 0, len(input)) - for c := range input { - keys = append(keys, c) - } - sort.Strings(keys) - return keys -} - // Caps holds the capabilities for a container. type Caps struct { pid capability.Capabilities diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cmd_clone.go b/vendor/github.com/opencontainers/runc/libcontainer/cmd_clone.go new file mode 100644 index 0000000000..67418070f0 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/cmd_clone.go @@ -0,0 +1,37 @@ +package libcontainer + +import "os/exec" + +// cloneCmd creates a copy of exec.Cmd. It is needed because cmd.Start +// must only be used once, and go1.26 actually enforces that (see +// https://go-review.googlesource.com/c/go/+/728642). The implementation +// is similar to +// +// cmd = *c +// return &cmd +// +// except it does not copy private fields, or fields populated +// after the call to cmd.Start. +// +// NOTE if Go will add exec.Cmd.Clone, we should switch to it. +func cloneCmd(c *exec.Cmd) *exec.Cmd { + cmd := &exec.Cmd{ + Path: c.Path, + Args: c.Args, + Env: c.Env, + Dir: c.Dir, + Stdin: c.Stdin, + Stdout: c.Stdout, + Stderr: c.Stderr, + ExtraFiles: c.ExtraFiles, + SysProcAttr: c.SysProcAttr, + // Don't copy Process, ProcessState, Err since + // these fields are populated after the start. + + // Technically, we do not use Cancel or WaitDelay, + // but they are here for the sake of completeness. + Cancel: c.Cancel, + WaitDelay: c.WaitDelay, + } + return cmd +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go index 3869a2edc2..6141c018fb 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go @@ -95,69 +95,72 @@ type Syscall struct { // Config defines configuration options for executing a process inside a contained environment. type Config struct { // NoPivotRoot will use MS_MOVE and a chroot to jail the process into the container's rootfs - // This is a common option when the container is running in ramdisk - NoPivotRoot bool `json:"no_pivot_root"` + // This is a common option when the container is running in ramdisk. + NoPivotRoot bool `json:"no_pivot_root,omitempty"` // ParentDeathSignal specifies the signal that is sent to the container's process in the case // that the parent process dies. - ParentDeathSignal int `json:"parent_death_signal"` + ParentDeathSignal int `json:"parent_death_signal,omitempty"` // Path to a directory containing the container's root filesystem. Rootfs string `json:"rootfs"` // Umask is the umask to use inside of the container. - Umask *uint32 `json:"umask"` + Umask *uint32 `json:"umask,omitempty"` // Readonlyfs will remount the container's rootfs as readonly where only externally mounted // bind mounts are writtable. - Readonlyfs bool `json:"readonlyfs"` + Readonlyfs bool `json:"readonlyfs,omitempty"` // Specifies the mount propagation flags to be applied to /. - RootPropagation int `json:"rootPropagation"` + RootPropagation int `json:"rootPropagation,omitempty"` // Mounts specify additional source and destination paths that will be mounted inside the container's - // rootfs and mount namespace if specified + // rootfs and mount namespace if specified. Mounts []*Mount `json:"mounts"` // The device nodes that should be automatically created within the container upon container start. Note, make sure that the node is marked as allowed in the cgroup as well! Devices []*devices.Device `json:"devices"` - MountLabel string `json:"mount_label"` + // NetDevices are key-value pairs, keyed by network device name, moved to the container's network namespace. + NetDevices map[string]*LinuxNetDevice `json:"netDevices,omitempty"` - // Hostname optionally sets the container's hostname if provided - Hostname string `json:"hostname"` + MountLabel string `json:"mount_label,omitempty"` - // Domainname optionally sets the container's domainname if provided - Domainname string `json:"domainname"` + // Hostname optionally sets the container's hostname if provided. + Hostname string `json:"hostname,omitempty"` + + // Domainname optionally sets the container's domainname if provided. + Domainname string `json:"domainname,omitempty"` // Namespaces specifies the container's namespaces that it should setup when cloning the init process - // If a namespace is not provided that namespace is shared from the container's parent process + // If a namespace is not provided that namespace is shared from the container's parent process. Namespaces Namespaces `json:"namespaces"` // Capabilities specify the capabilities to keep when executing the process inside the container - // All capabilities not specified will be dropped from the processes capability mask - Capabilities *Capabilities `json:"capabilities"` + // All capabilities not specified will be dropped from the processes capability mask. + Capabilities *Capabilities `json:"capabilities,omitempty"` - // Networks specifies the container's network setup to be created - Networks []*Network `json:"networks"` + // Networks specifies the container's network setup to be created. + Networks []*Network `json:"networks,omitempty"` - // Routes can be specified to create entries in the route table as the container is started - Routes []*Route `json:"routes"` + // Routes can be specified to create entries in the route table as the container is started. + Routes []*Route `json:"routes,omitempty"` // Cgroups specifies specific cgroup settings for the various subsystems that the container is // placed into to limit the resources the container has available. Cgroups *cgroups.Cgroup `json:"cgroups"` // AppArmorProfile specifies the profile to apply to the process running in the container and is - // change at the time the process is execed + // change at the time the process is executed. AppArmorProfile string `json:"apparmor_profile,omitempty"` // ProcessLabel specifies the label to apply to the process running in the container. It is - // commonly used by selinux + // commonly used by selinux. ProcessLabel string `json:"process_label,omitempty"` // Rlimits specifies the resource limits, such as max open files, to set in the container - // If Rlimits are not set, the container will inherit rlimits from the parent process + // If Rlimits are not set, the container will inherit rlimits from the parent process. Rlimits []Rlimit `json:"rlimits,omitempty"` // OomScoreAdj specifies the adjustment to be made by the kernel when calculating oom scores @@ -167,35 +170,35 @@ type Config struct { // More information about kernel oom score calculation here: https://lwn.net/Articles/317814/ OomScoreAdj *int `json:"oom_score_adj,omitempty"` - // UIDMappings is an array of User ID mappings for User Namespaces - UIDMappings []IDMap `json:"uid_mappings"` + // UIDMappings is an array of User ID mappings for User Namespaces. + UIDMappings []IDMap `json:"uid_mappings,omitempty"` - // GIDMappings is an array of Group ID mappings for User Namespaces - GIDMappings []IDMap `json:"gid_mappings"` + // GIDMappings is an array of Group ID mappings for User Namespaces. + GIDMappings []IDMap `json:"gid_mappings,omitempty"` // MaskPaths specifies paths within the container's rootfs to mask over with a bind // mount pointing to /dev/null as to prevent reads of the file. - MaskPaths []string `json:"mask_paths"` + MaskPaths []string `json:"mask_paths,omitempty"` // ReadonlyPaths specifies paths within the container's rootfs to remount as read-only // so that these files prevent any writes. - ReadonlyPaths []string `json:"readonly_paths"` + ReadonlyPaths []string `json:"readonly_paths,omitempty"` // Sysctl is a map of properties and their values. It is the equivalent of using // sysctl -w my.property.name value in Linux. - Sysctl map[string]string `json:"sysctl"` + Sysctl map[string]string `json:"sysctl,omitempty"` // Seccomp allows actions to be taken whenever a syscall is made within the container. // A number of rules are given, each having an action to be taken if a syscall matches it. // A default action to be taken if no rules match is also given. - Seccomp *Seccomp `json:"seccomp"` + Seccomp *Seccomp `json:"seccomp,omitempty"` // NoNewPrivileges controls whether processes in the container can gain additional privileges. NoNewPrivileges bool `json:"no_new_privileges,omitempty"` // Hooks are a collection of actions to perform at various container lifecycle events. // CommandHooks are serialized to JSON, but other hooks are not. - Hooks Hooks + Hooks Hooks `json:"Hooks,omitempty"` // Version is the version of opencontainer specification that is supported. Version string `json:"version"` @@ -205,12 +208,15 @@ type Config struct { // NoNewKeyring will not allocated a new session keyring for the container. It will use the // callers keyring in this case. - NoNewKeyring bool `json:"no_new_keyring"` + NoNewKeyring bool `json:"no_new_keyring,omitempty"` // IntelRdt specifies settings for Intel RDT group that the container is placed into // to limit the resources (e.g., L3 cache, memory bandwidth) the container has available IntelRdt *IntelRdt `json:"intel_rdt,omitempty"` + // MemoryPolicy specifies NUMA memory policy for the container. + MemoryPolicy *LinuxMemoryPolicy `json:"memory_policy,omitempty"` + // RootlessEUID is set when the runc was launched with non-zero EUID. // Note that RootlessEUID is set to false when launched with EUID=0 in userns. // When RootlessEUID is set, runc creates a new userns for the container. @@ -302,7 +308,8 @@ type CPUAffinity struct { Initial, Final *unix.CPUSet } -func toCPUSet(str string) (*unix.CPUSet, error) { +// ToCPUSet parses a string in list format into a unix.CPUSet, e.g. "0-3,5,7-9". +func ToCPUSet(str string) (*unix.CPUSet, error) { if str == "" { return nil, nil } @@ -322,7 +329,7 @@ func toCPUSet(str string) (*unix.CPUSet, error) { return int(ret), nil } - for _, r := range strings.Split(str, ",") { + for r := range strings.SplitSeq(str, ",") { // Allow extra spaces around. r = strings.TrimSpace(r) // Allow empty elements (extra commas). @@ -353,7 +360,7 @@ func toCPUSet(str string) (*unix.CPUSet, error) { } } if s.Count() == 0 { - return nil, fmt.Errorf("no CPUs found in %q", str) + return nil, fmt.Errorf("no members found in set %q", str) } return s, nil @@ -364,11 +371,11 @@ func ConvertCPUAffinity(sa *specs.CPUAffinity) (*CPUAffinity, error) { if sa == nil { return nil, nil } - initial, err := toCPUSet(sa.Initial) + initial, err := ToCPUSet(sa.Initial) if err != nil { return nil, fmt.Errorf("bad CPUAffinity.Initial: %w", err) } - final, err := toCPUSet(sa.Final) + final, err := ToCPUSet(sa.Final) if err != nil { return nil, fmt.Errorf("bad CPUAffinity.Final: %w", err) } @@ -448,15 +455,15 @@ func KnownHookNames() []string { type Capabilities struct { // Bounding is the set of capabilities checked by the kernel. - Bounding []string + Bounding []string `json:"Bounding,omitempty"` // Effective is the set of capabilities checked by the kernel. - Effective []string + Effective []string `json:"Effective,omitempty"` // Inheritable is the capabilities preserved across execve. - Inheritable []string + Inheritable []string `json:"Inheritable,omitempty"` // Permitted is the limiting superset for effective capabilities. - Permitted []string + Permitted []string `json:"Permitted,omitempty"` // Ambient is the ambient set of capabilities that are kept. - Ambient []string + Ambient []string `json:"Ambient,omitempty"` } // Deprecated: use [Hooks.Run] instead. @@ -506,7 +513,7 @@ func (hooks *Hooks) MarshalJSON() ([]byte, error) { return serializableHooks } - return json.Marshal(map[string]interface{}{ + return json.Marshal(map[string]any{ "prestart": serialize((*hooks)[Prestart]), "createRuntime": serialize((*hooks)[CreateRuntime]), "createContainer": serialize((*hooks)[CreateContainer]), diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/doc.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/doc.go new file mode 100644 index 0000000000..2d3ae0b27d --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/doc.go @@ -0,0 +1,2 @@ +// Package configs defines the structures and constants used for configuring a container +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 f8d951ab8b..11ccc2d1f5 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/intelrdt.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/intelrdt.go @@ -4,6 +4,10 @@ type IntelRdt struct { // The identity for RDT Class of Service ClosID string `json:"closID,omitempty"` + // Schemata is a generic field to specify schemata file in the resctrl + // filesystem. Each element represents one line written to the schemata file. + Schemata []string `json:"schemata,omitempty"` + // The schema for L3 cache id and capacity bitmask (CBM) // Format: "L3:=;=;..." L3CacheSchema string `json:"l3_cache_schema,omitempty"` @@ -13,4 +17,7 @@ type IntelRdt struct { // The unit of memory bandwidth is specified in "percentages" by // default, and in "MBps" if MBA Software Controller is enabled. MemBwSchema string `json:"memBwSchema,omitempty"` + + // Create a monitoring group for the container. + EnableMonitoring bool `json:"enableMonitoring,omitempty"` } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/memorypolicy.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/memorypolicy.go new file mode 100644 index 0000000000..b7b9c6bce1 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/memorypolicy.go @@ -0,0 +1,33 @@ +package configs + +import "golang.org/x/sys/unix" + +// Memory policy modes and flags as defined in /usr/include/linux/mempolicy.h +// +// Deprecated: use constants from [unix] instead. +// +//nolint:revive,staticcheck,nolintlint // ignore ALL_CAPS errors in consts from numaif.h, will match unix.* in the future +const ( + MPOL_DEFAULT = unix.MPOL_DEFAULT + MPOL_PREFERRED = unix.MPOL_PREFERRED + MPOL_BIND = unix.MPOL_BIND + MPOL_INTERLEAVE = unix.MPOL_INTERLEAVE + MPOL_LOCAL = unix.MPOL_LOCAL + MPOL_PREFERRED_MANY = unix.MPOL_PREFERRED_MANY + MPOL_WEIGHTED_INTERLEAVE = unix.MPOL_WEIGHTED_INTERLEAVE + + MPOL_F_STATIC_NODES = unix.MPOL_F_STATIC_NODES + MPOL_F_RELATIVE_NODES = unix.MPOL_F_RELATIVE_NODES + MPOL_F_NUMA_BALANCING = unix.MPOL_F_NUMA_BALANCING +) + +// LinuxMemoryPolicy contains memory policy configuration. +type LinuxMemoryPolicy struct { + // Mode specifies memory policy mode without mode flags. See + // set_mempolicy() documentation for details. + Mode int `json:"mode,omitempty"` + // Flags contains mode flags. + Flags int `json:"flags,omitempty"` + // Nodes contains NUMA nodes to which the mode applies. + Nodes *unix.CPUSet `json:"nodes,omitempty"` +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/mount_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/mount_linux.go index b69e9ab238..87b18bac3d 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/mount_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/mount_linux.go @@ -4,7 +4,7 @@ import "golang.org/x/sys/unix" type MountIDMapping struct { // Recursive indicates if the mapping needs to be recursive. - Recursive bool `json:"recursive"` + Recursive bool `json:"recursive,omitempty"` // UserNSPath is a path to a user namespace that indicates the necessary // id-mappings for MOUNT_ATTR_IDMAP. If set to non-"", UIDMappings and @@ -31,26 +31,26 @@ type Mount struct { Device string `json:"device"` // Mount flags. - Flags int `json:"flags"` + Flags int `json:"flags,omitempty"` // Mount flags that were explicitly cleared in the configuration (meaning // the user explicitly requested that these flags *not* be set). - ClearedFlags int `json:"cleared_flags"` + ClearedFlags int `json:"cleared_flags,omitempty"` - // Propagation Flags - PropagationFlags []int `json:"propagation_flags"` + // Propagation flags. + PropagationFlags []int `json:"propagation_flags,omitempty"` // Mount data applied to the mount. - Data string `json:"data"` + Data string `json:"data,omitempty"` // Relabel source if set, "z" indicates shared, "Z" indicates unshared. - Relabel string `json:"relabel"` + Relabel string `json:"relabel,omitempty"` // RecAttr represents mount properties to be applied recursively (AT_RECURSIVE), see mount_setattr(2). - RecAttr *unix.MountAttr `json:"rec_attr"` + RecAttr *unix.MountAttr `json:"rec_attr,omitempty"` // Extensions are additional flags that are specific to runc. - Extensions int `json:"extensions"` + Extensions int `json:"extensions,omitempty"` // Mapping is the MOUNT_ATTR_IDMAP configuration for the mount. If non-nil, // the mount is configured to use MOUNT_ATTR_IDMAP-style id mappings. diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_linux.go index 898f96fd0f..f950900460 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_linux.go @@ -3,6 +3,7 @@ package configs import ( "fmt" "os" + "slices" "sync" ) @@ -86,7 +87,7 @@ func NamespaceTypes() []NamespaceType { // alternate path that is able to be joined via setns. type Namespace struct { Type NamespaceType `json:"type"` - Path string `json:"path"` + Path string `json:"path,omitempty"` } func (n *Namespace) GetPath(pid int) string { @@ -98,7 +99,7 @@ func (n *Namespaces) Remove(t NamespaceType) bool { if i == -1 { return false } - *n = append((*n)[:i], (*n)[i+1:]...) + *n = slices.Delete((*n), i, i+1) return true } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/netdevices.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/netdevices.go new file mode 100644 index 0000000000..09c38649e4 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/netdevices.go @@ -0,0 +1,7 @@ +package configs + +// LinuxNetDevice represents a single network device to be added to the container's network namespace. +type LinuxNetDevice struct { + // Name of the device in the container namespace. + Name string `json:"name,omitempty"` +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/network.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/network.go index c44c3ea71b..aeac2efb34 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/network.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/network.go @@ -5,49 +5,49 @@ package configs // The network configuration can be omitted from a container causing the // container to be setup with the host's networking stack type Network struct { - // Type sets the networks type, commonly veth and loopback + // Type sets the networks type, commonly veth and loopback. Type string `json:"type"` - // Name of the network interface - Name string `json:"name"` + // Name of the network interface. + Name string `json:"name,omitempty"` // The bridge to use. - Bridge string `json:"bridge"` + Bridge string `json:"bridge,omitempty"` - // MacAddress contains the MAC address to set on the network interface - MacAddress string `json:"mac_address"` + // MacAddress contains the MAC address to set on the network interface. + MacAddress string `json:"mac_address,omitempty"` - // Address contains the IPv4 and mask to set on the network interface - Address string `json:"address"` + // Address contains the IPv4 and mask to set on the network interface. + Address string `json:"address,omitempty"` - // Gateway sets the gateway address that is used as the default for the interface - Gateway string `json:"gateway"` + // Gateway sets the gateway address that is used as the default for the interface. + Gateway string `json:"gateway,omitempty"` - // IPv6Address contains the IPv6 and mask to set on the network interface - IPv6Address string `json:"ipv6_address"` + // IPv6Address contains the IPv6 and mask to set on the network interface. + IPv6Address string `json:"ipv6_address,omitempty"` - // IPv6Gateway sets the ipv6 gateway address that is used as the default for the interface - IPv6Gateway string `json:"ipv6_gateway"` + // IPv6Gateway sets the ipv6 gateway address that is used as the default for the interface. + IPv6Gateway string `json:"ipv6_gateway,omitempty"` // Mtu sets the mtu value for the interface and will be mirrored on both the host and // container's interfaces if a pair is created, specifically in the case of type veth // Note: This does not apply to loopback interfaces. - Mtu int `json:"mtu"` + Mtu int `json:"mtu,omitempty"` // TxQueueLen sets the tx_queuelen value for the interface and will be mirrored on both the host and // container's interfaces if a pair is created, specifically in the case of type veth // Note: This does not apply to loopback interfaces. - TxQueueLen int `json:"txqueuelen"` + TxQueueLen int `json:"txqueuelen,omitempty"` // HostInterfaceName is a unique name of a veth pair that resides on in the host interface of the // container. - HostInterfaceName string `json:"host_interface_name"` + HostInterfaceName string `json:"host_interface_name,omitempty"` // HairpinMode specifies if hairpin NAT should be enabled on the virtual interface // bridge port in the case of type veth // Note: This is unsupported on some systems. // Note: This does not apply to loopback interfaces. - HairpinMode bool `json:"hairpin_mode"` + HairpinMode bool `json:"hairpin_mode,omitempty"` } // Route defines a routing table entry. @@ -62,14 +62,14 @@ type Network struct { // destination of 0.0.0.0(or *) when viewed in the route table. type Route struct { // Destination specifies the destination IP address and mask in the CIDR form. - Destination string `json:"destination"` + Destination string `json:"destination,omitempty"` // Source specifies the source IP address and mask in the CIDR form. - Source string `json:"source"` + Source string `json:"source,omitempty"` // Gateway specifies the gateway IP address. - Gateway string `json:"gateway"` + Gateway string `json:"gateway,omitempty"` // InterfaceName specifies the device to set this route up for, for example eth0. - InterfaceName string `json:"interface_name"` + InterfaceName string `json:"interface_name,omitempty"` } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/doc.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/doc.go new file mode 100644 index 0000000000..8819c8806c --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/doc.go @@ -0,0 +1,2 @@ +// Package validate provides helpers for validating configuration. +package validate diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/intelrdt.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/intelrdt.go new file mode 100644 index 0000000000..7b6015b826 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/intelrdt.go @@ -0,0 +1,41 @@ +package validate + +import ( + "sync" + + "github.com/opencontainers/runc/libcontainer/intelrdt" +) + +// Cache the result of intelrdt IsEnabled functions to avoid repeated sysfs +// access and enable mocking for unit tests. +type intelRdtStatus struct { + sync.Once + rdtEnabled bool + catEnabled bool + mbaEnabled bool +} + +var intelRdt = &intelRdtStatus{} + +func (i *intelRdtStatus) init() { + i.Do(func() { + i.rdtEnabled = intelrdt.IsEnabled() + i.catEnabled = intelrdt.IsCATEnabled() + i.mbaEnabled = intelrdt.IsMBAEnabled() + }) +} + +func (i *intelRdtStatus) isEnabled() bool { + i.init() + return i.rdtEnabled +} + +func (i *intelRdtStatus) isCATEnabled() bool { + i.init() + return i.catEnabled +} + +func (i *intelRdtStatus) isMBAEnabled() bool { + i.init() + return i.mbaEnabled +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go index 88cf1cd60f..ef9c8e6f94 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go @@ -60,7 +60,7 @@ func rootlessEUIDMount(config *configs.Config) error { if !strings.Contains(mount.Data, "id=") { continue } - for _, opt := range strings.Split(mount.Data, ",") { + for opt := range strings.SplitSeq(mount.Data, ",") { if str, ok := strings.CutPrefix(opt, "uid="); ok { uid, err := strconv.Atoi(str) if err != nil { 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 e0052900f4..dc61349917 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go @@ -10,7 +10,6 @@ import ( "github.com/opencontainers/cgroups" "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/runc/libcontainer/intelrdt" "github.com/opencontainers/runtime-spec/specs-go" selinux "github.com/opencontainers/selinux/go-selinux" "github.com/sirupsen/logrus" @@ -24,6 +23,7 @@ func Validate(config *configs.Config) error { cgroupsCheck, rootfs, network, + netdevices, uts, security, namespaces, @@ -33,6 +33,7 @@ func Validate(config *configs.Config) error { mountsStrict, scheduler, ioPriority, + memoryPolicy, } for _, c := range checks { if err := c(config); err != nil { @@ -70,6 +71,43 @@ func rootfs(config *configs.Config) error { return nil } +// https://elixir.bootlin.com/linux/v6.12/source/net/core/dev.c#L1066 +func devValidName(name string) bool { + if len(name) == 0 || len(name) > unix.IFNAMSIZ { + return false + } + if name == "." || name == ".." { + return false + } + if strings.ContainsAny(name, "/: ") { + return false + } + return true +} + +func netdevices(config *configs.Config) error { + if len(config.NetDevices) == 0 { + return nil + } + if !config.Namespaces.Contains(configs.NEWNET) { + return errors.New("unable to move network devices without a NET namespace") + } + + if config.RootlessEUID || config.RootlessCgroups { + return errors.New("network devices are not supported for rootless containers") + } + + for name, netdev := range config.NetDevices { + if !devValidName(name) { + return fmt.Errorf("invalid network device name %q", name) + } + if netdev.Name != "" && !devValidName(netdev.Name) { + return fmt.Errorf("invalid network device name %q", netdev.Name) + } + } + return nil +} + func network(config *configs.Config) error { if !config.Namespaces.Contains(configs.NEWNET) { if len(config.Networks) > 0 || len(config.Routes) > 0 { @@ -104,7 +142,7 @@ func security(config *configs.Config) error { func namespaces(config *configs.Config) error { if config.Namespaces.Contains(configs.NEWUSER) { - if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) { + if _, err := os.Stat("/proc/self/ns/user"); errors.Is(err, os.ErrNotExist) { return errors.New("user namespaces aren't enabled in the kernel") } hasPath := config.Namespaces.PathOf(configs.NEWUSER) != "" @@ -122,13 +160,13 @@ func namespaces(config *configs.Config) error { } if config.Namespaces.Contains(configs.NEWCGROUP) { - if _, err := os.Stat("/proc/self/ns/cgroup"); os.IsNotExist(err) { + if _, err := os.Stat("/proc/self/ns/cgroup"); errors.Is(err, os.ErrNotExist) { return errors.New("cgroup namespaces aren't enabled in the kernel") } } if config.Namespaces.Contains(configs.NEWTIME) { - if _, err := os.Stat("/proc/self/timens_offsets"); os.IsNotExist(err) { + if _, err := os.Stat("/proc/self/timens_offsets"); errors.Is(err, os.ErrNotExist) { return errors.New("time namespaces aren't enabled in the kernel") } hasPath := config.Namespaces.PathOf(configs.NEWTIME) != "" @@ -237,6 +275,30 @@ func sysctl(config *configs.Config) error { return fmt.Errorf("sysctl %q is not allowed as it conflicts with the OCI %q field", s, "hostname") } } + + if strings.HasPrefix(s, "user.") { + + // while it is technically true that a non-userns + // container can write to /proc/sys/user on behalf of + // the init_user_ns, it was not previously supported, + // and doesn't guarantee that someone else spawns a + // different container and writes there, changing the + // values. in particular, setting something like + // max_user_namespaces to non-zero could be a vector to + // use 0-days where the admin had previously disabled + // them. + // + // additionally, this setting affects other host + // processes that are not container related. + // + // so let's refuse this unless we know for sure it + // won't touch anything else. + if !config.Namespaces.Contains(configs.NEWUSER) { + return fmt.Errorf("setting ucounts without a user namespace not allowed: %v", s) + } + continue + } + return fmt.Errorf("sysctl %q is not in a separate kernel namespace", s) } @@ -245,14 +307,19 @@ func sysctl(config *configs.Config) error { func intelrdtCheck(config *configs.Config) error { if config.IntelRdt != nil { - if config.IntelRdt.ClosID == "." || config.IntelRdt.ClosID == ".." || strings.Contains(config.IntelRdt.ClosID, "/") { - return fmt.Errorf("invalid intelRdt.ClosID %q", config.IntelRdt.ClosID) + if !intelRdt.isEnabled() { + return fmt.Errorf("intelRdt is specified in config, but Intel RDT is not enabled") + } + + switch clos := config.IntelRdt.ClosID; { + case clos == ".", clos == "..", len(clos) > 1 && strings.Contains(clos, "/"): + return fmt.Errorf("invalid intelRdt.ClosID %q", clos) } - if !intelrdt.IsCATEnabled() && config.IntelRdt.L3CacheSchema != "" { + 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 != "" { + if !intelRdt.isMBAEnabled() && config.IntelRdt.MemBwSchema != "" { return errors.New("intelRdt.memBwSchema is specified in config, but Intel RDT/MBA is not enabled") } } @@ -416,3 +483,26 @@ func ioPriority(config *configs.Config) error { return nil } + +func memoryPolicy(config *configs.Config) error { + mpol := config.MemoryPolicy + if mpol == nil { + return nil + } + switch mpol.Mode { + case unix.MPOL_DEFAULT, unix.MPOL_LOCAL: + if mpol.Nodes != nil && mpol.Nodes.Count() != 0 { + return fmt.Errorf("memory policy mode requires 0 nodes but got %d", mpol.Nodes.Count()) + } + case unix.MPOL_BIND, unix.MPOL_INTERLEAVE, + unix.MPOL_PREFERRED_MANY, unix.MPOL_WEIGHTED_INTERLEAVE: + if mpol.Nodes == nil || mpol.Nodes.Count() == 0 { + return fmt.Errorf("memory policy mode requires at least one node but got 0") + } + case unix.MPOL_PREFERRED: + // Zero or more nodes are allowed by the kernel. + default: + return fmt.Errorf("invalid memory policy mode: %d", mpol.Mode) + } + return nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/console_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/console_linux.go index c93151bc6b..4131be4fcc 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/console_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/console_linux.go @@ -33,9 +33,10 @@ func checkPtmxHandle(ptmx *os.File) error { if stat.Ino != PTMX_INO { return fmt.Errorf("ptmx handle has wrong inode number: %v", stat.Ino) } - if stat.Mode&unix.S_IFMT != unix.S_IFCHR || stat.Rdev != unix.Mkdev(PTMX_MAJOR, PTMX_MINOR) { + rdev := uint64(stat.Rdev) //nolint:unconvert // Rdev is uint32 on MIPS. + if stat.Mode&unix.S_IFMT != unix.S_IFCHR || rdev != unix.Mkdev(PTMX_MAJOR, PTMX_MINOR) { return fmt.Errorf("ptmx handle is not a real char ptmx device: ftype %#x %d:%d", - stat.Mode&unix.S_IFMT, unix.Major(stat.Rdev), unix.Minor(stat.Rdev)) + stat.Mode&unix.S_IFMT, unix.Major(rdev), unix.Minor(rdev)) } return nil }) @@ -79,9 +80,10 @@ func getPtyPeer(pty console.Console, unsafePeerPath string, flags int) (*os.File if statfs.Type != unix.DEVPTS_SUPER_MAGIC { return fmt.Errorf("pty peer handle is not on a real devpts mount: super magic is %#x", statfs.Type) } - if stat.Mode&unix.S_IFMT != unix.S_IFCHR || stat.Rdev != wantPeerDev { + rdev := uint64(stat.Rdev) //nolint:unconvert // Rdev is uint32 on MIPS. + if stat.Mode&unix.S_IFMT != unix.S_IFCHR || rdev != wantPeerDev { return fmt.Errorf("pty peer handle is not the real char device for pty %d: ftype %#x %d:%d", - peerNum, stat.Mode&unix.S_IFMT, unix.Major(stat.Rdev), unix.Minor(stat.Rdev)) + peerNum, stat.Mode&unix.S_IFMT, unix.Major(rdev), unix.Minor(rdev)) } return nil }); err != nil { @@ -155,7 +157,7 @@ func mountConsole(peerPty *os.File) error { // dupStdio replaces stdio with the given peerPty. func dupStdio(peerPty *os.File) error { for _, i := range []int{0, 1, 2} { - if err := unix.Dup3(int(peerPty.Fd()), i, 0); err != nil { + if err := linux.Dup3(int(peerPty.Fd()), i, 0); err != nil { return err } } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go index 2dc2b86eb4..b4368547ca 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go @@ -7,7 +7,6 @@ import ( "io" "os" "os/exec" - "path" "path/filepath" "reflect" "strconv" @@ -50,11 +49,11 @@ type Container struct { type State struct { BaseState - // Platform specific fields below here + // Platform specific fields below. // Specified if the container was started under the rootless mode. // Set to true if BaseState.Config.RootlessEUID && BaseState.Config.RootlessCgroups - Rootless bool `json:"rootless"` + Rootless bool `json:"rootless,omitempty"` // Paths to all the container's cgroups, as returned by (*cgroups.Manager).GetPaths // @@ -62,17 +61,22 @@ type State struct { // to the cgroup for this subsystem. // // For cgroup v2 unified hierarchy, a key is "", and the value is the unified path. - CgroupPaths map[string]string `json:"cgroup_paths"` + CgroupPaths map[string]string `json:"cgroup_paths,omitempty"` // NamespacePaths are filepaths to the container's namespaces. Key is the namespace type // with the value as the path. NamespacePaths map[configs.NamespaceType]string `json:"namespace_paths"` - // Container's standard descriptors (std{in,out,err}), needed for checkpoint and restore + // Container's standard descriptors (std{in,out,err}), needed for checkpoint and restore. ExternalDescriptors []string `json:"external_descriptors,omitempty"` - // Intel RDT "resource control" filesystem path - IntelRdtPath string `json:"intel_rdt_path"` + // Intel RDT "resource control" filesystem path. + IntelRdtPath string `json:"intel_rdt_path,omitempty"` + + // Path of the container specific monitoring group in resctrl filesystem. + // Empty if the container does not have aindividual dedicated monitoring + // group. + IntelRdtMonPath string `json:"intel_rdt_mon_path,omitempty"` } // ID returns the container's unique ID @@ -290,7 +294,11 @@ func handleFifoResult(result openResult) error { if err := readFromExecFifo(f); err != nil { return err } - return os.Remove(f.Name()) + err := os.Remove(f.Name()) + if err == nil || errors.Is(err, os.ErrNotExist) { + return nil + } + return err } type openResult struct { @@ -330,8 +338,6 @@ func (c *Container) start(process *Process) (retErr error) { // We do not need the cloned binaries once the process is spawned. defer process.closeClonedExes() - logsDone := parent.forwardChildLogs() - // Before starting "runc init", mark all non-stdio open files as O_CLOEXEC // to make sure we don't leak any files into "runc init". Any files to be // passed to "runc init" through ExtraFiles will get dup2'd by the Go @@ -341,21 +347,28 @@ func (c *Container) start(process *Process) (retErr error) { if err := utils.CloseExecFrom(3); err != nil { return fmt.Errorf("unable to mark non-stdio fds as cloexec: %w", err) } - if err := parent.start(); err != nil { - return fmt.Errorf("unable to start container process: %w", err) - } - if logsDone != nil { + if logsDone := parent.forwardChildLogs(); logsDone != nil { defer func() { // Wait for log forwarder to finish. This depends on // runc init closing the _LIBCONTAINER_LOGPIPE log fd. err := <-logsDone - if err != nil && retErr == nil { - retErr = fmt.Errorf("unable to forward init logs: %w", err) + if err != nil { + // runc init errors are important; make sure retErr has them. + err = fmt.Errorf("runc init error(s): %w", err) + if retErr != nil { + retErr = fmt.Errorf("%w; %w", retErr, err) + } else { + retErr = err + } } }() } + if err := parent.start(); err != nil { + return fmt.Errorf("unable to start container process: %w", err) + } + if process.Init { c.fifo.Close() if c.config.HasHook(configs.Poststart) { @@ -515,6 +528,12 @@ func (c *Container) newParentProcess(p *Process) (parentProcess, error) { } cmd := exec.Command(exePath, "init") + // Theoretically, exec.Command can set cmd.Err. Practically, this + // should never happen (Linux, Go <= 1.26, exePath is absolute), + // but in the unlikely case it just did, let's fail early. + if cmd.Err != nil { + return nil, fmt.Errorf("exec.Command: %w", cmd.Err) + } cmd.Args[0] = os.Args[0] cmd.Stdin = p.Stdin cmd.Stdout = p.Stdout @@ -651,40 +670,10 @@ func (c *Container) newSetnsProcess(p *Process, cmd *exec.Cmd, comm *processComm bootstrapData: data, container: c, }, - cgroupPaths: state.CgroupPaths, rootlessCgroups: c.config.RootlessCgroups, intelRdtPath: state.IntelRdtPath, initProcessPid: state.InitProcessPid, } - 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 { - subPath := path.Join(proc.cgroupPaths[k], add) - if !strings.HasPrefix(subPath, proc.cgroupPaths[k]) { - return nil, fmt.Errorf("%s is not a sub cgroup path", add) - } - proc.cgroupPaths[k] = subPath - } - // 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 { - subPath := path.Join(val, add) - if !strings.HasPrefix(subPath, val) { - return nil, fmt.Errorf("%s is not a sub cgroup path", add) - } - proc.cgroupPaths[ctrl] = subPath - } else { - return nil, fmt.Errorf("unknown controller %s in SubCgroupPaths", ctrl) - } - } - } - } return proc, nil } @@ -938,8 +927,10 @@ func (c *Container) currentState() *State { } intelRdtPath := "" + intelRdtMonPath := "" if c.intelRdtManager != nil { intelRdtPath = c.intelRdtManager.GetPath() + intelRdtMonPath = c.intelRdtManager.GetMonPath() } state := &State{ BaseState: BaseState{ @@ -952,6 +943,7 @@ func (c *Container) currentState() *State { Rootless: c.config.RootlessEUID && c.config.RootlessCgroups, CgroupPaths: c.cgroupManager.GetPaths(), IntelRdtPath: intelRdtPath, + IntelRdtMonPath: intelRdtMonPath, NamespacePaths: make(map[configs.NamespaceType]string), ExternalDescriptors: externalDescriptors, } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/criu_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/criu_linux.go index 53a0202ad4..322e439578 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/criu_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/criu_linux.go @@ -16,14 +16,15 @@ import ( "strings" "time" - "github.com/checkpoint-restore/go-criu/v6" - criurpc "github.com/checkpoint-restore/go-criu/v6/rpc" + "github.com/checkpoint-restore/go-criu/v7" + criurpc "github.com/checkpoint-restore/go-criu/v7/rpc" securejoin "github.com/cyphar/filepath-securejoin" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" "google.golang.org/protobuf/proto" "github.com/opencontainers/cgroups" + "github.com/opencontainers/runc/internal/pathrs" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/utils" ) @@ -78,7 +79,7 @@ func (c *Container) checkCriuFeatures(criuOpts *CriuOpts, criuFeat *criurpc.Criu return nil } -func compareCriuVersion(criuVersion int, minVersion int) error { +func compareCriuVersion(criuVersion, minVersion int) error { // simple function to perform the actual version compare if criuVersion < minVersion { return fmt.Errorf("CRIU version %d must be %d or higher", criuVersion, minVersion) @@ -123,7 +124,7 @@ func (c *Container) addMaskPaths(req *criurpc.CriuReq) error { for _, path := range c.config.MaskPaths { fi, err := os.Stat(fmt.Sprintf("/proc/%d/root/%s", c.initProcess.pid(), path)) if err != nil { - if os.IsNotExist(err) { + if errors.Is(err, os.ErrNotExist) { continue } return err @@ -304,7 +305,7 @@ func (c *Container) Checkpoint(criuOpts *CriuOpts) error { // Since a container can be C/R'ed multiple times, // the checkpoint directory may already exist. - if err := os.Mkdir(criuOpts.ImagesDirectory, 0o700); err != nil && !os.IsExist(err) { + if err := os.Mkdir(criuOpts.ImagesDirectory, 0o700); err != nil && !errors.Is(err, os.ErrExist) { return err } @@ -339,7 +340,7 @@ func (c *Container) Checkpoint(criuOpts *CriuOpts) error { // 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) { + if err := os.Mkdir(criuOpts.WorkDirectory, 0o700); err != nil && !errors.Is(err, os.ErrExist) { return err } workDir, err := os.Open(criuOpts.WorkDirectory) @@ -542,16 +543,22 @@ func (c *Container) prepareCriuRestoreMounts(mounts []*configs.Mount) error { umounts := []string{} defer func() { 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 { + mntFile, err := pathrs.OpenInRoot(c.config.Rootfs, u, unix.O_PATH) + if err != nil { + logrus.Warnf("Error during cleanup unmounting %s: open handle: %v", u, err) + continue + } + _ = utils.WithProcfdFile(mntFile, func(procfd string) error { + if err := unix.Unmount(procfd, unix.MNT_DETACH); err != nil { + if err != unix.EINVAL { // 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) + logrus.Warnf("Error during cleanup unmounting of %s (%s): %v", procfd, u, err) } } return nil }) + _ = mntFile.Close() } }() // Now go through all mounts and create the required mountpoints. @@ -698,7 +705,7 @@ func (c *Container) Restore(process *Process, criuOpts *CriuOpts) error { 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) { + if err := os.Mkdir(criuOpts.WorkDirectory, 0o700); err != nil && !errors.Is(err, os.ErrExist) { return err } workDir, err := os.Open(criuOpts.WorkDirectory) @@ -819,7 +826,7 @@ func logCriuErrors(dir, file string) { logrus.Warn("...") } // Print the last lines. - for add := 0; add < max; add++ { + for add := range max { i := (idx + add) % max s := lines[i] actLineNo := lineNo + add - max + 1 @@ -948,7 +955,7 @@ func (c *Container) criuSwrk(process *Process, req *criurpc.CriuReq, opts *CriuO val := reflect.ValueOf(req.GetOpts()) v := reflect.Indirect(val) - for i := 0; i < v.NumField(); i++ { + for i := range v.NumField() { st := v.Type() name := st.Field(i).Name if 'A' <= name[0] && name[0] <= 'Z' { @@ -1149,7 +1156,7 @@ func (c *Container) criuNotifications(resp *criurpc.CriuResp, process *Process, return err } if err := os.Remove(filepath.Join(c.stateDir, "checkpoint")); err != nil { - if !os.IsNotExist(err) { + if !errors.Is(err, os.ErrNotExist) { logrus.Error(err) } } 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 c533eb1c67..409e58e963 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go @@ -98,7 +98,7 @@ func GetDevices(path string) ([]*Device, error) { if errors.Is(err, ErrNotADevice) { continue } - if os.IsNotExist(err) { + if errors.Is(err, os.ErrNotExist) { continue } return nil, err diff --git a/vendor/github.com/opencontainers/runc/libcontainer/exeseal/cloned_binary_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/exeseal/cloned_binary_linux.go index 146408f20d..1c5c60872f 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/exeseal/cloned_binary_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/exeseal/cloned_binary_linux.go @@ -49,7 +49,7 @@ func sealMemfd(f **os.File) error { // to work on older kernels. fd := (*f).Fd() - // Skip F_SEAL_FUTURE_WRITE, it is not needed because we alreadu use the + // Skip F_SEAL_FUTURE_WRITE, it is not needed because we already use the // stronger F_SEAL_WRITE (and is buggy on Linux <5.5 -- see kernel commit // 05d351102dbe and ). diff --git a/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go index 94b55eaa85..f1c223e981 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go @@ -11,10 +11,10 @@ import ( "github.com/opencontainers/cgroups" "github.com/opencontainers/cgroups/manager" + "github.com/opencontainers/runc/internal/pathrs" "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" ) const ( @@ -51,7 +51,7 @@ func Create(root, id string, config *configs.Config) (*Container, error) { } if _, err := os.Stat(stateDir); err == nil { return nil, ErrExist - } else if !os.IsNotExist(err) { + } else if !errors.Is(err, os.ErrNotExist) { return nil, err } @@ -154,7 +154,7 @@ func loadState(root string) (*State, error) { } f, err := os.Open(stateFilePath) if err != nil { - if os.IsNotExist(err) { + if errors.Is(err, os.ErrNotExist) { return nil, ErrNotExist } return nil, err @@ -195,7 +195,7 @@ func validateID(id string) error { } // Allowed characters: 0-9 A-Z a-z _ + - . - for i := 0; i < len(id); i++ { + for i := range len(id) { c := id[i] switch { case c >= 'a' && c <= 'z': @@ -211,7 +211,7 @@ func validateID(id string) error { } - if string(os.PathSeparator)+id != utils.CleanPath(string(os.PathSeparator)+id) { + if string(os.PathSeparator)+id != pathrs.LexicallyCleanPath(string(os.PathSeparator)+id) { return ErrInvalidID } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go index 4052920049..632d7c3491 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go @@ -21,6 +21,7 @@ import ( "golang.org/x/sys/unix" "github.com/opencontainers/cgroups" + "github.com/opencontainers/runc/internal/linux" "github.com/opencontainers/runc/internal/pathrs" "github.com/opencontainers/runc/libcontainer/capabilities" "github.com/opencontainers/runc/libcontainer/configs" @@ -174,6 +175,7 @@ func startInitialization() (retErr error) { return fmt.Errorf("unable to convert _LIBCONTAINER_LOGPIPE: %w", err) } logPipe := os.NewFile(uintptr(logFd), "logpipe") + defer logPipe.Close() logrus.SetOutput(logPipe) logrus.SetFormatter(new(logrus.JSONFormatter)) @@ -189,6 +191,7 @@ func startInitialization() (retErr error) { return fmt.Errorf("unable to convert _LIBCONTAINER_FIFOFD: %w", err) } fifoFile = os.NewFile(uintptr(fifoFd), "initfifo") + defer fifoFile.Close() } var consoleSocket *os.File @@ -276,10 +279,10 @@ func verifyCwd() error { // details, and CVE-2024-21626 for the security issue that motivated this // check. // - // We have to use unix.Getwd() here because os.Getwd() has a workaround for + // We do not use os.Getwd() here because it has a workaround for // $PWD which involves doing stat(.), which can fail if the current // directory is inaccessible to the container process. - if wd, err := unix.Getwd(); errors.Is(err, unix.ENOENT) { + if wd, err := linux.Getwd(); errors.Is(err, unix.ENOENT) { return errors.New("current working directory is outside of container mount namespace root -- possible container breakout detected") } else if err != nil { return fmt.Errorf("failed to verify if current working directory is safe: %w", err) @@ -311,7 +314,7 @@ func finalizeNamespace(config *initConfig) error { switch { case err == nil: doChdir = false - case os.IsPermission(err): + case errors.Is(err, os.ErrPermission): // If we hit an EPERM, we should attempt again after setting up user. // This will allow us to successfully chdir if the container user has access // to the directory, but the user running runc does not. @@ -477,7 +480,7 @@ func setupUser(config *initConfig) error { setgroups, err = io.ReadAll(setgroupsFile) _ = setgroupsFile.Close() } - if err != nil && !os.IsNotExist(err) { + if err != nil && !errors.Is(err, os.ErrNotExist) { return err } @@ -531,16 +534,17 @@ func fixStdioPermissions(uid int) error { // that users expect to be able to actually use their console. Without // this code, you couldn't effectively run as a non-root user inside a // container and also have a console set up. - if err := file.Chown(uid, int(s.Gid)); err != nil { - // If we've hit an EINVAL then s.Gid isn't mapped in the user - // namespace. If we've hit an EPERM then the inode's current owner + if err := file.Chown(uid, -1); err != nil { + // If we've hit an EPERM then the inode's current owner // is not mapped in our user namespace (in particular, // privileged_wrt_inode_uidgid() has failed). Read-only // /dev can result in EROFS error. In any case, it's // better for us to just not touch the stdio rather // than bail at this point. - - if errors.Is(err, unix.EINVAL) || errors.Is(err, unix.EPERM) || errors.Is(err, unix.EROFS) { + // EINVAL should never happen, as it would mean the uid + // is not mapped, we expect this function to be called + // with a mapped uid. + if errors.Is(err, unix.EPERM) || errors.Is(err, unix.EROFS) { continue } return err @@ -662,6 +666,14 @@ func setupIOPriority(config *initConfig) error { return nil } +func setupMemoryPolicy(config *configs.Config) error { + mpol := config.MemoryPolicy + if mpol == nil { + return nil + } + return linux.SetMempolicy(mpol.Mode|mpol.Flags, config.MemoryPolicy.Nodes) +} + func setupPersonality(config *configs.Config) error { return system.SetLinuxPersonality(config.Personality.Domain) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go index 7d4b4d38a6..3dcd71b7e0 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go @@ -10,6 +10,7 @@ import ( "strings" "sync" + securejoin "github.com/cyphar/filepath-securejoin" "github.com/moby/sys/mountinfo" "golang.org/x/sys/unix" @@ -155,20 +156,35 @@ type Manager struct { // NewManager returns a new instance of Manager, or nil if the Intel RDT // functionality is not specified in the config, available from hardware or // enabled in the kernel. -func NewManager(config *configs.Config, id string, path string) *Manager { +func NewManager(config *configs.Config, id, path string) *Manager { if config.IntelRdt == nil { return nil } - if _, err := Root(); err != nil { - // Intel RDT is not available. + + rootPath, err := Root() + if err != nil { return nil } + // NOTE: Should we check if the path provided as arg matches the path + // constructed below? If not, we're screwed as we've effectively lost resctrl + // control of the container (e.g. because the resctrl fs was unmounted or + // remounted elsewhere). All operations are deemed to fail. + if path == "" { + clos := id + if config.IntelRdt.ClosID != "" { + clos = config.IntelRdt.ClosID + } + if path, err = securejoin.SecureJoin(rootPath, clos); err != nil { + return nil + } + } + return newManager(config, id, path) } // newManager is the same as NewManager, except it does not check if the feature // is actually available. Used by unit tests that mock intelrdt paths. -func newManager(config *configs.Config, id string, path string) *Manager { +func newManager(config *configs.Config, id, path string) *Manager { return &Manager{ config: config, id: id, @@ -310,16 +326,6 @@ func getIntelRdtParamString(path, file string) (string, error) { return string(bytes.TrimSpace(contents)), nil } -func writeFile(dir, file, data string) error { - if dir == "" { - return fmt.Errorf("no such directory for %s", file) - } - 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 -} - // Get the read-only L3 cache information func getL3CacheInfo() (*L3CacheInfo, error) { l3CacheInfo := &L3CacheInfo{} @@ -416,6 +422,12 @@ func WriteIntelRdtTasks(dir string, pid int) error { return nil } +// IsEnabled checks if Intel RDT is enabled. +func IsEnabled() bool { + fsroot, err := Root() + return err == nil && fsroot != "" +} + // IsCATEnabled checks if Intel RDT/CAT is enabled. func IsCATEnabled() bool { featuresInit() @@ -428,21 +440,6 @@ func IsMBAEnabled() bool { return mbaEnabled } -// Get the path of the clos group in "resource control" filesystem that the container belongs to -func (m *Manager) getIntelRdtPath() (string, error) { - rootPath, err := Root() - if err != nil { - return "", err - } - - clos := m.id - if m.config.IntelRdt != nil && m.config.IntelRdt.ClosID != "" { - clos = m.config.IntelRdt.ClosID - } - - return filepath.Join(rootPath, clos), nil -} - // Apply applies Intel RDT configuration to the process with the specified pid. func (m *Manager) Apply(pid int) (err error) { // If intelRdt is not specified in config, we do nothing @@ -450,23 +447,20 @@ func (m *Manager) Apply(pid int) (err error) { return nil } - path, err := m.getIntelRdtPath() - if err != nil { - return err - } + path := m.GetPath() m.mu.Lock() defer m.mu.Unlock() - if m.config.IntelRdt.ClosID != "" && m.config.IntelRdt.L3CacheSchema == "" && m.config.IntelRdt.MemBwSchema == "" { + if m.config.IntelRdt.ClosID != "" && m.config.IntelRdt.L3CacheSchema == "" && m.config.IntelRdt.MemBwSchema == "" && len(m.config.IntelRdt.Schemata) == 0 { // 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) + return fmt.Errorf("clos dir not accessible (must be pre-created when schemata, l3CacheSchema and memBwSchema are empty): %w", err) } } - if err := os.MkdirAll(path, 0o755); err != nil { + if err := os.Mkdir(path, 0o755); err != nil && !errors.Is(err, os.ErrExist) { return newLastCmdError(err) } @@ -474,22 +468,41 @@ func (m *Manager) Apply(pid int) (err error) { return newLastCmdError(err) } + // Create MON group + if monPath := m.GetMonPath(); monPath != "" { + if err := os.Mkdir(monPath, 0o755); err != nil && !errors.Is(err, os.ErrExist) { + return newLastCmdError(err) + } + if err := WriteIntelRdtTasks(monPath, pid); err != nil { + return newLastCmdError(err) + } + } + m.path = path return nil } // Destroy destroys the Intel RDT container-specific container_id group. func (m *Manager) Destroy() error { + if m.config.IntelRdt == nil { + return nil + } // 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 == "" { + if m.config.IntelRdt.ClosID == "" { m.mu.Lock() defer m.mu.Unlock() - if err := os.RemoveAll(m.GetPath()); err != nil { + if err := os.Remove(m.GetPath()); err != nil && !errors.Is(err, os.ErrNotExist) { return err } m.path = "" + } else if monPath := m.GetMonPath(); monPath != "" { + // If ClosID is not specified the possible monintoring group was + // removed with the CLOS above. + if err := os.Remove(monPath); err != nil && !errors.Is(err, os.ErrNotExist) { + return err + } } return nil } @@ -497,12 +510,24 @@ func (m *Manager) Destroy() error { // GetPath returns Intel RDT path to save in a state file and to be able to // restore the object later. func (m *Manager) GetPath() string { - if m.path == "" { - m.path, _ = m.getIntelRdtPath() - } return m.path } +// GetMonPath returns path of the monitoring group of the container. Returns an +// empty string if the container does not have a individual dedicated +// monitoring group. +func (m *Manager) GetMonPath() string { + if !m.config.IntelRdt.EnableMonitoring { + return "" + } + closPath := m.GetPath() + if closPath == "" { + return "" + } + + return filepath.Join(closPath, "mon_groups", m.id) +} + // GetStats returns statistics for Intel RDT. func (m *Manager) GetStats() (*Stats, error) { // If intelRdt is not specified in config @@ -533,6 +558,8 @@ func (m *Manager) GetStats() (*Stats, error) { } schemaStrings := strings.Split(tmpStrings, "\n") + stats.Schemata = schemaStrings + if IsCATEnabled() { // The read-only L3 cache information l3CacheInfo, err := getL3CacheInfo() @@ -580,7 +607,16 @@ func (m *Manager) GetStats() (*Stats, error) { } if IsMBMEnabled() || IsCMTEnabled() { - err = getMonitoringStats(containerPath, stats) + monPath := m.GetMonPath() + if monPath == "" { + // NOTE: If per-container monitoring is not enabled, the monitoring + // data we get here might have little to do with this container as + // there might be anything from this single container to the half + // of the system assigned in the group. Should consider not + // exposing stats in this case(?) + monPath = containerPath + } + err = getMonitoringStats(monPath, stats) if err != nil { return nil, err } @@ -636,35 +672,24 @@ func (m *Manager) Set(container *configs.Config) error { // For example, on a two-socket machine, the schema line could be // "MB:0=5000;1=7000" which means 5000 MBps memory bandwidth limit on // socket 0 and 7000 MBps memory bandwidth limit on socket 1. - if container.IntelRdt != nil { - path := m.GetPath() - l3CacheSchema := container.IntelRdt.L3CacheSchema - memBwSchema := container.IntelRdt.MemBwSchema - + if r := container.IntelRdt; r != nil { // 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 err - } - } - - // Write only L3 cache schema string to schemata file - if l3CacheSchema != "" && memBwSchema == "" { - if err := writeFile(path, "schemata", l3CacheSchema); err != nil { - return err + var schemata strings.Builder + for _, s := range append([]string{r.L3CacheSchema, r.MemBwSchema}, r.Schemata...) { + if s != "" { + schemata.WriteString(s) + schemata.WriteString("\n") } } - // Write only memory bandwidth schema string to schemata file - if l3CacheSchema == "" && memBwSchema != "" { - if err := writeFile(path, "schemata", memBwSchema); err != nil { - return err + if schemata.Len() > 0 { + path := filepath.Join(m.GetPath(), "schemata") + if err := os.WriteFile(path, []byte(schemata.String()), 0o600); err != nil { + return newLastCmdError(fmt.Errorf("intelrdt: unable to write %q: %w", schemata.String(), err)) } } } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go index a5eb2541e8..d725af7731 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go @@ -45,6 +45,9 @@ type Stats struct { // The memory bandwidth schema in 'container_id' group MemBwSchema string `json:"mem_bw_schema,omitempty"` + // Schemata contains the full schemata of the ClosID (resctrl group) that the container is assigned to. + Schemata []string `json:"schemata,omitempty"` + // The memory bandwidth monitoring statistics from NUMA nodes in 'container_id' group MBMStats *[]MBMNumaNodeStats `json:"mbm_stats,omitempty"` diff --git a/vendor/github.com/opencontainers/runc/libcontainer/internal/userns/userns_maps_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/internal/userns/userns_maps_linux.go index 7a8c2b023b..c2fb8ca719 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/internal/userns/userns_maps_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/internal/userns/userns_maps_linux.go @@ -39,7 +39,7 @@ func parseIdmapData(data []byte) (ms []configs.IDMap, err error) { // Do something equivalent to nsenter --user= cat , but more // efficiently. Returns the contents of the requested file from within the user // namespace. -func spawnUserNamespaceCat(nsPath string, path string) ([]byte, error) { +func spawnUserNamespaceCat(nsPath, path string) ([]byte, error) { rdr, wtr, err := os.Pipe() if err != nil { return nil, fmt.Errorf("create pipe for userns spawn failed: %w", err) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/internal/userns/usernsfd_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/internal/userns/usernsfd_linux.go index 00b5cd0a21..a1151a3fb3 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/internal/userns/usernsfd_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/internal/userns/usernsfd_linux.go @@ -61,7 +61,7 @@ type Handles struct { // Release all resources associated with this Handle. All existing files // returned from Get() will continue to work even after calling Release(). The -// same Handles can be re-used after calling Release(). +// same Handles can be reused after calling Release(). func (hs *Handles) Release() { hs.m.Lock() defer hs.m.Unlock() diff --git a/vendor/github.com/opencontainers/runc/libcontainer/logs/logs.go b/vendor/github.com/opencontainers/runc/libcontainer/logs/logs.go index 95deb0d6ca..8594e1fec5 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/logs/logs.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/logs/logs.go @@ -2,12 +2,16 @@ package logs import ( "bufio" + "bytes" "encoding/json" + "errors" "io" "github.com/sirupsen/logrus" ) +var fatalsSep = []byte("; ") + func ForwardLogs(logPipe io.ReadCloser) chan error { done := make(chan error, 1) s := bufio.NewScanner(logPipe) @@ -23,24 +27,33 @@ func ForwardLogs(logPipe io.ReadCloser) chan error { } go func() { + fatals := []byte{} for s.Scan() { - processEntry(s.Bytes(), logger) + fatals = processEntry(s.Bytes(), logger, fatals) + } + if err := s.Err(); err != nil { + logrus.Errorf("error reading from log source: %v", err) } if err := logPipe.Close(); err != nil { logrus.Errorf("error closing log source: %v", err) } - // The only error we want to return is when reading from - // logPipe has failed. - done <- s.Err() + // The only error we return is fatal messages from runc init. + var err error + if len(fatals) > 0 { + err = errors.New(string(bytes.TrimSuffix(fatals, fatalsSep))) + } + done <- err close(done) }() return done } -func processEntry(text []byte, logger *logrus.Logger) { +// processEntry parses the error and either logs it via the standard logger or, +// if this is a fatal error, appends its text to fatals. +func processEntry(text []byte, logger *logrus.Logger, fatals []byte) []byte { if len(text) == 0 { - return + return fatals } var jl struct { @@ -49,8 +62,14 @@ func processEntry(text []byte, logger *logrus.Logger) { } if err := json.Unmarshal(text, &jl); err != nil { logrus.Errorf("failed to decode %q to json: %v", text, err) - return + return fatals } - logger.Log(jl.Level, jl.Msg) + if jl.Level == logrus.FatalLevel { + fatals = append(fatals, jl.Msg...) + fatals = append(fatals, fatalsSep...) + } else { + logger.Log(jl.Level, jl.Msg) + } + return fatals } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/mount_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/mount_linux.go index 9d4b5dcef5..82ef0fdf1b 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/mount_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/mount_linux.go @@ -110,7 +110,7 @@ func (e *mountError) Error() string { if e.source != "" { out += "src=" + e.source + ", " - if e.srcFile != nil { + if e.srcFile != nil && e.srcFile.file != nil { out += "srcType=" + string(e.srcFile.Type) + ", " out += "srcFd=" + strconv.Itoa(int(e.srcFile.file.Fd())) + ", " } @@ -250,7 +250,7 @@ func syscallMode(i fs.FileMode) (o uint32) { // process will need to do an old-fashioned mount(2) themselves. // // This helper is only intended to be used by goCreateMountSources. -func mountFd(nsHandles *userns.Handles, m *configs.Mount) (*mountSource, error) { +func mountFd(nsHandles *userns.Handles, m *configs.Mount) (_ *mountSource, retErr error) { if !m.IsBind() { return nil, errors.New("new mount api: only bind-mounts are supported") } @@ -261,6 +261,11 @@ func mountFd(nsHandles *userns.Handles, m *configs.Mount) (*mountSource, error) var mountFile *os.File var sourceType mountSourceType + defer func() { + if retErr != nil && mountFile != nil { + mountFile.Close() + } + }() // Ideally, we would use OPEN_TREE_CLONE for everything, because we can // be sure that the file descriptor cannot be used to escape outside of diff --git a/vendor/github.com/opencontainers/runc/libcontainer/network_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/network_linux.go index 8915548b3b..35bfe747db 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/network_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/network_linux.go @@ -2,6 +2,7 @@ package libcontainer import ( "bytes" + "errors" "fmt" "os" "path/filepath" @@ -9,7 +10,12 @@ import ( "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/types" + "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" + "github.com/vishvananda/netlink/nl" + "github.com/vishvananda/netns" + + "golang.org/x/sys/unix" ) var strategies = map[string]networkStrategy{ @@ -98,3 +104,129 @@ func (l *loopback) attach(n *configs.Network) (err error) { func (l *loopback) detach(n *configs.Network) (err error) { return nil } + +// devChangeNetNamespace allows to move a device given by name to a network namespace given by nsPath +// and optionally change the device name. +// The device name will be kept the same if device.Name is the zero value. +// This function ensures that the move and rename operations occur atomically. +// It preserves existing interface attributes, including global IP addresses. +func devChangeNetNamespace(name, nsPath string, device configs.LinuxNetDevice) error { + logrus.Debugf("attaching network device %s with attrs %+v to network namespace %s", name, device, nsPath) + link, err := netlink.LinkByName(name) + // recover same behavior on vishvananda/netlink@1.2.1 and do not fail when the kernel returns NLM_F_DUMP_INTR. + if err != nil && !errors.Is(err, netlink.ErrDumpInterrupted) { + return fmt.Errorf("link not found for interface %s on runtime namespace: %w", name, err) + } + + // Set the interface link state to DOWN before modifying attributes like namespace or name. + // This prevents potential conflicts or disruptions on the host network during the transition, + // particularly if other host components depend on this specific interface or its properties. + err = netlink.LinkSetDown(link) + if err != nil { + return fmt.Errorf("fail to set link down: %w", err) + } + + // Get the existing IP addresses on the interface. + addresses, err := netlink.AddrList(link, netlink.FAMILY_ALL) + // recover same behavior on vishvananda/netlink@1.2.1 and do not fail when the kernel returns NLM_F_DUMP_INTR. + if err != nil && !errors.Is(err, netlink.ErrDumpInterrupted) { + return fmt.Errorf("fail to get ip addresses: %w", err) + } + + // Do interface rename and namespace change in the same operation to avoid + // possible conflicts with the interface name. + // NLM_F_REQUEST: "It must be set on all request messages." + // NLM_F_ACK: "Request for an acknowledgment on success." + // netlink(7) man page: https://man7.org/linux/man-pages/man7/netlink.7.html + flags := unix.NLM_F_REQUEST | unix.NLM_F_ACK + req := nl.NewNetlinkRequest(unix.RTM_NEWLINK, flags) + + // Get a netlink socket in current namespace + nlSock, err := nl.GetNetlinkSocketAt(netns.None(), netns.None(), unix.NETLINK_ROUTE) + if err != nil { + return fmt.Errorf("could not get network namespace handle: %w", err) + } + defer nlSock.Close() + + req.Sockets = map[int]*nl.SocketHandle{ + unix.NETLINK_ROUTE: {Socket: nlSock}, + } + + // Set the interface index. + msg := nl.NewIfInfomsg(unix.AF_UNSPEC) + msg.Index = int32(link.Attrs().Index) + req.AddData(msg) + + // Set the interface name, also rename if requested. + newName := name + if device.Name != "" { + newName = device.Name + } + nameData := nl.NewRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(newName)) + req.AddData(nameData) + + // Get the new network namespace. + ns, err := netns.GetFromPath(nsPath) + if err != nil { + return fmt.Errorf("could not get network namespace from path %s for network device %s : %w", nsPath, name, err) + } + defer ns.Close() + + val := nl.Uint32Attr(uint32(ns)) + attr := nl.NewRtAttr(unix.IFLA_NET_NS_FD, val) + req.AddData(attr) + + _, err = req.Execute(unix.NETLINK_ROUTE, 0) + // recover same behavior on vishvananda/netlink@1.2.1 and do not fail when the kernel returns NLM_F_DUMP_INTR. + if err != nil && !errors.Is(err, netlink.ErrDumpInterrupted) { + return fmt.Errorf("fail to move network device %s to network namespace %s: %w", name, nsPath, err) + } + + // To avoid us the husle with goroutines when joining a netns, + // we let the library create the socket in the namespace for us. + nhNs, err := netlink.NewHandleAt(ns) + if err != nil { + return err + } + defer nhNs.Close() + + nsLink, err := nhNs.LinkByName(newName) + // recover same behavior on vishvananda/netlink@1.2.1 and do not fail when the kernel returns NLM_F_DUMP_INTR. + if err != nil && !errors.Is(err, netlink.ErrDumpInterrupted) { + return fmt.Errorf("link not found for interface %s on namespace %s : %w", newName, nsPath, err) + } + + // Re-add the original IP addresses to the interface in the new namespace. + // The kernel removes IP addresses when an interface is moved between network namespaces. + for _, address := range addresses { + logrus.Debugf("processing address %s from network device %s", address.String(), name) + // Only move permanent IP addresses configured by the user, dynamic addresses are excluded because + // their validity may rely on the original network namespace's context and they may have limited + // lifetimes and are not guaranteed to be available in a new namespace. + // Ref: https://www.ietf.org/rfc/rfc3549.txt + if address.Flags&unix.IFA_F_PERMANENT == 0 { + logrus.Debugf("skipping address %s from network device %s: not a permanent address", address.String(), name) + continue + } + // Only move IP addresses with global scope because those are not host-specific, auto-configured, + // or have limited network scope, making them unsuitable inside the container namespace. + // Ref: https://www.ietf.org/rfc/rfc3549.txt + if address.Scope != unix.RT_SCOPE_UNIVERSE { + logrus.Debugf("skipping address %s from network device %s: not an address with global scope", address.String(), name) + continue + } + // Remove the interface attribute of the original address + // to avoid issues when the interface is renamed. + err = nhNs.AddrAdd(nsLink, &netlink.Addr{IPNet: address.IPNet}) + if err != nil { + return fmt.Errorf("fail to set up address %s on namespace %s: %w", address.String(), nsPath, err) + } + } + + err = nhNs.LinkSetUp(nsLink) + if err != nil { + return fmt.Errorf("fail to set up interface %s on namespace %s: %w", nsLink.Attrs().Name, nsPath, err) + } + + return nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go index a8762842e8..af2f43ebab 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go @@ -17,7 +17,7 @@ const ( CriticalPressure ) -func registerMemoryEvent(cgDir string, evName string, arg string) (<-chan struct{}, error) { +func registerMemoryEvent(cgDir, evName, arg string) (<-chan struct{}, error) { evFile, err := os.Open(filepath.Join(cgDir, evName)) if err != nil { return nil, err @@ -51,7 +51,7 @@ func registerMemoryEvent(cgDir string, evName string, arg string) (<-chan struct } // When a cgroup is destroyed, an event is sent to eventfd. // So if the control path is gone, return instead of notifying. - if _, err := os.Lstat(eventControlPath); os.IsNotExist(err) { + if _, err := os.Lstat(eventControlPath); errors.Is(err, os.ErrNotExist) { return } ch <- struct{}{} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go index cc50f278ea..d9c441ec58 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go @@ -1,26 +1,33 @@ package libcontainer import ( + "bytes" "context" "encoding/json" "errors" "fmt" "io" + "maps" "net" "os" "os/exec" + "path" "path/filepath" "runtime" "strconv" + "strings" "sync" + "syscall" "time" - "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/cgroups" "github.com/opencontainers/cgroups/fs2" + "github.com/opencontainers/runc/internal/linux" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/intelrdt" "github.com/opencontainers/runc/libcontainer/internal/userns" @@ -63,7 +70,7 @@ type processComm struct { logPipeChild *os.File } -func newProcessComm() (*processComm, error) { +func newProcessComm() (_ *processComm, retErr error) { var ( comm processComm err error @@ -72,10 +79,24 @@ func newProcessComm() (*processComm, error) { if err != nil { return nil, fmt.Errorf("unable to create init pipe: %w", err) } + defer func() { + if retErr != nil { + comm.initSockParent.Close() + comm.initSockChild.Close() + } + }() + comm.syncSockParent, comm.syncSockChild, err = newSyncSockpair("sync") if err != nil { return nil, fmt.Errorf("unable to create sync pipe: %w", err) } + defer func() { + if retErr != nil { + comm.syncSockParent.Close() + comm.syncSockChild.Close() + } + }() + comm.logPipeParent, comm.logPipeChild, err = os.Pipe() if err != nil { return nil, fmt.Errorf("unable to create log pipe: %w", err) @@ -116,11 +137,7 @@ func (p *containerProcess) startTime() (uint64, error) { } func (p *containerProcess) signal(sig os.Signal) error { - s, ok := sig.(unix.Signal) - if !ok { - return errors.New("os: unsupported signal type") - } - return unix.Kill(p.pid(), s) + return p.cmd.Process.Signal(sig) } func (p *containerProcess) externalDescriptors() []string { @@ -157,7 +174,6 @@ func (p *containerProcess) wait() (*os.ProcessState, error) { //nolint:unparam type setnsProcess struct { containerProcess - cgroupPaths map[string]string rootlessCgroups bool intelRdtPath string initProcessPid int @@ -165,41 +181,33 @@ type setnsProcess struct { // tryResetCPUAffinity tries to reset the CPU affinity of the process // identified by pid to include all possible CPUs (notwithstanding cgroup -// cpuset restrictions and isolated CPUs). +// cpuset restrictions, isolated CPUs and CPU online status). func tryResetCPUAffinity(pid int) { - // When resetting the CPU affinity, we want to match the configured cgroup - // cpuset (or the default set of all CPUs, if no cpuset is configured) - // rather than some more restrictive affinity we were spawned in (such as - // one that may have been inherited from systemd). The cpuset cgroup used - // to reconfigure the cpumask automatically for joining processes, but - // kcommit da019032819a ("sched: Enforce user requested affinity") changed - // this behaviour in Linux 6.2. + // When resetting the CPU affinity, we want to allow all + // possible CPUs in the system, including those not in + // cpuset.cpus, online or even present (hot-plugged) at call + // time. Using a cpumask any tighter this that may disallow + // using those CPUs if they are added to cpuset.cpus later. // - // Parsing cpuset.cpus.effective is quite inefficient (and looking at - // things like /proc/stat would be wrong for most nested containers), but - // luckily sched_setaffinity(2) will implicitly: + // Note that sched_setaffinity(2) will implicitly: + // + // * Clamp the cpumask so that it matches the number of CPUs + // supported by the kernel. // - // * Clamp the cpumask so that it matches the current number of CPUs on - // the system. // * Mask out any CPUs that are not a member of the target task's - // configured cgroup cpuset. + // configured cgroup cpuset. This is for task's effective affinity, + // without forgetting masked-out CPUs should the cgroup cpuset + // change later. // - // So we can just pass a very large array of set cpumask bits and the - // kernel will silently convert that to the correct value very cheaply. - - // Ideally, we would just set the array to 0xFF...FF. Unfortunately, the - // size depends on the architecture. It is also a private newtype, so we - // can't use (^0) or generics since those require us to be able to name the - // type. However, we can just underflow the zero value instead. - // TODO: Once is merged, switch to that. - cpuset := unix.CPUSet{} - for i := range cpuset { - cpuset[i]-- // underflow to 0xFF..FF - } - if err := unix.SchedSetaffinity(pid, &cpuset); err != nil { - logrus.WithError( - os.NewSyscallError("sched_setaffinity", err), - ).Warnf("resetting the CPU affinity of pid %d failed -- the container process may inherit runc's CPU affinity", pid) + // Therefore, preparing the cpumask, we can avoid reading + // /sys/devices/system/cpu/possible and kernel_max. + // Instead, we use a huge buffer similarly to go 1.25 runtime in + // getCPUCount(). + const maxCPUs = 64 * 1024 + buf := bytes.Repeat([]byte{0xff}, maxCPUs/8) + if err := linux.SchedSetaffinity(pid, buf); err != nil { + logrus.WithError(err).Warnf("resetting the CPU affinity of pid %d failed -- the container process may inherit runc's CPU affinity", pid) + return } } @@ -248,15 +256,212 @@ func (p *setnsProcess) setFinalCPUAffinity() error { return nil } +func (p *setnsProcess) addIntoCgroupV1() error { + if sub, ok := p.process.SubCgroupPaths[""]; ok || len(p.process.SubCgroupPaths) == 0 { + // Either same sub-cgroup for all paths, or no sub-cgroup. + err := p.manager.AddPid(sub, p.pid()) + if err != nil && !p.rootlessCgroups { + return fmt.Errorf("error adding pid %d to cgroups: %w", p.pid(), err) + } + return nil + } + + // Per-controller sub-cgroup paths. Not supported by AddPid (or systemd), + // so we have to calculate and check all sub-cgroup paths, and write + // directly to cgroupfs. + paths := maps.Clone(p.manager.GetPaths()) + for ctrl, sub := range p.process.SubCgroupPaths { + base, ok := paths[ctrl] + if !ok { + return fmt.Errorf("unknown controller %s in SubCgroupPaths", ctrl) + } + cgPath := path.Join(base, sub) + if !strings.HasPrefix(cgPath, base) { + return fmt.Errorf("bad sub cgroup path: %s", sub) + } + paths[ctrl] = cgPath + } + + for _, path := range paths { + if err := cgroups.WriteCgroupProc(path, p.pid()); err != nil && !p.rootlessCgroups { + return fmt.Errorf("error adding pid %d to cgroups: %w", p.pid(), err) + } + } + + return nil +} + +// initProcessCgroupPath returns container init's cgroup path, +// as read from /proc/PID/cgroup. Only works for cgroup v2. +// Returns empty string if the path can not be obtained. +// +// This is used by runc exec in these cases: +// +// 1. On cgroup v2 + nesting + domain controllers, adding to initial cgroup +// may fail with EBUSY (https://github.com/opencontainers/runc/issues/2356); +// +// 2. A container init process with no cgroupns and /sys/fs/cgroup rw access +// may move itself to any other cgroup, and the original cgroup will disappear. +func (p *setnsProcess) initProcessCgroupPath() string { + if p.initProcessPid == 0 || !cgroups.IsCgroup2UnifiedMode() { + return "" + } + + cg, err := cgroups.ParseCgroupFile("/proc/" + strconv.Itoa(p.initProcessPid) + "/cgroup") + if err != nil { + return "" + } + cgroup, ok := cg[""] + if !ok { + return "" + } + + return fs2.UnifiedMountpoint + cgroup +} + +func (p *setnsProcess) addIntoCgroupV2() error { + sub := p.process.SubCgroupPaths[""] + err := p.manager.AddPid(sub, p.pid()) + if err == nil { + return nil + } + + // Failed to join the configured cgroup. Fall back to container init's cgroup + // unless sub-cgroup is explicitly requested. + var path string + if sub != "" { + goto fail + } + path = p.initProcessCgroupPath() + if path == "" { + goto fail + } + logrus.Debugf("adding pid %d to configured cgroup failed (%v), will join container init cgroup %q", p.pid(), err, path) + // NOTE: path is not guaranteed to exist because we didn't pause the container. + err = cgroups.WriteCgroupProc(path, p.pid()) + if err != nil { + goto fail + } + return nil + +fail: + if p.rootlessCgroups { + // Ignore cgroup join errors when rootless. + return nil + } + + return fmt.Errorf("error adding pid %d to cgroups: %w", p.pid(), err) +} + +func (p *setnsProcess) addIntoCgroup() error { + if p.cmd.SysProcAttr.UseCgroupFD { + // We've used cgroupfd successfully, so the process is + // already in the proper cgroup, nothing to do here. + return nil + } + if cgroups.IsCgroup2UnifiedMode() { + return p.addIntoCgroupV2() + } + return p.addIntoCgroupV1() +} + +// prepareCgroupFD sets up p.cmd to use clone3 with CLONE_INTO_CGROUP +// to join cgroup early, in p.cmd.Start. Returns an *os.File which +// must be closed by the caller after p.Cmd.Start return. +func (p *setnsProcess) prepareCgroupFD() (*os.File, error) { + const openFlags = unix.O_PATH | unix.O_DIRECTORY | unix.O_CLOEXEC + + if !cgroups.IsCgroup2UnifiedMode() { + return nil, nil + } + + base := p.manager.Path("") + if base == "" { // No cgroup to join. + return nil, nil + } + sub := "" + if p.process.SubCgroupPaths != nil { + sub = p.process.SubCgroupPaths[""] + } + cgroup := path.Join(base, sub) + if !strings.HasPrefix(cgroup, base) { + return nil, fmt.Errorf("bad sub cgroup path: %s", sub) + } + + fd, err := cgroups.OpenFile(base, sub, openFlags) + if err == nil { + goto success + } + // Failed to open the configured cgroup. Fall back to container init's cgroup + // unless sub-cgroup is explicitly requested. The fallback logic should be + // the same as in addIntoCgroupV2. + if sub != "" { + goto fail + } + cgroup = p.initProcessCgroupPath() + if cgroup == "" { + goto fail + } + logrus.Debugf("failed to open configured cgroup (%v), will open container init cgroup %q", err, cgroup) + // NOTE: path is not guaranteed to exist because we didn't pause the container. + fd, err = cgroups.OpenFile(cgroup, "", openFlags) + if err != nil { + goto fail + } + +success: + logrus.Debugf("using CLONE_INTO_CGROUP %q", cgroup) + if p.cmd.SysProcAttr == nil { + p.cmd.SysProcAttr = &syscall.SysProcAttr{} + } + p.cmd.SysProcAttr.UseCgroupFD = true + p.cmd.SysProcAttr.CgroupFD = int(fd.Fd()) + + return fd, nil + +fail: + // Ignore cgroup join error for rootless. + if p.rootlessCgroups { + return nil, nil + } + return nil, fmt.Errorf("can't open cgroup: %w", err) +} + +// startWithCgroupFD starts a process via clone3 with CLONE_INTO_CGROUP, +// with a fallback if it fails (e.g. not available). +func (p *setnsProcess) startWithCgroupFD() error { + // Close the child side of the pipes. + defer p.comm.closeChild() + + fd, err := p.prepareCgroupFD() + if err != nil { + return err + } + if fd != nil { + defer fd.Close() + } + + cmdCopy := cloneCmd(p.cmd) + err = p.startWithCPUAffinity() + if err != nil && p.cmd.SysProcAttr.UseCgroupFD { + logrus.Debugf("exec with CLONE_INTO_CGROUP failed: %v; retrying without", err) + // SysProcAttr.CgroupFD is never used when UseCgroupFD is unset. + cmdCopy.SysProcAttr.UseCgroupFD = false + // Must not reuse exec.Cmd. + p.cmd = cmdCopy + err = p.startWithCPUAffinity() + } + + return err +} + func (p *setnsProcess) start() (retErr error) { defer p.comm.closeParent() // Get the "before" value of oom kill count. oom, _ := p.manager.OOMKillCount() - err := p.startWithCPUAffinity() - // Close the child-side of the pipes (controlled by child). - p.comm.closeChild() - if err != nil { + + if err := p.startWithCgroupFD(); err != nil { return fmt.Errorf("error starting setns process: %w", err) } @@ -281,28 +486,8 @@ func (p *setnsProcess) start() (retErr error) { if err := p.execSetns(); err != nil { return fmt.Errorf("error executing setns process: %w", err) } - 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() && p.initProcessPid != 0 { - initProcCgroupFile := fmt.Sprintf("/proc/%d/cgroup", p.initProcessPid) - initCg, initCgErr := cgroups.ParseCgroupFile(initProcCgroupFile) - if initCgErr == nil { - if initCgPath, ok := initCg[""]; ok { - initCgDirpath := filepath.Join(fs2.UnifiedMountpoint, initCgPath) - logrus.Debugf("adding pid %d to cgroups %v failed (%v), attempting to join %q (obtained from %s)", - p.pid(), p.cgroupPaths, err, initCg, initCgDirpath) - // NOTE: initCgDirPath is not guaranteed to exist because we didn't pause the container. - err = cgroups.WriteCgroupProc(initCgDirpath, p.pid()) - } - } - } - if err != nil { - return fmt.Errorf("error adding pid %d to cgroups: %w", p.pid(), err) - } - } + if err := p.addIntoCgroup(); err != nil { + return err } // Set final CPU affinity right after the process is moved into container's cgroup. if err := p.setFinalCPUAffinity(); err != nil { @@ -600,20 +785,6 @@ func (p *initProcess) start() (retErr error) { return fmt.Errorf("unable to start init: %w", err) } - // If the runc-create process is terminated due to receiving SIGKILL signal, - // it may lead to the runc-init process leaking due - // to issues like cgroup freezing, - // and it cannot be cleaned up by runc delete/stop - // because the container lacks a state.json file. - // This typically occurs when higher-level - // container runtimes terminate the runc create process due to context cancellation or timeout. - // If the runc-create process terminates due to SIGKILL before - // reaching this line of code, we won't encounter the cgroup freezing issue. - _, err = p.container.updateState(nil) - if err != nil { - return fmt.Errorf("unable to store init state before creating cgroup: %w", err) - } - defer func() { if retErr != nil { // Find out if init is killed by the kernel's OOM killer. @@ -716,6 +887,10 @@ func (p *initProcess) start() (retErr error) { return fmt.Errorf("error creating network interfaces: %w", err) } + if err := p.setupNetworkDevices(); err != nil { + return fmt.Errorf("error creating network interfaces: %w", err) + } + // initConfig.SpecState is only needed to run hooks that are executed // inside a container, i.e. CreateContainer and StartContainer. if p.config.Config.HasHook(configs.CreateContainer, configs.StartContainer) { @@ -903,6 +1078,30 @@ func (p *initProcess) createNetworkInterfaces() error { return nil } +// setupNetworkDevices sets up and initializes any defined network interface inside the container. +func (p *initProcess) setupNetworkDevices() error { + // host network pods does not move network devices. + if !p.config.Config.Namespaces.Contains(configs.NEWNET) { + return nil + } + // the container init process has already joined the provided net namespace, + // so we can use the process's net ns path directly. + nsPath := fmt.Sprintf("/proc/%d/ns/net", p.pid()) + + // If moving any of the network devices fails, we return an error immediately. + // The runtime spec requires that the kernel handles moving back any devices + // that were successfully moved before the failure occurred. + // See: https://github.com/opencontainers/runtime-spec/blob/27cb0027fd92ef81eda1ea3a8153b8337f56d94a/config-linux.md#namespace-lifecycle-and-container-termination + for name, netDevice := range p.config.Config.NetDevices { + err := devChangeNetNamespace(name, nsPath, *netDevice) + if err != nil { + return fmt.Errorf("move netDevice %s to namespace %s: %w", name, nsPath, err) + } + } + + return nil +} + func pidGetFd(pid, srcFd int) (*os.File, error) { pidFd, err := unix.PidfdOpen(pid, 0) if err != nil { @@ -945,7 +1144,7 @@ func getPipeFds(pid int) ([]string, error) { fds := make([]string, 3) dirPath := filepath.Join("/proc", strconv.Itoa(pid), "/fd") - for i := 0; i < 3; i++ { + for i := range 3 { // XXX: This breaks if the path is not a valid symlink (which can // happen in certain particularly unlucky mount namespace setups). f := filepath.Join(dirPath, strconv.Itoa(i)) @@ -954,7 +1153,7 @@ func getPipeFds(pid int) ([]string, error) { // Ignore permission errors, for rootless containers and other // non-dumpable processes. if we can't get the fd for a particular // file, there's not much we can do. - if os.IsPermission(err) { + if errors.Is(err, os.ErrPermission) { continue } return fds, err diff --git a/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go index 8fc5a901dc..7aaa70d109 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go @@ -12,7 +12,6 @@ import ( "syscall" "time" - securejoin "github.com/cyphar/filepath-securejoin" "github.com/cyphar/filepath-securejoin/pathrs-lite/procfs" "github.com/moby/sys/mountinfo" "github.com/moby/sys/userns" @@ -25,6 +24,7 @@ import ( "github.com/opencontainers/cgroups" devices "github.com/opencontainers/cgroups/devices/config" "github.com/opencontainers/cgroups/fs2" + "github.com/opencontainers/runc/internal/linux" "github.com/opencontainers/runc/internal/pathrs" "github.com/opencontainers/runc/internal/sys" "github.com/opencontainers/runc/libcontainer/configs" @@ -90,13 +90,67 @@ func (m mountEntry) srcStatfs() (*unix.Statfs_t, error) { // needsSetupDev returns true if /dev needs to be set up. func needsSetupDev(config *configs.Config) bool { for _, m := range config.Mounts { - if m.Device == "bind" && utils.CleanPath(m.Destination) == "/dev" { + if m.Device == "bind" && pathrs.LexicallyCleanPath(m.Destination) == "/dev" { return false } } return true } +// setupAndMountToRootfs sets up the mount for a single mount point and mounts it to the rootfs. +func setupAndMountToRootfs(pipe *syncSocket, config *configs.Config, mountConfig *mountConfig, m *configs.Mount) error { + entry := mountEntry{Mount: m} + // Figure out whether we need to request runc to give us an + // open_tree(2)-style mountfd. For idmapped mounts, this is always + // necessary. For bind-mounts, this is only necessary if we cannot + // resolve the parent mount (this is only hit if you are running in a + // userns -- but for rootless the host-side thread can't help). + wantSourceFile := m.IsIDMapped() + if m.IsBind() && !config.RootlessEUID { + if _, err := os.Stat(m.Source); err != nil { + wantSourceFile = true + } + } + if wantSourceFile { + // Request a source file from the host. + if err := writeSyncArg(pipe, procMountPlease, m); err != nil { + return fmt.Errorf("failed to request mountfd for %q: %w", m.Source, err) + } + sync, err := readSyncFull(pipe, procMountFd) + if err != nil { + return fmt.Errorf("mountfd request for %q failed: %w", m.Source, err) + } + if sync.File == nil { + return fmt.Errorf("mountfd request for %q: response missing attached fd", m.Source) + } + defer sync.File.Close() + // Sanity-check to make sure we didn't get the wrong fd back. Note + // that while m.Source might contain symlinks, the (*os.File).Name + // is based on the path provided to os.OpenFile, not what it + // resolves to. So this should never happen. + if sync.File.Name() != m.Source { + return fmt.Errorf("returned mountfd for %q doesn't match requested mount configuration: mountfd path is %q", m.Source, sync.File.Name()) + } + // Unmarshal the procMountFd argument (the file is sync.File). + var src *mountSource + if sync.Arg == nil { + return fmt.Errorf("sync %q is missing an argument", sync.Type) + } + if err := json.Unmarshal(*sync.Arg, &src); err != nil { + return fmt.Errorf("invalid mount fd response argument %q: %w", string(*sync.Arg), err) + } + if src == nil { + return fmt.Errorf("mountfd request for %q: no mount source info received", m.Source) + } + src.file = sync.File + entry.srcFile = src + } + if err := mountToRootfs(mountConfig, entry); err != nil { + return fmt.Errorf("error mounting %q to rootfs at %q: %w", m.Source, m.Destination, err) + } + return nil +} + // 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. @@ -114,54 +168,8 @@ func prepareRootfs(pipe *syncSocket, iConfig *initConfig) (err error) { cgroupns: config.Namespaces.Contains(configs.NEWCGROUP), } for _, m := range config.Mounts { - entry := mountEntry{Mount: m} - // Figure out whether we need to request runc to give us an - // open_tree(2)-style mountfd. For idmapped mounts, this is always - // necessary. For bind-mounts, this is only necessary if we cannot - // resolve the parent mount (this is only hit if you are running in a - // userns -- but for rootless the host-side thread can't help). - wantSourceFile := m.IsIDMapped() - if m.IsBind() && !config.RootlessEUID { - if _, err := os.Stat(m.Source); err != nil { - wantSourceFile = true - } - } - if wantSourceFile { - // Request a source file from the host. - if err := writeSyncArg(pipe, procMountPlease, m); err != nil { - return fmt.Errorf("failed to request mountfd for %q: %w", m.Source, err) - } - sync, err := readSyncFull(pipe, procMountFd) - if err != nil { - return fmt.Errorf("mountfd request for %q failed: %w", m.Source, err) - } - if sync.File == nil { - return fmt.Errorf("mountfd request for %q: response missing attached fd", m.Source) - } - defer sync.File.Close() - // Sanity-check to make sure we didn't get the wrong fd back. Note - // that while m.Source might contain symlinks, the (*os.File).Name - // is based on the path provided to os.OpenFile, not what it - // resolves to. So this should never happen. - if sync.File.Name() != m.Source { - return fmt.Errorf("returned mountfd for %q doesn't match requested mount configuration: mountfd path is %q", m.Source, sync.File.Name()) - } - // Unmarshal the procMountFd argument (the file is sync.File). - var src *mountSource - if sync.Arg == nil { - return fmt.Errorf("sync %q is missing an argument", sync.Type) - } - if err := json.Unmarshal(*sync.Arg, &src); err != nil { - return fmt.Errorf("invalid mount fd response argument %q: %w", string(*sync.Arg), err) - } - if src == nil { - return fmt.Errorf("mountfd request for %q: no mount source info received", m.Source) - } - src.file = sync.File - entry.srcFile = src - } - if err := mountToRootfs(mountConfig, entry); err != nil { - return fmt.Errorf("error mounting %q to rootfs at %q: %w", m.Source, m.Destination, err) + if err := setupAndMountToRootfs(pipe, config, mountConfig, m); err != nil { + return err } } @@ -256,7 +264,7 @@ func finalizeRootfs(config *configs.Config) (err error) { if m.Flags&unix.MS_RDONLY != unix.MS_RDONLY { continue } - if m.Device == "tmpfs" || utils.CleanPath(m.Destination) == "/dev" { + if m.Device == "tmpfs" || pathrs.LexicallyCleanPath(m.Destination) == "/dev" { if err := remountReadonly(m); err != nil { return err } @@ -328,12 +336,15 @@ func mountCgroupV1(m mountEntry, c *mountConfig) error { // We just created the tmpfs, and so we can just use filepath.Join // here (not to mention we want to make sure we create the path // inside the tmpfs, so we don't want to resolve symlinks). + // TODO: Why not just use b.Destination (c.root is the root here)? subsystemPath := filepath.Join(c.root, b.Destination) subsystemName := filepath.Base(b.Destination) - if err := pathrs.MkdirAllInRoot(c.root, subsystemPath, 0o755); err != nil { + subsystemDir, err := pathrs.MkdirAllInRoot(c.root, subsystemPath, 0o755) + if err != nil { return err } - if err := utils.WithProcfd(c.root, b.Destination, func(dstFd string) error { + defer subsystemDir.Close() + if err := utils.WithProcfdFile(subsystemDir, func(dstFd string) error { flags := defaultMountFlags if m.Flags&unix.MS_RDONLY != 0 { flags = flags | unix.MS_RDONLY @@ -357,11 +368,11 @@ func mountCgroupV1(m mountEntry, c *mountConfig) error { } } for _, mc := range merged { - for _, ss := range strings.Split(mc, ",") { + for ss := range strings.SplitSeq(mc, ",") { // symlink(2) is very dumb, it will just shove the path into // the link and doesn't do any checks or relative path // conversion. Also, don't error out if the cgroup already exists. - if err := os.Symlink(mc, filepath.Join(c.root, m.Destination, ss)); err != nil && !os.IsExist(err) { + if err := os.Symlink(mc, filepath.Join(c.root, m.Destination, ss)); err != nil && !errors.Is(err, os.ErrExist) { return err } } @@ -502,16 +513,26 @@ func statfsToMountFlags(st unix.Statfs_t) int { return flags } -var errRootfsToFile = errors.New("config tries to change rootfs to file") - func (m *mountEntry) createOpenMountpoint(rootfs string) (Err error) { - unsafePath := utils.StripRoot(rootfs, m.Destination) + unsafePath := pathrs.LexicallyStripRoot(rootfs, m.Destination) dstFile, err := pathrs.OpenInRoot(rootfs, unsafePath, unix.O_PATH) defer func() { if dstFile != nil && Err != nil { _ = dstFile.Close() } }() + if err == nil && m.Device == "tmpfs" { + // If the original target exists, copy the mode for the tmpfs mount. + stat, err := dstFile.Stat() + if err != nil { + return fmt.Errorf("check tmpfs source mode: %w", err) + } + dt := fmt.Sprintf("mode=%04o", syscallMode(stat.Mode())) + if m.Data != "" { + dt = dt + "," + m.Data + } + m.Data = dt + } if err != nil { if !errors.Is(err, unix.ENOENT) { return fmt.Errorf("lookup mountpoint target: %w", err) @@ -530,41 +551,16 @@ func (m *mountEntry) createOpenMountpoint(rootfs string) (Err error) { } dstIsFile = !fi.IsDir() } - - // In previous runc versions, we would tolerate nonsense paths with - // dangling symlinks as path components. pathrs-lite does not support - // this, so instead we have to emulate this behaviour by doing - // SecureJoin *purely to get a semi-reasonable path to use* and then we - // use pathrs-lite to operate on the path safely. - newUnsafePath, err := securejoin.SecureJoin(rootfs, unsafePath) - if err != nil { - return err - } - unsafePath = utils.StripRoot(rootfs, newUnsafePath) - if dstIsFile { dstFile, err = pathrs.CreateInRoot(rootfs, unsafePath, unix.O_CREAT|unix.O_EXCL|unix.O_NOFOLLOW, 0o644) } else { - dstFile, err = pathrs.MkdirAllInRootOpen(rootfs, unsafePath, 0o755) + dstFile, err = pathrs.MkdirAllInRoot(rootfs, unsafePath, 0o755) } if err != nil { return fmt.Errorf("make mountpoint %q: %w", m.Destination, err) } } - if m.Device == "tmpfs" { - // If the original target exists, copy the mode for the tmpfs mount. - stat, err := dstFile.Stat() - if err != nil { - return fmt.Errorf("check tmpfs source mode: %w", err) - } - dt := fmt.Sprintf("mode=%04o", syscallMode(stat.Mode())) - if m.Data != "" { - dt = dt + "," + m.Data - } - m.Data = dt - } - dstFullPath, err := procfs.ProcSelfFdReadlink(dstFile) if err != nil { return fmt.Errorf("get mount destination real path: %w", err) @@ -589,6 +585,12 @@ func (m *mountEntry) createOpenMountpoint(rootfs string) (Err error) { func mountToRootfs(c *mountConfig, m mountEntry) error { rootfs := c.root + defer func() { + if m.dstFile != nil { + _ = m.dstFile.Close() + m.dstFile = nil + } + }() // procfs and sysfs are special because we need to ensure they are actually // mounted on a specific path in a container without any funny business. @@ -608,13 +610,13 @@ func mountToRootfs(c *mountConfig, m mountEntry) error { return err } if fi, err := os.Lstat(dest); err != nil { - if !os.IsNotExist(err) { + if !errors.Is(err, os.ErrNotExist) { return err } } else if !fi.IsDir() { return fmt.Errorf("filesystem %q must be mounted on ordinary directory", m.Device) } - dstFile, err := pathrs.MkdirAllInRootOpen(rootfs, dest, 0o755) + dstFile, err := pathrs.MkdirAllInRoot(rootfs, dest, 0o755) if err != nil { return err } @@ -629,12 +631,6 @@ func mountToRootfs(c *mountConfig, m mountEntry) error { if err := m.createOpenMountpoint(rootfs); err != nil { return fmt.Errorf("create mountpoint for %s mount: %w", m.Destination, err) } - defer func() { - if m.dstFile != nil { - _ = m.dstFile.Close() - m.dstFile = nil - } - }() switch m.Device { case "mqueue": @@ -911,7 +907,7 @@ func setupDevSymlinks(rootfs string) error { src = link[0] dst = filepath.Join(rootfs, link[1]) ) - if err := os.Symlink(src, dst); err != nil && !os.IsExist(err) { + if err := os.Symlink(src, dst); err != nil && !errors.Is(err, os.ErrExist) { return err } } @@ -931,19 +927,15 @@ func reOpenDevNull() error { if err := verifyDevNull(file); err != nil { return fmt.Errorf("can't reopen /dev/null: %w", err) } - for fd := 0; fd < 3; fd++ { + for fd := range 3 { var stat unix.Stat_t if err := unix.Fstat(fd, &stat); err != nil { return &os.PathError{Op: "fstat", Path: "fd " + strconv.Itoa(fd), Err: err} } if isDevNull(&stat) { // Close and re-open the fd. - if err := unix.Dup3(int(file.Fd()), fd, 0); err != nil { - return &os.PathError{ - Op: "dup3", - Path: "fd " + strconv.Itoa(int(file.Fd())), - Err: err, - } + if err := linux.Dup3(int(file.Fd()), fd, 0); err != nil { + return err } } } @@ -956,7 +948,7 @@ func createDevices(config *configs.Config) error { for _, node := range config.Devices { // The /dev/ptmx device is setup by setupPtmx() - if utils.CleanPath(node.Path) == "/dev/ptmx" { + if pathrs.LexicallyCleanPath(node.Path) == "/dev/ptmx" { continue } @@ -987,18 +979,12 @@ func createDeviceNode(rootfs string, node *devices.Device, bind bool) error { // The node only exists for cgroup reasons, ignore it here. return nil } - destPath, err := securejoin.SecureJoin(rootfs, node.Path) - if err != nil { - return err - } - if destPath == rootfs { - return fmt.Errorf("%w: mknod over rootfs", errRootfsToFile) - } - destDirPath, destName := filepath.Split(destPath) - destDir, err := pathrs.MkdirAllInRootOpen(rootfs, destDirPath, 0o755) + destDir, destName, err := pathrs.MkdirAllParentInRoot(rootfs, node.Path, 0o755) if err != nil { return fmt.Errorf("mkdir parent of device inode %q: %w", node.Path, err) } + defer destDir.Close() + if bind { return bindMountDeviceNode(destDir, destName, node) } @@ -1047,10 +1033,10 @@ func mknodDevice(destDir *os.File, destName string, node *devices.Device) error node.Type, node.Path, stat.Mode&unix.S_IFMT, fileMode&unix.S_IFMT) } - if stat.Rdev != dev { + if rdev := uint64(stat.Rdev); rdev != dev { //nolint:unconvert // Rdev is uint32 on MIPS. return fmt.Errorf("new %c device inode %s has incorrect major:minor: %d:%d doesn't match expected %d:%d", node.Type, node.Path, - unix.Major(stat.Rdev), unix.Minor(stat.Rdev), + unix.Major(rdev), unix.Minor(rdev), unix.Major(dev), unix.Minor(dev)) } return nil @@ -1085,7 +1071,7 @@ func rootfsParentMountPrivate(path string) error { if err == nil { return nil } - if err != unix.EINVAL || path == "/" { //nolint:errorlint // unix errors are bare + if err != unix.EINVAL || path == "/" { break } path = filepath.Dir(path) @@ -1131,7 +1117,7 @@ func setReadonly() error { func setupPtmx(config *configs.Config) error { ptmx := filepath.Join(config.Rootfs, "dev/ptmx") - if err := os.Remove(ptmx); err != nil && !os.IsNotExist(err) { + if err := os.Remove(ptmx); err != nil && !errors.Is(err, os.ErrNotExist) { return err } if err := os.Symlink("pts/ptmx", ptmx); err != nil { @@ -1149,17 +1135,17 @@ func pivotRoot(rootfs string) error { // with pivot_root this allows us to pivot without creating directories in // the rootfs. Shout-outs to the LXC developers for giving us this idea. - oldroot, err := unix.Open("/", unix.O_DIRECTORY|unix.O_RDONLY, 0) + oldroot, err := linux.Open("/", unix.O_DIRECTORY|unix.O_RDONLY, 0) if err != nil { - return &os.PathError{Op: "open", Path: "/", Err: err} + return err } - defer unix.Close(oldroot) //nolint: errcheck + defer unix.Close(oldroot) - newroot, err := unix.Open(rootfs, unix.O_DIRECTORY|unix.O_RDONLY, 0) + newroot, err := linux.Open(rootfs, unix.O_DIRECTORY|unix.O_RDONLY, 0) if err != nil { - return &os.PathError{Op: "open", Path: rootfs, Err: err} + return err } - defer unix.Close(newroot) //nolint: errcheck + defer unix.Close(newroot) // Change to the new root so that the pivot_root actually acts on it. if err := unix.Fchdir(newroot); err != nil { @@ -1300,7 +1286,7 @@ func remountReadonly(m *configs.Mount) error { dest = m.Destination flags = m.Flags ) - for i := 0; i < 5; i++ { + for range 5 { // There is a special case in the kernel for // MS_REMOUNT | MS_BIND, which allows us to change only the // flags even as an unprivileged user (i.e. user namespace) @@ -1321,7 +1307,8 @@ func remountReadonly(m *configs.Mount) error { } func isDevNull(st *unix.Stat_t) bool { - return st.Mode&unix.S_IFMT == unix.S_IFCHR && st.Rdev == unix.Mkdev(1, 3) + //nolint:unconvert // Rdev is uint32 on MIPS. + return st.Mode&unix.S_IFMT == unix.S_IFCHR && uint64(st.Rdev) == unix.Mkdev(1, 3) } func verifyDevNull(f *os.File) error { @@ -1393,7 +1380,7 @@ func reopenAfterMount(rootfs string, f *os.File, flags int) (_ *os.File, Err err if !pathrs.IsLexicallyInRoot(rootfs, fullPath) { return nil, fmt.Errorf("mountpoint %q is outside of rootfs %q", fullPath, rootfs) } - unsafePath := utils.StripRoot(rootfs, fullPath) + unsafePath := pathrs.LexicallyStripRoot(rootfs, fullPath) reopened, err := pathrs.OpenInRoot(rootfs, unsafePath, flags) if err != nil { return nil, fmt.Errorf("re-open mountpoint %q: %w", unsafePath, err) @@ -1424,7 +1411,7 @@ func reopenAfterMount(rootfs string, f *os.File, flags int) (_ *os.File, Err err // 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 (m *mountEntry) mountPropagate(rootfs string, mountLabel string) error { +func (m *mountEntry) mountPropagate(rootfs, mountLabel string) error { var ( data = label.FormatMountLabel(m.Data, mountLabel) flags = m.Flags @@ -1433,7 +1420,7 @@ func (m *mountEntry) mountPropagate(rootfs string, mountLabel string) error { // operations on it. We need to set up files in "/dev", and other tmpfs // mounts may need to be chmod-ed after mounting. These mounts will be // remounted ro later in finalizeRootfs(), if necessary. - if m.Device == "tmpfs" || utils.CleanPath(m.Destination) == "/dev" { + if m.Device == "tmpfs" || pathrs.LexicallyCleanPath(m.Destination) == "/dev" { flags &= ^unix.MS_RDONLY } @@ -1457,9 +1444,7 @@ func (m *mountEntry) mountPropagate(rootfs string, mountLabel string) error { _ = m.dstFile.Close() m.dstFile = newDstFile - // 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. + // Apply the propagation flags on the new mount. if err := utils.WithProcfdFile(m.dstFile, func(dstFd string) error { for _, pflag := range m.PropagationFlags { if err := mountViaFds("", nil, m.Destination, dstFd, "", uintptr(pflag), ""); err != nil { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go index 3ca03ed8a3..476f51d588 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go @@ -2,7 +2,8 @@ package seccomp import ( "fmt" - "sort" + "maps" + "slices" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runtime-spec/specs-go" @@ -25,12 +26,7 @@ var operators = map[string]configs.Operator{ // 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 + return slices.Sorted(maps.Keys(operators)) } var actions = map[string]configs.Action{ @@ -48,12 +44,7 @@ var actions = map[string]configs.Action{ // 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 + return slices.Sorted(maps.Keys(actions)) } var archs = map[string]string{ @@ -74,17 +65,13 @@ var archs = map[string]string{ "SCMP_ARCH_RISCV64": "riscv64", "SCMP_ARCH_S390": "s390", "SCMP_ARCH_S390X": "s390x", + "SCMP_ARCH_LOONGARCH64": "loong64", } // 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 + return slices.Sorted(maps.Keys(archs)) } // ConvertStringToOperator converts a string into a Seccomp comparison operator. 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 14c03f2779..035d0c0d83 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 @@ -58,6 +58,14 @@ const uintptr_t C_FILTER_FLAG_NEW_LISTENER = SECCOMP_FILTER_FLAG_NEW_LISTENER; #define AUDIT_ARCH_RISCV64 (EM_RISCV|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) #endif +// TODO: If loongarch support is not fully merged, at some point we will want to remove this. +#ifndef AUDIT_ARCH_LOONGARCH64 +#ifndef EM_LOONGARCH +#define EM_LOONGARCH 258 +#endif +#define AUDIT_ARCH_LOONGARCH64 (EM_LOONGARCH|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) +#endif + // 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_*. @@ -78,6 +86,7 @@ const uint32_t C_AUDIT_ARCH_PPC64LE = AUDIT_ARCH_PPC64LE; const uint32_t C_AUDIT_ARCH_S390 = AUDIT_ARCH_S390; const uint32_t C_AUDIT_ARCH_S390X = AUDIT_ARCH_S390X; const uint32_t C_AUDIT_ARCH_RISCV64 = AUDIT_ARCH_RISCV64; +const uint32_t C_AUDIT_ARCH_LOONGARCH64 = AUDIT_ARCH_LOONGARCH64; //nolint:godot // C code, not Go comment. */ import "C" @@ -217,6 +226,8 @@ func scmpArchToAuditArch(arch libseccomp.ScmpArch) (linuxAuditArch, error) { return linuxAuditArch(C.C_AUDIT_ARCH_S390X), nil case libseccomp.ArchRISCV64: return linuxAuditArch(C.C_AUDIT_ARCH_RISCV64), nil + case libseccomp.ArchLOONGARCH64: + return linuxAuditArch(C.C_AUDIT_ARCH_LOONGARCH64), nil default: return invalidArch, fmt.Errorf("unknown architecture: %v", arch) } 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 0a79f197e6..7f7c077175 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go @@ -10,6 +10,7 @@ import ( "github.com/sirupsen/logrus" "golang.org/x/sys/unix" + "github.com/opencontainers/runc/internal/linux" "github.com/opencontainers/runc/libcontainer/apparmor" "github.com/opencontainers/runc/libcontainer/keys" "github.com/opencontainers/runc/libcontainer/seccomp" @@ -33,16 +34,17 @@ func (l *linuxSetnsInit) getSessionRingName() string { func (l *linuxSetnsInit) Init() error { if !l.config.Config.NoNewKeyring { - if err := selinux.SetKeyLabel(l.config.ProcessLabel); err != nil { - return err + if l.config.ProcessLabel != "" { + if err := selinux.SetKeyLabel(l.config.ProcessLabel); err != nil { + return err + } + defer selinux.SetKeyLabel("") //nolint: errcheck } - defer selinux.SetKeyLabel("") //nolint: errcheck // Do not inherit the parent's session keyring. if _, err := keys.JoinSessionKeyring(l.getSessionRingName()); err != nil { - // Same justification as in standart_init_linux.go as to why we + logrus.Warnf("KeyctlJoinSessionKeyring: %v", err) + // Same justification as in standard_init_linux.go as to why we // don't bail on ENOSYS. - // - // TODO(cyphar): And we should have logging here too. if !errors.Is(err, unix.ENOSYS) { return fmt.Errorf("unable to join session keyring: %w", err) } @@ -78,17 +80,30 @@ func (l *linuxSetnsInit) Init() error { if err := setupIOPriority(l.config); err != nil { return err } + + // Set personality if specified. + if l.config.Config.Personality != nil { + if err := setupPersonality(l.config.Config); err != nil { + return err + } + } + + if err := setupMemoryPolicy(l.config.Config); err != nil { + return err + } + // Tell our parent that we're ready to exec. 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 fmt.Errorf("sync ready: %w", err) } - - if err := selinux.SetExecLabel(l.config.ProcessLabel); err != nil { - return err + if l.config.ProcessLabel != "" { + if err := selinux.SetExecLabel(l.config.ProcessLabel); err != nil { + return err + } + defer selinux.SetExecLabel("") //nolint: errcheck } - 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. @@ -107,11 +122,6 @@ func (l *linuxSetnsInit) Init() error { if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil { return err } - if l.config.Config.Personality != nil { - if err := setupPersonality(l.config.Config); err != nil { - return err - } - } // Check for the arg early to make sure it exists. name, err := exec.LookPath(l.config.Args[0]) if err != nil { @@ -154,5 +164,5 @@ func (l *linuxSetnsInit) Init() error { if err := utils.UnsafeCloseFrom(l.config.PassedFilesCount + 3); err != nil { return err } - return system.Exec(name, l.config.Args, l.config.Env) + return linux.Exec(name, l.config.Args, l.config.Env) } 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 21516bd338..570472bd41 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go @@ -11,6 +11,7 @@ import ( "github.com/sirupsen/logrus" "golang.org/x/sys/unix" + "github.com/opencontainers/runc/internal/linux" "github.com/opencontainers/runc/internal/pathrs" "github.com/opencontainers/runc/internal/sys" "github.com/opencontainers/runc/libcontainer/apparmor" @@ -49,22 +50,22 @@ func (l *linuxStandardInit) getSessionRingParams() (string, uint32, uint32) { func (l *linuxStandardInit) Init() error { if !l.config.Config.NoNewKeyring { - if err := selinux.SetKeyLabel(l.config.ProcessLabel); err != nil { - return err + if l.config.ProcessLabel != "" { + if err := selinux.SetKeyLabel(l.config.ProcessLabel); err != nil { + return err + } + defer selinux.SetKeyLabel("") //nolint: errcheck } - defer selinux.SetKeyLabel("") //nolint: errcheck ringname, keepperms, newperms := l.getSessionRingParams() // Do not inherit the parent's session keyring. if sessKeyId, err := keys.JoinSessionKeyring(ringname); err != nil { + logrus.Warnf("KeyctlJoinSessionKeyring: %v", err) // If keyrings aren't supported then it is likely we are on an // older kernel (or inside an LXC container). While we could bail, // the security feature we are using here is best-effort (it only // really provides marginal protection since VFS credentials are // the only significant protection of keyrings). - // - // TODO(cyphar): Log this so people know what's going on, once we - // have proper logging in 'runc init'. if !errors.Is(err, unix.ENOSYS) { return fmt.Errorf("unable to join session keyring: %w", err) } @@ -162,16 +163,29 @@ func (l *linuxStandardInit) Init() error { return err } + // Set personality if specified. + if l.config.Config.Personality != nil { + if err := setupPersonality(l.config.Config); err != nil { + return err + } + } + + if err := setupMemoryPolicy(l.config.Config); err != nil { + return err + } + // Tell our parent that we're ready to exec. 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 fmt.Errorf("sync ready: %w", err) } - if err := selinux.SetExecLabel(l.config.ProcessLabel); err != nil { - return fmt.Errorf("can't set process label: %w", err) + if l.config.ProcessLabel != "" { + if err := selinux.SetExecLabel(l.config.ProcessLabel); err != nil { + return fmt.Errorf("can't set process label: %w", err) + } + defer selinux.SetExecLabel("") //nolint: errcheck } - 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. @@ -234,13 +248,6 @@ func (l *linuxStandardInit) Init() error { } } - // Set personality if specified. - if l.config.Config.Personality != nil { - if err := setupPersonality(l.config.Config); 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() @@ -294,5 +301,5 @@ func (l *linuxStandardInit) Init() error { if err := utils.UnsafeCloseFrom(l.config.PassedFilesCount + 3); err != nil { return err } - return system.Exec(name, l.config.Args, l.config.Env) + return linux.Exec(name, l.config.Args, l.config.Env) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go index 2b7b8b5bc3..1f758e2a30 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go @@ -1,6 +1,7 @@ package libcontainer import ( + "errors" "fmt" "os" "path/filepath" @@ -213,7 +214,7 @@ func (r *restoredState) transition(s containerState) error { func (r *restoredState) destroy() error { if _, err := os.Stat(filepath.Join(r.c.stateDir, "checkpoint")); err != nil { - if !os.IsNotExist(err) { + if !errors.Is(err, os.ErrNotExist) { return err } } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/sync.go b/vendor/github.com/opencontainers/runc/libcontainer/sync.go index 0a54a4b81e..90cf49b86f 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/sync.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/sync.go @@ -113,7 +113,7 @@ func writeSync(pipe *syncSocket, sync syncType) error { return doWriteSync(pipe, syncT{Type: sync}) } -func writeSyncArg(pipe *syncSocket, sync syncType, arg interface{}) error { +func writeSyncArg(pipe *syncSocket, sync syncType, arg any) error { argJSON, err := json.Marshal(arg) if err != nil { return fmt.Errorf("writing sync %v: marshal argument failed: %w", sync, err) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/sync_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/sync_unix.go index 69c0228dbe..2c6e4387d4 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/sync_unix.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/sync_unix.go @@ -6,6 +6,7 @@ import ( "os" "sync/atomic" + "github.com/opencontainers/runc/internal/linux" "golang.org/x/sys/unix" ) @@ -42,20 +43,9 @@ func (s *syncSocket) WritePacket(b []byte) (int, error) { } func (s *syncSocket) ReadPacket() ([]byte, error) { - var ( - size int - err error - ) - - for { - size, _, err = unix.Recvfrom(int(s.f.Fd()), nil, unix.MSG_TRUNC|unix.MSG_PEEK) - if err != unix.EINTR { //nolint:errorlint // unix errors are bare - break - } - } - + size, _, err := linux.Recvfrom(int(s.f.Fd()), nil, unix.MSG_TRUNC|unix.MSG_PEEK) if err != nil { - return nil, fmt.Errorf("fetch packet length from socket: %w", os.NewSyscallError("recvfrom", err)) + return nil, fmt.Errorf("fetch packet length from socket: %w", err) } // We will only get a zero size if the socket has been closed from the // other end (otherwise recvfrom(2) will block until a packet is ready). In diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go b/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go index 5e558c4f99..eaaf13e63a 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go @@ -32,15 +32,6 @@ func (p ParentDeathSignal) Set() error { return SetParentDeathSignal(uintptr(p)) } -func Exec(cmd string, args []string, env []string) error { - for { - err := unix.Exec(cmd, args, env) - if err != unix.EINTR { - return &os.PathError{Op: "exec", Path: cmd, Err: err} - } - } -} - 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/rlimit_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_linux.go index 4595fa82aa..8add993c22 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_linux.go @@ -1,5 +1,3 @@ -//go:build go1.23 - package system import ( diff --git a/vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go b/vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go index 3aca5bdacc..93bfbbd7f5 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go @@ -21,6 +21,7 @@ import ( "os" "runtime" + "github.com/opencontainers/runc/internal/linux" "golang.org/x/sys/unix" ) @@ -49,7 +50,7 @@ func RecvFile(socket *os.File) (_ *os.File, Err error) { for { n, oobn, _, _, err = unix.Recvmsg(int(sockfd), name, oob, unix.MSG_CMSG_CLOEXEC) - if err != unix.EINTR { //nolint:errorlint // unix errors are bare + if err != unix.EINTR { break } } @@ -113,7 +114,7 @@ func RecvFile(socket *os.File) (_ *os.File, Err error) { // SendFile sends a file over the given AF_UNIX socket. file.Name() is also // included so that if the other end uses RecvFile, the file will have the same // name information. -func SendFile(socket *os.File, file *os.File) error { +func SendFile(socket, file *os.File) error { name := file.Name() if len(name) >= MaxNameLen { return fmt.Errorf("sendfd: filename too long: %s", name) @@ -126,10 +127,5 @@ func SendFile(socket *os.File, file *os.File) error { // SendRawFd sends a specific file descriptor over the given AF_UNIX socket. func SendRawFd(socket *os.File, msg string, fd uintptr) error { oob := unix.UnixRights(int(fd)) - for { - err := unix.Sendmsg(int(socket.Fd()), []byte(msg), oob, nil, 0) - if err != unix.EINTR { //nolint:errorlint // unix errors are bare - return os.NewSyscallError("sendmsg", err) - } - } + return linux.Sendmsg(int(socket.Fd()), []byte(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 17259de980..6c3baf0153 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go @@ -3,11 +3,11 @@ package utils import ( "encoding/json" "io" - "os" - "path/filepath" "strings" "golang.org/x/sys/unix" + + "github.com/opencontainers/runc/internal/pathrs" ) const ( @@ -27,7 +27,7 @@ func ExitStatus(status unix.WaitStatus) int { // without a trailing newline. This is used instead of json.Encoder because // there might be a problem in json decoder in some cases, see: // https://github.com/docker/docker/issues/14203#issuecomment-174177790 -func WriteJSON(w io.Writer, v interface{}) error { +func WriteJSON(w io.Writer, v any) error { data, err := json.Marshal(v) if err != nil { return err @@ -36,53 +36,6 @@ func WriteJSON(w io.Writer, v interface{}) error { return err } -// CleanPath makes a path safe for use with filepath.Join. This is done by not -// only cleaning the path, but also (if the path is relative) adding a leading -// '/' and cleaning it (then removing the leading '/'). This ensures that a -// path resulting from prepending another path will always resolve to lexically -// be a subdirectory of the prefixed path. This is all done lexically, so paths -// that include symlinks won't be safe as a result of using CleanPath. -func CleanPath(path string) string { - // Deal with empty strings nicely. - if path == "" { - return "" - } - - // Ensure that all paths are cleaned (especially problematic ones like - // "/../../../../../" which can cause lots of issues). - - if filepath.IsAbs(path) { - return filepath.Clean(path) - } - - // If the path isn't absolute, we need to do more processing to fix paths - // such as "../../../..//some/path". We also shouldn't convert absolute - // paths to relative ones. - path = filepath.Clean(string(os.PathSeparator) + path) - // This can't fail, as (by definition) all paths are relative to root. - path, _ = filepath.Rel(string(os.PathSeparator), path) - - return path -} - -// StripRoot returns the passed path, stripping the root path if it was -// (lexicially) inside it. Note that both passed paths will always be treated -// as absolute, and the returned path will also always be absolute. In -// addition, the paths are cleaned before stripping the root. -func StripRoot(root, path string) string { - // Make the paths clean and absolute. - root, path = CleanPath("/"+root), CleanPath("/"+path) - switch { - case path == root: - path = "/" - case root == "/": - // do nothing - default: - path = strings.TrimPrefix(path, root+"/") - } - return CleanPath("/" + path) -} - // SearchLabels searches through a list of key=value pairs for a given key, // returning its value, and the binary flag telling whether the key exist. func SearchLabels(labels []string, key string) (string, bool) { @@ -113,3 +66,23 @@ func Annotations(labels []string) (bundle string, userAnnotations map[string]str } return bundle, userAnnotations } + +// CleanPath makes a path safe for use with filepath.Join. This is done by not +// only cleaning the path, but also (if the path is relative) adding a leading +// '/' and cleaning it (then removing the leading '/'). This ensures that a +// path resulting from prepending another path will always resolve to lexically +// be a subdirectory of the prefixed path. This is all done lexically, so paths +// that include symlinks won't be safe as a result of using CleanPath. +// +// Deprecated: This function has been moved to internal/pathrs and this wrapper +// will be removed in runc 1.5. +var CleanPath = pathrs.LexicallyCleanPath + +// StripRoot returns the passed path, stripping the root path if it was +// (lexicially) inside it. Note that both passed paths will always be treated +// as absolute, and the returned path will also always be absolute. In +// addition, the paths are cleaned before stripping the root. +// +// Deprecated: This function has been moved to internal/pathrs and this wrapper +// will be removed in runc 1.5. +var StripRoot = pathrs.LexicallyStripRoot 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 7dbec54dc9..af5689e9a2 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go @@ -13,9 +13,11 @@ import ( _ "unsafe" // for go:linkname securejoin "github.com/cyphar/filepath-securejoin" - "github.com/opencontainers/runc/internal/pathrs" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" + + "github.com/opencontainers/runc/internal/linux" + "github.com/opencontainers/runc/internal/pathrs" ) var ( @@ -112,7 +114,7 @@ func runtime_IsPollDescriptor(fd uintptr) bool //nolint:revive // // NOTE: That this function is incredibly dangerous to use in most Go code, as // closing file descriptors from underneath *os.File handles can lead to very -// bad behaviour (the closed file descriptor can be re-used and then any +// bad behaviour (the closed file descriptor can be reused and then any // *os.File operations would apply to the wrong file). This function is only // intended to be called from the last stage of runc init. func UnsafeCloseFrom(minFd int) error { @@ -150,9 +152,12 @@ func NewSockPair(name string) (parent, child *os.File, err error) { // through the passed fdpath should be safe. Do not access this path through // the original path strings, and do not attempt to use the pathname outside of // the passed closure (the file handle will be freed once the closure returns). +// +// Deprecated: This function is an internal implementation detail of runc and +// is no longer used. It will be removed in runc 1.5. func WithProcfd(root, unsafePath string, fn func(procfd string) error) error { // Remove the root then forcefully resolve inside the root. - unsafePath = StripRoot(root, unsafePath) + unsafePath = pathrs.LexicallyStripRoot(root, unsafePath) fullPath, err := securejoin.SecureJoin(root, unsafePath) if err != nil { return fmt.Errorf("resolving path inside rootfs failed: %w", err) @@ -179,10 +184,15 @@ func WithProcfd(root, unsafePath string, fn func(procfd string) error) error { return fn(procfd) } -// WithProcfdFile is a very minimal wrapper around [ProcThreadSelfFd], intended -// to make migrating from [WithProcfd] and [WithProcfdPath] usage easier. The +// WithProcfdFile is a very minimal wrapper around [ProcThreadSelfFd]. The // caller is responsible for making sure that the provided file handle is // actually safe to operate on. +// +// NOTE: THIS FUNCTION IS INTERNAL TO RUNC, DO NOT USE IT. +// +// TODO: Migrate the mount logic towards a more move_mount(2)-friendly design +// where this is kind of /proc/self/... tomfoolery is only done in a fallback +// path for old kernels. func WithProcfdFile(file *os.File, fn func(procfd string) error) error { fdpath, closer := ProcThreadSelfFd(file.Fd()) defer closer() @@ -269,9 +279,9 @@ func Openat(dir *os.File, path string, flags int, mode uint32) (*os.File, error) } flags |= unix.O_CLOEXEC - fd, err := unix.Openat(dirFd, path, flags, mode) + fd, err := linux.Openat(dirFd, path, flags, mode) if err != nil { - return nil, &os.PathError{Op: "openat", Path: path, Err: err} + return nil, err } return os.NewFile(uintptr(fd), dir.Name()+"/"+path), nil } diff --git a/vendor/github.com/opencontainers/runc/types/events.go b/vendor/github.com/opencontainers/runc/types/events.go index ed7d2408fd..4d8782782e 100644 --- a/vendor/github.com/opencontainers/runc/types/events.go +++ b/vendor/github.com/opencontainers/runc/types/events.go @@ -7,9 +7,9 @@ import ( // Event struct for encoding the event data to json. type Event struct { - Type string `json:"type"` - ID string `json:"id"` - Data interface{} `json:"data,omitempty"` + Type string `json:"type"` + ID string `json:"id"` + Data any `json:"data,omitempty"` } // Stats is the runc specific stats structure for stability when encoding and decoding stats. @@ -75,8 +75,8 @@ type CpuUsage struct { } type Cpu struct { - Usage CpuUsage `json:"usage,omitempty"` - Throttling Throttling `json:"throttling,omitempty"` + Usage CpuUsage `json:"usage,omitzero"` + Throttling Throttling `json:"throttling,omitzero"` PSI *PSIStats `json:"psi,omitempty"` } @@ -103,10 +103,10 @@ type MemoryEntry struct { type Memory struct { Cache uint64 `json:"cache,omitempty"` - Usage MemoryEntry `json:"usage,omitempty"` - Swap MemoryEntry `json:"swap,omitempty"` - Kernel MemoryEntry `json:"kernel,omitempty"` - KernelTCP MemoryEntry `json:"kernelTCP,omitempty"` + Usage MemoryEntry `json:"usage,omitzero"` + Swap MemoryEntry `json:"swap,omitzero"` + Kernel MemoryEntry `json:"kernel,omitzero"` + KernelTCP MemoryEntry `json:"kernelTCP,omitzero"` Raw map[string]uint64 `json:"raw,omitempty"` PSI *PSIStats `json:"psi,omitempty"` } @@ -143,6 +143,9 @@ type IntelRdt struct { // The memory bandwidth schema in 'container_id' group MemBwSchema string `json:"mem_bw_schema,omitempty"` + // Schemata contains the full schemata of the ClosID (resctrl group) that the container is assigned to. + Schemata []string `json:"schemata,omitempty"` + // The memory bandwidth monitoring statistics from NUMA nodes in 'container_id' group MBMStats *[]intelrdt.MBMNumaNodeStats `json:"mbm_stats,omitempty"` diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go index 1aa0693b57..3ef333387b 100644 --- a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go +++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go @@ -31,6 +31,8 @@ type Spec struct { VM *VM `json:"vm,omitempty" platform:"vm"` // ZOS is platform-specific configuration for z/OS based containers. ZOS *ZOS `json:"zos,omitempty" platform:"zos"` + // FreeBSD is platform-specific configuration for FreeBSD based containers. + FreeBSD *FreeBSD `json:"freebsd,omitempty" platform:"freebsd"` } // Scheduler represents the scheduling attributes for a process. It is based on @@ -170,7 +172,7 @@ type Mount struct { // Destination is the absolute path where the mount will be placed in the container. Destination string `json:"destination"` // Type specifies the mount kind. - Type string `json:"type,omitempty" platform:"linux,solaris,zos"` + Type string `json:"type,omitempty" platform:"linux,solaris,zos,freebsd"` // Source specifies the source path of the mount. Source string `json:"source,omitempty"` // Options are fstab style mount options. @@ -236,6 +238,8 @@ type Linux struct { Namespaces []LinuxNamespace `json:"namespaces,omitempty"` // Devices are a list of device nodes that are created for the container Devices []LinuxDevice `json:"devices,omitempty"` + // NetDevices are key-value pairs, keyed by network device name on the host, moved to the container's network namespace. + NetDevices map[string]LinuxNetDevice `json:"netDevices,omitempty"` // Seccomp specifies the seccomp security settings for the container. Seccomp *LinuxSeccomp `json:"seccomp,omitempty"` // RootfsPropagation is the rootfs mount propagation mode for the container. @@ -249,6 +253,8 @@ type Linux struct { // IntelRdt contains Intel Resource Director Technology (RDT) information for // handling resource constraints and monitoring metrics (e.g., L3 cache, memory bandwidth) for the container IntelRdt *LinuxIntelRdt `json:"intelRdt,omitempty"` + // MemoryPolicy contains NUMA memory policy for the container. + MemoryPolicy *LinuxMemoryPolicy `json:"memoryPolicy,omitempty"` // Personality contains configuration for the Linux personality syscall Personality *LinuxPersonality `json:"personality,omitempty"` // TimeOffsets specifies the offset for supporting time namespaces. @@ -430,7 +436,7 @@ type LinuxCPU struct { // LinuxPids for Linux cgroup 'pids' resource management (Linux 4.3) type LinuxPids struct { // Maximum number of PIDs. Default is "no limit". - Limit int64 `json:"limit"` + Limit *int64 `json:"limit,omitempty"` } // LinuxNetwork identification and priority configuration @@ -491,6 +497,12 @@ type LinuxDevice struct { GID *uint32 `json:"gid,omitempty"` } +// LinuxNetDevice represents a single network device to be added to the container's network namespace +type LinuxNetDevice struct { + // Name of the device in the container namespace + Name string `json:"name,omitempty"` +} + // LinuxDeviceCgroup represents a device rule for the devices specified to // the device controller type LinuxDeviceCgroup struct { @@ -678,6 +690,32 @@ type WindowsHyperV struct { UtilityVMPath string `json:"utilityVMPath,omitempty"` } +// IOMems contains information about iomem addresses that should be passed to the VM. +type IOMems struct { + // Guest Frame Number to map the iomem range. If GFN is not specified, the mapping will be done to the same Frame Number as was provided in FirstMFN. + FirstGFN *uint64 `json:"firstGFN,omitempty"` + // Physical page number of iomem regions. + FirstMFN *uint64 `json:"firstMFN"` + // Number of pages to be mapped. + NrMFNs *uint64 `json:"nrMFNs"` +} + +// Hardware configuration for the VM image +type HWConfig struct { + // Path to the container device-tree file that should be passed to the VM configuration. + DeviceTree string `json:"deviceTree,omitempty"` + // Number of virtual cpus for the VM. + VCPUs *uint32 `json:"vcpus,omitempty"` + // Maximum memory in bytes allocated to the VM. + Memory *uint64 `json:"memory,omitempty"` + // Host device tree nodes to passthrough to the VM. + DtDevs []string `json:"dtdevs,omitempty"` + // Allow auto-translated domains to access specific hardware I/O memory pages. + IOMems []IOMems `json:"iomems,omitempty"` + // Allows VM to access specific physical IRQs. + Irqs []uint32 `json:"irqs,omitempty"` +} + // VM contains information for virtual-machine-based containers. type VM struct { // Hypervisor specifies hypervisor-related configuration for virtual-machine-based containers. @@ -686,6 +724,8 @@ type VM struct { Kernel VMKernel `json:"kernel"` // Image specifies guest image related configuration for virtual-machine-based containers. Image VMImage `json:"image,omitempty"` + // Hardware configuration that should be passed to the VM. + HwConfig *HWConfig `json:"hwconfig,omitempty"` } // VMHypervisor contains information about the hypervisor to use for a virtual machine. @@ -828,23 +868,41 @@ type LinuxSyscall struct { type LinuxIntelRdt struct { // The identity for RDT Class of Service ClosID string `json:"closID,omitempty"` + + // Schemata specifies the complete schemata to be written as is to the + // schemata file in resctrl fs. Each element represents a single line in the schemata file. + // NOTE: This will overwrite schemas specified in the L3CacheSchema and/or + // MemBwSchema fields. + Schemata []string `json:"schemata,omitempty"` + // The schema for L3 cache id and capacity bitmask (CBM) // Format: "L3:=;=;..." + // NOTE: Should not be specified if Schemata is non-empty. L3CacheSchema string `json:"l3CacheSchema,omitempty"` // The schema of memory bandwidth per L3 cache id // Format: "MB:=bandwidth0;=bandwidth1;..." // The unit of memory bandwidth is specified in "percentages" by // default, and in "MBps" if MBA Software Controller is enabled. + // NOTE: Should not be specified if Schemata is non-empty. MemBwSchema string `json:"memBwSchema,omitempty"` - // EnableCMT is the flag to indicate if the Intel RDT CMT is enabled. CMT (Cache Monitoring Technology) supports monitoring of - // the last-level cache (LLC) occupancy for the container. - EnableCMT bool `json:"enableCMT,omitempty"` + // EnableMonitoring enables resctrl monitoring for the container. This will + // create a dedicated resctrl monitoring group for the container. + EnableMonitoring bool `json:"enableMonitoring,omitempty"` +} + +// LinuxMemoryPolicy represents input for the set_mempolicy syscall. +type LinuxMemoryPolicy struct { + // Mode for the set_mempolicy syscall. + Mode MemoryPolicyModeType `json:"mode"` - // EnableMBM is the flag to indicate if the Intel RDT MBM is enabled. MBM (Memory Bandwidth Monitoring) supports monitoring of - // total and local memory bandwidth for the container. - EnableMBM bool `json:"enableMBM,omitempty"` + // Nodes representing the nodemask for the set_mempolicy syscall in comma separated ranges format. + // Format: "-,,-,..." + Nodes string `json:"nodes"` + + // Flags for the set_mempolicy syscall. + Flags []MemoryPolicyFlagType `json:"flags,omitempty"` } // ZOS contains platform-specific configuration for z/OS based containers. @@ -876,6 +934,26 @@ const ( ZOSUTSNamespace ZOSNamespaceType = "uts" ) +type MemoryPolicyModeType string + +const ( + MpolDefault MemoryPolicyModeType = "MPOL_DEFAULT" + MpolBind MemoryPolicyModeType = "MPOL_BIND" + MpolInterleave MemoryPolicyModeType = "MPOL_INTERLEAVE" + MpolWeightedInterleave MemoryPolicyModeType = "MPOL_WEIGHTED_INTERLEAVE" + MpolPreferred MemoryPolicyModeType = "MPOL_PREFERRED" + MpolPreferredMany MemoryPolicyModeType = "MPOL_PREFERRED_MANY" + MpolLocal MemoryPolicyModeType = "MPOL_LOCAL" +) + +type MemoryPolicyFlagType string + +const ( + MpolFNumaBalancing MemoryPolicyFlagType = "MPOL_F_NUMA_BALANCING" + MpolFRelativeNodes MemoryPolicyFlagType = "MPOL_F_RELATIVE_NODES" + MpolFStaticNodes MemoryPolicyFlagType = "MPOL_F_STATIC_NODES" +) + // LinuxSchedulerPolicy represents different scheduling policies used with the Linux Scheduler type LinuxSchedulerPolicy string @@ -915,3 +993,75 @@ const ( // SchedFlagUtilClampMin represents the utilization clamp maximum scheduling flag SchedFlagUtilClampMax LinuxSchedulerFlag = "SCHED_FLAG_UTIL_CLAMP_MAX" ) + +// FreeBSD contains platform-specific configuration for FreeBSD based containers. +type FreeBSD struct { + // Devices which are accessible in the container + Devices []FreeBSDDevice `json:"devices,omitempty"` + // Jail definition for this container + Jail *FreeBSDJail `json:"jail,omitempty"` +} + +type FreeBSDDevice struct { + // Path to the device, relative to /dev. + Path string `json:"path"` + // FileMode permission bits for the device. + Mode *os.FileMode `json:"mode,omitempty"` +} + +// FreeBSDJail describes how to configure the container's jail +type FreeBSDJail struct { + // Parent jail name - this can be used to share a single vnet + // across several containers + Parent string `json:"parent,omitempty"` + // Whether to use parent UTS names or override in the container + Host FreeBSDSharing `json:"host,omitempty"` + // IPv4 address sharing for the container + Ip4 FreeBSDSharing `json:"ip4,omitempty"` + // IPv4 addresses for the container + Ip4Addr []string `json:"ip4Addr,omitempty"` + // IPv6 address sharing for the container + Ip6 FreeBSDSharing `json:"ip6,omitempty"` + // IPv6 addresses for the container + Ip6Addr []string `json:"ip6Addr,omitempty"` + // Which network stack to use for the container + Vnet FreeBSDSharing `json:"vnet,omitempty"` + // If set, Ip4Addr and Ip6Addr addresses will be added to this interface + Interface string `json:"interface,omitempty"` + // List interfaces to be moved to the container's vnet + VnetInterfaces []string `json:"vnetInterfaces,omitempty"` + // SystemV IPC message sharing for the container + SysVMsg FreeBSDSharing `json:"sysvmsg,omitempty"` + // SystemV semaphore message sharing for the container + SysVSem FreeBSDSharing `json:"sysvsem,omitempty"` + // SystemV memory sharing for the container + SysVShm FreeBSDSharing `json:"sysvshm,omitempty"` + // Mount visibility (see jail(8) for details) + EnforceStatfs *int `json:"enforceStatfs,omitempty"` + // Jail capabilities + Allow *FreeBSDJailAllow `json:"allow,omitempty"` +} + +// These values are used to control access to features in the container, either +// disabling the feature, sharing state with the parent or creating new private +// state in the container. +type FreeBSDSharing string + +const ( + FreeBSDShareDisable FreeBSDSharing = "disable" + FreeBSDShareNew FreeBSDSharing = "new" + FreeBSDShareInherit FreeBSDSharing = "inherit" +) + +// FreeBSDJailAllow describes jail capabilities +type FreeBSDJailAllow struct { + SetHostname bool `json:"setHostname,omitempty"` + RawSockets bool `json:"rawSockets,omitempty"` + Chflags bool `json:"chflags,omitempty"` + Mount []string `json:"mount,omitempty"` + Quotas bool `json:"quotas,omitempty"` + SocketAf bool `json:"socketAf,omitempty"` + Mlock bool `json:"mlock,omitempty"` + ReservedPorts bool `json:"reservedPorts,omitempty"` + Suser bool `json:"suser,omitempty"` +} diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/features/features.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/features/features.go index 949f532b65..7b4c40640b 100644 --- a/vendor/github.com/opencontainers/runtime-spec/specs-go/features/features.go +++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/features/features.go @@ -47,7 +47,9 @@ type Linux struct { Apparmor *Apparmor `json:"apparmor,omitempty"` Selinux *Selinux `json:"selinux,omitempty"` IntelRdt *IntelRdt `json:"intelRdt,omitempty"` + MemoryPolicy *MemoryPolicy `json:"memoryPolicy,omitempty"` MountExtensions *MountExtensions `json:"mountExtensions,omitempty"` + NetDevices *NetDevices `json:"netDevices,omitempty"` } // Cgroup represents the "cgroup" field. @@ -129,6 +131,21 @@ type IntelRdt struct { // Unrelated to whether the host supports Intel RDT or not. // Nil value means "unknown", not "false". Enabled *bool `json:"enabled,omitempty"` + // Schemata is true if the "linux.intelRdt.enableMonitoring" field of the + // spec is implemented. + Schemata *bool `json:"schemata,omitempty"` + // Monitoring is true if the "linux.intelRdt.enableMonitoring" field of the + // spec is implemented. + // Nil value means "unknown", not "false". + Monitoring *bool `json:"monitoring,omitempty"` +} + +// MemoryPolicy represents the "memoryPolicy" field. +type MemoryPolicy struct { + // modes is the list of known memory policy modes, e.g., "MPOL_INTERLEAVE". + Modes []string `json:"modes,omitempty"` + // flags is the list of known memory policy mode flags, e.g., "MPOL_F_STATIC_NODES". + Flags []string `json:"flags,omitempty"` } // MountExtensions represents the "mountExtensions" field. @@ -143,3 +160,10 @@ type IDMap struct { // Nil value means "unknown", not "false". Enabled *bool `json:"enabled,omitempty"` } + +// NetDevices represents the "netDevices" field. +type NetDevices struct { + // Enabled is true if network devices support is compiled in. + // Nil value means "unknown", not "false". + Enabled *bool `json:"enabled,omitempty"` +} diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go index 23234a9c58..0257dba3e7 100644 --- a/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go +++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go @@ -6,9 +6,9 @@ const ( // VersionMajor is for an API incompatible changes VersionMajor = 1 // VersionMinor is for functionality in a backwards-compatible manner - VersionMinor = 2 + VersionMinor = 3 // VersionPatch is for backwards-compatible bug fixes - VersionPatch = 1 + VersionPatch = 0 // VersionDev indicates development branch. Releases will be empty string. VersionDev = "" diff --git a/vendor/github.com/seccomp/libseccomp-golang/.golangci.yml b/vendor/github.com/seccomp/libseccomp-golang/.golangci.yml index 7df8aa1983..10adc9bab7 100644 --- a/vendor/github.com/seccomp/libseccomp-golang/.golangci.yml +++ b/vendor/github.com/seccomp/libseccomp-golang/.golangci.yml @@ -1,4 +1,12 @@ # For documentation, see https://golangci-lint.run/usage/configuration/ -linters: +version: "2" + +formatters: enable: - gofumpt + +linters: + exclusions: + generated: disable + presets: + - std-error-handling diff --git a/vendor/github.com/seccomp/libseccomp-golang/CHANGELOG b/vendor/github.com/seccomp/libseccomp-golang/CHANGELOG index 905a9b5cdc..9e108660e5 100644 --- a/vendor/github.com/seccomp/libseccomp-golang/CHANGELOG +++ b/vendor/github.com/seccomp/libseccomp-golang/CHANGELOG @@ -2,6 +2,21 @@ libseccomp-golang: Releases =============================================================================== https://github.com/seccomp/libseccomp-golang +* Version 0.11.1 - August 5, 2025 +- Make GetArchFromString recognize "loong64" + +* Version 0.11.0 - April 23, 2025 +- Add new architectures (LOONGARCH64, M68K, SH, SHEB) +- Add support for SCMP_FLTATR_CTL_WAITKILL (GetWaitKill, SetWaitKill) +- Add support for filter precompute (Precompute) +- Add support for transactions (Transaction{Start,Commit,Reject}) +- Add ExportBPFMem +- Improve documentation for struct fields +- Fix TestRuleAddAndLoad for ppc architecture +- Fix TestRuleAddAndLoad to not use magic number +- Remove unused get_*_version implementation +- Test against latest libseccomp and Go versions + * Version 0.10.0 - June 9, 2022 - Minimum supported version of libseccomp bumped to v2.3.1 - Add seccomp userspace notification API (ActNotify, filter.*Notif*) diff --git a/vendor/github.com/seccomp/libseccomp-golang/seccomp.go b/vendor/github.com/seccomp/libseccomp-golang/seccomp.go index c23406754c..6f09b336db 100644 --- a/vendor/github.com/seccomp/libseccomp-golang/seccomp.go +++ b/vendor/github.com/seccomp/libseccomp-golang/seccomp.go @@ -17,8 +17,28 @@ import ( "unsafe" ) -// #include -// #include +/* +#include +#include +#include + +// The following functions were added in libseccomp v2.6.0. +#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 6 +int seccomp_precompute(scmp_filter_ctx ctx) { + return -EOPNOTSUPP; +} +int seccomp_export_bpf_mem(const scmp_filter_ctx ctx, void *buf, size_t *len) { + return -EOPNOTSUPP; +} +int seccomp_transaction_start(const scmp_filter_ctx ctx) { + return -EOPNOTSUPP; +} +int seccomp_transaction_commit(const scmp_filter_ctx ctx) { + return -EOPNOTSUPP; +} +void seccomp_transaction_reject(const scmp_filter_ctx ctx) {} +#endif +*/ import "C" // Exported types @@ -33,8 +53,9 @@ type VersionError struct { 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 + // which is necessary on older versions of libseccomp (< 2.5.0) in order to work // correctly. + // TODO: remove once libseccomp < v2.5.0 is not supported. _, _ = getAPI() } @@ -78,49 +99,44 @@ type ScmpSyscall int32 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"` + // Syscall is the syscall number. + Syscall ScmpSyscall `json:"syscall,omitempty"` + // Arch is the filter architecture. + Arch ScmpArch `json:"arch,omitempty"` + // InstrPointer is the address of the instruction that triggered a notification. + InstrPointer uint64 `json:"instr_pointer,omitempty"` + // Args are the arguments (up to 6) for the syscall. + 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"` + // ID is the notification ID. + ID uint64 `json:"id,omitempty"` + // Pid is the process that triggered the notification event. + Pid uint32 `json:"pid,omitempty"` + // Flags is filter flags (see seccomp(2)). + Flags uint32 `json:"flags,omitempty"` + // Data is system call context that triggered the notification. + 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"` + // ID is the notification ID (must match the corresponding ScmpNotifReq ID). + ID uint64 `json:"id,omitempty"` + // 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 + // is used as an error return from the syscall that created the + // notification. + Error int32 `json:"error,omitempty"` + // Val is a return value for the syscall that created the notification. + // Only relevant if Error is 0. + Val uint64 `json:"val,omitempty"` + // Flags is userspace notification response flag (e.g., NotifRespFlagContinue). Flags uint32 `json:"flags,omitempty"` } @@ -175,6 +191,14 @@ const ( ArchPARISC64 // ArchRISCV64 represents RISCV64 ArchRISCV64 + // ArchLOONGARCH64 represents 64-bit LoongArch. + ArchLOONGARCH64 + // ArchM68K represents 32-bit Motorola 68000. + ArchM68K + // ArchSH represents SuperH. + ArchSH + // ArchSHEB represents Big-endian SuperH. + ArchSHEB ) const ( @@ -306,6 +330,14 @@ func GetArchFromString(arch string) (ScmpArch, error) { return ArchPARISC64, nil case "riscv64": return ArchRISCV64, nil + case "loong64", "loongarch64": + return ArchLOONGARCH64, nil + case "m68k": + return ArchM68K, nil + case "sh": + return ArchSH, nil + case "sheb": + return ArchSHEB, nil default: return ArchInvalid, fmt.Errorf("cannot convert unrecognized string %q", arch) } @@ -352,6 +384,14 @@ func (a ScmpArch) String() string { return "parisc64" case ArchRISCV64: return "riscv64" + case ArchLOONGARCH64: + return "loong64" + case ArchM68K: + return "m68k" + case ArchSH: + return "sh" + case ArchSHEB: + return "sheb" case ArchNative: return "native" case ArchInvalid: @@ -798,6 +838,26 @@ func (f *ScmpFilter) RemoveArch(arch ScmpArch) error { return nil } +// Precompute precomputes the seccomp filter for later use by [Load] and +// similar functions. Not only does this improve performance of [Load], +// it also ensures that the seccomp filter can be loaded in an +// async-signal-safe manner if no changes have been made to the filter +// since it was precomputed. +func (f *ScmpFilter) Precompute() error { + f.lock.Lock() + defer f.lock.Unlock() + + if !f.valid { + return errBadFilter + } + + if retCode := C.seccomp_precompute(f.filterCtx); retCode != 0 { + return errRc(retCode) + } + + return nil +} + // Load loads a filter context into the kernel. // Returns an error if the filter context is invalid or the syscall failed. func (f *ScmpFilter) Load() error { @@ -941,6 +1001,25 @@ func (f *ScmpFilter) GetRawRC() (bool, error) { return true, nil } +// GetWaitKill returns the current state of WaitKill flag, +// or an error if an issue was encountered retrieving the value. +// See SetWaitKill for more details. +func (f *ScmpFilter) GetWaitKill() (bool, error) { + val, err := f.getFilterAttr(filterAttrWaitKill) + if err != nil { + if e := checkAPI("GetWaitKill", 7, 2, 6, 0); e != nil { + err = e + } + + return false, err + } + if val == 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. @@ -1053,6 +1132,25 @@ func (f *ScmpFilter) SetRawRC(state bool) error { return err } +// SetWaitKill sets whether libseccomp should request wait killable semantics +// when possible. Defaults to false. +func (f *ScmpFilter) SetWaitKill(state bool) error { + var toSet C.uint32_t = 0x0 + + if state { + toSet = 0x1 + } + + err := f.setFilterAttr(filterAttrWaitKill, toSet) + if err != nil { + if e := checkAPI("SetWaitKill", 7, 2, 6, 0); e != nil { + err = e + } + } + + 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 @@ -1154,6 +1252,30 @@ func (f *ScmpFilter) ExportBPF(file *os.File) error { return nil } +// ExportBPFMem is similar to [ExportBPF], except the data is written into +// a memory and returned as []byte. +func (f *ScmpFilter) ExportBPFMem() ([]byte, error) { + f.lock.Lock() + defer f.lock.Unlock() + + if !f.valid { + return nil, errBadFilter + } + + var len C.size_t + // Get the size required. + if retCode := C.seccomp_export_bpf_mem(f.filterCtx, unsafe.Pointer(nil), &len); retCode < 0 { + return nil, errRc(retCode) + } + // Get the data. + buf := make([]byte, int(len)) + if retCode := C.seccomp_export_bpf_mem(f.filterCtx, unsafe.Pointer(&buf[0]), &len); retCode < 0 { + return nil, errRc(retCode) + } + + return buf, nil +} + // Userspace Notification API // GetNotifFd returns the userspace notification file descriptor associated with the given @@ -1186,3 +1308,53 @@ func NotifRespond(fd ScmpFd, scmpResp *ScmpNotifResp) error { func NotifIDValid(fd ScmpFd, id uint64) error { return notifIDValid(fd, id) } + +// TransactionStart starts a new seccomp filter transaction that the caller can +// use to perform any number of filter modifications which can then be +// committed to the filter using [TransactionCommit] or rejected using +// [TransactionReject]. It is important to note that transactions only affect +// the seccomp filter state while it is being managed by libseccomp; seccomp +// filters which have been loaded into the kernel can not be modified, only new +// seccomp filters can be added on top of the existing loaded filter stack. +func (f *ScmpFilter) TransactionStart() error { + f.lock.Lock() + defer f.lock.Unlock() + + if !f.valid { + return errBadFilter + } + + if retCode := C.seccomp_transaction_start(f.filterCtx); retCode < 0 { + return errRc(retCode) + } + + return nil +} + +// TransactionReject rejects a transaction started by [TransactionStart]. +func (f *ScmpFilter) TransactionReject() { + f.lock.Lock() + defer f.lock.Unlock() + + if !f.valid { + return + } + + C.seccomp_transaction_reject(f.filterCtx) +} + +// TransactionCommit commits a transaction started by [TransactionStart]. +func (f *ScmpFilter) TransactionCommit() error { + f.lock.Lock() + defer f.lock.Unlock() + + if !f.valid { + return errBadFilter + } + + if retCode := C.seccomp_transaction_commit(f.filterCtx); retCode < 0 { + return errRc(retCode) + } + + return nil +} diff --git a/vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go b/vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go index 0a7fd34f51..cc905124c3 100644 --- a/vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go +++ b/vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go @@ -68,6 +68,22 @@ const uint32_t C_ARCH_BAD = ARCH_BAD; #define SCMP_ARCH_RISCV64 ARCH_BAD #endif +#ifndef SCMP_ARCH_LOONGARCH64 +#define SCMP_ARCH_LOONGARCH64 ARCH_BAD +#endif + +#ifndef SCMP_ARCH_M68K +#define SCMP_ARCH_M68K ARCH_BAD +#endif + +#ifndef SCMP_ARCH_SH +#define SCMP_ARCH_SH ARCH_BAD +#endif + +#ifndef SCMP_ARCH_SHEB +#define SCMP_ARCH_SHEB 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; @@ -88,6 +104,10 @@ 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; const uint32_t C_ARCH_RISCV64 = SCMP_ARCH_RISCV64; +const uint32_t C_ARCH_LOONGARCH64 = SCMP_ARCH_LOONGARCH64; +const uint32_t C_ARCH_M68K = SCMP_ARCH_M68K; +const uint32_t C_ARCH_SH = SCMP_ARCH_SH; +const uint32_t C_ARCH_SHEB = SCMP_ARCH_SHEB; #ifndef SCMP_ACT_LOG #define SCMP_ACT_LOG 0x7ffc0000U @@ -128,6 +148,11 @@ const uint32_t C_ACT_NOTIFY = SCMP_ACT_NOTIFY; #define SCMP_FLTATR_API_SYSRAWRC _SCMP_FLTATR_MIN #endif +// Added in libseccomp v2.6.0. +#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 6 +#define SCMP_FLTATR_CTL_WAITKILL _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; @@ -136,6 +161,7 @@ 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 uint32_t C_ATTRIBUTE_OPTIMIZE = (uint32_t)SCMP_FLTATR_CTL_OPTIMIZE; const uint32_t C_ATTRIBUTE_SYSRAWRC = (uint32_t)SCMP_FLTATR_API_SYSRAWRC; +const uint32_t C_ATTRIBUTE_WAITKILL = (uint32_t)SCMP_FLTATR_CTL_WAITKILL; const int C_CMP_NE = (int)SCMP_CMP_NE; const int C_CMP_LT = (int)SCMP_CMP_LT; @@ -145,11 +171,6 @@ const int C_CMP_GE = (int)SCMP_CMP_GE; const int C_CMP_GT = (int)SCMP_CMP_GT; const int C_CMP_MASKED_EQ = (int)SCMP_CMP_MASKED_EQ; -const int C_VERSION_MAJOR = SCMP_VER_MAJOR; -const int C_VERSION_MINOR = SCMP_VER_MINOR; -const int C_VERSION_MICRO = SCMP_VER_MICRO; - -#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR >= 3 unsigned int get_major_version() { return seccomp_version()->major; @@ -164,22 +185,6 @@ unsigned int get_micro_version() { return seccomp_version()->micro; } -#else -unsigned int get_major_version() -{ - return (unsigned int)C_VERSION_MAJOR; -} - -unsigned int get_minor_version() -{ - return (unsigned int)C_VERSION_MINOR; -} - -unsigned int get_micro_version() -{ - return (unsigned int)C_VERSION_MICRO; -} -#endif // The libseccomp API level functions were added in v2.4.0 #if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 4 @@ -284,6 +289,7 @@ const ( filterAttrSSB filterAttrOptimize filterAttrRawRC + filterAttrWaitKill ) const ( @@ -291,7 +297,7 @@ const ( scmpError C.int = -1 // Comparison boundaries to check for architecture validity archStart ScmpArch = ArchNative - archEnd ScmpArch = ArchRISCV64 + archEnd ScmpArch = ArchSHEB // Comparison boundaries to check for action validity actionStart ScmpAction = ActKillThread actionEnd ScmpAction = ActKillProcess @@ -552,6 +558,14 @@ func archFromNative(a C.uint32_t) (ScmpArch, error) { return ArchPARISC64, nil case C.C_ARCH_RISCV64: return ArchRISCV64, nil + case C.C_ARCH_LOONGARCH64: + return ArchLOONGARCH64, nil + case C.C_ARCH_M68K: + return ArchM68K, nil + case C.C_ARCH_SH: + return ArchSH, nil + case C.C_ARCH_SHEB: + return ArchSHEB, nil default: return 0x0, fmt.Errorf("unrecognized architecture %#x", uint32(a)) } @@ -598,6 +612,14 @@ func (a ScmpArch) toNative() C.uint32_t { return C.C_ARCH_PARISC64 case ArchRISCV64: return C.C_ARCH_RISCV64 + case ArchLOONGARCH64: + return C.C_ARCH_LOONGARCH64 + case ArchM68K: + return C.C_ARCH_M68K + case ArchSH: + return C.C_ARCH_SH + case ArchSHEB: + return C.C_ARCH_SHEB case ArchNative: return C.C_ARCH_NATIVE default: @@ -694,6 +716,8 @@ func (a scmpFilterAttr) toNative() uint32 { return uint32(C.C_ATTRIBUTE_OPTIMIZE) case filterAttrRawRC: return uint32(C.C_ATTRIBUTE_SYSRAWRC) + case filterAttrWaitKill: + return uint32(C.C_ATTRIBUTE_WAITKILL) default: return 0x0 } @@ -794,10 +818,7 @@ func notifReceive(fd ScmpFd) (*ScmpNotifReq, error) { if retCode := C.seccomp_notify_alloc(&req, &resp); retCode != 0 { return nil, errRc(retCode) } - - defer func() { - C.seccomp_notify_free(req, resp) - }() + defer C.seccomp_notify_free(req, resp) for { retCode, errno := C.seccomp_notify_receive(C.int(fd), req) @@ -831,10 +852,7 @@ func notifRespond(fd ScmpFd, scmpResp *ScmpNotifResp) error { if retCode := C.seccomp_notify_alloc(&req, &resp); retCode != 0 { return errRc(retCode) } - - defer func() { - C.seccomp_notify_free(req, resp) - }() + defer C.seccomp_notify_free(req, resp) scmpResp.toNative(resp) diff --git a/vendor/modules.txt b/vendor/modules.txt index 2b673c901c..2a17fd336b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,4 +1,4 @@ -# cyphar.com/go-pathrs v0.2.1 +# cyphar.com/go-pathrs v0.2.4 ## explicit; go 1.18 cyphar.com/go-pathrs cyphar.com/go-pathrs/internal/fdutils @@ -48,10 +48,10 @@ github.com/cenkalti/backoff/v4 # github.com/cespare/xxhash/v2 v2.3.0 ## explicit; go 1.11 github.com/cespare/xxhash/v2 -# github.com/checkpoint-restore/go-criu/v6 v6.3.0 -## explicit; go 1.16 -github.com/checkpoint-restore/go-criu/v6 -github.com/checkpoint-restore/go-criu/v6/rpc +# github.com/checkpoint-restore/go-criu/v7 v7.2.0 +## explicit; go 1.20 +github.com/checkpoint-restore/go-criu/v7 +github.com/checkpoint-restore/go-criu/v7/rpc # github.com/cilium/ebpf v0.17.3 ## explicit; go 1.22 github.com/cilium/ebpf @@ -153,13 +153,13 @@ github.com/containerd/ttrpc/cmd/protoc-gen-go-ttrpc # github.com/containerd/typeurl/v2 v2.2.3 ## explicit; go 1.21 github.com/containerd/typeurl/v2 -# github.com/coreos/go-systemd/v22 v22.5.0 -## explicit; go 1.12 +# github.com/coreos/go-systemd/v22 v22.7.0 +## explicit; go 1.23 github.com/coreos/go-systemd/v22/dbus -# github.com/cpuguy83/go-md2man/v2 v2.0.5 -## explicit; go 1.11 +# github.com/cpuguy83/go-md2man/v2 v2.0.7 +## explicit; go 1.12 github.com/cpuguy83/go-md2man/v2/md2man -# github.com/cyphar/filepath-securejoin v0.6.0 +# github.com/cyphar/filepath-securejoin v0.6.1 ## explicit; go 1.18 github.com/cyphar/filepath-securejoin github.com/cyphar/filepath-securejoin/internal/consts @@ -442,7 +442,7 @@ github.com/open-policy-agent/opa/types github.com/open-policy-agent/opa/util github.com/open-policy-agent/opa/util/decoding github.com/open-policy-agent/opa/version -# github.com/opencontainers/cgroups v0.0.4 +# github.com/opencontainers/cgroups v0.0.6 ## explicit; go 1.23.0 github.com/opencontainers/cgroups github.com/opencontainers/cgroups/devices/config @@ -459,8 +459,8 @@ github.com/opencontainers/go-digest ## explicit; go 1.18 github.com/opencontainers/image-spec/specs-go github.com/opencontainers/image-spec/specs-go/v1 -# github.com/opencontainers/runc v1.3.3 -## explicit; go 1.23.0 +# github.com/opencontainers/runc v1.4.2 +## explicit; go 1.24.0 github.com/opencontainers/runc/internal/linux github.com/opencontainers/runc/internal/pathrs github.com/opencontainers/runc/internal/sys @@ -480,7 +480,7 @@ github.com/opencontainers/runc/libcontainer/seccomp/patchbpf github.com/opencontainers/runc/libcontainer/system github.com/opencontainers/runc/libcontainer/utils github.com/opencontainers/runc/types -# github.com/opencontainers/runtime-spec v1.2.1 +# github.com/opencontainers/runtime-spec v1.3.0 ## explicit github.com/opencontainers/runtime-spec/specs-go github.com/opencontainers/runtime-spec/specs-go/features @@ -524,8 +524,8 @@ github.com/samber/lo/internal/constraints github.com/samber/lo/internal/xrand github.com/samber/lo/internal/xtime github.com/samber/lo/mutable -# github.com/seccomp/libseccomp-golang v0.10.0 -## explicit; go 1.14 +# github.com/seccomp/libseccomp-golang v0.11.1 +## explicit; go 1.19 github.com/seccomp/libseccomp-golang # github.com/sirupsen/logrus v1.9.3 ## explicit; go 1.13 @@ -533,7 +533,7 @@ github.com/sirupsen/logrus # github.com/tchap/go-patricia/v2 v2.3.2 ## explicit; go 1.16 github.com/tchap/go-patricia/v2/patricia -# github.com/urfave/cli v1.22.16 +# github.com/urfave/cli v1.22.17 ## explicit; go 1.11 github.com/urfave/cli # github.com/urfave/cli/v2 v2.27.6