mirror of
https://github.com/uselessd/alcove.git
synced 2026-04-15 01:04:41 +00:00
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:
@@ -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;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{application, alcove,
|
||||
[
|
||||
{description, "Erlang application container/sandbox"},
|
||||
{vsn, "0.16.0"},
|
||||
{vsn, "0.17.0"},
|
||||
{registered, []},
|
||||
{applications, [
|
||||
kernel,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}) ->
|
||||
|
||||
Reference in New Issue
Block a user