diff --git a/kola/tests/coretest/core.go b/kola/tests/coretest/core.go index f86cd5eca..189b99b6d 100644 --- a/kola/tests/coretest/core.go +++ b/kola/tests/coretest/core.go @@ -191,7 +191,19 @@ func TestNTPDate() error { // This execs gdbus, because we need to change uses to test perms. func TestDbusPerms() error { + // With the current SELinux policy the core user does not have access + // to the systemd RestartUnit method. Set SELinux to permisive + // mode so this test can run. c := exec.Command( + "sudo", "setenforce", "0", + ) + out, err := c.CombinedOutput() + + if err != nil { + return fmt.Errorf("setenforce faied: Err:%s\n Out:%s", err, string(out)) + } + + c = exec.Command( "sudo", "-u", "core", "gdbus", "call", "--system", "--dest", "org.freedesktop.systemd1", @@ -199,12 +211,11 @@ func TestDbusPerms() error { "--method", "org.freedesktop.systemd1.Manager.RestartUnit", "ntpd.service", "replace", ) - out, err := c.CombinedOutput() + out, err = c.CombinedOutput() if err != nil { - if !strings.Contains(string(out), "org.freedesktop.DBus.Error.AccessDenied") && - !strings.Contains(string(out), "org.freedesktop.DBus.Error.InteractiveAuthorizationRequired") { - return err + if !strings.Contains(string(out), "org.freedesktop.DBus.Error.InteractiveAuthorizationRequired") { + return fmt.Errorf("RestartUnit failed: Err:%s\n Out:%s", err, string(out)) } } else { return fmt.Errorf("We were able to call RestartUnit as a non-root user.") @@ -221,7 +232,7 @@ func TestDbusPerms() error { out, err = c.CombinedOutput() if err != nil { - return fmt.Errorf("Err:%s\n Out:%v", err, out) + return fmt.Errorf("GetAll failed: Err:%s\n Out:%s", err, string(out)) } return nil } diff --git a/kola/tests/docker/docker.go b/kola/tests/docker/docker.go index 6200d37cc..d37b794a2 100644 --- a/kola/tests/docker/docker.go +++ b/kola/tests/docker/docker.go @@ -220,6 +220,8 @@ func dockerBaseTests(c cluster.TestCluster) { c.Run("resources", dockerResources) c.Run("networks-reliably", dockerNetworksReliably) c.Run("user-no-caps", dockerUserNoCaps) + c.Run("sel-restricted", dockerSelRestricted) + c.Run("sel-readonly", dockerSelReadOnly) } // using a simple container, exercise various docker options that set resource @@ -381,7 +383,13 @@ func dockerUserns(c cluster.TestCluster) { genDockerContainer(c, m, "userns-test", []string{"echo", "sleep"}) - c.MustSSH(m, `sudo setenforce 1`) + // A docker bug causes the docker daemon to fail in creating a container + // when the '--userns-remap' option is used and SELinux is enforcing. + // Set SELinux to permisive mode so this test can run. + // See: https://github.com/opencontainers/runc/pull/1562 (nsenter: + // improve namespace creation and SELinux IPC handling). + c.MustSSH(m, "sudo setenforce 0") + output := c.MustSSH(m, `docker run userns-test echo fj.fj`) if !bytes.Equal(output, []byte("fj.fj")) { c.Fatalf("expected fj.fj, got %s", string(output)) @@ -435,6 +443,11 @@ func dockerUserNoCaps(c cluster.TestCluster) { genDockerContainer(c, m, "captest", []string{"capsh", "sh", "grep", "cat", "ls"}) + // With the current SELinux policy the docker daemon does not have + // access to the '/root' directory. Set SELinux to permisive mode + // so this test can run. + c.MustSSH(m, "sudo setenforce 0") + output := c.MustSSH(m, `docker run --user 1000:1000 \ -v /root:/root \ captest sh -c \ @@ -460,6 +473,43 @@ func dockerUserNoCaps(c cluster.TestCluster) { } } +// Ensure that when SELinux is enforcing the docker daemon cannot create a +// container instance with a mount to a restricted directory. +func dockerSelRestricted(c cluster.TestCluster) { + m := c.Machines()[0] + + genDockerContainer(c, m, "permtest", []string{"ls"}) + + _, stderr, _ := m.SSH("sudo setenforce 1 && docker run -v /root:/root permtest sh -c 'ls -dlZ /root'") + + if !(strings.Contains(string(stderr), "OCI runtime create failed") && + strings.Contains(string(stderr), "permission denied")) { + c.Fatalf("failed creating contanier with restricted directory: %q", string(stderr)) + } +} + +// Ensure that when SELinux is enforcing the docker daemon cannot create a +// container instance with a read-write mount to a read-only directory. +func dockerSelReadOnly(c cluster.TestCluster) { + m := c.Machines()[0] + + genDockerContainer(c, m, "writetest", []string{"echo"}) + + // Test ro mount as baseline, should succeed. + _, stderr, err := m.SSH("sudo setenforce 1 && docker run -v /etc/passwd:/etc/passwd:ro writetest sh -c 'echo badguy >> /etc/passwd'") + if err != nil { + c.Fatalf("failed creating contanier with read-only mount: %s, %v", stderr, err) + } + + // Now test rw mount. + _, stderr, _ = m.SSH("sudo setenforce 1 && docker run -v /etc/passwd:/etc/passwd:rw writetest sh -c 'echo badguy >> /etc/passwd'") + + if !(strings.Contains(string(stderr), "OCI runtime create failed") && + strings.Contains(string(stderr), "permission denied")) { + c.Fatalf("failed creating contanier with read-only directory: %q", string(stderr)) + } +} + // dockerContainerdRestart ensures containerd will restart if it dies. It tests that containerd is running, // kills it, the tests that it came back up. func dockerContainerdRestart(c cluster.TestCluster) { diff --git a/kola/tests/misc/selinux.go b/kola/tests/misc/selinux.go index 29c6d0f9e..93ec46c5e 100644 --- a/kola/tests/misc/selinux.go +++ b/kola/tests/misc/selinux.go @@ -17,9 +17,16 @@ package misc import ( "github.com/coreos/mantle/kola/cluster" "github.com/coreos/mantle/kola/register" + "strings" ) func init() { + register.Register(®ister.Test{ + Run: SelinuxLogCheck, + ClusterSize: 1, + Name: "coreos.selinux.logcheck", + Flags: []register.Flag{register.NoEnableSelinux}, + }) register.Register(®ister.Test{ Run: SelinuxEnforce, ClusterSize: 1, @@ -28,6 +35,25 @@ func init() { }) } +// SelinuxLogCheck checks that no audit AVC messages appear in boot logs. +func SelinuxLogCheck(c cluster.TestCluster) { + m := c.Machines()[0] + + cmd := "sudo journalctl -b --no-pager | egrep 'AVC avc'" + stdout, stderr, err := m.SSH(cmd) + + if err == nil { + c.Fatalf("Found audit AVC messages in boot logs: \n%v", string(stdout)) + } + + if err.Error() == "Process exited with status 1" && + strings.TrimSpace(string(stderr)) == "" { + return // OK, nothing found. + } + + c.Fatalf("cmd '%v' failed: %v: %v.\n", string(cmd), err, string(stderr)) +} + // SelinuxEnforce checks that some basic things work after `setenforce 1` func SelinuxEnforce(c cluster.TestCluster) { m := c.Machines()[0]