diff options
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | boot/boot.c | 54 | ||||
-rw-r--r-- | proc/info.c | 216 | ||||
-rw-r--r-- | proc/mgt.c | 56 | ||||
-rw-r--r-- | proc/msg.c | 26 | ||||
-rw-r--r-- | proc/pgrp.c | 100 | ||||
-rw-r--r-- | proc/proc.h | 2 |
7 files changed, 458 insertions, 2 deletions
@@ -1,3 +1,9 @@ +Version X (2017-06-XX) + +Subhurd's processes are now properly embedded in the Motherhurds +process hierarchy. They can be inspected and debugged just like any +other process. + Version 0.9 (2016-12-18) The 'boot' program can now be run as unprivileged user, allowing any diff --git a/boot/boot.c b/boot/boot.c index 950aedb9..13a19d28 100644 --- a/boot/boot.c +++ b/boot/boot.c @@ -196,12 +196,66 @@ mig_reply_setup ( #undef OutP } +error_t +mach_msg_forward (mach_msg_header_t *inp, + mach_port_t destination, mach_msg_type_name_t destination_type) +{ + /* Put the reply port back at the correct position, insert new + destination. */ + inp->msgh_local_port = inp->msgh_remote_port; + inp->msgh_remote_port = destination; + inp->msgh_bits = + MACH_MSGH_BITS (destination_type, MACH_MSGH_BITS_REMOTE (inp->msgh_bits)) + | MACH_MSGH_BITS_OTHER (inp->msgh_bits); + + /* A word about resources carried in complex messages. + + "In a received message, msgt_deallocate is TRUE in type + descriptors for out-of-line memory". Therefore, "[the + out-of-line memory] is implicitly deallocated from the sender + [when we resend the message], as if by vm_deallocate". + + Similarly, rights in messages will be either + MACH_MSG_TYPE_PORT_SEND, MACH_MSG_TYPE_PORT_SEND_ONCE, or + MACH_MSG_TYPE_PORT_RECEIVE. These types are aliases for, + respectively, MACH_MSG_TYPE_MOVE_SEND, + MACH_MSG_TYPE_MOVE_SEND_ONCE, and MACH_MSG_TYPE_MOVE_RECEIVE. + Therefore, the rights are moved when we resend the message. */ + + return mach_msg (inp, MACH_SEND_MSG, inp->msgh_size, + 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); +} + int boot_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp) { + error_t err; mig_routine_t routine; mig_reply_setup (inp, outp); + + if (inp->msgh_local_port == task_notification_port + && MACH_PORT_VALID (new_task_notification) + && 24000 <= inp->msgh_id && inp->msgh_id < 24100) + { + /* This is a message of the Process subsystem. We relay this to + allow the "outer" proc servers to communicate with the "inner" + one. */ + mig_reply_header_t *reply = (mig_reply_header_t *) outp; + + if (MACH_PORT_VALID (new_task_notification)) + err = mach_msg_forward (inp, new_task_notification, MACH_MSG_TYPE_COPY_SEND); + else + err = EOPNOTSUPP; + + if (err) + reply->RetCode = err; + else + reply->RetCode = MIG_NO_REPLY; + + return TRUE; + } + if ((routine = io_server_routine (inp)) || (routine = device_server_routine (inp)) || (routine = notify_server_routine (inp)) || 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; @@ -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. */ @@ -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 *); |