From 78cb60b644538a33e0479f25393d6c861e3605f8 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Sun, 4 Jun 2023 20:43:51 +0200 Subject: kernel: rework /proc/ and process IDs I'm yet to write proper docs but the TL;DR is: Mounting /proc/ creates a new pid namespace. You're still visible in the old namespace with your old pid, but your children won't be. You see your own pid as 1. Current pids of children will be preserved, pids will be allocated starting from the highest one of your children. --- src/kernel/proc.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 5 deletions(-) (limited to 'src/kernel/proc.c') diff --git a/src/kernel/proc.c b/src/kernel/proc.c index 65cbd81..108a006 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -30,10 +30,12 @@ Proc *proc_seed(void *data, size_t datalen) { proc_first->pages = pagedir_new(); proc_first->mount = vfs_mount_seed(); proc_first->globalid = next_pid++; - proc_first->cid = 1; - proc_first->nextcid = 1; proc_first->_handles = kzalloc(sizeof(Handle) * HANDLE_MAX); + proc_first->pns = proc_first; + proc_first->localid = 1; + proc_first->nextlid = 2; + // map .shared extern char _shared_len; for (size_t p = 0; p < (size_t)&_shared_len; p += PAGE_SIZE) @@ -74,12 +76,18 @@ Proc *proc_fork(Proc *parent, int flags) { child->parent = parent; parent->child = child; - if (parent->nextcid == 0) + if (next_pid == 0) { panic_unimplemented(); - child->cid = parent->nextcid++; - child->nextcid = 1; + } child->globalid = next_pid++; + child->pns = parent->pns; + if (child->pns->nextlid == 0) { + panic_unimplemented(); + } + child->localid = child->pns->nextlid++; + + if ((flags & FORK_NEWFS) == 0 && parent->controlled) { child->controlled = parent->controlled; assert(child->controlled->provhcnt); @@ -110,6 +118,106 @@ Proc *proc_fork(Proc *parent, int flags) { return child; } +bool proc_ns_contains(Proc *ns, Proc *proc) { + /* a namespace contains all the processes with ->ns == ns and all their + * direct children */ + if (ns == proc) return true; + if (proc->parent == NULL) return false; + return proc->parent->pns == ns; +} + +uint32_t proc_ns_id(Proc *ns, Proc *proc) { + if (proc == ns) { + return 1; + } else { + if (proc->pns == proc) { + assert(proc->parent->pns == ns); + } else { + assert(proc->pns == ns); + } + return proc->localid; + } +} + +Proc *proc_ns_byid(Proc *ns, uint32_t id) { + assert(ns->pns == ns); + for (Proc *it = ns; it; it = proc_ns_next(ns, it)) { + if (proc_ns_id(ns, it) == id) { + return it; + } + } + return NULL; +} + +Proc *proc_ns_next(Proc *ns, Proc *p) { + Proc *ret = NULL; + /* see comments in proc_next */ + + if (!p) goto end; + /* descend into children who own their own namespace, but no further */ + if (p->child && proc_ns_contains(ns, p->child)) { + ret = p->child; + goto end; + } + // TODO diverged from proc_next, integrate this fix into it + // also once you do that do regression tests - this behaviour is buggy + if (p == ns) { + /* don't escape the root */ + goto end; + } + while (!p->sibling) { + p = p->parent; + assert(p); + if (p == ns) goto end; + } + ret = p->sibling; + +end: + if (ret != NULL) { + assert(proc_ns_contains(ns, ret)); + } + return ret; +} + +void proc_ns_create(Proc *proc) { + // TODO test this. lots of fucky behaviour can happen here + // TODO document process namespaces + Proc *old = proc->pns; + if (old == proc) return; + proc->pns = proc; + proc->nextlid = 2; + for (Proc *it = proc; it; ) { + if (it != proc) { + if (proc->nextlid < it->localid + 1) { + proc->nextlid = it->localid + 1; + } + if (it->pns == old) { + it->pns = proc; + } else { + assert(it->pns == it); + } + } + + /* analogous to proc_ns_next - which can't be used directly as it gets + * confused by changing namespaces */ + + /* descend into children who own their own namespace, but no further */ + if (it->child && (proc_ns_contains(proc, it->child) || proc_ns_contains(old, it->child))) { + it = it->child; + continue; + } + if (it == proc) { + break; + } + while (!it->sibling) { + it = it->parent; + if (it == proc) break; + assert(it); + } + it = it->sibling; + } +} + /* meant to be used with p->*_refcount */ static bool unref(uint64_t *refcount) { if (!refcount) return true; @@ -394,6 +502,7 @@ Handle *proc_handle_get(Proc *p, hid_t id) { } else if (id == HANDLE_PROCFS) { if (!p->specialh.procfs) { Handle *h = kmalloc(sizeof *h); + proc_ns_create(p); *h = (Handle){ .type = HANDLE_FS_FRONT, .backend = procfs_backend(p), -- cgit v1.2.3