Merge pull request #12572 from jfrazelle/selinux-labels-carry

Modify volume mounts SELinux labels on the fly based on :Z or :z
This commit is contained in:
Arnaud Porterie
2015-05-27 14:46:16 -07:00
9 changed files with 126 additions and 46 deletions
+3
View File
@@ -1025,6 +1025,7 @@ func copyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error)
func (container *Container) networkMounts() []execdriver.Mount {
var mounts []execdriver.Mount
if container.ResolvConfPath != "" {
label.SetFileLabel(container.ResolvConfPath, container.MountLabel)
mounts = append(mounts, execdriver.Mount{
Source: container.ResolvConfPath,
Destination: "/etc/resolv.conf",
@@ -1033,6 +1034,7 @@ func (container *Container) networkMounts() []execdriver.Mount {
})
}
if container.HostnamePath != "" {
label.SetFileLabel(container.HostnamePath, container.MountLabel)
mounts = append(mounts, execdriver.Mount{
Source: container.HostnamePath,
Destination: "/etc/hostname",
@@ -1041,6 +1043,7 @@ func (container *Container) networkMounts() []execdriver.Mount {
})
}
if container.HostsPath != "" {
label.SetFileLabel(container.HostsPath, container.MountLabel)
mounts = append(mounts, execdriver.Mount{
Source: container.HostsPath,
Destination: "/etc/hosts",
+3
View File
@@ -129,6 +129,9 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos
if err != nil {
return nil, nil, err
}
if err := label.Relabel(v.Path(), container.MountLabel, "z"); err != nil {
return nil, nil, err
}
if err := container.copyImagePathContent(v, destination); err != nil {
return nil, nil, err
+9 -4
View File
@@ -1221,16 +1221,21 @@ func (daemon *Daemon) verifyHostConfig(hostConfig *runconfig.HostConfig) ([]stri
}
func (daemon *Daemon) setHostConfig(container *Container, hostConfig *runconfig.HostConfig) error {
container.Lock()
if err := parseSecurityOpt(container, hostConfig); err != nil {
container.Unlock()
return err
}
container.Unlock()
// Do not lock while creating volumes since this could be calling out to external plugins
// Don't want to block other actions, like `docker ps` because we're waiting on an external plugin
if err := daemon.registerMountPoints(container, hostConfig); err != nil {
return err
}
container.Lock()
defer container.Unlock()
if err := parseSecurityOpt(container, hostConfig); err != nil {
return err
}
// Register any links from the host config before starting the container
if err := daemon.RegisterLinks(container, hostConfig); err != nil {
return err
+42 -11
View File
@@ -11,6 +11,7 @@ import (
"github.com/docker/docker/pkg/chrootarchive"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/volume"
"github.com/docker/libcontainer/label"
)
type mountPoint struct {
@@ -20,6 +21,7 @@ type mountPoint struct {
RW bool
Volume volume.Volume `json:"-"`
Source string
Relabel string
}
func (m *mountPoint) Setup() (string, error) {
@@ -50,7 +52,7 @@ func (m *mountPoint) Path() string {
return m.Source
}
func parseBindMount(spec string, config *runconfig.Config) (*mountPoint, error) {
func parseBindMount(spec string, mountLabel string, config *runconfig.Config) (*mountPoint, error) {
bind := &mountPoint{
RW: true,
}
@@ -61,10 +63,13 @@ func parseBindMount(spec string, config *runconfig.Config) (*mountPoint, error)
bind.Destination = arr[1]
case 3:
bind.Destination = arr[1]
if !validMountMode(arr[2]) {
return nil, fmt.Errorf("invalid mode for volumes-from: %s", arr[2])
mode := arr[2]
if !validMountMode(mode) {
return nil, fmt.Errorf("invalid mode for volumes-from: %s", mode)
}
bind.RW = arr[2] == "rw"
bind.RW = rwModes[mode]
// Relabel will apply a SELinux label, if necessary
bind.Relabel = mode
default:
return nil, fmt.Errorf("Invalid volume specification: %s", spec)
}
@@ -106,12 +111,28 @@ func parseVolumesFrom(spec string) (string, string, error) {
return id, mode, nil
}
// read-write modes
var rwModes = map[string]bool{
"rw": true,
"rw,Z": true,
"rw,z": true,
"z,rw": true,
"Z,rw": true,
"Z": true,
"z": true,
}
// read-only modes
var roModes = map[string]bool{
"ro": true,
"ro,Z": true,
"ro,z": true,
"z,ro": true,
"Z,ro": true,
}
func validMountMode(mode string) bool {
validModes := map[string]bool{
"rw": true,
"ro": true,
}
return validModes[mode]
return roModes[mode] || rwModes[mode]
}
func copyExistingContents(source, destination string) error {
@@ -180,7 +201,7 @@ func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runc
// 3. Read bind mounts
for _, b := range hostConfig.Binds {
// #10618
bind, err := parseBindMount(b, container.Config)
bind, err := parseBindMount(b, container.MountLabel, container.Config)
if err != nil {
return err
}
@@ -190,18 +211,29 @@ func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runc
}
if len(bind.Name) > 0 && len(bind.Driver) > 0 {
// create the volume
v, err := createVolume(bind.Name, bind.Driver)
if err != nil {
return err
}
bind.Volume = v
bind.Source = v.Path()
// Since this is just a named volume and not a typical bind, set to shared mode `z`
if bind.Relabel == "" {
bind.Relabel = "z"
}
}
if err := label.Relabel(bind.Source, container.MountLabel, bind.Relabel); err != nil {
return err
}
binds[bind.Destination] = true
mountPoints[bind.Destination] = bind
}
container.Lock()
container.MountPoints = mountPoints
container.Unlock()
return nil
}
@@ -250,7 +282,6 @@ func (daemon *Daemon) verifyOldVolumesInfo(container *Container) error {
func createVolume(name, driverName string) (volume.Volume, error) {
vd, err := getVolumeDriver(driverName)
if err != nil {
return nil, err
}
+18 -17
View File
@@ -34,28 +34,29 @@ func TestGetVolumeDriver(t *testing.T) {
func TestParseBindMount(t *testing.T) {
cases := []struct {
bind string
driver string
expDest string
expSource string
expName string
expDriver string
expRW bool
fail bool
bind string
driver string
expDest string
expSource string
expName string
expDriver string
mountLabel string
expRW bool
fail bool
}{
{"/tmp:/tmp", "", "/tmp", "/tmp", "", "", true, false},
{"/tmp:/tmp:ro", "", "/tmp", "/tmp", "", "", false, false},
{"/tmp:/tmp:rw", "", "/tmp", "/tmp", "", "", true, false},
{"/tmp:/tmp:foo", "", "/tmp", "/tmp", "", "", false, true},
{"name:/tmp", "", "/tmp", "", "name", "local", true, false},
{"name:/tmp", "external", "/tmp", "", "name", "external", true, false},
{"name:/tmp:ro", "local", "/tmp", "", "name", "local", false, false},
{"local/name:/tmp:rw", "", "/tmp", "", "local/name", "local", true, false},
{"/tmp:/tmp", "", "/tmp", "/tmp", "", "", "", true, false},
{"/tmp:/tmp:ro", "", "/tmp", "/tmp", "", "", "", false, false},
{"/tmp:/tmp:rw", "", "/tmp", "/tmp", "", "", "", true, false},
{"/tmp:/tmp:foo", "", "/tmp", "/tmp", "", "", "", false, true},
{"name:/tmp", "", "/tmp", "", "name", "local", "", true, false},
{"name:/tmp", "external", "/tmp", "", "name", "external", "", true, false},
{"name:/tmp:ro", "local", "/tmp", "", "name", "local", "", false, false},
{"local/name:/tmp:rw", "", "/tmp", "", "local/name", "local", "", true, false},
}
for _, c := range cases {
conf := &runconfig.Config{VolumeDriver: c.driver}
m, err := parseBindMount(c.bind, conf)
m, err := parseBindMount(c.bind, c.mountLabel, conf)
if c.fail {
if err == nil {
t.Fatalf("Expected error, was nil, for spec %s\n", c.bind)
+14 -13
View File
@@ -37,24 +37,25 @@ func TestGetVolumeDefaultDriver(t *testing.T) {
func TestParseBindMount(t *testing.T) {
cases := []struct {
bind string
expDest string
expSource string
expName string
expRW bool
fail bool
bind string
expDest string
expSource string
expName string
mountLabel string
expRW bool
fail bool
}{
{"/tmp:/tmp", "/tmp", "/tmp", "", true, false},
{"/tmp:/tmp:ro", "/tmp", "/tmp", "", false, false},
{"/tmp:/tmp:rw", "/tmp", "/tmp", "", true, false},
{"/tmp:/tmp:foo", "/tmp", "/tmp", "", false, true},
{"name:/tmp", "", "", "", false, true},
{"local/name:/tmp:rw", "", "", "", true, true},
{"/tmp:/tmp", "/tmp", "/tmp", "", "", true, false},
{"/tmp:/tmp:ro", "/tmp", "/tmp", "", "", false, false},
{"/tmp:/tmp:rw", "/tmp", "/tmp", "", "", true, false},
{"/tmp:/tmp:foo", "/tmp", "/tmp", "", "", false, true},
{"name:/tmp", "", "", "", "", false, true},
{"local/name:/tmp:rw", "", "", "", "", true, true},
}
for _, c := range cases {
conf := &runconfig.Config{}
m, err := parseBindMount(c.bind, conf)
m, err := parseBindMount(c.bind, c.mountLabel, conf)
if c.fail {
if err == nil {
t.Fatalf("Expected error, was nil, for spec %s\n", c.bind)