Merge pull request #4430 from cyphar/securejoin-v0.3.4

go: update github.com/cyphar/filepath-securejoin to v0.3.4
This commit is contained in:
lfbzhm
2024-10-09 17:50:56 +08:00
committed by GitHub
11 changed files with 74 additions and 89 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ require (
github.com/cilium/ebpf v0.16.0 github.com/cilium/ebpf v0.16.0
github.com/containerd/console v1.0.4 github.com/containerd/console v1.0.4
github.com/coreos/go-systemd/v22 v22.5.0 github.com/coreos/go-systemd/v22 v22.5.0
github.com/cyphar/filepath-securejoin v0.3.3 github.com/cyphar/filepath-securejoin v0.3.4
github.com/docker/go-units v0.5.0 github.com/docker/go-units v0.5.0
github.com/godbus/dbus/v5 v5.1.0 github.com/godbus/dbus/v5 v5.1.0
github.com/moby/sys/mountinfo v0.7.1 github.com/moby/sys/mountinfo v0.7.1
+2 -2
View File
@@ -9,8 +9,8 @@ github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cyphar/filepath-securejoin v0.3.3 h1:lofZkCEVFIBe0KcdQOzFs8Soy9oaHOWl4gGtPI+gCFc= github.com/cyphar/filepath-securejoin v0.3.4 h1:VBWugsJh2ZxJmLFSM06/0qzQyiQX2Qs0ViKrUAcqdZ8=
github.com/cyphar/filepath-securejoin v0.3.3/go.mod h1:8s/MCNJREmFK0H02MF6Ihv1nakJe4L/w3WZLHNkvlYM= github.com/cyphar/filepath-securejoin v0.3.4/go.mod h1:8s/MCNJREmFK0H02MF6Ihv1nakJe4L/w3WZLHNkvlYM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+9 -1
View File
@@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased] ## ## [Unreleased] ##
## [0.3.4] - 2024-10-09 ##
### Fixed ###
- Previously, some testing mocks we had resulted in us doing `import "testing"`
in non-`_test.go` code, which made some downstreams like Kubernetes unhappy.
This has been fixed. (#32)
## [0.3.3] - 2024-09-30 ## ## [0.3.3] - 2024-09-30 ##
### Fixed ### ### Fixed ###
@@ -157,7 +164,8 @@ This is our first release of `github.com/cyphar/filepath-securejoin`,
containing a full implementation with a coverage of 93.5% (the only missing containing a full implementation with a coverage of 93.5% (the only missing
cases are the error cases, which are hard to mocktest at the moment). cases are the error cases, which are hard to mocktest at the moment).
[Unreleased]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.3...HEAD [Unreleased]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.4...HEAD
[0.3.3]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.3...v0.3.4
[0.3.3]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.2...v0.3.3 [0.3.3]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.2...v0.3.3
[0.3.2]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.1...v0.3.2 [0.3.2]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.1...v0.3.2
[0.3.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.0...v0.3.1 [0.3.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.0...v0.3.1
+2 -1
View File
@@ -1,5 +1,6 @@
## `filepath-securejoin` ## ## `filepath-securejoin` ##
[![Go Documentation](https://pkg.go.dev/badge/github.com/cyphar/filepath-securejoin.svg)](https://pkg.go.dev/github.com/cyphar/filepath-securejoin)
[![Build Status](https://github.com/cyphar/filepath-securejoin/actions/workflows/ci.yml/badge.svg)](https://github.com/cyphar/filepath-securejoin/actions/workflows/ci.yml) [![Build Status](https://github.com/cyphar/filepath-securejoin/actions/workflows/ci.yml/badge.svg)](https://github.com/cyphar/filepath-securejoin/actions/workflows/ci.yml)
### Old API ### ### Old API ###
@@ -85,7 +86,7 @@ more secure. In particular:
or avoid being tricked by a `/proc` that is not legitimate. This is done or avoid being tricked by a `/proc` that is not legitimate. This is done
using [`openat2`][openat2.2] for all users, and privileged users will also be using [`openat2`][openat2.2] for all users, and privileged users will also be
further protected by using [`fsopen`][fsopen.2] and [`open_tree`][open_tree.2] further protected by using [`fsopen`][fsopen.2] and [`open_tree`][open_tree.2]
(Linux 4.18 or later). (Linux 5.2 or later).
[openat2.2]: https://www.man7.org/linux/man-pages/man2/openat2.2.html [openat2.2]: https://www.man7.org/linux/man-pages/man2/openat2.2.html
[fsopen.2]: https://github.com/brauner/man-pages-md/blob/main/fsopen.md [fsopen.2]: https://github.com/brauner/man-pages-md/blob/main/fsopen.md
+1 -1
View File
@@ -1 +1 @@
0.3.3 0.3.4
+39
View File
@@ -0,0 +1,39 @@
// Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
// Copyright (C) 2017-2024 SUSE LLC. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package securejoin implements a set of helpers to make it easier to write Go
// code that is safe against symlink-related escape attacks. The primary idea
// is to let you resolve a path within a rootfs directory as if the rootfs was
// a chroot.
//
// securejoin has two APIs, a "legacy" API and a "modern" API.
//
// The legacy API is [SecureJoin] and [SecureJoinVFS]. These methods are
// **not** safe against race conditions where an attacker changes the
// filesystem after (or during) the [SecureJoin] operation.
//
// The new API is made up of [OpenInRoot] and [MkdirAll] (and derived
// functions). These are safe against racing attackers and have several other
// protections that are not provided by the legacy API. There are many more
// operations that most programs expect to be able to do safely, but we do not
// provide explicit support for them because we want to encourage users to
// switch to [libpathrs](https://github.com/openSUSE/libpathrs) which is a
// cross-language next-generation library that is entirely designed around
// operating on paths safely.
//
// securejoin has been used by several container runtimes (Docker, runc,
// Kubernetes, etc) for quite a few years as a de-facto standard for operating
// on container filesystem paths "safely". However, most users still use the
// legacy API which is unsafe against various attacks (there is a fairly long
// history of CVEs in dependent as a result). Users should switch to the modern
// API as soon as possible (or even better, switch to libpathrs).
//
// This project was initially intended to be included in the Go standard
// library, but [it was rejected](https://go.dev/issue/20126). There is now a
// [new Go proposal](https://go.dev/issue/67002) for a safe path resolution API
// that shares some of the goals of filepath-securejoin. However, that design
// is intended to work like `openat2(RESOLVE_BENEATH)` which does not fit the
// usecase of container runtimes and most system tools.
package securejoin
-5
View File
@@ -3,11 +3,6 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Package securejoin is an implementation of the hopefully-soon-to-be-included
// SecureJoin helper that is meant to be part of the "path/filepath" package.
// The purpose of this project is to provide a PoC implementation to make the
// SecureJoin proposal (https://github.com/golang/go/issues/20126) more
// tangible.
package securejoin package securejoin
import ( import (
-4
View File
@@ -42,10 +42,6 @@ func fstatatFile(dir *os.File, path string, flags int) (unix.Stat_t, error) {
return stat, nil return stat, nil
} }
func fstatFile(fd *os.File) (unix.Stat_t, error) {
return fstatatFile(fd, "", unix.AT_EMPTY_PATH)
}
func readlinkatFile(dir *os.File, path string) (string, error) { func readlinkatFile(dir *os.File, path string) (string, error) {
size := 4096 size := 4096
for { for {
+19 -5
View File
@@ -134,7 +134,7 @@ func clonePrivateProcMount() (_ *os.File, Err error) {
// we can be sure there are no over-mounts and so if the root is valid then // we can be sure there are no over-mounts and so if the root is valid then
// we're golden. Otherwise, we have to deal with over-mounts. // we're golden. Otherwise, we have to deal with over-mounts.
procfsHandle, err := openTree(nil, "/proc", unix.OPEN_TREE_CLONE) procfsHandle, err := openTree(nil, "/proc", unix.OPEN_TREE_CLONE)
if err != nil || testingForcePrivateProcRootOpenTreeAtRecursive(procfsHandle) { if err != nil || hookForcePrivateProcRootOpenTreeAtRecursive(procfsHandle) {
procfsHandle, err = openTree(nil, "/proc", unix.OPEN_TREE_CLONE|unix.AT_RECURSIVE) procfsHandle, err = openTree(nil, "/proc", unix.OPEN_TREE_CLONE|unix.AT_RECURSIVE)
} }
if err != nil { if err != nil {
@@ -152,13 +152,13 @@ func clonePrivateProcMount() (_ *os.File, Err error) {
} }
func privateProcRoot() (*os.File, error) { func privateProcRoot() (*os.File, error) {
if !hasNewMountApi() || testingForceGetProcRootUnsafe() { if !hasNewMountApi() || hookForceGetProcRootUnsafe() {
return nil, fmt.Errorf("new mount api: %w", unix.ENOTSUP) return nil, fmt.Errorf("new mount api: %w", unix.ENOTSUP)
} }
// Try to create a new procfs mount from scratch if we can. This ensures we // Try to create a new procfs mount from scratch if we can. This ensures we
// can get a procfs mount even if /proc is fake (for whatever reason). // can get a procfs mount even if /proc is fake (for whatever reason).
procRoot, err := newPrivateProcMount() procRoot, err := newPrivateProcMount()
if err != nil || testingForcePrivateProcRootOpenTree(procRoot) { if err != nil || hookForcePrivateProcRootOpenTree(procRoot) {
// Try to clone /proc then... // Try to clone /proc then...
procRoot, err = clonePrivateProcMount() procRoot, err = clonePrivateProcMount()
} }
@@ -227,10 +227,10 @@ func procThreadSelf(procRoot *os.File, subpath string) (_ *os.File, _ procThread
// Figure out what prefix we want to use. // Figure out what prefix we want to use.
threadSelf := "thread-self/" threadSelf := "thread-self/"
if !hasProcThreadSelf() || testingForceProcSelfTask() { if !hasProcThreadSelf() || hookForceProcSelfTask() {
/// Pre-3.17 kernels don't have /proc/thread-self, so do it manually. /// Pre-3.17 kernels don't have /proc/thread-self, so do it manually.
threadSelf = "self/task/" + strconv.Itoa(unix.Gettid()) + "/" threadSelf = "self/task/" + strconv.Itoa(unix.Gettid()) + "/"
if _, err := fstatatFile(procRoot, threadSelf, unix.AT_SYMLINK_NOFOLLOW); err != nil || testingForceProcSelf() { if _, err := fstatatFile(procRoot, threadSelf, unix.AT_SYMLINK_NOFOLLOW); err != nil || hookForceProcSelf() {
// In this case, we running in a pid namespace that doesn't match // In this case, we running in a pid namespace that doesn't match
// the /proc mount we have. This can happen inside runc. // the /proc mount we have. This can happen inside runc.
// //
@@ -424,3 +424,17 @@ func checkProcSelfFdPath(path string, file *os.File) error {
} }
return nil return nil
} }
// Test hooks used in the procfs tests to verify that the fallback logic works.
// See testing_mocks_linux_test.go and procfs_linux_test.go for more details.
var (
hookForcePrivateProcRootOpenTree = hookDummyFile
hookForcePrivateProcRootOpenTreeAtRecursive = hookDummyFile
hookForceGetProcRootUnsafe = hookDummy
hookForceProcSelfTask = hookDummy
hookForceProcSelf = hookDummy
)
func hookDummy() bool { return false }
func hookDummyFile(_ *os.File) bool { return false }
-68
View File
@@ -1,68 +0,0 @@
//go:build linux
// Copyright (C) 2024 SUSE LLC. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package securejoin
import (
"os"
"testing"
)
type forceGetProcRootLevel int
const (
forceGetProcRootDefault forceGetProcRootLevel = iota
forceGetProcRootOpenTree // force open_tree()
forceGetProcRootOpenTreeAtRecursive // force open_tree(AT_RECURSIVE)
forceGetProcRootUnsafe // force open()
)
var testingForceGetProcRoot *forceGetProcRootLevel
func testingCheckClose(check bool, f *os.File) bool {
if check {
if f != nil {
_ = f.Close()
}
return true
}
return false
}
func testingForcePrivateProcRootOpenTree(f *os.File) bool {
return testing.Testing() && testingForceGetProcRoot != nil &&
testingCheckClose(*testingForceGetProcRoot >= forceGetProcRootOpenTree, f)
}
func testingForcePrivateProcRootOpenTreeAtRecursive(f *os.File) bool {
return testing.Testing() && testingForceGetProcRoot != nil &&
testingCheckClose(*testingForceGetProcRoot >= forceGetProcRootOpenTreeAtRecursive, f)
}
func testingForceGetProcRootUnsafe() bool {
return testing.Testing() && testingForceGetProcRoot != nil &&
*testingForceGetProcRoot >= forceGetProcRootUnsafe
}
type forceProcThreadSelfLevel int
const (
forceProcThreadSelfDefault forceProcThreadSelfLevel = iota
forceProcSelfTask
forceProcSelf
)
var testingForceProcThreadSelf *forceProcThreadSelfLevel
func testingForceProcSelfTask() bool {
return testing.Testing() && testingForceProcThreadSelf != nil &&
*testingForceProcThreadSelf >= forceProcSelfTask
}
func testingForceProcSelf() bool {
return testing.Testing() && testingForceProcThreadSelf != nil &&
*testingForceProcThreadSelf >= forceProcSelf
}
+1 -1
View File
@@ -25,7 +25,7 @@ github.com/coreos/go-systemd/v22/dbus
# github.com/cpuguy83/go-md2man/v2 v2.0.2 # github.com/cpuguy83/go-md2man/v2 v2.0.2
## explicit; go 1.11 ## explicit; go 1.11
github.com/cpuguy83/go-md2man/v2/md2man github.com/cpuguy83/go-md2man/v2/md2man
# github.com/cyphar/filepath-securejoin v0.3.3 # github.com/cyphar/filepath-securejoin v0.3.4
## explicit; go 1.21 ## explicit; go 1.21
github.com/cyphar/filepath-securejoin github.com/cyphar/filepath-securejoin
# github.com/docker/go-units v0.5.0 # github.com/docker/go-units v0.5.0