prx (prx v0.14.1) View Source

Link to this section Summary

Functions

Register a function to be called at task termination.

Make a synchronous call into the port driver.

(FreeBSD only) cap_enter(2) : put process into capability mode
(FreeBSD only) cap_fcntls_get(2) : get allowed fnctl(2) commands on file descriptor
(FreeBSD only) cap_fcntls_limit(2) : set allowed fnctl(2) commands on file descriptor

(FreeBSD only) cap_getmode(2) : returns capability mode status of process

(FreeBSD only) cap_ioctls_limit(2) : set allowed ioctl(2) commands on file descriptor
(FreeBSD only) cap_rights_limit(2) : set allowed rights(4) of file descriptor
chdir(2) : change process current working directory
chmod(2) : change file permissions
chown(2) : change file ownership
chroot(2) : change root directory
clearenv(3) : zero process environment
(Linux only) clone(2) : create a new process
close(2) : close a file descriptor

Assign a new process owner.

Returns the list of child PIDs for this process.

Retrieve process info for forked processes.

environ(7) : return the process environment variables
Close stdin of child process.
Close stdin, stdout or stderr of child process.

Test if the task has called exec(2).

execve(2) : replace the process image, specifying the environment for the new process image.

execve(2) : replace the process image, specifying the environment for the new process image.

execvp(2) : replace the current process image using the search path

execvp(2) : replace the current process image using the search path

exit(3) : cause the child process to exit
fcntl(2) : perform operation on a file descriptor
fcntl(2) : perform operation on a file descriptor with argument
fexecve(2) : replace the process image, specifying the environment for the new process image, using a previously opened file descriptor. The file descriptor can be set to close after exec() by passing the O_CLOEXEC flag to open:
  {ok, FD} = prx:open(Task, "/bin/ls", [o_rdonly,o_cloexec]),
  ok = prx:fexecve(Task, FD, ["-al"], ["FOO=123"]).

Linux and FreeBSD only. Linux requires an environment be set unlike with execve(2). The environment can be empty

filter/2 : restrict control process calls

filter/3 : restrict control process and subprocess calls

fork(2) : create a new system process

fork(2) : create a child process

getcpid() : get options for child process of prx control process

getcpid() : retrieve attributes set by the prx control process for a child process

getcwd(3) : return the current working directory
getenv(3) : retrieve an environment variable
getgid(2) : retrieve the processes' group ID
getgroups(2) : retrieve the list of supplementary groups
gethostname(2) : retrieve the system hostname

getopt() : get options for the prx control process

getpgrp(2) : retrieve the process group
getpid(2) : retrieve the system PID of the process
getpriority(2) : retrieve scheduling priority of process process group or user

getresgid(2) : get real, effective and saved group ID

getresuid(2) : get real, effective and saved user ID

getrlimit(2) : retrieve the resource limits for a process
getsid(2) : retrieve the session ID
getuid(2) : returns the process user ID

ioctl(2) : control device

(FreeBSD only) jail(2) : restrict the current process in a system jail
kill(2) : terminate a process
lseek(2) : set file offset for read/write
mkdir(2) : create a directory
mkfifo(3) : create a named pipe

mount(2) : mount a filesystem, Linux style

(Solaris only) mount(2) : mount a filesystem

open(2) : returns a file descriptor associated with a file

open(2) : create a file, specifying permissions

Retrieves the system PID of the process similar to getpid(2).

(Linux only) pivot_root(2) : change the root filesystem
(OpenBSD only) pledge(2) : restrict system operations
  prx:pledge(Task, "stdio proc exec", [])

(Linux only) prctl(2) : operations on a process

(FreeBSD only) procctl(2) : control processes

(Linux only) ptrace(2) : trace processes
read(2) : read bytes from a file descriptor
readdir(3) : retrieve list of objects in a directory

Fork+exec prx process.

Replace the port process image using execve(2)/fexecve(2).

Alias for reexec/1.
rmdir(2) : delete a directory

seccomp(2) : restrict system operations

select(2) : poll a list of file descriptor for events

setcpid() : Set options for child process of prx control process

setcpid() : Set options for child process of prx control process

setenv(3) : set an environment variable
setgid(2) : set the GID of the process
setgroups(2) : set the supplementary groups of the process

sethostname(2) : set the system hostname

(Linux only) setns(2) : attach to a namespace

(Linux only) setns(2) : attach to a namespace, specifying namespace type

setopt() : set options for the prx control process

setpgid(2) : set process group
setpriority(2) : set scheduling priority of process, process group or user

setproctitle(3) : set the process title

setresgid(2) : set real, effective and saved group ID

setresuid(2) : set real, effective and saved user ID

setrlimit(2) : set a resource limit
setsid(2) : create a new session
setuid(2) : change UID

sigaction(2) : set process behaviour for signals

socket(2) : retrieve file descriptor for communication endpoint

Send data to the standard input of the process.

Assign a process to receive stdio.

Terminate the task.

Convenience function to fork a privileged process in the shell.

Convenience function to fork a privileged process in the shell.

umount(2) : unmount a filesystem

umount2(2) : unmount a filesystem

unlink(2) : delete references to a file
unsetenv(3) : remove an environment variable

(Linux only) unshare(2) : allows creating a new namespace in the current process

(OpenBSD only) unveil(2) : restrict filesystem view
  prx:unveil(Task, "/bin", "rx")

waitpid(2) : wait for child process

write(2): write to a file descriptor

Link to this section Types

Specs

call() :: alcove_proto:call() | reexec | replace_process_image | getcpid.

Specs

constant() :: atom() | integer().

Specs

cpid() ::
    #{pid := pid_t(),
      flowcontrol := uint32_t(),
      signaloneof := uint32_t(),
      exec := boolean(),
      fdctl := fd(),
      stdin := fd(),
      stdout := fd(),
      stderr := fd()}.

Specs

cstruct() :: [binary() | {ptr, binary() | non_neg_integer()}, ...].

Specs

fd() :: int32_t().

Specs

gid_t() :: uint32_t().

Specs

int32_t() :: - 2147483647..2147483647.

Specs

int64_t() :: - 9223372036854775807..9223372036854775807.

Specs

mode_t() :: uint32_t().

Specs

off_t() :: uint64_t().

Specs

pid_t() :: int32_t().

Specs

posix() :: alcove:posix().

Specs

prx_opt() :: maxchild | exit_status | maxforkdepth | termsig | flowcontrol | signaloneof.

Specs

ptr_arg() :: binary() | constant() | cstruct().

Specs

ptr_val() :: binary() | integer() | cstruct().

Specs

size_t() :: uint64_t().

Specs

ssize_t() :: int64_t().

Specs

task() :: pid().

Specs

uid_t() :: uint32_t().

Specs

uint32_t() :: 0..4294967295.

Specs

uint64_t() :: 0..18446744073709551615.

Specs

waitstatus() :: {exit_status, int32_t()} | {termsig, atom()} | {stopsig, atom()} | continued.

Link to this section Functions

Specs

atexit(task(), fun((pid(), [pid_t()], pid_t()) -> any())) -> ok.

Register a function to be called at task termination.

The atexit function runs in the parent of the process. atexit/2 must use prx_drv:call/4 to manipulate the task.

The default function closes stdin, stdout and stderr of the system process:

  fun(Drv, ForkChain, Pid) ->
   prx_drv:call(Drv, ForkChain, close, [maps:get(stdout, Pid)]),
   prx_drv:call(Drv, ForkChain, close, [maps:get(stdin, Pid)]),
   prx_drv:call(Drv, ForkChain, close, [maps:get(stderr, Pid)])
  end

Specs

call(task(), call(), [any()]) -> any().

Make a synchronous call into the port driver.

The list of available calls and their arguments can be found here:

https://github.com/msantos/alcove#alcove-1

For example, to directly call alcove:execve/5:

  call(Task, execve,
   ["/bin/ls", ["/bin/ls", "-al"], ["HOME=/home/foo"]])

Specs

cap_enter(task()) -> ok | {error, posix()}.
(FreeBSD only) cap_enter(2) : put process into capability mode
Link to this function

cap_fcntls_get(Task, Arg1)

View Source

Specs

cap_fcntls_get(task(), fd()) -> {ok, int32_t()} | {error, posix()}.
(FreeBSD only) cap_fcntls_get(2) : get allowed fnctl(2) commands on file descriptor
Link to this function

cap_fcntls_limit(Task, Arg1, Arg2)

View Source

Specs

cap_fcntls_limit(task(), fd(), [constant()]) -> ok | {error, posix()}.
(FreeBSD only) cap_fcntls_limit(2) : set allowed fnctl(2) commands on file descriptor

Specs

cap_getmode(task()) -> {ok, 0 | 1} | {error, posix()}.

(FreeBSD only) cap_getmode(2) : returns capability mode status of process

* 0 : false * 1 : true
Link to this function

cap_ioctls_limit(Task, Arg1, Arg2)

View Source

Specs

cap_ioctls_limit(task(), fd(), [constant()]) -> ok | {error, posix()}.
(FreeBSD only) cap_ioctls_limit(2) : set allowed ioctl(2) commands on file descriptor
Link to this function

cap_rights_limit(Task, Arg1, Arg2)

View Source

Specs

cap_rights_limit(task(), fd(), [constant()]) -> ok | {error, posix()}.
(FreeBSD only) cap_rights_limit(2) : set allowed rights(4) of file descriptor

Specs

chdir(task(), iodata()) -> ok | {error, posix()}.
chdir(2) : change process current working directory

Specs

chmod(task(), iodata(), mode_t()) -> ok | {error, posix()}.
chmod(2) : change file permissions
Link to this function

chown(Task, Arg1, Arg2, Arg3)

View Source

Specs

chown(task(), iodata(), uid_t(), gid_t()) -> ok | {error, posix()}.
chown(2) : change file ownership

Specs

chroot(task(), iodata()) -> ok | {error, posix()}.
chroot(2) : change root directory

Specs

clearenv(task()) -> ok | {error, posix()}.
clearenv(3) : zero process environment

Specs

clone(task(), [constant()]) -> {ok, task()} | {error, posix()}.
(Linux only) clone(2) : create a new process

Specs

close(task(), fd()) -> ok | {error, posix()}.
close(2) : close a file descriptor

Specs

cmd(task(), [iodata()]) -> binary() | {error, posix()}.
Link to this function

controlling_process(Task, Pid)

View Source

Specs

controlling_process(task(), pid()) -> ok | {error, badarg}.

Assign a new process owner.

call mode: the controlling process is allowed to make calls to the prx process.

exec mode: the controlling process receives standard output and standard error from the prx process

Specs

cpid(task()) -> [cpid()].

Returns the list of child PIDs for this process.

Each child task is a map composed of: * pid: system pid * exec: true if the child has called exec() * fdctl: parent end of CLOEXEC file descriptor used to monitor if the child process has called exec() * stdin: parent end of the child process' standard input * stdout: parent end of the child process' standard output * stderr: parent end of the child process' standard error

Specs

cpid(task(), task() | pid_t()) -> cpid() | error.

Retrieve process info for forked processes.

Retrieve the map for a child process as returned in prx:cpid/1.

cpid/2 searches the list of a process' children for a PID (an erlang or a system PID) and returns a map containing the parent's file descriptors towards the child.

Specs

drv(task()) -> pid().

Specs

environ(task()) -> [binary()].
environ(7) : return the process environment variables

Specs

eof(task(), task() | pid_t()) -> ok | {error, posix()}.
Close stdin of child process.

Specs

eof(task(), task() | pid_t(), stdin | stdout | stderr) -> ok | {error, posix()}.
Close stdin, stdout or stderr of child process.

Specs

execed(task()) -> boolean().

Test if the task has called exec(2).

Returns true if the task is running in exec mode.

Specs

execve(task(), [iodata()], [iodata()]) -> ok | {error, posix()}.
execve(2) : replace the process image, specifying the environment for the new process image.
Link to this function

execve(Task, Arg0, Argv, Env)

View Source

Specs

execve(task(), iodata(), [iodata()], [iodata()]) -> ok | {error, posix()}.

execve(2) : replace the process image, specifying the environment for the new process image.

Allows setting the command name in the process list:
  prx:execve(Task, "/bin/cat", ["name-in-process-list", "-n"], ["VAR=1"])

Specs

execvp(task(), [iodata()]) -> ok | {error, posix()}.
execvp(2) : replace the current process image using the search path
Link to this function

execvp(Task, Arg0, Argv)

View Source

Specs

execvp(task(), iodata(), [iodata()]) -> ok | {error, posix()}.

execvp(2) : replace the current process image using the search path

Allows setting the command name in the process list:
  prx:execvp(Task, "cat", ["name-in-process-list", "-n"])

Specs

exit(task(), int32_t()) -> ok.
exit(3) : cause the child process to exit

Specs

fcntl(task(), fd(), constant()) -> {ok, int64_t()} | {error, posix()}.
fcntl(2) : perform operation on a file descriptor
Link to this function

fcntl(Task, Arg1, Arg2, Arg3)

View Source

Specs

fcntl(task(), fd(), constant(), int64_t()) -> {ok, int64_t()} | {error, posix()}.
fcntl(2) : perform operation on a file descriptor with argument
Link to this function

fexecve(Task, FD, Argv, Env)

View Source

Specs

fexecve(task(), int32_t(), [iodata()], [iodata()]) -> ok | {error, posix()}.
fexecve(2) : replace the process image, specifying the environment for the new process image, using a previously opened file descriptor. The file descriptor can be set to close after exec() by passing the O_CLOEXEC flag to open:
  {ok, FD} = prx:open(Task, "/bin/ls", [o_rdonly,o_cloexec]),
  ok = prx:fexecve(Task, FD, ["-al"], ["FOO=123"]).

Linux and FreeBSD only. Linux requires an environment be set unlike with execve(2). The environment can be empty:

  % Environment required on Linux
  ok = prx:fexecve(Task, FD, ["-al"], [""]),
  [<<>>] = prx:environ(Task).

Specs

filter(task(), [call()] | {allow, [call()]} | {deny, [call()]}) -> ok.

filter/2 : restrict control process calls

Restricts the set of calls available to a prx control process. If fork is allowed, any subsequently forked control processes inherit the set of filtered calls:

  {ok, Ctrl} = prx:fork(),
  ok = prx:filter(Ctrl, [getpid]),
  {ok, Task} = prx:fork(Ctrl),
 
  {'EXIT', {undef, _}} = (catch prx:getpid(Task)).
To specify filtered calls for subprocesses, see filter/3.
Link to this function

filter(Task, Calls, Calls1)

View Source

Specs

filter(task(),
       [call()] | {allow, [call()]} | {deny, [call()]},
       [call()] | {allow, [call()]} | {deny, [call()]}) ->
          ok.

filter/3 : restrict control process and subprocess calls

filter/3 specifies the set of calls available to a prx control process and any subsequently forked control processes. Control processes continue to proxy data and monitor and reap subprocesses.

Invoking a filtered call will crash the process with 'undef'.

If the filter/3 call is filtered, subsequent calls to filter/3 will fail.

Calls can be either whitelisted or blacklisted. If a call is whitelisted, all other calls are filtered.

Once a filter for a call is added, the call cannot be removed from the filter set. Passing an empty list ([]) specifies the current filter set should not be modified.

  % the set of calls to filter, any forked control subprocesses
  % are unrestricted
  prx:filter(Task, {deny, [getpid, execve, execvp]}, [])
 
  % equivalent to {deny, [getpid, execve, execvp]}
  prx:filter(Task, [getpid, execve, execvp], [])
 
  % all other calls are filtered including filter
  prx:filter(Task, {allow, [fork, clone, kill]}, [])
 
  % init: control process can fork, subprocesses can exec a data process
  prx:filter(Task, {allow, [fork, clone, kill]}, {allow, [execve, execvp]})

Specs

fork() -> {ok, task()} | {error, posix()}.

fork(2) : create a new system process

The behaviour of the process can be controlled by setting the application environment:

  Option = {exec, string()}
   | {progname, string()}
   | {ctldir, string()}

* {exec, Exec}

Default: ""

Sets a command to run the port under such as sudo or valgrind.

For example, to start the process as root using sudo, allow running prx as root:

   sudo visudo -f /etc/sudoers.d/99_prx
   <user> ALL = NOPASSWD: /path/to/prx/priv/prx
   Defaults!/path/to/alcove/priv/alcove !requiretty
   ```
 
   Then:
 
   ```
   application:set_env(prx, options, [{exec, "sudo -n"}])

* {progname, Path}

Default: priv/prx

Sets the path to the prx executable.

* {ctldir, Path}

Default: priv

A control directory writable by the prx port process (the Unix process may be running under a different user than the Erlang VM).

The control directory contains a FIFO shared by beam and the port process which is used to notify the Erlang VM that the port process has called exec().

Specs

fork(task()) -> {ok, task()} | {error, posix()}.

fork(2) : create a child process

Forks child processes from an existing task. For example:

  {ok, Task} = prx:fork(),             % PID 16341
  {ok, Child1} = prx:fork(Task),       % PID 16349
  {ok, Child2} = prx:fork(Task),       % PID 16352
  {ok, Child2a} = prx:fork(Child2),    % PID 16354
  {ok, Child2aa} = prx:fork(Child2a),  % PID 16357
  {ok, Child2ab} = prx:fork(Child2a).  % PID 16482

Results in a process tree:

  prx(16341)-+-prx(16349)
             `-prx(16352)---prx(16354)-+-prx(16357)
                                       `-prx(16482)

Specs

forkchain(task()) -> [pid_t()].

Specs

getcpid(task(), atom()) -> int32_t() | false.

getcpid() : get options for child process of prx control process

Control behaviour of an exec()'ed process.

See getcpid/3 for options.

Specs

getcpid(task(), task() | cpid() | pid_t(), atom()) -> int32_t() | false.

getcpid() : retrieve attributes set by the prx control process for a child process

* flowcontrol: number of messages allowed from process

-1 : flowcontrol disabled 0 : stdout/stderr for process is not read 0+ : read this many messages from the process

* signaloneof: signal sent to child process on shutdown

Specs

getcwd(task()) -> {ok, binary()} | {error, posix()}.
getcwd(3) : return the current working directory

Specs

getenv(task(), iodata()) -> binary() | false.
getenv(3) : retrieve an environment variable

Specs

getgid(task()) -> gid_t().
getgid(2) : retrieve the processes' group ID

Specs

getgroups(task()) -> {ok, [gid_t()]} | {error, posix()}.
getgroups(2) : retrieve the list of supplementary groups

Specs

gethostname(task()) -> {ok, binary()} | {error, posix()}.
gethostname(2) : retrieve the system hostname

Specs

getopt(task(), prx_opt()) -> false | int32_t().

getopt() : get options for the prx control process

Retrieve port options for a prx control process. These options are configurable per process, with the default settings inherited from the parent.

The initial values for these options are set for the port by prx:fork/0:

maxchild : non_neg_integer() : (ulimit -n) / 4 - 4

Number of child processes allowed for this process. This value can be modified by adjusting RLIMIT_NOFILE for the process.

exit_status : 1 | 0 : 1

Controls whether the controlling Erlang process is informed of a process' exit value.

maxforkdepth : non_neg_integer() : 16

Sets the maximum length of the fork chain.

termsig : 1 | 0 : 1

If a child process exits because of a signal, notify the controlling Erlang process.

flowcontrol : int32_t() : -1 (disabled)

Sets the default flow control behaviour for a newly forked process. Flow control is applied after the child process calls exec().

See setcpid/3,4.

signaloneof : 0-254 : 15

Send a signal to a child process on shutdown (stdin of the alcove control process is closed).

See setcpid/3,4.

Specs

getpgrp(task()) -> pid_t().
getpgrp(2) : retrieve the process group

Specs

getpid(task()) -> pid_t().
getpid(2) : retrieve the system PID of the process
Link to this function

getpriority(Task, Arg1, Arg2)

View Source

Specs

getpriority(task(), constant(), int32_t()) -> {ok, int32_t()} | {error, posix()}.
getpriority(2) : retrieve scheduling priority of process process group or user

Specs

getresgid(task()) -> {ok, gid_t(), gid_t(), gid_t()} | {error, posix()}.

getresgid(2) : get real, effective and saved group ID

Supported on Linux and BSD's.

Specs

getresuid(task()) -> {ok, uid_t(), uid_t(), uid_t()} | {error, posix()}.

getresuid(2) : get real, effective and saved user ID

Supported on Linux and BSD's.
Link to this function

getrlimit(Task, Resource)

View Source

Specs

getrlimit(task(), constant()) -> {ok, #{cur => uint64_t(), max => uint64_t()}} | {error, posix()}.
getrlimit(2) : retrieve the resource limits for a process

Specs

getsid(task(), pid_t()) -> {ok, pid_t()} | {error, posix()}.
getsid(2) : retrieve the session ID

Specs

getuid(task()) -> uid_t().
getuid(2) : returns the process user ID
Link to this function

ioctl(Task, Arg1, Arg2, Arg3)

View Source

Specs

ioctl(task(), fd(), constant(), cstruct()) ->
         {ok, #{return_value := integer(), arg := iodata()}} | {error, posix()}.

ioctl(2) : control device

Controls a device using a file descriptor previously obtained using open/4.

Argp can be either a binary or a list representation of a C struct. See prctl/6 below for a description of the list elements.

On success, ioctl/4 returns a 2-tuple containing a map. The map keys are:

return_value: an integer equal to the return value of the ioctl.

Usually 0, however some ioctl's on Linux use the return value as the output parameter.

arg: the value depends on the type of the input parameter Argp.

cstruct: contains the contents of the memory pointed to by Argp

integer/binary: an empty binary

An example of creating a tap device in a net namespace on Linux:

  {ok, Child} = prx:clone(Task, [clone_newnet]),
  {ok, FD} = prx:open(Child, "/dev/net/tun", [o_rdwr], 0),
  {ok, #{return_value = 0, arg = <<"tap", N, _/binary>>}} = prx:ioctl(Child, FD,
      tunsetiff, <<
      0:(16*8), % generate a tuntap device name
      (16#0002 bor 16#1000):2/native-unsigned-integer-unit:8, % IFF_TAP, IFF_NO_PI
      0:(14*8)
      >>),
  {ok, <<"tap", N>>}.

Specs

jail(task(),
     #{version => alcove:uint32_t(),
       path => iodata(),
       hostname => iodata(),
       jailname => iodata(),
       ip4 => [inet:ip4_address()],
       ip6 => [inet:ip6_address()]} |
     cstruct()) ->
        {ok, int32_t()} | {error, posix()}.
(FreeBSD only) jail(2) : restrict the current process in a system jail

Specs

kill(task(), pid_t(), constant()) -> ok | {error, posix()}.
kill(2) : terminate a process
Link to this function

lseek(Task, Arg1, Arg2, Arg3)

View Source

Specs

lseek(task(), fd(), off_t(), int32_t()) -> ok | {error, posix()}.
lseek(2) : set file offset for read/write

Specs

mkdir(task(), iodata(), mode_t()) -> ok | {error, posix()}.
mkdir(2) : create a directory
Link to this function

mkfifo(Task, Arg1, Arg2)

View Source

Specs

mkfifo(task(), iodata(), mode_t()) -> ok | {error, posix()}.
mkfifo(3) : create a named pipe
Link to this function

mount(Task, Arg1, Arg2, Arg3, Arg4, Arg5)

View Source

Specs

mount(task(), iodata(), iodata(), iodata(), uint64_t() | [constant()], iodata()) ->
         ok | {error, posix()}.

mount(2) : mount a filesystem, Linux style

The arguments are:

* source * target * filesystem type * flags * data

An empty binary may be used to specify NULL.

For example, filesystems mounted in a Linux mount namespace may be visible in the global mount namespace. To avoid this, first remount the root filesystem within mount namespace using the MS_REC|MS_PRIVATE flags:

  {ok, Task} = prx:clone(Parent, [clone_newns]),
  ok = prx:mount(Task, "none", "/", <<>>, [ms_rec, ms_private], <<>>).

On BSD systems, the Source argument is ignored and passed to the system mount call as:

mount(FSType, Target, Flags, Data);
Link to this function

mount(Task, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)

View Source

Specs

mount(task(), iodata(), iodata(), iodata(), uint64_t() | [constant()], iodata(), iodata()) ->
         ok | {error, posix()}.

(Solaris only) mount(2) : mount a filesystem

On Solaris, some mount options are passed in the Options argument as a string of comma separated values terminated by a NULL. Other platforms ignore the Options parameter.

Specs

open(task(), iodata(), int32_t() | [constant()]) -> {ok, fd()} | {error, posix()}.

open(2) : returns a file descriptor associated with a file

Lists of values are OR'ed:

  prx:open(Task, "/etc/motd", [o_rdonly])
Link to this function

open(Task, Arg1, Arg2, Arg3)

View Source

Specs

open(task(), iodata(), int32_t() | [constant()], mode_t()) -> {ok, fd()} | {error, posix()}.

open(2) : create a file, specifying permissions

  prx:open(Task, "/tmp/test", [o_wronly,o_creat], 8#644)

Specs

parent(task()) -> task() | noproc.

Specs

pidof(task()) -> pid_t() | noproc.

Retrieves the system PID of the process similar to getpid(2).

Returns the cached value for the PID of the system process.
  OSPid = prx:getpid(Task),
  OSPid = prx:pidof(Task).
Link to this function

pivot_root(Task, Arg1, Arg2)

View Source

Specs

pivot_root(task(), iodata(), iodata()) -> ok | {error, posix()}.
(Linux only) pivot_root(2) : change the root filesystem
Link to this function

pledge(Task, Arg1, Arg2)

View Source

Specs

pledge(task(), iodata() | null, iodata() | null) -> ok | {error, posix()}.
(OpenBSD only) pledge(2) : restrict system operations
  prx:pledge(Task, "stdio proc exec", [])
Link to this function

prctl(Task, Arg1, Arg2, Arg3, Arg4, Arg5)

View Source

Specs

prctl(task(), constant(), ptr_arg(), ptr_arg(), ptr_arg(), ptr_arg()) ->
         {ok, integer(), ptr_val(), ptr_val(), ptr_val(), ptr_val()} | {error, posix()}.

(Linux only) prctl(2) : operations on a process

This function can be used to set BPF syscall filters on processes (seccomp mode).

A list can be used for prctl operations requiring a C structure as an argument. List elements are used to contiguously populate a buffer (it is up to the caller to add padding):

* binary(): the element is copied directly into the buffer

On return, the contents of the binary is returned to the caller.

* {ptr, N}: N bytes of zero'ed memory is allocated. The pointer is placed in the buffer.

On return, the contents of the memory is returned to the caller.

* {ptr, binary()}

Memory equal to the size of the binary is allocated and initialized with the contents of the binary.

On return, the contents of the memory is returned to the caller.

For example, to enforce a seccomp filter:

  % NOTE: this filter will result in the port being sent a SIGSYS
 
  % The prx process requires the following syscalls to run:
  %    sys_exit
  %    sys_exit_group
  %    sys_getrlimit
  %    sys_poll
  %    sys_read
  %    sys_restart_syscall
  %    sys_rt_sigreturn
  %    sys_setrlimit
  %    sys_sigreturn
  %    sys_ugetrlimit
  %    sys_write
  %    sys_writev
 
  Arch = prx:call(Task, syscall_constant, [alcove:audit_arch]),
  Filter = [
      ?VALIDATE_ARCHITECTURE(Arch),
      ?EXAMINE_SYSCALL,
      sys_read,
      sys_write
  ],
 
  {ok,_,_,_,_,_} = prx:prctl(Task, pr_set_no_new_privs, 1, 0, 0, 0),
  Pad = (erlang:system_info({wordsize,external}) - 2) * 8,
 
  Prog = [
      <<(iolist_size(Filter) div 8):2/native-unsigned-integer-unit:8>>,
      <<0:Pad>>,
      {ptr, list_to_binary(Filter)}
  ],
  prx:prctl(Task, pr_set_seccomp, seccomp_mode_filter, Prog, 0, 0).
Link to this function

procctl(Task, Arg1, Arg2, Arg3, Arg4)

View Source

Specs

procctl(task(), constant(), pid_t(), constant(), [] | cstruct()) ->
           {ok, binary(), cstruct()} | {error, posix()}.

(FreeBSD only) procctl(2) : control processes

  Pid = prx:pidof(Task),
  prx:procctl(Task, 0, Pid, 'PROC_REAP_ACQUIRE', []),
  prx:procctl(Task, p_pid, Pid, 'PROC_REAP_STATUS', [
     <<0,0,0,0>>, % rs_flags
     <<0,0,0,0>>, % rs_children
     <<0,0,0,0>>, % rs_descendants
     <<0,0,0,0>>, % rs_reaper
     <<0,0,0,0>>  % rs_pid
  ]).
Link to this function

ptrace(Task, Arg1, Arg2, Arg3, Arg4)

View Source

Specs

ptrace(task(), constant(), pid_t(), ptr_arg(), ptr_arg()) ->
          {ok, integer(), ptr_val(), ptr_val()} | {error, posix()}.
(Linux only) ptrace(2) : trace processes

Specs

read(task(), fd(), size_t()) -> {ok, binary()} | {error, posix()}.
read(2) : read bytes from a file descriptor

Specs

readdir(task(), iodata()) -> {ok, [binary()]} | {error, posix()}.
readdir(3) : retrieve list of objects in a directory

Specs

reexec(task()) -> ok | {error, posix()}.

Fork+exec prx process.

Fork+exec is a way of randomizing the memory space of a process:

https://poolp.org/posts/2016-09-12/opensmtpd-6.0.0-is-released/

prx processes fork recursively: * the calls stack increases in size * the memory space layout is identical to the parent

After forking a prx process using fork/1, the controlling process will typically instruct the new prx process to execute a command using one of the exec(3) functions: execvp/2, execve/3.

Some "system" or "supervisor" type processes may remain in call mode: these processes can call reexec/1 to exec() the port.

On platforms supporting fexecve(2) (FreeBSD, Linux), prx will open a file descriptor to the port binary and use it to re-exec() the port.

On other OS'es, execve(2) will be used with the the default path to the port binary.

If the binary is not accessible or, on Linux, /proc is not mounted, reexec/1 will fail.

Specs

reexec(task(), {fd, int32_t(), iodata()} | iodata(), iodata()) -> ok | {error, posix()}.

Replace the port process image using execve(2)/fexecve(2).

Specify the port program path or a file descriptor to the binary and the process environment.
Link to this function

replace_process_image(Task)

View Source

Specs

replace_process_image(task()) -> ok | {error, posix()}.
Alias for reexec/1.
Link to this function

replace_process_image(Task, Argv, Env)

View Source

Specs

replace_process_image(task(), {fd, int32_t(), iodata()} | iodata(), iodata()) ->
                         ok | {error, posix()}.
Alias for reexec/3.

Specs

rmdir(task(), iodata()) -> ok | {error, posix()}.
rmdir(2) : delete a directory
Link to this function

seccomp(Task, Arg1, Arg2, Arg3)

View Source

Specs

seccomp(task(), constant(), constant(), cstruct()) -> ok | {error, posix()}.

seccomp(2) : restrict system operations

See prctl/6.
Link to this function

select(Task, Readfds, Writefds, Exceptfds, Timeout)

View Source

Specs

select(task(), [fd()], [fd()], [fd()], null | 'NULL' | #{sec => int64_t(), usec => int64_t()}) ->
          {ok, [fd()], [fd()], [fd()]} | {error, posix()}.

select(2) : poll a list of file descriptor for events

select/5 will block until an event occurs on a file descriptor, a timeout is reached or interrupted by a signal.

The Timeout value may be:

* null (block forever)

* a map containing:
    sec : number of seconds to wait
    usec : number of microseconds to wait
For example:
  {ok,[],[],[]} = prx:select(Task, [], [], [], #{sec => 10, usec => 100}).

Specs

setcpid(task(), atom(), int32_t()) -> boolean().

setcpid() : Set options for child process of prx control process

Control behaviour of an exec()'ed process.

See setcpid/4 for options.
Link to this function

setcpid(Task, Pid, Opt, Val)

View Source

Specs

setcpid(task(), task() | cpid() | pid_t(), atom(), int32_t()) -> boolean().

setcpid() : Set options for child process of prx control process

* flowcontrol: enable rate limiting of the stdout and stderr of a child process. stdin is not rate limited (default: -1 (disabled))

0 : stdout/stderr for process is not read 1-2147483646 : read this many messages from the process -1 : disable flow control

NOTE: the limit applies to stdout and stderr. If the limit is set to 1, it is possible to get:

* 1 message from stdout * 1 message from stderr * 1 message from stdout and stderr

* signaloneof: the prx control process sends this signal to the child process on shutdown (default: 15 (SIGTERM))
Link to this function

setenv(Task, Arg1, Arg2, Arg3)

View Source

Specs

setenv(task(), iodata(), iodata(), int32_t()) -> ok | {error, posix()}.
setenv(3) : set an environment variable

Specs

setgid(task(), gid_t()) -> ok | {error, posix()}.
setgid(2) : set the GID of the process

Specs

setgroups(task(), [gid_t()]) -> ok | {error, posix()}.
setgroups(2) : set the supplementary groups of the process

Specs

sethostname(task(), iodata()) -> ok | {error, posix()}.

sethostname(2) : set the system hostname

This function is probably only useful if running in a uts namespace:

  {ok, Child} = prx:clone(Task, [clone_newuts]),
  ok = prx:sethostname(Child, "test"),
  Hostname1 = prx:gethostname(Task),
  Hostname2 = prx:gethostname(Child),
  Hostname1 =/= Hostname2.

Specs

setns(task(), iodata()) -> ok | {error, posix()}.

(Linux only) setns(2) : attach to a namespace

A process namespace is represented as a path in the /proc filesystem. The path is /proc/<pid>/ns/<ns>, where:

* pid = the system PID

* ns = a file representing the namespace

The available namespaces is dependent on the kernel version. You can see which are supported by running:

   ls -al /proc/$$/ns

For example, to attach to another process' network namespace:

  {ok, Child1} = prx:clone(Task, [clone_newnet]),
  {ok, Child2} = prx:fork(Task),
 
  % Move Child2 into the Child1 network namespace
  {ok,FD} = prx:open(Child2,
   ["/proc/", integer_to_list(Child1), "/ns/net"], [o_rdonly], 0),
  ok = prx:setns(Child2, FD, 0),
  ok = prx:close(Child2, FD).

Specs

setns(task(), iodata(), constant()) -> ok | {error, posix()}.

(Linux only) setns(2) : attach to a namespace, specifying namespace type

  ok = prx:setns(Task, FD, clone_newnet)
Link to this function

setopt(Task, Arg1, Arg2)

View Source

Specs

setopt(task(), prx_opt(), int32_t()) -> boolean().

setopt() : set options for the prx control process

See getopt/3 for options.
Link to this function

setpgid(Task, Arg1, Arg2)

View Source

Specs

setpgid(task(), pid_t(), pid_t()) -> ok | {error, posix()}.
setpgid(2) : set process group
Link to this function

setpriority(Task, Arg1, Arg2, Arg3)

View Source

Specs

setpriority(task(), constant(), int32_t(), int32_t()) -> ok | {error, posix()}.
setpriority(2) : set scheduling priority of process, process group or user
Link to this function

setproctitle(Task, Name)

View Source

Specs

setproctitle(task(), iodata()) -> ok.

setproctitle(3) : set the process title

Set the process title displayed in utilities like ps(1).

Linux systems may also want to set the command name using prctl/6:

  prx:prctl(Task, pr_set_name, <<"newname">>, 0, 0, 0)
Link to this function

setresgid(Task, Arg1, Arg2, Arg3)

View Source

Specs

setresgid(task(), gid_t(), gid_t(), gid_t()) -> ok | {error, posix()}.

setresgid(2) : set real, effective and saved group ID

Supported on Linux and BSD's.
Link to this function

setresuid(Task, Arg1, Arg2, Arg3)

View Source

Specs

setresuid(task(), uid_t(), uid_t(), uid_t()) -> ok | {error, posix()}.

setresuid(2) : set real, effective and saved user ID

Supported on Linux and BSD's.
Link to this function

setrlimit(Task, Resource, Rlim)

View Source

Specs

setrlimit(task(), constant(), #{cur => uint64_t(), max => uint64_t()}) -> ok | {error, posix()}.
setrlimit(2) : set a resource limit

Specs

setsid(task()) -> {ok, pid_t()} | {error, posix()}.
setsid(2) : create a new session

Specs

setuid(task(), uid_t()) -> ok | {error, posix()}.
setuid(2) : change UID

Specs

sh(task(), iodata()) -> binary() | {error, posix()}.
Link to this function

sigaction(Task, Signal, Arg2)

View Source

Specs

sigaction(task(),
          constant(),
          atom() | {sig_info, fun((pid(), [pid_t()], atom(), binary()) -> any())}) ->
             {ok, atom()} | {error, posix()}.

sigaction(2) : set process behaviour for signals

* sig_dfl : uses the default behaviour for the signal

* sig_ign : ignores the signal

* sig_info : catches the signal and sends the controlling Erlang process an event: {signal, atom(), Info}

'Info' is a binary containing the siginfo_t structure. See sigaction(2) for details.

* <<>> : retrieve current handler for signal

Multiple caught signals of the same type may be reported as one event.
Link to this function

socket(Task, Arg1, Arg2, Arg3)

View Source

Specs

socket(task(), constant(), constant(), int32_t()) -> {ok, fd()} | {error, posix()}.

socket(2) : retrieve file descriptor for communication endpoint

  {ok, FD} = prx:socket(Task, af_inet, sock_stream, 0).

Specs

start_link(pid()) -> {ok, task()} | {error, posix()}.

Specs

stdin(task(), iodata()) -> ok.
Send data to the standard input of the process.

Specs

stdio(task(), pid()) -> ok | {error, badarg}.

Assign a process to receive stdio.

Change the process receiving prx standard output and standard error.

stdio/2 and controlling_process/2 can be used to transfer a prx process between erlang processes without losing output when exec(3) is called:

~~~ ok = prx:stdio(Owner, NewOwner), ok = prx:execvp(Owner, Argv), ok = prx:controlling_process(Owner, NewOwner). ~~~

Specs

stop(task()) -> ok.
Terminate the task.

Specs

sudo() -> ok.

Convenience function to fork a privileged process in the shell.

Sets the application environment so prx can fork a privileged process. sudo must be configured to run the prx binary.

The application environment must be set before prx:fork/0 is called.

Equivalent to:
  application:set_env(prx, options, [{exec, "sudo -n"}]),
  {ok, Task} = prx:fork(),
  0 = prx:getuid(Task).

Specs

sudo(string()) -> ok.

Convenience function to fork a privileged process in the shell.

Allows specifying the command. For example, on OpenBSD:
  prx:sudo("doas"),
  {ok, Task} = prx:fork(),
  0 = prx:getuid(Task).

Specs

task(task(), [prx_task:op() | [prx_task:op()]], any()) -> {ok, task()} | {error, posix()}.
Link to this function

task(Task, Ops, State, Config)

View Source

Specs

task(task(), [prx_task:op() | [prx_task:op()]], any(), [prx_task:config()]) ->
        {ok, task()} | {error, posix()}.

Specs

umount(task(), iodata()) -> ok | {error, posix()}.

umount(2) : unmount a filesystem

On BSD systems, calls unmount(2).
Link to this function

umount2(Task, Arg1, Arg2)

View Source

Specs

umount2(task(), iodata(), [constant()]) -> ok | {error, posix()}.

umount2(2) : unmount a filesystem

On BSD systems, calls unmount(2).

Specs

unlink(task(), iodata()) -> ok | {error, posix()}.
unlink(2) : delete references to a file

Specs

unsetenv(task(), iodata()) -> ok | {error, posix()}.
unsetenv(3) : remove an environment variable

Specs

unshare(task(), int32_t() | [constant()]) -> ok | {error, posix()}.

(Linux only) unshare(2) : allows creating a new namespace in the current process

unshare(2) lets you make a new namespace without calling clone(2):

  % The port is now running in a namespace without network access.
  ok = prx:unshare(Task, [clone_newnet]).
Link to this function

unveil(Task, Arg1, Arg2)

View Source

Specs

unveil(task(), iodata() | null, iodata() | null) -> ok | {error, posix()}.
(OpenBSD only) unveil(2) : restrict filesystem view
  prx:unveil(Task, "/bin", "rx")
Link to this function

waitpid(Task, Arg1, Arg2)

View Source

Specs

waitpid(task(), pid_t(), int32_t() | [constant()]) ->
           {ok, pid_t(), int32_t(), [waitstatus()]} | {error, posix()}.

waitpid(2) : wait for child process

To use waitpid/3, disable handling of child processes by the event loop:

  {ok, sig_dfl} = prx:sigaction(Task, sigchld, sig_info),
  {ok, Child} = prx:fork(Task),
  Pid = prx:getpid(Child),
  ok = prx:exit(Child, 2),
  {ok, Pid, _, [{exit_status, 2}]} = prx:waitpid(Task, Pid, [wnohang]).

Specs

write(task(), fd(), iodata()) -> {ok, ssize_t()} | {error, posix()}.

write(2): write to a file descriptor

Writes a buffer to a file descriptor, returning the number of bytes written.