Beispiel #1
0
// UnpackWithDropPrivs will unapck the ClickDeb content into the
// target dir and drop privs when doing this.
//
// To do this reliably in go we need to exec a helper as we can not
// just fork() and drop privs in the child (no support for stock fork in go)
func (d *ClickDeb) UnpackWithDropPrivs(instDir, rootdir string) error {
	// no need to drop privs, we are not root
	if !helpers.ShouldDropPrivs() {
		return d.Unpack(instDir)
	}

	cmd := exec.Command("snappy", "internal-unpack", d.Name(), instDir, rootdir)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		return &ErrUnpackFailed{
			snapFile: d.Name(),
			instDir:  instDir,
			origErr:  err,
		}
	}

	return nil
}
func unpackAndDropPrivs(snapFile, targetDir, rootDir string) error {

	d, err := clickdeb.Open(snapFile)
	if err != nil {
		return err
	}
	defer d.Close()

	if helpers.ShouldDropPrivs() {
		var dropPrivsUser string

		// first find out what user to use
		passFile := passwdFile(rootDir, "passwd")
		for _, dropPrivsUser = range dropPrivsUsers {
			_, err := readUID(dropPrivsUser, passFile)
			if err == nil {
				break
			}
		}

		// then get uid/gid
		uid, err := readUID(dropPrivsUser, passFile)
		if err != nil {
			return err
		}

		groupFile := passwdFile(rootDir, "group")
		gid, err := readUID(dropPrivsUser, groupFile)
		if err != nil {
			return err
		}

		if err := os.MkdirAll(targetDir, 0755); err != nil {
			return err
		}

		if err := os.Chown(targetDir, uid, gid); err != nil {
			return err
		}

		// Setuid and Setgid only apply to the current Linux thread, so make
		// sure we don't get moved.
		runtime.LockOSThread()

		// run prctl(PR_SET_NO_NEW_PRIVS)
		rc := C.prctl_no_new_privs()
		if rc < 0 {
			return fmt.Errorf("prctl(PR_SET_NO_NEW_PRIVS) failed with %v", rc)
		}

		if err := syscall.Setgroups([]int{gid}); err != nil {
			return fmt.Errorf("Setgroups([]{%d}) call failed: %v", gid, err)
		}

		if err := setgid(gid); err != nil {
			return fmt.Errorf("Setgid(%d) call failed: %v", gid, err)
		}
		if err := setuid(uid); err != nil {
			return fmt.Errorf("Setuid(%d) call failed: %v", uid, err)
		}

		// extra paranoia
		if syscall.Getuid() != uid || syscall.Getgid() != gid {
			return fmt.Errorf("Dropping privileges failed, uid is %v, gid is %v", syscall.Getuid(), syscall.Getgid())
		}
	}

	return d.UnpackAll(targetDir)
}