// CreateNewNamespace creates a new namespace and binds it's fd to the specified path func CreateNewNamespace(namespace libcontainer.Namespace, bindTo string) error { var ( flag = namespaceMap[namespace] name = namespaceFileMap[namespace] nspath = filepath.Join("/proc/self/ns", name) ) // TODO: perform validation on name and flag pid, err := fork() if err != nil { return err } if pid == 0 { if err := unshare(flag); err != nil { writeError("unshare %s", err) } if err := mount(nspath, bindTo, "none", syscall.MS_BIND, ""); err != nil { writeError("bind mount %s", err) } os.Exit(0) } exit, err := utils.WaitOnPid(pid) if err != nil { return err } if exit != 0 { return fmt.Errorf("exit status %d", exit) } return err }
func execinAction(container *libcontainer.Container, cmd *libcontainer.Command, fds []uintptr) error { for _, fd := range fds { if fd > 0 { if err := JoinExistingNamespace(fd, ""); err != nil { for _, fd := range fds { syscall.Close(int(fd)) } return err } } syscall.Close(int(fd)) } if container.Namespaces.Contains(libcontainer.CLONE_NEWNS) && container.Namespaces.Contains(libcontainer.CLONE_NEWPID) { // important: // we need to fork and unshare so that re can remount proc and sys within // the namespace so the CLONE_NEWPID namespace will take effect // if we don't fork we would end up unmounting proc and sys for the entire // namespace child, err := fork() if err != nil { return fmt.Errorf("fork child %s", err) } if child == 0 { if err := unshare(CLONE_NEWNS); err != nil { writeError("unshare newns %s", err) } if err := remountProc(); err != nil { writeError("remount proc %s", err) } if err := remountSys(); err != nil { writeError("remount sys %s", err) } if err := capabilities.DropCapabilities(container); err != nil { writeError("drop caps %s", err) } if err := exec(cmd.Args[0], cmd.Args[0:], cmd.Env); err != nil { writeError("exec %s", err) } // unreachable } exit, err := utils.WaitOnPid(child) if err != nil { writeError("wait on child %s", err) } os.Exit(exit) } return nil }
func RunIn(containerName string, nsPid int, args []string, env []string) (int, error) { container, err := createContainer(containerName, nsPid, args, env) if err != nil { return -1, fmt.Errorf("error creating container %s", err) } pid, err := namespaces.ExecIn(container, container.Command) if err != nil { return -1, fmt.Errorf("error execin container %s", err) } exitcode, err := utils.WaitOnPid(pid) if err != nil { return -1, fmt.Errorf("error waiting on child %s", err) } return exitcode, nil }
func JoinContainer(containerName string, nsPid int, args []string, env []string) error { container, err := CreateContainer(containerName, nsPid, args, env) if err != nil { return fmt.Errorf("error creating container %s", err) } pid, err := namespaces.ExecIn(container, container.Command) if err != nil { return fmt.Errorf("error exexin container %s", err) } exitcode, err := utils.WaitOnPid(pid) if err != nil { return fmt.Errorf("error waiting on child %s", err) } os.Exit(exitcode) return nil }
func exec(container *libcontainer.Container, name string) error { f, err := os.Open("/root/nsroot/test") if err != nil { return err } container.NetNsFd = f.Fd() pid, err := namespaces.Exec(container) if err != nil { return fmt.Errorf("error exec container %s", err) } container.NsPid = pid if displayPid { fmt.Println(pid) } body, err := json.Marshal(container) if err != nil { return err } buf := bytes.NewBuffer(nil) if err := json.Indent(buf, body, "", " "); err != nil { return err } f, err = os.OpenFile(name, os.O_RDWR, 0755) if err != nil { return err } if _, err := buf.WriteTo(f); err != nil { f.Close() return err } f.Close() exitcode, err := utils.WaitOnPid(pid) if err != nil { return fmt.Errorf("error waiting on child %s", err) } if err := network.DeleteNetworkNamespace("/root/nsroot/test"); err != nil { return err } os.Exit(exitcode) return nil }
func execIn(container *libcontainer.Container) error { f, err := os.Open("/root/nsroot/test") if err != nil { return err } container.NetNsFd = f.Fd() pid, err := namespaces.ExecIn(container, &libcontainer.Command{ Env: container.Command.Env, Args: []string{ newCommand, }, }) if err != nil { return fmt.Errorf("error exexin container %s", err) } exitcode, err := utils.WaitOnPid(pid) if err != nil { return fmt.Errorf("error waiting on child %s", err) } os.Exit(exitcode) return nil }
// RunInNamespace executes the action in the namespace // specified by the fd passed func RunInNamespace(fd uintptr, action Action) error { pid, err := fork() if err != nil { return err } if pid == 0 { if err := setns(fd, 0); err != nil { writeError("setns %s", err) } if err := action(); err != nil { writeError("action %s", err) } os.Exit(0) } exit, err := utils.WaitOnPid(pid) if err != nil { return err } if exit != 0 { fmt.Errorf("exit status %d", exit) } return nil }