Merge pull request #4849 from AkihiroSuda/remove-selinux-tag

remove "selinux" build tag
This commit is contained in:
Phil Estes 2020-12-15 14:32:53 -05:00 committed by GitHub
commit e922d5553d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 268 additions and 124 deletions

View File

@ -107,7 +107,6 @@ make generate
> * `no_cri`: A build tag disables building Kubernetes [CRI](http://blog.kubernetes.io/2016/12/container-runtime-interface-cri-in-kubernetes.html) support into containerd. > * `no_cri`: A build tag disables building Kubernetes [CRI](http://blog.kubernetes.io/2016/12/container-runtime-interface-cri-in-kubernetes.html) support into containerd.
> See [here](https://github.com/containerd/cri-containerd#build-tags) for build tags of CRI plugin. > See [here](https://github.com/containerd/cri-containerd#build-tags) for build tags of CRI plugin.
> * `no_devmapper`: A build tag disables building the device mapper snapshot driver. > * `no_devmapper`: A build tag disables building the device mapper snapshot driver.
> * `selinux`: Enables selinux support in the cri plugin
> >
> For example, adding `BUILDTAGS=no_btrfs` to your environment before calling the **binaries** > For example, adding `BUILDTAGS=no_btrfs` to your environment before calling the **binaries**
> Makefile target will disable the btrfs driver within the containerd Go build. > Makefile target will disable the btrfs driver within the containerd Go build.

View File

@ -77,8 +77,7 @@ MANPAGES=ctr.8 containerd.8 containerd-config.8 containerd-config.toml.5
ifdef BUILDTAGS ifdef BUILDTAGS
GO_BUILDTAGS = ${BUILDTAGS} GO_BUILDTAGS = ${BUILDTAGS}
endif endif
# Build tag "selinux" is needed by CRI plugin. GO_BUILDTAGS ?=
GO_BUILDTAGS ?= selinux
GO_BUILDTAGS += ${DEBUG_TAGS} GO_BUILDTAGS += ${DEBUG_TAGS}
GO_TAGS=$(if $(GO_BUILDTAGS),-tags "$(GO_BUILDTAGS)",) GO_TAGS=$(if $(GO_BUILDTAGS),-tags "$(GO_BUILDTAGS)",)
GO_LDFLAGS=-ldflags '-X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PACKAGE) $(EXTRA_LDFLAGS)' GO_LDFLAGS=-ldflags '-X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PACKAGE) $(EXTRA_LDFLAGS)'

View File

@ -53,12 +53,12 @@ Information about the binaries in the release tarball:
| Binary Name | Support | OS | Architecture | | Binary Name | Support | OS | Architecture |
|:------------------------------:|:------------------:|:-----:|:------------:| |:------------------------------:|:------------------:|:-----:|:------------:|
| containerd | seccomp, apparmor, <br/> overlay, btrfs | linux | amd64 | | containerd | seccomp, apparmor, selinux<br/> overlay, btrfs | linux | amd64 |
| containerd-shim | overlay, btrfs | linux | amd64 | | containerd-shim | overlay, btrfs | linux | amd64 |
| runc | seccomp, apparmor | linux | amd64 | | runc | seccomp, apparmor, selinux | linux | amd64 |
If you have other requirements for the binaries, e.g. selinux support, another architecture support etc., you need to build the binaries yourself following [the instructions](../BUILDING.md). If you have other requirements for the binaries, e.g. another architecture support etc., you need to build the binaries yourself following [the instructions](../BUILDING.md).
### Download ### Download
@ -95,7 +95,7 @@ Follow [the instructions](https://kubernetes.io/docs/setup/independent/install-k
## Step 4: Create Systemd Drop-In for Containerd ## Step 4: Create Systemd Drop-In for Containerd
Create the systemd drop-in file `/etc/systemd/system/kubelet.service.d/0-containerd.conf`: Create the systemd drop-in file `/etc/systemd/system/kubelet.service.d/0-containerd.conf`:
``` ```
[Service] [Service]
Environment="KUBELET_EXTRA_ARGS=--container-runtime=remote --runtime-request-timeout=15m --container-runtime-endpoint=unix:///run/containerd/containerd.sock" Environment="KUBELET_EXTRA_ARGS=--container-runtime=remote --runtime-request-timeout=15m --container-runtime-endpoint=unix:///run/containerd/containerd.sock"
``` ```
And reload systemd configuration: And reload systemd configuration:

3
go.mod
View File

@ -42,7 +42,7 @@ require (
github.com/opencontainers/image-spec v1.0.1 github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/runc v1.0.0-rc92 github.com/opencontainers/runc v1.0.0-rc92
github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6 github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6
github.com/opencontainers/selinux v1.6.0 github.com/opencontainers/selinux v1.8.0
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.7.1 github.com/prometheus/client_golang v1.7.1
github.com/sirupsen/logrus v1.7.0 github.com/sirupsen/logrus v1.7.0
@ -50,7 +50,6 @@ require (
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2
github.com/tchap/go-patricia v2.2.6+incompatible github.com/tchap/go-patricia v2.2.6+incompatible
github.com/urfave/cli v1.22.2 github.com/urfave/cli v1.22.2
github.com/willf/bitset v1.1.11 // indirect
go.etcd.io/bbolt v1.3.5 go.etcd.io/bbolt v1.3.5
golang.org/x/net v0.0.0-20200707034311-ab3426394381 golang.org/x/net v0.0.0-20200707034311-ab3426394381
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208

2
go.sum
View File

@ -397,6 +397,8 @@ github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6/go.m
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
github.com/opencontainers/selinux v1.6.0 h1:+bIAS/Za3q5FTwWym4fTB0vObnfCf3G/NC7K6Jx62mY= github.com/opencontainers/selinux v1.6.0 h1:+bIAS/Za3q5FTwWym4fTB0vObnfCf3G/NC7K6Jx62mY=
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
github.com/opencontainers/selinux v1.8.0 h1:+77ba4ar4jsCbL1GLbFL8fFM57w6suPfSS9PDLDY7KM=
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@ -1,5 +1,3 @@
// +build selinux
/* /*
Copyright The containerd Authors. Copyright The containerd Authors.

View File

@ -29,7 +29,7 @@ cd "${ROOT}"
make clean make clean
# Build CRI+CNI release # Build CRI+CNI release
make BUILDTAGS="seccomp selinux no_aufs no_btrfs no_devmapper no_zfs" cri-cni-release make BUILDTAGS="seccomp no_aufs no_btrfs no_devmapper no_zfs" cri-cni-release
BUILDDIR=$(mktemp -d) BUILDDIR=$(mktemp -d)
cleanup() { cleanup() {

View File

@ -5,9 +5,6 @@ This package uses a selinux build tag to enable the selinux functionality. This
allows non-linux and linux users who do not have selinux support to still use allows non-linux and linux users who do not have selinux support to still use
tools that rely on this library. tools that rely on this library.
To compile with full selinux support use the -tags=selinux option in your build
and test commands.
Usage: Usage:
import "github.com/opencontainers/selinux/go-selinux" import "github.com/opencontainers/selinux/go-selinux"

View File

@ -1,5 +1,3 @@
// +build selinux,linux
package label package label
import ( import (
@ -27,14 +25,14 @@ var ErrIncompatibleLabel = errors.New("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) (plabel string, mlabel string, Err error) { func InitLabels(options []string) (plabel string, mlabel string, retErr error) {
if !selinux.GetEnabled() { if !selinux.GetEnabled() {
return "", "", nil return "", "", nil
} }
processLabel, mountLabel := selinux.ContainerLabels() processLabel, mountLabel := selinux.ContainerLabels()
if processLabel != "" { if processLabel != "" {
defer func() { defer func() {
if Err != nil { if retErr != nil {
selinux.ReleaseLabel(mountLabel) selinux.ReleaseLabel(mountLabel)
} }
}() }()
@ -57,7 +55,6 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) {
con := strings.SplitN(opt, ":", 2) con := strings.SplitN(opt, ":", 2)
if !validOptions[con[0]] { if !validOptions[con[0]] {
return "", "", errors.Errorf("Bad label option %q, valid options 'disable, user, role, level, type, filetype'", con[0]) return "", "", errors.Errorf("Bad label option %q, valid options 'disable, user, role, level, type, filetype'", con[0])
} }
if con[0] == "filetype" { if con[0] == "filetype" {
mcon["type"] = con[1] mcon["type"] = con[1]

View File

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

View File

@ -30,6 +30,11 @@ var (
// ErrLevelSyntax is returned when a sensitivity or category do not have correct syntax in a level // ErrLevelSyntax is returned when a sensitivity or category do not have correct syntax in a level
ErrLevelSyntax = errors.New("invalid level syntax") ErrLevelSyntax = errors.New("invalid level syntax")
// ErrContextMissing is returned if a requested context is not found in a file.
ErrContextMissing = errors.New("context does not have a match")
// ErrVerifierNil is returned when a context verifier function is nil.
ErrVerifierNil = errors.New("verifier function is nil")
// CategoryRange allows the upper bound on the category range to be adjusted // CategoryRange allows the upper bound on the category range to be adjusted
CategoryRange = DefaultCategoryRange CategoryRange = DefaultCategoryRange
) )
@ -63,8 +68,12 @@ func FileLabel(fpath string) (string, error) {
return fileLabel(fpath) return fileLabel(fpath)
} }
// SetFSCreateLabel tells kernel the label to create all file system objects // SetFSCreateLabel tells the kernel what label to use for all file system objects
// created by this task. Setting label="" to return to default. // created by this task.
// Set the label to an empty string to return to the default label. Calls to SetFSCreateLabel
// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until file system
// objects created by this task are finished to guarantee another goroutine does not migrate
// to the current thread before execution is complete.
func SetFSCreateLabel(label string) error { func SetFSCreateLabel(label string) error {
return setFSCreateLabel(label) return setFSCreateLabel(label)
} }
@ -113,19 +122,27 @@ func CalculateGlbLub(sourceRange, targetRange string) (string, error) {
} }
// 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. Calls to SetExecLabel
// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until execution
// of the program is finished to guarantee another goroutine does not migrate to the current
// thread before execution is complete.
func SetExecLabel(label string) error { func SetExecLabel(label string) error {
return setExecLabel(label) return setExecLabel(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.
// This requires the dyntransition permission. // This requires the dyntransition permission. Calls to SetTaskLabel should
// be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() to guarantee
// 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 setTaskLabel(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. Calls to SetSocketLabel
// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until
// the the socket is created to guarantee another goroutine does not migrate
// to the current thread before execution is complete.
func SetSocketLabel(label string) error { func SetSocketLabel(label string) error {
return setSocketLabel(label) return setSocketLabel(label)
} }
@ -141,7 +158,10 @@ func PeerLabel(fd uintptr) (string, error) {
} }
// SetKeyLabel takes a process label and tells the kernel to assign the // SetKeyLabel takes a process label and tells the kernel to assign the
// label to the next kernel keyring that gets created // label to the next kernel keyring that gets created. Calls to SetKeyLabel
// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until
// the kernel keyring is created to guarantee another goroutine does not migrate
// to the current thread before execution is complete.
func SetKeyLabel(label string) error { func SetKeyLabel(label string) error {
return setKeyLabel(label) return setKeyLabel(label)
} }
@ -247,3 +267,12 @@ func DupSecOpt(src string) ([]string, error) {
func DisableSecOpt() []string { func DisableSecOpt() []string {
return disableSecOpt() return disableSecOpt()
} }
// GetDefaultContextWithLevel gets a single context for the specified SELinux user
// identity that is reachable from the specified scon context. The context is based
// on the per-user /etc/selinux/{SELINUXTYPE}/contexts/users/<username> if it exists,
// and falls back to the global /etc/selinux/{SELINUXTYPE}/contexts/default_contexts
// file.
func GetDefaultContextWithLevel(user, level, scon string) (string, error) {
return getDefaultContextWithLevel(user, level, scon)
}

View File

@ -1,5 +1,3 @@
// +build selinux,linux
package selinux package selinux
import ( import (
@ -28,6 +26,8 @@ const (
minSensLen = 2 minSensLen = 2
contextFile = "/usr/share/containers/selinux/contexts" contextFile = "/usr/share/containers/selinux/contexts"
selinuxDir = "/etc/selinux/" selinuxDir = "/etc/selinux/"
selinuxUsersDir = "contexts/users"
defaultContexts = "contexts/default_contexts"
selinuxConfig = selinuxDir + "config" selinuxConfig = selinuxDir + "config"
selinuxfsMount = "/sys/fs/selinux" selinuxfsMount = "/sys/fs/selinux"
selinuxTypeTag = "SELINUXTYPE" selinuxTypeTag = "SELINUXTYPE"
@ -35,6 +35,8 @@ const (
xattrNameSelinux = "security.selinux" xattrNameSelinux = "security.selinux"
) )
var policyRoot = filepath.Join(selinuxDir, readConfig(selinuxTypeTag))
type selinuxState struct { type selinuxState struct {
enabledSet bool enabledSet bool
enabled bool enabled bool
@ -54,6 +56,13 @@ type mlsRange struct {
high *level high *level
} }
type defaultSECtx struct {
user, level, scon string
userRdr, defaultRdr io.Reader
verifier func(string) error
}
type levelItem byte type levelItem byte
const ( const (
@ -111,7 +120,7 @@ func verifySELinuxfsMount(mnt string) bool {
if err == nil { if err == nil {
break break
} }
if err == unix.EAGAIN { if err == unix.EAGAIN || err == unix.EINTR {
continue continue
} }
return false return false
@ -205,28 +214,16 @@ func getEnabled() bool {
} }
func readConfig(target string) string { func readConfig(target string) string {
var (
val, key string
bufin *bufio.Reader
)
in, err := os.Open(selinuxConfig) in, err := os.Open(selinuxConfig)
if err != nil { if err != nil {
return "" return ""
} }
defer in.Close() defer in.Close()
bufin = bufio.NewReader(in) scanner := bufio.NewScanner(in)
for done := false; !done; { for scanner.Scan() {
var line string line := strings.TrimSpace(scanner.Text())
if line, err = bufin.ReadString('\n'); err != nil {
if err != io.EOF {
return ""
}
done = true
}
line = strings.TrimSpace(line)
if len(line) == 0 { if len(line) == 0 {
// Skip blank lines // Skip blank lines
continue continue
@ -236,7 +233,7 @@ func readConfig(target string) string {
continue continue
} }
if groups := assignRegex.FindStringSubmatch(line); groups != nil { if groups := assignRegex.FindStringSubmatch(line); groups != nil {
key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) key, val := strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
if key == target { if key == target {
return strings.Trim(val, "\"") return strings.Trim(val, "\"")
} }
@ -245,15 +242,17 @@ func readConfig(target string) string {
return "" return ""
} }
func getSELinuxPolicyRoot() string {
return filepath.Join(selinuxDir, readConfig(selinuxTypeTag))
}
func isProcHandle(fh *os.File) error { func isProcHandle(fh *os.File) error {
var buf unix.Statfs_t var buf unix.Statfs_t
err := unix.Fstatfs(int(fh.Fd()), &buf)
if err != nil { for {
return errors.Wrapf(err, "statfs(%q) failed", fh.Name()) err := unix.Fstatfs(int(fh.Fd()), &buf)
if err == nil {
break
}
if err != unix.EINTR {
return errors.Wrapf(err, "statfs(%q) failed", fh.Name())
}
} }
if buf.Type != unix.PROC_SUPER_MAGIC { if buf.Type != unix.PROC_SUPER_MAGIC {
return errors.Errorf("file %q is not on procfs", fh.Name()) return errors.Errorf("file %q is not on procfs", fh.Name())
@ -307,9 +306,16 @@ func setFileLabel(fpath string, label string) error {
if fpath == "" { if fpath == "" {
return ErrEmptyPath return ErrEmptyPath
} }
if err := unix.Lsetxattr(fpath, xattrNameSelinux, []byte(label), 0); err != nil { for {
return errors.Wrapf(err, "failed to set file label on %s", fpath) err := unix.Lsetxattr(fpath, xattrNameSelinux, []byte(label), 0)
if err == nil {
break
}
if err != unix.EINTR {
return errors.Wrapf(err, "failed to set file label on %s", fpath)
}
} }
return nil return nil
} }
@ -751,7 +757,7 @@ 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 { if len(con) > 3 {
mcsAdd(con[3]) _ = mcsAdd(con[3])
} }
} }
} }
@ -828,11 +834,11 @@ func intToMcs(id int, catRange uint32) string {
} }
for ORD > TIER { for ORD > TIER {
ORD = ORD - TIER ORD -= TIER
TIER-- TIER--
} }
TIER = SETSIZE - TIER TIER = SETSIZE - TIER
ORD = ORD + TIER ORD += TIER
return fmt.Sprintf("s0:c%d,c%d", TIER, ORD) return fmt.Sprintf("s0:c%d,c%d", TIER, ORD)
} }
@ -844,16 +850,14 @@ func uniqMcs(catRange uint32) string {
) )
for { for {
binary.Read(rand.Reader, binary.LittleEndian, &n) _ = binary.Read(rand.Reader, binary.LittleEndian, &n)
c1 = n % catRange c1 = n % catRange
binary.Read(rand.Reader, binary.LittleEndian, &n) _ = binary.Read(rand.Reader, binary.LittleEndian, &n)
c2 = n % catRange c2 = n % catRange
if c1 == c2 { if c1 == c2 {
continue continue
} else { } else if c1 > c2 {
if c1 > c2 { c1, c2 = c2, c1
c1, c2 = c2, c1
}
} }
mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2) mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2)
if err := mcsAdd(mcs); err != nil { if err := mcsAdd(mcs); err != nil {
@ -884,18 +888,13 @@ 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
} }
lxcPath := filepath.Join(getSELinuxPolicyRoot(), "/contexts/lxc_contexts") lxcPath := filepath.Join(policyRoot, "/contexts/lxc_contexts")
return os.Open(lxcPath) return os.Open(lxcPath)
} }
var labels = loadLabels() var labels = loadLabels()
func loadLabels() map[string]string { func loadLabels() map[string]string {
var (
val, key string
bufin *bufio.Reader
)
labels := make(map[string]string) labels := make(map[string]string)
in, err := openContextFile() in, err := openContextFile()
if err != nil { if err != nil {
@ -903,18 +902,10 @@ func loadLabels() map[string]string {
} }
defer in.Close() defer in.Close()
bufin = bufio.NewReader(in) scanner := bufio.NewScanner(in)
for done := false; !done; { for scanner.Scan() {
var line string line := strings.TrimSpace(scanner.Text())
if line, err = bufin.ReadString('\n'); err != nil {
if err == io.EOF {
done = true
} else {
break
}
}
line = strings.TrimSpace(line)
if len(line) == 0 { if len(line) == 0 {
// Skip blank lines // Skip blank lines
continue continue
@ -924,7 +915,7 @@ func loadLabels() map[string]string {
continue continue
} }
if groups := assignRegex.FindStringSubmatch(line); groups != nil { if groups := assignRegex.FindStringSubmatch(line); groups != nil {
key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) key, val := strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
labels[key] = strings.Trim(val, "\"") labels[key] = strings.Trim(val, "\"")
} }
} }
@ -1015,7 +1006,7 @@ func copyLevel(src, dest string) (string, error) {
return "", err return "", err
} }
mcsDelete(tcon["level"]) mcsDelete(tcon["level"])
mcsAdd(scon["level"]) _ = mcsAdd(scon["level"])
tcon["level"] = scon["level"] tcon["level"] = scon["level"]
return tcon.Get(), nil return tcon.Get(), nil
} }
@ -1095,3 +1086,124 @@ func dupSecOpt(src string) ([]string, error) {
func disableSecOpt() []string { func disableSecOpt() []string {
return []string{"disable"} return []string{"disable"}
} }
// findUserInContext scans the reader for a valid SELinux context
// match that is verified with the verifier. Invalid contexts are
// skipped. It returns a matched context or an empty string if no
// match is found. If a scanner error occurs, it is returned.
func findUserInContext(context Context, r io.Reader, verifier func(string) error) (string, error) {
fromRole := context["role"]
fromType := context["type"]
scanner := bufio.NewScanner(r)
for scanner.Scan() {
fromConns := strings.Fields(scanner.Text())
if len(fromConns) == 0 {
// Skip blank lines
continue
}
line := fromConns[0]
if line[0] == ';' || line[0] == '#' {
// Skip comments
continue
}
// user context files contexts are formatted as
// role_r:type_t:s0 where the user is missing.
lineArr := strings.SplitN(line, ":", 4)
// skip context with typo, or role and type do not match
if len(lineArr) != 3 ||
lineArr[0] != fromRole ||
lineArr[1] != fromType {
continue
}
for _, cc := range fromConns[1:] {
toConns := strings.SplitN(cc, ":", 4)
if len(toConns) != 3 {
continue
}
context["role"] = toConns[0]
context["type"] = toConns[1]
outConn := context.get()
if err := verifier(outConn); err != nil {
continue
}
return outConn, nil
}
}
if err := scanner.Err(); err != nil {
return "", errors.Wrap(err, "failed to scan for context")
}
return "", nil
}
func getDefaultContextFromReaders(c *defaultSECtx) (string, error) {
if c.verifier == nil {
return "", ErrVerifierNil
}
context, err := newContext(c.scon)
if err != nil {
return "", errors.Wrapf(err, "failed to create label for %s", c.scon)
}
// set so the verifier validates the matched context with the provided user and level.
context["user"] = c.user
context["level"] = c.level
conn, err := findUserInContext(context, c.userRdr, c.verifier)
if err != nil {
return "", err
}
if conn != "" {
return conn, nil
}
conn, err = findUserInContext(context, c.defaultRdr, c.verifier)
if err != nil {
return "", err
}
if conn != "" {
return conn, nil
}
return "", errors.Wrapf(ErrContextMissing, "context not found: %q", c.scon)
}
func getDefaultContextWithLevel(user, level, scon string) (string, error) {
userPath := filepath.Join(policyRoot, selinuxUsersDir, user)
defaultPath := filepath.Join(policyRoot, defaultContexts)
fu, err := os.Open(userPath)
if err != nil {
return "", err
}
defer fu.Close()
fd, err := os.Open(defaultPath)
if err != nil {
return "", err
}
defer fd.Close()
c := defaultSECtx{
user: user,
level: level,
scon: scon,
userRdr: fu,
defaultRdr: fd,
verifier: securityCheckContext,
}
return getDefaultContextFromReaders(&c)
}

View File

@ -1,4 +1,4 @@
// +build !selinux !linux // +build !linux
package selinux package selinux
@ -146,3 +146,7 @@ func dupSecOpt(src string) ([]string, error) {
func disableSecOpt() []string { func disableSecOpt() []string {
return []string{"disable"} return []string{"disable"}
} }
func getDefaultContextWithLevel(user, level, scon string) (string, error) {
return "", nil
}

View File

@ -1,30 +0,0 @@
// +build selinux,linux
package selinux
import (
"golang.org/x/sys/unix"
)
// Returns a []byte slice if the xattr is set and nil otherwise
// Requires path and its attribute as arguments
func lgetxattr(path string, attr string) ([]byte, error) {
// Start with a 128 length byte array
dest := make([]byte, 128)
sz, errno := unix.Lgetxattr(path, attr, dest)
for errno == unix.ERANGE {
// Buffer too small, use zero-sized buffer to get the actual size
sz, errno = unix.Lgetxattr(path, attr, []byte{})
if errno != nil {
return nil, errno
}
dest = make([]byte, sz)
sz, errno = unix.Lgetxattr(path, attr, dest)
}
if errno != nil {
return nil, errno
}
return dest[:sz], nil
}

View File

@ -0,0 +1,38 @@
package selinux
import (
"golang.org/x/sys/unix"
)
// lgetxattr returns a []byte slice containing the value of
// an extended attribute attr set for path.
func lgetxattr(path, attr string) ([]byte, error) {
// Start with a 128 length byte array
dest := make([]byte, 128)
sz, errno := doLgetxattr(path, attr, dest)
for errno == unix.ERANGE {
// Buffer too small, use zero-sized buffer to get the actual size
sz, errno = doLgetxattr(path, attr, []byte{})
if errno != nil {
return nil, errno
}
dest = make([]byte, sz)
sz, errno = doLgetxattr(path, attr, dest)
}
if errno != nil {
return nil, errno
}
return dest[:sz], nil
}
// doLgetxattr is a wrapper that retries on EINTR
func doLgetxattr(path, attr string, dest []byte) (int, error) {
for {
sz, err := unix.Lgetxattr(path, attr, dest)
if err != unix.EINTR {
return sz, err
}
}
}

View File

@ -20,17 +20,16 @@ type WalkFunc = filepath.WalkFunc
// //
// Note that this implementation only supports primitive error handling: // Note that this implementation only supports primitive error handling:
// //
// * no errors are ever passed to WalkFn // - no errors are ever passed to WalkFn;
// //
// * once a walkFn returns any error, all further processing stops // - once a walkFn returns any error, all further processing stops
// and the error is returned to the caller of Walk; // and the error is returned to the caller of Walk;
// //
// * filepath.SkipDir is not supported; // - 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.
// //
// - 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 { func Walk(root string, walkFn WalkFunc) error {
return WalkN(root, walkFn, runtime.NumCPU()*2) return WalkN(root, walkFn, runtime.NumCPU()*2)
} }
@ -38,6 +37,8 @@ func Walk(root string, walkFn WalkFunc) error {
// WalkN is a wrapper for filepath.Walk which can call multiple walkFn // WalkN is a wrapper for filepath.Walk which can call multiple walkFn
// in parallel, allowing to handle each item concurrently. A maximum of // in parallel, allowing to handle each item concurrently. A maximum of
// num walkFn will be called at any one time. // 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 { func WalkN(root string, walkFn WalkFunc, num int) error {
// make sure limit is sensible // make sure limit is sensible
if num < 1 { if num < 1 {

3
vendor/modules.txt vendored
View File

@ -268,7 +268,7 @@ github.com/opencontainers/runc/libcontainer/user
# github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6 # github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6
## explicit ## explicit
github.com/opencontainers/runtime-spec/specs-go github.com/opencontainers/runtime-spec/specs-go
# github.com/opencontainers/selinux v1.6.0 # github.com/opencontainers/selinux v1.8.0
## explicit ## explicit
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
@ -314,7 +314,6 @@ github.com/tchap/go-patricia/patricia
## explicit ## explicit
github.com/urfave/cli github.com/urfave/cli
# github.com/willf/bitset v1.1.11 # github.com/willf/bitset v1.1.11
## explicit
github.com/willf/bitset github.com/willf/bitset
# go.etcd.io/bbolt v1.3.5 # go.etcd.io/bbolt v1.3.5
## explicit ## explicit