1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

vendor: opencontainers/selinux v1.5.1

full diff: https://github.com/opencontainers/selinux/compare/v1.3.3...v1.5.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2020-05-05 15:35:03 +02:00
parent 0a5cec2833
commit a8216806ce
No known key found for this signature in database
GPG key ID: 76698F39D527CE8C
11 changed files with 418 additions and 251 deletions

View file

@ -23,7 +23,7 @@ import (
"github.com/docker/docker/runconfig" "github.com/docker/docker/runconfig"
volumemounts "github.com/docker/docker/volume/mounts" volumemounts "github.com/docker/docker/volume/mounts"
"github.com/docker/go-connections/nat" "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/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -97,9 +97,7 @@ func (daemon *Daemon) load(id string) (*container.Container, error) {
if err := ctr.FromDisk(); err != nil { if err := ctr.FromDisk(); err != nil {
return nil, err return nil, err
} }
if err := label.ReserveLabel(ctr.ProcessLabel); err != nil { selinux.ReserveLabel(ctr.ProcessLabel)
return nil, err
}
if ctr.ID != id { if ctr.ID != id {
return ctr, fmt.Errorf("Container %s is stored at %s", ctr.ID, id) return ctr, fmt.Errorf("Container %s is stored at %s", ctr.ID, id)

View file

@ -16,7 +16,7 @@ import (
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/system" "github.com/docker/docker/pkg/system"
"github.com/docker/docker/runconfig" "github.com/docker/docker/runconfig"
"github.com/opencontainers/selinux/go-selinux/label" "github.com/opencontainers/selinux/go-selinux"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -247,7 +247,7 @@ func (daemon *Daemon) generateSecurityOpt(hostConfig *containertypes.HostConfig)
pidMode := hostConfig.PidMode pidMode := hostConfig.PidMode
privileged := hostConfig.Privileged privileged := hostConfig.Privileged
if ipcMode.IsHost() || pidMode.IsHost() || privileged { if ipcMode.IsHost() || pidMode.IsHost() || privileged {
return toHostConfigSelinuxLabels(label.DisableSecOpt()), nil return toHostConfigSelinuxLabels(selinux.DisableSecOpt()), nil
} }
var ipcLabel []string var ipcLabel []string
@ -259,7 +259,7 @@ func (daemon *Daemon) generateSecurityOpt(hostConfig *containertypes.HostConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ipcLabel, err = label.DupSecOpt(c.ProcessLabel) ipcLabel, err = selinux.DupSecOpt(c.ProcessLabel)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -273,7 +273,7 @@ func (daemon *Daemon) generateSecurityOpt(hostConfig *containertypes.HostConfig)
return nil, err return nil, err
} }
pidLabel, err = label.DupSecOpt(c.ProcessLabel) pidLabel, err = selinux.DupSecOpt(c.ProcessLabel)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -168,6 +168,6 @@ github.com/morikuni/aec 39771216ff4c63d11f5e604076f9
# metrics # metrics
github.com/docker/go-metrics b619b3592b65de4f087d9f16863a7e6ff905973c # v0.0.1 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 -------- # DO NOT EDIT BELOW THIS LINE -------- reserved for downstream projects --------

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"
) )
@ -31,13 +31,13 @@ const (
// Disabled constant to indicate SELinux is disabled // Disabled constant to indicate SELinux is disabled
Disabled = -1 Disabled = -1
contextFile = "/usr/share/containers/selinux/contexts"
selinuxDir = "/etc/selinux/" selinuxDir = "/etc/selinux/"
selinuxConfig = selinuxDir + "config" selinuxConfig = selinuxDir + "config"
selinuxfsMount = "/sys/fs/selinux" selinuxfsMount = "/sys/fs/selinux"
selinuxTypeTag = "SELINUXTYPE" selinuxTypeTag = "SELINUXTYPE"
selinuxTag = "SELINUX" selinuxTag = "SELINUX"
xattrNameSelinux = "security.selinux" xattrNameSelinux = "security.selinux"
stRdOnly = 0x01
) )
type selinuxState struct { type selinuxState struct {
@ -103,13 +103,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 +118,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 +251,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 +282,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 +407,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 +427,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 +490,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
@ -656,23 +685,26 @@ func ROFileLabel() string {
return roFileLabel return roFileLabel
} }
/* func openContextFile() (*os.File, error) {
ContainerLabels returns an allocated processLabel and fileLabel to be used for if f, err := os.Open(contextFile); err == nil {
container labeling by the calling process. return f, nil
*/ }
func ContainerLabels() (processLabel string, fileLabel string) { lxcPath := filepath.Join(getSELinuxPolicyRoot(), "/contexts/lxc_contexts")
return os.Open(lxcPath)
}
var labels = loadLabels()
func loadLabels() map[string]string {
var ( var (
val, key string val, key string
bufin *bufio.Reader bufin *bufio.Reader
) )
if !GetEnabled() { labels := make(map[string]string)
return "", "" in, err := openContextFile()
}
lxcPath := fmt.Sprintf("%s/contexts/lxc_contexts", getSELinuxPolicyRoot())
in, err := os.Open(lxcPath)
if err != nil { if err != nil {
return "", "" return labels
} }
defer in.Close() defer in.Close()
@ -684,7 +716,7 @@ func ContainerLabels() (processLabel string, fileLabel string) {
if err == io.EOF { if err == io.EOF {
done = true done = true
} else { } else {
goto exit break
} }
} }
line = strings.TrimSpace(line) line = strings.TrimSpace(line)
@ -698,26 +730,64 @@ func ContainerLabels() (processLabel string, fileLabel string) {
} }
if groups := assignRegex.FindStringSubmatch(line); groups != nil { if groups := assignRegex.FindStringSubmatch(line); groups != nil {
key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
if key == "process" { labels[key] = strings.Trim(val, "\"")
processLabel = strings.Trim(val, "\"")
}
if key == "file" {
fileLabel = strings.Trim(val, "\"")
}
if key == "ro_file" {
roFileLabel = 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 "", "" return "", ""
} }
processLabel = labels["process"]
fileLabel = labels["file"]
roFileLabel = labels["ro_file"]
if processLabel == "" || fileLabel == "" {
return "", fileLabel
}
if roFileLabel == "" { if roFileLabel == "" {
roFileLabel = fileLabel roFileLabel = fileLabel
} }
exit:
return addMcs(processLabel, fileLabel)
}
func addMcs(processLabel, fileLabel string) (string, string) {
scon, _ := NewContext(processLabel) scon, _ := NewContext(processLabel)
if scon["level"] != "" { if scon["level"] != "" {
mcs := uniqMcs(1024) mcs := uniqMcs(1024)
@ -772,14 +842,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 +861,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.
@ -101,7 +113,7 @@ SetTaskLabel sets the SELinux label for the current thread, or an error.
This requires the dyntransition permission. This requires the dyntransition permission.
*/ */
func SetTaskLabel(label string) error { func SetTaskLabel(label string) error {
return nil return nil
} }
/* /*
@ -189,6 +201,18 @@ func ROFileLabel() string {
return "" 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 ContainerLabels returns an allocated processLabel and fileLabel to be used for
container labeling by the calling process. container labeling by the calling process.

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
}