go.mod: github.com/opencontainers/selinux v1.11.0

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
This commit is contained in:
Akihiro Suda 2023-03-07 21:54:51 +09:00
parent 6bfc82dafe
commit 2b4f830ede
No known key found for this signature in database
GPG Key ID: 49524C6F9F638F1A
14 changed files with 153 additions and 366 deletions

2
go.mod
View File

@ -51,7 +51,7 @@ require (
// ATM the runtime-tools commit we need are beyond the latest tag. // ATM the runtime-tools commit we need are beyond the latest tag.
// We use a replace to handle that until a new version is tagged. // We use a replace to handle that until a new version is tagged.
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626
github.com/opencontainers/selinux v1.10.2 github.com/opencontainers/selinux v1.11.0
github.com/pelletier/go-toml v1.9.5 github.com/pelletier/go-toml v1.9.5
github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_golang v1.14.0
github.com/sirupsen/logrus v1.9.0 github.com/sirupsen/logrus v1.9.0

4
go.sum
View File

@ -802,8 +802,8 @@ github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xA
github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
github.com/opencontainers/selinux v1.10.2 h1:NFy2xCsjn7+WspbfZkUd5zyVeisV7VFbPSP96+8/ha4= github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
github.com/opencontainers/selinux v1.10.2/go.mod h1:cARutUbaUrlRClyvxOICCgKixCs6L05aUsohzA3EkHQ= github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=

View File

@ -49,7 +49,7 @@ require (
github.com/moby/sys/sequential v0.5.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/sys/signal v0.7.0 // indirect github.com/moby/sys/signal v0.7.0 // indirect
github.com/opencontainers/runc v1.1.4 // indirect github.com/opencontainers/runc v1.1.4 // indirect
github.com/opencontainers/selinux v1.10.2 // indirect github.com/opencontainers/selinux v1.11.0 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect

View File

@ -1191,8 +1191,8 @@ github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xA
github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
github.com/opencontainers/selinux v1.10.2 h1:NFy2xCsjn7+WspbfZkUd5zyVeisV7VFbPSP96+8/ha4= github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
github.com/opencontainers/selinux v1.10.2/go.mod h1:cARutUbaUrlRClyvxOICCgKixCs6L05aUsohzA3EkHQ= github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=

View File

@ -78,6 +78,9 @@ func ReleaseLabel(label string) error {
// Deprecated: use selinux.DupSecOpt // Deprecated: use selinux.DupSecOpt
var DupSecOpt = selinux.DupSecOpt var DupSecOpt = selinux.DupSecOpt
// FormatMountLabel returns a string to be used by the mount command. Using
// the SELinux `context` mount option. Changing labels of files on mount
// points with this option can never be changed.
// FormatMountLabel returns a string to be used by the mount command. // FormatMountLabel returns a string to be used by the mount command.
// The format of this string will be used to alter the labeling of the mountpoint. // The format of this string will be used to alter the labeling of the mountpoint.
// The string returned is suitable to be used as the options field of the mount command. // The string returned is suitable to be used as the options field of the mount command.
@ -85,12 +88,27 @@ var DupSecOpt = selinux.DupSecOpt
// the first parameter. Second parameter is the label that you wish to apply // the first parameter. Second parameter is the label that you wish to apply
// to all content in the mount point. // to all content in the mount point.
func FormatMountLabel(src, mountLabel string) string { func FormatMountLabel(src, mountLabel string) string {
return FormatMountLabelByType(src, mountLabel, "context")
}
// FormatMountLabelByType returns a string to be used by the mount command.
// Allow caller to specify the mount options. For example using the SELinux
// `fscontext` mount option would allow certain container processes to change
// labels of files created on the mount points, where as `context` option does
// not.
// FormatMountLabelByType returns a string to be used by the mount command.
// The format of this string will be used to alter the labeling of the mountpoint.
// The string returned is suitable to be used as the options field of the mount command.
// If you need to have additional mount point options, you can pass them in as
// the first parameter. Second parameter is the label that you wish to apply
// to all content in the mount point.
func FormatMountLabelByType(src, mountLabel, contextType string) string {
if mountLabel != "" { if mountLabel != "" {
switch src { switch src {
case "": case "":
src = fmt.Sprintf("context=%q", mountLabel) src = fmt.Sprintf("%s=%q", contextType, mountLabel)
default: default:
src = fmt.Sprintf("%s,context=%q", src, mountLabel) src = fmt.Sprintf("%s,%s=%q", src, contextType, mountLabel)
} }
} }
return src return src

View File

@ -1,34 +0,0 @@
//go:build linux && go1.16
// +build linux,go1.16
package selinux
import (
"errors"
"io/fs"
"os"
"github.com/opencontainers/selinux/pkg/pwalkdir"
)
func rchcon(fpath, label string) error {
fastMode := false
// If the current label matches the new label, assume
// other labels are correct.
if cLabel, err := lFileLabel(fpath); err == nil && cLabel == label {
fastMode = true
}
return pwalkdir.Walk(fpath, func(p string, _ fs.DirEntry, _ error) error {
if fastMode {
if cLabel, err := lFileLabel(fpath); err == nil && cLabel == label {
return nil
}
}
e := lSetFileLabel(p, label)
// Walk a file tree can race with removal, so ignore ENOENT.
if errors.Is(e, os.ErrNotExist) {
return nil
}
return e
})
}

View File

@ -1,22 +0,0 @@
//go:build linux && !go1.16
// +build linux,!go1.16
package selinux
import (
"errors"
"os"
"github.com/opencontainers/selinux/pkg/pwalk"
)
func rchcon(fpath, label string) error {
return pwalk.Walk(fpath, func(p string, _ os.FileInfo, _ error) error {
e := lSetFileLabel(p, label)
// Walk a file tree can race with removal, so ignore ENOENT.
if errors.Is(e, os.ErrNotExist) {
return nil
}
return e
})
}

View File

@ -23,8 +23,13 @@ var (
// ErrEmptyPath is returned when an empty path has been specified. // ErrEmptyPath is returned when an empty path has been specified.
ErrEmptyPath = errors.New("empty path") ErrEmptyPath = errors.New("empty path")
// ErrInvalidLabel is returned when an invalid label is specified.
ErrInvalidLabel = errors.New("invalid Label")
// InvalidLabel is returned when an invalid label is specified. // InvalidLabel is returned when an invalid label is specified.
InvalidLabel = errors.New("Invalid Label") //
// Deprecated: use [ErrInvalidLabel].
InvalidLabel = ErrInvalidLabel
// ErrIncomparable is returned two levels are not comparable // ErrIncomparable is returned two levels are not comparable
ErrIncomparable = errors.New("incomparable levels") ErrIncomparable = errors.New("incomparable levels")
@ -144,7 +149,7 @@ func CalculateGlbLub(sourceRange, targetRange string) (string, error) {
// of the program is finished to guarantee another goroutine does not migrate to the current // of the program is finished to guarantee another goroutine does not migrate to the current
// thread before execution is complete. // thread before execution is complete.
func SetExecLabel(label string) error { func SetExecLabel(label string) error {
return setExecLabel(label) return writeCon(attrPath("exec"), label)
} }
// SetTaskLabel sets the SELinux label for the current thread, or an error. // SetTaskLabel sets the SELinux label for the current thread, or an error.
@ -152,21 +157,21 @@ func SetExecLabel(label string) error {
// be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() to guarantee // be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() to guarantee
// the current thread does not run in a new mislabeled thread. // the current thread does not run in a new mislabeled thread.
func SetTaskLabel(label string) error { func SetTaskLabel(label string) error {
return setTaskLabel(label) return writeCon(attrPath("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. Calls to SetSocketLabel // label to the next socket that gets created. Calls to SetSocketLabel
// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until // should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until
// the the socket is created to guarantee another goroutine does not migrate // the socket is created to guarantee another goroutine does not migrate
// to the current thread before execution is complete. // to the current thread before execution is complete.
func SetSocketLabel(label string) error { func SetSocketLabel(label string) error {
return setSocketLabel(label) return writeCon(attrPath("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 socketLabel() return readCon(attrPath("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
@ -185,7 +190,7 @@ func SetKeyLabel(label string) error {
// KeyLabel retrieves the current kernel keyring label setting // KeyLabel retrieves the current kernel keyring label setting
func KeyLabel() (string, error) { func KeyLabel() (string, error) {
return keyLabel() return readCon("/proc/self/attr/keycreate")
} }
// Get returns the Context as a string // Get returns the Context as a string
@ -208,6 +213,11 @@ func ReserveLabel(label string) {
reserveLabel(label) reserveLabel(label)
} }
// MLSEnabled checks if MLS is enabled.
func MLSEnabled() bool {
return isMLSEnabled()
}
// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled // EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
func EnforceMode() int { func EnforceMode() int {
return enforceMode() return enforceMode()
@ -220,7 +230,7 @@ func SetEnforceMode(mode int) error {
} }
// DefaultEnforceMode returns the systems default SELinux mode Enforcing, // DefaultEnforceMode returns the systems default SELinux mode Enforcing,
// Permissive or Disabled. Note this is is just the default at boot time. // Permissive or Disabled. Note this is just the default at boot time.
// EnforceMode tells you the systems current mode. // EnforceMode tells you the systems current mode.
func DefaultEnforceMode() int { func DefaultEnforceMode() int {
return defaultEnforceMode() return defaultEnforceMode()
@ -266,7 +276,7 @@ func CopyLevel(src, dest string) (string, error) {
return copyLevel(src, dest) return copyLevel(src, dest)
} }
// Chcon changes the fpath file object to the SELinux label label. // Chcon changes the fpath file object to the SELinux label.
// If fpath is a directory and recurse is true, then Chcon walks the // If fpath is a directory and recurse is true, then Chcon walks the
// directory tree setting the label. // directory tree setting the label.
// //
@ -284,7 +294,7 @@ func DupSecOpt(src string) ([]string, error) {
// DisableSecOpt returns a security opt that can be used to disable SELinux // DisableSecOpt returns a security opt that can be used to disable SELinux
// labeling support for future container processes. // labeling support for future container processes.
func DisableSecOpt() []string { func DisableSecOpt() []string {
return disableSecOpt() return []string{"disable"}
} }
// GetDefaultContextWithLevel gets a single context for the specified SELinux user // GetDefaultContextWithLevel gets a single context for the specified SELinux user

View File

@ -8,16 +8,16 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/fs"
"math/big" "math/big"
"os" "os"
"os/user" "os/user"
"path"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"github.com/opencontainers/selinux/pkg/pwalkdir"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@ -35,17 +35,17 @@ const (
) )
type selinuxState struct { type selinuxState struct {
mcsList map[string]bool
selinuxfs string
selinuxfsOnce sync.Once
enabledSet bool enabledSet bool
enabled bool enabled bool
selinuxfsOnce sync.Once
selinuxfs string
mcsList map[string]bool
sync.Mutex sync.Mutex
} }
type level struct { type level struct {
sens uint
cats *big.Int cats *big.Int
sens uint
} }
type mlsRange struct { type mlsRange struct {
@ -54,10 +54,10 @@ type mlsRange struct {
} }
type defaultSECtx struct { type defaultSECtx struct {
user, level, scon string userRdr io.Reader
userRdr, defaultRdr io.Reader verifier func(string) error
defaultRdr io.Reader
verifier func(string) error user, level, scon string
} }
type levelItem byte type levelItem byte
@ -155,7 +155,7 @@ func findSELinuxfs() string {
} }
// check if selinuxfs is available before going the slow path // check if selinuxfs is available before going the slow path
fs, err := ioutil.ReadFile("/proc/filesystems") fs, err := os.ReadFile("/proc/filesystems")
if err != nil { if err != nil {
return "" return ""
} }
@ -292,7 +292,7 @@ func readCon(fpath string) (string, error) {
} }
func readConFd(in *os.File) (string, error) { func readConFd(in *os.File) (string, error) {
data, err := ioutil.ReadAll(in) data, err := io.ReadAll(in)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -305,7 +305,7 @@ func classIndex(class string) (int, error) {
permpath := fmt.Sprintf("class/%s/index", class) permpath := fmt.Sprintf("class/%s/index", class)
indexpath := filepath.Join(getSelinuxMountPoint(), permpath) indexpath := filepath.Join(getSelinuxMountPoint(), permpath)
indexB, err := ioutil.ReadFile(indexpath) indexB, err := os.ReadFile(indexpath)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@ -391,21 +391,19 @@ func lFileLabel(fpath string) (string, error) {
return string(label), nil return string(label), 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 { func setFSCreateLabel(label string) error {
return writeAttr("fscreate", label) return writeCon(attrPath("fscreate"), label)
} }
// fsCreateLabel returns the default label the kernel which the kernel is using // 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 readAttr("fscreate") return readCon(attrPath("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 readAttr("current") return readCon(attrPath("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.
@ -416,7 +414,7 @@ func pidLabel(pid int) (string, error) {
// ExecLabel returns the SELinux label that the kernel will use for any programs // 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 readAttr("exec") return readCon(attrPath("exec"))
} }
func writeCon(fpath, val string) error { func writeCon(fpath, val string) error {
@ -462,18 +460,10 @@ func attrPath(attr string) string {
}) })
if haveThreadSelf { if haveThreadSelf {
return path.Join(threadSelfPrefix, attr) return filepath.Join(threadSelfPrefix, attr)
} }
return path.Join("/proc/self/task/", strconv.Itoa(unix.Gettid()), "/attr/", attr) return filepath.Join("/proc/self/task", strconv.Itoa(unix.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
@ -560,30 +550,30 @@ func (l *level) parseLevel(levelStr string) error {
// rangeStrToMLSRange marshals a string representation of a range. // rangeStrToMLSRange marshals a string representation of a range.
func rangeStrToMLSRange(rangeStr string) (*mlsRange, error) { func rangeStrToMLSRange(rangeStr string) (*mlsRange, error) {
mlsRange := &mlsRange{} r := &mlsRange{}
levelSlice := strings.SplitN(rangeStr, "-", 2) l := strings.SplitN(rangeStr, "-", 2)
switch len(levelSlice) { switch len(l) {
// rangeStr that has a low and a high level, e.g. s4:c0.c1023-s6:c0.c1023 // rangeStr that has a low and a high level, e.g. s4:c0.c1023-s6:c0.c1023
case 2: case 2:
mlsRange.high = &level{} r.high = &level{}
if err := mlsRange.high.parseLevel(levelSlice[1]); err != nil { if err := r.high.parseLevel(l[1]); err != nil {
return nil, fmt.Errorf("failed to parse high level %q: %w", levelSlice[1], err) return nil, fmt.Errorf("failed to parse high level %q: %w", l[1], err)
} }
fallthrough fallthrough
// rangeStr that is single level, e.g. s6:c0,c3,c5,c30.c1023 // rangeStr that is single level, e.g. s6:c0,c3,c5,c30.c1023
case 1: case 1:
mlsRange.low = &level{} r.low = &level{}
if err := mlsRange.low.parseLevel(levelSlice[0]); err != nil { if err := r.low.parseLevel(l[0]); err != nil {
return nil, fmt.Errorf("failed to parse low level %q: %w", levelSlice[0], err) return nil, fmt.Errorf("failed to parse low level %q: %w", l[0], err)
} }
} }
if mlsRange.high == nil { if r.high == nil {
mlsRange.high = mlsRange.low r.high = r.low
} }
return mlsRange, nil return r, nil
} }
// bitsetToStr takes a category bitset and returns it in the // bitsetToStr takes a category bitset and returns it in the
@ -617,17 +607,17 @@ func bitsetToStr(c *big.Int) string {
return str return str
} }
func (l1 *level) equal(l2 *level) bool { func (l *level) equal(l2 *level) bool {
if l2 == nil || l1 == nil { if l2 == nil || l == nil {
return l1 == l2 return l == l2
} }
if l1.sens != l2.sens { if l2.sens != l.sens {
return false return false
} }
if l2.cats == nil || l1.cats == nil { if l2.cats == nil || l.cats == nil {
return l2.cats == l1.cats return l2.cats == l.cats
} }
return l1.cats.Cmp(l2.cats) == 0 return l.cats.Cmp(l2.cats) == 0
} }
// String returns an mlsRange as a string. // String returns an mlsRange as a string.
@ -721,36 +711,13 @@ func readWriteCon(fpath string, val string) (string, error) {
return readConFd(f) return readConFd(f)
} }
// 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 writeAttr("exec", label)
}
// setTaskLabel sets the SELinux label for the current thread, or an error.
// This requires the dyntransition permission.
func setTaskLabel(label string) error {
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 writeAttr("sockcreate", label)
}
// socketLabel retrieves the current socket label setting
func socketLabel() (string, error) {
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
func peerLabel(fd uintptr) (string, error) { func peerLabel(fd uintptr) (string, error) {
label, err := unix.GetsockoptString(int(fd), unix.SOL_SOCKET, unix.SO_PEERSEC) l, err := unix.GetsockoptString(int(fd), unix.SOL_SOCKET, unix.SO_PEERSEC)
if err != nil { if err != nil {
return "", &os.PathError{Op: "getsockopt", Path: "fd " + strconv.Itoa(int(fd)), Err: err} return "", &os.PathError{Op: "getsockopt", Path: "fd " + strconv.Itoa(int(fd)), Err: err}
} }
return label, nil return l, nil
} }
// setKeyLabel takes a process label and tells the kernel to assign the // setKeyLabel takes a process label and tells the kernel to assign the
@ -766,15 +733,10 @@ func setKeyLabel(label string) error {
return err 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 level := c["level"]; level != "" { if l := c["level"]; l != "" {
return c["user"] + ":" + c["role"] + ":" + c["type"] + ":" + level return c["user"] + ":" + c["role"] + ":" + c["type"] + ":" + l
} }
return c["user"] + ":" + c["role"] + ":" + c["type"] return c["user"] + ":" + c["role"] + ":" + c["type"]
} }
@ -786,7 +748,7 @@ func newContext(label string) (Context, error) {
if len(label) != 0 { if len(label) != 0 {
con := strings.SplitN(label, ":", 4) con := strings.SplitN(label, ":", 4)
if len(con) < 3 { if len(con) < 3 {
return c, InvalidLabel return c, ErrInvalidLabel
} }
c["user"] = con[0] c["user"] = con[0]
c["role"] = con[1] c["role"] = con[1]
@ -816,14 +778,23 @@ func reserveLabel(label string) {
} }
func selinuxEnforcePath() string { func selinuxEnforcePath() string {
return path.Join(getSelinuxMountPoint(), "enforce") return filepath.Join(getSelinuxMountPoint(), "enforce")
}
// isMLSEnabled checks if MLS is enabled.
func isMLSEnabled() bool {
enabledB, err := os.ReadFile(filepath.Join(getSelinuxMountPoint(), "mls"))
if err != nil {
return false
}
return bytes.Equal(enabledB, []byte{'1'})
} }
// 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
enforceB, err := ioutil.ReadFile(selinuxEnforcePath()) enforceB, err := os.ReadFile(selinuxEnforcePath())
if err != nil { if err != nil {
return -1 return -1
} }
@ -837,11 +808,12 @@ func enforceMode() int {
// setEnforceMode 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 {
return ioutil.WriteFile(selinuxEnforcePath(), []byte(strconv.Itoa(mode)), 0o644) //nolint:gosec // ignore G306: permissions to be 0600 or less.
return os.WriteFile(selinuxEnforcePath(), []byte(strconv.Itoa(mode)), 0o644)
} }
// defaultEnforceMode returns the systems default SELinux mode Enforcing, // defaultEnforceMode returns the systems default SELinux mode Enforcing,
// Permissive or Disabled. Note this is is just the default at boot time. // Permissive or Disabled. Note this is just the default at boot time.
// EnforceMode tells you the systems current mode. // EnforceMode tells you the systems current mode.
func defaultEnforceMode() int { func defaultEnforceMode() int {
switch readConfig(selinuxTag) { switch readConfig(selinuxTag) {
@ -941,7 +913,7 @@ func openContextFile() (*os.File, error) {
if f, err := os.Open(contextFile); err == nil { if f, err := os.Open(contextFile); err == nil {
return f, nil return f, nil
} }
return os.Open(filepath.Join(policyRoot(), "/contexts/lxc_contexts")) return os.Open(filepath.Join(policyRoot(), "contexts", "lxc_contexts"))
} }
func loadLabels() { func loadLabels() {
@ -1044,7 +1016,8 @@ func addMcs(processLabel, fileLabel string) (string, string) {
// 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 ioutil.WriteFile(path.Join(getSelinuxMountPoint(), "context"), []byte(val), 0o644) //nolint:gosec // ignore G306: permissions to be 0600 or less.
return os.WriteFile(filepath.Join(getSelinuxMountPoint(), "context"), []byte(val), 0o644)
} }
// copyLevel returns a label with the MLS/MCS level from src label replaced on // copyLevel returns a label with the MLS/MCS level from src label replaced on
@ -1073,7 +1046,7 @@ func copyLevel(src, dest string) (string, error) {
return tcon.Get(), nil return tcon.Get(), nil
} }
// chcon changes the fpath file object to the SELinux label label. // chcon changes the fpath file object to the SELinux label.
// If fpath is a directory and recurse is true, then chcon walks the // If fpath is a directory and recurse is true, then chcon walks 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 {
@ -1084,7 +1057,7 @@ func chcon(fpath string, label string, recurse bool) error {
return nil return nil
} }
exclude_paths := map[string]bool{ excludePaths := map[string]bool{
"/": true, "/": true,
"/bin": true, "/bin": true,
"/boot": true, "/boot": true,
@ -1112,19 +1085,19 @@ func chcon(fpath string, label string, recurse bool) error {
} }
if home := os.Getenv("HOME"); home != "" { if home := os.Getenv("HOME"); home != "" {
exclude_paths[home] = true excludePaths[home] = true
} }
if sudoUser := os.Getenv("SUDO_USER"); sudoUser != "" { if sudoUser := os.Getenv("SUDO_USER"); sudoUser != "" {
if usr, err := user.Lookup(sudoUser); err == nil { if usr, err := user.Lookup(sudoUser); err == nil {
exclude_paths[usr.HomeDir] = true excludePaths[usr.HomeDir] = true
} }
} }
if fpath != "/" { if fpath != "/" {
fpath = strings.TrimSuffix(fpath, "/") fpath = strings.TrimSuffix(fpath, "/")
} }
if exclude_paths[fpath] { if excludePaths[fpath] {
return fmt.Errorf("SELinux relabeling of %s is not allowed", fpath) return fmt.Errorf("SELinux relabeling of %s is not allowed", fpath)
} }
@ -1152,6 +1125,28 @@ func chcon(fpath string, label string, recurse bool) error {
return rchcon(fpath, label) return rchcon(fpath, label)
} }
func rchcon(fpath, label string) error { //revive:disable:cognitive-complexity
fastMode := false
// If the current label matches the new label, assume
// other labels are correct.
if cLabel, err := lFileLabel(fpath); err == nil && cLabel == label {
fastMode = true
}
return pwalkdir.Walk(fpath, func(p string, _ fs.DirEntry, _ error) error {
if fastMode {
if cLabel, err := lFileLabel(fpath); err == nil && cLabel == label {
return nil
}
}
err := lSetFileLabel(p, label)
// Walk a file tree can race with removal, so ignore ENOENT.
if errors.Is(err, os.ErrNotExist) {
return nil
}
return err
})
}
// dupSecOpt takes an SELinux process label and returns security options that // 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. // can be used to set the SELinux Type and Level for future container processes.
func dupSecOpt(src string) ([]string, error) { func dupSecOpt(src string) ([]string, error) {
@ -1180,12 +1175,6 @@ func dupSecOpt(src string) ([]string, error) {
return dup, nil return dup, 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"}
}
// findUserInContext scans the reader for a valid SELinux context // findUserInContext scans the reader for a valid SELinux context
// match that is verified with the verifier. Invalid contexts are // match that is verified with the verifier. Invalid contexts are
// skipped. It returns a matched context or an empty string if no // skipped. It returns a matched context or an empty string if no

View File

@ -3,9 +3,20 @@
package selinux package selinux
func setDisabled() { func attrPath(string) string {
return ""
} }
func readCon(fpath string) (string, error) {
return "", nil
}
func writeCon(string, string) error {
return nil
}
func setDisabled() {}
func getEnabled() bool { func getEnabled() bool {
return false return false
} }
@ -62,22 +73,6 @@ func calculateGlbLub(sourceRange, targetRange string) (string, error) {
return "", nil return "", nil
} }
func setExecLabel(label string) error {
return nil
}
func setTaskLabel(label string) error {
return nil
}
func setSocketLabel(label string) error {
return nil
}
func socketLabel() (string, error) {
return "", nil
}
func peerLabel(fd uintptr) (string, error) { func peerLabel(fd uintptr) (string, error) {
return "", nil return "", nil
} }
@ -86,17 +81,12 @@ func setKeyLabel(label string) error {
return nil return nil
} }
func keyLabel() (string, error) {
return "", nil
}
func (c Context) get() string { func (c Context) get() string {
return "" return ""
} }
func newContext(label string) (Context, error) { func newContext(label string) (Context, error) {
c := make(Context) return Context{}, nil
return c, nil
} }
func clearLabels() { func clearLabels() {
@ -105,6 +95,10 @@ func clearLabels() {
func reserveLabel(label string) { func reserveLabel(label string) {
} }
func isMLSEnabled() bool {
return false
}
func enforceMode() int { func enforceMode() int {
return Disabled return Disabled
} }
@ -152,10 +146,6 @@ func dupSecOpt(src string) ([]string, error) {
return nil, nil return nil, nil
} }
func disableSecOpt() []string {
return []string{"disable"}
}
func getDefaultContextWithLevel(user, level, scon string) (string, error) { func getDefaultContextWithLevel(user, level, scon string) (string, error) {
return "", nil return "", nil
} }

View File

@ -1,48 +0,0 @@
## 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).
### pwalk vs pwalkdir
This package is deprecated in favor of
[pwalkdir](https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalkdir),
which is faster, but requires at least Go 1.16.
### 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

@ -1,115 +0,0 @@
package pwalk
import (
"fmt"
"os"
"path/filepath"
"runtime"
"sync"
)
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.
//
// Please see Walk documentation for caveats of using this function.
func WalkN(root string, walkFn WalkFunc, num int) error {
// make sure limit is sensible
if num < 1 {
return fmt.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
wg sync.WaitGroup
rootLen = len(root)
rootEntry *walkArgs
)
wg.Add(1)
go func() {
err = filepath.Walk(root, func(p string, info os.FileInfo, err error) error {
if err != nil {
close(files)
return err
}
if len(p) == rootLen {
// Root entry is processed separately below.
rootEntry = &walkArgs{path: p, info: &info}
return nil
}
// 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)
}
wg.Done()
}()
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()
if err == nil {
err = walkFn(rootEntry.path, *rootEntry.info, nil)
}
return err
}
// walkArgs holds the arguments that were passed to the Walk or WalkN
// functions.
type walkArgs struct {
path string
info *os.FileInfo
}

View File

@ -111,6 +111,6 @@ func WalkN(root string, walkFn fs.WalkDirFunc, num int) error {
// walkArgs holds the arguments that were passed to the Walk or WalkN // walkArgs holds the arguments that were passed to the Walk or WalkN
// functions. // functions.
type walkArgs struct { type walkArgs struct {
path string
entry fs.DirEntry entry fs.DirEntry
path string
} }

5
vendor/modules.txt vendored
View File

@ -354,11 +354,10 @@ github.com/opencontainers/runtime-spec/specs-go
github.com/opencontainers/runtime-tools/generate github.com/opencontainers/runtime-tools/generate
github.com/opencontainers/runtime-tools/generate/seccomp github.com/opencontainers/runtime-tools/generate/seccomp
github.com/opencontainers/runtime-tools/validate/capabilities github.com/opencontainers/runtime-tools/validate/capabilities
# github.com/opencontainers/selinux v1.10.2 # github.com/opencontainers/selinux v1.11.0
## explicit; go 1.13 ## explicit; go 1.19
github.com/opencontainers/selinux/go-selinux github.com/opencontainers/selinux/go-selinux
github.com/opencontainers/selinux/go-selinux/label github.com/opencontainers/selinux/go-selinux/label
github.com/opencontainers/selinux/pkg/pwalk
github.com/opencontainers/selinux/pkg/pwalkdir github.com/opencontainers/selinux/pkg/pwalkdir
# github.com/pelletier/go-toml v1.9.5 # github.com/pelletier/go-toml v1.9.5
## explicit; go 1.12 ## explicit; go 1.12