#include "dat.h"#include "fns.h"#include "error.h"#include <interp.h> /* * Enable the heap device for environments that allow debugging => * Must be 1 for a production environment. */int SECURE = 0; enum{ Qdir, Qctl, Qdbgctl, Qheap, Qns, Qnsgrp, Qpgrp, Qproc, Qstack, Qstatus, Qtext, Qwait, Qfd, Qexception,}; enum{ CMclose, CMclosefiles, CMhang, CMnohang, CMkill, CMkillgrp, CMrestricted, CMexceptions, CMprivate}; /* * Status, fd, and ns are left readable (0400/0444) because of their use in debugging, * particularly on shared servers. * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000 */Dirtab procdir[] ={ "ctl", {Qctl}, 0, 0200, "dbgctl", {Qdbgctl}, 0, 0600, "fd", {Qfd}, 0, 0400, "heap", {Qheap}, 0, 0600, "ns", {Qns}, 0, 0400, "nsgrp", {Qnsgrp}, 0, 0444, "pgrp", {Qpgrp}, 0, 0444, "proc", {Qproc}, 0, 0400, "stack", {Qstack}, 0, 0400, "status", {Qstatus}, 0, 0444, "text", {Qtext}, 0, 0000, "wait", {Qwait}, 0, 0400, "exception", {Qexception}, 0, 0400,}; staticCmdtab proccmd[] = { CMclose, "close", 2, CMclosefiles, "closefiles", 1, CMkill, "kill", 1, CMkillgrp, "killgrp", 1, CMprivate, "private", 1, CMrestricted, "restricted", 1, CMexceptions, "exceptions", 2,}; /* * Qids are, in path: * 5 bits of file type (qids above) * 59? bits of (pid + 1) * in vers: * TODO: 32 bits of pid, for consistency checking * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid. */#define QSHIFT 5 /* location in qid of pid */#define QID(q) ((((ulong)(q).path) & ((1<<QSHIFT)-1)) >> 0)#define QPID(pid) (((pid+1)<<QSHIFT))#define PID(q) ((q).vers)#define PATH(q) ((ulong)(q).path&~((1<<QSHIFT)-1)) static char *procstate[] = /* must correspond to include/interp.h */{ "alt", /* blocked in alt instruction */ "send", /* waiting to send */ "recv", /* waiting to recv */ "debug", /* debugged */ "ready", /* ready to be scheduled */ "release", /* interpreter released */ "exiting", /* exit because of kill or error */ "broken", /* thread crashed */}; static void procctlreq(Proc*, char*, int);static void mntscan(Mntwalk*, Pgrp*);static char Emisalign[] = "misaligned address"; static intprocgen(Chan *c, char *name, Dirtab *tab, int ntab, int s, Dir *dp){ Qid qid; Proc *p; char *e; Osenv *o; ulong pid, path, perm, len; USED(ntab); if(s == DEVDOTDOT){ mkqid(&qid, Qdir, 0, QTDIR); devdir(c, qid, "#p", 0, eve, DMDIR|0555, dp); return 1; } if((ulong)c->qid.path == Qdir) { if(name != nil){ /* ignore s and use name to find pid */ pid = strtoul(name, &e, 0); if(/* pid == 0 || */ *e != '\0') return -1; acquire(); p = procpid(pid); if(p == nil){ release(); return -1; } }else{ acquire(); p = proctab(s); if(p == nil) { release(); return -1; } pid = p->pid; } o = p->env; sprint(up->genbuf, "%lud", pid); if(name != nil && strcmp(name, up->genbuf) != 0){ release(); return -1; } mkqid(&qid, (pid+1)<<QSHIFT, pid, QTDIR); devdir(c, qid, up->genbuf, 0, o->user, DMDIR|0555, dp); release(); return 1; } if(s >= nelem(procdir)) return -1; tab = &procdir[s]; path = PATH(c->qid); acquire(); p = procpid(PID(c->qid)); if(p == nil) { release(); return -1; } o = p->env; perm = tab->perm; if((perm & 7) == 0) perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode; len = tab->length; mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE); devdir(c, qid, tab->name, len, o->user, perm, dp); release(); return 1;} static Chan*procattach(char *spec){ return devattach('p', spec);} static Walkqid*procwalk(Chan *c, Chan *nc, char **name, int nname){ return devwalk(c, nc, name, nname, 0, 0, procgen);} static intprocstat(Chan *c, uchar *db, int n){ return devstat(c, db, n, 0, 0, procgen);} /* * none can't read or write state on other * processes. This is to contain access of * servers running as none should they be * subverted by, for example, a stack attack. */static voidnonone(Proc *p){ if(p == up) return; if(strcmp(up->env->user, "none") != 0) return; if(iseve()) return; error(Eperm);} static Chan*procopen(Chan *c, int omode){ Proc *p; Osenv *o; long perm; if(c->qid.type & QTDIR) return devopen(c, omode, 0, 0, procgen); acquire(); if (waserror()) { release(); nexterror(); } p = procpid(PID(c->qid)); if(p == nil) error(Ethread); o = p->env; perm = procdir[QID(c->qid)-1].perm; if((perm & 7) == 0) perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode; devpermcheck(o->user, perm, omode); omode = openmode(omode); switch(QID(c->qid)){ case Qexception: break; case Qproc: case Qfd: if(omode != OREAD) error(Eperm); break; case Qctl: //if(p->privatemem) // error(Eperm); nonone(p); break; case Qnsgrp: case Qpgrp: case Qstatus: nonone(p); break; case Qwait: c->aux = qopen(1024, Qmsg, nil, nil); if(c->aux == nil) error(Enomem); o->childq = c->aux; break; case Qns: if(omode != OREAD) error(Eperm); if(c->aux == nil) error(Enomem); break; default: print("procopen %#lux\n", QID(c->qid)); error(Egreg); } //if(p->state != Pexiting) c->qid.vers = p->pid; coherence(); poperror(); release(); c->offset = 0; c->mode = omode; c->flag |= COPEN; return c;} static intprocwstat(Chan *c, uchar *db, int n){ Dir d; Proc *p; char *u; Osenv *o; if(c->qid.type&QTDIR) error(Eperm); acquire(); p = procpid(PID(c->qid)); if(p == nil) { release(); error(Ethread); } u = up->env->user; o = p->env; if(strcmp(u, o->user) != 0 && strcmp(u, eve) != 0) { release(); error(Eperm); } n = convM2D(db, n, &d, nil); if(n == 0){ release(); error(Eshortstat); } if(d.mode != ~0UL) o->pgrp->progmode = d.mode&0777; release(); return n;} static intprocsize(Proc *p){ return 0 / 1024;} static longprocoffset(long offset, char *va, int *np){ if(offset > 0) { offset -= *np; if(offset < 0) { memmove(va, va+*np+offset, -offset); *np = -offset; } else *np = 0; } return offset;} static intprocqidwidth(Chan *c){ char buf[32]; return sprint(buf, "%lud", c->qid.vers);} intprocfdprint(Chan *c, int fd, int w, char *s, int ns){ int n; if(w == 0) w = procqidwidth(c); n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n", fd, &"r w rw"[(c->mode&3)<<1], devtab[c->type]->dc, c->dev, c->qid.path, w, c->qid.vers, c->qid.type, c->iounit, c->offset, c->name->s); return n;} static intprocfds(Proc *p, char *va, int count, long offset){ Fgrp *f; Chan *c; int n, i, w, ww; char a[256]; /* print to buf to avoid holding fgrp lock while writing to user space */ if(count > sizeof a) count = sizeof a; acquire(); //qlock(&p->debug); f = p->env->fgrp; /* f is not locked because we've acquired */ if(f == nil){ release(); //qunlock(&p->debug); return 0; } lock(&f->l); if(waserror()){ unlock(&f->l); release(); //qunlock(&p->debug); nexterror(); } n = readstr(0, a, count, p->env->pgrp->dot->name->s); n += snprint(a+n, count-n, "\n"); offset = procoffset(offset, a, &n); /* compute width of qid.path */ w = 0; for(i = 0; i <= f->maxfd; i++) { c = f->fd[i]; if(c == nil) continue; ww = procqidwidth(c); if(ww > w) w = ww; } for(i = 0; i <= f->maxfd; i++) { c = f->fd[i]; if(c == nil) continue; n += procfdprint(c, i, w, a+n, count-n); offset = procoffset(offset, a, &n); } unlock(&f->l); release(); //qunlock(&p->debug); poperror(); /* copy result to user space, now that locks are released */ memmove(va, a, n); return n;} static voidprocclose(Chan *c){ int i; Proc *f; Osenv *o; switch(QID(c->qid)) { case Qns: case Qheap: free(c->aux); break; case Qwait: acquire(); i = 0; for(;;) { f = proctab(i++); if(f == nil) break; o = f->env; if(o->waitq == c->aux) o->waitq = nil; if(o->childq == c->aux) o->childq = nil; } release(); qfree(c->aux); }} static voidint2flag(int flag, char *s){ if(flag == 0){ *s = '\0'; return; } *s++ = '-'; if(flag & MAFTER) *s++ = 'a'; if(flag & MBEFORE) *s++ = 'b'; if(flag & MCREATE) *s++ = 'c'; if(flag & MCACHE) *s++ = 'C'; *s = '\0';} static char*proctime(ulong msec, char *buf, char *ebuf){ int tenths, sec; tenths = msec/100; sec = tenths/10; seprint(buf, ebuf, "%4d:%2.2d.%d", sec/60, sec%60, tenths%10); return buf;} static longprocread(Chan *c, void *va, long n, vlong offset){ char *a = va; char flag[10]; ulong grpid; int i; char mbuf[64], timebuf[12]; Mntwalk *mw; Osenv *o; Proc *p;Lines 1–500 of 792. Load more
#include "dat.h" #include "fns.h" #include "error.h" #include <interp.h> /* * Enable the heap device for environments that allow debugging => * Must be 1 for a production environment. */ int SECURE = 0; enum { Qdir, Qctl, Qdbgctl, Qheap, Qns, Qnsgrp, Qpgrp, Qproc, Qstack, Qstatus, Qtext, Qwait, Qfd, Qexception, }; enum { CMclose, CMclosefiles, CMhang, CMnohang, CMkill, CMkillgrp, CMrestricted, CMexceptions, CMprivate }; /* * Status, fd, and ns are left readable (0400/0444) because of their use in debugging, * particularly on shared servers. * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000 */ Dirtab procdir[] = { "ctl", {Qctl}, 0, 0200, "dbgctl", {Qdbgctl}, 0, 0600, "fd", {Qfd}, 0, 0400, "heap", {Qheap}, 0, 0600, "ns", {Qns}, 0, 0400, "nsgrp", {Qnsgrp}, 0, 0444, "pgrp", {Qpgrp}, 0, 0444, "proc", {Qproc}, 0, 0400, "stack", {Qstack}, 0, 0400, "status", {Qstatus}, 0, 0444, "text", {Qtext}, 0, 0000, "wait", {Qwait}, 0, 0400, "exception", {Qexception}, 0, 0400, }; static Cmdtab proccmd[] = { CMclose, "close", 2, CMclosefiles, "closefiles", 1, CMkill, "kill", 1, CMkillgrp, "killgrp", 1, CMprivate, "private", 1, CMrestricted, "restricted", 1, CMexceptions, "exceptions", 2, }; /* * Qids are, in path: * 5 bits of file type (qids above) * 59? bits of (pid + 1) * in vers: * TODO: 32 bits of pid, for consistency checking * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid. */ #define QSHIFT 5 /* location in qid of pid */ #define QID(q) ((((ulong)(q).path) & ((1<<QSHIFT)-1)) >> 0) #define QPID(pid) (((pid+1)<<QSHIFT)) #define PID(q) ((q).vers) #define PATH(q) ((ulong)(q).path&~((1<<QSHIFT)-1)) static char *procstate[] = /* must correspond to include/interp.h */ { "alt", /* blocked in alt instruction */ "send", /* waiting to send */ "recv", /* waiting to recv */ "debug", /* debugged */ "ready", /* ready to be scheduled */ "release", /* interpreter released */ "exiting", /* exit because of kill or error */ "broken", /* thread crashed */ }; static void procctlreq(Proc*, char*, int); static void mntscan(Mntwalk*, Pgrp*); static char Emisalign[] = "misaligned address"; static int procgen(Chan *c, char *name, Dirtab *tab, int ntab, int s, Dir *dp) { Qid qid; Proc *p; char *e; Osenv *o; ulong pid, path, perm, len; USED(ntab); if(s == DEVDOTDOT){ mkqid(&qid, Qdir, 0, QTDIR); devdir(c, qid, "#p", 0, eve, DMDIR|0555, dp); return 1; } if((ulong)c->qid.path == Qdir) { if(name != nil){ /* ignore s and use name to find pid */ pid = strtoul(name, &e, 0); if(/* pid == 0 || */ *e != '\0') return -1; acquire(); p = procpid(pid); if(p == nil){ release(); return -1; } }else{ acquire(); p = proctab(s); if(p == nil) { release(); return -1; } pid = p->pid; } o = p->env; sprint(up->genbuf, "%lud", pid); if(name != nil && strcmp(name, up->genbuf) != 0){ release(); return -1; } mkqid(&qid, (pid+1)<<QSHIFT, pid, QTDIR); devdir(c, qid, up->genbuf, 0, o->user, DMDIR|0555, dp); release(); return 1; } if(s >= nelem(procdir)) return -1; tab = &procdir[s]; path = PATH(c->qid); acquire(); p = procpid(PID(c->qid)); if(p == nil) { release(); return -1; } o = p->env; perm = tab->perm; if((perm & 7) == 0) perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode; len = tab->length; mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE); devdir(c, qid, tab->name, len, o->user, perm, dp); release(); return 1; } static Chan* procattach(char *spec) { return devattach('p', spec); } static Walkqid* procwalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, 0, 0, procgen); } static int procstat(Chan *c, uchar *db, int n) { return devstat(c, db, n, 0, 0, procgen); } /* * none can't read or write state on other * processes. This is to contain access of * servers running as none should they be * subverted by, for example, a stack attack. */ static void nonone(Proc *p) { if(p == up) return; if(strcmp(up->env->user, "none") != 0) return; if(iseve()) return; error(Eperm); } static Chan* procopen(Chan *c, int omode) { Proc *p; Osenv *o; long perm; if(c->qid.type & QTDIR) return devopen(c, omode, 0, 0, procgen); acquire(); if (waserror()) { release(); nexterror(); } p = procpid(PID(c->qid)); if(p == nil) error(Ethread); o = p->env; perm = procdir[QID(c->qid)-1].perm; if((perm & 7) == 0) perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode; devpermcheck(o->user, perm, omode); omode = openmode(omode); switch(QID(c->qid)){ case Qexception: break; case Qproc: case Qfd: if(omode != OREAD) error(Eperm); break; case Qctl: //if(p->privatemem) // error(Eperm); nonone(p); break; case Qnsgrp: case Qpgrp: case Qstatus: nonone(p); break; case Qwait: c->aux = qopen(1024, Qmsg, nil, nil); if(c->aux == nil) error(Enomem); o->childq = c->aux; break; case Qns: if(omode != OREAD) error(Eperm); if(c->aux == nil) error(Enomem); break; default: print("procopen %#lux\n", QID(c->qid)); error(Egreg); } //if(p->state != Pexiting) c->qid.vers = p->pid; coherence(); poperror(); release(); c->offset = 0; c->mode = omode; c->flag |= COPEN; return c; } static int procwstat(Chan *c, uchar *db, int n) { Dir d; Proc *p; char *u; Osenv *o; if(c->qid.type&QTDIR) error(Eperm); acquire(); p = procpid(PID(c->qid)); if(p == nil) { release(); error(Ethread); } u = up->env->user; o = p->env; if(strcmp(u, o->user) != 0 && strcmp(u, eve) != 0) { release(); error(Eperm); } n = convM2D(db, n, &d, nil); if(n == 0){ release(); error(Eshortstat); } if(d.mode != ~0UL) o->pgrp->progmode = d.mode&0777; release(); return n; } static int procsize(Proc *p) { return 0 / 1024; } static long procoffset(long offset, char *va, int *np) { if(offset > 0) { offset -= *np; if(offset < 0) { memmove(va, va+*np+offset, -offset); *np = -offset; } else *np = 0; } return offset; } static int procqidwidth(Chan *c) { char buf[32]; return sprint(buf, "%lud", c->qid.vers); } int procfdprint(Chan *c, int fd, int w, char *s, int ns) { int n; if(w == 0) w = procqidwidth(c); n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n", fd, &"r w rw"[(c->mode&3)<<1], devtab[c->type]->dc, c->dev, c->qid.path, w, c->qid.vers, c->qid.type, c->iounit, c->offset, c->name->s); return n; } static int procfds(Proc *p, char *va, int count, long offset) { Fgrp *f; Chan *c; int n, i, w, ww; char a[256]; /* print to buf to avoid holding fgrp lock while writing to user space */ if(count > sizeof a) count = sizeof a; acquire(); //qlock(&p->debug); f = p->env->fgrp; /* f is not locked because we've acquired */ if(f == nil){ release(); //qunlock(&p->debug); return 0; } lock(&f->l); if(waserror()){ unlock(&f->l); release(); //qunlock(&p->debug); nexterror(); } n = readstr(0, a, count, p->env->pgrp->dot->name->s); n += snprint(a+n, count-n, "\n"); offset = procoffset(offset, a, &n); /* compute width of qid.path */ w = 0; for(i = 0; i <= f->maxfd; i++) { c = f->fd[i]; if(c == nil) continue; ww = procqidwidth(c); if(ww > w) w = ww; } for(i = 0; i <= f->maxfd; i++) { c = f->fd[i]; if(c == nil) continue; n += procfdprint(c, i, w, a+n, count-n); offset = procoffset(offset, a, &n); } unlock(&f->l); release(); //qunlock(&p->debug); poperror(); /* copy result to user space, now that locks are released */ memmove(va, a, n); return n; } static void procclose(Chan *c) { int i; Proc *f; Osenv *o; switch(QID(c->qid)) { case Qns: case Qheap: free(c->aux); break; case Qwait: acquire(); i = 0; for(;;) { f = proctab(i++); if(f == nil) break; o = f->env; if(o->waitq == c->aux) o->waitq = nil; if(o->childq == c->aux) o->childq = nil; } release(); qfree(c->aux); } } static void int2flag(int flag, char *s) { if(flag == 0){ *s = '\0'; return; } *s++ = '-'; if(flag & MAFTER) *s++ = 'a'; if(flag & MBEFORE) *s++ = 'b'; if(flag & MCREATE) *s++ = 'c'; if(flag & MCACHE) *s++ = 'C'; *s = '\0'; } static char* proctime(ulong msec, char *buf, char *ebuf) { int tenths, sec; tenths = msec/100; sec = tenths/10; seprint(buf, ebuf, "%4d:%2.2d.%d", sec/60, sec%60, tenths%10); return buf; } static long procread(Chan *c, void *va, long n, vlong offset) { char *a = va; char flag[10]; ulong grpid; int i; char mbuf[64], timebuf[12]; Mntwalk *mw; Osenv *o; Proc *p;