From 64f05273e30ee724508aa9fbf9ab4ff24baeba65 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Aug 2026 23:23:40 +0000 Subject: [PATCH] build(deps): bump github.com/checkpoint-restore/checkpointctl Bumps [github.com/checkpoint-restore/checkpointctl](https://github.com/checkpoint-restore/checkpointctl) from 1.5.0 to 1.6.0. - [Release notes](https://github.com/checkpoint-restore/checkpointctl/releases) - [Commits](https://github.com/checkpoint-restore/checkpointctl/compare/v1.5.0...v1.6.0) --- updated-dependencies: - dependency-name: github.com/checkpoint-restore/checkpointctl dependency-version: 1.6.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 6 +- go.sum | 12 +-- vendor/cyphar.com/go-pathrs/handle_linux.go | 8 +- .../internal/libpathrs/libpathrs_linux.go | 76 ++++++++++++------ .../go-pathrs/procfs/procfs_linux.go | 10 +-- vendor/cyphar.com/go-pathrs/root_linux.go | 54 +++++++------ vendor/cyphar.com/go-pathrs/version_linux.go | 27 +++++++ .../checkpointctl/lib/annotations.go | 3 + .../checkpointctl/lib/metadata.go | 80 ++++++++++++++++++- .../checkpointctl/lib/metadata_open_linux.go | 53 ++++++++++++ .../checkpointctl/lib/metadata_open_other.go | 13 +++ .../checkpointctl/lib/metadata_open_unix.go | 26 ++++++ .../pathrs-lite/open_libpathrs.go | 2 +- vendor/modules.txt | 8 +- 14 files changed, 305 insertions(+), 73 deletions(-) create mode 100644 vendor/cyphar.com/go-pathrs/version_linux.go create mode 100644 vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata_open_linux.go create mode 100644 vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata_open_other.go create mode 100644 vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata_open_unix.go diff --git a/go.mod b/go.mod index d50b773cde..0404a4b51c 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 github.com/Microsoft/go-winio v0.6.3-0.20251027160822-ad3df93bed29 github.com/Microsoft/hcsshim v0.15.0-rc.4 - github.com/checkpoint-restore/checkpointctl v1.5.0 + github.com/checkpoint-restore/checkpointctl v1.6.0 github.com/checkpoint-restore/go-criu/v7 v7.2.0 github.com/containerd/btrfs/v2 v2.0.0 github.com/containerd/cgroups/v3 v3.1.3 @@ -92,7 +92,7 @@ require ( ) require ( - cyphar.com/go-pathrs v0.2.4 // indirect + cyphar.com/go-pathrs v0.2.5 // indirect github.com/ProtonMail/go-crypto v1.4.1 // indirect github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -102,7 +102,7 @@ require ( github.com/cloudflare/circl v1.6.3 // indirect github.com/containers/ocicrypt v1.3.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect - github.com/cyphar/filepath-securejoin v0.6.1 // indirect + github.com/cyphar/filepath-securejoin v0.7.0 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/felixge/httpsnoop v1.1.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect diff --git a/go.sum b/go.sum index 15fddeb3c3..919b92c21f 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -cyphar.com/go-pathrs v0.2.4 h1:iD/mge36swa1UFKdINkr1Frkpp6wZsy3YYEildj9cLY= -cyphar.com/go-pathrs v0.2.4/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc= +cyphar.com/go-pathrs v0.2.5 h1:SnX9FBvnoyn3lUs1dkMgZ52bAETpirNu3FTRh5HlRik= +cyphar.com/go-pathrs v0.2.5/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= @@ -28,8 +28,8 @@ github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1x github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= 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/checkpointctl v1.5.0 h1:Uu+D2cOf/GUyCMk23Y8L69P6YoATTe6pH+Au64O3y28= -github.com/checkpoint-restore/checkpointctl v1.5.0/go.mod h1:y5HRs1ZWQUZGyEuthlTHmTJN9PUMOjlaH6JvVaNq9kE= +github.com/checkpoint-restore/checkpointctl v1.6.0 h1:e+hOhEFiUUYZRCbbfbceQ3lLGQXHt2+qKSAR2l9Mv5M= +github.com/checkpoint-restore/checkpointctl v1.6.0/go.mod h1:LjfSgCtcTMbzwcA7d+vXJ7udJsWC/VRJpKUojTAGeCk= 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/cilium/ebpf v0.17.3 h1:FnP4r16PWYSE4ux6zN+//jMcW4nMVRvuTLVTvCjyyjg= @@ -86,8 +86,8 @@ github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj 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/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE= -github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc= +github.com/cyphar/filepath-securejoin v0.7.0 h1:s0Y3ITPy6sQn5xt54DuYvTF8hu134ooYLUb58DX/HjE= +github.com/cyphar/filepath-securejoin v0.7.0/go.mod h1:ymLGms/u3BYaviIiuKFnUx8EkQEZeK6cInNoAPJA3o4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= diff --git a/vendor/cyphar.com/go-pathrs/handle_linux.go b/vendor/cyphar.com/go-pathrs/handle_linux.go index 6ed0b7af7a..78225e006a 100644 --- a/vendor/cyphar.com/go-pathrs/handle_linux.go +++ b/vendor/cyphar.com/go-pathrs/handle_linux.go @@ -17,6 +17,8 @@ import ( "fmt" "os" + "golang.org/x/sys/unix" + "cyphar.com/go-pathrs/internal/fdutils" "cyphar.com/go-pathrs/internal/libpathrs" ) @@ -56,11 +58,11 @@ func HandleFromFile(file *os.File) (*Handle, error) { // and can be opened multiple times. // // The handle returned is only usable for reading, and this is method is -// shorthand for [Handle.OpenFile] with os.O_RDONLY. +// shorthand for [Handle.OpenFile] with [unix.O_RDONLY]. // // TODO: Rename these to "Reopen" or something. func (h *Handle) Open() (*os.File, error) { - return h.OpenFile(os.O_RDONLY) + return h.OpenFile(unix.O_RDONLY) } // OpenFile creates an "upgraded" file handle to the file referenced by the @@ -71,7 +73,7 @@ func (h *Handle) Open() (*os.File, error) { // handle. // // TODO: Rename these to "Reopen" or something. -func (h *Handle) OpenFile(flags int) (*os.File, error) { +func (h *Handle) OpenFile(flags uint64) (*os.File, error) { return fdutils.WithFileFd(h.inner, func(fd uintptr) (*os.File, error) { newFd, err := libpathrs.Reopen(fd, flags) if err != nil { 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 d54497a5b7..d610a3be43 100644 --- a/vendor/cyphar.com/go-pathrs/internal/libpathrs/libpathrs_linux.go +++ b/vendor/cyphar.com/go-pathrs/internal/libpathrs/libpathrs_linux.go @@ -60,8 +60,8 @@ func OpenRoot(path string) (uintptr, error) { } // Reopen wraps pathrs_reopen. -func Reopen(fd uintptr, flags int) (uintptr, error) { - newFd := C.pathrs_reopen(C.int(fd), C.int(flags)) +func Reopen(fd uintptr, flags uint64) (uintptr, error) { + newFd := C.pathrs_reopen(C.int(fd), C.uint64_t(flags)) return uintptr(newFd), fetchError(newFd) } @@ -84,11 +84,11 @@ func InRootResolveNoFollow(rootFd uintptr, path string) (uintptr, error) { } // InRootOpen wraps pathrs_inroot_open. -func InRootOpen(rootFd uintptr, path string, flags int) (uintptr, error) { +func InRootOpen(rootFd uintptr, path string, flags uint64) (uintptr, error) { cPath := C.CString(path) defer C.free(unsafe.Pointer(cPath)) - fd := C.pathrs_inroot_open(C.int(rootFd), cPath, C.int(flags)) + fd := C.pathrs_inroot_open(C.int(rootFd), cPath, C.uint64_t(flags)) return uintptr(fd), fetchError(fd) } @@ -145,23 +145,23 @@ func InRootRemoveAll(rootFd uintptr, path string) error { } // InRootCreat wraps pathrs_inroot_creat. -func InRootCreat(rootFd uintptr, path string, flags int, mode uint32) (uintptr, error) { +func InRootCreat(rootFd uintptr, path string, flags uint64, mode uint32) (uintptr, error) { cPath := C.CString(path) defer C.free(unsafe.Pointer(cPath)) - fd := C.pathrs_inroot_creat(C.int(rootFd), cPath, C.int(flags), C.uint(mode)) + fd := C.pathrs_inroot_creat(C.int(rootFd), cPath, C.uint64_t(flags), C.uint(mode)) return uintptr(fd), fetchError(fd) } // InRootRename wraps pathrs_inroot_rename. -func InRootRename(rootFd uintptr, src, dst string, flags uint) error { - cSrc := C.CString(src) - defer C.free(unsafe.Pointer(cSrc)) +func InRootRename(oldRootFd uintptr, oldPath string, newRootFd uintptr, newPath string, flags uint64) error { + cOldPath := C.CString(oldPath) + defer C.free(unsafe.Pointer(cOldPath)) - cDst := C.CString(dst) - defer C.free(unsafe.Pointer(cDst)) + cNewPath := C.CString(newPath) + defer C.free(unsafe.Pointer(cNewPath)) - err := C.pathrs_inroot_rename(C.int(rootFd), cSrc, cDst, C.uint(flags)) + err := C.pathrs_inroot_rename(C.int(oldRootFd), cOldPath, C.int(newRootFd), cNewPath, C.uint64_t(flags)) return fetchError(err) } @@ -193,26 +193,26 @@ func InRootMknod(rootFd uintptr, path string, mode uint32, dev uint64) error { } // InRootSymlink wraps pathrs_inroot_symlink. -func InRootSymlink(rootFd uintptr, path, target string) error { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) +func InRootSymlink(target string, rootFd uintptr, linkpath string) error { + cLinkpath := C.CString(linkpath) + defer C.free(unsafe.Pointer(cLinkpath)) cTarget := C.CString(target) defer C.free(unsafe.Pointer(cTarget)) - err := C.pathrs_inroot_symlink(C.int(rootFd), cPath, cTarget) + err := C.pathrs_inroot_symlink(cTarget, C.int(rootFd), cLinkpath) return fetchError(err) } // InRootHardlink wraps pathrs_inroot_hardlink. -func InRootHardlink(rootFd uintptr, path, target string) error { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) +func InRootHardlink(oldRootFd uintptr, oldPath string, newRootFd uintptr, newPath string, flags uint64) error { + cNewPath := C.CString(newPath) + defer C.free(unsafe.Pointer(cNewPath)) - cTarget := C.CString(target) - defer C.free(unsafe.Pointer(cTarget)) + cOldPath := C.CString(oldPath) + defer C.free(unsafe.Pointer(cOldPath)) - err := C.pathrs_inroot_hardlink(C.int(rootFd), cPath, cTarget) + err := C.pathrs_inroot_hardlink(C.int(oldRootFd), cOldPath, C.int(newRootFd), cNewPath, C.uint64_t(flags)) return fetchError(err) } @@ -277,13 +277,13 @@ func init() { func ProcPid(pid uint32) ProcBase { return ProcBaseTypePid | ProcBase(pid) } // ProcOpenat wraps pathrs_proc_openat. -func ProcOpenat(procRootFd int, base ProcBase, path string, flags int) (uintptr, error) { +func ProcOpenat(procRootFd int, base ProcBase, path string, flags uint64) (uintptr, error) { cBase := C.pathrs_proc_base_t(base) cPath := C.CString(path) defer C.free(unsafe.Pointer(cPath)) - fd := C.pathrs_proc_openat(C.int(procRootFd), cBase, cPath, C.int(flags)) + fd := C.pathrs_proc_openat(C.int(procRootFd), cBase, cPath, C.uint64_t(flags)) return uintptr(fd), fetchError(fd) } @@ -335,3 +335,31 @@ func ProcfsOpen(how *ProcfsOpenHow) (uintptr, error) { fd := C.pathrs_procfs_open((*C.pathrs_procfs_open_how)(how), C.size_t(unsafe.Sizeof(*how))) return uintptr(fd), fetchError(fd) } + +// VersionInfo is a Go-friendly form of pathrs_version_info_t (struct). +type VersionInfo struct { + VersionString string +} + +// versionInfo is pathrs_version_info_t (struct). +type versionInfo C.pathrs_version_info_t + +// Version is pathrs_version_info_t (sizeof(version) is passed automatically). +func Version() (*VersionInfo, error) { + var rawVersion versionInfo + size := C.pathrs_version((*C.pathrs_version_info_t)(&rawVersion), C.size_t(unsafe.Sizeof(rawVersion))) + switch { + case size < 0: + return nil, fetchError(size) + case size > 0: + // TODO(log): Logging? + fallthrough + default: + // TODO(log): Add a log statement if sizeof(rawVersion) is bigger than + // the number of fields we store in VersionInfo. Otherwise a rebuild + // will mask that Go callers cannot see any new fields. + return &VersionInfo{ + VersionString: C.GoString(rawVersion.version_string), + }, nil + } +} diff --git a/vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go b/vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go index 915e9ccdb5..6a3142646f 100644 --- a/vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go +++ b/vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go @@ -127,7 +127,7 @@ func (proc *Handle) fd() int { } // TODO: Should we expose open? -func (proc *Handle) open(base ProcBase, path string, flags int) (_ *os.File, Closer ThreadCloser, Err error) { +func (proc *Handle) open(base ProcBase, path string, flags uint64) (_ *os.File, Closer ThreadCloser, Err error) { var closer ThreadCloser if base == ProcThreadSelf { runtime.LockOSThread() @@ -154,7 +154,7 @@ func (proc *Handle) open(base ProcBase, path string, flags int) (_ *os.File, Clo // (such as /proc/cpuinfo) or information about other processes (such as // /proc/1). Accessing your own process information should be done using // [Handle.OpenSelf] or [Handle.OpenThreadSelf]. -func (proc *Handle) OpenRoot(path string, flags int) (*os.File, error) { +func (proc *Handle) OpenRoot(path string, flags uint64) (*os.File, error) { file, closer, err := proc.open(ProcRoot, path, flags) if closer != nil { // should not happen @@ -180,7 +180,7 @@ 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. -func (proc *Handle) OpenSelf(path string, flags int) (*os.File, error) { +func (proc *Handle) OpenSelf(path string, flags uint64) (*os.File, error) { file, closer, err := proc.open(ProcSelf, path, flags) if closer != nil { // should not happen @@ -198,7 +198,7 @@ func (proc *Handle) OpenSelf(path string, flags int) (*os.File, error) { // Be aware that due to PID recycling, using this is generally not safe except // in certain circumstances. See the documentation of [ProcPid] for more // details. -func (proc *Handle) OpenPid(pid int, path string, flags int) (*os.File, error) { +func (proc *Handle) OpenPid(pid int, path string, flags uint64) (*os.File, error) { file, closer, err := proc.open(ProcPid(pid), path, flags) if closer != nil { // should not happen @@ -225,7 +225,7 @@ 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. -func (proc *Handle) OpenThreadSelf(path string, flags int) (*os.File, ThreadCloser, error) { +func (proc *Handle) OpenThreadSelf(path string, flags uint64) (*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 5bc2e90717..4741a24a46 100644 --- a/vendor/cyphar.com/go-pathrs/root_linux.go +++ b/vendor/cyphar.com/go-pathrs/root_linux.go @@ -19,6 +19,8 @@ import ( "os" "syscall" + "golang.org/x/sys/unix" + "cyphar.com/go-pathrs/internal/fdutils" "cyphar.com/go-pathrs/internal/libpathrs" ) @@ -27,7 +29,7 @@ import ( // purpose of this "root handle" is to perform operations within the directory // tree, or to get a [Handle] to inodes within the directory tree. // -// At time of writing, it is considered a *VERY BAD IDEA* to open a [Root] +// At time of writing, it is considered a *VERY BAD IDEA* to open a Root // inside a possibly-attacker-controlled directory tree. While we do have // protections that should defend against it, it's far more dangerous than just // opening a directory tree which is not inside a potentially-untrusted @@ -68,7 +70,7 @@ func RootFromFile(file *os.File) (*Root, error) { // // All symlinks (including trailing symlinks) are followed, but they are // resolved within the rootfs. If you wish to open a handle to the symlink -// itself, use [ResolveNoFollow]. +// itself, use [Root.ResolveNoFollow]. func (r *Root) Resolve(path string) (*Handle, error) { return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (*Handle, error) { handleFd, err := libpathrs.InRootResolve(rootFd, path) @@ -83,10 +85,10 @@ func (r *Root) Resolve(path string) (*Handle, error) { }) } -// ResolveNoFollow is effectively an O_NOFOLLOW version of [Resolve]. Their -// behaviour is identical, except that *trailing* symlinks will not be -// followed. If the final component is a trailing symlink, an O_PATH|O_NOFOLLOW -// handle to the symlink itself is returned. +// ResolveNoFollow is effectively an [unix.O_NOFOLLOW] version of +// [Root.Resolve]. Their behaviour is identical, except that *trailing* +// symlinks will not be followed. If the final component is a trailing symlink, +// an [unix.O_PATH]|[unix.O_NOFOLLOW] handle to the symlink itself is returned. func (r *Root) ResolveNoFollow(path string) (*Handle, error) { return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (*Handle, error) { handleFd, err := libpathrs.InRootResolveNoFollow(rootFd, path) @@ -101,29 +103,29 @@ func (r *Root) ResolveNoFollow(path string) (*Handle, error) { }) } -// Open is effectively shorthand for [Resolve] followed by [Handle.Open], but -// can be slightly more efficient (it reduces CGo overhead and the number of -// syscalls used when using the openat2-based resolver) and is arguably more +// Open is effectively shorthand for [Root.Resolve] followed by [Handle.Open], +// but can be slightly more efficient (it reduces CGo overhead and the number +// of syscalls used when using the openat2-based resolver) and is arguably more // ergonomic to use. // // This is effectively equivalent to [os.Open]. func (r *Root) Open(path string) (*os.File, error) { - return r.OpenFile(path, os.O_RDONLY) + return r.OpenFile(path, unix.O_RDONLY) } -// OpenFile is effectively shorthand for [Resolve] followed by +// OpenFile is effectively shorthand for [Root.Resolve] followed by // [Handle.OpenFile], but can be slightly more efficient (it reduces CGo // overhead and the number of syscalls used when using the openat2-based // resolver) and is arguably more ergonomic to use. // -// However, if flags contains os.O_NOFOLLOW and the path is a symlink, then +// However, if flags contains [unix.O_NOFOLLOW] and the path is a symlink, then // OpenFile's behaviour will match that of openat2. In most cases an error will -// be returned, but if os.O_PATH is provided along with os.O_NOFOLLOW then a -// file equivalent to [ResolveNoFollow] will be returned instead. +// be returned, but if [unix.O_PATH] is provided along with [unix.O_NOFOLLOW] +// then a file equivalent to [Root.ResolveNoFollow] will be returned instead. // -// This is effectively equivalent to [os.OpenFile], except that os.O_CREAT is -// not supported. -func (r *Root) OpenFile(path string, flags int) (*os.File, error) { +// This is effectively equivalent to [os.OpenFile], except that [unix.O_CREAT] +// is not supported. +func (r *Root) OpenFile(path string, flags uint64) (*os.File, error) { return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (*os.File, error) { fd, err := libpathrs.InRootOpen(rootFd, path, flags) if err != nil { @@ -139,7 +141,7 @@ 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. -func (r *Root) Create(path string, flags int, mode os.FileMode) (*os.File, error) { +func (r *Root) Create(path string, flags uint64, mode os.FileMode) (*os.File, error) { unixMode, err := toUnixMode(mode, false) if err != nil { return nil, err @@ -155,9 +157,9 @@ func (r *Root) Create(path string, flags int, mode os.FileMode) (*os.File, error // Rename two paths within a [Root]'s directory tree. The flags argument is // identical to the RENAME_* flags to the renameat2(2) system call. -func (r *Root) Rename(src, dst string, flags uint) error { +func (r *Root) Rename(src, dst string, flags uint64) error { _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { - err := libpathrs.InRootRename(rootFd, src, dst, flags) + err := libpathrs.InRootRename(rootFd, src, rootFd, dst, flags) return struct{}{}, err }) return err @@ -277,26 +279,26 @@ func (r *Root) Mknod(path string, mode os.FileMode, dev uint64) error { } // Symlink creates a symlink within a [Root]'s directory tree. The symlink is -// created at path and is a link to target. +// created at newname and is a link to oldname. // // This is effectively equivalent to [os.Symlink]. -func (r *Root) Symlink(path, target string) error { +func (r *Root) Symlink(oldname, newname string) error { _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { - err := libpathrs.InRootSymlink(rootFd, path, target) + err := libpathrs.InRootSymlink(oldname, rootFd, newname) return struct{}{}, err }) return err } // Hardlink creates a hardlink within a [Root]'s directory tree. The hardlink -// is created at path and is a link to target. Both paths are within the +// is created at newname and is a link to oldname. Both paths are within the // [Root]'s directory tree (you cannot hardlink to a different [Root] or the // host). // // This is effectively equivalent to [os.Link]. -func (r *Root) Hardlink(path, target string) error { +func (r *Root) Hardlink(oldname, newname string) error { _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { - err := libpathrs.InRootHardlink(rootFd, path, target) + err := libpathrs.InRootHardlink(rootFd, oldname, rootFd, newname, 0) return struct{}{}, err }) return err diff --git a/vendor/cyphar.com/go-pathrs/version_linux.go b/vendor/cyphar.com/go-pathrs/version_linux.go new file mode 100644 index 0000000000..9ed2d74eca --- /dev/null +++ b/vendor/cyphar.com/go-pathrs/version_linux.go @@ -0,0 +1,27 @@ +//go:build linux + +// SPDX-License-Identifier: MPL-2.0 +/* + * libpathrs: safe path resolution on Linux + * 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 + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +package pathrs + +import ( + "cyphar.com/go-pathrs/internal/libpathrs" +) + +// LibraryVersionInfo contains information about the version and features +// supported by the underlying libpathrs.so library at runtime. +type LibraryVersionInfo = libpathrs.VersionInfo + +// LibraryVersion returns information about the version and features supported +// by the underlying libpathrs.so library at runtime. +func LibraryVersion() (*LibraryVersionInfo, error) { + return libpathrs.Version() +} diff --git a/vendor/github.com/checkpoint-restore/checkpointctl/lib/annotations.go b/vendor/github.com/checkpoint-restore/checkpointctl/lib/annotations.go index 8d0ad98036..2ea7b8e8a9 100644 --- a/vendor/github.com/checkpoint-restore/checkpointctl/lib/annotations.go +++ b/vendor/github.com/checkpoint-restore/checkpointctl/lib/annotations.go @@ -19,6 +19,9 @@ const ( // CheckpointAnnotationNamespace specifies the namespace of the pod associated with the checkpoint. CheckpointAnnotationNamespace = "org.criu.checkpoint.pod.namespace" + // CheckpointAnnotationPodUID specifies the UID of the pod associated with the checkpoint. + CheckpointAnnotationPodUID = "org.criu.checkpoint.pod.uid" + // CheckpointAnnotationRootfsImageName specifies the name of the root filesystem image associated with the checkpoint. CheckpointAnnotationRootfsImageName = "org.criu.checkpoint.rootfsImageName" diff --git a/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata.go b/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata.go index 1d68f887f9..d2f0d94d90 100644 --- a/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata.go +++ b/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata.go @@ -4,7 +4,9 @@ package metadata import ( "encoding/json" + "errors" "fmt" + "io" "os" "path/filepath" "time" @@ -12,6 +14,8 @@ import ( spec "github.com/opencontainers/runtime-spec/specs-go" ) +var errNotRegularFile = errors.New("not a regular file") + const ( // container archive ConfigDumpFile = "config.dump" @@ -79,6 +83,43 @@ type KubernetesContainerCheckpointMetadata struct { Checkpoints []KubernetesCheckpoint `json:"checkpoints"` } +// CheckpointedPodOptions contains metadata about a checkpointed pod +type CheckpointedPodOptions struct { + // Version is the version of the pod checkpoint format + Version int `json:"version"` + // Containers is a map with the short container name as key and the full name as value + Containers map[string]string `json:"containers"` + // Annotations stores checkpoint-related annotations (keys defined in annotations.go) + Annotations map[string]string `json:"annotations,omitempty"` +} + +// PodmanNetworkSubnet represents a single subnet entry in the Podman network status +type PodmanNetworkSubnet struct { + IPNet string `json:"ipnet"` + Gateway string `json:"gateway"` +} + +// PodmanNetworkInterface represents a network interface in the Podman network status +type PodmanNetworkInterface struct { + Subnets []PodmanNetworkSubnet `json:"subnets"` + MacAddress string `json:"mac_address"` +} + +// PodmanNetworkResult represents the network status for a single CNI/netavark network +type PodmanNetworkResult struct { + Interfaces map[string]PodmanNetworkInterface `json:"interfaces"` +} + +// PodmanNetworkStatus maps network names to their results in the network.status file +type PodmanNetworkStatus map[string]PodmanNetworkResult + +func ReadContainerCheckpointNetworkStatus(checkpointDirectory string) (*PodmanNetworkStatus, string, error) { + var networkStatus PodmanNetworkStatus + networkStatusFile, err := ReadJSONFile(&networkStatus, checkpointDirectory, NetworkStatusFile) + + return &networkStatus, networkStatusFile, err +} + func ReadContainerCheckpointSpecDump(checkpointDirectory string) (*spec.Spec, string, error) { var specDump spec.Spec specDumpFile, err := ReadJSONFile(&specDump, checkpointDirectory, SpecDumpFile) @@ -107,6 +148,13 @@ func ReadContainerCheckpointStatusFile(checkpointDirectory string) (*ContainerdS return &containerdStatus, statusFile, err } +func ReadCheckpointPodOptions(checkpointDirectory string) (*CheckpointedPodOptions, string, error) { + var podOptions CheckpointedPodOptions + podOptionsFile, err := ReadJSONFile(&podOptions, checkpointDirectory, PodOptionsFile) + + return &podOptions, podOptionsFile, err +} + // WriteJSONFile marshalls and writes the given data to a JSON file func WriteJSONFile(v interface{}, dir, file string) (string, error) { fileJSON, err := json.MarshalIndent(v, "", " ") @@ -121,9 +169,18 @@ func WriteJSONFile(v interface{}, dir, file string) (string, error) { return file, nil } +// ReadJSONFile reads JSON from a regular file in dir. On Unix, a symbolic link +// in the final path component is rejected. On Linux, reopening the validated +// file descriptor requires access to a usable procfs instance. func ReadJSONFile(v interface{}, dir, file string) (string, error) { file = filepath.Join(dir, file) - content, err := os.ReadFile(file) + f, err := openRegularFile(file) + if err != nil { + return "", err + } + defer f.Close() + + content, err := io.ReadAll(f) if err != nil { return "", err } @@ -134,6 +191,27 @@ func ReadJSONFile(v interface{}, dir, file string) (string, error) { return file, nil } +// openRegularFile applies platform-specific opening safeguards and verifies +// the opened descriptor before returning it. +func openRegularFile(file string) (*os.File, error) { + f, err := openFile(file) + if err != nil { + return nil, err + } + + info, err := f.Stat() + if err != nil { + _ = f.Close() + return nil, err + } + if !info.Mode().IsRegular() { + _ = f.Close() + return nil, fmt.Errorf("%s is %w", file, errNotRegularFile) + } + + return f, nil +} + func ByteToString(b int64) string { const unit = 1024 if b < unit { diff --git a/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata_open_linux.go b/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata_open_linux.go new file mode 100644 index 0000000000..876305bf94 --- /dev/null +++ b/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata_open_linux.go @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: Apache-2.0 + +//go:build linux + +package metadata + +import ( + "fmt" + "os" + + pathrs "github.com/cyphar/filepath-securejoin/pathrs-lite" + "golang.org/x/sys/unix" +) + +// openFile opens path without activating the inode, verifies that the opened +// inode is a regular file, and then reopens that same inode for reading. +func openFile(path string) (*os.File, error) { + handle, err := os.OpenFile(path, unix.O_PATH|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0) + if err != nil { + return nil, err + } + defer handle.Close() + + handleInfo, err := handle.Stat() + if err != nil { + return nil, fmt.Errorf("stat %s: %w", path, err) + } + if !handleInfo.Mode().IsRegular() { + return nil, fmt.Errorf("%s is %w", path, errNotRegularFile) + } + + return reopenFile(handle, path, handleInfo) +} + +func reopenFile(handle *os.File, path string, handleInfo os.FileInfo) (*os.File, error) { + // Linux openat(2) does not support AT_EMPTY_PATH. Reopen the pinned O_PATH + // descriptor using pathrs, which protects against unsafe procfs mounts. + f, err := pathrs.Reopen(handle, unix.O_RDONLY) + if err != nil { + return nil, fmt.Errorf("reopen %s: %w", path, err) + } + info, err := f.Stat() + if err != nil { + _ = f.Close() + return nil, fmt.Errorf("stat reopened %s: %w", path, err) + } + if !os.SameFile(handleInfo, info) { + _ = f.Close() + return nil, fmt.Errorf("reopened file does not match %s", path) + } + + return f, nil +} diff --git a/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata_open_other.go b/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata_open_other.go new file mode 100644 index 0000000000..ae057983fb --- /dev/null +++ b/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata_open_other.go @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: Apache-2.0 + +//go:build !unix + +package metadata + +import "os" + +func openFile(path string) (*os.File, error) { + // Preserve the platform's ordinary open behavior. openRegularFile validates + // the resulting descriptor before any JSON is read. + return os.Open(path) +} diff --git a/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata_open_unix.go b/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata_open_unix.go new file mode 100644 index 0000000000..24d525e1e0 --- /dev/null +++ b/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata_open_unix.go @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 + +//go:build unix && !linux + +package metadata + +import ( + "fmt" + "os" + "syscall" +) + +func openFile(path string) (*os.File, error) { + // Reject stable special files before open. O_NONBLOCK prevents a FIFO + // replacement from blocking between this check and the descriptor check in + // openRegularFile. + info, err := os.Lstat(path) + if err != nil { + return nil, err + } + if !info.Mode().IsRegular() { + return nil, fmt.Errorf("%s is %w", path, errNotRegularFile) + } + + return os.OpenFile(path, os.O_RDONLY|syscall.O_NONBLOCK|syscall.O_NOFOLLOW, 0) +} diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_libpathrs.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_libpathrs.go index 53352000e6..15205d1344 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_libpathrs.go +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_libpathrs.go @@ -53,5 +53,5 @@ func Reopen(file *os.File, flags int) (*os.File, error) { } defer handle.Close() //nolint:errcheck // close failures aren't critical here - return handle.OpenFile(flags) + return handle.OpenFile(uint64(flags)) } diff --git a/vendor/modules.txt b/vendor/modules.txt index 075b8f37d7..f62b2aa08c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,4 +1,4 @@ -# cyphar.com/go-pathrs v0.2.4 +# cyphar.com/go-pathrs v0.2.5 ## explicit; go 1.18 cyphar.com/go-pathrs cyphar.com/go-pathrs/internal/fdutils @@ -106,8 +106,8 @@ github.com/cenkalti/backoff/v5 # github.com/cespare/xxhash/v2 v2.3.0 ## explicit; go 1.11 github.com/cespare/xxhash/v2 -# github.com/checkpoint-restore/checkpointctl v1.5.0 -## explicit; go 1.24.6 +# github.com/checkpoint-restore/checkpointctl v1.6.0 +## explicit; go 1.25.0 github.com/checkpoint-restore/checkpointctl/lib # github.com/checkpoint-restore/go-criu/v7 v7.2.0 ## explicit; go 1.20 @@ -306,7 +306,7 @@ github.com/coreos/go-systemd/v22/dbus # 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.1 +# github.com/cyphar/filepath-securejoin v0.7.0 ## explicit; go 1.18 github.com/cyphar/filepath-securejoin/internal/consts github.com/cyphar/filepath-securejoin/pathrs-lite