Plash: tools for practical least privilege

RPC methods

fs_op object

This object implements all the standard Unix filesystem calls that operate on pathnames: open(), mkdir(), unlink() and so on. You can construct one of these objects given a root directory.

This object has one piece of state: the current working directory (cwd). This is allowed to be unset, in which case any operation that it relative to the cwd will return an error.

Notation:

Methods:

// duplicate the connection -- called before the fork() syscall
// (now obsolete; will be removed)
"Fork"
=>
"RFrk" + FD
"Copy"
=> "Okay" + fs_op/obj
"Gdir" pathname
=> "Okay" + dir/obj
Resolves `pathname' to get a directory, and returns the directory object.
"Grtd"
=> "Okay" + dir/obj
Same as <<"Gdir" "/">>.
"Gobj" pathname
=> "Okay" + obj
Resolved `pathname' to get any object; will follow symlinks.
// open() call
"Open" flags/int mode/int filename
=>
"ROpn" + FD
"RDfd" + FD + dir_stack/obj // This is returned when open() is used on a directory.
                            // FD is for /dev/null, and the object is a dir_stack.
"Fail" errno/int
// stat() and lstat() calls
"Stat" nofollow/int pathname
=>
"RSta" stat
"Fail" errno/int
// readlink() call
"Rdlk" pathname
=>
"RRdl" string
"Fail" errno/int
// chdir() call
"Chdr" pathname
=>
"RSuc"
"Fail" errno/int
// fchdir() call:  takes a dir_stack object as returned by open()
"Fchd" + dir_stack/obj
=>
"Okay"
"Fail" errno/int
// getcwd() call
"Gcwd"
=>
"RCwd" pathname
"Fail" errno/int
// list contents of directories: opendir() + readdir() + closedir()
"Dlst" pathname
=>
// same as `struct dirent' format:
"RDls" (inode/int type/int name_size/int name)*
"Fail" errno/int
// access() call
"Accs" mode/int pathname
=>
"RAcc"
"Fail" errno/int
// mkdir()
"Mkdr" mode/int pathname
=>
"RMkd"
"Fail" errno/int
// chmod() call
"Chmd" mode/int pathname
=>
"RChm"
"Fail" errno/int
// utime()/utimes()/lutimes() calls
"Utim" nofollow/int
	atime_sec/int atime_usec/int
	mtime_sec/int mtime_usec/int
	pathname
=>
"RUtm"
"Fail" errno/int
// rename() call
"Renm" newpath-length/int newpath oldpath
=>
"RRnm"
"Fail" errno/int
// link() call
"Link" newpath-length/int newpath oldpath
=>
"RLnk"
"Fail" errno/int
// symlink() call
"Syml" newpath-length/int newpath oldpath
=>
"RSym"
"Fail" errno/int
// unlink() call
"Unlk" pathname
=>
"RUnl"
"Fail" errno/int
// rmdir() call
"Rmdr" pathname
=>
"RRmd"
"Fail" errno/int
// connect() on Unix domain sockets
"Fcon" pathname + FD
=>
"RFco"
"Fail" errno/int
// bind() on Unix domain sockets
"Fbnd" pathname + FD
=>
"RFbd"
"Fail" errno/int
// part of execve() call
// Arguments are:
//  * command pathname (in "cmd" and "cmd-len" below)
//  * a list of string arguments (in "ref" and "data")
// The RExe result tells the client what it should pass to the exec syscall.
// The RExo result returns an executable object which the client must invoke
// with full arguments, including the root directory.
"Exec" cmd-len/int cmd ref/int data
=>
"RExe" cmd-len/int cmd argc/int (arg-len/int arg)* + FD
"RExo" + CAP
"Fail" errno/int

where:

stat = dev ino mode nlink uid gid rdev size blksize blocks atime mtime ctime
       (all ints)

Filesystem objects: files, directories and symlinks

make-marshal.pl contains the definitions for these methods.

Executable objects

Executable objects are like files. They respond to the "fsobj_stat" method. You generally can't open them with the "file_open" method -- this will give "Permission denied". They support two methods besides the usual file methods.

// Test whether this is an executable object.
// Executables that are just files will not respond to this.
"Exep"
=> "Okay"
"Exeo" ref/int data
=> "Okay" return_code/int
The data is an array of pairs:
 * ("Argv", x):  x is an array of strings representing argv
 * ("Env.", x):  x is an array of strings representing the environment
   (usually each string is of the form "X=y")
 * ("Fds.", x):  x is an array of (i, FD)
 * ("Root", obj):  obj is the root directory
 * ("Cwd.", string):  pathname of current working directory
   (this can be omitted, in which case process will have no defined cwd)
 * ("Pgid", int):  process group ID to set for the new process
   (this is optional, but reading from the console won't work without
   setting it, and neither will Ctrl-C or Ctrl-Z)
The invocation returns when the process started has exited.  It returns
the exit code that `wait' returns for the process.

conn_maker object

This has one method:

"Mkco" M/int + (N objects)
=> "Okay" + FD + (M objects)

This creates a new connection on which the N objects are exported. It returns "Okay" and a file descriptor for the new connection. The new connection also imports M objects. The method call returns these M objects.

So far this is only used with M = 0.

fs_op_maker object

This has one method:

"Mkfs" + root_dir/obj
=> "Okay" + fs_op/obj

This creates an fs_op object (see above) with root_dir as the root directory. The current working directory is initially unset; you can set it with the "Chdr" (chdir) method.