From 2d3d55df98a37576e0e83e55c667cdcb11ee6a37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Thu, 23 Apr 2026 20:29:32 +0200 Subject: [PATCH] Stop depending on github.com/opencontainers/runc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only use a single 9-line function, so replace that with a local (and improved) version. This will allow us to remove the dependency on runc, and avoid the bureaucy of investigating and documenting how we (don't need to) handle unrelated vulnerabilities in that codebase. Signed-off-by: Miloslav Trmač --- common/go.mod | 1 - common/go.sum | 2 - common/pkg/apparmor/apparmor_linux.go | 3 +- .../apparmor/internal/supported/supported.go | 22 +- vendor/github.com/opencontainers/runc/LICENSE | 191 ------------------ vendor/github.com/opencontainers/runc/NOTICE | 17 -- .../opencontainers/runc/internal/linux/doc.go | 3 - .../runc/internal/linux/eintr.go | 28 --- .../runc/internal/linux/linux.go | 138 ------------- .../runc/internal/pathrs/doc.go | 23 --- .../runc/internal/pathrs/mkdirall.go | 51 ----- .../internal/pathrs/mkdirall_pathrslite.go | 79 -------- .../runc/internal/pathrs/path.go | 116 ----------- .../runc/internal/pathrs/procfs_pathrslite.go | 108 ---------- .../runc/internal/pathrs/retry.go | 66 ------ .../runc/internal/pathrs/root_pathrslite.go | 67 ------ .../runc/libcontainer/apparmor/apparmor.go | 18 -- .../libcontainer/apparmor/apparmor_linux.go | 68 ------- .../apparmor/apparmor_unsupported.go | 14 -- vendor/modules.txt | 5 - 20 files changed, 21 insertions(+), 999 deletions(-) delete mode 100644 vendor/github.com/opencontainers/runc/LICENSE delete mode 100644 vendor/github.com/opencontainers/runc/NOTICE delete mode 100644 vendor/github.com/opencontainers/runc/internal/linux/doc.go delete mode 100644 vendor/github.com/opencontainers/runc/internal/linux/eintr.go delete mode 100644 vendor/github.com/opencontainers/runc/internal/linux/linux.go delete mode 100644 vendor/github.com/opencontainers/runc/internal/pathrs/doc.go delete mode 100644 vendor/github.com/opencontainers/runc/internal/pathrs/mkdirall.go delete mode 100644 vendor/github.com/opencontainers/runc/internal/pathrs/mkdirall_pathrslite.go delete mode 100644 vendor/github.com/opencontainers/runc/internal/pathrs/path.go delete mode 100644 vendor/github.com/opencontainers/runc/internal/pathrs/procfs_pathrslite.go delete mode 100644 vendor/github.com/opencontainers/runc/internal/pathrs/retry.go delete mode 100644 vendor/github.com/opencontainers/runc/internal/pathrs/root_pathrslite.go delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_unsupported.go diff --git a/common/go.mod b/common/go.mod index 56bbba8ea1..2e1a70d50a 100644 --- a/common/go.mod +++ b/common/go.mod @@ -27,7 +27,6 @@ require ( github.com/opencontainers/cgroups v0.0.6 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.1 - github.com/opencontainers/runc v1.4.2 github.com/opencontainers/runtime-spec v1.3.0 github.com/opencontainers/runtime-tools v0.9.1-0.20260316125833-8a4db579f5c8 github.com/opencontainers/selinux v1.13.1 diff --git a/common/go.sum b/common/go.sum index 2df49e67b3..1a2bd289ba 100644 --- a/common/go.sum +++ b/common/go.sum @@ -200,8 +200,6 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= -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/runtime-tools v0.9.1-0.20260316125833-8a4db579f5c8 h1:2NAWFjN0PmdIe3XojVL9wf3lJ1//VqAgc7MOSYHQslE= diff --git a/common/pkg/apparmor/apparmor_linux.go b/common/pkg/apparmor/apparmor_linux.go index d677729d8c..288332175a 100644 --- a/common/pkg/apparmor/apparmor_linux.go +++ b/common/pkg/apparmor/apparmor_linux.go @@ -15,7 +15,6 @@ import ( "strings" "text/template" - runcaa "github.com/opencontainers/runc/libcontainer/apparmor" "github.com/sirupsen/logrus" "go.podman.io/common/pkg/apparmor/internal/supported" "go.podman.io/storage/pkg/fileutils" @@ -271,7 +270,7 @@ func CheckProfileAndLoadDefault(name string) (string, error) { } // Check if AppArmor is disabled and error out if a profile is to be set. - if !runcaa.IsEnabled() { + if !supported.IsEnabledOnHost() { if name == "" { return "", nil } diff --git a/common/pkg/apparmor/internal/supported/supported.go b/common/pkg/apparmor/internal/supported/supported.go index d74ab8f08b..512dca59ef 100644 --- a/common/pkg/apparmor/internal/supported/supported.go +++ b/common/pkg/apparmor/internal/supported/supported.go @@ -1,3 +1,5 @@ +//go:build linux + package supported import ( @@ -8,8 +10,8 @@ import ( "path/filepath" "sync" - runcaa "github.com/opencontainers/runc/libcontainer/apparmor" "github.com/sirupsen/logrus" + "go.podman.io/storage/pkg/fileutils" "go.podman.io/storage/pkg/unshare" ) @@ -102,7 +104,7 @@ func (d *defaultVerifier) UnshareIsRootless() bool { } func (d *defaultVerifier) RuncIsEnabled() bool { - return runcaa.IsEnabled() + return IsEnabledOnHost() } func (d *defaultVerifier) OsStat(name string) (os.FileInfo, error) { @@ -112,3 +114,19 @@ func (d *defaultVerifier) OsStat(name string) (os.FileInfo, error) { func (d *defaultVerifier) ExecLookPath(file string) (string, error) { return exec.LookPath(file) } + +var isEnabledOnHost = sync.OnceValue(func() bool { + if err := fileutils.Exists("/sys/kernel/security/apparmor"); err != nil { + return false + } + buf, err := os.ReadFile("/sys/module/apparmor/parameters/enabled") + if err != nil { + return false + } + return len(buf) >= 1 && buf[0] == 'Y' +}) + +// IsEnabled returns true if apparmor is enabled for the host. +func IsEnabledOnHost() bool { + return isEnabledOnHost() +} diff --git a/vendor/github.com/opencontainers/runc/LICENSE b/vendor/github.com/opencontainers/runc/LICENSE deleted file mode 100644 index 27448585ad..0000000000 --- a/vendor/github.com/opencontainers/runc/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2014 Docker, Inc. - - 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. diff --git a/vendor/github.com/opencontainers/runc/NOTICE b/vendor/github.com/opencontainers/runc/NOTICE deleted file mode 100644 index c29775c0d9..0000000000 --- a/vendor/github.com/opencontainers/runc/NOTICE +++ /dev/null @@ -1,17 +0,0 @@ -runc - -Copyright 2012-2015 Docker, Inc. - -This product includes software developed at Docker, Inc. (http://www.docker.com). - -The following is courtesy of our legal counsel: - - -Use and transfer of Docker may be subject to certain restrictions by the -United States and other governments. -It is your responsibility to ensure that your use and/or transfer does not -violate applicable laws. - -For more information, please see http://www.bis.doc.gov - -See also http://www.apache.org/dev/crypto.html and/or seek legal counsel. diff --git a/vendor/github.com/opencontainers/runc/internal/linux/doc.go b/vendor/github.com/opencontainers/runc/internal/linux/doc.go deleted file mode 100644 index 4d1eb90010..0000000000 --- a/vendor/github.com/opencontainers/runc/internal/linux/doc.go +++ /dev/null @@ -1,3 +0,0 @@ -// Package linux provides minimal wrappers around Linux system calls, primarily -// to provide support for automatic EINTR-retries. -package linux diff --git a/vendor/github.com/opencontainers/runc/internal/linux/eintr.go b/vendor/github.com/opencontainers/runc/internal/linux/eintr.go deleted file mode 100644 index 36a6e3e29e..0000000000 --- a/vendor/github.com/opencontainers/runc/internal/linux/eintr.go +++ /dev/null @@ -1,28 +0,0 @@ -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 deleted file mode 100644 index 1371315932..0000000000 --- a/vendor/github.com/opencontainers/runc/internal/linux/linux.go +++ /dev/null @@ -1,138 +0,0 @@ -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 := 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} - } - if n != size { - return string(linkBuf[:n]), nil - } - // Possible truncation, resize the buffer. - size *= 2 - } -} - -// GetPtyPeer is a wrapper for ioctl(TIOCGPTPEER). -func GetPtyPeer(ptyFd uintptr, unsafePeerPath string, flags int) (*os.File, error) { - // Make sure O_NOCTTY is always set -- otherwise runc might accidentally - // gain it as a controlling terminal. O_CLOEXEC also needs to be set to - // make sure we don't leak the handle either. - flags |= unix.O_NOCTTY | unix.O_CLOEXEC - - // There is no nice wrapper for this kind of ioctl in unix. - peerFd, _, errno := unix.Syscall( - unix.SYS_IOCTL, - ptyFd, - uintptr(unix.TIOCGPTPEER), - uintptr(flags), - ) - if errno != 0 { - return nil, os.NewSyscallError("ioctl TIOCGPTPEER", errno) - } - return os.NewFile(peerFd, unsafePeerPath), nil -} diff --git a/vendor/github.com/opencontainers/runc/internal/pathrs/doc.go b/vendor/github.com/opencontainers/runc/internal/pathrs/doc.go deleted file mode 100644 index 496ca59510..0000000000 --- a/vendor/github.com/opencontainers/runc/internal/pathrs/doc.go +++ /dev/null @@ -1,23 +0,0 @@ -// 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 provides wrappers around filepath-securejoin to add the -// minimum set of features needed from libpathrs that are not provided by -// filepath-securejoin, with the eventual goal being that these can be used to -// ease the transition by converting them stubs when enabling libpathrs builds. -package pathrs diff --git a/vendor/github.com/opencontainers/runc/internal/pathrs/mkdirall.go b/vendor/github.com/opencontainers/runc/internal/pathrs/mkdirall.go deleted file mode 100644 index 3a896f4841..0000000000 --- a/vendor/github.com/opencontainers/runc/internal/pathrs/mkdirall.go +++ /dev/null @@ -1,51 +0,0 @@ -// 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 deleted file mode 100644 index c2578e051f..0000000000 --- a/vendor/github.com/opencontainers/runc/internal/pathrs/mkdirall_pathrslite.go +++ /dev/null @@ -1,79 +0,0 @@ -// 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" - - "github.com/cyphar/filepath-securejoin/pathrs-lite" - "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" -) - -// MkdirAllInRoot attempts to make -// -// path, _ := securejoin.SecureJoin(root, unsafePath) -// os.MkdirAll(path, mode) -// os.Open(path) -// -// safer against attacks where components in the path are changed between -// SecureJoin returning and MkdirAll (or Open) being called. In particular, we -// try to detect any symlink components in the path while we are doing the -// MkdirAll. -// -// NOTE: If unsafePath is a subpath of root, we assume that you have already -// called SecureJoin and so we use the provided path verbatim without resolving -// any symlinks (this is done in a way that avoids symlink-exchange races). -// This means that the path also must not contain ".." elements, otherwise an -// error will occur. -// -// This uses (pathrs-lite).MkdirAllHandle under the hood, but it has special -// 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 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. - if mode&^0o7777 != 0 { - return nil, fmt.Errorf("tried to include non-mode bits in MkdirAll mode: 0o%.3o", mode) - } - // Linux (and thus os.MkdirAll) silently ignores the suid and sgid bits if - // passed. While it would make sense to return an error in that case (since - // the user has asked for a mode that won't be applied), for compatibility - // reasons we have to ignore these bits. - if ignoredBits := mode &^ 0o1777; ignoredBits != 0 { - logrus.Warnf("MkdirAll called with no-op mode bits that are ignored by Linux: 0o%.3o", ignoredBits) - mode &= 0o1777 - } - - rootDir, err := os.OpenFile(root, unix.O_DIRECTORY|unix.O_CLOEXEC, 0) - if err != nil { - return nil, fmt.Errorf("open root handle: %w", err) - } - defer rootDir.Close() - - return retryEAGAIN(func() (*os.File, error) { - return pathrs.MkdirAllHandle(rootDir, unsafePath, mode) - }) -} diff --git a/vendor/github.com/opencontainers/runc/internal/pathrs/path.go b/vendor/github.com/opencontainers/runc/internal/pathrs/path.go deleted file mode 100644 index 77be989241..0000000000 --- a/vendor/github.com/opencontainers/runc/internal/pathrs/path.go +++ /dev/null @@ -1,116 +0,0 @@ -// 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 ( - "os" - "path/filepath" - "strings" - - securejoin "github.com/cyphar/filepath-securejoin" -) - -// IsLexicallyInRoot is shorthand for strings.HasPrefix(path+"/", root+"/"), -// but properly handling the case where path or root have a "/" suffix. -// -// NOTE: The return value only make sense if the path is already mostly cleaned -// (i.e., doesn't contain "..", ".", nor unneeded "/"s). -func IsLexicallyInRoot(root, path string) bool { - root = strings.TrimRight(root, "/") - 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/procfs_pathrslite.go b/vendor/github.com/opencontainers/runc/internal/pathrs/procfs_pathrslite.go deleted file mode 100644 index 37450a0eca..0000000000 --- a/vendor/github.com/opencontainers/runc/internal/pathrs/procfs_pathrslite.go +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -/* - * Copyright (C) 2025 Aleksa Sarai - * Copyright (C) 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" - - "github.com/cyphar/filepath-securejoin/pathrs-lite" - "github.com/cyphar/filepath-securejoin/pathrs-lite/procfs" -) - -func procOpenReopen(openFn func(subpath string) (*os.File, error), subpath string, flags int) (*os.File, error) { - handle, err := retryEAGAIN(func() (*os.File, error) { - return openFn(subpath) - }) - if err != nil { - return nil, err - } - defer handle.Close() - - f, err := Reopen(handle, flags) - if err != nil { - return nil, fmt.Errorf("reopen %s: %w", handle.Name(), err) - } - return f, nil -} - -// ProcSelfOpen is a wrapper around [procfs.Handle.OpenSelf] and -// [pathrs.Reopen], to let you one-shot open a procfs file with the given -// flags. -func ProcSelfOpen(subpath string, flags int) (*os.File, error) { - proc, err := retryEAGAIN(procfs.OpenProcRoot) - if err != nil { - return nil, err - } - defer proc.Close() - return procOpenReopen(proc.OpenSelf, subpath, flags) -} - -// ProcPidOpen is a wrapper around [procfs.Handle.OpenPid] and [pathrs.Reopen], -// to let you one-shot open a procfs file with the given flags. -func ProcPidOpen(pid int, subpath string, flags int) (*os.File, error) { - proc, err := retryEAGAIN(procfs.OpenProcRoot) - if err != nil { - return nil, err - } - defer proc.Close() - return procOpenReopen(func(subpath string) (*os.File, error) { - return proc.OpenPid(pid, subpath) - }, subpath, flags) -} - -// ProcThreadSelfOpen is a wrapper around [procfs.Handle.OpenThreadSelf] and -// [pathrs.Reopen], to let you one-shot open a procfs file with the given -// flags. The returned [procfs.ProcThreadSelfCloser] needs the same handling as -// when using pathrs-lite. -func ProcThreadSelfOpen(subpath string, flags int) (_ *os.File, _ procfs.ProcThreadSelfCloser, Err error) { - proc, err := retryEAGAIN(procfs.OpenProcRoot) - if err != nil { - return nil, nil, err - } - defer proc.Close() - - handle, closer, err := retryEAGAIN2(func() (*os.File, procfs.ProcThreadSelfCloser, error) { - return proc.OpenThreadSelf(subpath) - }) - if err != nil { - return nil, nil, err - } - if closer != nil { - defer func() { - if Err != nil { - closer() - } - }() - } - defer handle.Close() - - f, err := Reopen(handle, flags) - if err != nil { - return nil, nil, fmt.Errorf("reopen %s: %w", handle.Name(), err) - } - return f, closer, nil -} - -// Reopen is a wrapper around pathrs.Reopen. -func Reopen(file *os.File, flags int) (*os.File, error) { - return retryEAGAIN(func() (*os.File, error) { - return pathrs.Reopen(file, flags) - }) -} diff --git a/vendor/github.com/opencontainers/runc/internal/pathrs/retry.go b/vendor/github.com/opencontainers/runc/internal/pathrs/retry.go deleted file mode 100644 index a51d335c0d..0000000000 --- a/vendor/github.com/opencontainers/runc/internal/pathrs/retry.go +++ /dev/null @@ -1,66 +0,0 @@ -// 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 ( - "errors" - "fmt" - "time" - - "golang.org/x/sys/unix" -) - -// Based on >50k tests running "runc run" on a 16-core system with very heavy -// rename(2) load, the single longest latency caused by -EAGAIN retries was -// ~800us (with the vast majority being closer to 400us). So, a 2ms limit -// should give more than enough headroom for any real system in practice. -const retryDeadline = 2 * time.Millisecond - -// retryEAGAIN is a top-level retry loop for pathrs to try to returning -// spurious errors in most normal user cases when using openat2 (libpathrs -// itself does up to 128 retries already, but this method takes a -// wallclock-deadline approach to simply retry until a timer elapses). -func retryEAGAIN[T any](fn func() (T, error)) (T, error) { - deadline := time.After(retryDeadline) - for { - v, err := fn() - if !errors.Is(err, unix.EAGAIN) { - return v, err - } - select { - case <-deadline: - return *new(T), fmt.Errorf("%v retry deadline exceeded: %w", retryDeadline, err) - default: - // retry - } - } -} - -// retryEAGAIN2 is like retryEAGAIN except it returns two values. -func retryEAGAIN2[T1, T2 any](fn func() (T1, T2, error)) (T1, T2, error) { - type ret struct { - v1 T1 - v2 T2 - } - v, err := retryEAGAIN(func() (ret, error) { - v1, v2, err := fn() - return ret{v1: v1, v2: v2}, err - }) - return v.v1, v.v2, err -} diff --git a/vendor/github.com/opencontainers/runc/internal/pathrs/root_pathrslite.go b/vendor/github.com/opencontainers/runc/internal/pathrs/root_pathrslite.go deleted file mode 100644 index 51db77440d..0000000000 --- a/vendor/github.com/opencontainers/runc/internal/pathrs/root_pathrslite.go +++ /dev/null @@ -1,67 +0,0 @@ -// 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 ( - "os" - - "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 -// is effectively shorthand for [securejoin.OpenInRoot] followed by -// [securejoin.Reopen]. -func OpenInRoot(root, subpath string, flags int) (*os.File, error) { - handle, err := retryEAGAIN(func() (*os.File, error) { - return pathrs.OpenInRoot(root, subpath) - }) - if err != nil { - return nil, err - } - defer handle.Close() - - return Reopen(handle, flags) -} - -// CreateInRoot creates a new file inside a root (as well as any missing parent -// directories) and returns a handle to said file. This effectively has -// open(O_CREAT|O_NOFOLLOW) semantics. If you want the creation to use O_EXCL, -// 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) { - dirFd, filename, err := MkdirAllParentInRoot(root, subpath, 0o755) - if err != nil { - return nil, err - } - defer dirFd.Close() - - // We know that the filename does not have any "/" components, and that - // dirFd is inside the root. O_NOFOLLOW will stop us from following - // 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 := linux.Openat(int(dirFd.Fd()), filename, flags, fileMode) - if err != nil { - return nil, err - } - return os.NewFile(uintptr(fd), root+"/"+subpath), nil -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go b/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go deleted file mode 100644 index e2a26488e0..0000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go +++ /dev/null @@ -1,18 +0,0 @@ -package apparmor - -import "errors" - -// 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. -func ApplyProfile(name string) error { - return applyProfile(name) -} - -// 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 deleted file mode 100644 index 9bb4fb2cd2..0000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go +++ /dev/null @@ -1,68 +0,0 @@ -package apparmor - -import ( - "errors" - "fmt" - "os" - "sync" - - "golang.org/x/sys/unix" - - "github.com/opencontainers/runc/internal/pathrs" -) - -var ( - appArmorEnabled bool - checkAppArmor sync.Once -) - -// isEnabled returns true if apparmor is enabled for the host. -func isEnabled() bool { - checkAppArmor.Do(func() { - if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil { - buf, err := os.ReadFile("/sys/module/apparmor/parameters/enabled") - appArmorEnabled = err == nil && len(buf) > 1 && buf[0] == 'Y' - } - }) - return appArmorEnabled -} - -func setProcAttr(attr, value string) error { - 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 - attrSubPath = "attr/" + attr - } - - // Under AppArmor you can only change your own attr, so there's no reason - // to not use /proc/thread-self/ (instead of /proc//, like libapparmor - // does). - f, closer, err := pathrs.ProcThreadSelfOpen(attrSubPath, unix.O_WRONLY|unix.O_CLOEXEC) - if err != nil { - return err - } - defer closer() - defer f.Close() - - _, err = f.WriteString(value) - return err -} - -// 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) - } - return nil -} - -// 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 - } - - return changeOnExec(name) -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_unsupported.go deleted file mode 100644 index 4484cd2397..0000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_unsupported.go +++ /dev/null @@ -1,14 +0,0 @@ -//go:build !linux - -package apparmor - -func isEnabled() bool { - return false -} - -func applyProfile(name string) error { - if name != "" { - return ErrApparmorNotEnabled - } - return nil -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 9d04bb6f4d..14b8d67ed3 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -354,11 +354,6 @@ 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.4.2 -## explicit; go 1.24.0 -github.com/opencontainers/runc/internal/linux -github.com/opencontainers/runc/internal/pathrs -github.com/opencontainers/runc/libcontainer/apparmor # github.com/opencontainers/runtime-spec v1.3.0 ## explicit github.com/opencontainers/runtime-spec/specs-go