From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=0.2 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED autolearn=no autolearn_force=no version=3.4.4 Received: (qmail 15486 invoked from network); 4 May 2022 14:13:40 -0000 Received: from 9front.inri.net (168.235.81.73) by inbox.vuxu.org with ESMTPUTF8; 4 May 2022 14:13:40 -0000 Received: from mail.posixcafe.org ([45.76.19.58]) by 9front; Wed May 4 10:12:09 -0400 2022 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posixcafe.org; s=20200506; t=1651673524; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=4diH20A+BwLgu+vwiSFNB01gqGms2mWA9xHsJGc5CQw=; b=dqXd4CX+qXKdJI4Ev3G+M597HqjModqDkw1QEOQnmdrKKKEmRpOqGbJPL6/owqeunkdkNc aurjLrY4AKAHsKZkCNWo8i6no+im8rQ+oMvbARH8NLT1lEWEPIFtonYF3u33bF6UiUL/SU ypHDxaPlaIHuWyMtIjwSyd7xi9o2jyc= Received: from [192.168.168.200] (161-97-228-135.lpcnextlight.net [161.97.228.135]) by mail.posixcafe.org (OpenSMTPD) with ESMTPSA id dc2923bc (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO) for <9front@9front.org>; Wed, 4 May 2022 09:12:04 -0500 (CDT) Message-ID: <164813d2-28cb-44dd-2aee-b789ea75ba9a@posixcafe.org> Date: Wed, 4 May 2022 08:09:56 -0600 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.8.1 Content-Language: en-US To: 9front@9front.org From: Jacob Moody Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit List-ID: <9front.9front.org> List-Help: X-Glyph: ➈ X-Bullshit: agile encrypted callback API Subject: [9front] [PATCH] Unmount to remove sharp devices. Reply-To: 9front@9front.org Precedence: bulk Hello, This patch allows processes to unmount sharp devices to prevent itself and its children from accessing them. This is implemented through an internal rework of how RFNOMNT works, making RFNOMNT a special case of setting disallowed devices. To replicate the mount blocking functionality of RFNOMNT a special case is given for blocking devmnt, which also blocks the process and its children from making any mount calls. If everything passes the sniff test I can commit these changes. Diff is here: http://okturing.com/src/13574/body and included below. Thanks, moody 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();