func bindMount(bindDir string, rootDir string, readonly bool) error { var srcDir, destDir string d := strings.SplitN(bindDir, ":", 2) if len(d) < 2 { srcDir = d[0] } else { srcDir, destDir = d[0], d[1] } if destDir == "" { destDir = srcDir } ok, err := osutil.IsDirEmpty(srcDir) if err != nil { return err } if ok { if _, err := os.Create(fp.Join(srcDir, ".droot.keep")); err != nil { return errwrap.Wrapf(err, "Failed to create .droot.keep: {{err}}") } } containerDir := fp.Join(rootDir, destDir) if err := fileutils.CreateIfNotExists(containerDir, true); err != nil { // mkdir -p return errwrap.Wrapff(err, "Failed to create directory: %s: {{err}}", containerDir) } ok, err = osutil.IsDirEmpty(containerDir) if err != nil { return err } if ok { log.Debug("bind mount", bindDir, "to", containerDir) if err := mount.Mount(srcDir, containerDir, "none", "bind,rw"); err != nil { return errwrap.Wrapff(err, "Failed to bind mount %s: {{err}}", containerDir) } if readonly { log.Debug("robind mount", bindDir, "to", containerDir) if err := mount.Mount(srcDir, containerDir, "none", "remount,ro,bind"); err != nil { return errwrap.Wrapff(err, "Failed to robind mount %s: {{err}}", containerDir) } } } return nil }
func doRun(c *cli.Context) error { command := c.Args() if len(command) < 1 { cli.ShowCommandHelp(c, "run") return errors.New("command required") } rootDir := c.String("root") if rootDir == "" { cli.ShowCommandHelp(c, "run") return errors.New("--root option required") } if !osutil.ExistsDir(rootDir) { return fmt.Errorf("No such directory %s:", rootDir) } var err error uid, gid := os.Getuid(), os.Getgid() if group := c.String("group"); group != "" { if gid, err = osutil.LookupGroup(group); err != nil { return fmt.Errorf("Failed to lookup group:", err) } } if user := c.String("user"); user != "" { if uid, err = osutil.LookupUser(user); err != nil { return fmt.Errorf("Failed to lookup user:"******"copy-files") { for _, f := range copyFiles { srcFile, destFile := fp.Join("/", f), fp.Join(rootDir, f) if err := osutil.Cp(srcFile, destFile); err != nil { return fmt.Errorf("Failed to copy %s:", f, err) } if err := os.Lchown(destFile, uid, gid); err != nil { return fmt.Errorf("Failed to lchown %s:", f, err) } } } // mount -t proc none {{rootDir}}/proc if err := mount.Mount("none", fp.Join(rootDir, "/proc"), "proc", ""); err != nil { return fmt.Errorf("Failed to mount /proc: %s", err) } // mount --rbind /sys {{rootDir}}/sys if err := mount.Mount("/sys", fp.Join(rootDir, "/sys"), "none", "rbind"); err != nil { return fmt.Errorf("Failed to mount /sys: %s", err) } for _, dir := range c.StringSlice("bind") { if err := bindMount(dir, rootDir, false); err != nil { return fmt.Errorf("Failed to bind mount %s:", dir, err) } } for _, dir := range c.StringSlice("robind") { if err := bindMount(dir, rootDir, true); err != nil { return fmt.Errorf("Failed to robind mount %s:", dir, err) } } // create symlinks if err := osutil.Symlink("../run/lock", fp.Join(rootDir, "/var/lock")); err != nil { return fmt.Errorf("Failed to symlink lock file:", err) } if err := createDevices(rootDir, uid, gid); err != nil { return fmt.Errorf("Failed to create devices:", err) } log.Debug("chroot", rootDir, command) if err := syscall.Chroot(rootDir); err != nil { return fmt.Errorf("Failed to chroot:", err) } if err := syscall.Chdir("/"); err != nil { return fmt.Errorf("Failed to chdir /:", err) } if !c.Bool("no-dropcaps") { log.Debug("drop capabilities") if err := osutil.DropCapabilities(keepCaps); err != nil { return fmt.Errorf("Failed to drop capabilities:", err) } } log.Debug("setgid", gid) if err := osutil.Setgid(gid); err != nil { return fmt.Errorf("Failed to set group %d:", gid, err) } log.Debug("setuid", uid) if err := osutil.Setuid(uid); err != nil { return fmt.Errorf("Failed to set user %d:", uid, err) } return osutil.Execv(command[0], command[0:], os.Environ()) }