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