Exit with badpid for invalid OS PID in fork path

A message sent to a non-existent Unix PID would be discarded, causing
the calling erlang process to block forever in receive.

This change modifies the behaviour of the port to return "badpid" if an
element in the fork path is not found. Since any element of the path may
be invalid, an event (as opposed to a call reply) is generated.
Currently any "badpid" event will cause the erlang process to exit.
Since only one call can be active at a time, it shouldn't interfere with
other operations but the mailbox should pattern match on the list
prefix (i.e., a call to [1,2,3,-1,4] would generate badpid for
[1,2,3,-1]).

Also define the behaviour when writing to invalid PIDs (<= 0). Since 0
is used to initialize the list of child PIDs in the port, passing in a
PID of 0 would match the first available slot in the PID table, causing
the port to write to fd 0.
This commit is contained in:
Michael Santos
2014-12-27 15:42:10 -05:00
parent 0f9c27d5d4
commit 2ba7caaf76
4 changed files with 31 additions and 10 deletions

View File

@@ -377,7 +377,14 @@ alcove_stdin(alcove_state_t *ap)
buf += 4;
buflen -= 4;
(void)pid_foreach(ap, pid, buf, &buflen, pid_equal, write_to_pid);
if ( (pid <= 0) || (pid_foreach(ap, pid, buf, &buflen, pid_equal,
write_to_pid) == 1)) {
int tlen = 0;
char t[MAXMSGLEN] = {0};
tlen = alcove_mk_atom(t, sizeof(t), "badpid");
if (alcove_call_fake_reply(pid, ALCOVE_MSG_EVENT, t, tlen) < 0)
return -1;
}
return 0;

View File

@@ -1,7 +1,7 @@
{application, alcove,
[
{description, "Erlang application container/sandbox"},
{vsn, "0.16.0"},
{vsn, "0.17.0"},
{registered, []},
{applications, [
kernel,

View File

@@ -185,6 +185,8 @@ call_reply(Drv, Pids, false, Timeout) ->
receive
{alcove_event, Drv, Pids, fdctl_closed} ->
ok;
{alcove_event, Drv, _Pids, badpid} ->
exit(badpid);
{alcove_call, Drv, Pids, Event} ->
Event
after
@@ -193,6 +195,8 @@ call_reply(Drv, Pids, false, Timeout) ->
end;
call_reply(Drv, Pids, true, Timeout) ->
receive
{alcove_event, Drv, _Pids, badpid} ->
exit(badpid);
{alcove_event, Drv, Pids, {termsig,_} = Signal} ->
exit(Signal);
{alcove_event, Drv, Pids, fdctl_closed} ->
@@ -211,6 +215,8 @@ call_reply(Drv, Pids, true, Timeout) ->
reply(Drv, Pids, Type, Timeout) ->
receive
{alcove_event, Drv, _Pids, badpid} ->
exit(badpid);
{Type, Drv, Pids, Event} ->
Event
after

View File

@@ -410,18 +410,26 @@ badpid(#state{pid = Drv}) ->
% EPIPE or PID not found
ok = alcove:execvp(Drv, [Child], "/bin/sh",
["/bin/sh", "-c", "echo > /dev/null"]),
Reply0 = (catch alcove:call(Drv, [Child], execvp, ["/bin/sh",
["/bin/sh", "-c", "echo > /dev/null"]], 1000)),
PID = get_unused_pid(Drv),
waitpid_exit(Drv, [], Child),
Reply0 = (catch alcove:execvp(Drv, [Child],
"/bin/sh", ["/bin/sh", "-c", "echo > /dev/null"])),
% PID not found
Reply1 = (catch alcove:call(Drv, [PID], execvp, ["/bin/sh",
["/bin/sh", "-c", "echo > /dev/null"]], 1000)),
PID = get_unused_pid(Drv),
Reply1 = (catch alcove:execvp(Drv, [PID],
"/bin/sh", ["/bin/sh", "-c", "echo > /dev/null"])),
% Invalid PIDs
Reply2 = (catch alcove:execvp(Drv, [-1],
"/bin/sh", ["/bin/sh", "-c", "echo > /dev/null"])),
Reply3 = (catch alcove:execvp(Drv, [0],
"/bin/sh", ["/bin/sh", "-c", "echo > /dev/null"])),
[
?_assertEqual({'EXIT',timeout}, Reply0),
?_assertEqual({'EXIT',timeout}, Reply1)
?_assertEqual({'EXIT',badpid}, Reply0),
?_assertEqual({'EXIT',badpid}, Reply1),
?_assertEqual({'EXIT',badpid}, Reply2),
?_assertEqual({'EXIT',badpid}, Reply3)
].
signal(#state{pid = Drv}) ->