Exemple #1
0
func setresuid(ruid, euid, suid int) error {
	eno := C.csetresuid(C.uid_t(ruid), C.uid_t(euid), C.uid_t(suid))
	if eno != 0 {
		return syscall.Errno(eno)
	}
	return nil
}
Exemple #2
0
// Set owner of the group control files and the @c tasks file. This function
// modifies only libcgroup internal cgroup structure, use
// Cgroup.Create() afterwards to create the group with given owners.
// @param cgroup
// @param tasks_uid UID of the owner of group's @c tasks file.
// @param tasks_gid GID of the owner of group's @c tasks file.
// @param control_uid UID of the owner of group's control files (i.e.
// parameters).
// @param control_gid GID of the owner of group's control files (i.e.
// parameters).
func (cg Cgroup) SetUidGid(tasks_uid UID, tasks_gid GID,
	control_uid UID, control_gid GID) error {
	return _err(C.cgroup_set_uid_gid(cg.g,
		C.uid_t(tasks_uid), C.gid_t(tasks_gid),
		C.uid_t(control_uid), C.gid_t(control_gid)))

}
Exemple #3
0
/*
SetUIDGID sets owner of the group control files and the @c tasks file. This function
modifies only libcgroup internal cgroup structure, use
Cgroup.Create() afterwards to create the group with given owners.

@param cgroup
@param tasksUID UID of the owner of group's @c tasks file.
@param tasksGID GID of the owner of group's @c tasks file.
@param controlUID UID of the owner of group's control files (i.e.
parameters).
@param controlGID GID of the owner of group's control files (i.e.
parameters).
*/
func (cg Cgroup) SetUIDGID(tasksUID UID, tasksGID GID,
	controlUID UID, controlGID GID) error {
	return _err(C.cgroup_set_uid_gid(cg.g,
		C.uid_t(tasksUID), C.gid_t(tasksGID),
		C.uid_t(controlUID), C.gid_t(controlGID)))

}
Exemple #4
0
func setuid(uid int) error {
	eno := C.csetuid(C.uid_t(uid))
	if eno != 0 {
		return syscall.Errno(eno)
	}
	return nil
}
Exemple #5
0
//
// Chown wraps keyctl_chown(3) to change ownership of the key.
//
// See: http://man7.org/linux/man-pages/man3/keyctl_chown.3.html
//
func Chown(key KeySerial, uid uint, gid uint) error {

	_, err := C.keyctl_chown(C.key_serial_t(key), C.uid_t(uid), C.gid_t(gid))

	if err != nil {
		return err.(syscall.Errno)
	}
	return nil
}
Exemple #6
0
func getGIDForUID(uid string) (int, error) {
	var x C.gid_t
	n, err := ParseUID(uid)
	if err != nil {
		return 0, err
	}
	uidn := C.uid_t(n)
	if C.de_gid_for_uid(uidn, &x) < 0 {
		return 0, fmt.Errorf("cannot get GID for UID: %d", n)
	}
	return int(x), nil
}
Exemple #7
0
// RunCommandStatus attachs a shell and runs the command within the container.
// The process will wait for the command to finish and return the result of
// waitpid(), i.e. the process' exit status. An error is returned only when
// invocation of the command completely fails.
func (c *Container) RunCommandStatus(args []string, options AttachOptions) (int, error) {
	if len(args) == 0 {
		return -1, ErrInsufficientNumberOfArguments
	}

	if err := c.makeSure(isRunning); err != nil {
		return -1, err
	}

	c.mu.Lock()
	defer c.mu.Unlock()

	cargs := makeNullTerminatedArgs(args)
	if cargs == nil {
		return -1, ErrAllocationFailed
	}
	defer freeNullTerminatedArgs(cargs, len(args))

	cenv := makeNullTerminatedArgs(options.Env)
	if cenv == nil {
		return -1, ErrAllocationFailed
	}
	defer freeNullTerminatedArgs(cenv, len(options.Env))

	cenvToKeep := makeNullTerminatedArgs(options.EnvToKeep)
	if cenvToKeep == nil {
		return -1, ErrAllocationFailed
	}
	defer freeNullTerminatedArgs(cenvToKeep, len(options.EnvToKeep))

	cwd := C.CString(options.Cwd)
	defer C.free(unsafe.Pointer(cwd))

	ret := int(C.go_lxc_attach_run_wait(
		c.container,
		C.bool(options.ClearEnv),
		C.int(options.Namespaces),
		C.long(options.Arch),
		C.uid_t(options.UID),
		C.gid_t(options.GID),
		C.int(options.StdinFd),
		C.int(options.StdoutFd),
		C.int(options.StderrFd),
		cwd,
		cenv,
		cenvToKeep,
		cargs,
	))

	return ret, nil
}
func (a *InoAttr) toCStat(o *C.struct_stat, timeout *C.double) {
	o.st_ino = C.__darwin_ino64_t(a.Ino)
	o.st_mode = C.mode_t(a.Mode)
	o.st_nlink = C.nlink_t(a.Nlink)
	o.st_size = C.off_t(a.Size)
	if a.Uid != nil {
		o.st_uid = C.uid_t(*a.Uid)
	}
	if a.Gid != nil {
		o.st_gid = C.gid_t(*a.Gid)
	}
	toCTime(&o.st_ctimespec, a.Ctim)
	toCTime(&o.st_mtimespec, a.Mtim)
	toCTime(&o.st_atimespec, a.Atim)
	if timeout != nil {
		(*timeout) = C.double(a.Timeout)
	}
}
Exemple #9
0
// AttachShell attaches a shell to the container.
// It clears all environment variables before attaching.
func (c *Container) AttachShell(options AttachOptions) error {
	if err := c.makeSure(isRunning); err != nil {
		return err
	}

	c.mu.Lock()
	defer c.mu.Unlock()

	cenv := makeNullTerminatedArgs(options.Env)
	if cenv == nil {
		return ErrAllocationFailed
	}
	defer freeNullTerminatedArgs(cenv, len(options.Env))

	cenvToKeep := makeNullTerminatedArgs(options.EnvToKeep)
	if cenvToKeep == nil {
		return ErrAllocationFailed
	}
	defer freeNullTerminatedArgs(cenvToKeep, len(options.EnvToKeep))

	cwd := C.CString(options.Cwd)
	defer C.free(unsafe.Pointer(cwd))

	ret := int(C.go_lxc_attach(c.container,
		C.bool(options.ClearEnv),
		C.int(options.Namespaces),
		C.long(options.Arch),
		C.uid_t(options.UID),
		C.gid_t(options.GID),
		C.int(options.StdinFd),
		C.int(options.StdoutFd),
		C.int(options.StderrFd),
		cwd,
		cenv,
		cenvToKeep,
	))
	if ret < 0 {
		return ErrAttachFailed
	}
	return nil
}
Exemple #10
0
func changeUser(username string) error {
	uid, gid, err := user.IDs(username)
	if err != nil {
		return util.Errorf("Could not retrieve uid/gid for %q: %s", username, err)
	}

	userCstring := C.CString(username)
	defer C.free(unsafe.Pointer(userCstring))

	ret, err := C.initgroups(userCstring, C.int(gid))
	if ret != 0 && err != nil {
		return util.Errorf("Could not initgroups for %q (primary gid %v): %s", username, gid, err)
	}
	ret, err = C.setgid(C.gid_t(gid))
	if ret != 0 && err != nil {
		return util.Errorf("Could not setgid %v: %s", gid, err)
	}
	ret, err = C.setuid(C.uid_t(uid))
	if ret != 0 && err != nil {
		return util.Errorf("Could not setuid %v: %s", uid, err)
	}
	return nil
}
Exemple #11
0
// Run is a simple wrapper around Start() then Wait() with a common err return.
func (c *Cmd) Start() (err error) {
	// If the process has already started then we can not continue here.
	if c.Process != nil {
		return fmt.Errorf("goclone: already started.")
	}

	// Check that UserMap and GroupMap are not defined if NewUserNameSpace
	// is not true.
	switch {
	case c.NewUserNameSpace:
	case c.UserMap != nil:
		return fmt.Errorf("goclone: UserMap set but NewUserNameSpace is false.")
	case c.GroupMap != nil:
		return fmt.Errorf(
			"goclone: GroupMap set but NewUserNameSpace is false.")
	}

	// Check to see if user name spaces are being used when the support
	// for them does not exist in the kernel.
	switch {
	case C.goclone_user_namespace_enabled == 1:
	case c.NewUserNameSpace:
		fallthrough
	case c.UserNameSpace != "":
		return fmt.Errorf("goclone: The kernel lacks user namespace support.")
	}

	// This function will walk through all of the file descriptors closing them
	// and returning the error passed in (or an error generated during the
	// Close() call if necessary.
	fail := func(err error) error {
		err = closeDescriptors(c.closeAfterStart, err)
		err = closeDescriptors(c.closeAfterWait, err)
		return err
	}

	// Setup the file descriptors needed to actually perform the syscall
	// level clone.
	stdin, err := c.reader(c.Stdin)
	if err != nil {
		return fail(err)
	}
	stdout, err := c.writer(c.Stdout)
	if err != nil {
		return fail(err)
	}

	// As a special case we have to check that stdout and stderr are not the
	// same object. If they are then we should use the same file descriptor
	// object rather than duplicating a whole new one.
	var stderr *os.File
	if c.Stdout == c.Stderr {
		stderr = stdout
	} else {
		stderr, err = c.writer(c.Stderr)
		if err != nil {
			return fail(err)
		}
	}

	// Make the native object type that is necessary in order to pass the
	// data into the cgo side of the world. We do this via a mmaped chunk
	// of memory so that we don't have to fiddle with malloc or any form
	// of shared memory allocations. Mmap works purely in pages so everything
	// needs to be sized to fit within pages of memory.
	//
	// The format for this allocation looks like this:
	// [ C.goclone_cmd ] - This will be several pages, rounded up to the
	//                     next page size.
	// [ buffer ] - This is necessary to ensure that we operate on sizes
	//              one page at a time.
	// [ page ] - This is a single page that will be memprotected in order to
	//            prevent the stack in the C side from growing large enough
	//            to cause memory corruption.
	// [ stack ] - This is a chunk of memory used as the stack for the cloned
	//             process.
	// [ page ] - This is another protected page.
	//
	// If double forking this will also be added to the allocation:
	// [ stack 2 ] - The stack for the short lived middle process.
	// [ page ] - Another protected page.

	// Start by calculating how much data needs to be available in the mmap
	// allocation.
	dataSize := rawDataSize(c)

	// Adjust the dataSize value to be a multiple of pageSize.
	dataSize = ((dataSize - 1) | (pageSize - 1)) + 1

	// Now calculate the total size of the allocation.
	size := dataSize + pageSize + stackSize + pageSize
	if c.DoubleFork {
		size += stackSize + pageSize
	}

	// Allocate the space and ensure it gets freed when the routine exits.
	m, err := mmapDataAlloc(size)
	if err != nil {
		return fail(err)
	}
	defer func() {
		err2 := m.free()
		if err == nil && err2 != nil {
			err = err2
		}
	}()

	// This boolean value is set if the credentials should be set at some
	// point. Its off by default unless a user defined the Credentials field
	// in the SysProcAttr field.
	setCredentials := false
	uid := uint32(0)
	gid := uint32(0)
	groups := []uint32(nil)
	if c.SysProcAttr != nil && c.SysProcAttr.Credential != nil {
		setCredentials = true
		uid = c.SysProcAttr.Credential.Uid
		gid = c.SysProcAttr.Credential.Gid
		groups = c.SysProcAttr.Credential.Groups
	}

	// If the c.SysProcAttr value is set then save the signal.
	deathSignal := syscall.SIGCHLD
	if c.SysProcAttr != nil && c.SysProcAttr.Pdeathsig != 0 {
		deathSignal = c.SysProcAttr.Pdeathsig
	}

	// The chroot directory is set from c.SysProcAttr if defined.
	chrootDir := ""
	if c.SysProcAttr != nil {
		chrootDir = c.SysProcAttr.Chroot
	}

	// Make an array of file descriptors that will be used to setup the
	// file descriptors in the child process.
	files := make([]int, len(c.ExtraFiles)+3)
	files[0] = int(stdin.Fd())
	files[1] = int(stdout.Fd())
	files[2] = int(stderr.Fd())
	for i, fd := range c.ExtraFiles {
		if fd != nil {
			files[i+3] = int(fd.Fd())
		} else {
			files[i+3] = -1
		}
	}

	// Populate the various data elements in the allocation.
	cmd := m.pushGocloneCmd()
	// Exec settings.
	cmd.path = m.pushString(c.Path)
	cmd.args = m.pushStringSlice(c.Args)
	cmd.env = m.pushStringSlice(c.Env)
	cmd.dir = m.pushString(c.Dir)
	cmd.chroot_dir = m.pushString(chrootDir)

	// Set hostname only for new UTS namespace
	if c.NewUTSNameSpace {
		cmd.hostname = m.pushString(c.Hostname)
	} else {
		cmd.hostname = m.pushString("")
	}

	// file descriptors.
	cmd.files = m.pushIntSlice(files)
	cmd.files_len = C.int(len(files))

	// Credentials
	cmd.set_credentials = C.bool(setCredentials)
	cmd.uid = C.uid_t(uid)
	cmd.gid = C.gid_t(gid)
	cmd.groups = m.pushGidSlice(groups)
	cmd.groups_len = C.int(len(groups))

	// Cgroups tasks files.
	cmd.cgroups_tasks_files = m.pushStringSlice(c.CgroupsTasksFiles)

	// Namespaces
	cmd.ipc_namespace = m.pushString(c.IPCNameSpace)
	cmd.mount_namespace = m.pushString(c.MountNameSpace)
	cmd.network_namespace = m.pushString(c.NetworkNameSpace)
	cmd.user_namespace = m.pushString(c.UserNameSpace)
	cmd.uts_namespace = m.pushString(c.UTSNameSpace)
	cmd.pid_namespace = m.pushString(c.PIDNameSpace)
	cmd.new_ipc_namespace = C.bool(c.NewIPCNameSpace)
	cmd.new_network_namespace = C.bool(c.NewNetworkNameSpace)
	cmd.new_pid_namespace = C.bool(c.NewPIDNameSpace)
	cmd.new_mount_namespace = C.bool(c.NewMountNameSpace)
	cmd.new_user_namespace = C.bool(c.NewUserNameSpace)
	cmd.new_uts_namespace = C.bool(c.NewUTSNameSpace)

	// See if we should mount a new /proc from the underlying process.
	if os.Getuid() == 0 && c.NewPIDNameSpace {
		cmd.mount_new_proc = C.bool(true)
	} else {
		cmd.mount_new_proc = C.bool(false)
	}

	// Various simple settings.
	cmd.double_fork = C.bool(c.DoubleFork)
	cmd.death_signal = C.int(deathSignal)

	// Allocate the stacks.
	if err = m.mprotect(); err != nil {
		return
	}
	cmd.stack = m.stack()
	if err = m.mprotect(); err != nil {
		return
	}

	// If double forking, allocate another stack and protect the page after it.
	if c.DoubleFork {
		cmd.df_stack = m.stack()
		if err = m.mprotect(); err != nil {
			return
		}
	}

	// Next we need to create a goclone_parent_data for use by the parent when
	// helpign with the child.
	var data C.goclone_parent_data

	// Setup the uid_map. This will be written to /proc/child/uid_map if
	// defined.
	var uid_map bytes.Buffer
	if c.UserMap == nil {
		data.uid_map = nil
		data.uid_map_length = 0
	} else {
		for i := range c.UserMap {
			elm := &c.UserMap[i]
			fmt.Fprintf(&uid_map, "%d %d %d\n", elm.Inside, elm.Outside, elm.Length)
		}
		data.uid_map = (*C.char)(unsafe.Pointer(&(uid_map.Bytes()[0])))
		data.uid_map_length = (C.int)(uid_map.Len())
	}

	// Setup the gid_map. This will be written to /proc/child/gid_map if
	// defined.
	var gid_map bytes.Buffer
	if c.UserMap == nil {
		data.gid_map = nil
		data.gid_map_length = 0
	} else {
		for i := range c.UserMap {
			elm := &c.UserMap[i]
			fmt.Fprintf(&gid_map, "%d %d %d\n", elm.Inside, elm.Outside, elm.Length)
		}
		b := gid_map.Bytes()
		data.gid_map = (*C.char)(unsafe.Pointer(&b[0]))
		data.gid_map_length = (C.int)(gid_map.Len())
	}

	// Call the C function.
	pid, err := C.goclone(cmd, &data)

	// Close any file descriptors that are no longer needed.
	err = closeDescriptors(c.closeAfterStart, err)

	// Make the Process structure. This functions foot print returns an error
	// but on linux an error can never be returned.
	c.Process, _ = os.FindProcess(int(pid))

	// Start all of the copy goroutines.
	for _, f := range c.copyRoutines {
		c.errWG.Add(1)
		go f()
	}
	c.copyRoutines = nil

	return
}