mirror of
https://github.com/containers/podman.git
synced 2025-11-29 17:48:05 +08:00
Merge pull request #27459 from TomSweeneyRedHat/dev/tsweeney/cve-2025-53881-main
Bump to runc v1.3.3 - CVE-2025-52881
This commit is contained in:
2
go.mod
2
go.mod
@@ -144,7 +144,7 @@ require (
|
|||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/morikuni/aec v1.0.0 // indirect
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
github.com/opencontainers/runc v1.3.2 // indirect
|
github.com/opencontainers/runc v1.3.3 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pkg/sftp v1.13.9 // indirect
|
github.com/pkg/sftp v1.13.9 // indirect
|
||||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -306,8 +306,8 @@ 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/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 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||||
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||||
github.com/opencontainers/runc v1.3.2 h1:GUwgo0Fx9M/pl2utaSYlJfdBcXAB/CZXDxe322lvJ3Y=
|
github.com/opencontainers/runc v1.3.3 h1:qlmBbbhu+yY0QM7jqfuat7M1H3/iXjju3VkP9lkFQr4=
|
||||||
github.com/opencontainers/runc v1.3.2/go.mod h1:F7UQQEsxcjUNnFpT1qPLHZBKYP7yWwk6hq8suLy9cl0=
|
github.com/opencontainers/runc v1.3.3/go.mod h1:D7rL72gfWxVs9cJ2/AayxB0Hlvn9g0gaF1R7uunumSI=
|
||||||
github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww=
|
github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww=
|
||||||
github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||||
github.com/opencontainers/runtime-tools v0.9.1-0.20250523060157-0ea5ed0382a2 h1:2xZEHOdeQBV6PW8ZtimN863bIOl7OCW/X10K0cnxKeA=
|
github.com/opencontainers/runtime-tools v0.9.1-0.20250523060157-0ea5ed0382a2 h1:2xZEHOdeQBV6PW8ZtimN863bIOl7OCW/X10K0cnxKeA=
|
||||||
|
|||||||
23
vendor/github.com/opencontainers/runc/internal/pathrs/doc.go
generated
vendored
Normal file
23
vendor/github.com/opencontainers/runc/internal/pathrs/doc.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||||
|
* 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
|
||||||
99
vendor/github.com/opencontainers/runc/internal/pathrs/mkdirall_pathrslite.go
generated
vendored
Normal file
99
vendor/github.com/opencontainers/runc/internal/pathrs/mkdirall_pathrslite.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
"github.com/cyphar/filepath-securejoin/pathrs-lite"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MkdirAllInRootOpen 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 MkdirAllInRootOpen(root, unsafePath string, mode os.FileMode) (*os.File, error) {
|
||||||
|
// If the path is already "within" the root, get the path relative to the
|
||||||
|
// root and use that as the unsafe path. This is necessary because a lot of
|
||||||
|
// MkdirAllInRootOpen callers have already done SecureJoin, and refactoring
|
||||||
|
// all of them to stop using these SecureJoin'd paths would require a fair
|
||||||
|
// amount of work.
|
||||||
|
// TODO(cyphar): Do the refactor to libpathrs once it's ready.
|
||||||
|
if IsLexicallyInRoot(root, unsafePath) {
|
||||||
|
subPath, err := filepath.Rel(root, unsafePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
unsafePath = subPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// MkdirAllInRoot is a wrapper around MkdirAllInRootOpen which closes the
|
||||||
|
// returned handle, for callers that don't need to use it.
|
||||||
|
func MkdirAllInRoot(root, unsafePath string, mode os.FileMode) error {
|
||||||
|
f, err := MkdirAllInRootOpen(root, unsafePath, mode)
|
||||||
|
if err == nil {
|
||||||
|
_ = f.Close()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
34
vendor/github.com/opencontainers/runc/internal/pathrs/path.go
generated
vendored
Normal file
34
vendor/github.com/opencontainers/runc/internal/pathrs/path.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||||
|
* 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 (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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+"/")
|
||||||
|
}
|
||||||
108
vendor/github.com/opencontainers/runc/internal/pathrs/procfs_pathrslite.go
generated
vendored
Normal file
108
vendor/github.com/opencontainers/runc/internal/pathrs/procfs_pathrslite.go
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||||
|
* 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
66
vendor/github.com/opencontainers/runc/internal/pathrs/retry.go
generated
vendored
Normal file
66
vendor/github.com/opencontainers/runc/internal/pathrs/retry.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||||
|
* 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
|
||||||
|
}
|
||||||
72
vendor/github.com/opencontainers/runc/internal/pathrs/root_pathrslite.go
generated
vendored
Normal file
72
vendor/github.com/opencontainers/runc/internal/pathrs/root_pathrslite.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
"github.com/cyphar/filepath-securejoin/pathrs-lite"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
dir, filename := filepath.Split(subpath)
|
||||||
|
if filepath.Join("/", filename) == "/" {
|
||||||
|
return nil, fmt.Errorf("create in root subpath %q has bad trailing component %q", subpath, filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
dirFd, err := MkdirAllInRootOpen(root, dir, 0o755)
|
||||||
|
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 := unix.Openat(int(dirFd.Fd()), filename, flags, fileMode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return os.NewFile(uintptr(fd), root+"/"+subpath), nil
|
||||||
|
}
|
||||||
13
vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go
generated
vendored
13
vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go
generated
vendored
@@ -6,6 +6,9 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
"github.com/opencontainers/runc/internal/pathrs"
|
||||||
"github.com/opencontainers/runc/libcontainer/utils"
|
"github.com/opencontainers/runc/libcontainer/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -36,19 +39,13 @@ func setProcAttr(attr, value string) error {
|
|||||||
// Under AppArmor you can only change your own attr, so there's no reason
|
// Under AppArmor you can only change your own attr, so there's no reason
|
||||||
// to not use /proc/thread-self/ (instead of /proc/<tid>/, like libapparmor
|
// to not use /proc/thread-self/ (instead of /proc/<tid>/, like libapparmor
|
||||||
// does).
|
// does).
|
||||||
attrPath, closer := utils.ProcThreadSelf(attrSubPath)
|
f, closer, err := pathrs.ProcThreadSelfOpen(attrSubPath, unix.O_WRONLY|unix.O_CLOEXEC)
|
||||||
defer closer()
|
|
||||||
|
|
||||||
f, err := os.OpenFile(attrPath, os.O_WRONLY, 0)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer closer()
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
if err := utils.EnsureProcHandle(f); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = f.WriteString(value)
|
_, err = f.WriteString(value)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
6
vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go
generated
vendored
6
vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go
generated
vendored
@@ -65,11 +65,11 @@ func CleanPath(path string) string {
|
|||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
// stripRoot returns the passed path, stripping the root path if it was
|
// StripRoot returns the passed path, stripping the root path if it was
|
||||||
// (lexicially) inside it. Note that both passed paths will always be treated
|
// (lexicially) inside it. Note that both passed paths will always be treated
|
||||||
// as absolute, and the returned path will also always be absolute. In
|
// as absolute, and the returned path will also always be absolute. In
|
||||||
// addition, the paths are cleaned before stripping the root.
|
// addition, the paths are cleaned before stripping the root.
|
||||||
func stripRoot(root, path string) string {
|
func StripRoot(root, path string) string {
|
||||||
// Make the paths clean and absolute.
|
// Make the paths clean and absolute.
|
||||||
root, path = CleanPath("/"+root), CleanPath("/"+path)
|
root, path = CleanPath("/"+root), CleanPath("/"+path)
|
||||||
switch {
|
switch {
|
||||||
@@ -111,5 +111,5 @@ func Annotations(labels []string) (bundle string, userAnnotations map[string]str
|
|||||||
userAnnotations[name] = value
|
userAnnotations[name] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return bundle, userAnnotations
|
||||||
}
|
}
|
||||||
|
|||||||
127
vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go
generated
vendored
127
vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go
generated
vendored
@@ -9,27 +9,15 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
_ "unsafe" // for go:linkname
|
_ "unsafe" // for go:linkname
|
||||||
|
|
||||||
securejoin "github.com/cyphar/filepath-securejoin"
|
securejoin "github.com/cyphar/filepath-securejoin"
|
||||||
|
"github.com/opencontainers/runc/internal/pathrs"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EnsureProcHandle returns whether or not the given file handle is on procfs.
|
|
||||||
func EnsureProcHandle(fh *os.File) error {
|
|
||||||
var buf unix.Statfs_t
|
|
||||||
if err := unix.Fstatfs(int(fh.Fd()), &buf); err != nil {
|
|
||||||
return fmt.Errorf("ensure %s is on procfs: %w", fh.Name(), err)
|
|
||||||
}
|
|
||||||
if buf.Type != unix.PROC_SUPER_MAGIC {
|
|
||||||
return fmt.Errorf("%s is not on procfs", fh.Name())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
haveCloseRangeCloexecBool bool
|
haveCloseRangeCloexecBool bool
|
||||||
haveCloseRangeCloexecOnce sync.Once
|
haveCloseRangeCloexecOnce sync.Once
|
||||||
@@ -59,19 +47,13 @@ type fdFunc func(fd int)
|
|||||||
// fdRangeFrom calls the passed fdFunc for each file descriptor that is open in
|
// fdRangeFrom calls the passed fdFunc for each file descriptor that is open in
|
||||||
// the current process.
|
// the current process.
|
||||||
func fdRangeFrom(minFd int, fn fdFunc) error {
|
func fdRangeFrom(minFd int, fn fdFunc) error {
|
||||||
procSelfFd, closer := ProcThreadSelf("fd")
|
fdDir, closer, err := pathrs.ProcThreadSelfOpen("fd/", unix.O_DIRECTORY|unix.O_CLOEXEC)
|
||||||
defer closer()
|
|
||||||
|
|
||||||
fdDir, err := os.Open(procSelfFd)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("get handle to /proc/thread-self/fd: %w", err)
|
||||||
}
|
}
|
||||||
|
defer closer()
|
||||||
defer fdDir.Close()
|
defer fdDir.Close()
|
||||||
|
|
||||||
if err := EnsureProcHandle(fdDir); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fdList, err := fdDir.Readdirnames(-1)
|
fdList, err := fdDir.Readdirnames(-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -170,8 +152,8 @@ func NewSockPair(name string) (parent, child *os.File, err error) {
|
|||||||
// the passed closure (the file handle will be freed once the closure returns).
|
// the passed closure (the file handle will be freed once the closure returns).
|
||||||
func WithProcfd(root, unsafePath string, fn func(procfd string) error) error {
|
func WithProcfd(root, unsafePath string, fn func(procfd string) error) error {
|
||||||
// Remove the root then forcefully resolve inside the root.
|
// Remove the root then forcefully resolve inside the root.
|
||||||
unsafePath = stripRoot(root, unsafePath)
|
unsafePath = StripRoot(root, unsafePath)
|
||||||
path, err := securejoin.SecureJoin(root, unsafePath)
|
fullPath, err := securejoin.SecureJoin(root, unsafePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("resolving path inside rootfs failed: %w", err)
|
return fmt.Errorf("resolving path inside rootfs failed: %w", err)
|
||||||
}
|
}
|
||||||
@@ -180,7 +162,7 @@ func WithProcfd(root, unsafePath string, fn func(procfd string) error) error {
|
|||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
// Open the target path.
|
// Open the target path.
|
||||||
fh, err := os.OpenFile(path, unix.O_PATH|unix.O_CLOEXEC, 0)
|
fh, err := os.OpenFile(fullPath, unix.O_PATH|unix.O_CLOEXEC, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("open o_path procfd: %w", err)
|
return fmt.Errorf("open o_path procfd: %w", err)
|
||||||
}
|
}
|
||||||
@@ -190,13 +172,24 @@ func WithProcfd(root, unsafePath string, fn func(procfd string) error) error {
|
|||||||
// Double-check the path is the one we expected.
|
// Double-check the path is the one we expected.
|
||||||
if realpath, err := os.Readlink(procfd); err != nil {
|
if realpath, err := os.Readlink(procfd); err != nil {
|
||||||
return fmt.Errorf("procfd verification failed: %w", err)
|
return fmt.Errorf("procfd verification failed: %w", err)
|
||||||
} else if realpath != path {
|
} else if realpath != fullPath {
|
||||||
return fmt.Errorf("possibly malicious path detected -- refusing to operate on %s", realpath)
|
return fmt.Errorf("possibly malicious path detected -- refusing to operate on %s", realpath)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fn(procfd)
|
return fn(procfd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithProcfdFile is a very minimal wrapper around [ProcThreadSelfFd], intended
|
||||||
|
// to make migrating from [WithProcfd] and [WithProcfdPath] usage easier. The
|
||||||
|
// caller is responsible for making sure that the provided file handle is
|
||||||
|
// actually safe to operate on.
|
||||||
|
func WithProcfdFile(file *os.File, fn func(procfd string) error) error {
|
||||||
|
fdpath, closer := ProcThreadSelfFd(file.Fd())
|
||||||
|
defer closer()
|
||||||
|
|
||||||
|
return fn(fdpath)
|
||||||
|
}
|
||||||
|
|
||||||
type ProcThreadSelfCloser func()
|
type ProcThreadSelfCloser func()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -268,88 +261,6 @@ func ProcThreadSelfFd(fd uintptr) (string, ProcThreadSelfCloser) {
|
|||||||
return ProcThreadSelf("fd/" + strconv.FormatUint(uint64(fd), 10))
|
return ProcThreadSelf("fd/" + strconv.FormatUint(uint64(fd), 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsLexicallyInRoot is shorthand for strings.HasPrefix(path+"/", root+"/"),
|
|
||||||
// but properly handling the case where path or root are "/".
|
|
||||||
//
|
|
||||||
// NOTE: The return value only make sense if the path doesn't contain "..".
|
|
||||||
func IsLexicallyInRoot(root, path string) bool {
|
|
||||||
if root != "/" {
|
|
||||||
root += "/"
|
|
||||||
}
|
|
||||||
if path != "/" {
|
|
||||||
path += "/"
|
|
||||||
}
|
|
||||||
return strings.HasPrefix(path, root)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MkdirAllInRootOpen 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 securejoin.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 MkdirAllInRootOpen(root, unsafePath string, mode os.FileMode) (_ *os.File, Err error) {
|
|
||||||
// If the path is already "within" the root, get the path relative to the
|
|
||||||
// root and use that as the unsafe path. This is necessary because a lot of
|
|
||||||
// MkdirAllInRootOpen callers have already done SecureJoin, and refactoring
|
|
||||||
// all of them to stop using these SecureJoin'd paths would require a fair
|
|
||||||
// amount of work.
|
|
||||||
// TODO(cyphar): Do the refactor to libpathrs once it's ready.
|
|
||||||
if IsLexicallyInRoot(root, unsafePath) {
|
|
||||||
subPath, err := filepath.Rel(root, unsafePath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
unsafePath = subPath
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 securejoin.MkdirAllHandle(rootDir, unsafePath, mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MkdirAllInRoot is a wrapper around MkdirAllInRootOpen which closes the
|
|
||||||
// returned handle, for callers that don't need to use it.
|
|
||||||
func MkdirAllInRoot(root, unsafePath string, mode os.FileMode) error {
|
|
||||||
f, err := MkdirAllInRootOpen(root, unsafePath, mode)
|
|
||||||
if err == nil {
|
|
||||||
_ = f.Close()
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Openat is a Go-friendly openat(2) wrapper.
|
// Openat is a Go-friendly openat(2) wrapper.
|
||||||
func Openat(dir *os.File, path string, flags int, mode uint32) (*os.File, error) {
|
func Openat(dir *os.File, path string, flags int, mode uint32) (*os.File, error) {
|
||||||
dirFd := unix.AT_FDCWD
|
dirFd := unix.AT_FDCWD
|
||||||
|
|||||||
3
vendor/modules.txt
vendored
3
vendor/modules.txt
vendored
@@ -544,8 +544,9 @@ github.com/opencontainers/go-digest
|
|||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
github.com/opencontainers/image-spec/specs-go
|
github.com/opencontainers/image-spec/specs-go
|
||||||
github.com/opencontainers/image-spec/specs-go/v1
|
github.com/opencontainers/image-spec/specs-go/v1
|
||||||
# github.com/opencontainers/runc v1.3.2
|
# github.com/opencontainers/runc v1.3.3
|
||||||
## explicit; go 1.23.0
|
## explicit; go 1.23.0
|
||||||
|
github.com/opencontainers/runc/internal/pathrs
|
||||||
github.com/opencontainers/runc/libcontainer/apparmor
|
github.com/opencontainers/runc/libcontainer/apparmor
|
||||||
github.com/opencontainers/runc/libcontainer/devices
|
github.com/opencontainers/runc/libcontainer/devices
|
||||||
github.com/opencontainers/runc/libcontainer/utils
|
github.com/opencontainers/runc/libcontainer/utils
|
||||||
|
|||||||
Reference in New Issue
Block a user