This patch adds SELinux labeling support.
docker will run the process(es) within the container with an SELinux label and will label all of the content within the container with mount label. Any temporary file systems created within the container need to be mounted with the same mount label. The user can override the process label by specifying -Z With a string of space separated options. -Z "user=unconfined_u role=unconfined_r type=unconfined_t level=s0" Would cause the process label to run with unconfined_u:unconfined_r:unconfined_t:s0" By default the processes will run execute within the container as svirt_lxc_net_t. All of the content in the container as svirt_sandbox_file_t. The process mcs level is based of the PID of the docker process that is creating the container. If you run the container in --priv mode, the labeling will be disabled. Docker-DCO-1.1-Signed-off-by: Dan Walsh <dwalsh@redhat.com> (github: rhatdan)
This commit is contained in:
parent
0424993f6d
commit
2b01982d1f
7 changed files with 573 additions and 11 deletions
23
label/label.go
Normal file
23
label/label.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
// +build !selinux !linux
|
||||
|
||||
package label
|
||||
|
||||
func GenLabels(options string) (string, string, error) {
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
func FormatMountLabel(src string, MountLabel string) string {
|
||||
return src
|
||||
}
|
||||
|
||||
func SetProcessLabel(processLabel string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetFileLabel(path string, fileLabel string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetPidCon(pid int) (string, error) {
|
||||
return "", nil
|
||||
}
|
69
label/label_selinux.go
Normal file
69
label/label_selinux.go
Normal file
|
@ -0,0 +1,69 @@
|
|||
// +build selinux,linux
|
||||
|
||||
package label
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/pkg/selinux"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GenLabels(options string) (string, string, error) {
|
||||
processLabel, mountLabel := selinux.GetLxcContexts()
|
||||
var err error
|
||||
if processLabel == "" { // SELinux is disabled
|
||||
return "", "", err
|
||||
}
|
||||
s := strings.Fields(options)
|
||||
l := len(s)
|
||||
if l > 0 {
|
||||
pcon := selinux.NewContext(processLabel)
|
||||
for i := 0; i < l; i++ {
|
||||
o := strings.Split(s[i], "=")
|
||||
pcon[o[0]] = o[1]
|
||||
}
|
||||
processLabel = pcon.Get()
|
||||
mountLabel, err = selinux.CopyLevel(processLabel, mountLabel)
|
||||
}
|
||||
return processLabel, mountLabel, err
|
||||
}
|
||||
|
||||
func FormatMountLabel(src string, MountLabel string) string {
|
||||
var mountLabel string
|
||||
if src != "" {
|
||||
mountLabel = src
|
||||
if MountLabel != "" {
|
||||
mountLabel = fmt.Sprintf("%s,context=\"%s\"", mountLabel, MountLabel)
|
||||
}
|
||||
} else {
|
||||
if MountLabel != "" {
|
||||
mountLabel = fmt.Sprintf("context=\"%s\"", MountLabel)
|
||||
}
|
||||
}
|
||||
return mountLabel
|
||||
}
|
||||
|
||||
func SetProcessLabel(processLabel string) error {
|
||||
if selinux.SelinuxEnabled() {
|
||||
return selinux.Setexeccon(processLabel)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetProcessLabel() (string, error) {
|
||||
if selinux.SelinuxEnabled() {
|
||||
return selinux.Getexeccon()
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func SetFileLabel(path string, fileLabel string) error {
|
||||
if selinux.SelinuxEnabled() && fileLabel != "" {
|
||||
return selinux.Setfilecon(path, fileLabel)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetPidCon(pid int) (string, error) {
|
||||
return selinux.Getpidcon(pid)
|
||||
}
|
|
@ -4,6 +4,7 @@ package nsinit
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/pkg/label"
|
||||
"github.com/dotcloud/docker/pkg/libcontainer"
|
||||
"github.com/dotcloud/docker/pkg/system"
|
||||
"os"
|
||||
|
@ -32,7 +33,11 @@ func (ns *linuxNs) ExecIn(container *libcontainer.Container, nspid int, args []s
|
|||
closeFds()
|
||||
return -1, err
|
||||
}
|
||||
|
||||
processLabel, err := label.GetPidCon(nspid)
|
||||
if err != nil {
|
||||
closeFds()
|
||||
return -1, err
|
||||
}
|
||||
// foreach namespace fd, use setns to join an existing container's namespaces
|
||||
for _, fd := range fds {
|
||||
if fd > 0 {
|
||||
|
@ -80,6 +85,10 @@ dropAndExec:
|
|||
if err := finalizeNamespace(container); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
err = label.SetProcessLabel(processLabel)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if err := system.Execv(args[0], args[0:], container.Env); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ package nsinit
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/pkg/label"
|
||||
"github.com/dotcloud/docker/pkg/libcontainer"
|
||||
"github.com/dotcloud/docker/pkg/libcontainer/apparmor"
|
||||
"github.com/dotcloud/docker/pkg/libcontainer/capabilities"
|
||||
|
@ -12,6 +13,7 @@ import (
|
|||
"github.com/dotcloud/docker/pkg/system"
|
||||
"github.com/dotcloud/docker/pkg/user"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
|
@ -57,7 +59,7 @@ func (ns *linuxNs) Init(container *libcontainer.Container, uncleanRootfs, consol
|
|||
return fmt.Errorf("parent death signal %s", err)
|
||||
}
|
||||
ns.logger.Println("setup mount namespace")
|
||||
if err := setupNewMountNamespace(rootfs, container.Mounts, console, container.ReadonlyFs, container.NoPivotRoot); err != nil {
|
||||
if err := setupNewMountNamespace(rootfs, container.Mounts, console, container.ReadonlyFs, container.NoPivotRoot, container.Context["mount_label"]); err != nil {
|
||||
return fmt.Errorf("setup mount namespace %s", err)
|
||||
}
|
||||
if err := setupNetwork(container, context); err != nil {
|
||||
|
@ -76,6 +78,10 @@ func (ns *linuxNs) Init(container *libcontainer.Container, uncleanRootfs, consol
|
|||
return err
|
||||
}
|
||||
}
|
||||
runtime.LockOSThread()
|
||||
if err := label.SetProcessLabel(container.Context["process_label"]); err != nil {
|
||||
return fmt.Errorf("SetProcessLabel label %s", err)
|
||||
}
|
||||
ns.logger.Printf("execing %s\n", args[0])
|
||||
return system.Execv(args[0], args[0:], container.Env)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ package nsinit
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/pkg/label"
|
||||
"github.com/dotcloud/docker/pkg/libcontainer"
|
||||
"github.com/dotcloud/docker/pkg/system"
|
||||
"io/ioutil"
|
||||
|
@ -20,7 +21,7 @@ const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NOD
|
|||
//
|
||||
// There is no need to unmount the new mounts because as soon as the mount namespace
|
||||
// is no longer in use, the mounts will be removed automatically
|
||||
func setupNewMountNamespace(rootfs string, bindMounts []libcontainer.Mount, console string, readonly, noPivotRoot bool) error {
|
||||
func setupNewMountNamespace(rootfs string, bindMounts []libcontainer.Mount, console string, readonly, noPivotRoot bool, mountLabel string) error {
|
||||
flag := syscall.MS_PRIVATE
|
||||
if noPivotRoot {
|
||||
flag = syscall.MS_SLAVE
|
||||
|
@ -36,7 +37,7 @@ func setupNewMountNamespace(rootfs string, bindMounts []libcontainer.Mount, cons
|
|||
return fmt.Errorf("mounting %s as readonly %s", rootfs, err)
|
||||
}
|
||||
}
|
||||
if err := mountSystem(rootfs); err != nil {
|
||||
if err := mountSystem(rootfs, mountLabel); err != nil {
|
||||
return fmt.Errorf("mount system %s", err)
|
||||
}
|
||||
|
||||
|
@ -64,7 +65,7 @@ func setupNewMountNamespace(rootfs string, bindMounts []libcontainer.Mount, cons
|
|||
if err := setupDev(rootfs); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setupPtmx(rootfs, console); err != nil {
|
||||
if err := setupPtmx(rootfs, console, mountLabel); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := system.Chdir(rootfs); err != nil {
|
||||
|
@ -196,7 +197,7 @@ func setupDev(rootfs string) error {
|
|||
}
|
||||
|
||||
// setupConsole ensures that the container has a proper /dev/console setup
|
||||
func setupConsole(rootfs, console string) error {
|
||||
func setupConsole(rootfs, console string, mountLabel string) error {
|
||||
oldMask := system.Umask(0000)
|
||||
defer system.Umask(oldMask)
|
||||
|
||||
|
@ -220,6 +221,9 @@ func setupConsole(rootfs, console string) error {
|
|||
if err := system.Mknod(dest, (st.Mode&^07777)|0600, int(st.Rdev)); err != nil {
|
||||
return fmt.Errorf("mknod %s %s", dest, err)
|
||||
}
|
||||
if err := label.SetFileLabel(console, mountLabel); err != nil {
|
||||
return fmt.Errorf("SetFileLabel Failed %s %s", dest, err)
|
||||
}
|
||||
if err := system.Mount(console, dest, "bind", syscall.MS_BIND, ""); err != nil {
|
||||
return fmt.Errorf("bind %s to %s %s", console, dest, err)
|
||||
}
|
||||
|
@ -228,7 +232,7 @@ func setupConsole(rootfs, console string) error {
|
|||
|
||||
// mountSystem sets up linux specific system mounts like sys, proc, shm, and devpts
|
||||
// inside the mount namespace
|
||||
func mountSystem(rootfs string) error {
|
||||
func mountSystem(rootfs string, mountLabel string) error {
|
||||
for _, m := range []struct {
|
||||
source string
|
||||
path string
|
||||
|
@ -238,8 +242,8 @@ func mountSystem(rootfs string) error {
|
|||
}{
|
||||
{source: "proc", path: filepath.Join(rootfs, "proc"), device: "proc", flags: defaultMountFlags},
|
||||
{source: "sysfs", path: filepath.Join(rootfs, "sys"), device: "sysfs", flags: defaultMountFlags},
|
||||
{source: "shm", path: filepath.Join(rootfs, "dev", "shm"), device: "tmpfs", flags: defaultMountFlags, data: "mode=1777,size=65536k"},
|
||||
{source: "devpts", path: filepath.Join(rootfs, "dev", "pts"), device: "devpts", flags: syscall.MS_NOSUID | syscall.MS_NOEXEC, data: "newinstance,ptmxmode=0666,mode=620,gid=5"},
|
||||
{source: "shm", path: filepath.Join(rootfs, "dev", "shm"), device: "tmpfs", flags: defaultMountFlags, data: label.FormatMountLabel("mode=1755,size=65536k", mountLabel)},
|
||||
{source: "devpts", path: filepath.Join(rootfs, "dev", "pts"), device: "devpts", flags: syscall.MS_NOSUID | syscall.MS_NOEXEC, data: label.FormatMountLabel("newinstance,ptmxmode=0666,mode=620,gid=5", mountLabel)},
|
||||
} {
|
||||
if err := os.MkdirAll(m.path, 0755); err != nil && !os.IsExist(err) {
|
||||
return fmt.Errorf("mkdirall %s %s", m.path, err)
|
||||
|
@ -253,7 +257,7 @@ func mountSystem(rootfs string) error {
|
|||
|
||||
// setupPtmx adds a symlink to pts/ptmx for /dev/ptmx and
|
||||
// finishes setting up /dev/console
|
||||
func setupPtmx(rootfs, console string) error {
|
||||
func setupPtmx(rootfs, console string, mountLabel string) error {
|
||||
ptmx := filepath.Join(rootfs, "dev/ptmx")
|
||||
if err := os.Remove(ptmx); err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
|
@ -262,7 +266,7 @@ func setupPtmx(rootfs, console string) error {
|
|||
return fmt.Errorf("symlink dev ptmx %s", err)
|
||||
}
|
||||
if console != "" {
|
||||
if err := setupConsole(rootfs, console); err != nil {
|
||||
if err := setupConsole(rootfs, console, mountLabel); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
387
selinux/selinux.go
Normal file
387
selinux/selinux.go
Normal file
|
@ -0,0 +1,387 @@
|
|||
package selinux
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/pkg/mount"
|
||||
"github.com/dotcloud/docker/pkg/system"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
Enforcing = 1
|
||||
Permissive = 0
|
||||
Disabled = -1
|
||||
selinuxDir = "/etc/selinux/"
|
||||
selinuxConfig = selinuxDir + "config"
|
||||
selinuxTypeTag = "SELINUXTYPE"
|
||||
selinuxTag = "SELINUX"
|
||||
selinuxPath = "/sys/fs/selinux"
|
||||
xattrNameSelinux = "security.selinux"
|
||||
stRdOnly = 0x01
|
||||
)
|
||||
|
||||
var (
|
||||
assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`)
|
||||
spaceRegex = regexp.MustCompile(`^([^=]+) (.*)$`)
|
||||
mcsList = make(map[string]bool)
|
||||
selinuxfs = "unknown"
|
||||
selinuxEnabled = false
|
||||
selinuxEnabledChecked = false
|
||||
)
|
||||
|
||||
type SELinuxContext map[string]string
|
||||
|
||||
func GetSelinuxMountPoint() string {
|
||||
if selinuxfs != "unknown" {
|
||||
return selinuxfs
|
||||
}
|
||||
selinuxfs = ""
|
||||
|
||||
mounts, err := mount.GetMounts()
|
||||
if err != nil {
|
||||
return selinuxfs
|
||||
}
|
||||
for _, mount := range mounts {
|
||||
if mount.Fstype == "selinuxfs" {
|
||||
selinuxfs = mount.Mountpoint
|
||||
break
|
||||
}
|
||||
}
|
||||
if selinuxfs != "" {
|
||||
var buf syscall.Statfs_t
|
||||
syscall.Statfs(selinuxfs, &buf)
|
||||
if (buf.Flags & stRdOnly) == 1 {
|
||||
selinuxfs = ""
|
||||
}
|
||||
}
|
||||
return selinuxfs
|
||||
}
|
||||
|
||||
func SelinuxEnabled() bool {
|
||||
if selinuxEnabledChecked {
|
||||
return selinuxEnabled
|
||||
}
|
||||
selinuxEnabledChecked = true
|
||||
if fs := GetSelinuxMountPoint(); fs != "" {
|
||||
if con, _ := Getcon(); con != "kernel" {
|
||||
selinuxEnabled = true
|
||||
}
|
||||
}
|
||||
return selinuxEnabled
|
||||
}
|
||||
|
||||
func ReadConfig(target string) (value string) {
|
||||
var (
|
||||
val, key string
|
||||
bufin *bufio.Reader
|
||||
)
|
||||
|
||||
in, err := os.Open(selinuxConfig)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
bufin = bufio.NewReader(in)
|
||||
|
||||
for done := false; !done; {
|
||||
var line string
|
||||
if line, err = bufin.ReadString('\n'); err != nil {
|
||||
if err != io.EOF {
|
||||
return ""
|
||||
}
|
||||
done = true
|
||||
}
|
||||
line = strings.TrimSpace(line)
|
||||
if len(line) == 0 {
|
||||
// Skip blank lines
|
||||
continue
|
||||
}
|
||||
if line[0] == ';' || line[0] == '#' {
|
||||
// Skip comments
|
||||
continue
|
||||
}
|
||||
if groups := assignRegex.FindStringSubmatch(line); groups != nil {
|
||||
key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
|
||||
if key == target {
|
||||
return strings.Trim(val, "\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func GetSELinuxPolicyRoot() string {
|
||||
return selinuxDir + ReadConfig(selinuxTypeTag)
|
||||
}
|
||||
|
||||
func readCon(name string) (string, error) {
|
||||
var val string
|
||||
|
||||
in, err := os.Open(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
_, err = fmt.Fscanf(in, "%s", &val)
|
||||
return val, err
|
||||
}
|
||||
|
||||
func Setfilecon(path string, scon string) error {
|
||||
return system.Lsetxattr(path, xattrNameSelinux, []byte(scon), 0)
|
||||
}
|
||||
|
||||
func Getfilecon(path string) (string, error) {
|
||||
var scon []byte
|
||||
|
||||
cnt, err := syscall.Getxattr(path, xattrNameSelinux, scon)
|
||||
scon = make([]byte, cnt)
|
||||
cnt, err = syscall.Getxattr(path, xattrNameSelinux, scon)
|
||||
return string(scon), err
|
||||
}
|
||||
|
||||
func Setfscreatecon(scon string) error {
|
||||
return writeCon("/proc/self/attr/fscreate", scon)
|
||||
}
|
||||
|
||||
func Getfscreatecon() (string, error) {
|
||||
return readCon("/proc/self/attr/fscreate")
|
||||
}
|
||||
|
||||
func Getcon() (string, error) {
|
||||
return readCon("/proc/self/attr/current")
|
||||
}
|
||||
|
||||
func Getpidcon(pid int) (string, error) {
|
||||
return readCon(fmt.Sprintf("/proc/%d/attr/current", pid))
|
||||
}
|
||||
|
||||
func Getexeccon() (string, error) {
|
||||
return readCon("/proc/self/attr/exec")
|
||||
}
|
||||
|
||||
func writeCon(name string, val string) error {
|
||||
if !SelinuxEnabled() {
|
||||
return nil
|
||||
}
|
||||
out, err := os.OpenFile(name, os.O_WRONLY, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
if val != "" {
|
||||
_, err = out.Write([]byte(val))
|
||||
} else {
|
||||
_, err = out.Write(nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func Setexeccon(scon string) error {
|
||||
return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), scon)
|
||||
}
|
||||
|
||||
func (c SELinuxContext) Get() string {
|
||||
return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"])
|
||||
}
|
||||
|
||||
func NewContext(scon string) SELinuxContext {
|
||||
c := make(SELinuxContext)
|
||||
|
||||
if len(scon) != 0 {
|
||||
con := strings.SplitN(scon, ":", 4)
|
||||
c["user"] = con[0]
|
||||
c["role"] = con[1]
|
||||
c["type"] = con[2]
|
||||
c["level"] = con[3]
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func SelinuxGetEnforce() int {
|
||||
var enforce int
|
||||
|
||||
enforceS, err := readCon(fmt.Sprintf("%s/enforce", selinuxPath))
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
enforce, err = strconv.Atoi(string(enforceS))
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
return enforce
|
||||
}
|
||||
|
||||
func SelinuxGetEnforceMode() int {
|
||||
switch ReadConfig(selinuxTag) {
|
||||
case "enforcing":
|
||||
return Enforcing
|
||||
case "permissive":
|
||||
return Permissive
|
||||
}
|
||||
return Disabled
|
||||
}
|
||||
|
||||
func mcsAdd(mcs string) {
|
||||
mcsList[mcs] = true
|
||||
}
|
||||
|
||||
func mcsDelete(mcs string) {
|
||||
mcsList[mcs] = false
|
||||
}
|
||||
|
||||
func mcsExists(mcs string) bool {
|
||||
return mcsList[mcs]
|
||||
}
|
||||
|
||||
func IntToMcs(id int, catRange uint32) string {
|
||||
var (
|
||||
SETSIZE = int(catRange)
|
||||
TIER = SETSIZE
|
||||
ORD = id
|
||||
)
|
||||
|
||||
if id < 1 || id > 523776 {
|
||||
return ""
|
||||
}
|
||||
|
||||
for ORD > TIER {
|
||||
ORD = ORD - TIER
|
||||
TIER -= 1
|
||||
}
|
||||
TIER = SETSIZE - TIER
|
||||
ORD = ORD + TIER
|
||||
return fmt.Sprintf("s0:c%d,c%d", TIER, ORD)
|
||||
}
|
||||
|
||||
func uniqMcs(catRange uint32) string {
|
||||
var (
|
||||
n uint32
|
||||
c1, c2 uint32
|
||||
mcs string
|
||||
)
|
||||
|
||||
for {
|
||||
binary.Read(rand.Reader, binary.LittleEndian, &n)
|
||||
c1 = n % catRange
|
||||
binary.Read(rand.Reader, binary.LittleEndian, &n)
|
||||
c2 = n % catRange
|
||||
if c1 == c2 {
|
||||
continue
|
||||
} else {
|
||||
if c1 > c2 {
|
||||
t := c1
|
||||
c1 = c2
|
||||
c2 = t
|
||||
}
|
||||
}
|
||||
mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2)
|
||||
if mcsExists(mcs) {
|
||||
continue
|
||||
}
|
||||
mcsAdd(mcs)
|
||||
break
|
||||
}
|
||||
return mcs
|
||||
}
|
||||
|
||||
func FreeContext(con string) {
|
||||
if con != "" {
|
||||
scon := NewContext(con)
|
||||
mcsDelete(scon["level"])
|
||||
}
|
||||
}
|
||||
|
||||
func GetLxcContexts() (processLabel string, fileLabel string) {
|
||||
var (
|
||||
val, key string
|
||||
bufin *bufio.Reader
|
||||
)
|
||||
|
||||
if !SelinuxEnabled() {
|
||||
return "", ""
|
||||
}
|
||||
lxcPath := fmt.Sprintf("%s/content/lxc_contexts", GetSELinuxPolicyRoot())
|
||||
fileLabel = "system_u:object_r:svirt_sandbox_file_t:s0"
|
||||
processLabel = "system_u:system_r:svirt_lxc_net_t:s0"
|
||||
|
||||
in, err := os.Open(lxcPath)
|
||||
if err != nil {
|
||||
goto exit
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
bufin = bufio.NewReader(in)
|
||||
|
||||
for done := false; !done; {
|
||||
var line string
|
||||
if line, err = bufin.ReadString('\n'); err != nil {
|
||||
if err == io.EOF {
|
||||
done = true
|
||||
} else {
|
||||
goto exit
|
||||
}
|
||||
}
|
||||
line = strings.TrimSpace(line)
|
||||
if len(line) == 0 {
|
||||
// Skip blank lines
|
||||
continue
|
||||
}
|
||||
if line[0] == ';' || line[0] == '#' {
|
||||
// Skip comments
|
||||
continue
|
||||
}
|
||||
if groups := assignRegex.FindStringSubmatch(line); groups != nil {
|
||||
key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
|
||||
if key == "process" {
|
||||
processLabel = strings.Trim(val, "\"")
|
||||
}
|
||||
if key == "file" {
|
||||
fileLabel = strings.Trim(val, "\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
exit:
|
||||
mcs := IntToMcs(os.Getpid(), 1024)
|
||||
scon := NewContext(processLabel)
|
||||
scon["level"] = mcs
|
||||
processLabel = scon.Get()
|
||||
scon = NewContext(fileLabel)
|
||||
scon["level"] = mcs
|
||||
fileLabel = scon.Get()
|
||||
return processLabel, fileLabel
|
||||
}
|
||||
|
||||
func SecurityCheckContext(val string) error {
|
||||
return writeCon(fmt.Sprintf("%s.context", selinuxPath), val)
|
||||
}
|
||||
|
||||
func CopyLevel(src, dest string) (string, error) {
|
||||
if !SelinuxEnabled() {
|
||||
return "", nil
|
||||
}
|
||||
if src == "" {
|
||||
return "", nil
|
||||
}
|
||||
if err := SecurityCheckContext(src); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := SecurityCheckContext(dest); err != nil {
|
||||
return "", err
|
||||
}
|
||||
scon := NewContext(src)
|
||||
tcon := NewContext(dest)
|
||||
tcon["level"] = scon["level"]
|
||||
return tcon.Get(), nil
|
||||
}
|
64
selinux/selinux_test.go
Normal file
64
selinux/selinux_test.go
Normal file
|
@ -0,0 +1,64 @@
|
|||
package selinux_test
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/pkg/selinux"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testSetfilecon(t *testing.T) {
|
||||
if selinux.SelinuxEnabled() {
|
||||
tmp := "selinux_test"
|
||||
out, _ := os.OpenFile(tmp, os.O_WRONLY, 0)
|
||||
out.Close()
|
||||
err := selinux.Setfilecon(tmp, "system_u:object_r:bin_t:s0")
|
||||
if err == nil {
|
||||
t.Log(selinux.Getfilecon(tmp))
|
||||
} else {
|
||||
t.Log("Setfilecon failed")
|
||||
t.Fatal(err)
|
||||
}
|
||||
os.Remove(tmp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSELinux(t *testing.T) {
|
||||
var (
|
||||
err error
|
||||
plabel, flabel string
|
||||
)
|
||||
|
||||
if selinux.SelinuxEnabled() {
|
||||
t.Log("Enabled")
|
||||
plabel, flabel = selinux.GetLxcContexts()
|
||||
t.Log(plabel)
|
||||
t.Log(flabel)
|
||||
plabel, flabel = selinux.GetLxcContexts()
|
||||
t.Log(plabel)
|
||||
t.Log(flabel)
|
||||
t.Log("getenforce ", selinux.SelinuxGetEnforce())
|
||||
t.Log("getenforcemode ", selinux.SelinuxGetEnforceMode())
|
||||
pid := os.Getpid()
|
||||
t.Log("PID:%d MCS:%s\n", pid, selinux.IntToMcs(pid, 1023))
|
||||
t.Log(selinux.Getcon())
|
||||
t.Log(selinux.Getfilecon("/etc/passwd"))
|
||||
err = selinux.Setfscreatecon("unconfined_u:unconfined_r:unconfined_t:s0")
|
||||
if err == nil {
|
||||
t.Log(selinux.Getfscreatecon())
|
||||
} else {
|
||||
t.Log("setfscreatecon failed", err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = selinux.Setfscreatecon("")
|
||||
if err == nil {
|
||||
t.Log(selinux.Getfscreatecon())
|
||||
} else {
|
||||
t.Log("setfscreatecon failed", err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(selinux.Getpidcon(1))
|
||||
t.Log(selinux.GetSelinuxMountPoint())
|
||||
} else {
|
||||
t.Log("Disabled")
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue