Beispiel #1
0
// setupConsole sets up the console from inside the container, and sends the
// master pty fd to the config.Pipe (using cmsg). This is done to ensure that
// consoles are scoped to a container properly (see runc#814 and the many
// issues related to that). This has to be run *after* we've pivoted to the new
// rootfs (and the users' configuration is entirely set up).
func setupConsole(pipe *os.File, config *initConfig, mount bool) error {
	// At this point, /dev/ptmx points to something that we would expect. We
	// used to change the owner of the slave path, but since the /dev/pts mount
	// can have gid=X set (at the users' option). So touching the owner of the
	// slave PTY is not necessary, as the kernel will handle that for us. Note
	// however, that setupUser (specifically fixStdioPermissions) *will* change
	// the UID owner of the console to be the user the process will run as (so
	// they can actually control their console).
	console, err := newConsole()
	if err != nil {
		return err
	}
	// After we return from here, we don't need the console anymore.
	defer console.Close()

	linuxConsole, ok := console.(*linuxConsole)
	if !ok {
		return fmt.Errorf("failed to cast console to *linuxConsole")
	}

	// Mount the console inside our rootfs.
	if mount {
		if err := linuxConsole.mount(); err != nil {
			return err
		}
	}

	if err := writeSync(pipe, procConsole); err != nil {
		return err
	}

	// We need to have a two-way synchronisation here. Though it might seem
	// pointless, it's important to make sure that the sendmsg(2) payload
	// doesn't get swallowed by an out-of-place read(2) [which happens if the
	// syscalls get reordered so that sendmsg(2) is before the other side's
	// read(2) of procConsole].
	if err := readSync(pipe, procConsoleReq); err != nil {
		return err
	}

	// While we can access console.master, using the API is a good idea.
	if err := utils.SendFd(pipe, linuxConsole.File()); err != nil {
		return err
	}

	// Make sure the other side recieved the fd.
	if err := readSync(pipe, procConsoleAck); err != nil {
		return err
	}

	// Now, dup over all the things.
	return linuxConsole.dupStdio()
}
Beispiel #2
0
func (t *tty) sendtty(socket *os.File, ti *libcontainer.TerminalInfo) error {
	if t.console == nil {
		return fmt.Errorf("tty.console not set")
	}

	// Create a fake file to contain the terminal info.
	console := os.NewFile(t.console.File().Fd(), ti.String())
	if err := utils.SendFd(socket, console); err != nil {
		return err
	}
	return nil
}