summaryrefslogtreecommitdiff
path: root/proc
diff options
context:
space:
mode:
authorJustus Winter <justus@gnupg.org>2017-03-09 23:55:12 +0100
committerJustus Winter <justus@gnupg.org>2017-03-11 18:07:23 +0100
commit34a94ce86b1bada9c0768f631540735d44f41100 (patch)
treec0e2871ecb2466ea001d9be505b05fdc10702087 /proc
parentbaf7e5c8ce176aead15c2559952d8bdf0da41ffd (diff)
proc: Hierarchical proc servers.
Previously, a Subhurd's tasks were shown as weird processes in the Motherhurd. This change connects the proc server in the Motherhurd with the proc server in the Subhurd, embedding the Subhurd's process hierarchy. Subhurd's processes can now be inspected and debugged like any other process. * NEWS: Update. * boot/boot.c (mach_msg_forward): New function. (boot_demuxer): Forward messages arriving on the new task notification port from the proc server, and forward them to the proc server inside the Subhurd via the notification port. * proc/info.c (S_proc_task2proc): Relay request for processes in a task namespace to the Subhurd's proc server. (S_proc_pid2proc): Likewise. (S_proc_getprocargs): Likewise. (S_proc_getprocenv): Likewise. (S_proc_getprocinfo): Likewise. Translate PIDs. (S_proc_getloginid): Likewise. (S_proc_getloginpids): Likewise. * proc/mgt.c (namespace_is_subprocess): New function. (namespace_translate_pids): Likewise. * proc/msg.c (S_proc_getmsgport): Relay request for processes in a task namespace to the Subhurd's proc server. * proc/pgrp.c (S_proc_getsid): Likewise. Translate PIDs. (S_proc_getsessionpids): Likewise. (S_proc_getsessionpgids): Likewise. (S_proc_getpgrppids): Likewise. * proc/proc.h (namespace_is_subprocess): New prototype. (namespace_translate_pids): Likewise.
Diffstat (limited to 'proc')
-rw-r--r--proc/info.c216
-rw-r--r--proc/mgt.c56
-rw-r--r--proc/msg.c26
-rw-r--r--proc/pgrp.c100
-rw-r--r--proc/proc.h2
5 files changed, 398 insertions, 2 deletions
diff --git a/proc/info.c b/proc/info.c
index 97321408..79a4c37f 100644
--- a/proc/info.c
+++ b/proc/info.c
@@ -109,6 +109,28 @@ S_proc_task2proc (struct proc *callerp,
if (!p)
return ESRCH;
+ if (namespace_is_subprocess (p))
+ {
+ /* Relay it to the Subhurd's proc server (if any). */
+ error_t err;
+
+ /* Release global lock while talking to the other proc server. */
+ pthread_mutex_unlock (&global_lock);
+
+ err = proc_task2proc (p->p_task_namespace, t, outproc);
+
+ pthread_mutex_lock (&global_lock);
+
+ if (! err)
+ {
+ *outproc_type = MACH_MSG_TYPE_MOVE_SEND;
+ mach_port_deallocate (mach_task_self (), t);
+ return 0;
+ }
+
+ /* Fallback. */
+ }
+
*outproc = ports_get_right (p);
*outproc_type = MACH_MSG_TYPE_MAKE_SEND;
mach_port_deallocate (mach_task_self (), t);
@@ -151,6 +173,27 @@ S_proc_pid2proc (struct proc *callerp,
if (! check_owner (callerp, p))
return EPERM;
+ if (namespace_is_subprocess (p))
+ {
+ /* Relay it to the Subhurd's proc server (if any). */
+ error_t err;
+
+ /* Release global lock while talking to the other proc server. */
+ pthread_mutex_unlock (&global_lock);
+
+ err = proc_task2proc (p->p_task_namespace, p->p_task, outproc);
+
+ pthread_mutex_lock (&global_lock);
+
+ if (! err)
+ {
+ *outproc_type = MACH_MSG_TYPE_MOVE_SEND;
+ return 0;
+ }
+
+ /* Fallback. */
+ }
+
*outproc = ports_get_right (p);
*outproc_type = MACH_MSG_TYPE_MAKE_SEND;
return 0;
@@ -345,6 +388,27 @@ S_proc_getprocargs (struct proc *callerp,
if (!p)
return ESRCH;
+ if (namespace_is_subprocess (p))
+ {
+ /* Relay it to the Subhurd's proc server (if any). */
+ error_t err;
+ pid_t pid_sub;
+
+ /* Release global lock while talking to the other proc server. */
+ pthread_mutex_unlock (&global_lock);
+
+ err = proc_task2pid (p->p_task_namespace, p->p_task, &pid_sub);
+ if (! err)
+ err = proc_getprocargs (p->p_task_namespace, pid_sub, buf, buflen);
+
+ pthread_mutex_lock (&global_lock);
+
+ if (! err)
+ return 0;
+
+ /* Fallback. */
+ }
+
return get_string_array (p->p_task, p->p_argv, (vm_address_t *) buf, buflen);
}
@@ -362,6 +426,27 @@ S_proc_getprocenv (struct proc *callerp,
if (!p)
return ESRCH;
+ if (namespace_is_subprocess (p))
+ {
+ /* Relay it to the Subhurd's proc server (if any). */
+ error_t err;
+ pid_t pid_sub;
+
+ /* Release global lock while talking to the other proc server. */
+ pthread_mutex_unlock (&global_lock);
+
+ err = proc_task2pid (p->p_task_namespace, p->p_task, &pid_sub);
+ if (! err)
+ err = proc_getprocenv (p->p_task_namespace, pid_sub, buf, buflen);
+
+ pthread_mutex_lock (&global_lock);
+
+ if (! err)
+ return 0;
+
+ /* Fallback. */
+ }
+
return get_string_array (p->p_task, p->p_envp, (vm_address_t *)buf, buflen);
}
@@ -398,6 +483,82 @@ S_proc_getprocinfo (struct proc *callerp,
if (!p)
return ESRCH;
+ if (namespace_is_subprocess (p))
+ {
+ /* Relay it to the Subhurd's proc server (if any). */
+ error_t err;
+ pid_t pid_sub;
+
+ /* Release global lock while talking to the other proc server. */
+ pthread_mutex_unlock (&global_lock);
+
+ err = proc_task2pid (p->p_task_namespace, p->p_task, &pid_sub);
+ if (! err)
+ err = proc_getprocinfo (p->p_task_namespace, pid_sub, flags,
+ piarray, piarraylen, waits, waits_len);
+
+ if (! err && *piarray && *piarraylen * sizeof (int) >= sizeof *pi)
+ {
+ /* Fixup the PIDs to refer to this Hurd's processes. */
+ task_t t_ppid = MACH_PORT_NULL;
+ task_t t_pgrp = MACH_PORT_NULL;
+ task_t t_session = MACH_PORT_NULL;
+ task_t t_logincollection = MACH_PORT_NULL;
+
+ pi = (struct procinfo *) *piarray;
+
+ /* We handle errors by checking each returned task. */
+ if (pi->ppid != pid_sub)
+ proc_pid2task (p->p_task_namespace, pi->ppid, &t_ppid);
+ proc_pid2task (p->p_task_namespace, pi->pgrp, &t_pgrp);
+ proc_pid2task (p->p_task_namespace, pi->session, &t_session);
+ proc_pid2task (p->p_task_namespace, pi->logincollection,
+ &t_logincollection);
+
+ /* Reacquire the global lock for the hash table lookups. */
+ pthread_mutex_lock (&global_lock);
+
+ if (MACH_PORT_VALID (t_ppid))
+ {
+ struct proc *q = task_find (t_ppid);
+ pi->ppid = q ? q->p_pid : (pid_t) -1;
+ mach_port_deallocate (mach_task_self (), t_ppid);
+ }
+ else
+ {
+ /* Either the pid2task lookup failed, or this process is
+ a root of a process hierarchy in the Subhurd. Either
+ way, we attach it to the creator of the task
+ namespace. */
+ pi->ppid = namespace_find_root (p)->p_pid;
+ }
+ if (MACH_PORT_VALID (t_pgrp))
+ {
+ struct proc *q = task_find (t_pgrp);
+ pi->pgrp = q ? q->p_pid : (pid_t) -1;
+ mach_port_deallocate (mach_task_self (), t_pgrp);
+ }
+ if (MACH_PORT_VALID (t_session))
+ {
+ struct proc *q = task_find (t_session);
+ pi->session = q ? q->p_pid : (pid_t) -1;
+ mach_port_deallocate (mach_task_self (), t_session);
+ }
+ if (MACH_PORT_VALID (t_logincollection))
+ {
+ struct proc *q = task_find (t_logincollection);
+ pi->logincollection = q ? q->p_pid : (pid_t) -1;
+ mach_port_deallocate (mach_task_self (), t_logincollection);
+ }
+
+ return 0;
+ }
+
+ pthread_mutex_lock (&global_lock);
+ err = 0;
+ /* Fallback. */
+ }
+
task = p->p_task;
check_msgport_death (p);
@@ -644,13 +805,37 @@ S_proc_getloginid (struct proc *callerp,
pid_t *leader)
{
struct proc *proc = pid_find (pid);
- struct proc *p;
+ struct proc *p = proc;
/* No need to check CALLERP here; we don't use it. */
if (!proc)
return ESRCH;
+ if (namespace_is_subprocess (p))
+ {
+ /* Relay it to the Subhurd's proc server (if any). */
+ error_t err;
+ pid_t pid_sub;
+
+ /* Release global lock while talking to the other proc server. */
+ pthread_mutex_unlock (&global_lock);
+
+ err = proc_task2pid (p->p_task_namespace, p->p_task, &pid_sub);
+ if (! err)
+ err = proc_getloginid (p->p_task_namespace, pid_sub, leader);
+ if (! err)
+ /* Acquires global_lock. */
+ err = namespace_translate_pids (p->p_task_namespace, leader, 1);
+ else
+ pthread_mutex_lock (&global_lock);
+
+ if (! err)
+ return 0;
+
+ /* Fallback. */
+ }
+
for (p = proc; !p->p_loginleader; p = p->p_parent)
assert (p);
@@ -674,6 +859,35 @@ S_proc_getloginpids (struct proc *callerp,
/* No need to check CALLERP here; we don't use it. */
+ if (!l)
+ return ESRCH;
+
+ if (namespace_is_subprocess (l))
+ {
+ /* Relay it to the Subhurd's proc server (if any). */
+ error_t err;
+ pid_t pid_sub;
+ pid_t leader_sub;
+ task_t leader_task;
+
+ /* Release global lock while talking to the other proc server. */
+ pthread_mutex_unlock (&global_lock);
+
+ err = proc_task2pid (l->p_task_namespace, l->p_task, &pid_sub);
+ if (! err)
+ err = proc_getloginpids (l->p_task_namespace, pid_sub, pids, npids);
+ if (! err)
+ /* Acquires global_lock. */
+ err = namespace_translate_pids (l->p_task_namespace, *pids, *npids);
+ else
+ pthread_mutex_lock (&global_lock);
+
+ if (! err)
+ return 0;
+
+ /* Fallback. */
+ }
+
if (!l || !l->p_loginleader)
return ESRCH;
diff --git a/proc/mgt.c b/proc/mgt.c
index 87a7c96b..a9015ccc 100644
--- a/proc/mgt.c
+++ b/proc/mgt.c
@@ -732,7 +732,61 @@ new_proc (task_t task)
complete_proc (p, genpid ());
return p;
}
+
+
+/* Task namespace support. */
+
+/* Check if a given process is part of a task namespace but is not the
+ root. The root is managed by us, while all other tasks are managed
+ by the root itself. */
+int
+namespace_is_subprocess (struct proc *p)
+{
+ return (p
+ && MACH_PORT_VALID (p->p_task_namespace)
+ && p->p_parent
+ && MACH_PORT_VALID (p->p_parent->p_task_namespace));
+}
+
+/* Translate PIDs valid in NAMESPACE into PIDs valid in our own
+ process space.
+
+ Conditions: global_lock is unlocked before calling, and is locked
+ afterwards. */
+error_t
+namespace_translate_pids (mach_port_t namespace, pid_t *pids, size_t pids_len)
+{
+ size_t i;
+ task_t *tasks;
+
+ tasks = calloc (pids_len, sizeof *tasks);
+ if (tasks == NULL)
+ {
+ pthread_mutex_lock (&global_lock);
+ return ENOMEM;
+ }
+
+ for (i = 0; i < pids_len; i++)
+ /* We handle errors by checking each returned task. */
+ proc_pid2task (namespace, pids[i], &tasks[i]);
+
+ pthread_mutex_lock (&global_lock);
+
+ for (i = 0; i < pids_len; i++)
+ if (MACH_PORT_VALID (tasks[i]))
+ {
+ struct proc *p = task_find_nocreate (tasks[i]);
+ mach_port_deallocate (mach_task_self (), tasks[i]);
+ pids[i] = p ? p->p_pid : (pid_t) -1;
+ }
+ else
+ pids[i] = (pid_t) -1;
+
+ free (tasks);
+ return 0;
+}
+
/* Find the creator of the task namespace that P is in. */
struct proc *
namespace_find_root (struct proc *p)
@@ -759,6 +813,8 @@ namespace_terminate (struct proc *p, void *cookie)
task_terminate (p->p_task);
}
+
+
/* The task associated with process P has died. Drop most state,
and then record us as dead. Our parent will eventually complete the
deallocation. */
diff --git a/proc/msg.c b/proc/msg.c
index e145f6e6..8efc993e 100644
--- a/proc/msg.c
+++ b/proc/msg.c
@@ -137,7 +137,31 @@ S_proc_getmsgport (struct proc *callerp,
p = pid_find_allow_zombie (pid);
-restart:
+ if (namespace_is_subprocess (p))
+ {
+ /* Relay it to the Subhurd's proc server (if any). */
+ error_t err;
+ pid_t pid_sub;
+
+ /* Release global lock while talking to the other proc server. */
+ pthread_mutex_unlock (&global_lock);
+
+ err = proc_task2pid (p->p_task_namespace, p->p_task, &pid_sub);
+ if (! err)
+ err = proc_getmsgport (p->p_task_namespace, pid_sub, msgport);
+
+ pthread_mutex_lock (&global_lock);
+
+ if (! err)
+ {
+ *msgport_type = MACH_MSG_TYPE_MOVE_SEND;
+ return 0;
+ }
+
+ /* Fallback. */
+ }
+
+ restart:
while (p && p->p_deadmsg && !p->p_dead)
{
callerp->p_msgportwait = 1;
diff --git a/proc/pgrp.c b/proc/pgrp.c
index d7c562fa..9db1dba6 100644
--- a/proc/pgrp.c
+++ b/proc/pgrp.c
@@ -147,6 +147,30 @@ S_proc_getsid (struct proc *callerp,
/* No need to check CALLERP; we don't use it. */
+ if (namespace_is_subprocess (p))
+ {
+ /* Relay it to the Subhurd's proc server (if any). */
+ error_t err;
+ pid_t pid_sub;
+
+ /* Release global lock while talking to the other proc server. */
+ pthread_mutex_unlock (&global_lock);
+
+ err = proc_task2pid (p->p_task_namespace, p->p_task, &pid_sub);
+ if (! err)
+ err = proc_getsid (p->p_task_namespace, pid_sub, sid);
+ if (! err)
+ /* Acquires global_lock. */
+ err = namespace_translate_pids (p->p_task_namespace, sid, 1);
+ else
+ pthread_mutex_lock (&global_lock);
+
+ if (! err)
+ return 0;
+
+ /* Fallback. */
+ }
+
*sid = p->p_pgrp->pg_session->s_sid;
return 0;
}
@@ -167,6 +191,31 @@ S_proc_getsessionpids (struct proc *callerp,
/* No need to check CALLERP; we don't use it. */
+ p = pid_find (sid);
+ if (namespace_is_subprocess (p))
+ {
+ /* Relay it to the Subhurd's proc server (if any). */
+ error_t err;
+ pid_t pid_sub;
+
+ /* Release global lock while talking to the other proc server. */
+ pthread_mutex_unlock (&global_lock);
+
+ err = proc_task2pid (p->p_task_namespace, p->p_task, &pid_sub);
+ if (! err)
+ err = proc_getsessionpids (p->p_task_namespace, pid_sub, pids, npidsp);
+ if (! err)
+ /* Acquires global_lock. */
+ err = namespace_translate_pids (p->p_task_namespace, *pids, *npidsp);
+ else
+ pthread_mutex_lock (&global_lock);
+
+ if (! err)
+ return 0;
+
+ /* Fallback. */
+ }
+
s = session_find (sid);
if (!s)
return ESRCH;
@@ -206,6 +255,7 @@ S_proc_getsessionpgids (struct proc *callerp,
size_t *npgidsp)
{
int count;
+ struct proc *p;
struct pgrp *pg;
struct session *s;
pid_t *pp = *pgids;
@@ -213,6 +263,31 @@ S_proc_getsessionpgids (struct proc *callerp,
/* No need to check CALLERP; we don't use it. */
+ p = pid_find (sid);
+ if (namespace_is_subprocess (p))
+ {
+ /* Relay it to the Subhurd's proc server (if any). */
+ error_t err;
+ pid_t pid_sub;
+
+ /* Release global lock while talking to the other proc server. */
+ pthread_mutex_unlock (&global_lock);
+
+ err = proc_task2pid (p->p_task_namespace, p->p_task, &pid_sub);
+ if (! err)
+ err = proc_getsessionpgids (p->p_task_namespace, pid_sub, pgids, npgidsp);
+ if (! err)
+ /* Acquires global_lock. */
+ err = namespace_translate_pids (p->p_task_namespace, *pgids, *npgidsp);
+ else
+ pthread_mutex_lock (&global_lock);
+
+ if (! err)
+ return 0;
+
+ /* Fallback. */
+ }
+
s = session_find (sid);
if (!s)
return ESRCH;
@@ -254,6 +329,31 @@ S_proc_getpgrppids (struct proc *callerp,
/* No need to check CALLERP; we don't use it. */
+ p = pid_find (pgid);
+ if (namespace_is_subprocess (p))
+ {
+ /* Relay it to the Subhurd's proc server (if any). */
+ error_t err;
+ pid_t pid_sub;
+
+ /* Release global lock while talking to the other proc server. */
+ pthread_mutex_unlock (&global_lock);
+
+ err = proc_task2pid (p->p_task_namespace, p->p_task, &pid_sub);
+ if (! err)
+ err = proc_getpgrppids (p->p_task_namespace, pid_sub, pids, npidsp);
+ if (! err)
+ /* Acquires global_lock. */
+ err = namespace_translate_pids (p->p_task_namespace, *pids, *npidsp);
+ else
+ pthread_mutex_lock (&global_lock);
+
+ if (! err)
+ return 0;
+
+ /* Fallback. */
+ }
+
if (pgid == 0)
pg = callerp->p_pgrp;
else
diff --git a/proc/proc.h b/proc/proc.h
index c0696149..333e8840 100644
--- a/proc/proc.h
+++ b/proc/proc.h
@@ -201,6 +201,8 @@ void leave_pgrp (struct proc *);
void join_pgrp (struct proc *);
void boot_setsid (struct proc *);
+int namespace_is_subprocess (struct proc *p);
+error_t namespace_translate_pids (mach_port_t namespace, pid_t *pids, size_t pids_len);
struct proc *namespace_find_root (struct proc *);
void process_has_exited (struct proc *);
void alert_parent (struct proc *);