| package nsenter |
| |
| import ( |
| "bytes" |
| "encoding/json" |
| "fmt" |
| "io" |
| "io/ioutil" |
| "os" |
| "os/exec" |
| "strings" |
| "testing" |
| |
| "github.com/opencontainers/runc/libcontainer" |
| "github.com/vishvananda/netlink/nl" |
| |
| "golang.org/x/sys/unix" |
| ) |
| |
| type pid struct { |
| Pid int `json:"Pid"` |
| } |
| |
| func TestNsenterValidPaths(t *testing.T) { |
| args := []string{"nsenter-exec"} |
| parent, child, err := newPipe() |
| if err != nil { |
| t.Fatalf("failed to create pipe %v", err) |
| } |
| |
| namespaces := []string{ |
| // join pid ns of the current process |
| fmt.Sprintf("pid:/proc/%d/ns/pid", os.Getpid()), |
| } |
| cmd := &exec.Cmd{ |
| Path: os.Args[0], |
| Args: args, |
| ExtraFiles: []*os.File{child}, |
| Env: []string{"_LIBCONTAINER_INITPIPE=3"}, |
| Stdout: os.Stdout, |
| Stderr: os.Stderr, |
| } |
| |
| if err := cmd.Start(); err != nil { |
| t.Fatalf("nsenter failed to start %v", err) |
| } |
| // write cloneFlags |
| r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0) |
| r.AddData(&libcontainer.Int32msg{ |
| Type: libcontainer.CloneFlagsAttr, |
| Value: uint32(unix.CLONE_NEWNET), |
| }) |
| r.AddData(&libcontainer.Bytemsg{ |
| Type: libcontainer.NsPathsAttr, |
| Value: []byte(strings.Join(namespaces, ",")), |
| }) |
| if _, err := io.Copy(parent, bytes.NewReader(r.Serialize())); err != nil { |
| t.Fatal(err) |
| } |
| |
| decoder := json.NewDecoder(parent) |
| var pid *pid |
| |
| if err := cmd.Wait(); err != nil { |
| t.Fatalf("nsenter exits with a non-zero exit status") |
| } |
| if err := decoder.Decode(&pid); err != nil { |
| dir, _ := ioutil.ReadDir(fmt.Sprintf("/proc/%d/ns", os.Getpid())) |
| for _, d := range dir { |
| t.Log(d.Name()) |
| } |
| t.Fatalf("%v", err) |
| } |
| |
| p, err := os.FindProcess(pid.Pid) |
| if err != nil { |
| t.Fatalf("%v", err) |
| } |
| p.Wait() |
| } |
| |
| func TestNsenterInvalidPaths(t *testing.T) { |
| args := []string{"nsenter-exec"} |
| parent, child, err := newPipe() |
| if err != nil { |
| t.Fatalf("failed to create pipe %v", err) |
| } |
| |
| namespaces := []string{ |
| // join pid ns of the current process |
| fmt.Sprintf("pid:/proc/%d/ns/pid", -1), |
| } |
| cmd := &exec.Cmd{ |
| Path: os.Args[0], |
| Args: args, |
| ExtraFiles: []*os.File{child}, |
| Env: []string{"_LIBCONTAINER_INITPIPE=3"}, |
| } |
| |
| if err := cmd.Start(); err != nil { |
| t.Fatal(err) |
| } |
| // write cloneFlags |
| r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0) |
| r.AddData(&libcontainer.Int32msg{ |
| Type: libcontainer.CloneFlagsAttr, |
| Value: uint32(unix.CLONE_NEWNET), |
| }) |
| r.AddData(&libcontainer.Bytemsg{ |
| Type: libcontainer.NsPathsAttr, |
| Value: []byte(strings.Join(namespaces, ",")), |
| }) |
| if _, err := io.Copy(parent, bytes.NewReader(r.Serialize())); err != nil { |
| t.Fatal(err) |
| } |
| |
| if err := cmd.Wait(); err == nil { |
| t.Fatalf("nsenter exits with a zero exit status") |
| } |
| } |
| |
| func TestNsenterIncorrectPathType(t *testing.T) { |
| args := []string{"nsenter-exec"} |
| parent, child, err := newPipe() |
| if err != nil { |
| t.Fatalf("failed to create pipe %v", err) |
| } |
| |
| namespaces := []string{ |
| // join pid ns of the current process |
| fmt.Sprintf("net:/proc/%d/ns/pid", os.Getpid()), |
| } |
| cmd := &exec.Cmd{ |
| Path: os.Args[0], |
| Args: args, |
| ExtraFiles: []*os.File{child}, |
| Env: []string{"_LIBCONTAINER_INITPIPE=3"}, |
| } |
| |
| if err := cmd.Start(); err != nil { |
| t.Fatal(err) |
| } |
| // write cloneFlags |
| r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0) |
| r.AddData(&libcontainer.Int32msg{ |
| Type: libcontainer.CloneFlagsAttr, |
| Value: uint32(unix.CLONE_NEWNET), |
| }) |
| r.AddData(&libcontainer.Bytemsg{ |
| Type: libcontainer.NsPathsAttr, |
| Value: []byte(strings.Join(namespaces, ",")), |
| }) |
| if _, err := io.Copy(parent, bytes.NewReader(r.Serialize())); err != nil { |
| t.Fatal(err) |
| } |
| |
| if err := cmd.Wait(); err == nil { |
| t.Fatalf("nsenter exits with a zero exit status") |
| } |
| } |
| |
| func init() { |
| if strings.HasPrefix(os.Args[0], "nsenter-") { |
| os.Exit(0) |
| } |
| return |
| } |
| |
| func newPipe() (parent *os.File, child *os.File, err error) { |
| fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0) |
| if err != nil { |
| return nil, nil, err |
| } |
| return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil |
| } |