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

vendor: update opencontainers/selinux v1.3.3

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

- go-selinux/SetKeyLabel: fix for RHEL7 kernels
- getSELinuxfs: optimize/simplify using sync.Once
- xattr: use x/sys/unix, simplify
- Use /proc/thread-self if available
- Fix EnforceMode, SetEnforceMode, and SecurityCheckContext

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2020-02-28 01:29:55 +01:00
parent 38f52c9fec
commit fa67cff34b
No known key found for this signature in database
GPG key ID: 76698F39D527CE8C
3 changed files with 87 additions and 110 deletions

View file

@ -161,6 +161,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 4defb1c884d2f4f9c890c615380f20f7fc215cf3 # v1.3.1 github.com/opencontainers/selinux 31f70552238c5e017d78c3f1ba65e85f593f48e0 # v1.3.3
# DO NOT EDIT BELOW THIS LINE -------- reserved for downstream projects -------- # DO NOT EDIT BELOW THIS LINE -------- reserved for downstream projects --------

View file

@ -11,6 +11,7 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"path"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strconv" "strconv"
@ -37,13 +38,12 @@ const (
selinuxTag = "SELINUX" selinuxTag = "SELINUX"
xattrNameSelinux = "security.selinux" xattrNameSelinux = "security.selinux"
stRdOnly = 0x01 stRdOnly = 0x01
selinuxfsMagic = 0xf97cff8c
) )
type selinuxState struct { type selinuxState struct {
enabledSet bool enabledSet bool
enabled bool enabled bool
selinuxfsSet bool selinuxfsOnce sync.Once
selinuxfs string selinuxfs string
mcsList map[string]bool mcsList map[string]bool
sync.Mutex sync.Mutex
@ -62,6 +62,10 @@ var (
state = selinuxState{ state = selinuxState{
mcsList: make(map[string]bool), mcsList: make(map[string]bool),
} }
// for attrPath()
attrPathOnce sync.Once
haveThreadSelf bool
) )
// Context is a representation of the SELinux label broken into 4 parts // Context is a representation of the SELinux label broken into 4 parts
@ -98,14 +102,6 @@ func SetDisabled() {
state.setEnable(false) 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 { func verifySELinuxfsMount(mnt string) bool {
var buf syscall.Statfs_t var buf syscall.Statfs_t
for { for {
@ -118,7 +114,8 @@ func verifySELinuxfsMount(mnt string) bool {
} }
return false return false
} }
if uint32(buf.Type) != uint32(selinuxfsMagic) {
if uint32(buf.Type) != uint32(unix.SELINUX_MAGIC) {
return false return false
} }
if (buf.Flags & stRdOnly) != 0 { 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. // if there is one, or an empty string in case of EOF or error.
func findSELinuxfsMount(s *bufio.Scanner) string { func findSELinuxfsMount(s *bufio.Scanner) string {
for s.Scan() { for s.Scan() {
txt := s.Text() txt := s.Bytes()
// The first field after - is fs type. // The first field after - is fs type.
// Safe as spaces in mountpoints are encoded as \040 // Safe as spaces in mountpoints are encoded as \040
if !strings.Contains(txt, " - selinuxfs ") { if !bytes.Contains(txt, []byte(" - selinuxfs ")) {
continue continue
} }
const mPos = 5 // mount point is 5th field 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 { if len(fields) < mPos+1 {
continue continue
} }
return fields[mPos-1] return string(fields[mPos-1])
} }
return "" return ""
} }
func (s *selinuxState) getSELinuxfs() string { func (s *selinuxState) getSELinuxfs() string {
s.Lock() s.selinuxfsOnce.Do(func() {
selinuxfs := s.selinuxfs s.selinuxfs = findSELinuxfs()
selinuxfsSet := s.selinuxfsSet })
s.Unlock()
if selinuxfsSet {
return selinuxfs
}
return s.setSELinuxfs(findSELinuxfs()) return s.selinuxfs
} }
// getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs // getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs
@ -254,10 +247,17 @@ func getSELinuxPolicyRoot() string {
return filepath.Join(selinuxDir, readConfig(selinuxTypeTag)) return filepath.Join(selinuxDir, readConfig(selinuxTypeTag))
} }
func isProcHandle(fh *os.File) (bool, error) { 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)
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) { func readCon(fpath string) (string, error) {
@ -271,10 +271,8 @@ func readCon(fpath string) (string, error) {
} }
defer in.Close() defer in.Close()
if ok, err := isProcHandle(in); err != nil { if err := isProcHandle(in); err != nil {
return "", err return "", err
} else if !ok {
return "", fmt.Errorf("%s not on procfs", fpath)
} }
var retval string 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. created by this task. Setting label="" to return to default.
*/ */
func SetFSCreateLabel(label string) error { 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. for file system objects created by this task. "" indicates default.
*/ */
func FSCreateLabel() (string, error) { 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. // CurrentLabel returns the SELinux label of the current process thread, or an error.
func CurrentLabel() (string, 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. // 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. that are executed by the current process thread, or an error.
*/ */
func ExecLabel() (string, 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 == "" { if fpath == "" {
return ErrEmptyPath return ErrEmptyPath
} }
@ -362,10 +360,8 @@ func writeCon(fpath string, val string) error {
} }
defer out.Close() defer out.Close()
if ok, err := isProcHandle(out); err != nil { if err := isProcHandle(out); err != nil {
return err return err
} else if !ok {
return fmt.Errorf("%s not on procfs", fpath)
} }
if val != "" { if val != "" {
@ -379,6 +375,32 @@ func writeCon(fpath string, val string) error {
return nil 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 CanonicalizeContext takes a context string and writes it to the kernel
the function then returns the context that the kernel will use. This function 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. that are executed by the current process thread, or an error.
*/ */
func SetExecLabel(label string) 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. This requires the dyntransition permission.
*/ */
func SetTaskLabel(label string) error { 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 // SetSocketLabel takes a process label and tells the kernel to assign the
// label to the next socket that gets created // label to the next socket that gets created
func SetSocketLabel(label string) error { 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 // SocketLabel retrieves the current socket label setting
func SocketLabel() (string, error) { 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 // 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) { if os.IsNotExist(err) {
return nil return nil
} }
if label == "" && os.IsPermission(err) && !GetEnabled() { if label == "" && os.IsPermission(err) {
return nil return nil
} }
return err return err
@ -505,19 +527,18 @@ func ReserveLabel(label string) {
} }
func selinuxEnforcePath() string { func selinuxEnforcePath() string {
return fmt.Sprintf("%s/enforce", getSelinuxMountPoint()) return path.Join(getSelinuxMountPoint(), "enforce")
} }
// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled // EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
func EnforceMode() int { func EnforceMode() int {
var enforce int var enforce int
enforceS, err := readCon(selinuxEnforcePath()) enforceB, err := ioutil.ReadFile(selinuxEnforcePath())
if err != nil { if err != nil {
return -1 return -1
} }
enforce, err = strconv.Atoi(string(enforceB))
enforce, err = strconv.Atoi(string(enforceS))
if err != nil { if err != nil {
return -1 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. Disabled is not valid, since this needs to be set at boot time.
*/ */
func SetEnforceMode(mode int) error { 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 // SecurityCheckContext validates that the SELinux label is understood by the kernel
func SecurityCheckContext(val string) error { func SecurityCheckContext(val string) error {
return writeCon(fmt.Sprintf("%s/context", getSelinuxMountPoint()), val) return ioutil.WriteFile(path.Join(getSelinuxMountPoint(), "context"), []byte(val), 0644)
} }
/* /*

View file

@ -3,76 +3,32 @@
package selinux package selinux
import ( import (
"syscall" "golang.org/x/sys/unix"
"unsafe"
) )
var _zero uintptr
// Returns a []byte slice if the xattr is set and nil otherwise // Returns a []byte slice if the xattr is set and nil otherwise
// Requires path and its attribute as arguments // Requires path and its attribute as arguments
func lgetxattr(path string, attr string) ([]byte, error) { func lgetxattr(path string, attr string) ([]byte, error) {
var sz int
pathBytes, err := syscall.BytePtrFromString(path)
if err != nil {
return nil, err
}
attrBytes, err := syscall.BytePtrFromString(attr)
if err != nil {
return nil, err
}
// Start with a 128 length byte array // Start with a 128 length byte array
sz = 128 dest := make([]byte, 128)
dest := make([]byte, sz) sz, errno := unix.Lgetxattr(path, attr, dest)
destBytes := unsafe.Pointer(&dest[0]) if errno == unix.ERANGE {
_sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) // Buffer too small, get the real size first
sz, errno = unix.Lgetxattr(path, attr, []byte{})
if errno != nil {
return nil, errno
}
switch {
case errno == syscall.ENODATA:
return nil, errno
case errno == syscall.ENOTSUP:
return nil, errno
case errno == syscall.ERANGE:
// 128 byte array might just not be good enough,
// A dummy buffer is used ``uintptr(0)`` to get real size
// of the xattrs on disk
_sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(unsafe.Pointer(nil)), uintptr(0), 0, 0)
sz = int(_sz)
if sz < 0 {
return nil, errno
}
dest = make([]byte, sz) dest = make([]byte, sz)
destBytes := unsafe.Pointer(&dest[0]) sz, errno = unix.Lgetxattr(path, attr, dest)
_sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) }
if errno != 0 { if errno != nil {
return nil, errno return nil, errno
} }
case errno != 0:
return nil, errno
}
sz = int(_sz)
return dest[:sz], nil return dest[:sz], nil
} }
func lsetxattr(path string, attr string, data []byte, flags int) error { func lsetxattr(path string, attr string, data []byte, flags int) error {
pathBytes, err := syscall.BytePtrFromString(path) return unix.Lsetxattr(path, attr, data, flags)
if err != nil {
return err
}
attrBytes, err := syscall.BytePtrFromString(attr)
if err != nil {
return err
}
var dataBytes unsafe.Pointer
if len(data) > 0 {
dataBytes = unsafe.Pointer(&data[0])
} else {
dataBytes = unsafe.Pointer(&_zero)
}
_, _, errno := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(dataBytes), uintptr(len(data)), uintptr(flags), 0)
if errno != 0 {
return errno
}
return nil
} }