diff --git a/go.mod b/go.mod index d5d08982f2b..3a754c1df3d 100644 --- a/go.mod +++ b/go.mod @@ -115,7 +115,7 @@ require ( github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/runc v0.0.0-20181113202123-f000fe11ece1 github.com/opencontainers/runtime-spec v1.0.0 // indirect - github.com/opencontainers/selinux v0.0.0-20170621221121-4a2974bf1ee9 + github.com/opencontainers/selinux v1.2.2 github.com/pborman/uuid v1.2.0 github.com/pelletier/go-toml v1.2.0 // indirect github.com/pkg/errors v0.8.0 @@ -365,7 +365,7 @@ replace ( github.com/opencontainers/image-spec => github.com/opencontainers/image-spec v1.0.1 github.com/opencontainers/runc => github.com/opencontainers/runc v0.0.0-20181113202123-f000fe11ece1 github.com/opencontainers/runtime-spec => github.com/opencontainers/runtime-spec v1.0.0 - github.com/opencontainers/selinux => github.com/opencontainers/selinux v0.0.0-20170621221121-4a2974bf1ee9 + github.com/opencontainers/selinux => github.com/opencontainers/selinux v1.2.2 github.com/pborman/uuid => github.com/pborman/uuid v1.2.0 github.com/pelletier/go-toml => github.com/pelletier/go-toml v1.2.0 github.com/peterbourgon/diskv => github.com/peterbourgon/diskv v2.0.1+incompatible diff --git a/go.sum b/go.sum index 1b85dc3716e..a2b4ce35463 100644 --- a/go.sum +++ b/go.sum @@ -321,8 +321,8 @@ github.com/opencontainers/runc v0.0.0-20181113202123-f000fe11ece1 h1:3gyy8YoD+Pv github.com/opencontainers/runc v0.0.0-20181113202123-f000fe11ece1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runtime-spec v1.0.0 h1:O6L965K88AilqnxeYPks/75HLpp4IG+FjeSCI3cVdRg= github.com/opencontainers/runtime-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v0.0.0-20170621221121-4a2974bf1ee9 h1:vVmQZ2IaaEe1MiuvZQbcydTbnlTG0OnZO5/4j7VZv0A= -github.com/opencontainers/selinux v0.0.0-20170621221121-4a2974bf1ee9/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs= +github.com/opencontainers/selinux v1.2.2 h1:Kx9J6eDG5/24A6DtUquGSpJQ+m2MUTahn4FtGEe8bFg= +github.com/opencontainers/selinux v1.2.2/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/BUILD b/vendor/github.com/opencontainers/selinux/go-selinux/BUILD index 95620f16e94..f2b322d9d49 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/BUILD +++ b/vendor/github.com/opencontainers/selinux/go-selinux/BUILD @@ -2,10 +2,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", - srcs = [ - "selinux.go", - "xattrs.go", - ], + srcs = ["selinux_stub.go"], importmap = "k8s.io/kubernetes/vendor/github.com/opencontainers/selinux/go-selinux", importpath = "github.com/opencontainers/selinux/go-selinux", visibility = ["//visibility:public"], 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 6cfc5fded85..e178568fd34 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go @@ -9,7 +9,7 @@ func InitLabels(options []string) (string, string, error) { return "", "", nil } -func GetROMountLabel() string { +func ROMountLabel() string { return "" } @@ -25,7 +25,27 @@ func SetProcessLabel(processLabel string) error { return nil } -func GetFileLabel(path string) (string, error) { +func ProcessLabel() (string, error) { + return "", nil +} + +func SetSocketLabel(processLabel string) error { + return nil +} + +func SocketLabel() (string, error) { + return "", nil +} + +func SetKeyLabel(processLabel string) error { + return nil +} + +func KeyLabel() (string, error) { + return "", nil +} + +func FileLabel(path string) (string, error) { return "", nil } @@ -41,13 +61,18 @@ func Relabel(path string, fileLabel string, shared bool) error { return nil } -func GetPidLabel(pid int) (string, error) { +func PidLabel(pid int) (string, error) { return "", nil } func Init() { } +// ClearLabels clears all reserved labels +func ClearLabels() { + return +} + func ReserveLabel(label string) error { return nil } @@ -58,8 +83,8 @@ func ReleaseLabel(label string) error { // 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 { - return nil +func DupSecOpt(src string) ([]string, error) { + return nil, nil } // DisableSecOpt returns a security opt that can disable labeling 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 569dcf0841f..1eb9a6bf252 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 @@ -4,6 +4,8 @@ package label import ( "fmt" + "os" + "os/user" "strings" "github.com/opencontainers/selinux/go-selinux" @@ -24,17 +26,29 @@ var ErrIncompatibleLabel = fmt.Errorf("Bad SELinux option z and Z can not be use // the container. A list of options can be passed into this function to alter // the labels. The labels returned will include a random MCS String, that is // guaranteed to be unique. -func InitLabels(options []string) (string, string, error) { +func InitLabels(options []string) (plabel string, mlabel string, Err error) { if !selinux.GetEnabled() { return "", "", nil } processLabel, mountLabel := selinux.ContainerLabels() if processLabel != "" { - pcon := selinux.NewContext(processLabel) - mcon := selinux.NewContext(mountLabel) + defer func() { + if Err != nil { + ReleaseLabel(mountLabel) + } + }() + pcon, err := selinux.NewContext(processLabel) + if err != nil { + return "", "", err + } + + mcon, err := selinux.NewContext(mountLabel) + if err != nil { + return "", "", err + } for _, opt := range options { if opt == "disable" { - return "", "", nil + 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' followed by ':' and a value", opt) @@ -49,8 +63,10 @@ func InitLabels(options []string) (string, string, error) { mcon[con[0]] = con[1] } } + _ = ReleaseLabel(processLabel) processLabel = pcon.Get() mountLabel = mcon.Get() + _ = ReserveLabel(processLabel) } return processLabel, mountLabel, nil } @@ -85,12 +101,31 @@ func FormatMountLabel(src, mountLabel string) string { // 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 { - if processLabel == "" { - return nil - } 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. @@ -98,7 +133,7 @@ func ProcessLabel() (string, error) { return selinux.ExecLabel() } -// GetFileLabel returns the label for specified path +// FileLabel returns the label for specified path func FileLabel(path string) (string, error) { return selinux.FileLabel(path) } @@ -131,13 +166,56 @@ func Relabel(path string, fileLabel string, shared bool) error { return nil } - exclude_paths := map[string]bool{"/": true, "/usr": true, "/etc": true} + exclude_paths := map[string]bool{ + "/": true, + "/bin": true, + "/boot": true, + "/dev": true, + "/etc": true, + "/etc/passwd": true, + "/etc/pki": true, + "/etc/shadow": true, + "/home": true, + "/lib": true, + "/lib64": true, + "/media": true, + "/opt": true, + "/proc": true, + "/root": true, + "/run": true, + "/sbin": true, + "/srv": true, + "/sys": true, + "/tmp": true, + "/usr": true, + "/var": true, + "/var/lib": true, + "/var/log": true, + } + + if home := os.Getenv("HOME"); home != "" { + exclude_paths[home] = true + } + + if sudoUser := os.Getenv("SUDO_USER"); sudoUser != "" { + if usr, err := user.Lookup(sudoUser); err == nil { + exclude_paths[usr.HomeDir] = true + } + } + + if path != "/" { + path = strings.TrimSuffix(path, "/") + } if exclude_paths[path] { return fmt.Errorf("SELinux relabeling of %s is not allowed", path) } if shared { - c := selinux.NewContext(fileLabel) + c, err := selinux.NewContext(fileLabel) + if err != nil { + return err + } + c["level"] = "s0" fileLabel = c.Get() } @@ -157,6 +235,11 @@ 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 @@ -175,7 +258,7 @@ func ReleaseLabel(label string) error { // 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 { +func DupSecOpt(src string) ([]string, error) { return selinux.DupSecOpt(src) } diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go similarity index 62% rename from vendor/github.com/opencontainers/selinux/go-selinux/selinux.go rename to vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go index de9316c2e2a..d7786c33c19 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go @@ -1,13 +1,16 @@ -// +build linux +// +build selinux,linux package selinux import ( "bufio" + "bytes" "crypto/rand" "encoding/binary" + "errors" "fmt" "io" + "io/ioutil" "os" "path/filepath" "regexp" @@ -23,14 +26,16 @@ const ( // Permissive constant to indicate SELinux is in permissive mode Permissive = 0 // Disabled constant to indicate SELinux is disabled - Disabled = -1 + Disabled = -1 + selinuxDir = "/etc/selinux/" selinuxConfig = selinuxDir + "config" + selinuxfsMount = "/sys/fs/selinux" selinuxTypeTag = "SELINUXTYPE" selinuxTag = "SELINUX" - selinuxPath = "/sys/fs/selinux" xattrNameSelinux = "security.selinux" stRdOnly = 0x01 + selinuxfsMagic = 0xf97cff8c ) type selinuxState struct { @@ -43,7 +48,15 @@ type selinuxState struct { } var ( + // ErrMCSAlreadyExists is returned when trying to allocate a duplicate MCS. + ErrMCSAlreadyExists = errors.New("MCS label already exists") + // ErrEmptyPath is returned when an empty path has been specified. + ErrEmptyPath = errors.New("empty path") + // InvalidLabel is returned when an invalid label is specified. + InvalidLabel = errors.New("Invalid Label") + assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`) + roFileLabel string state = selinuxState{ mcsList: make(map[string]bool), } @@ -91,6 +104,83 @@ func (s *selinuxState) setSELinuxfs(selinuxfs string) string { return s.selinuxfs } +func verifySELinuxfsMount(mnt string) bool { + var buf syscall.Statfs_t + for { + err := syscall.Statfs(mnt, &buf) + if err == nil { + break + } + if err == syscall.EAGAIN { + continue + } + return false + } + if uint32(buf.Type) != uint32(selinuxfsMagic) { + return false + } + if (buf.Flags & stRdOnly) != 0 { + return false + } + + return true +} + +func findSELinuxfs() string { + // fast path: check the default mount first + if verifySELinuxfsMount(selinuxfsMount) { + return selinuxfsMount + } + + // check if selinuxfs is available before going the slow path + fs, err := ioutil.ReadFile("/proc/filesystems") + if err != nil { + return "" + } + if !bytes.Contains(fs, []byte("\tselinuxfs\n")) { + return "" + } + + // slow path: try to find among the mounts + f, err := os.Open("/proc/self/mountinfo") + if err != nil { + return "" + } + defer f.Close() + + scanner := bufio.NewScanner(f) + for { + mnt := findSELinuxfsMount(scanner) + if mnt == "" { // error or not found + return "" + } + if verifySELinuxfsMount(mnt) { + return mnt + } + } +} + +// findSELinuxfsMount returns a next selinuxfs mount point found, +// if there is one, or an empty string in case of EOF or error. +func findSELinuxfsMount(s *bufio.Scanner) string { + for s.Scan() { + txt := s.Text() + // The first field after - is fs type. + // Safe as spaces in mountpoints are encoded as \040 + if !strings.Contains(txt, " - selinuxfs ") { + continue + } + const mPos = 5 // mount point is 5th field + fields := strings.SplitN(txt, " ", mPos+1) + if len(fields) < mPos+1 { + continue + } + return fields[mPos-1] + } + + return "" +} + func (s *selinuxState) getSELinuxfs() string { s.Lock() selinuxfs := s.selinuxfs @@ -100,40 +190,7 @@ func (s *selinuxState) getSELinuxfs() string { return selinuxfs } - selinuxfs = "" - f, err := os.Open("/proc/self/mountinfo") - if err != nil { - return selinuxfs - } - defer f.Close() - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - txt := scanner.Text() - // Safe as mountinfo encodes mountpoints with spaces as \040. - sepIdx := strings.Index(txt, " - ") - if sepIdx == -1 { - continue - } - if !strings.Contains(txt[sepIdx:], "selinuxfs") { - continue - } - fields := strings.Split(txt, " ") - if len(fields) < 5 { - continue - } - selinuxfs = fields[4] - break - } - - if selinuxfs != "" { - var buf syscall.Statfs_t - syscall.Statfs(selinuxfs, &buf) - if (buf.Flags & stRdOnly) == 1 { - selinuxfs = "" - } - } - return s.setSELinuxfs(selinuxfs) + return s.setSELinuxfs(findSELinuxfs()) } // getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs @@ -150,7 +207,7 @@ func GetEnabled() bool { return state.getEnabled() } -func readConfig(target string) (value string) { +func readConfig(target string) string { var ( val, key string bufin *bufio.Reader @@ -192,30 +249,42 @@ func readConfig(target string) (value string) { } func getSELinuxPolicyRoot() string { - return selinuxDir + readConfig(selinuxTypeTag) + return filepath.Join(selinuxDir, readConfig(selinuxTypeTag)) } -func readCon(name string) (string, error) { - var val string +func readCon(fpath string) (string, error) { + if fpath == "" { + return "", ErrEmptyPath + } - in, err := os.Open(name) + in, err := os.Open(fpath) if err != nil { return "", err } defer in.Close() - _, err = fmt.Fscanf(in, "%s", &val) - return val, err + var retval string + if _, err := fmt.Fscanf(in, "%s", &retval); err != nil { + return "", err + } + return strings.Trim(retval, "\x00"), nil } // SetFileLabel sets the SELinux label for this path or returns an error. -func SetFileLabel(path string, label string) error { - return lsetxattr(path, xattrNameSelinux, []byte(label), 0) +func SetFileLabel(fpath string, label string) error { + if fpath == "" { + return ErrEmptyPath + } + return lsetxattr(fpath, xattrNameSelinux, []byte(label), 0) } // FileLabel returns the SELinux label for this path or returns an error. -func FileLabel(path string) (string, error) { - label, err := lgetxattr(path, xattrNameSelinux) +func FileLabel(fpath string) (string, error) { + if fpath == "" { + return "", ErrEmptyPath + } + + label, err := lgetxattr(fpath, xattrNameSelinux) if err != nil { return "", err } @@ -260,8 +329,17 @@ func ExecLabel() (string, error) { return readCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid())) } -func writeCon(name string, val string) error { - out, err := os.OpenFile(name, os.O_WRONLY, 0) +func writeCon(fpath string, val string) error { + if fpath == "" { + return ErrEmptyPath + } + if val == "" { + if !GetEnabled() { + return nil + } + } + + out, err := os.OpenFile(fpath, os.O_WRONLY, 0) if err != nil { return err } @@ -275,6 +353,37 @@ func writeCon(name string, val string) error { return err } +/* +CanonicalizeContext takes a context string and writes it to the kernel +the function then returns the context that the kernel will use. This function +can be used to see if two contexts are equivalent +*/ +func CanonicalizeContext(val string) (string, error) { + return readWriteCon(filepath.Join(getSelinuxMountPoint(), "context"), val) +} + +func readWriteCon(fpath string, val string) (string, error) { + if fpath == "" { + return "", ErrEmptyPath + } + f, err := os.OpenFile(fpath, os.O_RDWR, 0) + if err != nil { + return "", err + } + defer f.Close() + + _, err = f.Write([]byte(val)) + if err != nil { + return "", err + } + + var retval string + if _, err := fmt.Fscanf(f, "%s", &retval); err != nil { + return "", err + } + return strings.Trim(retval, "\x00"), 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. @@ -283,35 +392,81 @@ func SetExecLabel(label string) error { return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), label) } +// SetSocketLabel takes a process label and tells the kernel to assign the +// label to the next socket that gets created +func SetSocketLabel(label string) error { + return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/sockcreate", syscall.Gettid()), label) +} + +// SocketLabel retrieves the current socket label setting +func SocketLabel() (string, error) { + return readCon(fmt.Sprintf("/proc/self/task/%d/attr/sockcreate", syscall.Gettid())) +} + +// 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) { + return nil + } + if label == "" && os.IsPermission(err) && !GetEnabled() { + return nil + } + return err +} + +// KeyLabel retrieves the current kernel keyring label setting +func KeyLabel() (string, error) { + return readCon("/proc/self/attr/keycreate") +} + // Get returns the Context as a string func (c Context) Get() string { - return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"]) + if c["level"] != "" { + return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"]) + } + return fmt.Sprintf("%s:%s:%s", c["user"], c["role"], c["type"]) } // NewContext creates a new Context struct from the specified label -func NewContext(label string) Context { +func NewContext(label string) (Context, error) { c := make(Context) if len(label) != 0 { con := strings.SplitN(label, ":", 4) + if len(con) < 3 { + return c, InvalidLabel + } c["user"] = con[0] c["role"] = con[1] c["type"] = con[2] - c["level"] = con[3] + if len(con) > 3 { + c["level"] = con[3] + } } - return c + return c, nil +} + +// ClearLabels clears all reserved labels +func ClearLabels() { + state.Lock() + state.mcsList = make(map[string]bool) + state.Unlock() } // ReserveLabel reserves the MLS/MCS level component of the specified label func ReserveLabel(label string) { if len(label) != 0 { con := strings.SplitN(label, ":", 4) - mcsAdd(con[3]) + if len(con) > 3 { + mcsAdd(con[3]) + } } } func selinuxEnforcePath() string { - return fmt.Sprintf("%s/enforce", selinuxPath) + return fmt.Sprintf("%s/enforce", getSelinuxMountPoint()) } // EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled @@ -354,16 +509,22 @@ func DefaultEnforceMode() int { } func mcsAdd(mcs string) error { + if mcs == "" { + return nil + } state.Lock() defer state.Unlock() if state.mcsList[mcs] { - return fmt.Errorf("MCS Label already exists") + return ErrMCSAlreadyExists } state.mcsList[mcs] = true return nil } func mcsDelete(mcs string) { + if mcs == "" { + return + } state.Lock() defer state.Unlock() state.mcsList[mcs] = false @@ -424,14 +585,14 @@ Allowing it to be used by another process. func ReleaseLabel(label string) { if len(label) != 0 { con := strings.SplitN(label, ":", 4) - mcsDelete(con[3]) + if len(con) > 3 { + mcsDelete(con[3]) + } } } -var roFileLabel string - // ROFileLabel returns the specified SELinux readonly file label -func ROFileLabel() (fileLabel string) { +func ROFileLabel() string { return roFileLabel } @@ -497,23 +658,25 @@ func ContainerLabels() (processLabel string, fileLabel string) { roFileLabel = fileLabel } exit: - mcs := uniqMcs(1024) - scon := NewContext(processLabel) - scon["level"] = mcs - processLabel = scon.Get() - scon = NewContext(fileLabel) - scon["level"] = mcs - fileLabel = scon.Get() + scon, _ := NewContext(processLabel) + if scon["level"] != "" { + mcs := uniqMcs(1024) + scon["level"] = mcs + processLabel = scon.Get() + scon, _ = NewContext(fileLabel) + scon["level"] = mcs + fileLabel = scon.Get() + } return processLabel, fileLabel } // SecurityCheckContext validates that the SELinux label is understood by the kernel func SecurityCheckContext(val string) error { - return writeCon(fmt.Sprintf("%s.context", selinuxPath), val) + return writeCon(fmt.Sprintf("%s/context", getSelinuxMountPoint()), val) } /* -CopyLevel returns a label with the MLS/MCS level from src label replaces on +CopyLevel returns a label with the MLS/MCS level from src label replaced on the dest label. */ func CopyLevel(src, dest string) (string, error) { @@ -526,8 +689,14 @@ func CopyLevel(src, dest string) (string, error) { if err := SecurityCheckContext(dest); err != nil { return "", err } - scon := NewContext(src) - tcon := NewContext(dest) + scon, err := NewContext(src) + if err != nil { + return "", err + } + tcon, err := NewContext(dest) + if err != nil { + return "", err + } mcsDelete(tcon["level"]) mcsAdd(scon["level"]) tcon["level"] = scon["level"] @@ -536,20 +705,26 @@ func CopyLevel(src, dest string) (string, error) { // Prevent users from relabing system files func badPrefix(fpath string) error { - var badprefixes = []string{"/usr"} + if fpath == "" { + return ErrEmptyPath + } - for _, prefix := range badprefixes { - if fpath == prefix || strings.HasPrefix(fpath, fmt.Sprintf("%s/", prefix)) { + badPrefixes := []string{"/usr"} + for _, prefix := range badPrefixes { + if strings.HasPrefix(fpath, prefix) { return fmt.Errorf("relabeling content in %s is not allowed", prefix) } } return nil } -// Chcon changes the fpath file object to the SELinux label label. -// If the fpath is a directory and recurse is true Chcon will walk the -// directory tree setting the 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 +// directory tree setting the label. func Chcon(fpath string, label string, recurse bool) error { + if fpath == "" { + return ErrEmptyPath + } if label == "" { return nil } @@ -557,7 +732,11 @@ func Chcon(fpath string, label string, recurse bool) error { return err } callback := func(p string, info os.FileInfo, err error) error { - return SetFileLabel(p, label) + e := SetFileLabel(p, label) + if os.IsNotExist(e) { + return nil + } + return e } if recurse { @@ -568,26 +747,34 @@ func Chcon(fpath string, label string, recurse bool) error { } // DupSecOpt takes an SELinux process label and returns security options that -// can will set the SELinux Type and Level for future container processes -func DupSecOpt(src string) []string { +// can be used to set the SELinux Type and Level for future container processes. +func DupSecOpt(src string) ([]string, error) { if src == "" { - return nil + return nil, nil + } + con, err := NewContext(src) + if err != nil { + return nil, err } - con := NewContext(src) if con["user"] == "" || con["role"] == "" || - con["type"] == "" || - con["level"] == "" { - return nil + con["type"] == "" { + return nil, nil } - return []string{"user:" + con["user"], + dup := []string{"user:" + con["user"], "role:" + con["role"], "type:" + con["type"], - "level:" + con["level"]} + } + + if con["level"] != "" { + dup = append(dup, "level:"+con["level"]) + } + + return dup, nil } -// DisableSecOpt returns a security opt that can be used to disabling SELinux -// labeling support for future container processes +// DisableSecOpt returns a security opt that can be used to disable SELinux +// labeling support for future container processes. func DisableSecOpt() []string { return []string{"disable"} } diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go new file mode 100644 index 00000000000..79b005d194c --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go @@ -0,0 +1,217 @@ +// +build !selinux + +package selinux + +import ( + "errors" +) + +const ( + // Enforcing constant indicate SELinux is in enforcing mode + Enforcing = 1 + // Permissive constant to indicate SELinux is in permissive mode + Permissive = 0 + // Disabled constant to indicate SELinux is disabled + Disabled = -1 +) + +var ( + // ErrMCSAlreadyExists is returned when trying to allocate a duplicate MCS. + ErrMCSAlreadyExists = errors.New("MCS label already exists") + // ErrEmptyPath is returned when an empty path has been specified. + ErrEmptyPath = errors.New("empty path") +) + +// Context is a representation of the SELinux label broken into 4 parts +type Context map[string]string + +// SetDisabled disables selinux support for the package +func SetDisabled() { + return +} + +// GetEnabled returns whether selinux is currently enabled. +func GetEnabled() bool { + return false +} + +// SetFileLabel sets the SELinux label for this path or returns an error. +func SetFileLabel(fpath string, label string) error { + return nil +} + +// FileLabel returns the SELinux label for this path or returns an error. +func FileLabel(fpath string) (string, error) { + return "", nil +} + +/* +SetFSCreateLabel tells kernel the label to create all file system objects +created by this task. Setting label="" to return to default. +*/ +func SetFSCreateLabel(label string) error { + return nil +} + +/* +FSCreateLabel returns the default label the kernel which the kernel is using +for file system objects created by this task. "" indicates default. +*/ +func FSCreateLabel() (string, error) { + return "", nil +} + +// CurrentLabel returns the SELinux label of the current process thread, or an error. +func CurrentLabel() (string, error) { + return "", nil +} + +// PidLabel returns the SELinux label of the given pid, or an error. +func PidLabel(pid int) (string, error) { + return "", nil +} + +/* +ExecLabel returns the SELinux label that the kernel will use for any programs +that are executed by the current process thread, or an error. +*/ +func ExecLabel() (string, error) { + return "", nil +} + +/* +CanonicalizeContext takes a context string and writes it to the kernel +the function then returns the context that the kernel will use. This function +can be used to see if two contexts are equivalent +*/ +func CanonicalizeContext(val 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. +*/ +func SetExecLabel(label string) error { + return nil +} + +/* +SetSocketLabel sets the SELinux label that the kernel will use for any programs +that are executed by the current process thread, or an error. +*/ +func SetSocketLabel(label string) error { + return nil +} + +// SocketLabel retrieves the current socket label setting +func SocketLabel() (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 +func SetKeyLabel(label string) error { + return nil +} + +// KeyLabel retrieves the current kernel keyring label setting +func KeyLabel() (string, error) { + return "", nil +} + +// Get returns the Context as a string +func (c Context) Get() string { + return "" +} + +// NewContext creates a new Context struct from the specified label +func NewContext(label string) (Context, error) { + c := make(Context) + return c, nil +} + +// ClearLabels clears all reserved MLS/MCS levels +func ClearLabels() { + return +} + +// ReserveLabel reserves the MLS/MCS level component of the specified label +func ReserveLabel(label string) { + return +} + +// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled +func EnforceMode() int { + return Disabled +} + +/* +SetEnforceMode sets the current SELinux mode Enforcing, Permissive. +Disabled is not valid, since this needs to be set at boot time. +*/ +func SetEnforceMode(mode int) error { + return nil +} + +/* +DefaultEnforceMode returns the systems default SELinux mode Enforcing, +Permissive or Disabled. Note this is is just the default at boot time. +EnforceMode tells you the systems current mode. +*/ +func DefaultEnforceMode() int { + return Disabled +} + +/* +ReleaseLabel will unreserve the MLS/MCS Level field of the specified label. +Allowing it to be used by another process. +*/ +func ReleaseLabel(label string) { + return +} + +// ROFileLabel returns the specified SELinux readonly file label +func ROFileLabel() string { + return "" +} + +/* +ContainerLabels returns an allocated processLabel and fileLabel to be used for +container labeling by the calling process. +*/ +func ContainerLabels() (processLabel string, fileLabel string) { + return "", "" +} + +// SecurityCheckContext validates that the SELinux label is understood by the kernel +func SecurityCheckContext(val string) error { + return nil +} + +/* +CopyLevel returns a label with the MLS/MCS level from src label replaced on +the dest label. +*/ +func CopyLevel(src, dest string) (string, error) { + 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 +// directory tree setting the label. +func Chcon(fpath string, label string, recurse bool) error { + return nil +} + +// DupSecOpt takes an SELinux process label and returns security options that +// can be used to set the SELinux Type and Level for future container processes. +func DupSecOpt(src string) ([]string, error) { + return nil, nil +} + +// DisableSecOpt returns a security opt that can be used to disable SELinux +// labeling support for future container processes. +func DisableSecOpt() []string { + return []string{"disable"} +} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go b/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go index 7f2ef850490..67a9d8ee85f 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go @@ -1,4 +1,4 @@ -// +build linux +// +build selinux,linux package selinux diff --git a/vendor/modules.txt b/vendor/modules.txt index 1fbc678cfb8..021626e611d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -686,7 +686,7 @@ github.com/opencontainers/runc/libcontainer/user github.com/opencontainers/runc/libcontainer/utils # github.com/opencontainers/runtime-spec v1.0.0 => github.com/opencontainers/runtime-spec v1.0.0 github.com/opencontainers/runtime-spec/specs-go -# github.com/opencontainers/selinux v0.0.0-20170621221121-4a2974bf1ee9 => github.com/opencontainers/selinux v0.0.0-20170621221121-4a2974bf1ee9 +# github.com/opencontainers/selinux v1.2.2 => github.com/opencontainers/selinux v1.2.2 github.com/opencontainers/selinux/go-selinux github.com/opencontainers/selinux/go-selinux/label # github.com/pborman/uuid v1.2.0 => github.com/pborman/uuid v1.2.0