summaryrefslogtreecommitdiff
path: root/sys/src/9/port
diff options
context:
space:
mode:
authorJacob Moody <moody@posixcafe.org>2022-05-28 02:23:29 +0000
committerJacob Moody <moody@posixcafe.org>2022-05-28 02:23:29 +0000
commite9bb7876e1bd7f9aaef4e1cd0c64c97f411ffde5 (patch)
tree161d07a002c1b9623afff61d72d3d5703a40a252 /sys/src/9/port
parent3351b674802d5a69ddb6d4d0354c0e034804b0c1 (diff)
kernel: add chdev command to devcons
Diffstat (limited to 'sys/src/9/port')
-rw-r--r--sys/src/9/port/chan.c37
-rw-r--r--sys/src/9/port/dev.c57
-rw-r--r--sys/src/9/port/devcons.c56
-rw-r--r--sys/src/9/port/devshr.c6
-rwxr-xr-xsys/src/9/port/mkdevc3
-rw-r--r--sys/src/9/port/portdat.h3
-rw-r--r--sys/src/9/port/portfns.h3
-rw-r--r--sys/src/9/port/sysfile.c10
-rw-r--r--sys/src/9/port/sysproc.c18
9 files changed, 158 insertions, 35 deletions
diff --git a/sys/src/9/port/chan.c b/sys/src/9/port/chan.c
index e69e5d7b6..04d072ea4 100644
--- a/sys/src/9/port/chan.c
+++ b/sys/src/9/port/chan.c
@@ -1272,7 +1272,7 @@ nameerror(char *name, char *err)
Chan*
namec(char *aname, int amode, int omode, ulong perm)
{
- int len, n, t, nomount;
+ int len, n, t, nomount, devunmount;
Chan *c;
Chan *volatile cnew;
Path *volatile path;
@@ -1292,6 +1292,24 @@ namec(char *aname, int amode, int omode, ulong perm)
name = aname;
/*
+ * When unmounting, the name parameter must be accessed
+ * using Aopen in order to get the real chan from
+ * something like /srv/cs or /fd/0. However when sandboxing,
+ * unmounting a sharp from a union is a valid operation even
+ * if the device is blocked.
+ */
+ devunmount = 0;
+ if(amode == Aunmount){
+ /*
+ * Doing any walks down the device could leak information
+ * about the existence of files.
+ */
+ if(name[0] == '#' && utflen(name) == 2)
+ devunmount = 1;
+ amode = Aopen;
+ }
+
+ /*
* Find the starting off point (the current slash, the root of
* a device tree, or the current dot) as well as the name to
* evaluate starting there.
@@ -1313,24 +1331,13 @@ namec(char *aname, int amode, int omode, ulong perm)
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);
+ if(!devunmount && !devallowed(up->pgrp, r))
+ error(Enoattach);
+
c = devtab[t]->attach(up->genbuf+n);
break;
diff --git a/sys/src/9/port/dev.c b/sys/src/9/port/dev.c
index e875c50e4..185d7ffd0 100644
--- a/sys/src/9/port/dev.c
+++ b/sys/src/9/port/dev.c
@@ -31,6 +31,63 @@ devno(int c, int user)
}
void
+devmask(Pgrp *pgrp, int invert, char *devs)
+{
+ int i, t, w;
+ char *p;
+ Rune r;
+ u64int mask[nelem(pgrp->notallowed)];
+
+ if(invert)
+ memset(mask, 0xFF, sizeof mask);
+ else
+ memset(mask, 0, sizeof mask);
+
+ w = sizeof mask[0] * 8;
+ for(p = devs; *p != '\0';){
+ p += chartorune(&r, p);
+ t = devno(r, 1);
+ if(t == -1)
+ continue;
+ if(invert)
+ mask[t/w] &= ~(1<<t%w);
+ else
+ mask[t/w] |= 1<<t%w;
+ }
+
+ wlock(&pgrp->ns);
+ for(i=0; i < nelem(pgrp->notallowed); i++)
+ pgrp->notallowed[i] |= mask[i];
+ wunlock(&pgrp->ns);
+}
+
+int
+devallowed(Pgrp *pgrp, int r)
+{
+ int t, w, b;
+
+ t = devno(r, 1);
+ if(t == -1)
+ return 0;
+
+ w = sizeof(u64int) * 8;
+ rlock(&pgrp->ns);
+ b = !(pgrp->notallowed[t/w] & 1<<t%w);
+ runlock(&pgrp->ns);
+ return b;
+}
+
+int
+canmount(Pgrp *pgrp)
+{
+ /*
+ * Devmnt is not usable directly from user procs, so
+ * having it removed is interpreted to block any mounts.
+ */
+ return devallowed(pgrp, 'M');
+}
+
+void
devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db)
{
db->name = n;
diff --git a/sys/src/9/port/devcons.c b/sys/src/9/port/devcons.c
index eb60d411e..756a47936 100644
--- a/sys/src/9/port/devcons.c
+++ b/sys/src/9/port/devcons.c
@@ -39,6 +39,16 @@ Cmdtab rebootmsg[] =
CMrdb, "rdb", 0,
};
+enum
+{
+ CMchdev,
+};
+
+Cmdtab drivermsg[] =
+{
+ CMchdev, "chdev", 0,
+};
+
void
printinit(void)
{
@@ -332,7 +342,7 @@ static Dirtab consdir[]={
"cons", {Qcons}, 0, 0660,
"consctl", {Qconsctl}, 0, 0220,
"cputime", {Qcputime}, 6*NUMSIZE, 0444,
- "drivers", {Qdrivers}, 0, 0444,
+ "drivers", {Qdrivers}, 0, 0666,
"hostdomain", {Qhostdomain}, DOMLEN, 0664,
"hostowner", {Qhostowner}, 0, 0664,
"kmesg", {Qkmesg}, 0, 0440,
@@ -583,9 +593,15 @@ consread(Chan *c, void *buf, long n, vlong off)
case Qdrivers:
b = smalloc(READSTR);
k = 0;
- for(i = 0; devtab[i] != nil; i++)
+
+ rlock(&up->pgrp->ns);
+ for(i = 0; devtab[i] != nil; i++){
+ if(up->pgrp->notallowed[i/(sizeof(u64int)*8)] & 1<<i%(sizeof(u64int)*8))
+ continue;
k += snprint(b+k, READSTR-k, "#%C %s\n",
devtab[i]->dc, devtab[i]->name);
+ }
+ runlock(&up->pgrp->ns);
if(waserror()){
free(b);
nexterror();
@@ -620,6 +636,7 @@ conswrite(Chan *c, void *va, long n, vlong off)
{
char buf[256];
long l, bp;
+ int invert;
char *a;
Mach *mp;
int id;
@@ -676,6 +693,41 @@ conswrite(Chan *c, void *va, long n, vlong off)
error(Eperm);
break;
+ case Qdrivers:
+ cb = parsecmd(a, n);
+ if(waserror()) {
+ free(cb);
+ nexterror();
+ }
+
+ ct = lookupcmd(cb, drivermsg, nelem(drivermsg));
+ if(ct == nil)
+ error(Ebadarg);
+ if(ct->index != CMchdev)
+ error(Ebadarg);
+ if(cb->nf < 2 || cb->nf > 3)
+ error(Ebadarg);
+
+ invert = 1;
+ a = cb->f[2];
+ switch(cb->f[1][0]){
+ case '&':
+ if(cb->f[1][1] == '~')
+ invert--;
+ break;
+ case '~':
+ a = "";
+ break;
+ default:
+ error(Ebadarg);
+ break;
+ }
+
+ devmask(up->pgrp, invert, a);
+ poperror();
+ free(cb);
+ break;
+
case Qreboot:
if(!iseve())
error(Eperm);
diff --git a/sys/src/9/port/devshr.c b/sys/src/9/port/devshr.c
index 225ba6c93..6f2431951 100644
--- a/sys/src/9/port/devshr.c
+++ b/sys/src/9/port/devshr.c
@@ -464,7 +464,7 @@ shrcreate(Chan *c, char *name, int omode, ulong perm)
cclose(c);
return nc;
case Qcroot:
- if(up->pgrp->noattach)
+ if(!canmount(up->pgrp))
error(Enoattach);
if((perm & DMDIR) == 0 || mode != OREAD)
error(Eperm);
@@ -498,7 +498,7 @@ shrcreate(Chan *c, char *name, int omode, ulong perm)
sch->shr = shr;
break;
case Qcshr:
- if(up->pgrp->noattach)
+ if(!canmount(up->pgrp))
error(Enoattach);
if((perm & DMDIR) != 0 || mode != OWRITE)
error(Eperm);
@@ -731,7 +731,7 @@ shrwrite(Chan *c, void *va, long n, vlong)
Mhead *h;
Mount *m;
- if(up->pgrp->noattach)
+ if(!canmount(up->pgrp))
error(Enoattach);
sch = tosch(c);
if(sch->level != Qcmpt)
diff --git a/sys/src/9/port/mkdevc b/sys/src/9/port/mkdevc
index 8e87636d8..601d1adba 100755
--- a/sys/src/9/port/mkdevc
+++ b/sys/src/9/port/mkdevc
@@ -78,6 +78,9 @@ END{
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";
diff --git a/sys/src/9/port/portdat.h b/sys/src/9/port/portdat.h
index 421f673e6..e9bb02f1e 100644
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -121,6 +121,7 @@ enum
Amount, /* to be mounted or mounted upon */
Acreate, /* is to be created */
Aremove, /* will be removed by caller */
+ Aunmount, /* unmount arg[0] */
COPEN = 0x0001, /* for i/o */
CMSG = 0x0002, /* the message channel for a mount */
@@ -484,7 +485,7 @@ struct Pgrp
{
Ref;
RWlock ns; /* Namespace n read/one write lock */
- int noattach;
+ u64int notallowed[4]; /* Room for 256 devices */
Mhead *mnthash[MNTHASH];
};
diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h
index d2345c508..13666ef30 100644
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -413,6 +413,9 @@ uint nhgetl(void*);
ushort nhgets(void*);
ulong µs(void);
long lcycles(void);
+void devmask(Pgrp*,int,char*);
+int devallowed(Pgrp*, int);
+int canmount(Pgrp*);
#pragma varargck argpos iprint 1
#pragma varargck argpos panic 1
diff --git a/sys/src/9/port/sysfile.c b/sys/src/9/port/sysfile.c
index b7b0c51aa..f98fbf841 100644
--- a/sys/src/9/port/sysfile.c
+++ b/sys/src/9/port/sysfile.c
@@ -1048,7 +1048,7 @@ bindmount(int ismount, int fd, int afd, char* arg0, char* arg1, int flag, char*
nexterror();
}
- if(up->pgrp->noattach)
+ if(!canmount(up->pgrp))
error(Enoattach);
ac = nil;
@@ -1160,14 +1160,8 @@ sysunmount(va_list list)
nexterror();
}
if(name != nil) {
- /*
- * This has to be namec(..., Aopen, ...) because
- * if arg[0] is something like /srv/cs or /fd/0,
- * opening it is the only way to get at the real
- * Chan underneath.
- */
validaddr((uintptr)name, 1, 0);
- cmounted = namec(name, Aopen, OREAD, 0);
+ cmounted = namec(name, Aunmount, OREAD, 0);
}
cunmount(cmount, cmounted);
poperror();
diff --git a/sys/src/9/port/sysproc.c b/sys/src/9/port/sysproc.c
index b3b7a0439..bb25b2b4b 100644
--- a/sys/src/9/port/sysproc.c
+++ b/sys/src/9/port/sysproc.c
@@ -34,6 +34,7 @@ sysrfork(va_list list)
Egrp *oeg;
ulong pid, flag;
Mach *wm;
+ char *devs;
flag = va_arg(list, ulong);
/* Check flags before we commit */
@@ -44,6 +45,11 @@ sysrfork(va_list list)
if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG))
error(Ebadarg);
+ /*
+ * Code using RFNOMNT expects to block all but
+ * the following devices.
+ */
+ devs = "|decp";
if((flag&RFPROC) == 0) {
if(flag & (RFMEM|RFNOWAIT))
error(Ebadarg);
@@ -60,12 +66,12 @@ sysrfork(va_list list)
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;
+ devmask(up->pgrp, 1, devs);
if(flag & RFREND) {
org = up->rgrp;
up->rgrp = newrgrp();
@@ -177,15 +183,15 @@ sysrfork(va_list list)
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;
incref(p->pgrp);
}
if(flag & RFNOMNT)
- p->pgrp->noattach = 1;
+ devmask(p->pgrp, 1, devs);
if(flag & RFREND)
p->rgrp = newrgrp();