diff options
Diffstat (limited to 'vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go')
-rw-r--r-- | vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go | 123 |
1 files changed, 72 insertions, 51 deletions
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 9fcfd0867..0e97a0778 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go @@ -11,6 +11,7 @@ import ( "io" "io/ioutil" "os" + "path" "path/filepath" "regexp" "strconv" @@ -37,15 +38,14 @@ const ( selinuxTag = "SELINUX" xattrNameSelinux = "security.selinux" stRdOnly = 0x01 - selinuxfsMagic = 0xf97cff8c ) type selinuxState struct { - enabledSet bool - enabled bool - selinuxfsSet bool - selinuxfs string - mcsList map[string]bool + enabledSet bool + enabled bool + selinuxfsOnce sync.Once + selinuxfs string + mcsList map[string]bool sync.Mutex } @@ -62,6 +62,10 @@ var ( state = selinuxState{ mcsList: make(map[string]bool), } + + // for attrPath() + attrPathOnce sync.Once + haveThreadSelf bool ) // Context is a representation of the SELinux label broken into 4 parts @@ -98,14 +102,6 @@ func SetDisabled() { state.setEnable(false) } -func (s *selinuxState) setSELinuxfs(selinuxfs string) string { - s.Lock() - defer s.Unlock() - s.selinuxfsSet = true - s.selinuxfs = selinuxfs - return s.selinuxfs -} - func verifySELinuxfsMount(mnt string) bool { var buf syscall.Statfs_t for { @@ -118,7 +114,8 @@ func verifySELinuxfsMount(mnt string) bool { } return false } - if uint32(buf.Type) != uint32(selinuxfsMagic) { + + if buf.Type != unix.SELINUX_MAGIC { return false } if (buf.Flags & stRdOnly) != 0 { @@ -166,33 +163,29 @@ func findSELinuxfs() string { // 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() + txt := s.Bytes() // The first field after - is fs type. // Safe as spaces in mountpoints are encoded as \040 - if !strings.Contains(txt, " - selinuxfs ") { + if !bytes.Contains(txt, []byte(" - selinuxfs ")) { continue } const mPos = 5 // mount point is 5th field - fields := strings.SplitN(txt, " ", mPos+1) + fields := bytes.SplitN(txt, []byte(" "), mPos+1) if len(fields) < mPos+1 { continue } - return fields[mPos-1] + return string(fields[mPos-1]) } return "" } func (s *selinuxState) getSELinuxfs() string { - s.Lock() - selinuxfs := s.selinuxfs - selinuxfsSet := s.selinuxfsSet - s.Unlock() - if selinuxfsSet { - return selinuxfs - } + s.selinuxfsOnce.Do(func() { + s.selinuxfs = findSELinuxfs() + }) - return s.setSELinuxfs(findSELinuxfs()) + return s.selinuxfs } // getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs @@ -254,10 +247,17 @@ func getSELinuxPolicyRoot() string { return filepath.Join(selinuxDir, readConfig(selinuxTypeTag)) } -func isProcHandle(fh *os.File) (bool, error) { +func isProcHandle(fh *os.File) error { var buf unix.Statfs_t err := unix.Fstatfs(int(fh.Fd()), &buf) - return buf.Type == unix.PROC_SUPER_MAGIC, err + if err != nil { + return fmt.Errorf("statfs(%q) failed: %v", fh.Name(), err) + } + if buf.Type != unix.PROC_SUPER_MAGIC { + return fmt.Errorf("file %q is not on procfs", fh.Name()) + } + + return nil } func readCon(fpath string) (string, error) { @@ -271,10 +271,8 @@ func readCon(fpath string) (string, error) { } defer in.Close() - if ok, err := isProcHandle(in); err != nil { + if err := isProcHandle(in); err != nil { return "", err - } else if !ok { - return "", fmt.Errorf("%s not on procfs", fpath) } var retval string @@ -317,7 +315,7 @@ 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 writeCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid()), label) + return writeAttr("fscreate", label) } /* @@ -325,12 +323,12 @@ 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 readCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid())) + return readAttr("fscreate") } // CurrentLabel returns the SELinux label of the current process thread, or an error. func CurrentLabel() (string, error) { - return readCon(fmt.Sprintf("/proc/self/task/%d/attr/current", syscall.Gettid())) + return readAttr("current") } // PidLabel returns the SELinux label of the given pid, or an error. @@ -343,10 +341,10 @@ 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 readCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid())) + return readAttr("exec") } -func writeCon(fpath string, val string) error { +func writeCon(fpath, val string) error { if fpath == "" { return ErrEmptyPath } @@ -362,10 +360,8 @@ func writeCon(fpath string, val string) error { } defer out.Close() - if ok, err := isProcHandle(out); err != nil { + if err := isProcHandle(out); err != nil { return err - } else if !ok { - return fmt.Errorf("%s not on procfs", fpath) } if val != "" { @@ -379,6 +375,32 @@ func writeCon(fpath string, val string) error { return nil } +func attrPath(attr string) string { + // Linux >= 3.17 provides this + const threadSelfPrefix = "/proc/thread-self/attr" + + attrPathOnce.Do(func() { + st, err := os.Stat(threadSelfPrefix) + if err == nil && st.Mode().IsDir() { + haveThreadSelf = true + } + }) + + if haveThreadSelf { + return path.Join(threadSelfPrefix, attr) + } + + return path.Join("/proc/self/task/", strconv.Itoa(syscall.Gettid()), "/attr/", attr) +} + +func readAttr(attr string) (string, error) { + return readCon(attrPath(attr)) +} + +func writeAttr(attr, val string) error { + return writeCon(attrPath(attr), val) +} + /* CanonicalizeContext takes a context string and writes it to the kernel the function then returns the context that the kernel will use. This function @@ -415,7 +437,7 @@ 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 writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), label) + return writeAttr("exec", label) } /* @@ -423,18 +445,18 @@ SetTaskLabel sets the SELinux label for the current thread, or an error. This requires the dyntransition permission. */ func SetTaskLabel(label string) error { - return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/current", syscall.Gettid()), label) + return writeAttr("current", 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) + return writeAttr("sockcreate", label) } // SocketLabel retrieves the current socket label setting func SocketLabel() (string, error) { - return readCon(fmt.Sprintf("/proc/self/task/%d/attr/sockcreate", syscall.Gettid())) + return readAttr("sockcreate") } // PeerLabel retrieves the label of the client on the other side of a socket @@ -449,7 +471,7 @@ func SetKeyLabel(label string) error { if os.IsNotExist(err) { return nil } - if label == "" && os.IsPermission(err) && !GetEnabled() { + if label == "" && os.IsPermission(err) { return nil } return err @@ -505,19 +527,18 @@ func ReserveLabel(label string) { } func selinuxEnforcePath() string { - return fmt.Sprintf("%s/enforce", getSelinuxMountPoint()) + return path.Join(getSelinuxMountPoint(), "enforce") } // EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled func EnforceMode() int { var enforce int - enforceS, err := readCon(selinuxEnforcePath()) + enforceB, err := ioutil.ReadFile(selinuxEnforcePath()) if err != nil { return -1 } - - enforce, err = strconv.Atoi(string(enforceS)) + enforce, err = strconv.Atoi(string(enforceB)) if err != nil { return -1 } @@ -529,7 +550,7 @@ 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 writeCon(selinuxEnforcePath(), fmt.Sprintf("%d", mode)) + return ioutil.WriteFile(selinuxEnforcePath(), []byte(strconv.Itoa(mode)), 0644) } /* @@ -711,7 +732,7 @@ exit: // SecurityCheckContext validates that the SELinux label is understood by the kernel func SecurityCheckContext(val string) error { - return writeCon(fmt.Sprintf("%s/context", getSelinuxMountPoint()), val) + return ioutil.WriteFile(path.Join(getSelinuxMountPoint(), "context"), []byte(val), 0644) } /* |