Bump github.com/containers/storage from 1.16.2 to 1.16.3

Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.16.2 to 1.16.3.
- [Release notes](https://github.com/containers/storage/releases)
- [Changelog](https://github.com/containers/storage/blob/master/docs/containers-storage-changes.md)
- [Commits](https://github.com/containers/storage/compare/v1.16.2...v1.16.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
dependabot-preview[bot]
2020-03-12 09:17:29 +00:00
committed by Daniel J Walsh
parent 78e090092b
commit 925da74118
37 changed files with 600 additions and 602 deletions

4
go.mod
View File

@ -14,7 +14,7 @@ require (
github.com/containers/conmon v2.0.10+incompatible github.com/containers/conmon v2.0.10+incompatible
github.com/containers/image/v5 v5.2.1 github.com/containers/image/v5 v5.2.1
github.com/containers/psgo v1.4.0 github.com/containers/psgo v1.4.0
github.com/containers/storage v1.16.2 github.com/containers/storage v1.16.3
github.com/coreos/go-systemd/v22 v22.0.0 github.com/coreos/go-systemd/v22 v22.0.0
github.com/cri-o/ocicni v0.1.1-0.20190920040751-deac903fd99b github.com/cri-o/ocicni v0.1.1-0.20190920040751-deac903fd99b
github.com/cyphar/filepath-securejoin v0.2.2 github.com/cyphar/filepath-securejoin v0.2.2
@ -43,7 +43,7 @@ require (
github.com/opencontainers/runc v1.0.0-rc9 github.com/opencontainers/runc v1.0.0-rc9
github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7 github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7
github.com/opencontainers/runtime-tools v0.9.0 github.com/opencontainers/runtime-tools v0.9.0
github.com/opencontainers/selinux v1.3.3 github.com/opencontainers/selinux v1.4.0
github.com/opentracing/opentracing-go v1.1.0 github.com/opentracing/opentracing-go v1.1.0
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/pmezard/go-difflib v1.0.0 github.com/pmezard/go-difflib v1.0.0

4
go.sum
View File

@ -86,6 +86,8 @@ github.com/containers/storage v1.16.1 h1:gVLVqbqaoyopLJbcQ9PQdsnm8SzVy6Vw24fofwM
github.com/containers/storage v1.16.1/go.mod h1:toFp72SLn/iyJ6YbrnrZ0bW63aH2Qw3dA8JVwL4ADPo= github.com/containers/storage v1.16.1/go.mod h1:toFp72SLn/iyJ6YbrnrZ0bW63aH2Qw3dA8JVwL4ADPo=
github.com/containers/storage v1.16.2 h1:S77Y+lmJcnGoPEZB2OOrTrRGyjT8viDCGyhVNNz78h8= github.com/containers/storage v1.16.2 h1:S77Y+lmJcnGoPEZB2OOrTrRGyjT8viDCGyhVNNz78h8=
github.com/containers/storage v1.16.2/go.mod h1:/RNmsK01ajCL+VtMSi3W8kHzpBwN+Q5gLYWgfw5wlMg= github.com/containers/storage v1.16.2/go.mod h1:/RNmsK01ajCL+VtMSi3W8kHzpBwN+Q5gLYWgfw5wlMg=
github.com/containers/storage v1.16.3 h1:bctiz1I+0TIivtXbrVmy02ZYlOA+IjKIJMzAMTBifj8=
github.com/containers/storage v1.16.3/go.mod h1:dNTv0+BaebIAOGgH34dPtwGPR+Km2fObcfOlFxYFwA0=
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/go-iptables v0.4.5 h1:DpHb9vJrZQEFMcVLFKAAGMUVX0XoRC0ptCthinRYm38= github.com/coreos/go-iptables v0.4.5 h1:DpHb9vJrZQEFMcVLFKAAGMUVX0XoRC0ptCthinRYm38=
@ -349,6 +351,8 @@ github.com/opencontainers/selinux v1.3.2 h1:DR4lL9SYVjgcTZKEZIncvDU06fKSc/eygjmN
github.com/opencontainers/selinux v1.3.2/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g= github.com/opencontainers/selinux v1.3.2/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
github.com/opencontainers/selinux v1.3.3 h1:RX0wAeqtvVSYQcr017X3pFXPkLEtB6V4NjRD7gVQgg4= github.com/opencontainers/selinux v1.3.3 h1:RX0wAeqtvVSYQcr017X3pFXPkLEtB6V4NjRD7gVQgg4=
github.com/opencontainers/selinux v1.3.3/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g= github.com/opencontainers/selinux v1.3.3/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
github.com/opencontainers/selinux v1.4.0 h1:cpiX/2wWIju/6My60T6/z9CxNG7c8xTQyEmA9fChpUo=
github.com/opencontainers/selinux v1.4.0/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
github.com/openshift/api v0.0.0-20200106203948-7ab22a2c8316 h1:enQG2QUGwug4fR1yM6hL0Fjzx6Km/exZY6RbSPwMu3o= github.com/openshift/api v0.0.0-20200106203948-7ab22a2c8316 h1:enQG2QUGwug4fR1yM6hL0Fjzx6Km/exZY6RbSPwMu3o=
github.com/openshift/api v0.0.0-20200106203948-7ab22a2c8316/go.mod h1:dv+J0b/HWai0QnMVb37/H0v36klkLBi2TNpPeWDxX10= github.com/openshift/api v0.0.0-20200106203948-7ab22a2c8316/go.mod h1:dv+J0b/HWai0QnMVb37/H0v36klkLBi2TNpPeWDxX10=
github.com/openshift/imagebuilder v1.1.1 h1:KAUR31p8UBJdfVO42azWgb+LeMAed2zaKQ19e0C0X2I= github.com/openshift/imagebuilder v1.1.1 h1:KAUR31p8UBJdfVO42azWgb+LeMAed2zaKQ19e0C0X2I=

View File

@ -1 +1 @@
1.16.2 1.16.3

View File

@ -5,10 +5,10 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
"path/filepath"
"github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/idtools"
"github.com/containers/storage/pkg/reexec" "github.com/containers/storage/pkg/reexec"
"github.com/opencontainers/selinux/pkg/pwalk"
) )
const ( const (
@ -51,16 +51,13 @@ func chownByMapsMain() {
if len(toHost.UIDs()) == 0 && len(toHost.GIDs()) == 0 { if len(toHost.UIDs()) == 0 && len(toHost.GIDs()) == 0 {
toHost = nil toHost = nil
} }
chown := func(path string, info os.FileInfo, err error) error { chown := func(path string, info os.FileInfo, _ error) error {
if err != nil {
return fmt.Errorf("error walking to %q: %v", path, err)
}
if path == "." { if path == "." {
return nil return nil
} }
return platformLChown(path, info, toHost, toContainer) return platformLChown(path, info, toHost, toContainer)
} }
if err := filepath.Walk(".", chown); err != nil { if err := pwalk.Walk(".", chown); err != nil {
fmt.Fprintf(os.Stderr, "error during chown: %v", err) fmt.Fprintf(os.Stderr, "error during chown: %v", err)
os.Exit(1) os.Exit(1)
} }

View File

@ -12,66 +12,63 @@ import (
) )
func platformLChown(path string, info os.FileInfo, toHost, toContainer *idtools.IDMappings) error { func platformLChown(path string, info os.FileInfo, toHost, toContainer *idtools.IDMappings) error {
sysinfo := info.Sys() st, ok := info.Sys().(*syscall.Stat_t)
if st, ok := sysinfo.(*syscall.Stat_t); ok { if !ok {
// Map an on-disk UID/GID pair from host to container return nil
// using the first map, then back to the host using the }
// second map. Skip that first step if they're 0, to // Map an on-disk UID/GID pair from host to container
// compensate for cases where a parent layer should // using the first map, then back to the host using the
// have had a mapped value, but didn't. // second map. Skip that first step if they're 0, to
uid, gid := int(st.Uid), int(st.Gid) // compensate for cases where a parent layer should
if toContainer != nil { // have had a mapped value, but didn't.
pair := idtools.IDPair{ uid, gid := int(st.Uid), int(st.Gid)
UID: uid, if toContainer != nil {
GID: gid, pair := idtools.IDPair{
} UID: uid,
mappedUID, mappedGID, err := toContainer.ToContainer(pair) GID: gid,
if err != nil {
if (uid != 0) || (gid != 0) {
return fmt.Errorf("error mapping host ID pair %#v for %q to container: %v", pair, path, err)
}
mappedUID, mappedGID = uid, gid
}
uid, gid = mappedUID, mappedGID
} }
if toHost != nil { mappedUID, mappedGID, err := toContainer.ToContainer(pair)
pair := idtools.IDPair{ if err != nil {
UID: uid, if (uid != 0) || (gid != 0) {
GID: gid, return fmt.Errorf("error mapping host ID pair %#v for %q to container: %v", pair, path, err)
} }
mappedPair, err := toHost.ToHost(pair) mappedUID, mappedGID = uid, gid
if err != nil { }
return fmt.Errorf("error mapping container ID pair %#v for %q to host: %v", pair, path, err) uid, gid = mappedUID, mappedGID
} }
uid, gid = mappedPair.UID, mappedPair.GID if toHost != nil {
pair := idtools.IDPair{
UID: uid,
GID: gid,
}
mappedPair, err := toHost.ToHost(pair)
if err != nil {
return fmt.Errorf("error mapping container ID pair %#v for %q to host: %v", pair, path, err)
}
uid, gid = mappedPair.UID, mappedPair.GID
}
if uid != int(st.Uid) || gid != int(st.Gid) {
cap, err := system.Lgetxattr(path, "security.capability")
if err != nil && err != system.ErrNotSupportedPlatform {
return fmt.Errorf("%s: Lgetxattr(%q): %v", os.Args[0], path, err)
} }
if uid != int(st.Uid) || gid != int(st.Gid) {
stat, err := os.Lstat(path)
if err != nil {
return fmt.Errorf("%s: lstat(%q): %v", os.Args[0], path, err)
}
cap, err := system.Lgetxattr(path, "security.capability")
if err != nil && err != system.ErrNotSupportedPlatform {
return fmt.Errorf("%s: Lgetxattr(%q): %v", os.Args[0], path, err)
}
// Make the change.
if err := syscall.Lchown(path, uid, gid); err != nil {
return fmt.Errorf("%s: chown(%q): %v", os.Args[0], path, err)
}
// Restore the SUID and SGID bits if they were originally set.
if (stat.Mode()&os.ModeSymlink == 0) && stat.Mode()&(os.ModeSetuid|os.ModeSetgid) != 0 {
if err := os.Chmod(path, stat.Mode()); err != nil {
return fmt.Errorf("%s: chmod(%q): %v", os.Args[0], path, err)
}
}
if cap != nil {
if err := system.Lsetxattr(path, "security.capability", cap, 0); err != nil {
return fmt.Errorf("%s: Lsetxattr(%q): %v", os.Args[0], path, err)
}
}
// Make the change.
if err := syscall.Lchown(path, uid, gid); err != nil {
return fmt.Errorf("%s: chown(%q): %v", os.Args[0], path, err)
} }
// Restore the SUID and SGID bits if they were originally set.
if (info.Mode()&os.ModeSymlink == 0) && info.Mode()&(os.ModeSetuid|os.ModeSetgid) != 0 {
if err := os.Chmod(path, info.Mode()); err != nil {
return fmt.Errorf("%s: chmod(%q): %v", os.Args[0], path, err)
}
}
if cap != nil {
if err := system.Lsetxattr(path, "security.capability", cap, 0); err != nil {
return fmt.Errorf("%s: Lsetxattr(%q): %v", os.Args[0], path, err)
}
}
} }
return nil return nil
} }

View File

@ -1209,7 +1209,7 @@ func (devices *DeviceSet) growFS(info *devInfo) error {
options = joinMountOptions(options, devices.mountOptions) options = joinMountOptions(options, devices.mountOptions)
if err := mount.Mount(info.DevName(), fsMountPoint, devices.BaseDeviceFilesystem, options); err != nil { if err := mount.Mount(info.DevName(), fsMountPoint, devices.BaseDeviceFilesystem, options); err != nil {
return fmt.Errorf("Error mounting '%s' on '%s': %s\n%v", info.DevName(), fsMountPoint, err, string(dmesg.Dmesg(256))) return errors.Wrapf(err, "Failed to mount; dmesg: %s", string(dmesg.Dmesg(256)))
} }
defer unix.Unmount(fsMountPoint, unix.MNT_DETACH) defer unix.Unmount(fsMountPoint, unix.MNT_DETACH)
@ -2414,7 +2414,7 @@ func (devices *DeviceSet) MountDevice(hash, path string, moptions graphdriver.Mo
options = joinMountOptions(options, label.FormatMountLabel("", moptions.MountLabel)) options = joinMountOptions(options, label.FormatMountLabel("", moptions.MountLabel))
if err := mount.Mount(info.DevName(), path, fstype, options); err != nil { if err := mount.Mount(info.DevName(), path, fstype, options); err != nil {
return fmt.Errorf("devmapper: Error mounting '%s' on '%s': %s\n%v", info.DevName(), path, err, string(dmesg.Dmesg(256))) return errors.Wrapf(err, "Failed to mount; dmesg: %s", string(dmesg.Dmesg(256)))
} }
if fstype == xfs && devices.xfsNospaceRetries != "" { if fstype == xfs && devices.xfsNospaceRetries != "" {

View File

@ -11,7 +11,7 @@ require (
github.com/mistifyio/go-zfs v2.1.1+incompatible github.com/mistifyio/go-zfs v2.1.1+incompatible
github.com/opencontainers/go-digest v1.0.0-rc1 github.com/opencontainers/go-digest v1.0.0-rc1
github.com/opencontainers/runc v1.0.0-rc9 github.com/opencontainers/runc v1.0.0-rc9
github.com/opencontainers/selinux v1.3.3 github.com/opencontainers/selinux v1.4.0
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7 github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7
github.com/sirupsen/logrus v1.4.2 github.com/sirupsen/logrus v1.4.2

View File

@ -55,8 +55,8 @@ github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
github.com/opencontainers/selinux v1.3.3 h1:RX0wAeqtvVSYQcr017X3pFXPkLEtB6V4NjRD7gVQgg4= github.com/opencontainers/selinux v1.4.0 h1:cpiX/2wWIju/6My60T6/z9CxNG7c8xTQyEmA9fChpUo=
github.com/opencontainers/selinux v1.3.3/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g= github.com/opencontainers/selinux v1.4.0/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -1,49 +0,0 @@
// +build freebsd,cgo
package mount
/*
#include <sys/mount.h>
*/
import "C"
const (
// RDONLY will mount the filesystem as read-only.
RDONLY = C.MNT_RDONLY
// NOSUID will not allow set-user-identifier or set-group-identifier bits to
// take effect.
NOSUID = C.MNT_NOSUID
// NOEXEC will not allow execution of any binaries on the mounted file system.
NOEXEC = C.MNT_NOEXEC
// SYNCHRONOUS will allow any I/O to the file system to be done synchronously.
SYNCHRONOUS = C.MNT_SYNCHRONOUS
// NOATIME will not update the file access time when reading from a file.
NOATIME = C.MNT_NOATIME
)
// These flags are unsupported.
const (
BIND = 0
DIRSYNC = 0
MANDLOCK = 0
NODEV = 0
NODIRATIME = 0
UNBINDABLE = 0
RUNBINDABLE = 0
PRIVATE = 0
RPRIVATE = 0
SHARED = 0
RSHARED = 0
SLAVE = 0
RSLAVE = 0
RBIND = 0
RELATIVE = 0
RELATIME = 0
REMOUNT = 0
STRICTATIME = 0
mntDetach = 0
)

View File

@ -82,4 +82,6 @@ const (
// it possible for the kernel to default to relatime or noatime but still // it possible for the kernel to default to relatime or noatime but still
// allow userspace to override it. // allow userspace to override it.
STRICTATIME = unix.MS_STRICTATIME STRICTATIME = unix.MS_STRICTATIME
mntDetach = unix.MNT_DETACH
) )

View File

@ -1,4 +1,4 @@
// +build !linux,!freebsd freebsd,!cgo solaris,!cgo // +build !linux
package mount package mount

View File

@ -2,12 +2,47 @@ package mount
import ( import (
"sort" "sort"
"strconv"
"strings" "strings"
"time"
"github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/fileutils"
) )
// mountError holds an error from a mount or unmount operation
type mountError struct {
op string
source, target string
flags uintptr
data string
err error
}
// Error returns a string representation of mountError
func (e *mountError) Error() string {
out := e.op + " "
if e.source != "" {
out += e.source + ":" + e.target
} else {
out += e.target
}
if e.flags != uintptr(0) {
out += ", flags: 0x" + strconv.FormatUint(uint64(e.flags), 16)
}
if e.data != "" {
out += ", data: " + e.data
}
out += ": " + e.err.Error()
return out
}
// Cause returns the underlying cause of the error
func (e *mountError) Cause() error {
return e.err
}
// GetMounts retrieves a list of mounts for the current running process. // GetMounts retrieves a list of mounts for the current running process.
func GetMounts() ([]*Info, error) { func GetMounts() ([]*Info, error) {
return parseMountTable() return parseMountTable()
@ -39,13 +74,13 @@ func Mounted(mountpoint string) (bool, error) {
// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See // specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See
// flags.go for supported option flags. // flags.go for supported option flags.
func Mount(device, target, mType, options string) error { func Mount(device, target, mType, options string) error {
flag, _ := ParseOptions(options) flag, data := ParseOptions(options)
if flag&REMOUNT != REMOUNT { if flag&REMOUNT != REMOUNT {
if mounted, err := Mounted(target); err != nil || mounted { if mounted, err := Mounted(target); err != nil || mounted {
return err return err
} }
} }
return ForceMount(device, target, mType, options) return mount(device, target, mType, uintptr(flag), data)
} }
// ForceMount will mount a filesystem according to the specified configuration, // ForceMount will mount a filesystem according to the specified configuration,
@ -60,14 +95,11 @@ func ForceMount(device, target, mType, options string) error {
// Unmount lazily unmounts a filesystem on supported platforms, otherwise // Unmount lazily unmounts a filesystem on supported platforms, otherwise
// does a normal unmount. // does a normal unmount.
func Unmount(target string) error { func Unmount(target string) error {
if mounted, err := Mounted(target); err != nil || !mounted { return unmount(target, mntDetach)
return err
}
return ForceUnmount(target)
} }
// RecursiveUnmount unmounts the target and all mounts underneath, starting with // RecursiveUnmount unmounts the target and all mounts underneath, starting with
// the deepsest mount first. // the deepest mount first.
func RecursiveUnmount(target string) error { func RecursiveUnmount(target string) error {
mounts, err := GetMounts() mounts, err := GetMounts()
if err != nil { if err != nil {
@ -75,16 +107,16 @@ func RecursiveUnmount(target string) error {
} }
// Make the deepest mount be first // Make the deepest mount be first
sort.Sort(sort.Reverse(byMountpoint(mounts))) sort.Slice(mounts, func(i, j int) bool {
return len(mounts[i].Mountpoint) > len(mounts[j].Mountpoint)
})
for i, m := range mounts { for i, m := range mounts {
if !strings.HasPrefix(m.Mountpoint, target) { if !strings.HasPrefix(m.Mountpoint, target) {
continue continue
} }
if err := Unmount(m.Mountpoint); err != nil && i == len(mounts)-1 { if err := Unmount(m.Mountpoint); err != nil && i == len(mounts)-1 {
if mounted, err := Mounted(m.Mountpoint); err != nil || mounted { return err
return err
}
// Ignore errors for submounts and continue trying to unmount others // Ignore errors for submounts and continue trying to unmount others
// The final unmount should fail if there ane any submounts remaining // The final unmount should fail if there ane any submounts remaining
} }
@ -92,15 +124,10 @@ func RecursiveUnmount(target string) error {
return nil return nil
} }
// ForceUnmount will force an unmount of the target filesystem, regardless if // ForceUnmount lazily unmounts a filesystem on supported platforms,
// it is mounted or not. // otherwise does a normal unmount.
func ForceUnmount(target string) (err error) { //
// Simple retry logic for unmount // Deprecated: please use Unmount instead, it is identical.
for i := 0; i < 10; i++ { func ForceUnmount(target string) error {
if err = unmount(target, 0); err == nil { return unmount(target, mntDetach)
return nil
}
time.Sleep(100 * time.Millisecond)
}
return nil
} }

View File

@ -14,8 +14,6 @@ import (
"fmt" "fmt"
"strings" "strings"
"unsafe" "unsafe"
"golang.org/x/sys/unix"
) )
func allocateIOVecs(options []string) []C.struct_iovec { func allocateIOVecs(options []string) []C.struct_iovec {
@ -54,7 +52,3 @@ func mount(device, target, mType string, flag uintptr, data string) error {
} }
return nil return nil
} }
func unmount(target string, flag int) error {
return unix.Unmount(target, flag)
}

View File

@ -35,25 +35,40 @@ func mount(device, target, mType string, flags uintptr, data string) error {
// Initial call applying all non-propagation flags for mount // Initial call applying all non-propagation flags for mount
// or remount with changed data // or remount with changed data
if err := unix.Mount(device, target, mType, oflags, data); err != nil { if err := unix.Mount(device, target, mType, oflags, data); err != nil {
return err return &mountError{
op: "mount",
source: device,
target: target,
flags: oflags,
data: data,
err: err,
}
} }
} }
if flags&ptypes != 0 { if flags&ptypes != 0 {
// Change the propagation type. // Change the propagation type.
if err := unix.Mount("", target, "", flags&pflags, ""); err != nil { if err := unix.Mount("", target, "", flags&pflags, ""); err != nil {
return err return &mountError{
op: "remount",
target: target,
flags: flags & pflags,
err: err,
}
} }
} }
if oflags&broflags == broflags { if oflags&broflags == broflags {
// Remount the bind to apply read only. // Remount the bind to apply read only.
return unix.Mount("", target, "", oflags|unix.MS_REMOUNT, "") if err := unix.Mount("", target, "", oflags|unix.MS_REMOUNT, ""); err != nil {
return &mountError{
op: "remount-ro",
target: target,
flags: oflags | unix.MS_REMOUNT,
err: err,
}
}
} }
return nil return nil
} }
func unmount(target string, flag int) error {
return unix.Unmount(target, flag)
}

View File

@ -1,34 +0,0 @@
// +build solaris,cgo
package mount
import (
"unsafe"
"golang.org/x/sys/unix"
)
// #include <stdlib.h>
// #include <stdio.h>
// #include <sys/mount.h>
// int Mount(const char *spec, const char *dir, int mflag,
// char *fstype, char *dataptr, int datalen, char *optptr, int optlen) {
// return mount(spec, dir, mflag, fstype, dataptr, datalen, optptr, optlen);
// }
import "C"
func mount(device, target, mType string, flag uintptr, data string) error {
spec := C.CString(device)
dir := C.CString(target)
fstype := C.CString(mType)
_, err := C.Mount(spec, dir, C.int(flag), fstype, nil, 0, nil, 0)
C.free(unsafe.Pointer(spec))
C.free(unsafe.Pointer(dir))
C.free(unsafe.Pointer(fstype))
return err
}
func unmount(target string, flag int) error {
err := unix.Unmount(target, flag)
return err
}

View File

@ -1,11 +1,7 @@
// +build !linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo // +build !linux
package mount package mount
func mount(device, target, mType string, flag uintptr, data string) error { func mount(device, target, mType string, flag uintptr, data string) error {
panic("Not implemented") panic("Not implemented")
} }
func unmount(target string, flag int) error {
panic("Not implemented")
}

View File

@ -38,17 +38,3 @@ type Info struct {
// VfsOpts represents per super block options. // VfsOpts represents per super block options.
VfsOpts string VfsOpts string
} }
type byMountpoint []*Info
func (by byMountpoint) Len() int {
return len(by)
}
func (by byMountpoint) Less(i, j int) bool {
return by[i].Mountpoint < by[j].Mountpoint
}
func (by byMountpoint) Swap(i, j int) {
by[i], by[j] = by[j], by[i]
}

View File

@ -1,5 +1,3 @@
// +build linux
package mount package mount
import ( import (
@ -7,25 +5,10 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"strconv"
"strings" "strings"
)
const ( "github.com/pkg/errors"
/* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
(1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
(1) mount ID: unique identifier of the mount (may be reused after umount)
(2) parent ID: ID of parent (or of self for the top of the mount tree)
(3) major:minor: value of st_dev for files on filesystem
(4) root: root of the mount within the filesystem
(5) mount point: mount point relative to the process's root
(6) mount options: per mount options
(7) optional fields: zero or more fields of the form "tag[:value]"
(8) separator: marks the end of the optional fields
(9) filesystem type: name of filesystem of the form "type[.subtype]"
(10) mount source: filesystem specific information or "none"
(11) super options: per super block options*/
mountinfoFormat = "%d %d %d:%d %s %s %s %s"
) )
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from // Parse /proc/self/mountinfo because comparing Dev and ino does not work from
@ -41,43 +24,85 @@ func parseMountTable() ([]*Info, error) {
} }
func parseInfoFile(r io.Reader) ([]*Info, error) { func parseInfoFile(r io.Reader) ([]*Info, error) {
var ( s := bufio.NewScanner(r)
s = bufio.NewScanner(r) out := []*Info{}
out = []*Info{}
)
for s.Scan() { for s.Scan() {
if err := s.Err(); err != nil { /*
return nil, err 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
(0)(1)(2) (3) (4) (5) (6) (7) (8) (9) (10)
(0) mount ID: unique identifier of the mount (may be reused after umount)
(1) parent ID: ID of parent (or of self for the top of the mount tree)
(2) major:minor: value of st_dev for files on filesystem
(3) root: root of the mount within the filesystem
(4) mount point: mount point relative to the process's root
(5) mount options: per mount options
(6) optional fields: zero or more fields of the form "tag[:value]"
(7) separator: marks the end of the optional fields
(8) filesystem type: name of filesystem of the form "type[.subtype]"
(9) mount source: filesystem specific information or "none"
(10) super options: per super block options
*/
text := s.Text()
fields := strings.Split(text, " ")
numFields := len(fields)
if numFields < 10 {
// should be at least 10 fields
return nil, errors.Errorf("Parsing %q failed: not enough fields (%d)", text, numFields)
} }
var ( p := &Info{}
p = &Info{} // ignore any number parsing errors, there should not be any
text = s.Text() p.ID, _ = strconv.Atoi(fields[0])
optionalFields string p.Parent, _ = strconv.Atoi(fields[1])
) mm := strings.Split(fields[2], ":")
if len(mm) != 2 {
if _, err := fmt.Sscanf(text, mountinfoFormat, return nil, fmt.Errorf("Parsing %q failed: unexpected minor:major pair %s", text, mm)
&p.ID, &p.Parent, &p.Major, &p.Minor,
&p.Root, &p.Mountpoint, &p.Opts, &optionalFields); err != nil {
return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err)
} }
// Safe as mountinfo encodes mountpoints with spaces as \040. p.Major, _ = strconv.Atoi(mm[0])
index := strings.Index(text, " - ") p.Minor, _ = strconv.Atoi(mm[1])
postSeparatorFields := strings.Fields(text[index+3:]) p.Root = fields[3]
if len(postSeparatorFields) < 3 { p.Mountpoint = fields[4]
return nil, fmt.Errorf("Error found less than 3 fields post '-' in %q", text) p.Opts = fields[5]
// one or more optional fields, when a separator (-)
i := 6
for ; i < numFields && fields[i] != "-"; i++ {
switch i {
case 6:
p.Optional = string(fields[6])
default:
/* NOTE there might be more optional fields before the separator,
such as fields[7] or fields[8], although as of Linux kernel 5.5
the only known ones are mount propagation flags in fields[6].
The correct behavior is to ignore any unknown optional fields.
*/
}
}
if i == numFields {
return nil, fmt.Errorf("Parsing %q failed: missing - separator", text)
} }
if optionalFields != "-" { // There should be 3 fields after the separator...
p.Optional = optionalFields if i+4 > numFields {
return nil, fmt.Errorf("Parsing %q failed: not enough fields after a - separator", text)
} }
// ... but in Linux <= 3.9 mounting a cifs with spaces in a share name
// (like "//serv/My Documents") _may_ end up having a space in the last field
// of mountinfo (like "unc=//serv/My Documents"). Since kernel 3.10-rc1, cifs
// option unc= is ignored, so a space should not appear. In here we ignore
// those "extra" fields caused by extra spaces.
p.Fstype = fields[i+1]
p.Source = fields[i+2]
p.VfsOpts = fields[i+3]
p.Fstype = postSeparatorFields[0]
p.Source = postSeparatorFields[1]
p.VfsOpts = strings.Join(postSeparatorFields[2:], " ")
out = append(out, p) out = append(out, p)
} }
if err := s.Err(); err != nil {
return nil, err
}
return out, nil return out, nil
} }

View File

@ -1,37 +0,0 @@
// +build solaris,cgo
package mount
/*
#include <stdio.h>
#include <sys/mnttab.h>
*/
import "C"
import (
"fmt"
)
func parseMountTable() ([]*Info, error) {
mnttab := C.fopen(C.CString(C.MNTTAB), C.CString("r"))
if mnttab == nil {
return nil, fmt.Errorf("Failed to open %s", C.MNTTAB)
}
var out []*Info
var mp C.struct_mnttab
ret := C.getmntent(mnttab, &mp)
for ret == 0 {
var mountinfo Info
mountinfo.Mountpoint = C.GoString(mp.mnt_mountp)
mountinfo.Source = C.GoString(mp.mnt_special)
mountinfo.Fstype = C.GoString(mp.mnt_fstype)
mountinfo.Opts = C.GoString(mp.mnt_mntopts)
out = append(out, &mountinfo)
ret = C.getmntent(mnttab, &mp)
}
C.fclose(mnttab)
return out, nil
}

View File

@ -1,4 +1,4 @@
// +build !windows,!linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo // +build !linux
package mount package mount

View File

@ -1,6 +0,0 @@
package mount
func parseMountTable() ([]*Info, error) {
// Do NOT return an error!
return nil, nil
}

View File

@ -1,69 +1,64 @@
// +build linux
package mount package mount
// MakeShared ensures a mounted filesystem has the SHARED mount option enabled. // MakeShared ensures a mounted filesystem has the SHARED mount option enabled.
// See the supported options in flags.go for further reference. // See the supported options in flags.go for further reference.
func MakeShared(mountPoint string) error { func MakeShared(mountPoint string) error {
return ensureMountedAs(mountPoint, "shared") return ensureMountedAs(mountPoint, SHARED)
} }
// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled. // MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled.
// See the supported options in flags.go for further reference. // See the supported options in flags.go for further reference.
func MakeRShared(mountPoint string) error { func MakeRShared(mountPoint string) error {
return ensureMountedAs(mountPoint, "rshared") return ensureMountedAs(mountPoint, RSHARED)
} }
// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled. // MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled.
// See the supported options in flags.go for further reference. // See the supported options in flags.go for further reference.
func MakePrivate(mountPoint string) error { func MakePrivate(mountPoint string) error {
return ensureMountedAs(mountPoint, "private") return ensureMountedAs(mountPoint, PRIVATE)
} }
// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option // MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option
// enabled. See the supported options in flags.go for further reference. // enabled. See the supported options in flags.go for further reference.
func MakeRPrivate(mountPoint string) error { func MakeRPrivate(mountPoint string) error {
return ensureMountedAs(mountPoint, "rprivate") return ensureMountedAs(mountPoint, RPRIVATE)
} }
// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled. // MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled.
// See the supported options in flags.go for further reference. // See the supported options in flags.go for further reference.
func MakeSlave(mountPoint string) error { func MakeSlave(mountPoint string) error {
return ensureMountedAs(mountPoint, "slave") return ensureMountedAs(mountPoint, SLAVE)
} }
// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled. // MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled.
// See the supported options in flags.go for further reference. // See the supported options in flags.go for further reference.
func MakeRSlave(mountPoint string) error { func MakeRSlave(mountPoint string) error {
return ensureMountedAs(mountPoint, "rslave") return ensureMountedAs(mountPoint, RSLAVE)
} }
// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option // MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option
// enabled. See the supported options in flags.go for further reference. // enabled. See the supported options in flags.go for further reference.
func MakeUnbindable(mountPoint string) error { func MakeUnbindable(mountPoint string) error {
return ensureMountedAs(mountPoint, "unbindable") return ensureMountedAs(mountPoint, UNBINDABLE)
} }
// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount // MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount
// option enabled. See the supported options in flags.go for further reference. // option enabled. See the supported options in flags.go for further reference.
func MakeRUnbindable(mountPoint string) error { func MakeRUnbindable(mountPoint string) error {
return ensureMountedAs(mountPoint, "runbindable") return ensureMountedAs(mountPoint, RUNBINDABLE)
} }
func ensureMountedAs(mountPoint, options string) error { func ensureMountedAs(mnt string, flags int) error {
mounted, err := Mounted(mountPoint) mounted, err := Mounted(mnt)
if err != nil { if err != nil {
return err return err
} }
if !mounted { if !mounted {
if err := Mount(mountPoint, mountPoint, "none", "bind,rw"); err != nil { if err := mount(mnt, mnt, "none", uintptr(BIND), ""); err != nil {
return err return err
} }
} }
if _, err = Mounted(mountPoint); err != nil {
return err
}
return ForceMount("", mountPoint, "none", options) return mount("", mnt, "none", uintptr(flags), "")
} }

View File

@ -1,58 +0,0 @@
// +build solaris
package mount
// MakeShared ensures a mounted filesystem has the SHARED mount option enabled.
// See the supported options in flags.go for further reference.
func MakeShared(mountPoint string) error {
return ensureMountedAs(mountPoint, "shared")
}
// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled.
// See the supported options in flags.go for further reference.
func MakeRShared(mountPoint string) error {
return ensureMountedAs(mountPoint, "rshared")
}
// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled.
// See the supported options in flags.go for further reference.
func MakePrivate(mountPoint string) error {
return ensureMountedAs(mountPoint, "private")
}
// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option
// enabled. See the supported options in flags.go for further reference.
func MakeRPrivate(mountPoint string) error {
return ensureMountedAs(mountPoint, "rprivate")
}
// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled.
// See the supported options in flags.go for further reference.
func MakeSlave(mountPoint string) error {
return ensureMountedAs(mountPoint, "slave")
}
// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled.
// See the supported options in flags.go for further reference.
func MakeRSlave(mountPoint string) error {
return ensureMountedAs(mountPoint, "rslave")
}
// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option
// enabled. See the supported options in flags.go for further reference.
func MakeUnbindable(mountPoint string) error {
return ensureMountedAs(mountPoint, "unbindable")
}
// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount
// option enabled. See the supported options in flags.go for further reference.
func MakeRUnbindable(mountPoint string) error {
return ensureMountedAs(mountPoint, "runbindable")
}
func ensureMountedAs(mountPoint, options string) error {
// TODO: Solaris does not support bind mounts.
// Evaluate lofs and also look at the relevant
// mount flags to be supported.
return nil
}

View File

@ -0,0 +1,22 @@
// +build !windows
package mount
import "golang.org/x/sys/unix"
func unmount(target string, flags int) error {
err := unix.Unmount(target, flags)
if err == nil || err == unix.EINVAL {
// Ignore "not mounted" error here. Note the same error
// can be returned if flags are invalid, so this code
// assumes that the flags value is always correct.
return nil
}
return &mountError{
op: "umount",
target: target,
flags: uintptr(flags),
err: err,
}
}

View File

@ -0,0 +1,7 @@
// +build windows
package mount
func unmount(target string, flag int) error {
panic("Not implemented")
}

View File

@ -3,6 +3,7 @@
package system package system
import ( import (
"os"
"syscall" "syscall"
) )
@ -13,7 +14,7 @@ import (
func Lstat(path string) (*StatT, error) { func Lstat(path string) (*StatT, error) {
s := &syscall.Stat_t{} s := &syscall.Stat_t{}
if err := syscall.Lstat(path, s); err != nil { if err := syscall.Lstat(path, s); err != nil {
return nil, err return nil, &os.PathError{"Lstat", path, err}
} }
return fromStatT(s) return fromStatT(s)
} }

View File

@ -34,7 +34,7 @@ func EnsureRemoveAll(dir string) error {
for { for {
err := os.RemoveAll(dir) err := os.RemoveAll(dir)
if err == nil { if err == nil {
return err return nil
} }
pe, ok := err.(*os.PathError) pe, ok := err.(*os.PathError)
@ -63,12 +63,8 @@ func EnsureRemoveAll(dir string) error {
return err return err
} }
if mounted, _ := mount.Mounted(pe.Path); mounted { if e := mount.Unmount(pe.Path); e != nil {
if e := mount.Unmount(pe.Path); e != nil { return errors.Wrapf(e, "error while removing %s", dir)
if mounted, _ := mount.Mounted(pe.Path); mounted {
return errors.Wrapf(e, "error while removing %s", dir)
}
}
} }
if exitOnErr[pe.Path] == maxRetry { if exitOnErr[pe.Path] == maxRetry {

View File

@ -3,6 +3,8 @@
package system package system
import ( import (
"os"
"strconv"
"syscall" "syscall"
) )
@ -54,7 +56,7 @@ func (s StatT) Mtim() syscall.Timespec {
func Stat(path string) (*StatT, error) { func Stat(path string) (*StatT, error) {
s := &syscall.Stat_t{} s := &syscall.Stat_t{}
if err := syscall.Stat(path, s); err != nil { if err := syscall.Stat(path, s); err != nil {
return nil, err return nil, &os.PathError{Op: "Stat", Path: path, Err: err}
} }
return fromStatT(s) return fromStatT(s)
} }
@ -66,7 +68,7 @@ func Stat(path string) (*StatT, error) {
func Fstat(fd int) (*StatT, error) { func Fstat(fd int) (*StatT, error) {
s := &syscall.Stat_t{} s := &syscall.Stat_t{}
if err := syscall.Fstat(fd, s); err != nil { if err := syscall.Fstat(fd, s); err != nil {
return nil, err return nil, &os.PathError{Op: "Fstat", Path: strconv.Itoa(fd), Err: err}
} }
return fromStatT(s) return fromStatT(s)
} }

View File

@ -1,109 +1,77 @@
// +build !selinux !linux
package label package label
// InitLabels returns the process label and file labels to be used within import (
// the container. A list of options can be passed into this function to alter "github.com/opencontainers/selinux/go-selinux"
// the labels. )
func InitLabels(options []string) (string, string, error) {
return "", "", nil
}
func ROMountLabel() string { // Deprecated: use selinux.ROFileLabel
return "" var ROMountLabel = selinux.ROFileLabel
}
func GenLabels(options string) (string, string, error) { // SetProcessLabel takes a process label and tells the kernel to assign the
return "", "", nil // label to the next program executed by the current process.
} // Deprecated: use selinux.SetExecLabel
var SetProcessLabel = selinux.SetExecLabel
func FormatMountLabel(src string, mountLabel string) string { // ProcessLabel returns the process label that the kernel will assign
return src // to the next program executed by the current process. If "" is returned
} // this indicates that the default labeling will happen for the process.
// Deprecated: use selinux.ExecLabel
var ProcessLabel = selinux.ExecLabel
func SetProcessLabel(processLabel string) error { // SetSocketLabel takes a process label and tells the kernel to assign the
return nil // label to the next socket that gets created
} // Deprecated: use selinux.SetSocketLabel
var SetSocketLabel = selinux.SetSocketLabel
func ProcessLabel() (string, error) { // SocketLabel retrieves the current default socket label setting
return "", nil // Deprecated: use selinux.SocketLabel
} var SocketLabel = selinux.SocketLabel
func SetSocketLabel(processLabel string) error { // SetKeyLabel takes a process label and tells the kernel to assign the
return nil // label to the next kernel keyring that gets created
} // Deprecated: use selinux.SetKeyLabel
var SetKeyLabel = selinux.SetKeyLabel
func SocketLabel() (string, error) { // KeyLabel retrieves the current default kernel keyring label setting
return "", nil // Deprecated: use selinux.KeyLabel
} var KeyLabel = selinux.KeyLabel
func SetKeyLabel(processLabel string) error { // FileLabel returns the label for specified path
return nil // Deprecated: use selinux.FileLabel
} var FileLabel = selinux.FileLabel
func KeyLabel() (string, error) { // PidLabel will return the label of the process running with the specified pid
return "", nil // Deprecated: use selinux.PidLabel
} var PidLabel = selinux.PidLabel
func FileLabel(path string) (string, error) {
return "", nil
}
func SetFileLabel(path string, fileLabel string) error {
return nil
}
func SetFileCreateLabel(fileLabel string) error {
return nil
}
func Relabel(path string, fileLabel string, shared bool) error {
return nil
}
func PidLabel(pid int) (string, error) {
return "", nil
}
// Init initialises the labeling system
func Init() { func Init() {
selinux.GetEnabled()
} }
// ClearLabels clears all reserved labels // ClearLabels will clear all reserved labels
func ClearLabels() { // Deprecated: use selinux.ClearLabels
return var ClearLabels = selinux.ClearLabels
}
// ReserveLabel will record the fact that the MCS label has already been used.
// This will prevent InitLabels from using the MCS label in a newly created
// container
// Deprecated: use selinux.ReserveLabel
func ReserveLabel(label string) error { func ReserveLabel(label string) error {
selinux.ReserveLabel(label)
return nil return nil
} }
// ReleaseLabel will remove the reservation of the MCS label.
// This will allow InitLabels to use the MCS label in a newly created
// containers
// Deprecated: use selinux.ReleaseLabel
func ReleaseLabel(label string) error { func ReleaseLabel(label string) error {
selinux.ReleaseLabel(label)
return nil return nil
} }
// DupSecOpt takes a process label and returns security options that // DupSecOpt takes a process label and returns security options that
// can be used to set duplicate labels on future container processes // can be used to set duplicate labels on future container processes
func DupSecOpt(src string) ([]string, error) { // Deprecated: use selinux.DupSecOpt
return nil, nil var DupSecOpt = selinux.DupSecOpt
}
// DisableSecOpt returns a security opt that can disable labeling
// support for future container processes
func DisableSecOpt() []string {
return nil
}
// Validate checks that the label does not include unexpected options
func Validate(label string) error {
return nil
}
// RelabelNeeded checks whether the user requested a relabel
func RelabelNeeded(label string) bool {
return false
}
// IsShared checks that the label includes a "shared" mark
func IsShared(label string) bool {
return false
}

View File

@ -9,6 +9,7 @@ import (
"strings" "strings"
"github.com/opencontainers/selinux/go-selinux" "github.com/opencontainers/selinux/go-selinux"
"github.com/pkg/errors"
) )
// Valid Label Options // Valid Label Options
@ -21,7 +22,7 @@ var validOptions = map[string]bool{
"level": true, "level": true,
} }
var ErrIncompatibleLabel = fmt.Errorf("Bad SELinux option z and Z can not be used together") var ErrIncompatibleLabel = errors.New("Bad SELinux option z and Z can not be used together")
// InitLabels returns the process label and file labels to be used within // InitLabels returns the process label and file labels to be used within
// the container. A list of options can be passed into this function to alter // the container. A list of options can be passed into this function to alter
@ -35,7 +36,7 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) {
if processLabel != "" { if processLabel != "" {
defer func() { defer func() {
if Err != nil { if Err != nil {
ReleaseLabel(mountLabel) selinux.ReleaseLabel(mountLabel)
} }
}() }()
pcon, err := selinux.NewContext(processLabel) pcon, err := selinux.NewContext(processLabel)
@ -52,11 +53,11 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) {
return "", mountLabel, nil return "", mountLabel, nil
} }
if i := strings.Index(opt, ":"); i == -1 { if i := strings.Index(opt, ":"); i == -1 {
return "", "", fmt.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type, filetype' followed by ':' and a value", opt) return "", "", errors.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type, filetype' followed by ':' and a value", opt)
} }
con := strings.SplitN(opt, ":", 2) con := strings.SplitN(opt, ":", 2)
if !validOptions[con[0]] { if !validOptions[con[0]] {
return "", "", fmt.Errorf("Bad label option %q, valid options 'disable, user, role, level, type, filetype'", con[0]) return "", "", errors.Errorf("Bad label option %q, valid options 'disable, user, role, level, type, filetype'", con[0])
} }
if con[0] == "filetype" { if con[0] == "filetype" {
@ -67,19 +68,16 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) {
mcon[con[0]] = con[1] mcon[con[0]] = con[1]
} }
} }
_ = ReleaseLabel(processLabel) selinux.ReleaseLabel(processLabel)
processLabel = pcon.Get() processLabel = pcon.Get()
mountLabel = mcon.Get() mountLabel = mcon.Get()
_ = ReserveLabel(processLabel) selinux.ReserveLabel(processLabel)
} }
return processLabel, mountLabel, nil return processLabel, mountLabel, nil
} }
func ROMountLabel() string { // Deprecated: The GenLabels function is only to be used during the transition
return selinux.ROFileLabel() // to the official API. Use InitLabels(strings.Fields(options)) instead.
}
// DEPRECATED: The GenLabels function is only to be used during the transition to the official API.
func GenLabels(options string) (string, string, error) { func GenLabels(options string) (string, string, error) {
return InitLabels(strings.Fields(options)) return InitLabels(strings.Fields(options))
} }
@ -102,71 +100,27 @@ func FormatMountLabel(src, mountLabel string) string {
return src return src
} }
// SetProcessLabel takes a process label and tells the kernel to assign the
// label to the next program executed by the current process.
func SetProcessLabel(processLabel string) error {
return selinux.SetExecLabel(processLabel)
}
// SetSocketLabel takes a process label and tells the kernel to assign the
// label to the next socket that gets created
func SetSocketLabel(processLabel string) error {
return selinux.SetSocketLabel(processLabel)
}
// SocketLabel retrieves the current default socket label setting
func SocketLabel() (string, error) {
return selinux.SocketLabel()
}
// SetKeyLabel takes a process label and tells the kernel to assign the
// label to the next kernel keyring that gets created
func SetKeyLabel(processLabel string) error {
return selinux.SetKeyLabel(processLabel)
}
// KeyLabel retrieves the current default kernel keyring label setting
func KeyLabel() (string, error) {
return selinux.KeyLabel()
}
// ProcessLabel returns the process label that the kernel will assign
// to the next program executed by the current process. If "" is returned
// this indicates that the default labeling will happen for the process.
func ProcessLabel() (string, error) {
return selinux.ExecLabel()
}
// FileLabel returns the label for specified path
func FileLabel(path string) (string, error) {
return selinux.FileLabel(path)
}
// SetFileLabel modifies the "path" label to the specified file label // SetFileLabel modifies the "path" label to the specified file label
func SetFileLabel(path string, fileLabel string) error { func SetFileLabel(path string, fileLabel string) error {
if selinux.GetEnabled() && fileLabel != "" { if !selinux.GetEnabled() || fileLabel == "" {
return selinux.SetFileLabel(path, fileLabel) return nil
} }
return nil return selinux.SetFileLabel(path, fileLabel)
} }
// SetFileCreateLabel tells the kernel the label for all files to be created // SetFileCreateLabel tells the kernel the label for all files to be created
func SetFileCreateLabel(fileLabel string) error { func SetFileCreateLabel(fileLabel string) error {
if selinux.GetEnabled() { if !selinux.GetEnabled() {
return selinux.SetFSCreateLabel(fileLabel) return nil
} }
return nil return selinux.SetFSCreateLabel(fileLabel)
} }
// Relabel changes the label of path to the filelabel string. // Relabel changes the label of path to the filelabel string.
// It changes the MCS label to s0 if shared is true. // It changes the MCS label to s0 if shared is true.
// This will allow all containers to share the content. // This will allow all containers to share the content.
func Relabel(path string, fileLabel string, shared bool) error { func Relabel(path string, fileLabel string, shared bool) error {
if !selinux.GetEnabled() { if !selinux.GetEnabled() || fileLabel == "" {
return nil
}
if fileLabel == "" {
return nil return nil
} }
@ -211,7 +165,7 @@ func Relabel(path string, fileLabel string, shared bool) error {
path = strings.TrimSuffix(path, "/") path = strings.TrimSuffix(path, "/")
} }
if exclude_paths[path] { if exclude_paths[path] {
return fmt.Errorf("SELinux relabeling of %s is not allowed", path) return errors.Errorf("SELinux relabeling of %s is not allowed", path)
} }
if shared { if shared {
@ -229,48 +183,10 @@ func Relabel(path string, fileLabel string, shared bool) error {
return nil return nil
} }
// PidLabel will return the label of the process running with the specified pid
func PidLabel(pid int) (string, error) {
return selinux.PidLabel(pid)
}
// Init initialises the labeling system
func Init() {
selinux.GetEnabled()
}
// ClearLabels will clear all reserved labels
func ClearLabels() {
selinux.ClearLabels()
}
// ReserveLabel will record the fact that the MCS label has already been used.
// This will prevent InitLabels from using the MCS label in a newly created
// container
func ReserveLabel(label string) error {
selinux.ReserveLabel(label)
return nil
}
// ReleaseLabel will remove the reservation of the MCS label.
// This will allow InitLabels to use the MCS label in a newly created
// containers
func ReleaseLabel(label string) error {
selinux.ReleaseLabel(label)
return nil
}
// DupSecOpt takes a process label and returns security options that
// can be used to set duplicate labels on future container processes
func DupSecOpt(src string) ([]string, error) {
return selinux.DupSecOpt(src)
}
// DisableSecOpt returns a security opt that can disable labeling // DisableSecOpt returns a security opt that can disable labeling
// support for future container processes // support for future container processes
func DisableSecOpt() []string { // Deprecated: use selinux.DisableSecOpt
return selinux.DisableSecOpt() var DisableSecOpt = selinux.DisableSecOpt
}
// Validate checks that the label does not include unexpected options // Validate checks that the label does not include unexpected options
func Validate(label string) error { func Validate(label string) error {

View File

@ -0,0 +1,54 @@
// +build !selinux !linux
package label
// InitLabels returns the process label and file labels to be used within
// the container. A list of options can be passed into this function to alter
// the labels.
func InitLabels(options []string) (string, string, error) {
return "", "", nil
}
// Deprecated: The GenLabels function is only to be used during the transition
// to the official API. Use InitLabels(strings.Fields(options)) instead.
func GenLabels(options string) (string, string, error) {
return "", "", nil
}
func FormatMountLabel(src string, mountLabel string) string {
return src
}
func SetFileLabel(path string, fileLabel string) error {
return nil
}
func SetFileCreateLabel(fileLabel string) error {
return nil
}
func Relabel(path string, fileLabel string, shared bool) error {
return nil
}
// DisableSecOpt returns a security opt that can disable labeling
// support for future container processes
func DisableSecOpt() []string {
// TODO the selinux.DisableSecOpt stub returns []string{"disable"} instead of "nil"
return nil
}
// Validate checks that the label does not include unexpected options
func Validate(label string) error {
return nil
}
// RelabelNeeded checks whether the user requested a relabel
func RelabelNeeded(label string) bool {
return false
}
// IsShared checks that the label includes a "shared" mark
func IsShared(label string) bool {
return false
}

View File

@ -17,8 +17,8 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"syscall"
"github.com/opencontainers/selinux/pkg/pwalk"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@ -37,7 +37,6 @@ const (
selinuxTypeTag = "SELINUXTYPE" selinuxTypeTag = "SELINUXTYPE"
selinuxTag = "SELINUX" selinuxTag = "SELINUX"
xattrNameSelinux = "security.selinux" xattrNameSelinux = "security.selinux"
stRdOnly = 0x01
) )
type selinuxState struct { type selinuxState struct {
@ -103,13 +102,13 @@ func SetDisabled() {
} }
func verifySELinuxfsMount(mnt string) bool { func verifySELinuxfsMount(mnt string) bool {
var buf syscall.Statfs_t var buf unix.Statfs_t
for { for {
err := syscall.Statfs(mnt, &buf) err := unix.Statfs(mnt, &buf)
if err == nil { if err == nil {
break break
} }
if err == syscall.EAGAIN { if err == unix.EAGAIN {
continue continue
} }
return false return false
@ -118,7 +117,7 @@ func verifySELinuxfsMount(mnt string) bool {
if uint32(buf.Type) != uint32(unix.SELINUX_MAGIC) { if uint32(buf.Type) != uint32(unix.SELINUX_MAGIC) {
return false return false
} }
if (buf.Flags & stRdOnly) != 0 { if (buf.Flags & unix.ST_RDONLY) != 0 {
return false return false
} }
@ -251,10 +250,10 @@ func isProcHandle(fh *os.File) error {
var buf unix.Statfs_t var buf unix.Statfs_t
err := unix.Fstatfs(int(fh.Fd()), &buf) err := unix.Fstatfs(int(fh.Fd()), &buf)
if err != nil { if err != nil {
return fmt.Errorf("statfs(%q) failed: %v", fh.Name(), err) return errors.Wrapf(err, "statfs(%q) failed", fh.Name())
} }
if buf.Type != unix.PROC_SUPER_MAGIC { if buf.Type != unix.PROC_SUPER_MAGIC {
return fmt.Errorf("file %q is not on procfs", fh.Name()) return errors.Errorf("file %q is not on procfs", fh.Name())
} }
return nil return nil
@ -282,12 +281,29 @@ func readCon(fpath string) (string, error) {
return strings.Trim(retval, "\x00"), nil return strings.Trim(retval, "\x00"), nil
} }
// ClassIndex returns the int index for an object class in the loaded policy, or -1 and an error
func ClassIndex(class string) (int, error) {
permpath := fmt.Sprintf("class/%s/index", class)
indexpath := filepath.Join(getSelinuxMountPoint(), permpath)
indexB, err := ioutil.ReadFile(indexpath)
if err != nil {
return -1, err
}
index, err := strconv.Atoi(string(indexB))
if err != nil {
return -1, err
}
return index, nil
}
// SetFileLabel sets the SELinux label for this path or returns an error. // SetFileLabel sets the SELinux label for this path or returns an error.
func SetFileLabel(fpath string, label string) error { func SetFileLabel(fpath string, label string) error {
if fpath == "" { if fpath == "" {
return ErrEmptyPath return ErrEmptyPath
} }
if err := lsetxattr(fpath, xattrNameSelinux, []byte(label), 0); err != nil { if err := unix.Lsetxattr(fpath, xattrNameSelinux, []byte(label), 0); err != nil {
return errors.Wrapf(err, "failed to set file label on %s", fpath) return errors.Wrapf(err, "failed to set file label on %s", fpath)
} }
return nil return nil
@ -390,7 +406,7 @@ func attrPath(attr string) string {
return path.Join(threadSelfPrefix, attr) return path.Join(threadSelfPrefix, attr)
} }
return path.Join("/proc/self/task/", strconv.Itoa(syscall.Gettid()), "/attr/", attr) return path.Join("/proc/self/task/", strconv.Itoa(unix.Gettid()), "/attr/", attr)
} }
func readAttr(attr string) (string, error) { func readAttr(attr string) (string, error) {
@ -410,6 +426,18 @@ func CanonicalizeContext(val string) (string, error) {
return readWriteCon(filepath.Join(getSelinuxMountPoint(), "context"), val) return readWriteCon(filepath.Join(getSelinuxMountPoint(), "context"), val)
} }
/*
ComputeCreateContext requests the type transition from source to target for class from the kernel.
*/
func ComputeCreateContext(source string, target string, class string) (string, error) {
classidx, err := ClassIndex(class)
if err != nil {
return "", err
}
return readWriteCon(filepath.Join(getSelinuxMountPoint(), "create"), fmt.Sprintf("%s %s %d", source, target, classidx))
}
func readWriteCon(fpath string, val string) (string, error) { func readWriteCon(fpath string, val string) (string, error) {
if fpath == "" { if fpath == "" {
return "", ErrEmptyPath return "", ErrEmptyPath
@ -461,17 +489,17 @@ func SocketLabel() (string, error) {
// PeerLabel retrieves the label of the client on the other side of a socket // PeerLabel retrieves the label of the client on the other side of a socket
func PeerLabel(fd uintptr) (string, error) { func PeerLabel(fd uintptr) (string, error) {
return unix.GetsockoptString(int(fd), syscall.SOL_SOCKET, syscall.SO_PEERSEC) return unix.GetsockoptString(int(fd), unix.SOL_SOCKET, unix.SO_PEERSEC)
} }
// SetKeyLabel takes a process label and tells the kernel to assign the // SetKeyLabel takes a process label and tells the kernel to assign the
// label to the next kernel keyring that gets created // label to the next kernel keyring that gets created
func SetKeyLabel(label string) error { func SetKeyLabel(label string) error {
err := writeCon("/proc/self/attr/keycreate", label) err := writeCon("/proc/self/attr/keycreate", label)
if os.IsNotExist(err) { if os.IsNotExist(errors.Cause(err)) {
return nil return nil
} }
if label == "" && os.IsPermission(err) { if label == "" && os.IsPermission(errors.Cause(err)) {
return nil return nil
} }
return err return err
@ -772,14 +800,14 @@ func badPrefix(fpath string) error {
badPrefixes := []string{"/usr"} badPrefixes := []string{"/usr"}
for _, prefix := range badPrefixes { for _, prefix := range badPrefixes {
if strings.HasPrefix(fpath, prefix) { if strings.HasPrefix(fpath, prefix) {
return fmt.Errorf("relabeling content in %s is not allowed", prefix) return errors.Errorf("relabeling content in %s is not allowed", prefix)
} }
} }
return nil return nil
} }
// Chcon changes the `fpath` file object to the SELinux label `label`. // Chcon changes the fpath file object to the SELinux label label.
// If `fpath` is a directory and `recurse`` is true, Chcon will walk the // If fpath is a directory and recurse is true, Chcon will walk the
// directory tree setting the label. // directory tree setting the label.
func Chcon(fpath string, label string, recurse bool) error { func Chcon(fpath string, label string, recurse bool) error {
if fpath == "" { if fpath == "" {
@ -791,19 +819,19 @@ func Chcon(fpath string, label string, recurse bool) error {
if err := badPrefix(fpath); err != nil { if err := badPrefix(fpath); err != nil {
return err return err
} }
callback := func(p string, info os.FileInfo, err error) error {
if !recurse {
return SetFileLabel(fpath, label)
}
return pwalk.Walk(fpath, func(p string, info os.FileInfo, err error) error {
e := SetFileLabel(p, label) e := SetFileLabel(p, label)
if os.IsNotExist(e) { // Walk a file tree can race with removal, so ignore ENOENT
if os.IsNotExist(errors.Cause(e)) {
return nil return nil
} }
return e return e
} })
if recurse {
return filepath.Walk(fpath, callback)
}
return SetFileLabel(fpath, label)
} }
// DupSecOpt takes an SELinux process label and returns security options that // DupSecOpt takes an SELinux process label and returns security options that

View File

@ -1,4 +1,4 @@
// +build !selinux // +build !selinux !linux
package selinux package selinux
@ -35,6 +35,11 @@ func GetEnabled() bool {
return false return false
} }
// ClassIndex returns the int index for an object class in the loaded policy, or -1 and an error
func ClassIndex(class string) (int, error) {
return -1, nil
}
// SetFileLabel sets the SELinux label for this path or returns an error. // SetFileLabel sets the SELinux label for this path or returns an error.
func SetFileLabel(fpath string, label string) error { func SetFileLabel(fpath string, label string) error {
return nil return nil
@ -88,6 +93,13 @@ func CanonicalizeContext(val string) (string, error) {
return "", nil return "", nil
} }
/*
ComputeCreateContext requests the type transition from source to target for class from the kernel.
*/
func ComputeCreateContext(source string, target string, class string) (string, error) {
return "", nil
}
/* /*
SetExecLabel sets the SELinux label that the kernel will use for any programs SetExecLabel sets the SELinux label that the kernel will use for any programs
that are executed by the current process thread, or an error. that are executed by the current process thread, or an error.

View File

@ -12,8 +12,8 @@ func lgetxattr(path string, attr string) ([]byte, error) {
// Start with a 128 length byte array // Start with a 128 length byte array
dest := make([]byte, 128) dest := make([]byte, 128)
sz, errno := unix.Lgetxattr(path, attr, dest) sz, errno := unix.Lgetxattr(path, attr, dest)
if errno == unix.ERANGE { for errno == unix.ERANGE {
// Buffer too small, get the real size first // Buffer too small, use zero-sized buffer to get the actual size
sz, errno = unix.Lgetxattr(path, attr, []byte{}) sz, errno = unix.Lgetxattr(path, attr, []byte{})
if errno != nil { if errno != nil {
return nil, errno return nil, errno
@ -28,7 +28,3 @@ func lgetxattr(path string, attr string) ([]byte, error) {
return dest[:sz], nil return dest[:sz], nil
} }
func lsetxattr(path string, attr string, data []byte, flags int) error {
return unix.Lsetxattr(path, attr, data, flags)
}

View File

@ -0,0 +1,42 @@
## pwalk: parallel implementation of filepath.Walk
This is a wrapper for [filepath.Walk](https://pkg.go.dev/path/filepath?tab=doc#Walk)
which may speed it up by calling multiple callback functions (WalkFunc) in parallel,
utilizing goroutines.
By default, it utilizes 2\*runtime.NumCPU() goroutines for callbacks.
This can be changed by using WalkN function which has the additional
parameter, specifying the number of goroutines (concurrency).
### Caveats
Please note the following limitations of this code:
* Unlike filepath.Walk, the order of calls is non-deterministic;
* Only primitive error handling is supported:
* filepath.SkipDir is not supported;
* no errors are ever passed to WalkFunc;
* once any error is returned from any WalkFunc instance, no more new calls
to WalkFunc are made, and the error is returned to the caller of Walk;
* if more than one walkFunc instance will return an error, only one
of such errors will be propagated and returned by Walk, others
will be silently discarded.
### Documentation
For the official documentation, see
https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalk?tab=doc
### Benchmarks
For a WalkFunc that consists solely of the return statement, this
implementation is about 10% slower than the standard library's
filepath.Walk.
Otherwise (if a WalkFunc is doing something) this is usually faster,
except when the WalkN(..., 1) is used.

View File

@ -0,0 +1,99 @@
package pwalk
import (
"os"
"path/filepath"
"runtime"
"sync"
"github.com/pkg/errors"
)
type WalkFunc = filepath.WalkFunc
// Walk is a wrapper for filepath.Walk which can call multiple walkFn
// in parallel, allowing to handle each item concurrently. A maximum of
// twice the runtime.NumCPU() walkFn will be called at any one time.
// If you want to change the maximum, use WalkN instead.
//
// The order of calls is non-deterministic.
//
// Note that this implementation only supports primitive error handling:
//
// * no errors are ever passed to WalkFn
//
// * once a walkFn returns any error, all further processing stops
// and the error is returned to the caller of Walk;
//
// * filepath.SkipDir is not supported;
//
// * if more than one walkFn instance will return an error, only one
// of such errors will be propagated and returned by Walk, others
// will be silently discarded.
//
func Walk(root string, walkFn WalkFunc) error {
return WalkN(root, walkFn, runtime.NumCPU()*2)
}
// WalkN is a wrapper for filepath.Walk which can call multiple walkFn
// in parallel, allowing to handle each item concurrently. A maximum of
// num walkFn will be called at any one time.
func WalkN(root string, walkFn WalkFunc, num int) error {
// make sure limit is sensible
if num < 1 {
return errors.Errorf("walk(%q): num must be > 0", root)
}
files := make(chan *walkArgs, 2*num)
errCh := make(chan error, 1) // get the first error, ignore others
// Start walking a tree asap
var err error
go func() {
err = filepath.Walk(root, func(p string, info os.FileInfo, err error) error {
if err != nil {
close(files)
return err
}
// add a file to the queue unless a callback sent an error
select {
case e := <-errCh:
close(files)
return e
default:
files <- &walkArgs{path: p, info: &info}
return nil
}
})
if err == nil {
close(files)
}
}()
var wg sync.WaitGroup
wg.Add(num)
for i := 0; i < num; i++ {
go func() {
for file := range files {
if e := walkFn(file.path, *file.info, nil); e != nil {
select {
case errCh <- e: // sent ok
default: // buffer full
}
}
}
wg.Done()
}()
}
wg.Wait()
return err
}
// walkArgs holds the arguments that were passed to the Walk or WalkLimit
// functions.
type walkArgs struct {
path string
info *os.FileInfo
}

5
vendor/modules.txt vendored
View File

@ -142,7 +142,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.16.2 # github.com/containers/storage v1.16.3
github.com/containers/storage github.com/containers/storage
github.com/containers/storage/drivers github.com/containers/storage/drivers
github.com/containers/storage/drivers/aufs github.com/containers/storage/drivers/aufs
@ -404,9 +404,10 @@ github.com/opencontainers/runtime-tools/generate
github.com/opencontainers/runtime-tools/generate/seccomp github.com/opencontainers/runtime-tools/generate/seccomp
github.com/opencontainers/runtime-tools/specerror github.com/opencontainers/runtime-tools/specerror
github.com/opencontainers/runtime-tools/validate github.com/opencontainers/runtime-tools/validate
# github.com/opencontainers/selinux v1.3.3 # github.com/opencontainers/selinux v1.4.0
github.com/opencontainers/selinux/go-selinux github.com/opencontainers/selinux/go-selinux
github.com/opencontainers/selinux/go-selinux/label github.com/opencontainers/selinux/go-selinux/label
github.com/opencontainers/selinux/pkg/pwalk
# github.com/openshift/api v0.0.0-20200106203948-7ab22a2c8316 # github.com/openshift/api v0.0.0-20200106203948-7ab22a2c8316
github.com/openshift/api/config/v1 github.com/openshift/api/config/v1
# github.com/openshift/imagebuilder v1.1.1 # github.com/openshift/imagebuilder v1.1.1