[release/1.1] Update cri to f117382467baf182382c44332bfbf488effc34bb.

Signed-off-by: Lantao Liu <lantaol@google.com>
This commit is contained in:
Lantao Liu committed 2018-09-17 15:19:37 -07:00
1 parent 57508dcb0b
commit 8dcb03e60d
12 files changed
+640 -137

No files matched your search

+2 -2
View File
@@ -44,7 +44,7 @@ github.com/gotestyourself/gotestyourself 44dbf532bbf5767611f6f2a61bded572e337010
github.com/google/go-cmp v0.1.0
# cri dependencies
github.com/containerd/cri v1.0.5
github.com/containerd/cri f117382467baf182382c44332bfbf488effc34bb # release/1.0
github.com/containerd/go-cni f2d7272f12d045b16ed924f50e91f9f9cecc55a7
github.com/blang/semver v3.1.0
github.com/containernetworking/cni v0.6.0
@@ -61,7 +61,7 @@ github.com/hashicorp/errwrap 7554cd9344cec97297fa6649b055a8c98c2a1e55
github.com/hashicorp/go-multierror ed905158d87462226a13fe39ddf685ea65f1c11f
github.com/json-iterator/go 1.0.4
github.com/opencontainers/runtime-tools 6073aff4ac61897f75895123f7e24135204a404d
github.com/opencontainers/selinux 4a2974bf1ee960774ffd517717f1f45325af0206
github.com/opencontainers/selinux b6fa367ed7f534f9ba25391cc2d467085dbb445a
github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
github.com/spf13/pflag v1.0.0
github.com/tchap/go-patricia 5ad6cdb7538b0097d5598c7e57f0a24072adf7dc
+51
View File
@@ -0,0 +1,51 @@
/*
Copyright 2018 The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package opts
import (
"context"
"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/oci"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
)
// WithAdditionalGIDs adds any additional groups listed for a particular user in the
// /etc/groups file of the image's root filesystem to the OCI spec's additionalGids array.
func WithAdditionalGIDs(userstr string) oci.SpecOpts {
return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) (err error) {
gids := s.Process.User.AdditionalGids
if err := oci.WithAdditionalGIDs(userstr)(ctx, client, c, s); err != nil {
return err
}
// Merge existing gids and new gids.
s.Process.User.AdditionalGids = mergeGids(s.Process.User.AdditionalGids, gids)
return nil
}
}
func mergeGids(gids1, gids2 []uint32) []uint32 {
for _, gid1 := range gids1 {
for i, gid2 := range gids2 {
if gid1 == gid2 {
gids2 = append(gids2[:i], gids2[i+1:]...)
break
}
}
}
return append(gids1, gids2...)
}
+6
View File
@@ -44,6 +44,7 @@ type OS interface {
Mount(source string, target string, fstype string, flags uintptr, data string) error
Unmount(target string, flags int) error
LookupMount(path string) (containerdmount.Info, error)
Hostname() (string, error)
}
// RealOS is used to dispatch the real system level operations.
@@ -132,3 +133,8 @@ func Unmount(target string, flags int) error {
}
return unix.Unmount(target, flags)
}
// Hostname will call os.Hostname to get the hostname of the host.
func (RealOS) Hostname() (string, error) {
return os.Hostname()
}
+72 -6
View File
@@ -19,6 +19,7 @@ package server
import (
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"time"
@@ -232,6 +233,15 @@ func (c *criService) CreateContainer(ctx context.Context, r *runtime.CreateConta
specOpts = append(specOpts, oci.WithUser(userstr))
}
if securityContext.GetRunAsUsername() != "" {
userstr = securityContext.GetRunAsUsername()
} else {
// Even if RunAsUser is not set, we still call `GetValue` to get uid 0.
// Because it is still useful to get additional gids for uid 0.
userstr = strconv.FormatInt(securityContext.GetRunAsUser().GetValue(), 10)
}
specOpts = append(specOpts, customopts.WithAdditionalGIDs(userstr))
apparmorSpecOpts, err := generateApparmorSpecOpts(
securityContext.GetApparmorProfile(),
securityContext.GetPrivileged(),
@@ -333,6 +343,17 @@ func (c *criService) generateContainerSpec(id string, sandboxID string, sandboxP
g.AddProcessEnv("TERM", "xterm")
}
// Add HOSTNAME env.
hostname := sandboxConfig.GetHostname()
if sandboxConfig.GetLinux().GetSecurityContext().GetNamespaceOptions().GetNetwork() == runtime.NamespaceMode_NODE &&
hostname == "" {
hostname, err = c.os.Hostname()
if err != nil {
return nil, err
}
}
g.AddProcessEnv(hostnameEnv, hostname)
// Apply envs from image config first, so that envs from container config
// can override them.
if err := addImageEnvs(&g, imageConfig.Env); err != nil {
@@ -349,8 +370,8 @@ func (c *criService) generateContainerSpec(id string, sandboxID string, sandboxP
return nil, errors.Wrapf(err, "failed to init selinux options %+v", securityContext.GetSelinuxOptions())
}
// Add extra mounts first so that CRI specified mounts can override.
mounts := append(extraMounts, config.GetMounts()...)
// Merge extra mounts and CRI mounts.
mounts := mergeMounts(config.GetMounts(), extraMounts)
if err := c.addOCIBindMounts(&g, mounts, mountLabel); err != nil {
return nil, errors.Wrapf(err, "failed to set OCI bind mounts %+v", mounts)
}
@@ -596,8 +617,35 @@ func setOCIDevicesPrivileged(g *generate.Generator) error {
// addOCIBindMounts adds bind mounts.
func (c *criService) addOCIBindMounts(g *generate.Generator, mounts []*runtime.Mount, mountLabel string) error {
// Sort mounts in number of parts. This ensures that high level mounts don't
// shadow other mounts.
sort.Sort(orderedMounts(mounts))
// Mount cgroup into the container as readonly, which inherits docker's behavior.
g.AddCgroupsMount("ro") // nolint: errcheck
// Copy all mounts from default mounts, except for
// - mounts overriden by supplied mount;
// - all mounts under /dev if a supplied /dev is present.
mountSet := make(map[string]struct{})
for _, m := range mounts {
mountSet[filepath.Clean(m.ContainerPath)] = struct{}{}
}
defaultMounts := g.Spec().Mounts
g.Spec().Mounts = nil
for _, m := range defaultMounts {
dst := filepath.Clean(m.Destination)
if _, ok := mountSet[dst]; ok {
// filter out mount overridden by a supplied mount
continue
}
if _, mountDev := mountSet["/dev"]; mountDev && strings.HasPrefix(dst, "/dev/") {
// filter out everything under /dev if /dev is a supplied mount
continue
}
g.Spec().Mounts = append(g.Spec().Mounts, m)
}
for _, mount := range mounts {
dst := mount.GetContainerPath()
src := mount.GetHostPath()
@@ -777,10 +825,6 @@ func defaultRuntimeSpec(id string) (*runtimespec.Spec, error) {
if mount.Destination == "/run" {
continue
}
// CRI plugin handles `/dev/shm` itself.
if mount.Destination == "/dev/shm" {
continue
}
mounts = append(mounts, mount)
}
spec.Mounts = mounts
@@ -924,3 +968,25 @@ func generateUserString(username string, uid, gid *runtime.Int64Value) (string,
}
return userstr, nil
}
// mergeMounts merge CRI mounts with extra mounts. If a mount destination
// is mounted by both a CRI mount and an extra mount, the CRI mount will
// be kept.
func mergeMounts(criMounts, extraMounts []*runtime.Mount) []*runtime.Mount {
var mounts []*runtime.Mount
mounts = append(mounts, criMounts...)
// Copy all mounts from extra mounts, except for mounts overriden by CRI.
for _, e := range extraMounts {
found := false
for _, c := range criMounts {
if filepath.Clean(e.ContainerPath) == filepath.Clean(c.ContainerPath) {
found = true
break
}
}
if !found {
mounts = append(mounts, e)
}
}
return mounts
}
+44 -36
View File
@@ -33,7 +33,10 @@ import (
// killContainerTimeout is the timeout that we wait for the container to
// be SIGKILLed.
const killContainerTimeout = 2 * time.Minute
// The timeout is set to 1 min, because the default CRI operation timeout
// for StopContainer is (2 min + stop timeout). Set to 1 min, so that we
// have enough time for kill(all=true) and kill(all=false).
const killContainerTimeout = 1 * time.Minute
// StopContainer stops a running container with a grace period (i.e., timeout).
func (c *criService) StopContainer(ctx context.Context, r *runtime.StopContainerRequest) (*runtime.StopContainerResponse, error) {
@@ -63,6 +66,16 @@ func (c *criService) stopContainer(ctx context.Context, container containerstore
return nil
}
task, err := container.Container.Task(ctx, nil)
if err != nil {
if !errdefs.IsNotFound(err) {
return errors.Wrapf(err, "failed to stop container, task not found for container %q", id)
}
return nil
}
// We only need to kill the task. The event handler will Delete the
// task from containerd after it handles the Exited event.
if timeout > 0 {
stopSignal := unix.SIGTERM
image, err := c.imageStore.Get(container.ImageRef)
@@ -81,52 +94,47 @@ func (c *criService) stopContainer(ctx context.Context, container containerstore
}
}
logrus.Infof("Stop container %q with signal %v", id, stopSignal)
task, err := container.Container.Task(ctx, nil)
if err != nil {
if !errdefs.IsNotFound(err) {
return errors.Wrapf(err, "failed to stop container, task not found for container %q", id)
}
return nil
}
if task != nil {
if err = task.Kill(ctx, stopSignal); err != nil {
if !errdefs.IsNotFound(err) {
return errors.Wrapf(err, "failed to stop container %q", id)
}
// Move on to make sure container status is updated.
}
if err = task.Kill(ctx, stopSignal); err != nil && !errdefs.IsNotFound(err) {
return errors.Wrapf(err, "failed to stop container %q", id)
}
err = c.waitContainerStop(ctx, container, timeout)
if err == nil {
if err = c.waitContainerStop(ctx, container, timeout); err == nil {
return nil
}
logrus.WithError(err).Errorf("Stop container %q timed out", id)
logrus.WithError(err).Errorf("An error occurs during waiting for container %q to be stopped", id)
}
task, err := container.Container.Task(ctx, nil)
if err != nil {
if !errdefs.IsNotFound(err) {
return errors.Wrapf(err, "failed to stop container, task not found for container %q", id)
}
return nil
}
// Event handler will Delete the container from containerd after it handles the Exited event.
logrus.Infof("Kill container %q", id)
if task != nil {
if err = task.Kill(ctx, unix.SIGKILL, containerd.WithKillAll); err != nil {
if !errdefs.IsNotFound(err) {
return errors.Wrapf(err, "failed to kill container %q", id)
}
// Move on to make sure container status is updated.
}
if err = task.Kill(ctx, unix.SIGKILL, containerd.WithKillAll); err != nil && !errdefs.IsNotFound(err) {
return errors.Wrapf(err, "failed to kill container %q", id)
}
// Wait for a fixed timeout until container stop is observed by event monitor.
if err := c.waitContainerStop(ctx, container, killContainerTimeout); err != nil {
return errors.Wrapf(err, "an error occurs during waiting for container %q to stop", id)
if err = c.waitContainerStop(ctx, container, killContainerTimeout); err == nil {
return nil
}
return nil
logrus.WithError(err).Errorf("An error occurs during waiting for container %q to be killed", id)
// This is a fix for `runc`, and should not break other runtimes. With
// containerd.WithKillAll, `runc` will get all processes from the container
// cgroups, and kill them. However, sometimes the processes may be moved
// out from the container cgroup, e.g. users manually move them by mistake,
// or systemd.Delegate=true is not set.
// In these cases, we should try our best to do cleanup, kill the container
// without containerd.WithKillAll, so that runc can kill the container init
// process directly.
// NOTE(random-liu): If pid namespace is shared inside the pod, non-init processes
// of this container will be left running until the pause container is stopped.
logrus.Infof("Kill container %q init process", id)
if err = task.Kill(ctx, unix.SIGKILL); err != nil && !errdefs.IsNotFound(err) {
return errors.Wrapf(err, "failed to kill container %q init process", id)
}
// Wait for a fixed timeout until container stop is observed by event monitor.
if err = c.waitContainerStop(ctx, container, killContainerTimeout); err == nil {
return nil
}
return errors.Wrapf(err, "an error occurs during waiting for container %q init process to be killed", id)
}
// waitContainerStop waits for container to be stopped until timeout exceeds or context is cancelled.
+50 -2
View File
@@ -19,8 +19,10 @@ package server
import (
"encoding/json"
"fmt"
"os"
"path"
"path/filepath"
"regexp"
"strconv"
"strings"
@@ -95,6 +97,8 @@ const (
etcHosts = "/etc/hosts"
// resolvConfPath is the abs path of resolv.conf on host or container.
resolvConfPath = "/etc/resolv.conf"
// hostnameEnv is the key for HOSTNAME env.
hostnameEnv = "HOSTNAME"
)
const (
@@ -370,11 +374,16 @@ func initSelinuxOpts(selinuxOpt *runtime.SELinuxOption) (string, string, error)
// Should ignored selinuxOpts if they are incomplete.
if selinuxOpt.GetUser() == "" ||
selinuxOpt.GetRole() == "" ||
selinuxOpt.GetType() == "" ||
selinuxOpt.GetLevel() == "" {
selinuxOpt.GetType() == "" {
return "", "", nil
}
// make sure the format of "level" is correct.
ok, err := checkSelinuxLevel(selinuxOpt.GetLevel())
if err != nil || !ok {
return "", "", err
}
labelOpts := fmt.Sprintf("%s:%s:%s:%s",
selinuxOpt.GetUser(),
selinuxOpt.GetRole(),
@@ -383,6 +392,18 @@ func initSelinuxOpts(selinuxOpt *runtime.SELinuxOption) (string, string, error)
return label.InitLabels(selinux.DupSecOpt(labelOpts))
}
func checkSelinuxLevel(level string) (bool, error) {
if len(level) == 0 {
return true, nil
}
matched, err := regexp.MatchString(`^s\d(-s\d)??(:c\d{1,4}((.c\d{1,4})?,c\d{1,4})*(.c\d{1,4})?(,c\d{1,4}(.c\d{1,4})?)*)?$`, level)
if err != nil || !matched {
return false, fmt.Errorf("the format of 'level' %q is not correct: %v", level, err)
}
return true, nil
}
// isInCRIMounts checks whether a destination is in CRI mount list.
func isInCRIMounts(dst string, mounts []*runtime.Mount) bool {
for _, m := range mounts {
@@ -444,3 +465,30 @@ func getRuntimeConfigFromContainerInfo(c containers.Container) (criconfig.Runtim
r.Root = runtimeOpts.RuntimeRoot
return r, nil
}
// mounts defines how to sort runtime.Mount.
// This is the same with the Docker implementation:
// https://github.com/moby/moby/blob/17.05.x/daemon/volumes.go#L26
type orderedMounts []*runtime.Mount
// Len returns the number of mounts. Used in sorting.
func (m orderedMounts) Len() int {
return len(m)
}
// Less returns true if the number of parts (a/b/c would be 3 parts) in the
// mount indexed by parameter 1 is less than that of the mount indexed by
// parameter 2. Used in sorting.
func (m orderedMounts) Less(i, j int) bool {
return m.parts(i) < m.parts(j)
}
// Swap swaps two items in an array of mounts. Used in sorting
func (m orderedMounts) Swap(i, j int) {
m[i], m[j] = m[j], m[i]
}
// parts returns the number of parts in the destination of a mount. Used in sorting.
func (m orderedMounts) parts(i int) int {
return strings.Count(filepath.Clean(m[i].ContainerPath), string(os.PathSeparator))
}
+11 -2
View File
@@ -109,11 +109,20 @@ func (c *criService) stopSandboxContainer(ctx context.Context, sandbox sandboxst
}
// Kill the sandbox container.
err = task.Kill(ctx, unix.SIGKILL, containerd.WithKillAll)
if err != nil && !errdefs.IsNotFound(err) {
if err = task.Kill(ctx, unix.SIGKILL, containerd.WithKillAll); err != nil && !errdefs.IsNotFound(err) {
return errors.Wrap(err, "failed to kill sandbox container")
}
if err = c.waitSandboxStop(ctx, sandbox, killContainerTimeout); err == nil {
return nil
}
logrus.WithError(err).Errorf("An error occurs during waiting for sandbox %q to be killed", sandbox.ID)
// Kill the sandbox container init process.
if err = task.Kill(ctx, unix.SIGKILL); err != nil && !errdefs.IsNotFound(err) {
return errors.Wrap(err, "failed to kill sandbox container init process")
}
return c.waitSandboxStop(ctx, sandbox, killContainerTimeout)
}
+4 -4
View File
@@ -3,9 +3,9 @@ github.com/blang/semver v3.1.0
github.com/boltdb/bolt e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd
github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
github.com/containerd/cgroups fe281dd265766145e943a034aa41086474ea6130
github.com/containerd/console cb7008ab3d8359b78c5f464cb7cf160107ad5925
github.com/containerd/containerd 01a0741488487779a95035cd85504589034d2e91
github.com/containerd/continuity 3e8f2ea4b190484acb976a5b378d373429639a1a
github.com/containerd/console 4d8a41f4ce5b9bae77c41786ea2458330f43f081
github.com/containerd/containerd 57508dcb0b5776efaacd0828ed42f819fab5ba07
github.com/containerd/continuity a60600ad77f38aaa70165825f61e2ea72e51c9b1
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
github.com/containerd/go-cni f2d7272f12d045b16ed924f50e91f9f9cecc55a7
github.com/containerd/go-runc bcb223a061a3dd7de1a89c0b402a60f4dd9bd307
@@ -40,7 +40,7 @@ github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/runc 69663f0bd4b60df09991c08812a60108003fa340
github.com/opencontainers/runtime-spec v1.0.1
github.com/opencontainers/runtime-tools 6073aff4ac61897f75895123f7e24135204a404d
github.com/opencontainers/selinux 4a2974bf1ee960774ffd517717f1f45325af0206
github.com/opencontainers/selinux b6fa367ed7f534f9ba25391cc2d467085dbb445a
github.com/pkg/errors v0.8.0
github.com/pmezard/go-difflib v1.0.0
github.com/prometheus/client_golang f4fb1b73fb099f396a7f0036bf86aa8def4ed823
@@ -49,8 +49,10 @@ func InitLabels(options []string) (string, string, error) {
mcon[con[0]] = con[1]
}
}
_ = ReleaseLabel(processLabel)
processLabel = pcon.Get()
mountLabel = mcon.Get()
_ = ReserveLabel(processLabel)
}
return processLabel, mountLabel, nil
}
@@ -85,9 +87,6 @@ func FormatMountLabel(src, mountLabel string) string {
// SetProcessLabel takes a process label and tells the kernel to assign the
// label to the next program executed by the current process.
func SetProcessLabel(processLabel string) error {
if processLabel == "" {
return nil
}
return selinux.SetExecLabel(processLabel)
}
@@ -131,7 +130,7 @@ func Relabel(path string, fileLabel string, shared bool) error {
return nil
}
exclude_paths := map[string]bool{"/": true, "/usr": true, "/etc": true}
exclude_paths := map[string]bool{"/": true, "/usr": true, "/etc": true, "/tmp": true, "/home": true, "/run": true, "/var": true, "/root": true}
if exclude_paths[path] {
return fmt.Errorf("SELinux relabeling of %s is not allowed", path)
}
@@ -1,13 +1,16 @@
// +build linux
// +build selinux,linux
package selinux
import (
"bufio"
"bytes"
"crypto/rand"
"encoding/binary"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"regexp"
@@ -23,14 +26,16 @@ const (
// Permissive constant to indicate SELinux is in permissive mode
Permissive = 0
// Disabled constant to indicate SELinux is disabled
Disabled = -1
Disabled = -1
selinuxDir = "/etc/selinux/"
selinuxConfig = selinuxDir + "config"
selinuxfsMount = "/sys/fs/selinux"
selinuxTypeTag = "SELINUXTYPE"
selinuxTag = "SELINUX"
selinuxPath = "/sys/fs/selinux"
xattrNameSelinux = "security.selinux"
stRdOnly = 0x01
selinuxfsMagic = 0xf97cff8c
)
type selinuxState struct {
@@ -43,7 +48,13 @@ type selinuxState struct {
}
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")
assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`)
roFileLabel string
state = selinuxState{
mcsList: make(map[string]bool),
}
@@ -91,6 +102,83 @@ func (s *selinuxState) setSELinuxfs(selinuxfs string) string {
return s.selinuxfs
}
func verifySELinuxfsMount(mnt string) bool {
var buf syscall.Statfs_t
for {
err := syscall.Statfs(mnt, &buf)
if err == nil {
break
}
if err == syscall.EAGAIN {
continue
}
return false
}
if uint32(buf.Type) != uint32(selinuxfsMagic) {
return false
}
if (buf.Flags & stRdOnly) != 0 {
return false
}
return true
}
func findSELinuxfs() string {
// fast path: check the default mount first
if verifySELinuxfsMount(selinuxfsMount) {
return selinuxfsMount
}
// check if selinuxfs is available before going the slow path
fs, err := ioutil.ReadFile("/proc/filesystems")
if err != nil {
return ""
}
if !bytes.Contains(fs, []byte("\tselinuxfs\n")) {
return ""
}
// slow path: try to find among the mounts
f, err := os.Open("/proc/self/mountinfo")
if err != nil {
return ""
}
defer f.Close()
scanner := bufio.NewScanner(f)
for {
mnt := findSELinuxfsMount(scanner)
if mnt == "" { // error or not found
return ""
}
if verifySELinuxfsMount(mnt) {
return mnt
}
}
}
// findSELinuxfsMount returns a next selinuxfs mount point found,
// if there is one, or an empty string in case of EOF or error.
func findSELinuxfsMount(s *bufio.Scanner) string {
for s.Scan() {
txt := s.Text()
// The first field after - is fs type.
// Safe as spaces in mountpoints are encoded as \040
if !strings.Contains(txt, " - selinuxfs ") {
continue
}
const mPos = 5 // mount point is 5th field
fields := strings.SplitN(txt, " ", mPos+1)
if len(fields) < mPos+1 {
continue
}
return fields[mPos-1]
}
return ""
}
func (s *selinuxState) getSELinuxfs() string {
s.Lock()
selinuxfs := s.selinuxfs
@@ -100,40 +188,7 @@ func (s *selinuxState) getSELinuxfs() string {
return selinuxfs
}
selinuxfs = ""
f, err := os.Open("/proc/self/mountinfo")
if err != nil {
return selinuxfs
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
txt := scanner.Text()
// Safe as mountinfo encodes mountpoints with spaces as \040.
sepIdx := strings.Index(txt, " - ")
if sepIdx == -1 {
continue
}
if !strings.Contains(txt[sepIdx:], "selinuxfs") {
continue
}
fields := strings.Split(txt, " ")
if len(fields) < 5 {
continue
}
selinuxfs = fields[4]
break
}
if selinuxfs != "" {
var buf syscall.Statfs_t
syscall.Statfs(selinuxfs, &buf)
if (buf.Flags & stRdOnly) == 1 {
selinuxfs = ""
}
}
return s.setSELinuxfs(selinuxfs)
return s.setSELinuxfs(findSELinuxfs())
}
// getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs
@@ -150,7 +205,7 @@ func GetEnabled() bool {
return state.getEnabled()
}
func readConfig(target string) (value string) {
func readConfig(target string) string {
var (
val, key string
bufin *bufio.Reader
@@ -192,30 +247,42 @@ func readConfig(target string) (value string) {
}
func getSELinuxPolicyRoot() string {
return selinuxDir + readConfig(selinuxTypeTag)
return filepath.Join(selinuxDir, readConfig(selinuxTypeTag))
}
func readCon(name string) (string, error) {
var val string
func readCon(fpath string) (string, error) {
if fpath == "" {
return "", ErrEmptyPath
}
in, err := os.Open(name)
in, err := os.Open(fpath)
if err != nil {
return "", err
}
defer in.Close()
_, err = fmt.Fscanf(in, "%s", &val)
return val, err
var retval string
if _, err := fmt.Fscanf(in, "%s", &retval); err != nil {
return "", err
}
return strings.Trim(retval, "\x00"), nil
}
// SetFileLabel sets the SELinux label for this path or returns an error.
func SetFileLabel(path string, label string) error {
return lsetxattr(path, xattrNameSelinux, []byte(label), 0)
func SetFileLabel(fpath string, label string) error {
if fpath == "" {
return ErrEmptyPath
}
return lsetxattr(fpath, xattrNameSelinux, []byte(label), 0)
}
// FileLabel returns the SELinux label for this path or returns an error.
func FileLabel(path string) (string, error) {
label, err := lgetxattr(path, xattrNameSelinux)
func FileLabel(fpath string) (string, error) {
if fpath == "" {
return "", ErrEmptyPath
}
label, err := lgetxattr(fpath, xattrNameSelinux)
if err != nil {
return "", err
}
@@ -260,8 +327,12 @@ func ExecLabel() (string, error) {
return readCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()))
}
func writeCon(name string, val string) error {
out, err := os.OpenFile(name, os.O_WRONLY, 0)
func writeCon(fpath string, val string) error {
if fpath == "" {
return ErrEmptyPath
}
out, err := os.OpenFile(fpath, os.O_WRONLY, 0)
if err != nil {
return err
}
@@ -275,6 +346,37 @@ func writeCon(name string, val string) error {
return err
}
/*
CanonicalizeContext takes a context string and writes it to the kernel
the function then returns the context that the kernel will use. This function
can be used to see if two contexts are equivalent
*/
func CanonicalizeContext(val string) (string, error) {
return readWriteCon(filepath.Join(getSelinuxMountPoint(), "context"), val)
}
func readWriteCon(fpath string, val string) (string, error) {
if fpath == "" {
return "", ErrEmptyPath
}
f, err := os.OpenFile(fpath, os.O_RDWR, 0)
if err != nil {
return "", err
}
defer f.Close()
_, err = f.Write([]byte(val))
if err != nil {
return "", err
}
var retval string
if _, err := fmt.Fscanf(f, "%s", &retval); err != nil {
return "", err
}
return strings.Trim(retval, "\x00"), nil
}
/*
SetExecLabel sets the SELinux label that the kernel will use for any programs
that are executed by the current process thread, or an error.
@@ -285,7 +387,10 @@ func SetExecLabel(label string) error {
// Get returns the Context as a string
func (c Context) Get() string {
return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"])
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
@@ -297,7 +402,9 @@ func NewContext(label string) Context {
c["user"] = con[0]
c["role"] = con[1]
c["type"] = con[2]
c["level"] = con[3]
if len(con) > 3 {
c["level"] = con[3]
}
}
return c
}
@@ -306,12 +413,14 @@ func NewContext(label string) Context {
func ReserveLabel(label string) {
if len(label) != 0 {
con := strings.SplitN(label, ":", 4)
mcsAdd(con[3])
if len(con) > 3 {
mcsAdd(con[3])
}
}
}
func selinuxEnforcePath() string {
return fmt.Sprintf("%s/enforce", selinuxPath)
return fmt.Sprintf("%s/enforce", getSelinuxMountPoint())
}
// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
@@ -354,16 +463,22 @@ func DefaultEnforceMode() int {
}
func mcsAdd(mcs string) error {
if mcs == "" {
return nil
}
state.Lock()
defer state.Unlock()
if state.mcsList[mcs] {
return fmt.Errorf("MCS Label already exists")
return ErrMCSAlreadyExists
}
state.mcsList[mcs] = true
return nil
}
func mcsDelete(mcs string) {
if mcs == "" {
return
}
state.Lock()
defer state.Unlock()
state.mcsList[mcs] = false
@@ -424,14 +539,14 @@ Allowing it to be used by another process.
func ReleaseLabel(label string) {
if len(label) != 0 {
con := strings.SplitN(label, ":", 4)
mcsDelete(con[3])
if len(con) > 3 {
mcsDelete(con[3])
}
}
}
var roFileLabel string
// ROFileLabel returns the specified SELinux readonly file label
func ROFileLabel() (fileLabel string) {
func ROFileLabel() string {
return roFileLabel
}
@@ -497,23 +612,25 @@ func ContainerLabels() (processLabel string, fileLabel string) {
roFileLabel = fileLabel
}
exit:
mcs := uniqMcs(1024)
scon := NewContext(processLabel)
scon["level"] = mcs
processLabel = scon.Get()
scon = NewContext(fileLabel)
scon["level"] = mcs
fileLabel = scon.Get()
if scon["level"] != "" {
mcs := uniqMcs(1024)
scon["level"] = mcs
processLabel = scon.Get()
scon = NewContext(fileLabel)
scon["level"] = mcs
fileLabel = scon.Get()
}
return processLabel, fileLabel
}
// SecurityCheckContext validates that the SELinux label is understood by the kernel
func SecurityCheckContext(val string) error {
return writeCon(fmt.Sprintf("%s.context", selinuxPath), val)
return writeCon(fmt.Sprintf("%s/context", getSelinuxMountPoint()), val)
}
/*
CopyLevel returns a label with the MLS/MCS level from src label replaces on
CopyLevel returns a label with the MLS/MCS level from src label replaced on
the dest label.
*/
func CopyLevel(src, dest string) (string, error) {
@@ -536,20 +653,26 @@ func CopyLevel(src, dest string) (string, error) {
// Prevent users from relabing system files
func badPrefix(fpath string) error {
var badprefixes = []string{"/usr"}
if fpath == "" {
return ErrEmptyPath
}
for _, prefix := range badprefixes {
if fpath == prefix || strings.HasPrefix(fpath, fmt.Sprintf("%s/", prefix)) {
badPrefixes := []string{"/usr"}
for _, prefix := range badPrefixes {
if strings.HasPrefix(fpath, prefix) {
return fmt.Errorf("relabeling content in %s is not allowed", prefix)
}
}
return nil
}
// Chcon changes the fpath file object to the SELinux label label.
// If the fpath is a directory and recurse is true Chcon will walk the
// directory tree setting the label
// 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 {
if fpath == "" {
return ErrEmptyPath
}
if label == "" {
return nil
}
@@ -568,7 +691,7 @@ func Chcon(fpath string, label string, recurse bool) error {
}
// DupSecOpt takes an SELinux process label and returns security options that
// can will set the SELinux Type and Level for future container processes
// can be used to set the SELinux Type and Level for future container processes.
func DupSecOpt(src string) []string {
if src == "" {
return nil
@@ -576,18 +699,23 @@ func DupSecOpt(src string) []string {
con := NewContext(src)
if con["user"] == "" ||
con["role"] == "" ||
con["type"] == "" ||
con["level"] == "" {
con["type"] == "" {
return nil
}
return []string{"user:" + con["user"],
dup := []string{"user:" + con["user"],
"role:" + con["role"],
"type:" + con["type"],
"level:" + con["level"]}
}
if con["level"] != "" {
dup = append(dup, "level:"+con["level"])
}
return dup
}
// DisableSecOpt returns a security opt that can be used to disabling SELinux
// labeling support for future container processes
// DisableSecOpt returns a security opt that can be used to disable SELinux
// labeling support for future container processes.
func DisableSecOpt() []string {
return []string{"disable"}
}
+188
View File
@@ -0,0 +1,188 @@
// +build !selinux
package selinux
import (
"errors"
)
const (
// Enforcing constant indicate SELinux is in enforcing mode
Enforcing = 1
// Permissive constant to indicate SELinux is in permissive mode
Permissive = 0
// Disabled constant to indicate SELinux is disabled
Disabled = -1
)
var (
// ErrMCSAlreadyExists is returned when trying to allocate a duplicate MCS.
ErrMCSAlreadyExists = errors.New("MCS label already exists")
// ErrEmptyPath is returned when an empty path has been specified.
ErrEmptyPath = errors.New("empty path")
)
// Context is a representation of the SELinux label broken into 4 parts
type Context map[string]string
// SetDisabled disables selinux support for the package
func SetDisabled() {
return
}
// GetEnabled returns whether selinux is currently enabled.
func GetEnabled() bool {
return false
}
// SetFileLabel sets the SELinux label for this path or returns an error.
func SetFileLabel(fpath string, label string) error {
return nil
}
// FileLabel returns the SELinux label for this path or returns an error.
func FileLabel(fpath string) (string, error) {
return "", nil
}
/*
SetFSCreateLabel tells kernel the label to create all file system objects
created by this task. Setting label="" to return to default.
*/
func SetFSCreateLabel(label string) error {
return nil
}
/*
FSCreateLabel returns the default label the kernel which the kernel is using
for file system objects created by this task. "" indicates default.
*/
func FSCreateLabel() (string, error) {
return "", nil
}
// CurrentLabel returns the SELinux label of the current process thread, or an error.
func CurrentLabel() (string, error) {
return "", nil
}
// PidLabel returns the SELinux label of the given pid, or an error.
func PidLabel(pid int) (string, error) {
return "", nil
}
/*
ExecLabel returns the SELinux label that the kernel will use for any programs
that are executed by the current process thread, or an error.
*/
func ExecLabel() (string, error) {
return "", nil
}
/*
CanonicalizeContext takes a context string and writes it to the kernel
the function then returns the context that the kernel will use. This function
can be used to see if two contexts are equivalent
*/
func CanonicalizeContext(val string) (string, error) {
return "", nil
}
/*
SetExecLabel sets the SELinux label that the kernel will use for any programs
that are executed by the current process thread, or an error.
*/
func SetExecLabel(label string) error {
return nil
}
// Get returns the Context as a string
func (c Context) Get() string {
return ""
}
// NewContext creates a new Context struct from the specified label
func NewContext(label string) Context {
c := make(Context)
return c
}
// ReserveLabel reserves the MLS/MCS level component of the specified label
func ReserveLabel(label string) {
return
}
// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
func EnforceMode() int {
return Disabled
}
/*
SetEnforceMode sets the current SELinux mode Enforcing, Permissive.
Disabled is not valid, since this needs to be set at boot time.
*/
func SetEnforceMode(mode int) error {
return nil
}
/*
DefaultEnforceMode returns the systems default SELinux mode Enforcing,
Permissive or Disabled. Note this is is just the default at boot time.
EnforceMode tells you the systems current mode.
*/
func DefaultEnforceMode() int {
return Disabled
}
/*
ReleaseLabel will unreserve the MLS/MCS Level field of the specified label.
Allowing it to be used by another process.
*/
func ReleaseLabel(label string) {
return
}
// ROFileLabel returns the specified SELinux readonly file label
func ROFileLabel() string {
return ""
}
/*
ContainerLabels returns an allocated processLabel and fileLabel to be used for
container labeling by the calling process.
*/
func ContainerLabels() (processLabel string, fileLabel string) {
return "", ""
}
// SecurityCheckContext validates that the SELinux label is understood by the kernel
func SecurityCheckContext(val string) error {
return nil
}
/*
CopyLevel returns a label with the MLS/MCS level from src label replaced on
the dest label.
*/
func CopyLevel(src, dest string) (string, error) {
return "", nil
}
// Chcon changes the `fpath` file object to the SELinux label `label`.
// If `fpath` is a directory and `recurse`` is true, Chcon will walk the
// directory tree setting the label.
func Chcon(fpath string, label string, recurse bool) error {
return nil
}
// DupSecOpt takes an SELinux process label and returns security options that
// can be used to set the SELinux Type and Level for future container processes.
func DupSecOpt(src string) []string {
return nil
}
// DisableSecOpt returns a security opt that can be used to disable SELinux
// labeling support for future container processes.
func DisableSecOpt() []string {
return []string{"disable"}
}
+1 -1
View File
@@ -1,4 +1,4 @@
// +build linux
// +build selinux,linux
package selinux