Update github.com/opencontainers/selinux

Or github.com/opencontainers/selinux/go-selinux, a dependency of
libcontainer.
This commit is contained in:
Mahmood Ali 2019-06-18 14:49:11 -04:00
parent 0848f577bb
commit 3dd3195d45
6 changed files with 623 additions and 111 deletions

View file

@ -9,7 +9,7 @@ func InitLabels(options []string) (string, string, error) {
return "", "", nil return "", "", nil
} }
func GetROMountLabel() string { func ROMountLabel() string {
return "" return ""
} }
@ -25,7 +25,27 @@ func SetProcessLabel(processLabel string) error {
return nil 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 return "", nil
} }
@ -41,13 +61,18 @@ func Relabel(path string, fileLabel string, shared bool) error {
return nil return nil
} }
func GetPidLabel(pid int) (string, error) { func PidLabel(pid int) (string, error) {
return "", nil return "", nil
} }
func Init() { func Init() {
} }
// ClearLabels clears all reserved labels
func ClearLabels() {
return
}
func ReserveLabel(label string) error { func ReserveLabel(label string) error {
return nil return nil
} }
@ -58,8 +83,8 @@ func ReleaseLabel(label string) error {
// 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 { func DupSecOpt(src string) ([]string, error) {
return nil return nil, nil
} }
// DisableSecOpt returns a security opt that can disable labeling // DisableSecOpt returns a security opt that can disable labeling

View file

@ -4,6 +4,8 @@ package label
import ( import (
"fmt" "fmt"
"os"
"os/user"
"strings" "strings"
"github.com/opencontainers/selinux/go-selinux" "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 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 // the labels. The labels returned will include a random MCS String, that is
// guaranteed to be unique. // guaranteed to be unique.
func InitLabels(options []string) (string, string, error) { func InitLabels(options []string) (plabel string, mlabel string, Err error) {
if !selinux.GetEnabled() { if !selinux.GetEnabled() {
return "", "", nil return "", "", nil
} }
processLabel, mountLabel := selinux.ContainerLabels() processLabel, mountLabel := selinux.ContainerLabels()
if processLabel != "" { if processLabel != "" {
pcon := selinux.NewContext(processLabel) defer func() {
mcon := selinux.NewContext(mountLabel) 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 { for _, opt := range options {
if opt == "disable" { if opt == "disable" {
return "", "", 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' followed by ':' and a value", opt) 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] mcon[con[0]] = con[1]
} }
} }
_ = ReleaseLabel(processLabel)
processLabel = pcon.Get() processLabel = pcon.Get()
mountLabel = mcon.Get() mountLabel = mcon.Get()
_ = ReserveLabel(processLabel)
} }
return processLabel, mountLabel, nil 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 // SetProcessLabel takes a process label and tells the kernel to assign the
// label to the next program executed by the current process. // label to the next program executed by the current process.
func SetProcessLabel(processLabel string) error { func SetProcessLabel(processLabel string) error {
if processLabel == "" {
return nil
}
return selinux.SetExecLabel(processLabel) 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 // ProcessLabel returns the process label that the kernel will assign
// to the next program executed by the current process. If "" is returned // to the next program executed by the current process. If "" is returned
// this indicates that the default labeling will happen for the process. // this indicates that the default labeling will happen for the process.
@ -98,7 +133,7 @@ func ProcessLabel() (string, error) {
return selinux.ExecLabel() return selinux.ExecLabel()
} }
// GetFileLabel returns the label for specified path // FileLabel returns the label for specified path
func FileLabel(path string) (string, error) { func FileLabel(path string) (string, error) {
return selinux.FileLabel(path) return selinux.FileLabel(path)
} }
@ -131,13 +166,56 @@ func Relabel(path string, fileLabel string, shared bool) error {
return nil 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] { if exclude_paths[path] {
return fmt.Errorf("SELinux relabeling of %s is not allowed", path) return fmt.Errorf("SELinux relabeling of %s is not allowed", path)
} }
if shared { if shared {
c := selinux.NewContext(fileLabel) c, err := selinux.NewContext(fileLabel)
if err != nil {
return err
}
c["level"] = "s0" c["level"] = "s0"
fileLabel = c.Get() fileLabel = c.Get()
} }
@ -157,6 +235,11 @@ func Init() {
selinux.GetEnabled() 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. // 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 // This will prevent InitLabels from using the MCS label in a newly created
// container // container
@ -175,7 +258,7 @@ func ReleaseLabel(label string) error {
// 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 { func DupSecOpt(src string) ([]string, error) {
return selinux.DupSecOpt(src) return selinux.DupSecOpt(src)
} }

View file

@ -1,13 +1,16 @@
// +build linux // +build selinux,linux
package selinux package selinux
import ( import (
"bufio" "bufio"
"bytes"
"crypto/rand" "crypto/rand"
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
@ -24,13 +27,15 @@ const (
Permissive = 0 Permissive = 0
// Disabled constant to indicate SELinux is disabled // Disabled constant to indicate SELinux is disabled
Disabled = -1 Disabled = -1
selinuxDir = "/etc/selinux/" selinuxDir = "/etc/selinux/"
selinuxConfig = selinuxDir + "config" selinuxConfig = selinuxDir + "config"
selinuxfsMount = "/sys/fs/selinux"
selinuxTypeTag = "SELINUXTYPE" selinuxTypeTag = "SELINUXTYPE"
selinuxTag = "SELINUX" selinuxTag = "SELINUX"
selinuxPath = "/sys/fs/selinux"
xattrNameSelinux = "security.selinux" xattrNameSelinux = "security.selinux"
stRdOnly = 0x01 stRdOnly = 0x01
selinuxfsMagic = 0xf97cff8c
) )
type selinuxState struct { type selinuxState struct {
@ -43,7 +48,15 @@ type selinuxState struct {
} }
var ( 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(`^([^=]+)=(.*)$`) assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`)
roFileLabel string
state = selinuxState{ state = selinuxState{
mcsList: make(map[string]bool), mcsList: make(map[string]bool),
} }
@ -91,6 +104,83 @@ func (s *selinuxState) setSELinuxfs(selinuxfs string) string {
return s.selinuxfs 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 { func (s *selinuxState) getSELinuxfs() string {
s.Lock() s.Lock()
selinuxfs := s.selinuxfs selinuxfs := s.selinuxfs
@ -100,40 +190,7 @@ func (s *selinuxState) getSELinuxfs() string {
return selinuxfs return selinuxfs
} }
selinuxfs = "" return s.setSELinuxfs(findSELinuxfs())
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)
} }
// getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs // getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs
@ -150,7 +207,7 @@ func GetEnabled() bool {
return state.getEnabled() return state.getEnabled()
} }
func readConfig(target string) (value string) { func readConfig(target string) string {
var ( var (
val, key string val, key string
bufin *bufio.Reader bufin *bufio.Reader
@ -192,30 +249,42 @@ func readConfig(target string) (value string) {
} }
func getSELinuxPolicyRoot() string { func getSELinuxPolicyRoot() string {
return selinuxDir + readConfig(selinuxTypeTag) return filepath.Join(selinuxDir, readConfig(selinuxTypeTag))
} }
func readCon(name string) (string, error) { func readCon(fpath string) (string, error) {
var val string if fpath == "" {
return "", ErrEmptyPath
}
in, err := os.Open(name) in, err := os.Open(fpath)
if err != nil { if err != nil {
return "", err return "", err
} }
defer in.Close() defer in.Close()
_, err = fmt.Fscanf(in, "%s", &val) var retval string
return val, err 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. // SetFileLabel sets the SELinux label for this path or returns an error.
func SetFileLabel(path string, label string) error { func SetFileLabel(fpath string, label string) error {
return lsetxattr(path, xattrNameSelinux, []byte(label), 0) if fpath == "" {
return ErrEmptyPath
}
return lsetxattr(fpath, xattrNameSelinux, []byte(label), 0)
} }
// Filecon returns the SELinux label for this path or returns an error. // FileLabel returns the SELinux label for this path or returns an error.
func FileLabel(path string) (string, error) { func FileLabel(fpath string) (string, error) {
label, err := lgetxattr(path, xattrNameSelinux) if fpath == "" {
return "", ErrEmptyPath
}
label, err := lgetxattr(fpath, xattrNameSelinux)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -260,8 +329,17 @@ func ExecLabel() (string, error) {
return readCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid())) return readCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()))
} }
func writeCon(name string, val string) error { func writeCon(fpath string, val string) error {
out, err := os.OpenFile(name, os.O_WRONLY, 0) if fpath == "" {
return ErrEmptyPath
}
if val == "" {
if !GetEnabled() {
return nil
}
}
out, err := os.OpenFile(fpath, os.O_WRONLY, 0)
if err != nil { if err != nil {
return err return err
} }
@ -275,6 +353,37 @@ func writeCon(name string, val string) error {
return err 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 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.
@ -283,35 +392,81 @@ func SetExecLabel(label string) error {
return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), label) 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 // Get returns the Context as a string
func (c Context) Get() string { func (c Context) Get() string {
if c["level"] != "" {
return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], 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 // NewContext creates a new Context struct from the specified label
func NewContext(label string) Context { func NewContext(label string) (Context, error) {
c := make(Context) c := make(Context)
if len(label) != 0 { if len(label) != 0 {
con := strings.SplitN(label, ":", 4) con := strings.SplitN(label, ":", 4)
if len(con) < 3 {
return c, InvalidLabel
}
c["user"] = con[0] c["user"] = con[0]
c["role"] = con[1] c["role"] = con[1]
c["type"] = con[2] c["type"] = con[2]
if len(con) > 3 {
c["level"] = 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 // ReserveLabel reserves the MLS/MCS level component of the specified label
func ReserveLabel(label string) { func ReserveLabel(label string) {
if len(label) != 0 { if len(label) != 0 {
con := strings.SplitN(label, ":", 4) con := strings.SplitN(label, ":", 4)
if len(con) > 3 {
mcsAdd(con[3]) mcsAdd(con[3])
} }
} }
}
func selinuxEnforcePath() string { func selinuxEnforcePath() string {
return fmt.Sprintf("%s/enforce", selinuxPath) return fmt.Sprintf("%s/enforce", getSelinuxMountPoint())
} }
// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled // EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
@ -331,7 +486,7 @@ func EnforceMode() int {
} }
/* /*
SetEnforce sets the current SELinux mode Enforcing, Permissive. 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 {
@ -354,16 +509,22 @@ func DefaultEnforceMode() int {
} }
func mcsAdd(mcs string) error { func mcsAdd(mcs string) error {
if mcs == "" {
return nil
}
state.Lock() state.Lock()
defer state.Unlock() defer state.Unlock()
if state.mcsList[mcs] { if state.mcsList[mcs] {
return fmt.Errorf("MCS Label already exists") return ErrMCSAlreadyExists
} }
state.mcsList[mcs] = true state.mcsList[mcs] = true
return nil return nil
} }
func mcsDelete(mcs string) { func mcsDelete(mcs string) {
if mcs == "" {
return
}
state.Lock() state.Lock()
defer state.Unlock() defer state.Unlock()
state.mcsList[mcs] = false state.mcsList[mcs] = false
@ -424,14 +585,14 @@ Allowing it to be used by another process.
func ReleaseLabel(label string) { func ReleaseLabel(label string) {
if len(label) != 0 { if len(label) != 0 {
con := strings.SplitN(label, ":", 4) con := strings.SplitN(label, ":", 4)
if len(con) > 3 {
mcsDelete(con[3]) mcsDelete(con[3])
} }
} }
}
var roFileLabel string
// ROFileLabel returns the specified SELinux readonly file label // ROFileLabel returns the specified SELinux readonly file label
func ROFileLabel() (fileLabel string) { func ROFileLabel() string {
return roFileLabel return roFileLabel
} }
@ -497,23 +658,25 @@ func ContainerLabels() (processLabel string, fileLabel string) {
roFileLabel = fileLabel roFileLabel = fileLabel
} }
exit: exit:
scon, _ := NewContext(processLabel)
if scon["level"] != "" {
mcs := uniqMcs(1024) mcs := uniqMcs(1024)
scon := NewContext(processLabel)
scon["level"] = mcs scon["level"] = mcs
processLabel = scon.Get() processLabel = scon.Get()
scon = NewContext(fileLabel) scon, _ = NewContext(fileLabel)
scon["level"] = mcs scon["level"] = mcs
fileLabel = scon.Get() fileLabel = scon.Get()
}
return processLabel, fileLabel return processLabel, fileLabel
} }
// 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", 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. the dest label.
*/ */
func CopyLevel(src, dest string) (string, error) { func CopyLevel(src, dest string) (string, error) {
@ -526,8 +689,14 @@ func CopyLevel(src, dest string) (string, error) {
if err := SecurityCheckContext(dest); err != nil { if err := SecurityCheckContext(dest); err != nil {
return "", err return "", err
} }
scon := NewContext(src) scon, err := NewContext(src)
tcon := NewContext(dest) if err != nil {
return "", err
}
tcon, err := NewContext(dest)
if err != nil {
return "", err
}
mcsDelete(tcon["level"]) mcsDelete(tcon["level"])
mcsAdd(scon["level"]) mcsAdd(scon["level"])
tcon["level"] = scon["level"] tcon["level"] = scon["level"]
@ -536,20 +705,26 @@ func CopyLevel(src, dest string) (string, error) {
// Prevent users from relabing system files // Prevent users from relabing system files
func badPrefix(fpath string) error { func badPrefix(fpath string) error {
var badprefixes = []string{"/usr"} if fpath == "" {
return ErrEmptyPath
}
for _, prefix := range badprefixes { badPrefixes := []string{"/usr"}
if fpath == prefix || strings.HasPrefix(fpath, fmt.Sprintf("%s/", prefix)) { for _, prefix := range badPrefixes {
if strings.HasPrefix(fpath, prefix) {
return fmt.Errorf("relabeling content in %s is not allowed", prefix) return fmt.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 the 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 == "" {
return ErrEmptyPath
}
if label == "" { if label == "" {
return nil return nil
} }
@ -557,7 +732,11 @@ func Chcon(fpath string, label string, recurse bool) error {
return err return err
} }
callback := func(p string, info os.FileInfo, err error) error { 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 { 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 // DupSecOpt takes an SELinux process label and returns security options that
// can will set the SELinux Type and Level for future container processes // can be used to set the SELinux Type and Level for future container processes.
func DupSecOpt(src string) []string { func DupSecOpt(src string) ([]string, error) {
if src == "" { if src == "" {
return nil return nil, nil
}
con, err := NewContext(src)
if err != nil {
return nil, err
} }
con := NewContext(src)
if con["user"] == "" || if con["user"] == "" ||
con["role"] == "" || con["role"] == "" ||
con["type"] == "" || con["type"] == "" {
con["level"] == "" { return nil, nil
return nil
} }
return []string{"user:" + con["user"], dup := []string{"user:" + con["user"],
"role:" + con["role"], "role:" + con["role"],
"type:" + con["type"], "type:" + con["type"],
"level:" + con["level"]}
} }
// DisableSecOpt returns a security opt that can be used to disabling SELinux if con["level"] != "" {
// labeling support for future container processes dup = append(dup, "level:"+con["level"])
}
return dup, nil
}
// DisableSecOpt returns a security opt that can be used to disable SELinux
// labeling support for future container processes.
func DisableSecOpt() []string { func DisableSecOpt() []string {
return []string{"disable"} return []string{"disable"}
} }

View file

@ -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"}
}

View file

@ -1,4 +1,4 @@
// +build linux // +build selinux,linux
package selinux package selinux

4
vendor/vendor.json vendored
View file

@ -323,8 +323,8 @@
{"path":"github.com/opencontainers/runc/libcontainer/user","checksumSHA1":"mdUukOXCVJxmT0CufSKDeMg5JFM=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"}, {"path":"github.com/opencontainers/runc/libcontainer/user","checksumSHA1":"mdUukOXCVJxmT0CufSKDeMg5JFM=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/utils","checksumSHA1":"PqGgeBjTHnyGrTr5ekLFEXpC3iQ=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"}, {"path":"github.com/opencontainers/runc/libcontainer/utils","checksumSHA1":"PqGgeBjTHnyGrTr5ekLFEXpC3iQ=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runtime-spec/specs-go","checksumSHA1":"AMYc2X2O/IL6EGrq6lTl5vEhLiY=","origin":"github.com/opencontainers/runc/vendor/github.com/opencontainers/runtime-spec/specs-go","revision":"459bfaec1fc6c17d8bfb12d0a0f69e7e7271ed2a","revisionTime":"2018-08-23T14:46:37Z"}, {"path":"github.com/opencontainers/runtime-spec/specs-go","checksumSHA1":"AMYc2X2O/IL6EGrq6lTl5vEhLiY=","origin":"github.com/opencontainers/runc/vendor/github.com/opencontainers/runtime-spec/specs-go","revision":"459bfaec1fc6c17d8bfb12d0a0f69e7e7271ed2a","revisionTime":"2018-08-23T14:46:37Z"},
{"path":"github.com/opencontainers/selinux/go-selinux","checksumSHA1":"j9efF9bPmCCag+LzqwjyB8a44B8=","origin":"github.com/opencontainers/runc/vendor/github.com/opencontainers/selinux/go-selinux","revision":"459bfaec1fc6c17d8bfb12d0a0f69e7e7271ed2a","revisionTime":"2018-08-23T14:46:37Z"}, {"path":"github.com/opencontainers/selinux/go-selinux","checksumSHA1":"X4jufgAG12FCYi0U9VK4DK5vvXo=","origin":"github.com/opencontainers/runc/vendor/github.com/opencontainers/selinux/go-selinux","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/selinux/go-selinux/label","checksumSHA1":"QbeVoKIoaJWZDH8V/588i8/Pjjs=","origin":"github.com/opencontainers/runc/vendor/github.com/opencontainers/selinux/go-selinux/label","revision":"459bfaec1fc6c17d8bfb12d0a0f69e7e7271ed2a","revisionTime":"2018-08-23T14:46:37Z"}, {"path":"github.com/opencontainers/selinux/go-selinux/label","checksumSHA1":"5hHzDoXjeTtGaVzyN8lOowcwvdQ=","origin":"github.com/opencontainers/runc/vendor/github.com/opencontainers/selinux/go-selinux/label","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/pkg/errors","checksumSHA1":"ynJSWoF6v+3zMnh9R0QmmG6iGV8=","revision":"248dadf4e9068a0b3e79f02ed0a610d935de5302","revisionTime":"2016-10-29T09:36:37Z"}, {"path":"github.com/pkg/errors","checksumSHA1":"ynJSWoF6v+3zMnh9R0QmmG6iGV8=","revision":"248dadf4e9068a0b3e79f02ed0a610d935de5302","revisionTime":"2016-10-29T09:36:37Z"},
{"path":"github.com/pmezard/go-difflib/difflib","checksumSHA1":"LuFv4/jlrmFNnDb/5SCSEPAM9vU=","revision":"792786c7400a136282c1664665ae0a8db921c6c2","revisionTime":"2016-01-10T10:55:54Z"}, {"path":"github.com/pmezard/go-difflib/difflib","checksumSHA1":"LuFv4/jlrmFNnDb/5SCSEPAM9vU=","revision":"792786c7400a136282c1664665ae0a8db921c6c2","revisionTime":"2016-01-10T10:55:54Z"},
{"path":"github.com/posener/complete","checksumSHA1":"rTNABfFJ9wtLQRH8uYNkEZGQOrY=","revision":"9f41f7636a724791a3b8b1d35e84caa1124f0d3c","revisionTime":"2017-08-29T17:11:12Z"}, {"path":"github.com/posener/complete","checksumSHA1":"rTNABfFJ9wtLQRH8uYNkEZGQOrY=","revision":"9f41f7636a724791a3b8b1d35e84caa1124f0d3c","revisionTime":"2017-08-29T17:11:12Z"},