Switch to using opencontainers/selinux for selinux bindings
Vincent Demeester authored on 2017/04/30 02:05:32... | ... |
@@ -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() { |
... | ... |
@@ -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 |
... | ... |
@@ -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 |
|