diff --git a/daemon/container.go b/daemon/container.go index 62392f2ba3..68b3445849 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -23,7 +23,7 @@ import ( "github.com/docker/docker/runconfig" volumemounts "github.com/docker/docker/volume/mounts" "github.com/docker/go-connections/nat" - "github.com/opencontainers/selinux/go-selinux/label" + "github.com/opencontainers/selinux/go-selinux" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -97,9 +97,7 @@ func (daemon *Daemon) load(id string) (*container.Container, error) { if err := ctr.FromDisk(); err != nil { return nil, err } - if err := label.ReserveLabel(ctr.ProcessLabel); err != nil { - return nil, err - } + selinux.ReserveLabel(ctr.ProcessLabel) if ctr.ID != id { return ctr, fmt.Errorf("Container %s is stored at %s", ctr.ID, id) diff --git a/daemon/create.go b/daemon/create.go index d2bc6919fc..dd1160971d 100644 --- a/daemon/create.go +++ b/daemon/create.go @@ -16,7 +16,7 @@ import ( "github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/system" "github.com/docker/docker/runconfig" - "github.com/opencontainers/selinux/go-selinux/label" + "github.com/opencontainers/selinux/go-selinux" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -247,7 +247,7 @@ func (daemon *Daemon) generateSecurityOpt(hostConfig *containertypes.HostConfig) pidMode := hostConfig.PidMode privileged := hostConfig.Privileged if ipcMode.IsHost() || pidMode.IsHost() || privileged { - return toHostConfigSelinuxLabels(label.DisableSecOpt()), nil + return toHostConfigSelinuxLabels(selinux.DisableSecOpt()), nil } var ipcLabel []string @@ -259,7 +259,7 @@ func (daemon *Daemon) generateSecurityOpt(hostConfig *containertypes.HostConfig) if err != nil { return nil, err } - ipcLabel, err = label.DupSecOpt(c.ProcessLabel) + ipcLabel, err = selinux.DupSecOpt(c.ProcessLabel) if err != nil { return nil, err } @@ -273,7 +273,7 @@ func (daemon *Daemon) generateSecurityOpt(hostConfig *containertypes.HostConfig) return nil, err } - pidLabel, err = label.DupSecOpt(c.ProcessLabel) + pidLabel, err = selinux.DupSecOpt(c.ProcessLabel) if err != nil { return nil, err } diff --git a/vendor.conf b/vendor.conf index fcb7eda7bc..965125feb9 100644 --- a/vendor.conf +++ b/vendor.conf @@ -168,6 +168,6 @@ github.com/morikuni/aec 39771216ff4c63d11f5e604076f9 # metrics github.com/docker/go-metrics b619b3592b65de4f087d9f16863a7e6ff905973c # v0.0.1 -github.com/opencontainers/selinux 31f70552238c5e017d78c3f1ba65e85f593f48e0 # v1.3.3 +github.com/opencontainers/selinux 0d49ba2a6aae052c614dfe5de62a158711a6c461 # v1.5.1 # DO NOT EDIT BELOW THIS LINE -------- reserved for downstream projects -------- diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go index e178568fd3..6e38d3d324 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go @@ -1,109 +1,77 @@ -// +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 -} +import ( + "github.com/opencontainers/selinux/go-selinux" +) -func ROMountLabel() string { - return "" -} +// Deprecated: use selinux.ROFileLabel +var ROMountLabel = selinux.ROFileLabel -func GenLabels(options string) (string, string, error) { - return "", "", nil -} +// SetProcessLabel takes a process label and tells the kernel to assign the +// 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 { - return src -} +// 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. +// Deprecated: use selinux.ExecLabel +var ProcessLabel = selinux.ExecLabel -func SetProcessLabel(processLabel string) error { - return nil -} +// SetSocketLabel takes a process label and tells the kernel to assign the +// label to the next socket that gets created +// Deprecated: use selinux.SetSocketLabel +var SetSocketLabel = selinux.SetSocketLabel -func ProcessLabel() (string, error) { - return "", nil -} +// SocketLabel retrieves the current default socket label setting +// Deprecated: use selinux.SocketLabel +var SocketLabel = selinux.SocketLabel -func SetSocketLabel(processLabel string) error { - return nil -} +// SetKeyLabel takes a process label and tells the kernel to assign the +// label to the next kernel keyring that gets created +// Deprecated: use selinux.SetKeyLabel +var SetKeyLabel = selinux.SetKeyLabel -func SocketLabel() (string, error) { - return "", nil -} +// KeyLabel retrieves the current default kernel keyring label setting +// Deprecated: use selinux.KeyLabel +var KeyLabel = selinux.KeyLabel -func SetKeyLabel(processLabel string) error { - return nil -} +// FileLabel returns the label for specified path +// Deprecated: use selinux.FileLabel +var FileLabel = selinux.FileLabel -func KeyLabel() (string, error) { - return "", nil -} - -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 -} +// PidLabel will return the label of the process running with the specified pid +// Deprecated: use selinux.PidLabel +var PidLabel = selinux.PidLabel +// Init initialises the labeling system func Init() { + selinux.GetEnabled() } -// ClearLabels clears all reserved labels -func ClearLabels() { - return -} +// ClearLabels will clear all reserved labels +// Deprecated: use selinux.ClearLabels +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 { + 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 +// Deprecated: use selinux.ReleaseLabel 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 nil, nil -} - -// 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 -} +// Deprecated: use selinux.DupSecOpt +var DupSecOpt = selinux.DupSecOpt diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go index 2730fcf4a9..903829958d 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/opencontainers/selinux/go-selinux" + "github.com/pkg/errors" ) // Valid Label Options @@ -21,7 +22,7 @@ var validOptions = map[string]bool{ "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 // 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 != "" { defer func() { if Err != nil { - ReleaseLabel(mountLabel) + selinux.ReleaseLabel(mountLabel) } }() pcon, err := selinux.NewContext(processLabel) @@ -52,11 +53,11 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) { return "", mountLabel, nil } 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) 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" { @@ -67,19 +68,16 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) { mcon[con[0]] = con[1] } } - _ = ReleaseLabel(processLabel) + selinux.ReleaseLabel(processLabel) processLabel = pcon.Get() mountLabel = mcon.Get() - _ = ReserveLabel(processLabel) + selinux.ReserveLabel(processLabel) } return processLabel, mountLabel, nil } -func ROMountLabel() string { - return selinux.ROFileLabel() -} - -// DEPRECATED: The GenLabels function is only to be used during the transition to the official API. +// 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 InitLabels(strings.Fields(options)) } @@ -102,71 +100,27 @@ func FormatMountLabel(src, mountLabel string) string { 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 func SetFileLabel(path string, fileLabel string) error { - if selinux.GetEnabled() && fileLabel != "" { - return selinux.SetFileLabel(path, fileLabel) + if !selinux.GetEnabled() || fileLabel == "" { + return nil } - return nil + return selinux.SetFileLabel(path, fileLabel) } // SetFileCreateLabel tells the kernel the label for all files to be created func SetFileCreateLabel(fileLabel string) error { - if selinux.GetEnabled() { - return selinux.SetFSCreateLabel(fileLabel) + if !selinux.GetEnabled() { + return nil } - return nil + return selinux.SetFSCreateLabel(fileLabel) } // Relabel changes the label of path to the filelabel string. // It changes the MCS label to s0 if shared is true. // This will allow all containers to share the content. func Relabel(path string, fileLabel string, shared bool) error { - if !selinux.GetEnabled() { - return nil - } - - if fileLabel == "" { + if !selinux.GetEnabled() || fileLabel == "" { return nil } @@ -211,7 +165,7 @@ func Relabel(path string, fileLabel string, shared bool) error { path = strings.TrimSuffix(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 { @@ -229,48 +183,10 @@ func Relabel(path string, fileLabel string, shared bool) error { 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 // support for future container processes -func DisableSecOpt() []string { - return selinux.DisableSecOpt() -} +// Deprecated: use selinux.DisableSecOpt +var DisableSecOpt = selinux.DisableSecOpt // Validate checks that the label does not include unexpected options func Validate(label string) error { diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go new file mode 100644 index 0000000000..cda59d671b --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go @@ -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 +} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go index c51ddfda2c..9c979e5e2c 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go @@ -17,8 +17,8 @@ import ( "strconv" "strings" "sync" - "syscall" + "github.com/opencontainers/selinux/pkg/pwalk" "github.com/pkg/errors" "golang.org/x/sys/unix" ) @@ -31,13 +31,13 @@ const ( // Disabled constant to indicate SELinux is disabled Disabled = -1 + contextFile = "/usr/share/containers/selinux/contexts" selinuxDir = "/etc/selinux/" selinuxConfig = selinuxDir + "config" selinuxfsMount = "/sys/fs/selinux" selinuxTypeTag = "SELINUXTYPE" selinuxTag = "SELINUX" xattrNameSelinux = "security.selinux" - stRdOnly = 0x01 ) type selinuxState struct { @@ -103,13 +103,13 @@ func SetDisabled() { } func verifySELinuxfsMount(mnt string) bool { - var buf syscall.Statfs_t + var buf unix.Statfs_t for { - err := syscall.Statfs(mnt, &buf) + err := unix.Statfs(mnt, &buf) if err == nil { break } - if err == syscall.EAGAIN { + if err == unix.EAGAIN { continue } return false @@ -118,7 +118,7 @@ func verifySELinuxfsMount(mnt string) bool { if uint32(buf.Type) != uint32(unix.SELINUX_MAGIC) { return false } - if (buf.Flags & stRdOnly) != 0 { + if (buf.Flags & unix.ST_RDONLY) != 0 { return false } @@ -251,10 +251,10 @@ func isProcHandle(fh *os.File) error { var buf unix.Statfs_t err := unix.Fstatfs(int(fh.Fd()), &buf) 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 { - return fmt.Errorf("file %q is not on procfs", fh.Name()) + return errors.Errorf("file %q is not on procfs", fh.Name()) } return nil @@ -282,12 +282,29 @@ func readCon(fpath string) (string, error) { 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. func SetFileLabel(fpath string, label string) error { if fpath == "" { 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 nil @@ -390,7 +407,7 @@ func attrPath(attr string) string { 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) { @@ -410,6 +427,18 @@ func CanonicalizeContext(val string) (string, error) { 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) { if fpath == "" { return "", ErrEmptyPath @@ -461,17 +490,17 @@ func SocketLabel() (string, error) { // PeerLabel retrieves the label of the client on the other side of a socket 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 // label to the next kernel keyring that gets created func SetKeyLabel(label string) error { err := writeCon("/proc/self/attr/keycreate", label) - if os.IsNotExist(err) { + if os.IsNotExist(errors.Cause(err)) { return nil } - if label == "" && os.IsPermission(err) { + if label == "" && os.IsPermission(errors.Cause(err)) { return nil } return err @@ -656,23 +685,26 @@ func ROFileLabel() string { return roFileLabel } -/* -ContainerLabels returns an allocated processLabel and fileLabel to be used for -container labeling by the calling process. -*/ -func ContainerLabels() (processLabel string, fileLabel string) { +func openContextFile() (*os.File, error) { + if f, err := os.Open(contextFile); err == nil { + return f, nil + } + lxcPath := filepath.Join(getSELinuxPolicyRoot(), "/contexts/lxc_contexts") + return os.Open(lxcPath) +} + +var labels = loadLabels() + +func loadLabels() map[string]string { var ( val, key string bufin *bufio.Reader ) - if !GetEnabled() { - return "", "" - } - lxcPath := fmt.Sprintf("%s/contexts/lxc_contexts", getSELinuxPolicyRoot()) - in, err := os.Open(lxcPath) + labels := make(map[string]string) + in, err := openContextFile() if err != nil { - return "", "" + return labels } defer in.Close() @@ -684,7 +716,7 @@ func ContainerLabels() (processLabel string, fileLabel string) { if err == io.EOF { done = true } else { - goto exit + break } } line = strings.TrimSpace(line) @@ -698,26 +730,64 @@ func ContainerLabels() (processLabel string, fileLabel string) { } if groups := assignRegex.FindStringSubmatch(line); groups != nil { key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) - if key == "process" { - processLabel = strings.Trim(val, "\"") - } - if key == "file" { - fileLabel = strings.Trim(val, "\"") - } - if key == "ro_file" { - roFileLabel = strings.Trim(val, "\"") - } + labels[key] = strings.Trim(val, "\"") } } - if processLabel == "" || fileLabel == "" { + return labels +} + +/* +KVMContainerLabels returns the default processLabel and mountLabel to be used +for kvm containers by the calling process. +*/ +func KVMContainerLabels() (string, string) { + processLabel := labels["kvm_process"] + if processLabel == "" { + processLabel = labels["process"] + } + + return addMcs(processLabel, labels["file"]) +} + +/* +InitContainerLabels returns the default processLabel and file labels to be +used for containers running an init system like systemd by the calling process. +*/ +func InitContainerLabels() (string, string) { + processLabel := labels["init_process"] + if processLabel == "" { + processLabel = labels["process"] + } + + return addMcs(processLabel, labels["file"]) +} + +/* +ContainerLabels returns an allocated processLabel and fileLabel to be used for +container labeling by the calling process. +*/ +func ContainerLabels() (processLabel string, fileLabel string) { + if !GetEnabled() { return "", "" } + processLabel = labels["process"] + fileLabel = labels["file"] + roFileLabel = labels["ro_file"] + + if processLabel == "" || fileLabel == "" { + return "", fileLabel + } + if roFileLabel == "" { roFileLabel = fileLabel } -exit: + + return addMcs(processLabel, fileLabel) +} + +func addMcs(processLabel, fileLabel string) (string, string) { scon, _ := NewContext(processLabel) if scon["level"] != "" { mcs := uniqMcs(1024) @@ -772,14 +842,14 @@ func badPrefix(fpath string) error { badPrefixes := []string{"/usr"} for _, prefix := range badPrefixes { 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 } -// Chcon changes the `fpath` file object to the SELinux label `label`. -// If `fpath` is a directory and `recurse`` is true, Chcon will walk the +// Chcon changes the fpath file object to the SELinux label label. +// If fpath is a directory and recurse is true, Chcon will walk the // directory tree setting the label. func Chcon(fpath string, label string, recurse bool) error { if fpath == "" { @@ -791,19 +861,19 @@ func Chcon(fpath string, label string, recurse bool) error { if err := badPrefix(fpath); err != nil { 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) - if os.IsNotExist(e) { + // Walk a file tree can race with removal, so ignore ENOENT + if os.IsNotExist(errors.Cause(e)) { return nil } return e - } - - if recurse { - return filepath.Walk(fpath, callback) - } - - return SetFileLabel(fpath, label) + }) } // DupSecOpt takes an SELinux process label and returns security options that diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go index 0c2e1cd38e..f9f5e2061d 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go @@ -1,4 +1,4 @@ -// +build !selinux +// +build !selinux !linux package selinux @@ -35,6 +35,11 @@ func GetEnabled() bool { 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. func SetFileLabel(fpath string, label string) error { return nil @@ -88,6 +93,13 @@ func CanonicalizeContext(val string) (string, error) { 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 that are executed by the current process thread, or an error. @@ -101,7 +113,7 @@ SetTaskLabel sets the SELinux label for the current thread, or an error. This requires the dyntransition permission. */ func SetTaskLabel(label string) error { - return nil + return nil } /* @@ -189,6 +201,18 @@ func ROFileLabel() string { return "" } +// KVMContainerLabels returns the default processLabel and mountLabel to be used +// for kvm containers by the calling process. +func KVMContainerLabels() (string, string) { + return "", "" +} + +// InitContainerLabels returns the default processLabel and file labels to be +// used for containers running an init system like systemd by the calling +func InitContainerLabels() (string, string) { + return "", "" +} + /* ContainerLabels returns an allocated processLabel and fileLabel to be used for container labeling by the calling process. diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go b/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go index 4e711a9f80..de5c80ef3a 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go @@ -12,8 +12,8 @@ func lgetxattr(path string, attr string) ([]byte, error) { // Start with a 128 length byte array dest := make([]byte, 128) sz, errno := unix.Lgetxattr(path, attr, dest) - if errno == unix.ERANGE { - // Buffer too small, get the real size first + for errno == unix.ERANGE { + // Buffer too small, use zero-sized buffer to get the actual size sz, errno = unix.Lgetxattr(path, attr, []byte{}) if errno != nil { return nil, errno @@ -28,7 +28,3 @@ func lgetxattr(path string, attr string) ([]byte, error) { return dest[:sz], nil } - -func lsetxattr(path string, attr string, data []byte, flags int) error { - return unix.Lsetxattr(path, attr, data, flags) -} diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md b/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md new file mode 100644 index 0000000000..16c4dfd3ec --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md @@ -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. diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go new file mode 100644 index 0000000000..2ee0d01508 --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go @@ -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 +}