Skip to content
This repository has been archived by the owner on Apr 21, 2021. It is now read-only.

Commit

Permalink
validation: add a new test for NSPathMatchTypeError
Browse files Browse the repository at this point in the history
`checkNSPathMatchType` checks if the container returns an error when
deliberately setting a wrong namespace type. Doing that, it is possible
to verify `NSPathMatchTypeError`, i.e. `The runtime MUST generate an
error if path is not associated with a namespace of type "type"`.

See also opencontainers#572

Signed-off-by: Dongsu Park <dongsu@kinvolk.io>
  • Loading branch information
Dongsu Park committed May 29, 2018
1 parent 9b65419 commit 0f52f9a
Showing 1 changed file with 120 additions and 0 deletions.
120 changes: 120 additions & 0 deletions validation/linux_ns_path_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package main

import (
"fmt"
"os/exec"
"runtime"
"syscall"

"github.com/mndrix/tap-go"
rspec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/specerror"
"github.com/opencontainers/runtime-tools/validation/util"
)

func getRuntimeToolsNamespace(ns string) string {
// Deal with exceptional cases of "net" and "mnt", because those strings
// cannot be recognized by mapStrToNamespace(), which actually expects
// "network" and "mount" respectively.
switch ns {
case "net":
return "network"
case "mnt":
return "mount"
}

// In other cases, return just the original string
return ns
}

func checkNSPathMatchType(t *tap.T, ns, wrongNs string) error {
// Deliberately set ns path with a wrong namespace, to check if the runtime
// returns error when running with the wrong namespace path.
unshareNsPath := fmt.Sprintf("/proc/self/ns/%s", wrongNs)

g, err := util.GetDefaultGenerator()
if err != nil {
return fmt.Errorf("cannot get default config from generator: %v", err)
}

rtns := getRuntimeToolsNamespace(ns)
g.AddOrReplaceLinuxNamespace(rtns, unshareNsPath)

err = util.RuntimeOutsideValidate(g, nil)

t.Ok(err != nil, fmt.Sprintf("got error when setting a wrong namespace path %q with type %s", unshareNsPath, rtns))
if err == nil {
rfcError, errRfc := specerror.NewRFCError(specerror.NSPathMatchTypeError,
fmt.Errorf("got no error when setting a wrong namespace path %q with type %s", unshareNsPath, rtns),
rspec.Version)
if errRfc != nil {
return fmt.Errorf("cannot get new rfcError: %v", errRfc)
}
diagnostic := map[string]string{
"expected": fmt.Sprintf("err == %v", err),
"actual": "err == nil",
"namespace type": rtns,
"level": rfcError.Level.String(),
"reference": rfcError.Reference,
}
t.YAML(diagnostic)

return fmt.Errorf("cannot validate path with wrong type")
}

return nil
}

func testNSPathMatchType(t *tap.T, ns, unshareOpt, wrongNs string) error {
// Calling 'unshare' (part of util-linux) is easier than doing it from
// Golang: mnt namespaces cannot be unshared from multithreaded
// programs.
cmd := exec.Command("unshare", unshareOpt, "--fork", "sleep", "10000")
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
err := cmd.Start()
if err != nil {
return fmt.Errorf("cannot run unshare: %s", err)
}
defer func() {
if cmd.Process != nil {
cmd.Process.Kill()
}
cmd.Wait()
syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
}()
if cmd.Process == nil {
return fmt.Errorf("process failed to start")
}

return checkNSPathMatchType(t, ns, wrongNs)
}

func main() {
t := tap.New()
t.Header(0)

cases := []struct {
name string
unshareOpt string
wrongname string
}{
{"cgroup", "--cgroup", "ipc"},
{"ipc", "--ipc", "mnt"},
{"mnt", "--mount", "net"},
{"net", "--net", "pid"},
{"pid", "--pid", "user"},
{"user", "--user", "uts"},
{"uts", "--uts", "cgroup"},
}

for _, c := range cases {
if "linux" != runtime.GOOS {
t.Skip(1, fmt.Sprintf("linux-specific namespace test: %s", c))
}

err := testNSPathMatchType(t, c.name, c.unshareOpt, c.wrongname)
t.Ok(err == nil, fmt.Sprintf("namespace path matches with type %s", c.name))
}

t.AutoPlan()
}

0 comments on commit 0f52f9a

Please sign in to comment.