diff 9126ee3eea90d639f4e877c01400248581d10f65 uncommitted --- a//sys/man/3/0intro +++ b//sys/man/3/0intro @@ -87,6 +87,20 @@ commands will need quotes to protect the .B # characters. +.PP +Access to a kernel device can be forfeited by +unmounting it. For example, after +.IP +.EX +unmount(nil, "#c") +.EE +.LP +the calling process and its children can no longer access the device through its +sharp name. Existing binds of these devices are untouched. +Unmounting the mount device (see +.IR mnt (3)) +has the side effect of preventing the calling process and its children +from performing mounts. .SH SEE ALSO .IR intro (5), .IR intro (2) --- a//sys/src/9/port/chan.c +++ b//sys/src/9/port/chan.c @@ -1313,24 +1313,19 @@ up->genbuf[n++] = *name++; } up->genbuf[n] = '\0'; - /* - * noattach is sandboxing. - * - * the OK exceptions are: - * | it only gives access to pipes you create - * d this process's file descriptors - * e this process's environment - * the iffy exceptions are: - * c time and pid, but also cons and consctl - * p control of your own processes (and unfortunately - * any others left unprotected) - */ n = chartorune(&r, up->genbuf+1)+1; - if(up->pgrp->noattach && utfrune("|decp", r)==nil) - error(Enoattach); t = devno(r, 1); if(t == -1) error(Ebadsharp); + /* + * Notallowed is sandboxing. + * A process group can willingly give up access to a + * sharp device by unmounting it. Notallowed itself is + * a bitmask of indicies in to devtab, a high bit indicating + * that the process has given up its right to use that device. + */ + if((up->pgrp->notallowed[t/(sizeof(u64int)*8)] & 1<<(t%(sizeof(u64int)*8))) != 0) + error(Enoattach); c = devtab[t]->attach(up->genbuf+n); break; --- a//sys/src/9/port/devshr.c +++ b//sys/src/9/port/devshr.c @@ -464,7 +464,7 @@ cclose(c); return nc; case Qcroot: - if(up->pgrp->noattach) + if(!canmount(up->pgrp, 1)) error(Enoattach); if((perm & DMDIR) == 0 || mode != OREAD) error(Eperm); @@ -498,7 +498,7 @@ sch->shr = shr; break; case Qcshr: - if(up->pgrp->noattach) + if(!canmount(up->pgrp, 1)) error(Enoattach); if((perm & DMDIR) != 0 || mode != OWRITE) error(Eperm); @@ -731,7 +731,7 @@ Mhead *h; Mount *m; - if(up->pgrp->noattach) + if(!canmount(up->pgrp, 1)) error(Enoattach); sch = tosch(c); if(sch->level != Qcmpt) --- a//sys/src/9/port/mkdevc +++ b//sys/src/9/port/mkdevc @@ -78,6 +78,9 @@ if(ARGC < 2) exit "usage" + if(ndev >= 256) + exit "device count will overflow Pgrp.notallowed" + printf "#include \"u.h\"\n"; printf "#include \"../port/lib.h\"\n"; printf "#include \"mem.h\"\n"; --- a//sys/src/9/port/portdat.h +++ b//sys/src/9/port/portdat.h @@ -484,7 +484,7 @@ { Ref; RWlock ns; /* Namespace n read/one write lock */ - int noattach; + u64int notallowed[4]; /* Room for 256 devices */ Mhead *mnthash[MNTHASH]; }; --- a//sys/src/9/port/portfns.h +++ b//sys/src/9/port/portfns.h @@ -413,6 +413,7 @@ ushort nhgets(void*); ulong µs(void); long lcycles(void); +int canmount(Pgrp*,int); #pragma varargck argpos iprint 1 #pragma varargck argpos panic 1 --- a//sys/src/9/port/sysfile.c +++ b//sys/src/9/port/sysfile.c @@ -1048,7 +1048,7 @@ nexterror(); } - if(up->pgrp->noattach) + if(!canmount(up->pgrp, 1)) error(Enoattach); ac = nil; @@ -1146,6 +1146,8 @@ { Chan *cmount, *cmounted; char *name, *old; + int t; + Rune r; name = va_arg(list, char*); old = va_arg(list, char*); @@ -1152,6 +1154,14 @@ cmounted = nil; validaddr((uintptr)old, 1, 0); + if(old[0] == '#' && utflen(old) == 2){ + chartorune(&r, old+1); + t = devno(r, 1); + if(t == -1) + error(Ebadsharp); + up->pgrp->notallowed[t/(sizeof(u64int)*8)] |= 1<<(t%(sizeof(u64int)*8)); + return 0; + } cmount = namec(old, Amount, 0, 0); if(waserror()) { cclose(cmount); --- a//sys/src/9/port/sysproc.c +++ b//sys/src/9/port/sysproc.c @@ -23,6 +23,43 @@ pexit("fork aborted", 1); } +int +canmount(Pgrp *p, int user) +{ + int t; + + /* + * Devmnt is not usable directly from user procs, so + * having it removed is interpreted to block any mounts. + */ + t = devno('M', user); + if(t != -1 && (p->notallowed[t/(sizeof(u64int)*8)] & 1<<(t%(sizeof(u64int)*8))) != 0) + return 0; + return 1; +} + +static void +setrfnomnt(Pgrp *p) +{ + int t, i; + u64int mask[nelem(p->notallowed)]; + char allowed[] = "|decp"; + + /* + * Code using RFNOMNT expects to block all sharp devices + * and mounting except for the devices defined in allowed[] + */ + for(i=0; i < sizeof allowed; i++){ + t = devno(allowed[i], 1); + if(t == -1) + continue; + mask[t/(sizeof(u64int)*8)] |= 1<<(t%(sizeof(u64int)*8)); + } + /* Sets bit for devmnt, so all mounts are disabled implicitly */ + for(i=0; i < nelem(p->notallowed); i++) + p->notallowed[i] |= ~mask[i]; +} + uintptr sysrfork(va_list list) { @@ -60,12 +97,12 @@ up->pgrp = newpgrp(); if(flag & RFNAMEG) pgrpcpy(up->pgrp, opg); - /* inherit noattach */ - up->pgrp->noattach = opg->noattach; + /* inherit notallowed */ + memmove(up->pgrp->notallowed, opg->notallowed, sizeof up->pgrp->notallowed); closepgrp(opg); } if(flag & RFNOMNT) - up->pgrp->noattach = 1; + setrfnomnt(up->pgrp); if(flag & RFREND) { org = up->rgrp; up->rgrp = newrgrp(); @@ -177,8 +214,8 @@ p->pgrp = newpgrp(); if(flag & RFNAMEG) pgrpcpy(p->pgrp, up->pgrp); - /* inherit noattach */ - p->pgrp->noattach = up->pgrp->noattach; + /* inherit notallowed */ + memmove(p->pgrp->notallowed, up->pgrp->notallowed, sizeof p->pgrp->notallowed); } else { p->pgrp = up->pgrp; @@ -185,7 +222,7 @@ incref(p->pgrp); } if(flag & RFNOMNT) - p->pgrp->noattach = 1; + setrfnomnt(p->pgrp); if(flag & RFREND) p->rgrp = newrgrp();