123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- 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())
- in, err := os.Open(lxcPath)
- 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 {
- 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, "\"")
- }
- }
- }
- if processLabel == "" || fileLabel == "" {
- return "", ""
- }
- 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
- }
|