summaryrefslogtreecommitdiff
path: root/libdiskfs
diff options
context:
space:
mode:
authorSergey Bugaev <bugaevc@gmail.com>2021-05-30 13:16:30 +0300
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2022-08-10 22:17:08 +0200
commitb6c6e41a0d94740f4ecce9afdafa0c17348ce4c0 (patch)
tree188a6fb3aa934a4ed7ea0f7cc685b09a58f69258 /libdiskfs
parent2e3a1e0f028ae5498d96a4a3618a3533e062d2eb (diff)
libnetfs, libtrivs: Shield S_file_exec_paths () from cancellation
Here's the sequence of events that leads to a bug: * A task calls file_exec_paths () on itself, holding the only send right to the protid, passing EXEC_NEWTASK (or EXEC_SECURE, which implies it). * S_file_exec_paths () calls exec_exec_paths () * The exec server sets up a new task and calls proc_reassign () or proc_reauthenticate_reassign (). * The proc server destroys the old task, and the only send right to the protid with it. * The translator gets a no-senders notification, which results in a ports_interrupt_rpcs () call on the S_file_exec_paths (). * This propagates to the exec server (and potentially proc and auth servers). * The exec gets canceled, and the new task gets killed. In my opinion, the party that seems most guilty is the translator canceling exec upon receiving a no-senders notification for the protid. Normally, a no-senders notification means that the caller is no longer interested in the RPC, but this is not true in case of exec. To work around this, create an additional send right to the protid.
Diffstat (limited to 'libdiskfs')
-rw-r--r--libdiskfs/file-exec.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/libdiskfs/file-exec.c b/libdiskfs/file-exec.c
index 55b33a14..b1cb33c3 100644
--- a/libdiskfs/file-exec.c
+++ b/libdiskfs/file-exec.c
@@ -94,7 +94,7 @@ diskfs_S_file_exec_paths (struct protid *cred,
mach_port_t execserver;
int cached_exec;
struct hurd_userlink ulink;
- mach_port_t right;
+ mach_port_t right, cred_right;
#define RETURN(code) do { err = (code); goto out; } while (0)
@@ -195,6 +195,7 @@ diskfs_S_file_exec_paths (struct protid *cred,
do
{
right = ports_get_send_right (newpi);
+ cred_right = ports_get_send_right (cred);
#ifdef HAVE_EXEC_EXEC_PATHS
err = exec_exec_paths (execserver,
right, MACH_MSG_TYPE_COPY_SEND,
@@ -221,6 +222,7 @@ diskfs_S_file_exec_paths (struct protid *cred,
mach_port_deallocate (mach_task_self (), right);
+ mach_port_deallocate (mach_task_self (), cred_right);
if (err == MACH_SEND_INVALID_DEST)
{
if (cached_exec)