Documentation ¶
Overview ¶
Package session is for managing cpu sessions, i.e. the process started by cpud.
New(port9p, cmd string, args ...string) creates a new Session. The port9p argument, if is not empty, specifies the 9p port to use. The cmd parameter specifies a command and arguments, a la exec.Command. Sessions are very similar to exec.Command, providing access to Stdin, Stdout, Stderr. For Stdin, Run determines if a pty is needed and will set one up.
Run will also set up a process namespace via 9p and other mounts, if needed. If CPU_NAMESPACE is non-empty, it defines the bind mounts from /tmp/cpu. See the cpu command documentation for more information on how CPU_NAMESPACE is set. If CPU_FSTAB is set, it is assumed to be a string in fstab(5) format and Run will mount the specified file systems. CPU_FSTAB is most often used for virtiofs mounts from virtual machines.
For the moment, servers only call Run(), which does all namespace, tty, and process startup. Run returns when the process it directly started returns. It does not wait for children.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Bind ¶
Bind defines a bind mount. It records the Local directory, e.g. /bin, and the remote directory, e.g. /tmp/cpu/bin.
func ParseBinds ¶
ParseBinds parses a CPU_NAMESPACE-style string to a slice of Bind structures.
type Session ¶
type Session struct { Stdin io.Reader Stdout io.Writer Stderr io.Writer // contains filtered or unexported fields }
Session is one instance of a cpu session, started by a cpud.
func New ¶
New returns a New session with defaults set. It requires a port for 9p (which can be the empty string, but is usually not) and a command name.
func (*Session) Namespace ¶
Namespace assembles a NameSpace for this cpud, iff CPU_NONCE is set and len(s.binds) > 0.
This code assumes you have a non-shared namespace. This is archieved in go by setting exec.Cmd.SysprocAttr.Unshareflags to CLONE_NEWNS; the go runtime will then do what is needed to privatize a namespace. I can say this because I wrote that code 5 years ago, and go tests for it are run as part of the go release process.
To reiterate, this package requires, for proper operation, that the process using it be in a private name space, and, further, that the namespace can't magically be reshared.
It's very hard and probably impossible to test for a namespace being set up properly on Linux. On plan 9 it's easy: read the process namespace file and see if it's empty. But no such operation is possible on Linux and, worse, since sometime in the 3.x kernel series, even once a namespace is unshared, another process can start using it via nsenter(2).
Hence this note: it is a warning to our future selves or users of this package.
Note, however, that cpud does the right thing, by setting Unshareflags to CLONE_NEWNS. Tests in the cpu server code ensure that continues to be the case.
tl;dr: Linux namespaces are a pretty terrible mess. They may have been inspired by Plan 9, but an understanding of some critical core ideas has been lost. As a result, they do not remotely represent any kind of security boundary.
func (*Session) Run ¶
Run starts up a remote cpu session. It is started by a cpu daemon via a -remote switch.
This code assumes that cpud is running as init, or that an init has started a cpud, and that the code is running with a private namespace (CLONE_NEWNS on Linux; RFNAMEG on Plan9). On Linux, it starts as uid 0, and once the mount/bind is done, calls DropPrivs.
func (*Session) TmpMounts ¶
TmpMounts sets up directories, and bind mounts, in /tmp/cpu. N.B. the /tmp/cpu mount is private assuming this program was started correctly with the namespace unshared (on Linux and Plan 9; on *BSD or Windows no such guarantees can be made).
See the longer comment (rant) in session_linux.go