Commit Graph

86 Commits

Author SHA1 Message Date
Michael Santos
24da8cbfa0 stream test: use receive
Use a receive with timeout rather than polling the mailbox.
2014-08-30 11:25:33 -04:00
Michael Santos
cb690bcab5 test: stream data through fork chain 2014-08-30 10:55:15 -04:00
Michael Santos
fdb1ebb0ae Improve iolist handling
Support bytes in iolists. Imitate iolist_to_binary/1 and accept strings,
binaries and lists of binaries, lists and bytes.

Unlike the real iolist_to_binary, this version places an arbitrary limit
of 16 nested lists.
2014-08-18 09:37:42 -04:00
Michael Santos
bb9eb9f338 Remove alcove_stats 2014-08-10 12:24:12 -04:00
Michael Santos
56857281f8 Crash if call/2,3,4,5 reaches the timeout
To ensure consistency, exit if a timeout is set and reached. Otherwise,
late messages may arrive in the queue, messing up subsequent calls:

    1> {ok,P} = alcove_drv:start().
    {ok,<0.45.0>}
    2> catch alcove:call(P, [], getpid, [], 0).
    {'EXIT',timeout}
    3> alcove:version(P).
    2897
    4> flush().
    Shell got {alcove_call,<0.45.0>,[],<<"0.6.1">>}
    ok

Using timeouts might be needed if it is not known whether is still
running in the event loop.

Remove the cast functions, since they are dangerous and can be emulated
by using call/5.
2014-08-04 16:26:18 -04:00
Michael Santos
bc84d869d3 Add test for writing to invalid PIDs 2014-08-03 10:23:18 -04:00
Michael Santos
bb94149c09 Use writev(2) for stdio
Begin cleanup of code by replacing usage of write + malloc with writev.
2014-07-26 10:27:35 -04:00
Michael Santos
ace0cd5724 Run chroot tests on openbsd
Skip tests on unsupported platforms.
2014-07-21 07:58:35 -04:00
Michael Santos
9149b4c1d4 tests: run alloc test on all platforms
Currently, alloc/2,3 tests functionality that only is needed for linux
(for seccomp mode). Run the tests on other plaforms like freebsd, so we
can catch any bugs.
2014-07-18 12:26:37 -04:00
Michael Santos
f25c9377bb Correct type for version/1,2
Calls now have an infinite timeout.
2014-07-09 10:07:36 -04:00
Michael Santos
43030ab2a6 setopt/3,4: clean up
Cleanup of the setopt function:

* use an unsigned integer for holding the arg

* add a typespec for setopt/3,4.

* change the return value to true/false

Previously, if an unknown option was passed to setopt, the process would
crash with badarg. Reserve badarg for wrong types and return a value to
the caller.

inet:getopts/setopts take a list of options. If any of the options are
invalid, {error,einval} is returned to the caller. The valid options are
not changed.

alcove:getopt/2,3 returns an unsigned integer or false if the option is
not supported.

alcove:getopt,setopt will (should?) never fail if a valid argument is
used. So replying with an ok tuple, like the inet functions, is not necessary.

So setopt could more exactly return 'ok' and 'invalid' or 'not_found'
(diverging from getopt) or it could follow getopt and return ok/false,
which, to be more consistent, should be a boolean.
2014-06-27 10:25:29 -04:00
Michael Santos
296cdc911e seccomp/allow_syscall: remove the call to port
The macro should be a "pure" function. Remove the call to the port. This
forces the caller to catch the case where a syscall does not exist on a
particular platform.
2014-06-21 10:33:21 -04:00
Michael Santos
b12386458a tests: remove unused var 2014-06-20 11:06:34 -04:00
Michael Santos
7ea1404ebb seccomp: move macros to header
Move the BPF generation macros to the header file. This needs further
cleanup:

* some of the macros require the port pid, others do not

* some of the macros refer to functions

* some of the raw BPF statements should be wrapped in a function or
  macro
2014-06-20 10:53:37 -04:00
Michael Santos
3b89edf91a Fix dialzyer errors 2014-06-19 10:05:34 -04:00
Michael Santos
bb7bc1665f tests: skip tests on unsupported OS'es 2014-06-18 10:32:11 -04:00
Michael Santos
32d898f552 tests/seccomp: no tests on unsupported os'es 2014-06-17 13:32:48 -04:00
Michael Santos
91d6da74a2 tests: check for seccomp mode support 2014-06-16 11:33:08 -04:00
Michael Santos
dc2a102275 test: fix return value of trapped syscall
On some systems (Linux 3.8.11 armv7l), the return value of a trapped call
is {error,unknown}.

On other systems (Linux 3.13.0-24-generic x86_64), the return value is
{ok,<<>>}.

Could be a bug on ARM, but accomodate multiple return values for now.
2014-06-16 11:10:47 -04:00
Michael Santos
1e08427fe4 test: rough test for seccomp mode 2014-06-16 11:07:17 -04:00
Michael Santos
99e4cd4ba3 test: allocated buffer for prctl 2014-06-15 10:41:05 -04:00
Michael Santos
3db7a623ca Fix race condition when exit/2,3 called
Fixes issue in commit 1003087.

Depending on the order when the fd's are closed, the control socket
could return from poll after the pid was zero'ed. Since the event loop
uses an event on the control fd to return an 'ok' message, the erlang
process would block forever in receive, waiting for a response from the
port.
2014-05-13 07:45:04 -04:00
Michael Santos
1003087ef9 tests: eof tests hangs on some systems
Clean up after the forkchain test by forcing the top level process to
exit.

On some systems, the eof test would hang while forcing the process to
exit. Not sure why, this cleanup just covers up the problem.
2014-05-11 15:42:55 -04:00
Michael Santos
310b246e2d Use a namespace: #rlimit{} -> #alcove_rlimit{} 2014-05-09 10:41:38 -04:00
Michael Santos
1b689de29f Disable sigchld events by default 2014-04-23 08:13:02 -04:00
Michael Santos
26a207d876 Stream messages from port through a proxy process
Convert the binary format messages from the port into erlang terms using
a gen_server.
2014-04-22 14:16:06 -04:00
Michael Santos
f4c320ba50 Check for invalid fd's
Add a test for closing stdio. The final test (closing stdin) is marked
as passing if {error,esrch} or {error,ebadf} is returned because there
is a race condition: the event loop may not have noticed the fd is
closed depending on how quickly the test is run.
2014-04-21 12:23:29 -04:00
Michael Santos
737e3f3dbe tests: restore wait after exit
On slow systems, the child will not have exited before the next fork.
2014-04-16 14:31:15 -04:00
Michael Santos
5ba36d4cb6 tests: set exec program, disable clone
To support running the tests under valgrind, add two environment
variables:

    ALCOVE_TEST_EXEC : set the {exec, string()} parameter to
                       alcove_drv:start/1.

    ALCOVE_TEST_USE_FORK : use fork() instead of clone()

For example:

    ALCOVE_TEST_EXEC="sudo valgrind --leak-check=yes --log-file=alcove.log" \
        ALCOVE_TEST_USE_FORK=1 make test
2014-04-16 13:10:12 -04:00
Michael Santos
baabad5216 tests: call exit during forkstress
On slow systems, the process may not have exited from a kill before the
next process is started, causing the test to fail with {error,eagain}.
2014-04-06 12:03:52 -04:00
Michael Santos
cae994fd02 define/2: convert an atom to an integer
Remove define/3. Figure out the function to call based on the name of
the flag.

The behaviour of this function is to crash if passed an unknown
constant. There are 2 ways it can crash:

* name is not matched in case state
* if the port returns badarg

Either way the process will crash followed by the port.

Possibly define/2 should return a value, like 'false' or {badarg,
atom()} (in which case, the process will probably crash anyway when it
attempts to pass the value to another function.)

Alternatively, define/2 could ignore unknown atoms but this could become
a source of creeping errors.

When a C compiler comes across an unknown constant, the compilation
fails. Since we are evaluating the constant at runtime, we should crash.
2014-04-05 10:21:20 -04:00
Michael Santos
f010b148b2 Allow setting the number of child processes
The maximum number of forks a process can have is limited by the
available file descriptors, with the upper boundary set by the number of
fd's select() can handle.

This option is provided because the number of child process per fork
can't easily be done by other means. For example, setrlimit() with
RLIMIT_NPROC applies to all the user processes and RLIMIT_NFILE will
interfere with normal file operations. Useful for testing and for
preventing accidental fork bombs.

The maxchild options applies to child processes. The value in the
current process is unchanged.
2014-04-03 10:20:23 -04:00
Michael Santos
a27694a000 Add environ(7), clearenv(3) 2014-03-30 09:43:00 -04:00
Michael Santos
3fb6bf4317 Add functions for manipulating the environment
The process environment can be set up in a few ways:

* using the {env, [{Key, Val}]} option in alcove_drv:start/1

  Global: will effect all future spawned processes.

* at exec, using execve/5

  Per process: will affect the child process

* using getenv(3), setenv(3) and unsetenv(3)
2014-03-29 18:29:13 -04:00
Michael Santos
dc6a1d7392 tests: SIGCHLD is 17 on linux, 20 on freebsd 2014-03-29 16:16:11 -04:00
Michael Santos
ef8f2f62b7 tests: add events
Add exit(3) for testing.

Confirm events are delivered properly, for example, to the parent after
the child has exited.

The event extraction in alcove_drv is still messy, redundant and error
prone. Needs to be cleaned up.
2014-03-29 15:30:45 -04:00
Michael Santos
8600ae82f0 Always treat stderr as a stream
Using exact reads for processes running the event loop broke stderr.
2014-03-29 13:13:11 -04:00
Michael Santos
e641b00891 setopt: remove setting maxchild per process
Accidentally the maxchild option. maxchild is used to size an array of
file descriptors. So obviously resetting this value will either crash
the process (read outside the bounds of the array) or cause it leak fd's.

So punt for now and remove support for changing maxchild. I guess the
simplest way to handle this would be to:

* get the new value of maxchild
* allocate an array of maxchild bytes
* copy PIDs from old to new
* if there is not enough space, free new array and return badarg
* otherwise, point the state to the new array and free the old array

Instead of crashing the caller by returning badarg, we could synthesize
an errno value and return {error,enomem} or simply leave the maxchild
unchanged and return ok.
2014-03-29 11:30:15 -04:00
Michael Santos
bb9b98011c Add getopt/1: retrieve per process port options 2014-03-28 16:54:01 -04:00
Michael Santos
86ceca06b1 headers: mirror numbering of Unix stdio
Change the order of the message header types so that STDIN is 0, STDOUT
is 1 and STDERR is 3.
2014-03-27 14:50:51 -04:00
Michael Santos
0dd6ca4dcd mount: add portable mount flags 2014-03-26 15:32:17 -04:00
Michael Santos
04b5277555 Define constants as atoms
Instead of using a case statement, simplify the lookup by searching
through an array.

Do not modify the name of constants: previously, the names were
downcased and the leading namespace removed, e.g, PR_CAPBSET_READ
would become 'get_capbset_read' and SIG_TERM would be represented by
'term'.  Constants are now atoms mirroring the name in the header file:
'PR_CAPBSET_READ', 'SIG_TERM'.

This change will cause issues with non-portable naming of constants. For
example, Linux uses MS_ to preface mount constants and FreeBSD uses
MNT_. A future change will add portable representations of the atom.
Something like 'rdonly' for MS_RDONLY and MNT_RDONLY.
2014-03-26 14:13:12 -04:00
Michael Santos
778b6cbc6b Allow arbitrarily long chains of processes
Decode messages as they arrive from the port. Non-matching messages are
converted to tuples and sent back into the process' mailbox.

A busy port that is generating many messages (stdout, signals, stderr)
could cause a call to timeout. Still messy, cleanup required.
2014-03-23 12:08:36 -04:00
Michael Santos
a08e904ded Add support for execve(2)
Execute a program with an environment:

    Port = alcove_drv:start(),
    {ok, Child} = alcove:fork(Port),
    ok = alcove:execve(Port, [Child], "/usr/bin/env",
            ["/usr/bin/env"], ["FOO=bar", "BAR=1234567"]),

    <<"FOO=bar\nBAR=1234567\n">> = alcove:stdout(Port, [Child], 5000).

An empty list is treated as NULL.
2014-03-23 09:14:13 -04:00
Michael Santos
280c132549 Notify the parent when the child has exec'ed
Notify the parent when the child has called exec by using a pair of file
descripts with the "close on exec" flag set.

socketpair() was used for possible bidirectional communication in the
future. The socket is only monitored by the parent for EOF right now.
2014-03-21 12:38:50 -04:00
Michael Santos
d77a5a040e alcove_drv:event/4: simplify the interface
Return a tuple from event/4. Modify alcove:event/1,2,3 to:

* only request event types
* return the data portion of the tuple

Probably alcove_drv:event/4 should be renamed and a new event function
that returns the data should be added.
2014-03-19 10:14:58 -04:00
Michael Santos
e38acf8e2e alcove_drv:event/4: return {error, timedout}
Fix dialyzer warnings. Since the return value from event is the huge
mess of values from the port, a timeout cannot be distinguised.

The return value of event should be changed to:

    {alcove_drv:type(), [integer()], reply()} | 'false'
    {alcove_drv:type(), [integer()], binary()} | 'false'
2014-03-19 09:37:05 -04:00
Michael Santos
369a840459 test: check the child has exited
On slow platforms like the beaglebone, SIGCHLD is received by the parent
but a slot in the process table has not been freed so the next call to
fork fails with {error, eagain} and the subsequent fork succeeds.

Check for the child by sending a kill(0).
2014-03-18 17:56:36 -04:00
Michael Santos
ba1bfcad15 test: wait for SIGCHLD 2014-03-18 17:36:37 -04:00
Michael Santos
acf0cacca8 Ignore the length in nested message headers 2014-03-18 16:51:27 -04:00