If newuidmap or newgidmap fail, then check their permissions

Often distributions to not have newuidmap and netgidmap configured
to be setuid. If Podman fails to setup the user namespace, check to
see if these files doe not have the proper protection and tell the user.

[NO NEW TESTS NEEDED]

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
Daniel J Walsh 2022-04-08 10:51:39 -04:00
parent cdbc33112e
commit 2508913a0f
No known key found for this signature in database
GPG Key ID: A2DF901DABE2C028
20 changed files with 133 additions and 101 deletions

2
go.mod
View File

@ -17,7 +17,7 @@ require (
github.com/containers/image/v5 v5.21.0 github.com/containers/image/v5 v5.21.0
github.com/containers/ocicrypt v1.1.3 github.com/containers/ocicrypt v1.1.3
github.com/containers/psgo v1.7.2 github.com/containers/psgo v1.7.2
github.com/containers/storage v1.39.1-0.20220330193934-f3200eb5a5d9 github.com/containers/storage v1.39.1-0.20220406221121-28f3ba9b891d
github.com/coreos/go-systemd/v22 v22.3.2 github.com/coreos/go-systemd/v22 v22.3.2
github.com/coreos/stream-metadata-go v0.0.0-20210225230131-70edb9eb47b3 github.com/coreos/stream-metadata-go v0.0.0-20210225230131-70edb9eb47b3
github.com/cyphar/filepath-securejoin v0.2.3 github.com/cyphar/filepath-securejoin v0.2.3

3
go.sum
View File

@ -378,8 +378,9 @@ github.com/containers/storage v1.38.0/go.mod h1:lBzt28gAk5ADZuRtwdndRJyqX22vnRaX
github.com/containers/storage v1.38.2/go.mod h1:INP0RPLHWBxx+pTsO5uiHlDUGHDFvWZPWprAbAlQWPQ= github.com/containers/storage v1.38.2/go.mod h1:INP0RPLHWBxx+pTsO5uiHlDUGHDFvWZPWprAbAlQWPQ=
github.com/containers/storage v1.38.3-0.20220301151551-d06b0f81c0aa/go.mod h1:LkkL34WRi4dI4jt9Cp+ImdZi/P5i36glSHimT5CP5zM= github.com/containers/storage v1.38.3-0.20220301151551-d06b0f81c0aa/go.mod h1:LkkL34WRi4dI4jt9Cp+ImdZi/P5i36glSHimT5CP5zM=
github.com/containers/storage v1.39.0/go.mod h1:UAD0cKLouN4BOQRgZut/nMjrh/EnTCjSNPgp4ZuGWMs= github.com/containers/storage v1.39.0/go.mod h1:UAD0cKLouN4BOQRgZut/nMjrh/EnTCjSNPgp4ZuGWMs=
github.com/containers/storage v1.39.1-0.20220330193934-f3200eb5a5d9 h1:fA/2FemaDv+POCJgg+QGJm84gMEDBwL5H0lDeubDJoE=
github.com/containers/storage v1.39.1-0.20220330193934-f3200eb5a5d9/go.mod h1:IMa2AfBI+Fxxk2hQqLTGhpJX6z2pZS1/I785QJeUwUY= github.com/containers/storage v1.39.1-0.20220330193934-f3200eb5a5d9/go.mod h1:IMa2AfBI+Fxxk2hQqLTGhpJX6z2pZS1/I785QJeUwUY=
github.com/containers/storage v1.39.1-0.20220406221121-28f3ba9b891d h1:Xapzm11C1zDNPpdb/1TgTqGvnQEnDoFHUwM487r64Eo=
github.com/containers/storage v1.39.1-0.20220406221121-28f3ba9b891d/go.mod h1:UuYvGSKIdmzkjHbT/PENtxLRVGQ974nyhMbYp0KP19w=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=

View File

@ -25,6 +25,7 @@ import (
"github.com/containers/storage/pkg/unshare" "github.com/containers/storage/pkg/unshare"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/syndtr/gocapability/capability"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@ -114,8 +115,14 @@ func GetRootlessGID() int {
func tryMappingTool(uid bool, pid int, hostID int, mappings []idtools.IDMap) error { func tryMappingTool(uid bool, pid int, hostID int, mappings []idtools.IDMap) error {
var tool = "newuidmap" var tool = "newuidmap"
mode := os.ModeSetuid
cap := capability.CAP_SETUID
idtype := "setuid"
if !uid { if !uid {
tool = "newgidmap" tool = "newgidmap"
mode = os.ModeSetgid
cap = capability.CAP_SETGID
idtype = "setgid"
} }
path, err := exec.LookPath(tool) path, err := exec.LookPath(tool)
if err != nil { if err != nil {
@ -147,7 +154,13 @@ func tryMappingTool(uid bool, pid int, hostID int, mappings []idtools.IDMap) err
if output, err := cmd.CombinedOutput(); err != nil { if output, err := cmd.CombinedOutput(); err != nil {
logrus.Errorf("running `%s`: %s", strings.Join(args, " "), output) logrus.Errorf("running `%s`: %s", strings.Join(args, " "), output)
return errors.Wrapf(err, "cannot setup namespace using %q", path) errorStr := fmt.Sprintf("cannot setup namespace using %q", path)
if isSet, err := unshare.IsSetID(cmd.Path, mode, cap); err != nil {
logrus.Errorf("Failed to check for %s on %s: %v", idtype, path, err)
} else if !isSet {
errorStr = fmt.Sprintf("%s: should have %s or have filecaps %s", errorStr, idtype, idtype)
}
return errors.Wrapf(err, errorStr)
} }
return nil return nil
} }

View File

@ -117,7 +117,7 @@ lint_task:
env: env:
CIRRUS_WORKING_DIR: "/go/src/github.com/containers/storage" CIRRUS_WORKING_DIR: "/go/src/github.com/containers/storage"
container: container:
image: golang:1.15 image: golang:1.16
modules_cache: modules_cache:
fingerprint_script: cat go.sum fingerprint_script: cat go.sum
folder: $GOPATH/pkg/mod folder: $GOPATH/pkg/mod
@ -154,7 +154,7 @@ meta_task:
vendor_task: vendor_task:
container: container:
image: golang:1.15 image: golang:1.16
modules_cache: modules_cache:
fingerprint_script: cat go.sum fingerprint_script: cat go.sum
folder: $GOPATH/pkg/mod folder: $GOPATH/pkg/mod
@ -172,6 +172,6 @@ success_task:
- meta - meta
- vendor - vendor
container: container:
image: golang:1.15 image: golang:1.16
clone_script: 'mkdir -p "$CIRRUS_WORKING_DIR"' # Source code not needed clone_script: 'mkdir -p "$CIRRUS_WORKING_DIR"' # Source code not needed
script: /bin/true script: /bin/true

View File

@ -1,3 +1,4 @@
//go:build linux
// +build linux // +build linux
/* /*
@ -26,6 +27,7 @@ import (
"bufio" "bufio"
"fmt" "fmt"
"io" "io"
"io/fs"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
@ -649,11 +651,11 @@ func (a *Driver) mounted(mountpoint string) (bool, error) {
// Cleanup aufs and unmount all mountpoints // Cleanup aufs and unmount all mountpoints
func (a *Driver) Cleanup() error { func (a *Driver) Cleanup() error {
var dirs []string var dirs []string
if err := filepath.Walk(a.mntPath(), func(path string, info os.FileInfo, err error) error { if err := filepath.WalkDir(a.mntPath(), func(path string, d fs.DirEntry, err error) error {
if err != nil { if err != nil {
return err return err
} }
if !info.IsDir() { if !d.IsDir() {
return nil return nil
} }
dirs = append(dirs, path) dirs = append(dirs, path)

View File

@ -1,3 +1,4 @@
//go:build linux && cgo
// +build linux,cgo // +build linux,cgo
package btrfs package btrfs
@ -16,6 +17,7 @@ import "C"
import ( import (
"fmt" "fmt"
"io/fs"
"io/ioutil" "io/ioutil"
"math" "math"
"os" "os"
@ -256,7 +258,7 @@ func subvolDelete(dirpath, name string, quotaEnabled bool) error {
var args C.struct_btrfs_ioctl_vol_args var args C.struct_btrfs_ioctl_vol_args
// walk the btrfs subvolumes // walk the btrfs subvolumes
walkSubvolumes := func(p string, f os.FileInfo, err error) error { walkSubvolumes := func(p string, d fs.DirEntry, err error) error {
if err != nil { if err != nil {
if os.IsNotExist(err) && p != fullPath { if os.IsNotExist(err) && p != fullPath {
// missing most likely because the path was a subvolume that got removed in the previous iteration // missing most likely because the path was a subvolume that got removed in the previous iteration
@ -267,20 +269,20 @@ func subvolDelete(dirpath, name string, quotaEnabled bool) error {
} }
// we want to check children only so skip itself // we want to check children only so skip itself
// it will be removed after the filepath walk anyways // it will be removed after the filepath walk anyways
if f.IsDir() && p != fullPath { if d.IsDir() && p != fullPath {
sv, err := isSubvolume(p) sv, err := isSubvolume(p)
if err != nil { if err != nil {
return fmt.Errorf("Failed to test if %s is a btrfs subvolume: %v", p, err) return fmt.Errorf("Failed to test if %s is a btrfs subvolume: %v", p, err)
} }
if sv { if sv {
if err := subvolDelete(path.Dir(p), f.Name(), quotaEnabled); err != nil { if err := subvolDelete(path.Dir(p), d.Name(), quotaEnabled); err != nil {
return fmt.Errorf("Failed to destroy btrfs child subvolume (%s) of parent (%s): %v", p, dirpath, err) return fmt.Errorf("Failed to destroy btrfs child subvolume (%s) of parent (%s): %v", p, dirpath, err)
} }
} }
} }
return nil return nil
} }
if err := filepath.Walk(path.Join(dirpath, name), walkSubvolumes); err != nil { if err := filepath.WalkDir(path.Join(dirpath, name), walkSubvolumes); err != nil {
return fmt.Errorf("Recursively walking subvolumes for %s failed: %v", dirpath, err) return fmt.Errorf("Recursively walking subvolumes for %s failed: %v", dirpath, err)
} }

View File

@ -84,7 +84,7 @@ func (c *platformChowner) LChown(path string, info os.FileInfo, toHost, toContai
} }
if uid != int(st.Uid) || gid != int(st.Gid) { if uid != int(st.Uid) || gid != int(st.Gid) {
cap, err := system.Lgetxattr(path, "security.capability") cap, err := system.Lgetxattr(path, "security.capability")
if err != nil && !errors.Is(err, system.EOPNOTSUPP) && err != system.ErrNotSupportedPlatform { if err != nil && !errors.Is(err, system.EOPNOTSUPP) && !errors.Is(err, system.EOVERFLOW) && err != system.ErrNotSupportedPlatform {
return fmt.Errorf("%s: %v", os.Args[0], err) return fmt.Errorf("%s: %v", os.Args[0], err)
} }

View File

@ -1,3 +1,4 @@
//go:build linux && cgo
// +build linux,cgo // +build linux,cgo
package devmapper package devmapper
@ -6,6 +7,7 @@ import (
"bufio" "bufio"
"fmt" "fmt"
"io" "io"
"io/fs"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
@ -419,40 +421,35 @@ func (devices *DeviceSet) constructDeviceIDMap() {
} }
} }
func (devices *DeviceSet) deviceFileWalkFunction(path string, finfo os.FileInfo) error { func (devices *DeviceSet) deviceFileWalkFunction(path string, name string) error {
// Skip some of the meta files which are not device files. // Skip some of the meta files which are not device files.
if strings.HasSuffix(finfo.Name(), ".migrated") { if strings.HasSuffix(name, ".migrated") {
logrus.Debugf("devmapper: Skipping file %s", path) logrus.Debugf("devmapper: Skipping file %s", path)
return nil return nil
} }
if strings.HasPrefix(finfo.Name(), ".") { if strings.HasPrefix(name, ".") {
logrus.Debugf("devmapper: Skipping file %s", path) logrus.Debugf("devmapper: Skipping file %s", path)
return nil return nil
} }
if finfo.Name() == deviceSetMetaFile { if name == deviceSetMetaFile {
logrus.Debugf("devmapper: Skipping file %s", path) logrus.Debugf("devmapper: Skipping file %s", path)
return nil return nil
} }
if finfo.Name() == transactionMetaFile { if name == transactionMetaFile {
logrus.Debugf("devmapper: Skipping file %s", path) logrus.Debugf("devmapper: Skipping file %s", path)
return nil return nil
} }
logrus.Debugf("devmapper: Loading data for file %s", path) logrus.Debugf("devmapper: Loading data for file %s", path)
hash := finfo.Name()
if hash == base {
hash = ""
}
// Include deleted devices also as cleanup delete device logic // Include deleted devices also as cleanup delete device logic
// will go through it and see if there are any deleted devices. // will go through it and see if there are any deleted devices.
if _, err := devices.lookupDevice(hash); err != nil { if _, err := devices.lookupDevice(name); err != nil {
return fmt.Errorf("devmapper: Error looking up device %s:%v", hash, err) return fmt.Errorf("devmapper: Error looking up device %s:%v", name, err)
} }
return nil return nil
@ -462,21 +459,21 @@ func (devices *DeviceSet) loadDeviceFilesOnStart() error {
logrus.Debug("devmapper: loadDeviceFilesOnStart()") logrus.Debug("devmapper: loadDeviceFilesOnStart()")
defer logrus.Debug("devmapper: loadDeviceFilesOnStart() END") defer logrus.Debug("devmapper: loadDeviceFilesOnStart() END")
var scan = func(path string, info os.FileInfo, err error) error { var scan = func(path string, d fs.DirEntry, err error) error {
if err != nil { if err != nil {
logrus.Debugf("devmapper: Can't walk the file %s", path) logrus.Debugf("devmapper: Can't walk the file %s", path)
return nil return nil
} }
// Skip any directories // Skip any directories
if info.IsDir() { if d.IsDir() {
return nil return nil
} }
return devices.deviceFileWalkFunction(path, info) return devices.deviceFileWalkFunction(path, d.Name())
} }
return filepath.Walk(devices.metadataDir(), scan) return filepath.WalkDir(devices.metadataDir(), scan)
} }
// Should be called with devices.Lock() held. // Should be called with devices.Lock() held.

View File

@ -1,42 +0,0 @@
// +build !go1.16
package overlay
import (
"os"
"path/filepath"
"strings"
"github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/system"
)
func scanForMountProgramIndicators(home string) (detected bool, err error) {
err = filepath.Walk(home, func(path string, info os.FileInfo, err error) error {
if detected {
return filepath.SkipDir
}
if err != nil {
return err
}
basename := filepath.Base(path)
if strings.HasPrefix(basename, archive.WhiteoutPrefix) {
detected = true
return filepath.SkipDir
}
if info.IsDir() {
xattrs, err := system.Llistxattr(path)
if err != nil {
return err
}
for _, xattr := range xattrs {
if strings.HasPrefix(xattr, "user.fuseoverlayfs.") || strings.HasPrefix(xattr, "user.containers.") {
detected = true
return filepath.SkipDir
}
}
}
return nil
})
return detected, err
}

View File

@ -1,9 +1,9 @@
go 1.14 go 1.16
module github.com/containers/storage module github.com/containers/storage
require ( require (
github.com/BurntSushi/toml v1.0.0 github.com/BurntSushi/toml v1.1.0
github.com/Microsoft/go-winio v0.5.2 github.com/Microsoft/go-winio v0.5.2
github.com/Microsoft/hcsshim v0.9.2 github.com/Microsoft/hcsshim v0.9.2
github.com/containerd/stargz-snapshotter/estargz v0.11.3 github.com/containerd/stargz-snapshotter/estargz v0.11.3

View File

@ -36,8 +36,8 @@ github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935
github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=

View File

@ -7,6 +7,7 @@ import (
"compress/bzip2" "compress/bzip2"
"fmt" "fmt"
"io" "io"
"io/fs"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -863,14 +864,14 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
rebaseName := options.RebaseNames[include] rebaseName := options.RebaseNames[include]
walkRoot := getWalkRoot(srcPath, include) walkRoot := getWalkRoot(srcPath, include)
filepath.Walk(walkRoot, func(filePath string, f os.FileInfo, err error) error { filepath.WalkDir(walkRoot, func(filePath string, d fs.DirEntry, err error) error {
if err != nil { if err != nil {
logrus.Errorf("Tar: Can't stat file %s to tar: %s", srcPath, err) logrus.Errorf("Tar: Can't stat file %s to tar: %s", srcPath, err)
return nil return nil
} }
relFilePath, err := filepath.Rel(srcPath, filePath) relFilePath, err := filepath.Rel(srcPath, filePath)
if err != nil || (!options.IncludeSourceDir && relFilePath == "." && f.IsDir()) { if err != nil || (!options.IncludeSourceDir && relFilePath == "." && d.IsDir()) {
// Error getting relative path OR we are looking // Error getting relative path OR we are looking
// at the source directory path. Skip in both situations. // at the source directory path. Skip in both situations.
return nil return nil
@ -903,7 +904,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
// dir. If so then we can't skip this dir. // dir. If so then we can't skip this dir.
// Its not a dir then so we can just return/skip. // Its not a dir then so we can just return/skip.
if !f.IsDir() { if !d.IsDir() {
return nil return nil
} }

View File

@ -1,9 +1,11 @@
//go:build !linux
// +build !linux // +build !linux
package archive package archive
import ( import (
"fmt" "fmt"
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
@ -41,7 +43,7 @@ func collectFileInfoForChanges(oldDir, newDir string, oldIDMap, newIDMap *idtool
func collectFileInfo(sourceDir string, idMappings *idtools.IDMappings) (*FileInfo, error) { func collectFileInfo(sourceDir string, idMappings *idtools.IDMappings) (*FileInfo, error) {
root := newRootFileInfo(idMappings) root := newRootFileInfo(idMappings)
err := filepath.Walk(sourceDir, func(path string, f os.FileInfo, err error) error { err := filepath.WalkDir(sourceDir, func(path string, d fs.DirEntry, err error) error {
if err != nil { if err != nil {
return err return err
} }

View File

@ -4,6 +4,7 @@ import (
"archive/tar" "archive/tar"
"fmt" "fmt"
"io" "io"
"io/fs"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -134,7 +135,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
if err != nil { if err != nil {
return 0, err return 0, err
} }
err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { err = filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
err = nil // parent was deleted err = nil // parent was deleted

View File

@ -1,8 +1,10 @@
//go:build linux || darwin || freebsd || solaris
// +build linux darwin freebsd solaris // +build linux darwin freebsd solaris
package directory package directory
import ( import (
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"syscall" "syscall"
@ -21,7 +23,7 @@ func Size(dir string) (size int64, err error) {
func Usage(dir string) (usage *DiskUsage, err error) { func Usage(dir string) (usage *DiskUsage, err error) {
usage = &DiskUsage{} usage = &DiskUsage{}
data := make(map[uint64]struct{}) data := make(map[uint64]struct{})
err = filepath.Walk(dir, func(d string, fileInfo os.FileInfo, err error) error { err = filepath.WalkDir(dir, func(d string, entry fs.DirEntry, err error) error {
if err != nil { if err != nil {
// if dir does not exist, Usage() returns the error. // if dir does not exist, Usage() returns the error.
// if dir/x disappeared while walking, Usage() ignores dir/x. // if dir/x disappeared while walking, Usage() ignores dir/x.
@ -31,8 +33,9 @@ func Usage(dir string) (usage *DiskUsage, err error) {
return err return err
} }
if fileInfo == nil { fileInfo, err := entry.Info()
return nil if err != nil {
return err
} }
// Check inode to only count the sizes of files with multiple hard links once. // Check inode to only count the sizes of files with multiple hard links once.
@ -44,9 +47,8 @@ func Usage(dir string) (usage *DiskUsage, err error) {
// inode is not a uint64 on all platforms. Cast it to avoid issues. // inode is not a uint64 on all platforms. Cast it to avoid issues.
data[uint64(inode)] = struct{}{} data[uint64(inode)] = struct{}{}
// Ignore directory sizes // Ignore directory sizes
if fileInfo.IsDir() { if entry.IsDir() {
return nil return nil
} }

View File

@ -1,8 +1,10 @@
//go:build windows
// +build windows // +build windows
package directory package directory
import ( import (
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
) )
@ -19,11 +21,11 @@ func Size(dir string) (size int64, err error) {
// Usage walks a directory tree and returns its total size in bytes and the number of inodes. // Usage walks a directory tree and returns its total size in bytes and the number of inodes.
func Usage(dir string) (usage *DiskUsage, err error) { func Usage(dir string) (usage *DiskUsage, err error) {
usage = &DiskUsage{} usage = &DiskUsage{}
err = filepath.Walk(dir, func(d string, fileInfo os.FileInfo, err error) error { err = filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
if err != nil { if err != nil {
// if dir does not exist, Size() returns the error. // if dir does not exist, Size() returns the error.
// if dir/x disappeared while walking, Size() ignores dir/x. // if dir/x disappeared while walking, Size() ignores dir/x.
if os.IsNotExist(err) && d != dir { if os.IsNotExist(err) && path != dir {
return nil return nil
} }
return err return err
@ -32,16 +34,15 @@ func Usage(dir string) (usage *DiskUsage, err error) {
usage.InodeCount++ usage.InodeCount++
// Ignore directory sizes // Ignore directory sizes
if fileInfo == nil { if d.IsDir() {
return nil return nil
} }
s := fileInfo.Size() fileInfo, err := d.Info()
if fileInfo.IsDir() || s == 0 { if err != nil {
return nil return err
} }
usage.Size += fileInfo.Size()
usage.Size += s
return nil return nil
}) })

View File

@ -13,6 +13,9 @@ const (
// Operation not supported // Operation not supported
EOPNOTSUPP unix.Errno = unix.EOPNOTSUPP EOPNOTSUPP unix.Errno = unix.EOPNOTSUPP
// Value is too small or too large for maximum size allowed
EOVERFLOW unix.Errno = unix.EOVERFLOW
) )
// Lgetxattr retrieves the value of the extended attribute identified by attr // Lgetxattr retrieves the value of the extended attribute identified by attr

View File

@ -10,6 +10,9 @@ const (
// Operation not supported // Operation not supported
EOPNOTSUPP syscall.Errno = syscall.Errno(0) EOPNOTSUPP syscall.Errno = syscall.Errno(0)
// Value is too small or too large for maximum size allowed
EOVERFLOW syscall.Errno = syscall.Errno(0)
) )
// Lgetxattr is not supported on platforms other than linux. // Lgetxattr is not supported on platforms other than linux.

View File

@ -1,3 +1,4 @@
//go:build linux
// +build linux // +build linux
package unshare package unshare
@ -76,6 +77,28 @@ func getRootlessGID() int {
return os.Getegid() return os.Getegid()
} }
// IsSetID checks if specified path has correct FileMode (Setuid|SETGID) or the
// matching file capabilitiy
func IsSetID(path string, modeid os.FileMode, capid capability.Cap) (bool, error) {
info, err := os.Stat(path)
if err != nil {
return false, err
}
mode := info.Mode()
if mode&modeid == modeid {
return true, nil
}
cap, err := capability.NewFile2(path)
if err != nil {
return false, err
}
if err := cap.Load(); err != nil {
return false, err
}
return cap.Get(capability.EFFECTIVE, capid), nil
}
func (c *Cmd) Start() error { func (c *Cmd) Start() error {
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
@ -215,15 +238,26 @@ func (c *Cmd) Start() error {
gidmapSet := false gidmapSet := false
// Set the GID map. // Set the GID map.
if c.UseNewgidmap { if c.UseNewgidmap {
cmd := exec.Command("newgidmap", append([]string{pidString}, strings.Fields(strings.Replace(g.String(), "\n", " ", -1))...)...) path, err := exec.LookPath("newgidmap")
if err != nil {
return errors.Wrapf(err, "error finding newgidmap")
}
cmd := exec.Command(path, append([]string{pidString}, strings.Fields(strings.Replace(g.String(), "\n", " ", -1))...)...)
g.Reset() g.Reset()
cmd.Stdout = g cmd.Stdout = g
cmd.Stderr = g cmd.Stderr = g
err := cmd.Run() if err := cmd.Run(); err == nil {
if err == nil {
gidmapSet = true gidmapSet = true
} else { } else {
logrus.Warnf("Error running newgidmap: %v: %s", err, g.String()) logrus.Warnf("Error running newgidmap: %v: %s", err, g.String())
isSetgid, err := IsSetID(path, os.ModeSetgid, capability.CAP_SETGID)
if err != nil {
logrus.Warnf("Failed to check for setgid on %s: %v", path, err)
} else {
if !isSetgid {
logrus.Warnf("%s should be setgid or have filecaps setgid", path)
}
}
logrus.Warnf("Falling back to single mapping") logrus.Warnf("Falling back to single mapping")
g.Reset() g.Reset()
g.Write([]byte(fmt.Sprintf("0 %d 1\n", os.Getegid()))) g.Write([]byte(fmt.Sprintf("0 %d 1\n", os.Getegid())))
@ -262,17 +296,29 @@ func (c *Cmd) Start() error {
fmt.Fprintf(u, "%d %d %d\n", m.ContainerID, m.HostID, m.Size) fmt.Fprintf(u, "%d %d %d\n", m.ContainerID, m.HostID, m.Size)
} }
uidmapSet := false uidmapSet := false
// Set the GID map. // Set the UID map.
if c.UseNewuidmap { if c.UseNewuidmap {
cmd := exec.Command("newuidmap", append([]string{pidString}, strings.Fields(strings.Replace(u.String(), "\n", " ", -1))...)...) path, err := exec.LookPath("newuidmap")
if err != nil {
return errors.Wrapf(err, "error finding newuidmap")
}
cmd := exec.Command(path, append([]string{pidString}, strings.Fields(strings.Replace(u.String(), "\n", " ", -1))...)...)
u.Reset() u.Reset()
cmd.Stdout = u cmd.Stdout = u
cmd.Stderr = u cmd.Stderr = u
err := cmd.Run() if err := cmd.Run(); err == nil {
if err == nil {
uidmapSet = true uidmapSet = true
} else { } else {
logrus.Warnf("Error running newuidmap: %v: %s", err, u.String()) logrus.Warnf("Error running newuidmap: %v: %s", err, u.String())
isSetuid, err := IsSetID(path, os.ModeSetuid, capability.CAP_SETUID)
if err != nil {
logrus.Warnf("Failed to check for setuid on %s: %v", path, err)
} else {
if !isSetuid {
logrus.Warnf("%s should be setuid or have filecaps setuid", path)
}
}
logrus.Warnf("Falling back to single mapping") logrus.Warnf("Falling back to single mapping")
u.Reset() u.Reset()
u.Write([]byte(fmt.Sprintf("0 %d 1\n", os.Geteuid()))) u.Write([]byte(fmt.Sprintf("0 %d 1\n", os.Geteuid())))

2
vendor/modules.txt vendored
View File

@ -233,7 +233,7 @@ github.com/containers/psgo/internal/dev
github.com/containers/psgo/internal/host github.com/containers/psgo/internal/host
github.com/containers/psgo/internal/proc github.com/containers/psgo/internal/proc
github.com/containers/psgo/internal/process github.com/containers/psgo/internal/process
# github.com/containers/storage v1.39.1-0.20220330193934-f3200eb5a5d9 # github.com/containers/storage v1.39.1-0.20220406221121-28f3ba9b891d
## explicit ## explicit
github.com/containers/storage github.com/containers/storage
github.com/containers/storage/drivers github.com/containers/storage/drivers