Browse code

Merge pull request #32687 from runcom/oci-selinux

Switch to using opencontainers/selinux for selinux bindings

Vincent Demeester authored on 2017/04/30 02:05:32
Showing 26 changed files
... ...
@@ -43,7 +43,7 @@ import (
43 43
 	"github.com/docker/libnetwork/options"
44 44
 	"github.com/docker/libnetwork/types"
45 45
 	agentexec "github.com/docker/swarmkit/agent/exec"
46
-	"github.com/opencontainers/runc/libcontainer/label"
46
+	"github.com/opencontainers/selinux/go-selinux/label"
47 47
 )
48 48
 
49 49
 const configFileName = "config.v2.json"
... ...
@@ -17,7 +17,7 @@ import (
17 17
 	"github.com/docker/docker/pkg/symlink"
18 18
 	"github.com/docker/docker/pkg/system"
19 19
 	"github.com/docker/docker/volume"
20
-	"github.com/opencontainers/runc/libcontainer/label"
20
+	"github.com/opencontainers/selinux/go-selinux/label"
21 21
 	"golang.org/x/sys/unix"
22 22
 )
23 23
 
... ...
@@ -19,7 +19,7 @@ import (
19 19
 	"github.com/docker/docker/pkg/stringid"
20 20
 	"github.com/docker/docker/runconfig"
21 21
 	"github.com/docker/libnetwork"
22
-	"github.com/opencontainers/runc/libcontainer/label"
22
+	"github.com/opencontainers/selinux/go-selinux/label"
23 23
 	"github.com/pkg/errors"
24 24
 )
25 25
 
... ...
@@ -20,7 +20,7 @@ import (
20 20
 	"github.com/docker/docker/pkg/idtools"
21 21
 	"github.com/docker/docker/pkg/stringid"
22 22
 	"github.com/docker/docker/runconfig"
23
-	"github.com/opencontainers/runc/libcontainer/label"
23
+	"github.com/opencontainers/selinux/go-selinux/label"
24 24
 )
25 25
 
26 26
 // CreateManagedContainer creates a container that is managed by a Service
... ...
@@ -155,6 +155,13 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (
155 155
 	return container, nil
156 156
 }
157 157
 
158
+func toHostConfigSelinuxLabels(labels []string) []string {
159
+	for i, l := range labels {
160
+		labels[i] = "label=" + l
161
+	}
162
+	return labels
163
+}
164
+
158 165
 func (daemon *Daemon) generateSecurityOpt(hostConfig *containertypes.HostConfig) ([]string, error) {
159 166
 	for _, opt := range hostConfig.SecurityOpt {
160 167
 		con := strings.Split(opt, "=")
... ...
@@ -167,7 +174,7 @@ func (daemon *Daemon) generateSecurityOpt(hostConfig *containertypes.HostConfig)
167 167
 	pidMode := hostConfig.PidMode
168 168
 	privileged := hostConfig.Privileged
169 169
 	if ipcMode.IsHost() || pidMode.IsHost() || privileged {
170
-		return label.DisableSecOpt(), nil
170
+		return toHostConfigSelinuxLabels(label.DisableSecOpt()), nil
171 171
 	}
172 172
 
173 173
 	var ipcLabel []string
... ...
@@ -181,7 +188,7 @@ func (daemon *Daemon) generateSecurityOpt(hostConfig *containertypes.HostConfig)
181 181
 		}
182 182
 		ipcLabel = label.DupSecOpt(c.ProcessLabel)
183 183
 		if pidContainer == "" {
184
-			return ipcLabel, err
184
+			return toHostConfigSelinuxLabels(ipcLabel), err
185 185
 		}
186 186
 	}
187 187
 	if pidContainer != "" {
... ...
@@ -192,7 +199,7 @@ func (daemon *Daemon) generateSecurityOpt(hostConfig *containertypes.HostConfig)
192 192
 
193 193
 		pidLabel = label.DupSecOpt(c.ProcessLabel)
194 194
 		if ipcContainer == "" {
195
-			return pidLabel, err
195
+			return toHostConfigSelinuxLabels(pidLabel), err
196 196
 		}
197 197
 	}
198 198
 
... ...
@@ -202,7 +209,7 @@ func (daemon *Daemon) generateSecurityOpt(hostConfig *containertypes.HostConfig)
202 202
 				return nil, fmt.Errorf("--ipc and --pid containers SELinux labels aren't the same")
203 203
 			}
204 204
 		}
205
-		return pidLabel, nil
205
+		return toHostConfigSelinuxLabels(pidLabel), nil
206 206
 	}
207 207
 	return nil, nil
208 208
 }
... ...
@@ -12,7 +12,7 @@ import (
12 12
 	mounttypes "github.com/docker/docker/api/types/mount"
13 13
 	"github.com/docker/docker/container"
14 14
 	"github.com/docker/docker/pkg/stringid"
15
-	"github.com/opencontainers/runc/libcontainer/label"
15
+	"github.com/opencontainers/selinux/go-selinux/label"
16 16
 )
17 17
 
18 18
 // createContainerPlatformSpecificSettings performs platform specific container create functionality
... ...
@@ -23,8 +23,8 @@ import (
23 23
 	"github.com/docker/libnetwork/netlabel"
24 24
 	"github.com/docker/libnetwork/netutils"
25 25
 	lntypes "github.com/docker/libnetwork/types"
26
-	"github.com/opencontainers/runc/libcontainer/label"
27 26
 	"github.com/opencontainers/runtime-spec/specs-go"
27
+	"github.com/opencontainers/selinux/go-selinux/label"
28 28
 	"github.com/pkg/errors"
29 29
 )
30 30
 
... ...
@@ -41,9 +41,9 @@ import (
41 41
 	lntypes "github.com/docker/libnetwork/types"
42 42
 	"github.com/golang/protobuf/ptypes"
43 43
 	"github.com/opencontainers/runc/libcontainer/cgroups"
44
-	"github.com/opencontainers/runc/libcontainer/label"
45 44
 	rsystem "github.com/opencontainers/runc/libcontainer/system"
46 45
 	specs "github.com/opencontainers/runtime-spec/specs-go"
46
+	"github.com/opencontainers/selinux/go-selinux/label"
47 47
 	"github.com/pkg/errors"
48 48
 	"github.com/vishvananda/netlink"
49 49
 )
... ...
@@ -47,8 +47,8 @@ import (
47 47
 	"github.com/docker/docker/pkg/locker"
48 48
 	mountpk "github.com/docker/docker/pkg/mount"
49 49
 
50
-	"github.com/opencontainers/runc/libcontainer/label"
51 50
 	rsystem "github.com/opencontainers/runc/libcontainer/system"
51
+	"github.com/opencontainers/selinux/go-selinux/label"
52 52
 )
53 53
 
54 54
 var (
... ...
@@ -28,7 +28,7 @@ import (
28 28
 	"github.com/docker/docker/pkg/mount"
29 29
 	"github.com/docker/docker/pkg/parsers"
30 30
 	"github.com/docker/go-units"
31
-	"github.com/opencontainers/runc/libcontainer/label"
31
+	"github.com/opencontainers/selinux/go-selinux/label"
32 32
 )
33 33
 
34 34
 func init() {
... ...
@@ -30,7 +30,7 @@ import (
30 30
 	"github.com/docker/docker/pkg/parsers"
31 31
 	units "github.com/docker/go-units"
32 32
 
33
-	"github.com/opencontainers/runc/libcontainer/label"
33
+	"github.com/opencontainers/selinux/go-selinux/label"
34 34
 )
35 35
 
36 36
 var (
... ...
@@ -21,7 +21,7 @@ import (
21 21
 	"github.com/docker/docker/pkg/idtools"
22 22
 	"github.com/docker/docker/pkg/locker"
23 23
 	"github.com/docker/docker/pkg/mount"
24
-	"github.com/opencontainers/runc/libcontainer/label"
24
+	"github.com/opencontainers/selinux/go-selinux/label"
25 25
 )
26 26
 
27 27
 // This is a small wrapper over the NaiveDiffWriter that lets us have a custom
... ...
@@ -33,7 +33,7 @@ import (
33 33
 	"github.com/docker/docker/pkg/parsers/kernel"
34 34
 	units "github.com/docker/go-units"
35 35
 
36
-	"github.com/opencontainers/runc/libcontainer/label"
36
+	"github.com/opencontainers/selinux/go-selinux/label"
37 37
 )
38 38
 
39 39
 var (
... ...
@@ -9,7 +9,7 @@ import (
9 9
 	"github.com/docker/docker/pkg/chrootarchive"
10 10
 	"github.com/docker/docker/pkg/idtools"
11 11
 
12
-	"github.com/opencontainers/runc/libcontainer/label"
12
+	"github.com/opencontainers/selinux/go-selinux/label"
13 13
 )
14 14
 
15 15
 var (
... ...
@@ -19,7 +19,7 @@ import (
19 19
 	"github.com/docker/docker/pkg/mount"
20 20
 	"github.com/docker/docker/pkg/parsers"
21 21
 	zfs "github.com/mistifyio/go-zfs"
22
-	"github.com/opencontainers/runc/libcontainer/label"
22
+	"github.com/opencontainers/selinux/go-selinux/label"
23 23
 )
24 24
 
25 25
 type zfsOptions struct {
... ...
@@ -2,16 +2,16 @@
2 2
 
3 3
 package daemon
4 4
 
5
-import "github.com/opencontainers/runc/libcontainer/selinux"
5
+import "github.com/opencontainers/selinux/go-selinux"
6 6
 
7 7
 func selinuxSetDisabled() {
8 8
 	selinux.SetDisabled()
9 9
 }
10 10
 
11 11
 func selinuxFreeLxcContexts(label string) {
12
-	selinux.FreeLxcContexts(label)
12
+	selinux.ReleaseLabel(label)
13 13
 }
14 14
 
15 15
 func selinuxEnabled() bool {
16
-	return selinux.SelinuxEnabled()
16
+	return selinux.GetEnabled()
17 17
 }
... ...
@@ -143,3 +143,4 @@ github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a
143 143
 github.com/xeipuuv/gojsonreference e02fc20de94c78484cd5ffb007f8af96be030a45
144 144
 github.com/xeipuuv/gojsonschema 93e72a773fade158921402d6a24c819b48aba29d
145 145
 gopkg.in/yaml.v2 4c78c975fe7c825c6d1466c42be594d1d6f3aba6
146
+github.com/opencontainers/selinux ba1aefe8057f1d0cfb8e88d0ec1dc85925ef987d
146 147
deleted file mode 100644
... ...
@@ -1,84 +0,0 @@
1
-// +build !selinux !linux
2
-
3
-package label
4
-
5
-// InitLabels returns the process label and file labels to be used within
6
-// the container.  A list of options can be passed into this function to alter
7
-// the labels.
8
-func InitLabels(options []string) (string, string, error) {
9
-	return "", "", nil
10
-}
11
-
12
-func GetROMountLabel() string {
13
-	return ""
14
-}
15
-
16
-func GenLabels(options string) (string, string, error) {
17
-	return "", "", nil
18
-}
19
-
20
-func FormatMountLabel(src string, mountLabel string) string {
21
-	return src
22
-}
23
-
24
-func SetProcessLabel(processLabel string) error {
25
-	return nil
26
-}
27
-
28
-func GetFileLabel(path string) (string, error) {
29
-	return "", nil
30
-}
31
-
32
-func SetFileLabel(path string, fileLabel string) error {
33
-	return nil
34
-}
35
-
36
-func SetFileCreateLabel(fileLabel string) error {
37
-	return nil
38
-}
39
-
40
-func Relabel(path string, fileLabel string, shared bool) error {
41
-	return nil
42
-}
43
-
44
-func GetPidLabel(pid int) (string, error) {
45
-	return "", nil
46
-}
47
-
48
-func Init() {
49
-}
50
-
51
-func ReserveLabel(label string) error {
52
-	return nil
53
-}
54
-
55
-func UnreserveLabel(label string) error {
56
-	return nil
57
-}
58
-
59
-// DupSecOpt takes a process label and returns security options that
60
-// can be used to set duplicate labels on future container processes
61
-func DupSecOpt(src string) []string {
62
-	return nil
63
-}
64
-
65
-// DisableSecOpt returns a security opt that can disable labeling
66
-// support for future container processes
67
-func DisableSecOpt() []string {
68
-	return nil
69
-}
70
-
71
-// Validate checks that the label does not include unexpected options
72
-func Validate(label string) error {
73
-	return nil
74
-}
75
-
76
-// RelabelNeeded checks whether the user requested a relabel
77
-func RelabelNeeded(label string) bool {
78
-	return false
79
-}
80
-
81
-// IsShared checks that the label includes a "shared" mark
82
-func IsShared(label string) bool {
83
-	return false
84
-}
85 1
deleted file mode 100644
... ...
@@ -1,204 +0,0 @@
1
-// +build selinux,linux
2
-
3
-package label
4
-
5
-import (
6
-	"fmt"
7
-	"strings"
8
-
9
-	"github.com/opencontainers/runc/libcontainer/selinux"
10
-)
11
-
12
-// Valid Label Options
13
-var validOptions = map[string]bool{
14
-	"disable": true,
15
-	"type":    true,
16
-	"user":    true,
17
-	"role":    true,
18
-	"level":   true,
19
-}
20
-
21
-var ErrIncompatibleLabel = fmt.Errorf("Bad SELinux option z and Z can not be used together")
22
-
23
-// InitLabels returns the process label and file labels to be used within
24
-// the container.  A list of options can be passed into this function to alter
25
-// the labels.  The labels returned will include a random MCS String, that is
26
-// guaranteed to be unique.
27
-func InitLabels(options []string) (string, string, error) {
28
-	if !selinux.SelinuxEnabled() {
29
-		return "", "", nil
30
-	}
31
-	processLabel, mountLabel := selinux.GetLxcContexts()
32
-	if processLabel != "" {
33
-		pcon := selinux.NewContext(processLabel)
34
-		mcon := selinux.NewContext(mountLabel)
35
-		for _, opt := range options {
36
-			if opt == "disable" {
37
-				return "", "", nil
38
-			}
39
-			if i := strings.Index(opt, ":"); i == -1 {
40
-				return "", "", fmt.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type' followed by ':' and a value", opt)
41
-			}
42
-			con := strings.SplitN(opt, ":", 2)
43
-			if !validOptions[con[0]] {
44
-				return "", "", fmt.Errorf("Bad label option %q, valid options 'disable, user, role, level, type'", con[0])
45
-
46
-			}
47
-			pcon[con[0]] = con[1]
48
-			if con[0] == "level" || con[0] == "user" {
49
-				mcon[con[0]] = con[1]
50
-			}
51
-		}
52
-		processLabel = pcon.Get()
53
-		mountLabel = mcon.Get()
54
-	}
55
-	return processLabel, mountLabel, nil
56
-}
57
-
58
-func GetROMountLabel() string {
59
-	return selinux.GetROFileLabel()
60
-}
61
-
62
-// DEPRECATED: The GenLabels function is only to be used during the transition to the official API.
63
-func GenLabels(options string) (string, string, error) {
64
-	return InitLabels(strings.Fields(options))
65
-}
66
-
67
-// FormatMountLabel returns a string to be used by the mount command.
68
-// The format of this string will be used to alter the labeling of the mountpoint.
69
-// The string returned is suitable to be used as the options field of the mount command.
70
-// If you need to have additional mount point options, you can pass them in as
71
-// the first parameter.  Second parameter is the label that you wish to apply
72
-// to all content in the mount point.
73
-func FormatMountLabel(src, mountLabel string) string {
74
-	if mountLabel != "" {
75
-		switch src {
76
-		case "":
77
-			src = fmt.Sprintf("context=%q", mountLabel)
78
-		default:
79
-			src = fmt.Sprintf("%s,context=%q", src, mountLabel)
80
-		}
81
-	}
82
-	return src
83
-}
84
-
85
-// SetProcessLabel takes a process label and tells the kernel to assign the
86
-// label to the next program executed by the current process.
87
-func SetProcessLabel(processLabel string) error {
88
-	if processLabel == "" {
89
-		return nil
90
-	}
91
-	return selinux.Setexeccon(processLabel)
92
-}
93
-
94
-// GetProcessLabel returns the process label that the kernel will assign
95
-// to the next program executed by the current process.  If "" is returned
96
-// this indicates that the default labeling will happen for the process.
97
-func GetProcessLabel() (string, error) {
98
-	return selinux.Getexeccon()
99
-}
100
-
101
-// GetFileLabel returns the label for specified path
102
-func GetFileLabel(path string) (string, error) {
103
-	return selinux.Getfilecon(path)
104
-}
105
-
106
-// SetFileLabel modifies the "path" label to the specified file label
107
-func SetFileLabel(path string, fileLabel string) error {
108
-	if selinux.SelinuxEnabled() && fileLabel != "" {
109
-		return selinux.Setfilecon(path, fileLabel)
110
-	}
111
-	return nil
112
-}
113
-
114
-// SetFileCreateLabel tells the kernel the label for all files to be created
115
-func SetFileCreateLabel(fileLabel string) error {
116
-	if selinux.SelinuxEnabled() {
117
-		return selinux.Setfscreatecon(fileLabel)
118
-	}
119
-	return nil
120
-}
121
-
122
-// Relabel changes the label of path to the filelabel string.
123
-// It changes the MCS label to s0 if shared is true.
124
-// This will allow all containers to share the content.
125
-func Relabel(path string, fileLabel string, shared bool) error {
126
-	if !selinux.SelinuxEnabled() {
127
-		return nil
128
-	}
129
-
130
-	if fileLabel == "" {
131
-		return nil
132
-	}
133
-
134
-	exclude_paths := map[string]bool{"/": true, "/usr": true, "/etc": true}
135
-	if exclude_paths[path] {
136
-		return fmt.Errorf("SELinux relabeling of %s is not allowed", path)
137
-	}
138
-
139
-	if shared {
140
-		c := selinux.NewContext(fileLabel)
141
-		c["level"] = "s0"
142
-		fileLabel = c.Get()
143
-	}
144
-	if err := selinux.Chcon(path, fileLabel, true); err != nil {
145
-		return err
146
-	}
147
-	return nil
148
-}
149
-
150
-// GetPidLabel will return the label of the process running with the specified pid
151
-func GetPidLabel(pid int) (string, error) {
152
-	return selinux.Getpidcon(pid)
153
-}
154
-
155
-// Init initialises the labeling system
156
-func Init() {
157
-	selinux.SelinuxEnabled()
158
-}
159
-
160
-// ReserveLabel will record the fact that the MCS label has already been used.
161
-// This will prevent InitLabels from using the MCS label in a newly created
162
-// container
163
-func ReserveLabel(label string) error {
164
-	selinux.ReserveLabel(label)
165
-	return nil
166
-}
167
-
168
-// UnreserveLabel will remove the reservation of the MCS label.
169
-// This will allow InitLabels to use the MCS label in a newly created
170
-// containers
171
-func UnreserveLabel(label string) error {
172
-	selinux.FreeLxcContexts(label)
173
-	return nil
174
-}
175
-
176
-// DupSecOpt takes an process label and returns security options that
177
-// can be used to set duplicate labels on future container processes
178
-func DupSecOpt(src string) []string {
179
-	return selinux.DupSecOpt(src)
180
-}
181
-
182
-// DisableSecOpt returns a security opt that can disable labeling
183
-// support for future container processes
184
-func DisableSecOpt() []string {
185
-	return selinux.DisableSecOpt()
186
-}
187
-
188
-// Validate checks that the label does not include unexpected options
189
-func Validate(label string) error {
190
-	if strings.Contains(label, "z") && strings.Contains(label, "Z") {
191
-		return ErrIncompatibleLabel
192
-	}
193
-	return nil
194
-}
195
-
196
-// RelabelNeeded checks whether the user requested a relabel
197
-func RelabelNeeded(label string) bool {
198
-	return strings.Contains(label, "z") || strings.Contains(label, "Z")
199
-}
200
-
201
-// IsShared checks that the label includes a "shared" mark
202
-func IsShared(label string) bool {
203
-	return strings.Contains(label, "z")
204
-}
205 1
deleted file mode 100644
... ...
@@ -1,511 +0,0 @@
1
-// +build linux
2
-
3
-package selinux
4
-
5
-import (
6
-	"bufio"
7
-	"crypto/rand"
8
-	"encoding/binary"
9
-	"fmt"
10
-	"io"
11
-	"os"
12
-	"path/filepath"
13
-	"regexp"
14
-	"strconv"
15
-	"strings"
16
-	"sync"
17
-	"syscall"
18
-
19
-	"github.com/opencontainers/runc/libcontainer/system"
20
-)
21
-
22
-const (
23
-	Enforcing        = 1
24
-	Permissive       = 0
25
-	Disabled         = -1
26
-	selinuxDir       = "/etc/selinux/"
27
-	selinuxConfig    = selinuxDir + "config"
28
-	selinuxTypeTag   = "SELINUXTYPE"
29
-	selinuxTag       = "SELINUX"
30
-	selinuxPath      = "/sys/fs/selinux"
31
-	xattrNameSelinux = "security.selinux"
32
-	stRdOnly         = 0x01
33
-)
34
-
35
-var (
36
-	assignRegex           = regexp.MustCompile(`^([^=]+)=(.*)$`)
37
-	mcsList               = make(map[string]bool)
38
-	mcsLock               sync.Mutex
39
-	selinuxfs             = "unknown"
40
-	selinuxEnabled        = false // Stores whether selinux is currently enabled
41
-	selinuxEnabledChecked = false // Stores whether selinux enablement has been checked or established yet
42
-)
43
-
44
-type SELinuxContext map[string]string
45
-
46
-// SetDisabled disables selinux support for the package
47
-func SetDisabled() {
48
-	selinuxEnabled, selinuxEnabledChecked = false, true
49
-}
50
-
51
-// getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs
52
-// filesystem or an empty string if no mountpoint is found.  Selinuxfs is
53
-// a proc-like pseudo-filesystem that exposes the selinux policy API to
54
-// processes.  The existence of an selinuxfs mount is used to determine
55
-// whether selinux is currently enabled or not.
56
-func getSelinuxMountPoint() string {
57
-	if selinuxfs != "unknown" {
58
-		return selinuxfs
59
-	}
60
-	selinuxfs = ""
61
-
62
-	f, err := os.Open("/proc/self/mountinfo")
63
-	if err != nil {
64
-		return selinuxfs
65
-	}
66
-	defer f.Close()
67
-
68
-	scanner := bufio.NewScanner(f)
69
-	for scanner.Scan() {
70
-		txt := scanner.Text()
71
-		// Safe as mountinfo encodes mountpoints with spaces as \040.
72
-		sepIdx := strings.Index(txt, " - ")
73
-		if sepIdx == -1 {
74
-			continue
75
-		}
76
-		if !strings.Contains(txt[sepIdx:], "selinuxfs") {
77
-			continue
78
-		}
79
-		fields := strings.Split(txt, " ")
80
-		if len(fields) < 5 {
81
-			continue
82
-		}
83
-		selinuxfs = fields[4]
84
-		break
85
-	}
86
-
87
-	if selinuxfs != "" {
88
-		var buf syscall.Statfs_t
89
-		syscall.Statfs(selinuxfs, &buf)
90
-		if (buf.Flags & stRdOnly) == 1 {
91
-			selinuxfs = ""
92
-		}
93
-	}
94
-	return selinuxfs
95
-}
96
-
97
-// SelinuxEnabled returns whether selinux is currently enabled.
98
-func SelinuxEnabled() bool {
99
-	if selinuxEnabledChecked {
100
-		return selinuxEnabled
101
-	}
102
-	selinuxEnabledChecked = true
103
-	if fs := getSelinuxMountPoint(); fs != "" {
104
-		if con, _ := Getcon(); con != "kernel" {
105
-			selinuxEnabled = true
106
-		}
107
-	}
108
-	return selinuxEnabled
109
-}
110
-
111
-func readConfig(target string) (value string) {
112
-	var (
113
-		val, key string
114
-		bufin    *bufio.Reader
115
-	)
116
-
117
-	in, err := os.Open(selinuxConfig)
118
-	if err != nil {
119
-		return ""
120
-	}
121
-	defer in.Close()
122
-
123
-	bufin = bufio.NewReader(in)
124
-
125
-	for done := false; !done; {
126
-		var line string
127
-		if line, err = bufin.ReadString('\n'); err != nil {
128
-			if err != io.EOF {
129
-				return ""
130
-			}
131
-			done = true
132
-		}
133
-		line = strings.TrimSpace(line)
134
-		if len(line) == 0 {
135
-			// Skip blank lines
136
-			continue
137
-		}
138
-		if line[0] == ';' || line[0] == '#' {
139
-			// Skip comments
140
-			continue
141
-		}
142
-		if groups := assignRegex.FindStringSubmatch(line); groups != nil {
143
-			key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
144
-			if key == target {
145
-				return strings.Trim(val, "\"")
146
-			}
147
-		}
148
-	}
149
-	return ""
150
-}
151
-
152
-func getSELinuxPolicyRoot() string {
153
-	return selinuxDir + readConfig(selinuxTypeTag)
154
-}
155
-
156
-func readCon(name string) (string, error) {
157
-	var val string
158
-
159
-	in, err := os.Open(name)
160
-	if err != nil {
161
-		return "", err
162
-	}
163
-	defer in.Close()
164
-
165
-	_, err = fmt.Fscanf(in, "%s", &val)
166
-	return val, err
167
-}
168
-
169
-// Setfilecon sets the SELinux label for this path or returns an error.
170
-func Setfilecon(path string, scon string) error {
171
-	return system.Lsetxattr(path, xattrNameSelinux, []byte(scon), 0)
172
-}
173
-
174
-// Getfilecon returns the SELinux label for this path or returns an error.
175
-func Getfilecon(path string) (string, error) {
176
-	con, err := system.Lgetxattr(path, xattrNameSelinux)
177
-	if err != nil {
178
-		return "", err
179
-	}
180
-	// Trim the NUL byte at the end of the byte buffer, if present.
181
-	if len(con) > 0 && con[len(con)-1] == '\x00' {
182
-		con = con[:len(con)-1]
183
-	}
184
-	return string(con), nil
185
-}
186
-
187
-func Setfscreatecon(scon string) error {
188
-	return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid()), scon)
189
-}
190
-
191
-func Getfscreatecon() (string, error) {
192
-	return readCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid()))
193
-}
194
-
195
-// Getcon returns the SELinux label of the current process thread, or an error.
196
-func Getcon() (string, error) {
197
-	return readCon(fmt.Sprintf("/proc/self/task/%d/attr/current", syscall.Gettid()))
198
-}
199
-
200
-// Getpidcon returns the SELinux label of the given pid, or an error.
201
-func Getpidcon(pid int) (string, error) {
202
-	return readCon(fmt.Sprintf("/proc/%d/attr/current", pid))
203
-}
204
-
205
-func Getexeccon() (string, error) {
206
-	return readCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()))
207
-}
208
-
209
-func writeCon(name string, val string) error {
210
-	out, err := os.OpenFile(name, os.O_WRONLY, 0)
211
-	if err != nil {
212
-		return err
213
-	}
214
-	defer out.Close()
215
-
216
-	if val != "" {
217
-		_, err = out.Write([]byte(val))
218
-	} else {
219
-		_, err = out.Write(nil)
220
-	}
221
-	return err
222
-}
223
-
224
-func Setexeccon(scon string) error {
225
-	return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), scon)
226
-}
227
-
228
-func (c SELinuxContext) Get() string {
229
-	return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"])
230
-}
231
-
232
-func NewContext(scon string) SELinuxContext {
233
-	c := make(SELinuxContext)
234
-
235
-	if len(scon) != 0 {
236
-		con := strings.SplitN(scon, ":", 4)
237
-		c["user"] = con[0]
238
-		c["role"] = con[1]
239
-		c["type"] = con[2]
240
-		c["level"] = con[3]
241
-	}
242
-	return c
243
-}
244
-
245
-func ReserveLabel(scon string) {
246
-	if len(scon) != 0 {
247
-		con := strings.SplitN(scon, ":", 4)
248
-		mcsAdd(con[3])
249
-	}
250
-}
251
-
252
-func selinuxEnforcePath() string {
253
-	return fmt.Sprintf("%s/enforce", selinuxPath)
254
-}
255
-
256
-func SelinuxGetEnforce() int {
257
-	var enforce int
258
-
259
-	enforceS, err := readCon(selinuxEnforcePath())
260
-	if err != nil {
261
-		return -1
262
-	}
263
-
264
-	enforce, err = strconv.Atoi(string(enforceS))
265
-	if err != nil {
266
-		return -1
267
-	}
268
-	return enforce
269
-}
270
-
271
-func SelinuxSetEnforce(mode int) error {
272
-	return writeCon(selinuxEnforcePath(), fmt.Sprintf("%d", mode))
273
-}
274
-
275
-func SelinuxGetEnforceMode() int {
276
-	switch readConfig(selinuxTag) {
277
-	case "enforcing":
278
-		return Enforcing
279
-	case "permissive":
280
-		return Permissive
281
-	}
282
-	return Disabled
283
-}
284
-
285
-func mcsAdd(mcs string) error {
286
-	mcsLock.Lock()
287
-	defer mcsLock.Unlock()
288
-	if mcsList[mcs] {
289
-		return fmt.Errorf("MCS Label already exists")
290
-	}
291
-	mcsList[mcs] = true
292
-	return nil
293
-}
294
-
295
-func mcsDelete(mcs string) {
296
-	mcsLock.Lock()
297
-	mcsList[mcs] = false
298
-	mcsLock.Unlock()
299
-}
300
-
301
-func IntToMcs(id int, catRange uint32) string {
302
-	var (
303
-		SETSIZE = int(catRange)
304
-		TIER    = SETSIZE
305
-		ORD     = id
306
-	)
307
-
308
-	if id < 1 || id > 523776 {
309
-		return ""
310
-	}
311
-
312
-	for ORD > TIER {
313
-		ORD = ORD - TIER
314
-		TIER--
315
-	}
316
-	TIER = SETSIZE - TIER
317
-	ORD = ORD + TIER
318
-	return fmt.Sprintf("s0:c%d,c%d", TIER, ORD)
319
-}
320
-
321
-func uniqMcs(catRange uint32) string {
322
-	var (
323
-		n      uint32
324
-		c1, c2 uint32
325
-		mcs    string
326
-	)
327
-
328
-	for {
329
-		binary.Read(rand.Reader, binary.LittleEndian, &n)
330
-		c1 = n % catRange
331
-		binary.Read(rand.Reader, binary.LittleEndian, &n)
332
-		c2 = n % catRange
333
-		if c1 == c2 {
334
-			continue
335
-		} else {
336
-			if c1 > c2 {
337
-				t := c1
338
-				c1 = c2
339
-				c2 = t
340
-			}
341
-		}
342
-		mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2)
343
-		if err := mcsAdd(mcs); err != nil {
344
-			continue
345
-		}
346
-		break
347
-	}
348
-	return mcs
349
-}
350
-
351
-func FreeLxcContexts(scon string) {
352
-	if len(scon) != 0 {
353
-		con := strings.SplitN(scon, ":", 4)
354
-		mcsDelete(con[3])
355
-	}
356
-}
357
-
358
-var roFileLabel string
359
-
360
-func GetROFileLabel() (fileLabel string) {
361
-	return roFileLabel
362
-}
363
-
364
-func GetLxcContexts() (processLabel string, fileLabel string) {
365
-	var (
366
-		val, key string
367
-		bufin    *bufio.Reader
368
-	)
369
-
370
-	if !SelinuxEnabled() {
371
-		return "", ""
372
-	}
373
-	lxcPath := fmt.Sprintf("%s/contexts/lxc_contexts", getSELinuxPolicyRoot())
374
-	in, err := os.Open(lxcPath)
375
-	if err != nil {
376
-		return "", ""
377
-	}
378
-	defer in.Close()
379
-
380
-	bufin = bufio.NewReader(in)
381
-
382
-	for done := false; !done; {
383
-		var line string
384
-		if line, err = bufin.ReadString('\n'); err != nil {
385
-			if err == io.EOF {
386
-				done = true
387
-			} else {
388
-				goto exit
389
-			}
390
-		}
391
-		line = strings.TrimSpace(line)
392
-		if len(line) == 0 {
393
-			// Skip blank lines
394
-			continue
395
-		}
396
-		if line[0] == ';' || line[0] == '#' {
397
-			// Skip comments
398
-			continue
399
-		}
400
-		if groups := assignRegex.FindStringSubmatch(line); groups != nil {
401
-			key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
402
-			if key == "process" {
403
-				processLabel = strings.Trim(val, "\"")
404
-			}
405
-			if key == "file" {
406
-				fileLabel = strings.Trim(val, "\"")
407
-			}
408
-			if key == "ro_file" {
409
-				roFileLabel = strings.Trim(val, "\"")
410
-			}
411
-		}
412
-	}
413
-
414
-	if processLabel == "" || fileLabel == "" {
415
-		return "", ""
416
-	}
417
-
418
-	if roFileLabel == "" {
419
-		roFileLabel = fileLabel
420
-	}
421
-exit:
422
-	//	mcs := IntToMcs(os.Getpid(), 1024)
423
-	mcs := uniqMcs(1024)
424
-	scon := NewContext(processLabel)
425
-	scon["level"] = mcs
426
-	processLabel = scon.Get()
427
-	scon = NewContext(fileLabel)
428
-	scon["level"] = mcs
429
-	fileLabel = scon.Get()
430
-	return processLabel, fileLabel
431
-}
432
-
433
-func SecurityCheckContext(val string) error {
434
-	return writeCon(fmt.Sprintf("%s.context", selinuxPath), val)
435
-}
436
-
437
-func CopyLevel(src, dest string) (string, error) {
438
-	if src == "" {
439
-		return "", nil
440
-	}
441
-	if err := SecurityCheckContext(src); err != nil {
442
-		return "", err
443
-	}
444
-	if err := SecurityCheckContext(dest); err != nil {
445
-		return "", err
446
-	}
447
-	scon := NewContext(src)
448
-	tcon := NewContext(dest)
449
-	mcsDelete(tcon["level"])
450
-	mcsAdd(scon["level"])
451
-	tcon["level"] = scon["level"]
452
-	return tcon.Get(), nil
453
-}
454
-
455
-// Prevent users from relabing system files
456
-func badPrefix(fpath string) error {
457
-	var badprefixes = []string{"/usr"}
458
-
459
-	for _, prefix := range badprefixes {
460
-		if fpath == prefix || strings.HasPrefix(fpath, fmt.Sprintf("%s/", prefix)) {
461
-			return fmt.Errorf("Relabeling content in %s is not allowed.", prefix)
462
-		}
463
-	}
464
-	return nil
465
-}
466
-
467
-// Chcon changes the fpath file object to the SELinux label scon.
468
-// If the fpath is a directory and recurse is true Chcon will walk the
469
-// directory tree setting the label
470
-func Chcon(fpath string, scon string, recurse bool) error {
471
-	if scon == "" {
472
-		return nil
473
-	}
474
-	if err := badPrefix(fpath); err != nil {
475
-		return err
476
-	}
477
-	callback := func(p string, info os.FileInfo, err error) error {
478
-		return Setfilecon(p, scon)
479
-	}
480
-
481
-	if recurse {
482
-		return filepath.Walk(fpath, callback)
483
-	}
484
-
485
-	return Setfilecon(fpath, scon)
486
-}
487
-
488
-// DupSecOpt takes an SELinux process label and returns security options that
489
-// can will set the SELinux Type and Level for future container processes
490
-func DupSecOpt(src string) []string {
491
-	if src == "" {
492
-		return nil
493
-	}
494
-	con := NewContext(src)
495
-	if con["user"] == "" ||
496
-		con["role"] == "" ||
497
-		con["type"] == "" ||
498
-		con["level"] == "" {
499
-		return nil
500
-	}
501
-	return []string{"label=user:" + con["user"],
502
-		"label=role:" + con["role"],
503
-		"label=type:" + con["type"],
504
-		"label=level:" + con["level"]}
505
-}
506
-
507
-// DisableSecOpt returns a security opt that can be used to disabling SELinux
508
-// labeling support for future container processes
509
-func DisableSecOpt() []string {
510
-	return []string{"label=disable"}
511
-}
512 1
new file mode 100644
... ...
@@ -0,0 +1,201 @@
0
+                                 Apache License
1
+                           Version 2.0, January 2004
2
+                        http://www.apache.org/licenses/
3
+
4
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
5
+
6
+   1. Definitions.
7
+
8
+      "License" shall mean the terms and conditions for use, reproduction,
9
+      and distribution as defined by Sections 1 through 9 of this document.
10
+
11
+      "Licensor" shall mean the copyright owner or entity authorized by
12
+      the copyright owner that is granting the License.
13
+
14
+      "Legal Entity" shall mean the union of the acting entity and all
15
+      other entities that control, are controlled by, or are under common
16
+      control with that entity. For the purposes of this definition,
17
+      "control" means (i) the power, direct or indirect, to cause the
18
+      direction or management of such entity, whether by contract or
19
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
20
+      outstanding shares, or (iii) beneficial ownership of such entity.
21
+
22
+      "You" (or "Your") shall mean an individual or Legal Entity
23
+      exercising permissions granted by this License.
24
+
25
+      "Source" form shall mean the preferred form for making modifications,
26
+      including but not limited to software source code, documentation
27
+      source, and configuration files.
28
+
29
+      "Object" form shall mean any form resulting from mechanical
30
+      transformation or translation of a Source form, including but
31
+      not limited to compiled object code, generated documentation,
32
+      and conversions to other media types.
33
+
34
+      "Work" shall mean the work of authorship, whether in Source or
35
+      Object form, made available under the License, as indicated by a
36
+      copyright notice that is included in or attached to the work
37
+      (an example is provided in the Appendix below).
38
+
39
+      "Derivative Works" shall mean any work, whether in Source or Object
40
+      form, that is based on (or derived from) the Work and for which the
41
+      editorial revisions, annotations, elaborations, or other modifications
42
+      represent, as a whole, an original work of authorship. For the purposes
43
+      of this License, Derivative Works shall not include works that remain
44
+      separable from, or merely link (or bind by name) to the interfaces of,
45
+      the Work and Derivative Works thereof.
46
+
47
+      "Contribution" shall mean any work of authorship, including
48
+      the original version of the Work and any modifications or additions
49
+      to that Work or Derivative Works thereof, that is intentionally
50
+      submitted to Licensor for inclusion in the Work by the copyright owner
51
+      or by an individual or Legal Entity authorized to submit on behalf of
52
+      the copyright owner. For the purposes of this definition, "submitted"
53
+      means any form of electronic, verbal, or written communication sent
54
+      to the Licensor or its representatives, including but not limited to
55
+      communication on electronic mailing lists, source code control systems,
56
+      and issue tracking systems that are managed by, or on behalf of, the
57
+      Licensor for the purpose of discussing and improving the Work, but
58
+      excluding communication that is conspicuously marked or otherwise
59
+      designated in writing by the copyright owner as "Not a Contribution."
60
+
61
+      "Contributor" shall mean Licensor and any individual or Legal Entity
62
+      on behalf of whom a Contribution has been received by Licensor and
63
+      subsequently incorporated within the Work.
64
+
65
+   2. Grant of Copyright License. Subject to the terms and conditions of
66
+      this License, each Contributor hereby grants to You a perpetual,
67
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
68
+      copyright license to reproduce, prepare Derivative Works of,
69
+      publicly display, publicly perform, sublicense, and distribute the
70
+      Work and such Derivative Works in Source or Object form.
71
+
72
+   3. Grant of Patent License. Subject to the terms and conditions of
73
+      this License, each Contributor hereby grants to You a perpetual,
74
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
75
+      (except as stated in this section) patent license to make, have made,
76
+      use, offer to sell, sell, import, and otherwise transfer the Work,
77
+      where such license applies only to those patent claims licensable
78
+      by such Contributor that are necessarily infringed by their
79
+      Contribution(s) alone or by combination of their Contribution(s)
80
+      with the Work to which such Contribution(s) was submitted. If You
81
+      institute patent litigation against any entity (including a
82
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
83
+      or a Contribution incorporated within the Work constitutes direct
84
+      or contributory patent infringement, then any patent licenses
85
+      granted to You under this License for that Work shall terminate
86
+      as of the date such litigation is filed.
87
+
88
+   4. Redistribution. You may reproduce and distribute copies of the
89
+      Work or Derivative Works thereof in any medium, with or without
90
+      modifications, and in Source or Object form, provided that You
91
+      meet the following conditions:
92
+
93
+      (a) You must give any other recipients of the Work or
94
+          Derivative Works a copy of this License; and
95
+
96
+      (b) You must cause any modified files to carry prominent notices
97
+          stating that You changed the files; and
98
+
99
+      (c) You must retain, in the Source form of any Derivative Works
100
+          that You distribute, all copyright, patent, trademark, and
101
+          attribution notices from the Source form of the Work,
102
+          excluding those notices that do not pertain to any part of
103
+          the Derivative Works; and
104
+
105
+      (d) If the Work includes a "NOTICE" text file as part of its
106
+          distribution, then any Derivative Works that You distribute must
107
+          include a readable copy of the attribution notices contained
108
+          within such NOTICE file, excluding those notices that do not
109
+          pertain to any part of the Derivative Works, in at least one
110
+          of the following places: within a NOTICE text file distributed
111
+          as part of the Derivative Works; within the Source form or
112
+          documentation, if provided along with the Derivative Works; or,
113
+          within a display generated by the Derivative Works, if and
114
+          wherever such third-party notices normally appear. The contents
115
+          of the NOTICE file are for informational purposes only and
116
+          do not modify the License. You may add Your own attribution
117
+          notices within Derivative Works that You distribute, alongside
118
+          or as an addendum to the NOTICE text from the Work, provided
119
+          that such additional attribution notices cannot be construed
120
+          as modifying the License.
121
+
122
+      You may add Your own copyright statement to Your modifications and
123
+      may provide additional or different license terms and conditions
124
+      for use, reproduction, or distribution of Your modifications, or
125
+      for any such Derivative Works as a whole, provided Your use,
126
+      reproduction, and distribution of the Work otherwise complies with
127
+      the conditions stated in this License.
128
+
129
+   5. Submission of Contributions. Unless You explicitly state otherwise,
130
+      any Contribution intentionally submitted for inclusion in the Work
131
+      by You to the Licensor shall be under the terms and conditions of
132
+      this License, without any additional terms or conditions.
133
+      Notwithstanding the above, nothing herein shall supersede or modify
134
+      the terms of any separate license agreement you may have executed
135
+      with Licensor regarding such Contributions.
136
+
137
+   6. Trademarks. This License does not grant permission to use the trade
138
+      names, trademarks, service marks, or product names of the Licensor,
139
+      except as required for reasonable and customary use in describing the
140
+      origin of the Work and reproducing the content of the NOTICE file.
141
+
142
+   7. Disclaimer of Warranty. Unless required by applicable law or
143
+      agreed to in writing, Licensor provides the Work (and each
144
+      Contributor provides its Contributions) on an "AS IS" BASIS,
145
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
146
+      implied, including, without limitation, any warranties or conditions
147
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
148
+      PARTICULAR PURPOSE. You are solely responsible for determining the
149
+      appropriateness of using or redistributing the Work and assume any
150
+      risks associated with Your exercise of permissions under this License.
151
+
152
+   8. Limitation of Liability. In no event and under no legal theory,
153
+      whether in tort (including negligence), contract, or otherwise,
154
+      unless required by applicable law (such as deliberate and grossly
155
+      negligent acts) or agreed to in writing, shall any Contributor be
156
+      liable to You for damages, including any direct, indirect, special,
157
+      incidental, or consequential damages of any character arising as a
158
+      result of this License or out of the use or inability to use the
159
+      Work (including but not limited to damages for loss of goodwill,
160
+      work stoppage, computer failure or malfunction, or any and all
161
+      other commercial damages or losses), even if such Contributor
162
+      has been advised of the possibility of such damages.
163
+
164
+   9. Accepting Warranty or Additional Liability. While redistributing
165
+      the Work or Derivative Works thereof, You may choose to offer,
166
+      and charge a fee for, acceptance of support, warranty, indemnity,
167
+      or other liability obligations and/or rights consistent with this
168
+      License. However, in accepting such obligations, You may act only
169
+      on Your own behalf and on Your sole responsibility, not on behalf
170
+      of any other Contributor, and only if You agree to indemnify,
171
+      defend, and hold each Contributor harmless for any liability
172
+      incurred by, or claims asserted against, such Contributor by reason
173
+      of your accepting any such warranty or additional liability.
174
+
175
+   END OF TERMS AND CONDITIONS
176
+
177
+   APPENDIX: How to apply the Apache License to your work.
178
+
179
+      To apply the Apache License to your work, attach the following
180
+      boilerplate notice, with the fields enclosed by brackets "{}"
181
+      replaced with your own identifying information. (Don't include
182
+      the brackets!)  The text should be enclosed in the appropriate
183
+      comment syntax for the file format. We also recommend that a
184
+      file or class name and description of purpose be included on the
185
+      same "printed page" as the copyright notice for easier
186
+      identification within third-party archives.
187
+
188
+   Copyright {yyyy} {name of copyright owner}
189
+
190
+   Licensed under the Apache License, Version 2.0 (the "License");
191
+   you may not use this file except in compliance with the License.
192
+   You may obtain a copy of the License at
193
+
194
+       http://www.apache.org/licenses/LICENSE-2.0
195
+
196
+   Unless required by applicable law or agreed to in writing, software
197
+   distributed under the License is distributed on an "AS IS" BASIS,
198
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
199
+   See the License for the specific language governing permissions and
200
+   limitations under the License.
0 201
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+# selinux
1
+
2
+[![GoDoc](https://godoc.org/github.com/opencontainers/selinux?status.svg)](https://godoc.org/github.com/opencontainers/selinux) [![Go Report Card](https://goreportcard.com/badge/github.com/opencontainers/selinux)](https://goreportcard.com/report/github.com/opencontainers/selinux) [![Build Status](https://travis-ci.org/opencontainers/selinux.svg?branch=master)](https://travis-ci.org/opencontainers/selinux)
3
+
4
+Common SELinux package used across the container ecosystem.
5
+
6
+Please see the [godoc](https://godoc.org/github.com/opencontainers/selinux) for more information.
0 7
new file mode 100644
... ...
@@ -0,0 +1,84 @@
0
+// +build !selinux !linux
1
+
2
+package label
3
+
4
+// InitLabels returns the process label and file labels to be used within
5
+// the container.  A list of options can be passed into this function to alter
6
+// the labels.
7
+func InitLabels(options []string) (string, string, error) {
8
+	return "", "", nil
9
+}
10
+
11
+func GetROMountLabel() string {
12
+	return ""
13
+}
14
+
15
+func GenLabels(options string) (string, string, error) {
16
+	return "", "", nil
17
+}
18
+
19
+func FormatMountLabel(src string, mountLabel string) string {
20
+	return src
21
+}
22
+
23
+func SetProcessLabel(processLabel string) error {
24
+	return nil
25
+}
26
+
27
+func GetFileLabel(path string) (string, error) {
28
+	return "", nil
29
+}
30
+
31
+func SetFileLabel(path string, fileLabel string) error {
32
+	return nil
33
+}
34
+
35
+func SetFileCreateLabel(fileLabel string) error {
36
+	return nil
37
+}
38
+
39
+func Relabel(path string, fileLabel string, shared bool) error {
40
+	return nil
41
+}
42
+
43
+func GetPidLabel(pid int) (string, error) {
44
+	return "", nil
45
+}
46
+
47
+func Init() {
48
+}
49
+
50
+func ReserveLabel(label string) error {
51
+	return nil
52
+}
53
+
54
+func ReleaseLabel(label string) error {
55
+	return nil
56
+}
57
+
58
+// DupSecOpt takes a process label and returns security options that
59
+// can be used to set duplicate labels on future container processes
60
+func DupSecOpt(src string) []string {
61
+	return nil
62
+}
63
+
64
+// DisableSecOpt returns a security opt that can disable labeling
65
+// support for future container processes
66
+func DisableSecOpt() []string {
67
+	return nil
68
+}
69
+
70
+// Validate checks that the label does not include unexpected options
71
+func Validate(label string) error {
72
+	return nil
73
+}
74
+
75
+// RelabelNeeded checks whether the user requested a relabel
76
+func RelabelNeeded(label string) bool {
77
+	return false
78
+}
79
+
80
+// IsShared checks that the label includes a "shared" mark
81
+func IsShared(label string) bool {
82
+	return false
83
+}
0 84
new file mode 100644
... ...
@@ -0,0 +1,204 @@
0
+// +build selinux,linux
1
+
2
+package label
3
+
4
+import (
5
+	"fmt"
6
+	"strings"
7
+
8
+	"github.com/opencontainers/selinux/go-selinux"
9
+)
10
+
11
+// Valid Label Options
12
+var validOptions = map[string]bool{
13
+	"disable": true,
14
+	"type":    true,
15
+	"user":    true,
16
+	"role":    true,
17
+	"level":   true,
18
+}
19
+
20
+var ErrIncompatibleLabel = fmt.Errorf("Bad SELinux option z and Z can not be used together")
21
+
22
+// InitLabels returns the process label and file labels to be used within
23
+// the container.  A list of options can be passed into this function to alter
24
+// the labels.  The labels returned will include a random MCS String, that is
25
+// guaranteed to be unique.
26
+func InitLabels(options []string) (string, string, error) {
27
+	if !selinux.GetEnabled() {
28
+		return "", "", nil
29
+	}
30
+	processLabel, mountLabel := selinux.ContainerLabels()
31
+	if processLabel != "" {
32
+		pcon := selinux.NewContext(processLabel)
33
+		mcon := selinux.NewContext(mountLabel)
34
+		for _, opt := range options {
35
+			if opt == "disable" {
36
+				return "", "", nil
37
+			}
38
+			if i := strings.Index(opt, ":"); i == -1 {
39
+				return "", "", fmt.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type' followed by ':' and a value", opt)
40
+			}
41
+			con := strings.SplitN(opt, ":", 2)
42
+			if !validOptions[con[0]] {
43
+				return "", "", fmt.Errorf("Bad label option %q, valid options 'disable, user, role, level, type'", con[0])
44
+
45
+			}
46
+			pcon[con[0]] = con[1]
47
+			if con[0] == "level" || con[0] == "user" {
48
+				mcon[con[0]] = con[1]
49
+			}
50
+		}
51
+		processLabel = pcon.Get()
52
+		mountLabel = mcon.Get()
53
+	}
54
+	return processLabel, mountLabel, nil
55
+}
56
+
57
+func ROMountLabel() string {
58
+	return selinux.ROFileLabel()
59
+}
60
+
61
+// DEPRECATED: The GenLabels function is only to be used during the transition to the official API.
62
+func GenLabels(options string) (string, string, error) {
63
+	return InitLabels(strings.Fields(options))
64
+}
65
+
66
+// FormatMountLabel returns a string to be used by the mount command.
67
+// The format of this string will be used to alter the labeling of the mountpoint.
68
+// The string returned is suitable to be used as the options field of the mount command.
69
+// If you need to have additional mount point options, you can pass them in as
70
+// the first parameter.  Second parameter is the label that you wish to apply
71
+// to all content in the mount point.
72
+func FormatMountLabel(src, mountLabel string) string {
73
+	if mountLabel != "" {
74
+		switch src {
75
+		case "":
76
+			src = fmt.Sprintf("context=%q", mountLabel)
77
+		default:
78
+			src = fmt.Sprintf("%s,context=%q", src, mountLabel)
79
+		}
80
+	}
81
+	return src
82
+}
83
+
84
+// SetProcessLabel takes a process label and tells the kernel to assign the
85
+// label to the next program executed by the current process.
86
+func SetProcessLabel(processLabel string) error {
87
+	if processLabel == "" {
88
+		return nil
89
+	}
90
+	return selinux.SetExecLabel(processLabel)
91
+}
92
+
93
+// ProcessLabel returns the process label that the kernel will assign
94
+// to the next program executed by the current process.  If "" is returned
95
+// this indicates that the default labeling will happen for the process.
96
+func ProcessLabel() (string, error) {
97
+	return selinux.ExecLabel()
98
+}
99
+
100
+// GetFileLabel returns the label for specified path
101
+func FileLabel(path string) (string, error) {
102
+	return selinux.FileLabel(path)
103
+}
104
+
105
+// SetFileLabel modifies the "path" label to the specified file label
106
+func SetFileLabel(path string, fileLabel string) error {
107
+	if selinux.GetEnabled() && fileLabel != "" {
108
+		return selinux.SetFileLabel(path, fileLabel)
109
+	}
110
+	return nil
111
+}
112
+
113
+// SetFileCreateLabel tells the kernel the label for all files to be created
114
+func SetFileCreateLabel(fileLabel string) error {
115
+	if selinux.GetEnabled() {
116
+		return selinux.SetFSCreateLabel(fileLabel)
117
+	}
118
+	return nil
119
+}
120
+
121
+// Relabel changes the label of path to the filelabel string.
122
+// It changes the MCS label to s0 if shared is true.
123
+// This will allow all containers to share the content.
124
+func Relabel(path string, fileLabel string, shared bool) error {
125
+	if !selinux.GetEnabled() {
126
+		return nil
127
+	}
128
+
129
+	if fileLabel == "" {
130
+		return nil
131
+	}
132
+
133
+	exclude_paths := map[string]bool{"/": true, "/usr": true, "/etc": true}
134
+	if exclude_paths[path] {
135
+		return fmt.Errorf("SELinux relabeling of %s is not allowed", path)
136
+	}
137
+
138
+	if shared {
139
+		c := selinux.NewContext(fileLabel)
140
+		c["level"] = "s0"
141
+		fileLabel = c.Get()
142
+	}
143
+	if err := selinux.Chcon(path, fileLabel, true); err != nil {
144
+		return err
145
+	}
146
+	return nil
147
+}
148
+
149
+// PidLabel will return the label of the process running with the specified pid
150
+func PidLabel(pid int) (string, error) {
151
+	return selinux.PidLabel(pid)
152
+}
153
+
154
+// Init initialises the labeling system
155
+func Init() {
156
+	selinux.GetEnabled()
157
+}
158
+
159
+// ReserveLabel will record the fact that the MCS label has already been used.
160
+// This will prevent InitLabels from using the MCS label in a newly created
161
+// container
162
+func ReserveLabel(label string) error {
163
+	selinux.ReserveLabel(label)
164
+	return nil
165
+}
166
+
167
+// ReleaseLabel will remove the reservation of the MCS label.
168
+// This will allow InitLabels to use the MCS label in a newly created
169
+// containers
170
+func ReleaseLabel(label string) error {
171
+	selinux.ReleaseLabel(label)
172
+	return nil
173
+}
174
+
175
+// DupSecOpt takes a process label and returns security options that
176
+// can be used to set duplicate labels on future container processes
177
+func DupSecOpt(src string) []string {
178
+	return selinux.DupSecOpt(src)
179
+}
180
+
181
+// DisableSecOpt returns a security opt that can disable labeling
182
+// support for future container processes
183
+func DisableSecOpt() []string {
184
+	return selinux.DisableSecOpt()
185
+}
186
+
187
+// Validate checks that the label does not include unexpected options
188
+func Validate(label string) error {
189
+	if strings.Contains(label, "z") && strings.Contains(label, "Z") {
190
+		return ErrIncompatibleLabel
191
+	}
192
+	return nil
193
+}
194
+
195
+// RelabelNeeded checks whether the user requested a relabel
196
+func RelabelNeeded(label string) bool {
197
+	return strings.Contains(label, "z") || strings.Contains(label, "Z")
198
+}
199
+
200
+// IsShared checks that the label includes a "shared" mark
201
+func IsShared(label string) bool {
202
+	return strings.Contains(label, "z")
203
+}
0 204
new file mode 100644
... ...
@@ -0,0 +1,593 @@
0
+// +build linux
1
+
2
+package selinux
3
+
4
+import (
5
+	"bufio"
6
+	"crypto/rand"
7
+	"encoding/binary"
8
+	"fmt"
9
+	"io"
10
+	"os"
11
+	"path/filepath"
12
+	"regexp"
13
+	"strconv"
14
+	"strings"
15
+	"sync"
16
+	"syscall"
17
+)
18
+
19
+const (
20
+	// Enforcing constant indicate SELinux is in enforcing mode
21
+	Enforcing = 1
22
+	// Permissive constant to indicate SELinux is in permissive mode
23
+	Permissive = 0
24
+	// Disabled constant to indicate SELinux is disabled
25
+	Disabled         = -1
26
+	selinuxDir       = "/etc/selinux/"
27
+	selinuxConfig    = selinuxDir + "config"
28
+	selinuxTypeTag   = "SELINUXTYPE"
29
+	selinuxTag       = "SELINUX"
30
+	selinuxPath      = "/sys/fs/selinux"
31
+	xattrNameSelinux = "security.selinux"
32
+	stRdOnly         = 0x01
33
+)
34
+
35
+type selinuxState struct {
36
+	enabledSet   bool
37
+	enabled      bool
38
+	selinuxfsSet bool
39
+	selinuxfs    string
40
+	mcsList      map[string]bool
41
+	sync.Mutex
42
+}
43
+
44
+var (
45
+	assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`)
46
+	state       = selinuxState{
47
+		mcsList: make(map[string]bool),
48
+	}
49
+)
50
+
51
+// Context is a representation of the SELinux label broken into 4 parts
52
+type Context map[string]string
53
+
54
+func (s *selinuxState) setEnable(enabled bool) bool {
55
+	s.Lock()
56
+	defer s.Unlock()
57
+	s.enabledSet = true
58
+	s.enabled = enabled
59
+	return s.enabled
60
+}
61
+
62
+func (s *selinuxState) getEnabled() bool {
63
+	s.Lock()
64
+	enabled := s.enabled
65
+	enabledSet := s.enabledSet
66
+	s.Unlock()
67
+	if enabledSet {
68
+		return enabled
69
+	}
70
+
71
+	enabled = false
72
+	if fs := getSelinuxMountPoint(); fs != "" {
73
+		if con, _ := CurrentLabel(); con != "kernel" {
74
+			enabled = true
75
+		}
76
+	}
77
+	return s.setEnable(enabled)
78
+}
79
+
80
+// SetDisabled disables selinux support for the package
81
+func SetDisabled() {
82
+	state.setEnable(false)
83
+}
84
+
85
+func (s *selinuxState) setSELinuxfs(selinuxfs string) string {
86
+	s.Lock()
87
+	defer s.Unlock()
88
+	s.selinuxfsSet = true
89
+	s.selinuxfs = selinuxfs
90
+	return s.selinuxfs
91
+}
92
+
93
+func (s *selinuxState) getSELinuxfs() string {
94
+	s.Lock()
95
+	selinuxfs := s.selinuxfs
96
+	selinuxfsSet := s.selinuxfsSet
97
+	s.Unlock()
98
+	if selinuxfsSet {
99
+		return selinuxfs
100
+	}
101
+
102
+	selinuxfs = ""
103
+	f, err := os.Open("/proc/self/mountinfo")
104
+	if err != nil {
105
+		return selinuxfs
106
+	}
107
+	defer f.Close()
108
+
109
+	scanner := bufio.NewScanner(f)
110
+	for scanner.Scan() {
111
+		txt := scanner.Text()
112
+		// Safe as mountinfo encodes mountpoints with spaces as \040.
113
+		sepIdx := strings.Index(txt, " - ")
114
+		if sepIdx == -1 {
115
+			continue
116
+		}
117
+		if !strings.Contains(txt[sepIdx:], "selinuxfs") {
118
+			continue
119
+		}
120
+		fields := strings.Split(txt, " ")
121
+		if len(fields) < 5 {
122
+			continue
123
+		}
124
+		selinuxfs = fields[4]
125
+		break
126
+	}
127
+
128
+	if selinuxfs != "" {
129
+		var buf syscall.Statfs_t
130
+		syscall.Statfs(selinuxfs, &buf)
131
+		if (buf.Flags & stRdOnly) == 1 {
132
+			selinuxfs = ""
133
+		}
134
+	}
135
+	return s.setSELinuxfs(selinuxfs)
136
+}
137
+
138
+// getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs
139
+// filesystem or an empty string if no mountpoint is found.  Selinuxfs is
140
+// a proc-like pseudo-filesystem that exposes the selinux policy API to
141
+// processes.  The existence of an selinuxfs mount is used to determine
142
+// whether selinux is currently enabled or not.
143
+func getSelinuxMountPoint() string {
144
+	return state.getSELinuxfs()
145
+}
146
+
147
+// GetEnabled returns whether selinux is currently enabled.
148
+func GetEnabled() bool {
149
+	return state.getEnabled()
150
+}
151
+
152
+func readConfig(target string) (value string) {
153
+	var (
154
+		val, key string
155
+		bufin    *bufio.Reader
156
+	)
157
+
158
+	in, err := os.Open(selinuxConfig)
159
+	if err != nil {
160
+		return ""
161
+	}
162
+	defer in.Close()
163
+
164
+	bufin = bufio.NewReader(in)
165
+
166
+	for done := false; !done; {
167
+		var line string
168
+		if line, err = bufin.ReadString('\n'); err != nil {
169
+			if err != io.EOF {
170
+				return ""
171
+			}
172
+			done = true
173
+		}
174
+		line = strings.TrimSpace(line)
175
+		if len(line) == 0 {
176
+			// Skip blank lines
177
+			continue
178
+		}
179
+		if line[0] == ';' || line[0] == '#' {
180
+			// Skip comments
181
+			continue
182
+		}
183
+		if groups := assignRegex.FindStringSubmatch(line); groups != nil {
184
+			key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
185
+			if key == target {
186
+				return strings.Trim(val, "\"")
187
+			}
188
+		}
189
+	}
190
+	return ""
191
+}
192
+
193
+func getSELinuxPolicyRoot() string {
194
+	return selinuxDir + readConfig(selinuxTypeTag)
195
+}
196
+
197
+func readCon(name string) (string, error) {
198
+	var val string
199
+
200
+	in, err := os.Open(name)
201
+	if err != nil {
202
+		return "", err
203
+	}
204
+	defer in.Close()
205
+
206
+	_, err = fmt.Fscanf(in, "%s", &val)
207
+	return val, err
208
+}
209
+
210
+// SetFileLabel sets the SELinux label for this path or returns an error.
211
+func SetFileLabel(path string, label string) error {
212
+	return lsetxattr(path, xattrNameSelinux, []byte(label), 0)
213
+}
214
+
215
+// Filecon returns the SELinux label for this path or returns an error.
216
+func FileLabel(path string) (string, error) {
217
+	label, err := lgetxattr(path, xattrNameSelinux)
218
+	if err != nil {
219
+		return "", err
220
+	}
221
+	// Trim the NUL byte at the end of the byte buffer, if present.
222
+	if len(label) > 0 && label[len(label)-1] == '\x00' {
223
+		label = label[:len(label)-1]
224
+	}
225
+	return string(label), nil
226
+}
227
+
228
+/*
229
+SetFSCreateLabel tells kernel the label to create all file system objects
230
+created by this task. Setting label="" to return to default.
231
+*/
232
+func SetFSCreateLabel(label string) error {
233
+	return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid()), label)
234
+}
235
+
236
+/*
237
+FSCreateLabel returns the default label the kernel which the kernel is using
238
+for file system objects created by this task. "" indicates default.
239
+*/
240
+func FSCreateLabel() (string, error) {
241
+	return readCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid()))
242
+}
243
+
244
+// CurrentLabel returns the SELinux label of the current process thread, or an error.
245
+func CurrentLabel() (string, error) {
246
+	return readCon(fmt.Sprintf("/proc/self/task/%d/attr/current", syscall.Gettid()))
247
+}
248
+
249
+// PidLabel returns the SELinux label of the given pid, or an error.
250
+func PidLabel(pid int) (string, error) {
251
+	return readCon(fmt.Sprintf("/proc/%d/attr/current", pid))
252
+}
253
+
254
+/*
255
+ExecLabel returns the SELinux label that the kernel will use for any programs
256
+that are executed by the current process thread, or an error.
257
+*/
258
+func ExecLabel() (string, error) {
259
+	return readCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()))
260
+}
261
+
262
+func writeCon(name string, val string) error {
263
+	out, err := os.OpenFile(name, os.O_WRONLY, 0)
264
+	if err != nil {
265
+		return err
266
+	}
267
+	defer out.Close()
268
+
269
+	if val != "" {
270
+		_, err = out.Write([]byte(val))
271
+	} else {
272
+		_, err = out.Write(nil)
273
+	}
274
+	return err
275
+}
276
+
277
+/*
278
+SetExecLabel sets the SELinux label that the kernel will use for any programs
279
+that are executed by the current process thread, or an error.
280
+*/
281
+func SetExecLabel(label string) error {
282
+	return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), label)
283
+}
284
+
285
+// Get returns the Context as a string
286
+func (c Context) Get() string {
287
+	return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"])
288
+}
289
+
290
+// NewContext creates a new Context struct from the specified label
291
+func NewContext(label string) Context {
292
+	c := make(Context)
293
+
294
+	if len(label) != 0 {
295
+		con := strings.SplitN(label, ":", 4)
296
+		c["user"] = con[0]
297
+		c["role"] = con[1]
298
+		c["type"] = con[2]
299
+		c["level"] = con[3]
300
+	}
301
+	return c
302
+}
303
+
304
+// ReserveLabel reserves the MLS/MCS level component of the specified label
305
+func ReserveLabel(label string) {
306
+	if len(label) != 0 {
307
+		con := strings.SplitN(label, ":", 4)
308
+		mcsAdd(con[3])
309
+	}
310
+}
311
+
312
+func selinuxEnforcePath() string {
313
+	return fmt.Sprintf("%s/enforce", selinuxPath)
314
+}
315
+
316
+// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
317
+func EnforceMode() int {
318
+	var enforce int
319
+
320
+	enforceS, err := readCon(selinuxEnforcePath())
321
+	if err != nil {
322
+		return -1
323
+	}
324
+
325
+	enforce, err = strconv.Atoi(string(enforceS))
326
+	if err != nil {
327
+		return -1
328
+	}
329
+	return enforce
330
+}
331
+
332
+/*
333
+SetEnforce sets the current SELinux mode Enforcing, Permissive.
334
+Disabled is not valid, since this needs to be set at boot time.
335
+*/
336
+func SetEnforceMode(mode int) error {
337
+	return writeCon(selinuxEnforcePath(), fmt.Sprintf("%d", mode))
338
+}
339
+
340
+/*
341
+DefaultEnforceMode returns the systems default SELinux mode Enforcing,
342
+Permissive or Disabled. Note this is is just the default at boot time.
343
+EnforceMode tells you the systems current mode.
344
+*/
345
+func DefaultEnforceMode() int {
346
+	switch readConfig(selinuxTag) {
347
+	case "enforcing":
348
+		return Enforcing
349
+	case "permissive":
350
+		return Permissive
351
+	}
352
+	return Disabled
353
+}
354
+
355
+func mcsAdd(mcs string) error {
356
+	state.Lock()
357
+	defer state.Unlock()
358
+	if state.mcsList[mcs] {
359
+		return fmt.Errorf("MCS Label already exists")
360
+	}
361
+	state.mcsList[mcs] = true
362
+	return nil
363
+}
364
+
365
+func mcsDelete(mcs string) {
366
+	state.Lock()
367
+	defer state.Unlock()
368
+	state.mcsList[mcs] = false
369
+}
370
+
371
+func intToMcs(id int, catRange uint32) string {
372
+	var (
373
+		SETSIZE = int(catRange)
374
+		TIER    = SETSIZE
375
+		ORD     = id
376
+	)
377
+
378
+	if id < 1 || id > 523776 {
379
+		return ""
380
+	}
381
+
382
+	for ORD > TIER {
383
+		ORD = ORD - TIER
384
+		TIER--
385
+	}
386
+	TIER = SETSIZE - TIER
387
+	ORD = ORD + TIER
388
+	return fmt.Sprintf("s0:c%d,c%d", TIER, ORD)
389
+}
390
+
391
+func uniqMcs(catRange uint32) string {
392
+	var (
393
+		n      uint32
394
+		c1, c2 uint32
395
+		mcs    string
396
+	)
397
+
398
+	for {
399
+		binary.Read(rand.Reader, binary.LittleEndian, &n)
400
+		c1 = n % catRange
401
+		binary.Read(rand.Reader, binary.LittleEndian, &n)
402
+		c2 = n % catRange
403
+		if c1 == c2 {
404
+			continue
405
+		} else {
406
+			if c1 > c2 {
407
+				c1, c2 = c2, c1
408
+			}
409
+		}
410
+		mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2)
411
+		if err := mcsAdd(mcs); err != nil {
412
+			continue
413
+		}
414
+		break
415
+	}
416
+	return mcs
417
+}
418
+
419
+/*
420
+ReleaseLabel will unreserve the MLS/MCS Level field of the specified label.
421
+Allowing it to be used by another process.
422
+*/
423
+func ReleaseLabel(label string) {
424
+	if len(label) != 0 {
425
+		con := strings.SplitN(label, ":", 4)
426
+		mcsDelete(con[3])
427
+	}
428
+}
429
+
430
+var roFileLabel string
431
+
432
+// ROFileLabel returns the specified SELinux readonly file label
433
+func ROFileLabel() (fileLabel string) {
434
+	return roFileLabel
435
+}
436
+
437
+/*
438
+ContainerLabels returns an allocated processLabel and fileLabel to be used for
439
+container labeling by the calling process.
440
+*/
441
+func ContainerLabels() (processLabel string, fileLabel string) {
442
+	var (
443
+		val, key string
444
+		bufin    *bufio.Reader
445
+	)
446
+
447
+	if !GetEnabled() {
448
+		return "", ""
449
+	}
450
+	lxcPath := fmt.Sprintf("%s/contexts/lxc_contexts", getSELinuxPolicyRoot())
451
+	in, err := os.Open(lxcPath)
452
+	if err != nil {
453
+		return "", ""
454
+	}
455
+	defer in.Close()
456
+
457
+	bufin = bufio.NewReader(in)
458
+
459
+	for done := false; !done; {
460
+		var line string
461
+		if line, err = bufin.ReadString('\n'); err != nil {
462
+			if err == io.EOF {
463
+				done = true
464
+			} else {
465
+				goto exit
466
+			}
467
+		}
468
+		line = strings.TrimSpace(line)
469
+		if len(line) == 0 {
470
+			// Skip blank lines
471
+			continue
472
+		}
473
+		if line[0] == ';' || line[0] == '#' {
474
+			// Skip comments
475
+			continue
476
+		}
477
+		if groups := assignRegex.FindStringSubmatch(line); groups != nil {
478
+			key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
479
+			if key == "process" {
480
+				processLabel = strings.Trim(val, "\"")
481
+			}
482
+			if key == "file" {
483
+				fileLabel = strings.Trim(val, "\"")
484
+			}
485
+			if key == "ro_file" {
486
+				roFileLabel = strings.Trim(val, "\"")
487
+			}
488
+		}
489
+	}
490
+
491
+	if processLabel == "" || fileLabel == "" {
492
+		return "", ""
493
+	}
494
+
495
+	if roFileLabel == "" {
496
+		roFileLabel = fileLabel
497
+	}
498
+exit:
499
+	mcs := uniqMcs(1024)
500
+	scon := NewContext(processLabel)
501
+	scon["level"] = mcs
502
+	processLabel = scon.Get()
503
+	scon = NewContext(fileLabel)
504
+	scon["level"] = mcs
505
+	fileLabel = scon.Get()
506
+	return processLabel, fileLabel
507
+}
508
+
509
+// SecurityCheckContext validates that the SELinux label is understood by the kernel
510
+func SecurityCheckContext(val string) error {
511
+	return writeCon(fmt.Sprintf("%s.context", selinuxPath), val)
512
+}
513
+
514
+/*
515
+CopyLevel returns a label with the MLS/MCS level from src label replaces on
516
+the dest label.
517
+*/
518
+func CopyLevel(src, dest string) (string, error) {
519
+	if src == "" {
520
+		return "", nil
521
+	}
522
+	if err := SecurityCheckContext(src); err != nil {
523
+		return "", err
524
+	}
525
+	if err := SecurityCheckContext(dest); err != nil {
526
+		return "", err
527
+	}
528
+	scon := NewContext(src)
529
+	tcon := NewContext(dest)
530
+	mcsDelete(tcon["level"])
531
+	mcsAdd(scon["level"])
532
+	tcon["level"] = scon["level"]
533
+	return tcon.Get(), nil
534
+}
535
+
536
+// Prevent users from relabing system files
537
+func badPrefix(fpath string) error {
538
+	var badprefixes = []string{"/usr"}
539
+
540
+	for _, prefix := range badprefixes {
541
+		if fpath == prefix || strings.HasPrefix(fpath, fmt.Sprintf("%s/", prefix)) {
542
+			return fmt.Errorf("relabeling content in %s is not allowed", prefix)
543
+		}
544
+	}
545
+	return nil
546
+}
547
+
548
+// Chcon changes the fpath file object to the SELinux label label.
549
+// If the fpath is a directory and recurse is true Chcon will walk the
550
+// directory tree setting the label
551
+func Chcon(fpath string, label string, recurse bool) error {
552
+	if label == "" {
553
+		return nil
554
+	}
555
+	if err := badPrefix(fpath); err != nil {
556
+		return err
557
+	}
558
+	callback := func(p string, info os.FileInfo, err error) error {
559
+		return SetFileLabel(p, label)
560
+	}
561
+
562
+	if recurse {
563
+		return filepath.Walk(fpath, callback)
564
+	}
565
+
566
+	return SetFileLabel(fpath, label)
567
+}
568
+
569
+// DupSecOpt takes an SELinux process label and returns security options that
570
+// can will set the SELinux Type and Level for future container processes
571
+func DupSecOpt(src string) []string {
572
+	if src == "" {
573
+		return nil
574
+	}
575
+	con := NewContext(src)
576
+	if con["user"] == "" ||
577
+		con["role"] == "" ||
578
+		con["type"] == "" ||
579
+		con["level"] == "" {
580
+		return nil
581
+	}
582
+	return []string{"user:" + con["user"],
583
+		"role:" + con["role"],
584
+		"type:" + con["type"],
585
+		"level:" + con["level"]}
586
+}
587
+
588
+// DisableSecOpt returns a security opt that can be used to disabling SELinux
589
+// labeling support for future container processes
590
+func DisableSecOpt() []string {
591
+	return []string{"disable"}
592
+}
0 593
new file mode 100644
... ...
@@ -0,0 +1,78 @@
0
+// +build linux
1
+
2
+package selinux
3
+
4
+import (
5
+	"syscall"
6
+	"unsafe"
7
+)
8
+
9
+var _zero uintptr
10
+
11
+// Returns a []byte slice if the xattr is set and nil otherwise
12
+// Requires path and its attribute as arguments
13
+func lgetxattr(path string, attr string) ([]byte, error) {
14
+	var sz int
15
+	pathBytes, err := syscall.BytePtrFromString(path)
16
+	if err != nil {
17
+		return nil, err
18
+	}
19
+	attrBytes, err := syscall.BytePtrFromString(attr)
20
+	if err != nil {
21
+		return nil, err
22
+	}
23
+
24
+	// Start with a 128 length byte array
25
+	sz = 128
26
+	dest := make([]byte, sz)
27
+	destBytes := unsafe.Pointer(&dest[0])
28
+	_sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0)
29
+
30
+	switch {
31
+	case errno == syscall.ENODATA:
32
+		return nil, errno
33
+	case errno == syscall.ENOTSUP:
34
+		return nil, errno
35
+	case errno == syscall.ERANGE:
36
+		// 128 byte array might just not be good enough,
37
+		// A dummy buffer is used ``uintptr(0)`` to get real size
38
+		// of the xattrs on disk
39
+		_sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(unsafe.Pointer(nil)), uintptr(0), 0, 0)
40
+		sz = int(_sz)
41
+		if sz < 0 {
42
+			return nil, errno
43
+		}
44
+		dest = make([]byte, sz)
45
+		destBytes := unsafe.Pointer(&dest[0])
46
+		_sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0)
47
+		if errno != 0 {
48
+			return nil, errno
49
+		}
50
+	case errno != 0:
51
+		return nil, errno
52
+	}
53
+	sz = int(_sz)
54
+	return dest[:sz], nil
55
+}
56
+
57
+func lsetxattr(path string, attr string, data []byte, flags int) error {
58
+	pathBytes, err := syscall.BytePtrFromString(path)
59
+	if err != nil {
60
+		return err
61
+	}
62
+	attrBytes, err := syscall.BytePtrFromString(attr)
63
+	if err != nil {
64
+		return err
65
+	}
66
+	var dataBytes unsafe.Pointer
67
+	if len(data) > 0 {
68
+		dataBytes = unsafe.Pointer(&data[0])
69
+	} else {
70
+		dataBytes = unsafe.Pointer(&_zero)
71
+	}
72
+	_, _, errno := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(dataBytes), uintptr(len(data)), uintptr(flags), 0)
73
+	if errno != 0 {
74
+		return errno
75
+	}
76
+	return nil
77
+}
... ...
@@ -10,7 +10,7 @@ import (
10 10
 	mounttypes "github.com/docker/docker/api/types/mount"
11 11
 	"github.com/docker/docker/pkg/idtools"
12 12
 	"github.com/docker/docker/pkg/stringid"
13
-	"github.com/opencontainers/runc/libcontainer/label"
13
+	"github.com/opencontainers/selinux/go-selinux/label"
14 14
 	"github.com/pkg/errors"
15 15
 )
16 16