vendor: cadvisor v0.38.4

This commit is contained in:
David Porter
2020-11-13 19:52:57 +00:00
parent ec734aced7
commit 8af7405f17
396 changed files with 73154 additions and 18510 deletions

View File

@@ -12,16 +12,17 @@ go_library(
importmap = "k8s.io/kubernetes/vendor/github.com/opencontainers/runc/libcontainer/cgroups",
importpath = "github.com/opencontainers/runc/libcontainer/cgroups",
visibility = ["//visibility:public"],
deps = select({
deps = [
"//vendor/github.com/cyphar/filepath-securejoin:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
] + select({
"@io_bazel_rules_go//go/platform:android": [
"//vendor/github.com/docker/go-units:go_default_library",
"//vendor/github.com/opencontainers/runc/libcontainer/configs:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:linux": [
"//vendor/github.com/docker/go-units:go_default_library",
"//vendor/github.com/opencontainers/runc/libcontainer/configs:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"//conditions:default": [],
}),

View File

@@ -22,12 +22,8 @@ func (s *BlkioGroup) Name() string {
return "blkio"
}
func (s *BlkioGroup) Apply(d *cgroupData) error {
_, err := d.join("blkio")
if err != nil && !cgroups.IsNotFound(err) {
return err
}
return nil
func (s *BlkioGroup) Apply(path string, d *cgroupData) error {
return join(path, d.pid)
}
func (s *BlkioGroup) Set(path string, cgroup *configs.Cgroup) error {
@@ -74,10 +70,6 @@ func (s *BlkioGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
func (s *BlkioGroup) Remove(d *cgroupData) error {
return removePath(d.path("blkio"))
}
/*
examples:

View File

@@ -21,17 +21,7 @@ func (s *CpuGroup) Name() string {
return "cpu"
}
func (s *CpuGroup) Apply(d *cgroupData) error {
// We always want to join the cpu group, to allow fair cpu scheduling
// on a container basis
path, err := d.path("cpu")
if err != nil && !cgroups.IsNotFound(err) {
return err
}
return s.ApplyDir(path, d.config, d.pid)
}
func (s *CpuGroup) ApplyDir(path string, cgroup *configs.Cgroup, pid int) error {
func (s *CpuGroup) Apply(path string, d *cgroupData) error {
// This might happen if we have no cpu cgroup mounted.
// Just do nothing and don't fail.
if path == "" {
@@ -43,12 +33,12 @@ func (s *CpuGroup) ApplyDir(path string, cgroup *configs.Cgroup, pid int) error
// We should set the real-Time group scheduling settings before moving
// in the process because if the process is already in SCHED_RR mode
// and no RT bandwidth is set, adding it will fail.
if err := s.SetRtSched(path, cgroup); err != nil {
if err := s.SetRtSched(path, d.config); err != nil {
return err
}
// because we are not using d.join we need to place the pid into the procs file
// unlike the other subsystems
return cgroups.WriteCgroupProc(path, pid)
// Since we are not using join(), we need to place the pid
// into the procs file unlike other subsystems.
return cgroups.WriteCgroupProc(path, d.pid)
}
func (s *CpuGroup) SetRtSched(path string, cgroup *configs.Cgroup) error {
@@ -96,10 +86,6 @@ func (s *CpuGroup) Set(path string, cgroup *configs.Cgroup) error {
return s.SetRtSched(path, cgroup)
}
func (s *CpuGroup) Remove(d *cgroupData) error {
return removePath(d.path("cpu"))
}
func (s *CpuGroup) GetStats(path string, stats *cgroups.Stats) error {
f, err := os.Open(filepath.Join(path, "cpu.stat"))
if err != nil {

View File

@@ -40,24 +40,18 @@ func (s *CpuacctGroup) Name() string {
return "cpuacct"
}
func (s *CpuacctGroup) Apply(d *cgroupData) error {
// we just want to join this group even though we don't set anything
if _, err := d.join("cpuacct"); err != nil && !cgroups.IsNotFound(err) {
return err
}
return nil
func (s *CpuacctGroup) Apply(path string, d *cgroupData) error {
return join(path, d.pid)
}
func (s *CpuacctGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
func (s *CpuacctGroup) Remove(d *cgroupData) error {
return removePath(d.path("cpuacct"))
}
func (s *CpuacctGroup) GetStats(path string, stats *cgroups.Stats) error {
if !cgroups.PathExists(path) {
return nil
}
userModeUsage, kernelModeUsage, err := getCpuUsageBreakdown(path)
if err != nil {
return err

View File

@@ -23,12 +23,8 @@ func (s *CpusetGroup) Name() string {
return "cpuset"
}
func (s *CpusetGroup) Apply(d *cgroupData) error {
dir, err := d.path("cpuset")
if err != nil && !cgroups.IsNotFound(err) {
return err
}
return s.ApplyDir(dir, d.config, d.pid)
func (s *CpusetGroup) Apply(path string, d *cgroupData) error {
return s.ApplyDir(path, d.config, d.pid)
}
func (s *CpusetGroup) Set(path string, cgroup *configs.Cgroup) error {
@@ -45,10 +41,6 @@ func (s *CpusetGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
func (s *CpusetGroup) Remove(d *cgroupData) error {
return removePath(d.path("cpuset"))
}
func (s *CpusetGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}

View File

@@ -22,17 +22,16 @@ func (s *DevicesGroup) Name() string {
return "devices"
}
func (s *DevicesGroup) Apply(d *cgroupData) error {
func (s *DevicesGroup) Apply(path string, d *cgroupData) error {
if d.config.SkipDevices {
return nil
}
_, err := d.join("devices")
if err != nil {
// We will return error even it's `not found` error, devices
// cgroup is hard requirement for container's security.
return err
if path == "" {
// Return error here, since devices cgroup
// is a hard requirement for container's security.
return errSubsystemDoesNotExist
}
return nil
return join(path, d.pid)
}
func loadEmulator(path string) (*devices.Emulator, error) {
@@ -106,10 +105,6 @@ func (s *DevicesGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
func (s *DevicesGroup) Remove(d *cgroupData) error {
return removePath(d.path("devices"))
}
func (s *DevicesGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}

View File

@@ -22,12 +22,8 @@ func (s *FreezerGroup) Name() string {
return "freezer"
}
func (s *FreezerGroup) Apply(d *cgroupData) error {
_, err := d.join("freezer")
if err != nil && !cgroups.IsNotFound(err) {
return err
}
return nil
func (s *FreezerGroup) Apply(path string, d *cgroupData) error {
return join(path, d.pid)
}
func (s *FreezerGroup) Set(path string, cgroup *configs.Cgroup) error {
@@ -61,10 +57,6 @@ func (s *FreezerGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
func (s *FreezerGroup) Remove(d *cgroupData) error {
return removePath(d.path("freezer"))
}
func (s *FreezerGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}

View File

@@ -18,7 +18,7 @@ import (
)
var (
subsystemsLegacy = subsystemSet{
subsystems = []subsystem{
&CpusetGroup{},
&DevicesGroup{},
&MemoryGroup{},
@@ -38,26 +38,13 @@ var (
var errSubsystemDoesNotExist = errors.New("cgroup: subsystem does not exist")
type subsystemSet []subsystem
func (s subsystemSet) Get(name string) (subsystem, error) {
for _, ss := range s {
if ss.Name() == name {
return ss, nil
}
}
return nil, errSubsystemDoesNotExist
}
type subsystem interface {
// Name returns the name of the subsystem.
Name() string
// Returns the stats, as 'stats', corresponding to the cgroup under 'path'.
GetStats(path string, stats *cgroups.Stats) error
// Removes the cgroup represented by 'cgroupData'.
Remove(*cgroupData) error
// Creates and joins the cgroup represented by 'cgroupData'.
Apply(*cgroupData) error
Apply(path string, c *cgroupData) error
// Set the cgroup represented by cgroup.
Set(path string, cgroup *configs.Cgroup) error
}
@@ -81,6 +68,56 @@ func NewManager(cg *configs.Cgroup, paths map[string]string, rootless bool) cgro
var cgroupRootLock sync.Mutex
var cgroupRoot string
const defaultCgroupRoot = "/sys/fs/cgroup"
func tryDefaultCgroupRoot() string {
var st, pst unix.Stat_t
// (1) it should be a directory...
err := unix.Lstat(defaultCgroupRoot, &st)
if err != nil || st.Mode&unix.S_IFDIR == 0 {
return ""
}
// (2) ... and a mount point ...
err = unix.Lstat(filepath.Dir(defaultCgroupRoot), &pst)
if err != nil {
return ""
}
if st.Dev == pst.Dev {
// parent dir has the same dev -- not a mount point
return ""
}
// (3) ... of 'tmpfs' fs type.
var fst unix.Statfs_t
err = unix.Statfs(defaultCgroupRoot, &fst)
if err != nil || fst.Type != unix.TMPFS_MAGIC {
return ""
}
// (4) it should have at least 1 entry ...
dir, err := os.Open(defaultCgroupRoot)
if err != nil {
return ""
}
names, err := dir.Readdirnames(1)
if err != nil {
return ""
}
if len(names) < 1 {
return ""
}
// ... which is a cgroup mount point.
err = unix.Statfs(filepath.Join(defaultCgroupRoot, names[0]), &fst)
if err != nil || fst.Type != unix.CGROUP_SUPER_MAGIC {
return ""
}
return defaultCgroupRoot
}
// Gets the cgroupRoot.
func getCgroupRoot() (string, error) {
cgroupRootLock.Lock()
@@ -90,6 +127,14 @@ func getCgroupRoot() (string, error) {
return cgroupRoot, nil
}
// fast path
cgroupRoot = tryDefaultCgroupRoot()
if cgroupRoot != "" {
return cgroupRoot, nil
}
// slow path: parse mountinfo, find the first mount where fs=cgroup
// (e.g. "/sys/fs/cgroup/memory"), use its parent.
f, err := os.Open("/proc/self/mountinfo")
if err != nil {
return "", err
@@ -166,10 +211,6 @@ func isIgnorableError(rootless bool, err error) bool {
return false
}
func (m *manager) getSubsystems() subsystemSet {
return subsystemsLegacy
}
func (m *manager) Apply(pid int) (err error) {
if m.cgroups == nil {
return nil
@@ -199,7 +240,7 @@ func (m *manager) Apply(pid int) (err error) {
return cgroups.EnterPid(m.paths, pid)
}
for _, sys := range m.getSubsystems() {
for _, sys := range subsystems {
p, err := d.path(sys.Name())
if err != nil {
// The non-presence of the devices subsystem is
@@ -211,7 +252,7 @@ func (m *manager) Apply(pid int) (err error) {
}
m.paths[sys.Name()] = p
if err := sys.Apply(d); err != nil {
if err := sys.Apply(p, d); err != nil {
// In the case of rootless (including euid=0 in userns), where an
// explicit cgroup path hasn't been set, we don't bail on error in
// case of permission problems. Cases where limits have been set
@@ -250,9 +291,9 @@ func (m *manager) GetStats() (*cgroups.Stats, error) {
m.mu.Lock()
defer m.mu.Unlock()
stats := cgroups.NewStats()
for name, path := range m.paths {
sys, err := m.getSubsystems().Get(name)
if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) {
for _, sys := range subsystems {
path := m.paths[sys.Name()]
if path == "" {
continue
}
if err := sys.GetStats(path, stats); err != nil {
@@ -275,7 +316,7 @@ func (m *manager) Set(container *configs.Config) error {
m.mu.Lock()
defer m.mu.Unlock()
for _, sys := range m.getSubsystems() {
for _, sys := range subsystems {
path := m.paths[sys.Name()]
if err := sys.Set(path, container.Cgroups); err != nil {
if m.rootless && sys.Name() == "devices" {
@@ -374,18 +415,14 @@ func (raw *cgroupData) path(subsystem string) (string, error) {
return filepath.Join(parentPath, raw.innerPath), nil
}
func (raw *cgroupData) join(subsystem string) (string, error) {
path, err := raw.path(subsystem)
if err != nil {
return "", err
func join(path string, pid int) error {
if path == "" {
return nil
}
if err := os.MkdirAll(path, 0755); err != nil {
return "", err
return err
}
if err := cgroups.WriteCgroupProc(path, raw.pid); err != nil {
return "", err
}
return path, nil
return cgroups.WriteCgroupProc(path, pid)
}
func removePath(p string, err error) error {

View File

@@ -19,12 +19,8 @@ func (s *HugetlbGroup) Name() string {
return "hugetlb"
}
func (s *HugetlbGroup) Apply(d *cgroupData) error {
_, err := d.join("hugetlb")
if err != nil && !cgroups.IsNotFound(err) {
return err
}
return nil
func (s *HugetlbGroup) Apply(path string, d *cgroupData) error {
return join(path, d.pid)
}
func (s *HugetlbGroup) Set(path string, cgroup *configs.Cgroup) error {
@@ -37,12 +33,11 @@ func (s *HugetlbGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
func (s *HugetlbGroup) Remove(d *cgroupData) error {
return removePath(d.path("hugetlb"))
}
func (s *HugetlbGroup) GetStats(path string, stats *cgroups.Stats) error {
hugetlbStats := cgroups.HugetlbStats{}
if !cgroups.PathExists(path) {
return nil
}
for _, pageSize := range HugePageSizes {
usage := strings.Join([]string{"hugetlb", pageSize, "usage_in_bytes"}, ".")
value, err := fscommon.GetCgroupParamUint(path, usage)

View File

@@ -37,11 +37,8 @@ func (s *MemoryGroup) Name() string {
return "memory"
}
func (s *MemoryGroup) Apply(d *cgroupData) (err error) {
path, err := d.path("memory")
if err != nil && !cgroups.IsNotFound(err) {
return err
} else if path == "" {
func (s *MemoryGroup) Apply(path string, d *cgroupData) (err error) {
if path == "" {
return nil
}
if memoryAssigned(d.config) {
@@ -66,11 +63,7 @@ func (s *MemoryGroup) Apply(d *cgroupData) (err error) {
// We need to join memory cgroup after set memory limits, because
// kmem.limit_in_bytes can only be set when the cgroup is empty.
_, err = d.join("memory")
if err != nil && !cgroups.IsNotFound(err) {
return err
}
return nil
return join(path, d.pid)
}
func setMemoryAndSwap(path string, cgroup *configs.Cgroup) error {
@@ -165,10 +158,6 @@ func (s *MemoryGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
func (s *MemoryGroup) Remove(d *cgroupData) error {
return removePath(d.path("memory"))
}
func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error {
// Set stats from memory.stat.
statsFile, err := os.Open(filepath.Join(path, "memory.stat"))

View File

@@ -16,10 +16,10 @@ func (s *NameGroup) Name() string {
return s.GroupName
}
func (s *NameGroup) Apply(d *cgroupData) error {
func (s *NameGroup) Apply(path string, d *cgroupData) error {
if s.Join {
// ignore errors if the named cgroup does not exist
d.join(s.GroupName)
join(path, d.pid)
}
return nil
}
@@ -28,13 +28,6 @@ func (s *NameGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
func (s *NameGroup) Remove(d *cgroupData) error {
if s.Join {
removePath(d.path(s.GroupName))
}
return nil
}
func (s *NameGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}

View File

@@ -17,12 +17,8 @@ func (s *NetClsGroup) Name() string {
return "net_cls"
}
func (s *NetClsGroup) Apply(d *cgroupData) error {
_, err := d.join("net_cls")
if err != nil && !cgroups.IsNotFound(err) {
return err
}
return nil
func (s *NetClsGroup) Apply(path string, d *cgroupData) error {
return join(path, d.pid)
}
func (s *NetClsGroup) Set(path string, cgroup *configs.Cgroup) error {
@@ -35,10 +31,6 @@ func (s *NetClsGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
func (s *NetClsGroup) Remove(d *cgroupData) error {
return removePath(d.path("net_cls"))
}
func (s *NetClsGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}

View File

@@ -15,12 +15,8 @@ func (s *NetPrioGroup) Name() string {
return "net_prio"
}
func (s *NetPrioGroup) Apply(d *cgroupData) error {
_, err := d.join("net_prio")
if err != nil && !cgroups.IsNotFound(err) {
return err
}
return nil
func (s *NetPrioGroup) Apply(path string, d *cgroupData) error {
return join(path, d.pid)
}
func (s *NetPrioGroup) Set(path string, cgroup *configs.Cgroup) error {
@@ -33,10 +29,6 @@ func (s *NetPrioGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
func (s *NetPrioGroup) Remove(d *cgroupData) error {
return removePath(d.path("net_prio"))
}
func (s *NetPrioGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}

View File

@@ -14,22 +14,14 @@ func (s *PerfEventGroup) Name() string {
return "perf_event"
}
func (s *PerfEventGroup) Apply(d *cgroupData) error {
// we just want to join this group even though we don't set anything
if _, err := d.join("perf_event"); err != nil && !cgroups.IsNotFound(err) {
return err
}
return nil
func (s *PerfEventGroup) Apply(path string, d *cgroupData) error {
return join(path, d.pid)
}
func (s *PerfEventGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
func (s *PerfEventGroup) Remove(d *cgroupData) error {
return removePath(d.path("perf_event"))
}
func (s *PerfEventGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}

View File

@@ -19,12 +19,8 @@ func (s *PidsGroup) Name() string {
return "pids"
}
func (s *PidsGroup) Apply(d *cgroupData) error {
_, err := d.join("pids")
if err != nil && !cgroups.IsNotFound(err) {
return err
}
return nil
func (s *PidsGroup) Apply(path string, d *cgroupData) error {
return join(path, d.pid)
}
func (s *PidsGroup) Set(path string, cgroup *configs.Cgroup) error {
@@ -44,11 +40,10 @@ func (s *PidsGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
func (s *PidsGroup) Remove(d *cgroupData) error {
return removePath(d.path("pids"))
}
func (s *PidsGroup) GetStats(path string, stats *cgroups.Stats) error {
if !cgroups.PathExists(path) {
return nil
}
current, err := fscommon.GetCgroupParamUint(path, "pids.current")
if err != nil {
return fmt.Errorf("failed to parse pids.current - %s", err)

View File

@@ -41,18 +41,7 @@ type subsystem interface {
var errSubsystemDoesNotExist = errors.New("cgroup: subsystem does not exist")
type subsystemSet []subsystem
func (s subsystemSet) Get(name string) (subsystem, error) {
for _, ss := range s {
if ss.Name() == name {
return ss, nil
}
}
return nil, errSubsystemDoesNotExist
}
var legacySubsystems = subsystemSet{
var legacySubsystems = []subsystem{
&fs.CpusetGroup{},
&fs.DevicesGroup{},
&fs.MemoryGroup{},
@@ -355,9 +344,9 @@ func (m *legacyManager) GetStats() (*cgroups.Stats, error) {
m.mu.Lock()
defer m.mu.Unlock()
stats := cgroups.NewStats()
for name, path := range m.paths {
sys, err := legacySubsystems.Get(name)
if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) {
for _, sys := range legacySubsystems {
path := m.paths[sys.Name()]
if path == "" {
continue
}
if err := sys.GetStats(path, stats); err != nil {

View File

@@ -8,6 +8,10 @@ import (
"os"
"path/filepath"
"strings"
"syscall"
securejoin "github.com/cyphar/filepath-securejoin"
"golang.org/x/sys/unix"
)
// Code in this source file are specific to cgroup v1,
@@ -15,6 +19,7 @@ import (
const (
CgroupNamePrefix = "name="
defaultPrefix = "/sys/fs/cgroup"
)
var (
@@ -43,11 +48,59 @@ func IsNotFound(err error) bool {
return ok
}
func tryDefaultPath(cgroupPath, subsystem string) string {
if !strings.HasPrefix(defaultPrefix, cgroupPath) {
return ""
}
// remove possible prefix
subsystem = strings.TrimPrefix(subsystem, CgroupNamePrefix)
// Make sure we're still under defaultPrefix, and resolve
// a possible symlink (like cpu -> cpu,cpuacct).
path, err := securejoin.SecureJoin(defaultPrefix, subsystem)
if err != nil {
return ""
}
// (1) path should be a directory.
st, err := os.Lstat(path)
if err != nil || !st.IsDir() {
return ""
}
// (2) path should be a mount point.
pst, err := os.Lstat(filepath.Dir(path))
if err != nil {
return ""
}
if st.Sys().(*syscall.Stat_t).Dev == pst.Sys().(*syscall.Stat_t).Dev {
// parent dir has the same dev -- path is not a mount point
return ""
}
// (3) path should have 'cgroup' fs type.
fst := unix.Statfs_t{}
err = unix.Statfs(path, &fst)
if err != nil || fst.Type != unix.CGROUP_SUPER_MAGIC {
return ""
}
return path
}
// https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt
func FindCgroupMountpoint(cgroupPath, subsystem string) (string, error) {
if IsCgroup2UnifiedMode() {
return "", errUnified
}
// Avoid parsing mountinfo by trying the default path first, if possible.
if path := tryDefaultPath(cgroupPath, subsystem); path != "" {
return path, nil
}
mnt, _, err := FindCgroupMountpointAndRoot(cgroupPath, subsystem)
return mnt, err
}
@@ -57,9 +110,7 @@ func FindCgroupMountpointAndRoot(cgroupPath, subsystem string) (string, string,
return "", "", errUnified
}
// We are not using mount.GetMounts() because it's super-inefficient,
// parsing it directly sped up x10 times because of not using Sscanf.
// It was one of two major performance drawbacks in container start.
// Avoid parsing mountinfo by checking if subsystem is valid/available.
if !isSubsystemAvailable(subsystem) {
return "", "", NewNotFoundError(subsystem)
}

View File

@@ -9,6 +9,8 @@ go_library(
"config.go",
"config_linux.go",
"device.go",
"device_unix.go",
"device_windows.go",
"hugepage_limit.go",
"intelrdt.go",
"interface_priority_map.go",
@@ -27,13 +29,50 @@ go_library(
"//vendor/github.com/opencontainers/runtime-spec/specs-go:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/github.com/sirupsen/logrus:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
] + select({
"@io_bazel_rules_go//go/platform:aix": [
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:android": [
"//vendor/github.com/coreos/go-systemd/v22/dbus:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:darwin": [
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:illumos": [
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:ios": [
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:js": [
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:linux": [
"//vendor/github.com/coreos/go-systemd/v22/dbus:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:nacl": [
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:plan9": [
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:solaris": [
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"//conditions:default": [],
}),

View File

@@ -239,15 +239,6 @@ const (
Poststop = "poststop"
)
// TODO move this to runtime-spec
// See: https://github.com/opencontainers/runtime-spec/pull/1046
const (
Creating = "creating"
Created = "created"
Running = "running"
Stopped = "stopped"
)
type Capabilities struct {
// Bounding is the set of capabilities checked by the kernel.
Bounding []string

View File

@@ -1,20 +1,15 @@
package configs
import (
"errors"
"fmt"
"os"
"strconv"
"golang.org/x/sys/unix"
)
const (
Wildcard = -1
)
// TODO Windows: This can be factored out in the future
type Device struct {
DeviceRule
@@ -173,10 +168,3 @@ func (d *DeviceRule) CgroupString() string {
}
return fmt.Sprintf("%c %s:%s %s", d.Type, major, minor, d.Permissions)
}
func (d *DeviceRule) Mkdev() (uint64, error) {
if d.Major == Wildcard || d.Minor == Wildcard {
return 0, errors.New("cannot mkdev() device with wildcards")
}
return unix.Mkdev(uint32(d.Major), uint32(d.Minor)), nil
}

View File

@@ -0,0 +1,16 @@
// +build !windows
package configs
import (
"errors"
"golang.org/x/sys/unix"
)
func (d *DeviceRule) Mkdev() (uint64, error) {
if d.Major == Wildcard || d.Minor == Wildcard {
return 0, errors.New("cannot mkdev() device with wildcards")
}
return unix.Mkdev(uint32(d.Major), uint32(d.Minor)), nil
}

View File

@@ -0,0 +1,5 @@
package configs
func (d *DeviceRule) Mkdev() (uint64, error) {
return 0, nil
}

View File

@@ -764,6 +764,7 @@ func (c *linuxContainer) checkCriuVersion(minVersion int) error {
}
criu := criu.MakeCriu()
criu.SetCriuPath(c.criuPath)
var err error
c.criuVersion, err = criu.GetCriuVersion()
if err != nil {
@@ -836,6 +837,78 @@ func (c *linuxContainer) handleCriuConfigurationFile(rpcOpts *criurpc.CriuOpts)
}
}
func (c *linuxContainer) criuSupportsExtNS(t configs.NamespaceType) bool {
var minVersion int
switch t {
case configs.NEWNET:
// CRIU supports different external namespace with different released CRIU versions.
// For network namespaces to work we need at least criu 3.11.0 => 31100.
minVersion = 31100
case configs.NEWPID:
// For PID namespaces criu 31500 is needed.
minVersion = 31500
default:
return false
}
return c.checkCriuVersion(minVersion) == nil
}
func (c *linuxContainer) criuNsToKey(t configs.NamespaceType) string {
return "extRoot" + strings.Title(configs.NsName(t)) + "NS"
}
func (c *linuxContainer) handleCheckpointingExternalNamespaces(rpcOpts *criurpc.CriuOpts, t configs.NamespaceType) error {
if !c.criuSupportsExtNS(t) {
return nil
}
nsPath := c.config.Namespaces.PathOf(t)
if nsPath == "" {
return nil
}
// CRIU expects the information about an external namespace
// like this: --external <TYPE>[<inode>]:<key>
// This <key> is always 'extRoot<TYPE>NS'.
var ns unix.Stat_t
if err := unix.Stat(nsPath, &ns); err != nil {
return err
}
criuExternal := fmt.Sprintf("%s[%d]:%s", configs.NsName(t), ns.Ino, c.criuNsToKey(t))
rpcOpts.External = append(rpcOpts.External, criuExternal)
return nil
}
func (c *linuxContainer) handleRestoringExternalNamespaces(rpcOpts *criurpc.CriuOpts, extraFiles *[]*os.File, t configs.NamespaceType) error {
if !c.criuSupportsExtNS(t) {
return nil
}
nsPath := c.config.Namespaces.PathOf(t)
if nsPath == "" {
return nil
}
// CRIU wants the information about an existing namespace
// like this: --inherit-fd fd[<fd>]:<key>
// The <key> needs to be the same as during checkpointing.
// We are always using 'extRoot<TYPE>NS' as the key in this.
nsFd, err := os.Open(nsPath)
if err != nil {
logrus.Errorf("If a specific network namespace is defined it must exist: %s", err)
return fmt.Errorf("Requested network namespace %v does not exist", nsPath)
}
inheritFd := new(criurpc.InheritFd)
inheritFd.Key = proto.String(c.criuNsToKey(t))
// The offset of four is necessary because 0, 1, 2 and 3 is already
// used by stdin, stdout, stderr, 'criu swrk' socket.
inheritFd.Fd = proto.Int32(int32(4 + len(*extraFiles)))
rpcOpts.InheritFd = append(rpcOpts.InheritFd, inheritFd)
// All open FDs need to be transferred to CRIU via extraFiles
*extraFiles = append(*extraFiles, nsFd)
return nil
}
func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
c.m.Lock()
defer c.m.Unlock()
@@ -909,25 +982,13 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
// will expect that the namespace exists during restore.
// This basically means that CRIU will ignore the namespace
// and expect to be setup correctly.
nsPath := c.config.Namespaces.PathOf(configs.NEWNET)
if nsPath != "" {
// For this to work we need at least criu 3.11.0 => 31100.
// As there was already a successful version check we will
// not error out if it fails. runc will just behave as it used
// to do and ignore external network namespaces.
err := c.checkCriuVersion(31100)
if err == nil {
// CRIU expects the information about an external namespace
// like this: --external net[<inode>]:<key>
// This <key> is always 'extRootNetNS'.
var netns unix.Stat_t
err = unix.Stat(nsPath, &netns)
if err != nil {
return err
}
criuExternal := fmt.Sprintf("net[%d]:extRootNetNS", netns.Ino)
rpcOpts.External = append(rpcOpts.External, criuExternal)
}
if err := c.handleCheckpointingExternalNamespaces(&rpcOpts, configs.NEWNET); err != nil {
return err
}
// Same for possible external PID namespaces
if err := c.handleCheckpointingExternalNamespaces(&rpcOpts, configs.NEWPID); err != nil {
return err
}
// CRIU can use cgroup freezer; when rpcOpts.FreezeCgroup
@@ -1251,33 +1312,13 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
// Same as during checkpointing. If the container has a specific network namespace
// assigned to it, this now expects that the checkpoint will be restored in a
// already created network namespace.
nsPath := c.config.Namespaces.PathOf(configs.NEWNET)
if nsPath != "" {
// For this to work we need at least criu 3.11.0 => 31100.
// As there was already a successful version check we will
// not error out if it fails. runc will just behave as it used
// to do and ignore external network namespaces.
err := c.checkCriuVersion(31100)
if err == nil {
// CRIU wants the information about an existing network namespace
// like this: --inherit-fd fd[<fd>]:<key>
// The <key> needs to be the same as during checkpointing.
// We are always using 'extRootNetNS' as the key in this.
netns, err := os.Open(nsPath)
if err != nil {
logrus.Errorf("If a specific network namespace is defined it must exist: %s", err)
return fmt.Errorf("Requested network namespace %v does not exist", nsPath)
}
defer netns.Close()
inheritFd := new(criurpc.InheritFd)
inheritFd.Key = proto.String("extRootNetNS")
// The offset of four is necessary because 0, 1, 2 and 3 is already
// used by stdin, stdout, stderr, 'criu swrk' socket.
inheritFd.Fd = proto.Int32(int32(4 + len(extraFiles)))
req.Opts.InheritFd = append(req.Opts.InheritFd, inheritFd)
// All open FDs need to be transferred to CRIU via extraFiles
extraFiles = append(extraFiles, netns)
}
if err := c.handleRestoringExternalNamespaces(req.Opts, &extraFiles, configs.NEWNET); err != nil {
return err
}
// Same for PID namespaces.
if err := c.handleRestoringExternalNamespaces(req.Opts, &extraFiles, configs.NEWPID); err != nil {
return err
}
// This will modify the rootfs of the container in the same way runc
@@ -1345,7 +1386,14 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
req.Opts.InheritFd = append(req.Opts.InheritFd, inheritFd)
}
}
return c.criuSwrk(process, req, criuOpts, extraFiles)
err = c.criuSwrk(process, req, criuOpts, extraFiles)
// Now that CRIU is done let's close all opened FDs CRIU needed.
for _, fd := range extraFiles {
fd.Close()
}
return err
}
func (c *linuxContainer) criuApplyCgroups(pid int, req *criurpc.CriuReq) error {
@@ -1863,7 +1911,7 @@ func (c *linuxContainer) currentOCIState() (*specs.State, error) {
if err != nil {
return nil, err
}
state.Status = status.String()
state.Status = specs.ContainerState(status.String())
if status != Stopped {
if c.initProcess != nil {
state.Pid = c.initProcess.pid()

View File

@@ -19,7 +19,7 @@ import (
"github.com/opencontainers/runc/libcontainer/logs"
"github.com/opencontainers/runc/libcontainer/system"
"github.com/opencontainers/runc/libcontainer/utils"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
@@ -400,7 +400,7 @@ func (p *initProcess) start() (retErr error) {
}
// initProcessStartTime hasn't been set yet.
s.Pid = p.cmd.Process.Pid
s.Status = configs.Creating
s.Status = specs.StateCreating
hooks := p.config.Config.Hooks
if err := hooks[configs.Prestart].RunHooks(s); err != nil {
@@ -433,7 +433,7 @@ func (p *initProcess) start() (retErr error) {
}
// initProcessStartTime hasn't been set yet.
s.Pid = p.cmd.Process.Pid
s.Status = configs.Creating
s.Status = specs.StateCreating
hooks := p.config.Config.Hooks
if err := hooks[configs.Prestart].RunHooks(s); err != nil {

View File

@@ -20,6 +20,7 @@ import (
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/system"
libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux/label"
"golang.org/x/sys/unix"
@@ -100,7 +101,7 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) {
s := iConfig.SpecState
s.Pid = unix.Getpid()
s.Status = configs.Creating
s.Status = specs.StateCreating
if err := iConfig.Config.Hooks[configs.CreateContainer].RunHooks(s); err != nil {
return err
}
@@ -110,7 +111,7 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) {
} else if config.Namespaces.Contains(configs.NEWNS) {
err = pivotRoot(config.Rootfs)
} else {
err = chroot(config.Rootfs)
err = chroot()
}
if err != nil {
return newSystemErrorWithCause(err, "jailing process inside rootfs")
@@ -836,10 +837,10 @@ func msMoveRoot(rootfs string) error {
if err := unix.Mount(rootfs, "/", "", unix.MS_MOVE, ""); err != nil {
return err
}
return chroot(rootfs)
return chroot()
}
func chroot(rootfs string) error {
func chroot() error {
if err := unix.Chroot("."); err != nil {
return err
}

View File

@@ -13,9 +13,9 @@ import (
"github.com/opencontainers/runc/libcontainer/keys"
"github.com/opencontainers/runc/libcontainer/seccomp"
"github.com/opencontainers/runc/libcontainer/system"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux"
"github.com/pkg/errors"
"golang.org/x/sys/unix"
)
@@ -210,7 +210,7 @@ func (l *linuxStandardInit) Init() error {
s := l.config.SpecState
s.Pid = unix.Getpid()
s.Status = configs.Created
s.Status = specs.StateCreated
if err := l.config.Config.Hooks[configs.StartContainer].RunHooks(s); err != nil {
return err
}

View File

@@ -8,7 +8,7 @@ import (
"path/filepath"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
@@ -70,7 +70,7 @@ func runPoststopHooks(c *linuxContainer) error {
if err != nil {
return err
}
s.Status = configs.Stopped
s.Status = specs.StateStopped
if err := hooks[configs.Poststop].RunHooks(s); err != nil {
return err

View File

@@ -90,7 +90,7 @@ type User struct {
// GID is the group id.
GID uint32 `json:"gid" platform:"linux,solaris"`
// Umask is the umask for the init process.
Umask uint32 `json:"umask,omitempty" platform:"linux,solaris"`
Umask *uint32 `json:"umask,omitempty" platform:"linux,solaris"`
// AdditionalGids are additional group ids set for the container's process.
AdditionalGids []uint32 `json:"additionalGids,omitempty" platform:"linux,solaris"`
// Username is the user name.
@@ -635,12 +635,13 @@ type LinuxSeccompAction string
// Define actions for Seccomp rules
const (
ActKill LinuxSeccompAction = "SCMP_ACT_KILL"
ActTrap LinuxSeccompAction = "SCMP_ACT_TRAP"
ActErrno LinuxSeccompAction = "SCMP_ACT_ERRNO"
ActTrace LinuxSeccompAction = "SCMP_ACT_TRACE"
ActAllow LinuxSeccompAction = "SCMP_ACT_ALLOW"
ActLog LinuxSeccompAction = "SCMP_ACT_LOG"
ActKill LinuxSeccompAction = "SCMP_ACT_KILL"
ActKillProcess LinuxSeccompAction = "SCMP_ACT_KILL_PROCESS"
ActTrap LinuxSeccompAction = "SCMP_ACT_TRAP"
ActErrno LinuxSeccompAction = "SCMP_ACT_ERRNO"
ActTrace LinuxSeccompAction = "SCMP_ACT_TRACE"
ActAllow LinuxSeccompAction = "SCMP_ACT_ALLOW"
ActLog LinuxSeccompAction = "SCMP_ACT_LOG"
)
// LinuxSeccompOperator used to match syscall arguments in Seccomp

View File

@@ -1,5 +1,23 @@
package specs
// ContainerState represents the state of a container.
type ContainerState string
const (
// StateCreating indicates that the container is being created
StateCreating ContainerState = "creating"
// StateCreated indicates that the runtime has finished the create operation
StateCreated ContainerState = "created"
// StateRunning indicates that the container process has executed the
// user-specified program but has not exited
StateRunning ContainerState = "running"
// StateStopped indicates that the container process has exited
StateStopped ContainerState = "stopped"
)
// State holds information about the runtime state of the container.
type State struct {
// Version is the version of the specification that is supported.
@@ -7,7 +25,7 @@ type State struct {
// ID is the container ID
ID string `json:"id"`
// Status is the runtime status of the container.
Status string `json:"status"`
Status ContainerState `json:"status"`
// Pid is the process ID for the container process.
Pid int `json:"pid,omitempty"`
// Bundle is the path to the container's bundle directory.

View File

@@ -3,6 +3,8 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"selinux.go",
"selinux_linux.go",
"selinux_stub.go",
"xattrs.go",
@@ -10,15 +12,17 @@ go_library(
importmap = "k8s.io/kubernetes/vendor/github.com/opencontainers/selinux/go-selinux",
importpath = "github.com/opencontainers/selinux/go-selinux",
visibility = ["//visibility:public"],
deps = select({
deps = [
"//vendor/github.com/pkg/errors:go_default_library",
] + select({
"@io_bazel_rules_go//go/platform:android": [
"//vendor/github.com/opencontainers/selinux/pkg/pwalk:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/github.com/willf/bitset:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:linux": [
"//vendor/github.com/opencontainers/selinux/pkg/pwalk:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/github.com/willf/bitset:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"//conditions:default": [],

View File

@@ -0,0 +1,21 @@
/*
Package selinux provides a high-level interface for interacting with selinux.
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
tools that rely on this library.
To compile with full selinux support use the -tags=selinux option in your build
and test commands.
Usage:
import "github.com/opencontainers/selinux/go-selinux"
// Ensure that selinux is enforcing mode.
if selinux.EnforceMode() != selinux.Enforcing {
selinux.SetEnforceMode(selinux.Enforcing)
}
*/
package selinux

View File

@@ -73,9 +73,9 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) {
selinux.ReleaseLabel(processLabel)
}
processLabel = pcon.Get()
mountLabel = mcon.Get()
selinux.ReserveLabel(processLabel)
}
mountLabel = mcon.Get()
}
return processLabel, mountLabel, nil
}

View File

@@ -30,7 +30,6 @@ func Relabel(path string, fileLabel string, shared bool) error {
// DisableSecOpt returns a security opt that can disable labeling
// support for future container processes
func DisableSecOpt() []string {
// TODO the selinux.DisableSecOpt stub returns []string{"disable"} instead of "nil"
return nil
}

View File

@@ -0,0 +1,249 @@
package selinux
import (
"github.com/pkg/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
// DefaultCategoryRange is the upper bound on the category range
DefaultCategoryRange = uint32(1024)
)
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")
// ErrIncomparable is returned two levels are not comparable
ErrIncomparable = errors.New("incomparable levels")
// ErrLevelSyntax is returned when a sensitivity or category do not have correct syntax in a level
ErrLevelSyntax = errors.New("invalid level syntax")
// CategoryRange allows the upper bound on the category range to be adjusted
CategoryRange = DefaultCategoryRange
)
// 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() {
setDisabled()
}
// GetEnabled returns whether SELinux is currently enabled.
func GetEnabled() bool {
return getEnabled()
}
// ClassIndex returns the int index for an object class in the loaded policy,
// or -1 and an error
func ClassIndex(class string) (int, error) {
return classIndex(class)
}
// SetFileLabel sets the SELinux label for this path or returns an error.
func SetFileLabel(fpath string, label string) error {
return setFileLabel(fpath, label)
}
// FileLabel returns the SELinux label for this path or returns an error.
func FileLabel(fpath string) (string, error) {
return fileLabel(fpath)
}
// 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 setFSCreateLabel(label)
}
// 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 fsCreateLabel()
}
// CurrentLabel returns the SELinux label of the current process thread, or an error.
func CurrentLabel() (string, error) {
return currentLabel()
}
// PidLabel returns the SELinux label of the given pid, or an error.
func PidLabel(pid int) (string, error) {
return pidLabel(pid)
}
// 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 execLabel()
}
// CanonicalizeContext takes a context string and writes it to the kernel
// the function then returns the context that the kernel will use. Use this
// function to check if two contexts are equivalent
func CanonicalizeContext(val string) (string, error) {
return canonicalizeContext(val)
}
// ComputeCreateContext requests the type transition from source to target for
// class from the kernel.
func ComputeCreateContext(source string, target string, class string) (string, error) {
return computeCreateContext(source, target, class)
}
// CalculateGlbLub computes the glb (greatest lower bound) and lub (least upper bound)
// of a source and target range.
// The glblub is calculated as the greater of the low sensitivities and
// the lower of the high sensitivities and the and of each category bitset.
func CalculateGlbLub(sourceRange, targetRange string) (string, error) {
return calculateGlbLub(sourceRange, targetRange)
}
// 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 setExecLabel(label)
}
// SetTaskLabel sets the SELinux label for the current thread, or an error.
// This requires the dyntransition permission.
func SetTaskLabel(label string) error {
return setTaskLabel(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 setSocketLabel(label)
}
// SocketLabel retrieves the current socket label setting
func SocketLabel() (string, error) {
return socketLabel()
}
// PeerLabel retrieves the label of the client on the other side of a socket
func PeerLabel(fd uintptr) (string, error) {
return peerLabel(fd)
}
// 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 setKeyLabel(label)
}
// KeyLabel retrieves the current kernel keyring label setting
func KeyLabel() (string, error) {
return keyLabel()
}
// Get returns the Context as a string
func (c Context) Get() string {
return c.get()
}
// NewContext creates a new Context struct from the specified label
func NewContext(label string) (Context, error) {
return newContext(label)
}
// ClearLabels clears all reserved labels
func ClearLabels() {
clearLabels()
}
// ReserveLabel reserves the MLS/MCS level component of the specified label
func ReserveLabel(label string) {
reserveLabel(label)
}
// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
func EnforceMode() int {
return enforceMode()
}
// 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 setEnforceMode(mode)
}
// 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 defaultEnforceMode()
}
// ReleaseLabel un-reserves the MLS/MCS Level field of the specified label,
// allowing it to be used by another process.
func ReleaseLabel(label string) {
releaseLabel(label)
}
// ROFileLabel returns the specified SELinux readonly file label
func ROFileLabel() string {
return roFileLabel()
}
// KVMContainerLabels returns the default processLabel and mountLabel to be used
// for kvm containers by the calling process.
func KVMContainerLabels() (string, string) {
return kvmContainerLabels()
}
// InitContainerLabels returns the default processLabel and file labels to be
// used for containers running an init system like systemd by the calling process.
func InitContainerLabels() (string, string) {
return initContainerLabels()
}
// ContainerLabels returns an allocated processLabel and fileLabel to be used for
// container labeling by the calling process.
func ContainerLabels() (processLabel string, fileLabel string) {
return containerLabels()
}
// SecurityCheckContext validates that the SELinux label is understood by the kernel
func SecurityCheckContext(val string) error {
return securityCheckContext(val)
}
// 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 copyLevel(src, dest)
}
// Chcon changes the fpath file object to the SELinux label label.
// If fpath is a directory and recurse is true, then Chcon walks the
// directory tree setting the label.
func Chcon(fpath string, label string, recurse bool) error {
return chcon(fpath, label, recurse)
}
// 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 dupSecOpt(src)
}
// DisableSecOpt returns a security opt that can be used to disable SELinux
// labeling support for future container processes.
func DisableSecOpt() []string {
return disableSecOpt()
}

View File

@@ -20,17 +20,12 @@ import (
"github.com/opencontainers/selinux/pkg/pwalk"
"github.com/pkg/errors"
"github.com/willf/bitset"
"golang.org/x/sys/unix"
)
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
minSensLen = 2
contextFile = "/usr/share/containers/selinux/contexts"
selinuxDir = "/etc/selinux/"
selinuxConfig = selinuxDir + "config"
@@ -49,17 +44,27 @@ type selinuxState struct {
sync.Mutex
}
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")
type level struct {
sens uint
cats *bitset.BitSet
}
assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`)
roFileLabel string
state = selinuxState{
type mlsRange struct {
low *level
high *level
}
type levelItem byte
const (
sensitivity levelItem = 's'
category levelItem = 'c'
)
var (
assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`)
readOnlyFileLabel string
state = selinuxState{
mcsList: make(map[string]bool),
}
@@ -68,9 +73,6 @@ var (
haveThreadSelf bool
)
// Context is a representation of the SELinux label broken into 4 parts
type Context map[string]string
func (s *selinuxState) setEnable(enabled bool) bool {
s.Lock()
defer s.Unlock()
@@ -97,8 +99,8 @@ func (s *selinuxState) getEnabled() bool {
return s.setEnable(enabled)
}
// SetDisabled disables selinux support for the package
func SetDisabled() {
// setDisabled disables SELinux support for the package
func setDisabled() {
state.setEnable(false)
}
@@ -190,15 +192,15 @@ func (s *selinuxState) getSELinuxfs() string {
// getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs
// filesystem or an empty string if no mountpoint is found. Selinuxfs is
// a proc-like pseudo-filesystem that exposes the selinux policy API to
// a proc-like pseudo-filesystem that exposes the SELinux policy API to
// processes. The existence of an selinuxfs mount is used to determine
// whether selinux is currently enabled or not.
// whether SELinux is currently enabled or not.
func getSelinuxMountPoint() string {
return state.getSELinuxfs()
}
// GetEnabled returns whether selinux is currently enabled.
func GetEnabled() bool {
// getEnabled returns whether SELinux is currently enabled.
func getEnabled() bool {
return state.getEnabled()
}
@@ -282,8 +284,9 @@ func readCon(fpath string) (string, error) {
return strings.Trim(retval, "\x00"), nil
}
// ClassIndex returns the int index for an object class in the loaded policy, or -1 and an error
func ClassIndex(class string) (int, error) {
// classIndex returns the int index for an object class in the loaded policy,
// or -1 and an error
func classIndex(class string) (int, error) {
permpath := fmt.Sprintf("class/%s/index", class)
indexpath := filepath.Join(getSelinuxMountPoint(), permpath)
@@ -299,8 +302,8 @@ func ClassIndex(class string) (int, error) {
return index, nil
}
// SetFileLabel sets the SELinux label for this path or returns an error.
func SetFileLabel(fpath string, label string) error {
// setFileLabel sets the SELinux label for this path or returns an error.
func setFileLabel(fpath string, label string) error {
if fpath == "" {
return ErrEmptyPath
}
@@ -310,8 +313,8 @@ 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) {
// fileLabel returns the SELinux label for this path or returns an error.
func fileLabel(fpath string) (string, error) {
if fpath == "" {
return "", ErrEmptyPath
}
@@ -327,37 +330,31 @@ func FileLabel(fpath string) (string, error) {
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 {
// 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 writeAttr("fscreate", label)
}
/*
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) {
// 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 readAttr("fscreate")
}
// CurrentLabel returns the SELinux label of the current process thread, or an error.
func CurrentLabel() (string, error) {
// currentLabel returns the SELinux label of the current process thread, or an error.
func currentLabel() (string, error) {
return readAttr("current")
}
// PidLabel returns the SELinux label of the given pid, or an error.
func PidLabel(pid int) (string, error) {
// pidLabel returns the SELinux label of the given pid, or an error.
func pidLabel(pid int) (string, error) {
return readCon(fmt.Sprintf("/proc/%d/attr/current", pid))
}
/*
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) {
// 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 readAttr("exec")
}
@@ -366,7 +363,7 @@ func writeCon(fpath, val string) error {
return ErrEmptyPath
}
if val == "" {
if !GetEnabled() {
if !getEnabled() {
return nil
}
}
@@ -418,20 +415,17 @@ func writeAttr(attr, val string) error {
return writeCon(attrPath(attr), val)
}
/*
CanonicalizeContext takes a context string and writes it to the kernel
the function then returns the context that the kernel will use. This function
can be used to see if two contexts are equivalent
*/
func CanonicalizeContext(val string) (string, error) {
// canonicalizeContext takes a context string and writes it to the kernel
// the function then returns the context that the kernel will use. Use this
// function to check if two contexts are equivalent
func canonicalizeContext(val string) (string, error) {
return readWriteCon(filepath.Join(getSelinuxMountPoint(), "context"), val)
}
/*
ComputeCreateContext requests the type transition from source to target for class from the kernel.
*/
func ComputeCreateContext(source string, target string, class string) (string, error) {
classidx, err := ClassIndex(class)
// computeCreateContext requests the type transition from source to target for
// class from the kernel.
func computeCreateContext(source string, target string, class string) (string, error) {
classidx, err := classIndex(class)
if err != nil {
return "", err
}
@@ -439,6 +433,217 @@ func ComputeCreateContext(source string, target string, class string) (string, e
return readWriteCon(filepath.Join(getSelinuxMountPoint(), "create"), fmt.Sprintf("%s %s %d", source, target, classidx))
}
// catsToBitset stores categories in a bitset.
func catsToBitset(cats string) (*bitset.BitSet, error) {
bitset := &bitset.BitSet{}
catlist := strings.Split(cats, ",")
for _, r := range catlist {
ranges := strings.SplitN(r, ".", 2)
if len(ranges) > 1 {
catstart, err := parseLevelItem(ranges[0], category)
if err != nil {
return nil, err
}
catend, err := parseLevelItem(ranges[1], category)
if err != nil {
return nil, err
}
for i := catstart; i <= catend; i++ {
bitset.Set(i)
}
} else {
cat, err := parseLevelItem(ranges[0], category)
if err != nil {
return nil, err
}
bitset.Set(cat)
}
}
return bitset, nil
}
// parseLevelItem parses and verifies that a sensitivity or category are valid
func parseLevelItem(s string, sep levelItem) (uint, error) {
if len(s) < minSensLen || levelItem(s[0]) != sep {
return 0, ErrLevelSyntax
}
val, err := strconv.ParseUint(s[1:], 10, 32)
if err != nil {
return 0, err
}
return uint(val), nil
}
// parseLevel fills a level from a string that contains
// a sensitivity and categories
func (l *level) parseLevel(levelStr string) error {
lvl := strings.SplitN(levelStr, ":", 2)
sens, err := parseLevelItem(lvl[0], sensitivity)
if err != nil {
return errors.Wrap(err, "failed to parse sensitivity")
}
l.sens = sens
if len(lvl) > 1 {
cats, err := catsToBitset(lvl[1])
if err != nil {
return errors.Wrap(err, "failed to parse categories")
}
l.cats = cats
}
return nil
}
// rangeStrToMLSRange marshals a string representation of a range.
func rangeStrToMLSRange(rangeStr string) (*mlsRange, error) {
mlsRange := &mlsRange{}
levelSlice := strings.SplitN(rangeStr, "-", 2)
switch len(levelSlice) {
// rangeStr that has a low and a high level, e.g. s4:c0.c1023-s6:c0.c1023
case 2:
mlsRange.high = &level{}
if err := mlsRange.high.parseLevel(levelSlice[1]); err != nil {
return nil, errors.Wrapf(err, "failed to parse high level %q", levelSlice[1])
}
fallthrough
// rangeStr that is single level, e.g. s6:c0,c3,c5,c30.c1023
case 1:
mlsRange.low = &level{}
if err := mlsRange.low.parseLevel(levelSlice[0]); err != nil {
return nil, errors.Wrapf(err, "failed to parse low level %q", levelSlice[0])
}
}
if mlsRange.high == nil {
mlsRange.high = mlsRange.low
}
return mlsRange, nil
}
// bitsetToStr takes a category bitset and returns it in the
// canonical selinux syntax
func bitsetToStr(c *bitset.BitSet) string {
var str string
i, e := c.NextSet(0)
len := 0
for e {
if len == 0 {
if str != "" {
str += ","
}
str += "c" + strconv.Itoa(int(i))
}
next, e := c.NextSet(i + 1)
if e {
// consecutive cats
if next == i+1 {
len++
i = next
continue
}
}
if len == 1 {
str += ",c" + strconv.Itoa(int(i))
} else if len > 1 {
str += ".c" + strconv.Itoa(int(i))
}
if !e {
break
}
len = 0
i = next
}
return str
}
func (l1 *level) equal(l2 *level) bool {
if l2 == nil || l1 == nil {
return l1 == l2
}
if l1.sens != l2.sens {
return false
}
return l1.cats.Equal(l2.cats)
}
// String returns an mlsRange as a string.
func (m mlsRange) String() string {
low := "s" + strconv.Itoa(int(m.low.sens))
if m.low.cats != nil && m.low.cats.Count() > 0 {
low += ":" + bitsetToStr(m.low.cats)
}
if m.low.equal(m.high) {
return low
}
high := "s" + strconv.Itoa(int(m.high.sens))
if m.high.cats != nil && m.high.cats.Count() > 0 {
high += ":" + bitsetToStr(m.high.cats)
}
return low + "-" + high
}
func max(a, b uint) uint {
if a > b {
return a
}
return b
}
func min(a, b uint) uint {
if a < b {
return a
}
return b
}
// calculateGlbLub computes the glb (greatest lower bound) and lub (least upper bound)
// of a source and target range.
// The glblub is calculated as the greater of the low sensitivities and
// the lower of the high sensitivities and the and of each category bitset.
func calculateGlbLub(sourceRange, targetRange string) (string, error) {
s, err := rangeStrToMLSRange(sourceRange)
if err != nil {
return "", err
}
t, err := rangeStrToMLSRange(targetRange)
if err != nil {
return "", err
}
if s.high.sens < t.low.sens || t.high.sens < s.low.sens {
/* these ranges have no common sensitivities */
return "", ErrIncomparable
}
outrange := &mlsRange{low: &level{}, high: &level{}}
/* take the greatest of the low */
outrange.low.sens = max(s.low.sens, t.low.sens)
/* take the least of the high */
outrange.high.sens = min(s.high.sens, t.high.sens)
/* find the intersecting categories */
if s.low.cats != nil && t.low.cats != nil {
outrange.low.cats = s.low.cats.Intersection(t.low.cats)
}
if s.high.cats != nil && t.high.cats != nil {
outrange.high.cats = s.high.cats.Intersection(t.high.cats)
}
return outrange.String(), nil
}
func readWriteCon(fpath string, val string) (string, error) {
if fpath == "" {
return "", ErrEmptyPath
@@ -461,41 +666,37 @@ func readWriteCon(fpath string, val string) (string, error) {
return strings.Trim(retval, "\x00"), 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 {
// 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 {
// 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
// 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 {
func setSocketLabel(label string) error {
return writeAttr("sockcreate", label)
}
// SocketLabel retrieves the current socket label setting
func SocketLabel() (string, error) {
// 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
func PeerLabel(fd uintptr) (string, error) {
// peerLabel retrieves the label of the client on the other side of a socket
func peerLabel(fd uintptr) (string, error) {
return unix.GetsockoptString(int(fd), unix.SOL_SOCKET, unix.SO_PEERSEC)
}
// 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
func SetKeyLabel(label string) error {
func setKeyLabel(label string) error {
err := writeCon("/proc/self/attr/keycreate", label)
if os.IsNotExist(errors.Cause(err)) {
return nil
@@ -506,21 +707,21 @@ func SetKeyLabel(label string) error {
return err
}
// KeyLabel retrieves the current kernel keyring label setting
func KeyLabel() (string, error) {
// 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
func (c Context) Get() string {
// get returns the Context as a 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", c["user"], c["role"], c["type"])
}
// NewContext creates a new Context struct from the specified label
func NewContext(label string) (Context, error) {
// newContext creates a new Context struct from the specified label
func newContext(label string) (Context, error) {
c := make(Context)
if len(label) != 0 {
@@ -538,15 +739,15 @@ func NewContext(label string) (Context, error) {
return c, nil
}
// ClearLabels clears all reserved labels
func ClearLabels() {
// 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
func ReserveLabel(label string) {
// reserveLabel reserves the MLS/MCS level component of the specified label
func reserveLabel(label string) {
if len(label) != 0 {
con := strings.SplitN(label, ":", 4)
if len(con) > 3 {
@@ -559,8 +760,8 @@ func selinuxEnforcePath() string {
return path.Join(getSelinuxMountPoint(), "enforce")
}
// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
func EnforceMode() int {
// enforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
func enforceMode() int {
var enforce int
enforceB, err := ioutil.ReadFile(selinuxEnforcePath())
@@ -574,20 +775,16 @@ func EnforceMode() int {
return enforce
}
/*
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 {
// 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 ioutil.WriteFile(selinuxEnforcePath(), []byte(strconv.Itoa(mode)), 0644)
}
/*
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 {
// 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 {
switch readConfig(selinuxTag) {
case "enforcing":
return Enforcing
@@ -667,11 +864,9 @@ func uniqMcs(catRange uint32) string {
return mcs
}
/*
ReleaseLabel will unreserve the MLS/MCS Level field of the specified label.
Allowing it to be used by another process.
*/
func ReleaseLabel(label string) {
// releaseLabel un-reserves the MLS/MCS Level field of the specified label,
// allowing it to be used by another process.
func releaseLabel(label string) {
if len(label) != 0 {
con := strings.SplitN(label, ":", 4)
if len(con) > 3 {
@@ -680,9 +875,9 @@ func ReleaseLabel(label string) {
}
}
// ROFileLabel returns the specified SELinux readonly file label
func ROFileLabel() string {
return roFileLabel
// roFileLabel returns the specified SELinux readonly file label
func roFileLabel() string {
return readOnlyFileLabel
}
func openContextFile() (*os.File, error) {
@@ -737,11 +932,9 @@ func loadLabels() map[string]string {
return labels
}
/*
KVMContainerLabels returns the default processLabel and mountLabel to be used
for kvm containers by the calling process.
*/
func KVMContainerLabels() (string, string) {
// kvmContainerLabels returns the default processLabel and mountLabel to be used
// for kvm containers by the calling process.
func kvmContainerLabels() (string, string) {
processLabel := labels["kvm_process"]
if processLabel == "" {
processLabel = labels["process"]
@@ -750,11 +943,9 @@ func KVMContainerLabels() (string, string) {
return addMcs(processLabel, labels["file"])
}
/*
InitContainerLabels returns the default processLabel and file labels to be
used for containers running an init system like systemd by the calling process.
*/
func InitContainerLabels() (string, string) {
// initContainerLabels returns the default processLabel and file labels to be
// used for containers running an init system like systemd by the calling process.
func initContainerLabels() (string, string) {
processLabel := labels["init_process"]
if processLabel == "" {
processLabel = labels["process"]
@@ -763,25 +954,23 @@ func InitContainerLabels() (string, string) {
return addMcs(processLabel, labels["file"])
}
/*
ContainerLabels returns an allocated processLabel and fileLabel to be used for
container labeling by the calling process.
*/
func ContainerLabels() (processLabel string, fileLabel string) {
if !GetEnabled() {
// containerLabels returns an allocated processLabel and fileLabel to be used for
// container labeling by the calling process.
func containerLabels() (processLabel string, fileLabel string) {
if !getEnabled() {
return "", ""
}
processLabel = labels["process"]
fileLabel = labels["file"]
roFileLabel = labels["ro_file"]
readOnlyFileLabel = labels["ro_file"]
if processLabel == "" || fileLabel == "" {
return "", fileLabel
}
if roFileLabel == "" {
roFileLabel = fileLabel
if readOnlyFileLabel == "" {
readOnlyFileLabel = fileLabel
}
return addMcs(processLabel, fileLabel)
@@ -790,7 +979,7 @@ func ContainerLabels() (processLabel string, fileLabel string) {
func addMcs(processLabel, fileLabel string) (string, string) {
scon, _ := NewContext(processLabel)
if scon["level"] != "" {
mcs := uniqMcs(1024)
mcs := uniqMcs(CategoryRange)
scon["level"] = mcs
processLabel = scon.Get()
scon, _ = NewContext(fileLabel)
@@ -800,16 +989,14 @@ func addMcs(processLabel, fileLabel string) (string, string) {
return processLabel, fileLabel
}
// SecurityCheckContext validates that the SELinux label is understood by the kernel
func SecurityCheckContext(val string) error {
// securityCheckContext validates that the SELinux label is understood by the kernel
func securityCheckContext(val string) error {
return ioutil.WriteFile(path.Join(getSelinuxMountPoint(), "context"), []byte(val), 0644)
}
/*
CopyLevel returns a label with the MLS/MCS level from src label replaced on
the dest label.
*/
func CopyLevel(src, dest string) (string, error) {
// copyLevel returns a label with the MLS/MCS level from src label replaced on
// the dest label.
func copyLevel(src, dest string) (string, error) {
if src == "" {
return "", nil
}
@@ -833,7 +1020,7 @@ func CopyLevel(src, dest string) (string, error) {
return tcon.Get(), nil
}
// Prevent users from relabing system files
// Prevent users from relabeling system files
func badPrefix(fpath string) error {
if fpath == "" {
return ErrEmptyPath
@@ -848,10 +1035,10 @@ func badPrefix(fpath 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
// chcon changes the fpath file object to the SELinux label label.
// If fpath is a directory and recurse is true, then chcon walks the
// 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
}
@@ -876,9 +1063,9 @@ 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 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) {
if src == "" {
return nil, nil
}
@@ -903,8 +1090,8 @@ func DupSecOpt(src string) ([]string, error) {
return dup, nil
}
// 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.
func DisableSecOpt() []string {
func disableSecOpt() []string {
return []string{"disable"}
}

View File

@@ -2,253 +2,147 @@
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
func setDisabled() {
}
// GetEnabled returns whether selinux is currently enabled.
func GetEnabled() bool {
func getEnabled() bool {
return false
}
// ClassIndex returns the int index for an object class in the loaded policy, or -1 and an error
func ClassIndex(class string) (int, error) {
func classIndex(class string) (int, error) {
return -1, nil
}
// SetFileLabel sets the SELinux label for this path or returns an error.
func SetFileLabel(fpath string, label string) 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) {
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 {
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) {
func fsCreateLabel() (string, error) {
return "", nil
}
// CurrentLabel returns the SELinux label of the current process thread, or an error.
func CurrentLabel() (string, 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) {
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) {
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) {
func canonicalizeContext(val string) (string, error) {
return "", nil
}
/*
ComputeCreateContext requests the type transition from source to target for class from the kernel.
*/
func ComputeCreateContext(source string, target string, class string) (string, error) {
func computeCreateContext(source string, target string, class 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 {
func calculateGlbLub(sourceRange, targetRange string) (string, error) {
return "", nil
}
func setExecLabel(label string) error {
return nil
}
/*
SetTaskLabel sets the SELinux label for the current thread, or an error.
This requires the dyntransition permission.
*/
func SetTaskLabel(label string) error {
func setTaskLabel(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 {
func setSocketLabel(label string) error {
return nil
}
// SocketLabel retrieves the current socket label setting
func SocketLabel() (string, error) {
func socketLabel() (string, error) {
return "", nil
}
// 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) {
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 {
func setKeyLabel(label string) error {
return nil
}
// KeyLabel retrieves the current kernel keyring label setting
func KeyLabel() (string, error) {
func keyLabel() (string, error) {
return "", nil
}
// Get returns the Context as a string
func (c Context) Get() string {
func (c Context) get() string {
return ""
}
// NewContext creates a new Context struct from the specified label
func NewContext(label string) (Context, error) {
func newContext(label string) (Context, error) {
c := make(Context)
return c, nil
}
// ClearLabels clears all reserved MLS/MCS levels
func ClearLabels() {
return
func clearLabels() {
}
// ReserveLabel reserves the MLS/MCS level component of the specified label
func ReserveLabel(label string) {
return
func reserveLabel(label string) {
}
// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
func EnforceMode() int {
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 {
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 {
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
func releaseLabel(label string) {
}
// ROFileLabel returns the specified SELinux readonly file label
func ROFileLabel() string {
func roFileLabel() string {
return ""
}
// KVMContainerLabels returns the default processLabel and mountLabel to be used
// for kvm containers by the calling process.
func KVMContainerLabels() (string, string) {
func kvmContainerLabels() (string, string) {
return "", ""
}
// InitContainerLabels returns the default processLabel and file labels to be
// used for containers running an init system like systemd by the calling
func InitContainerLabels() (string, string) {
func initContainerLabels() (string, 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) {
func containerLabels() (processLabel string, fileLabel string) {
return "", ""
}
// SecurityCheckContext validates that the SELinux label is understood by the kernel
func SecurityCheckContext(val string) error {
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) {
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 {
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) {
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 {
func disableSecOpt() []string {
return []string{"disable"}
}

View File

@@ -48,7 +48,11 @@ func WalkN(root string, walkFn WalkFunc, num int) error {
errCh := make(chan error, 1) // get the first error, ignore others
// Start walking a tree asap
var err error
var (
err error
wg sync.WaitGroup
)
wg.Add(1)
go func() {
err = filepath.Walk(root, func(p string, info os.FileInfo, err error) error {
if err != nil {
@@ -68,9 +72,9 @@ func WalkN(root string, walkFn WalkFunc, num int) error {
if err == nil {
close(files)
}
wg.Done()
}()
var wg sync.WaitGroup
wg.Add(num)
for i := 0; i < num; i++ {
go func() {