kernel: add chdev command to devcons
This commit is contained in:
parent
54328d2e65
commit
00b7d2385a
10 changed files with 209 additions and 36 deletions
|
@ -90,12 +90,62 @@ file is a read-only file that produces an infinite stream of zero-valued bytes w
|
||||||
.PP
|
.PP
|
||||||
The
|
The
|
||||||
.B drivers
|
.B drivers
|
||||||
file contains, one per line, a listing of the drivers configured in the kernel, in the format
|
file contains, one per line, a listing of available kernel drivers, in the format
|
||||||
.IP
|
.IP
|
||||||
.EX
|
.EX
|
||||||
#c cons
|
#c cons
|
||||||
.EE
|
.EE
|
||||||
.PP
|
.PP
|
||||||
|
Each process name group (see
|
||||||
|
.IR fork (2))
|
||||||
|
maintains a mask of allowed drivers.
|
||||||
|
A process can modify that mask through writes to the
|
||||||
|
.B drivers
|
||||||
|
file. Messages are in the format of:
|
||||||
|
.IP
|
||||||
|
.EX
|
||||||
|
chdev \f2op\fP \f2devmask\fP
|
||||||
|
.EE
|
||||||
|
.PP
|
||||||
|
.I Devmask
|
||||||
|
is a string of driver characters.
|
||||||
|
.I Op
|
||||||
|
specifies how
|
||||||
|
.I devmask
|
||||||
|
is interpreted.
|
||||||
|
.I Op
|
||||||
|
is one of:
|
||||||
|
.TP
|
||||||
|
.B &
|
||||||
|
Permit access to just the drivers specified in
|
||||||
|
.IR devmask .
|
||||||
|
.TP
|
||||||
|
.B &~
|
||||||
|
Permit access to all but the drivers specified in
|
||||||
|
.IR devmask .
|
||||||
|
.TP
|
||||||
|
.B ~
|
||||||
|
Remove access to all devices.
|
||||||
|
.I Devmask
|
||||||
|
is ignored.
|
||||||
|
.PP
|
||||||
|
Access may only be removed. No
|
||||||
|
.I op
|
||||||
|
permits a process to regain access to a driver
|
||||||
|
once it has been removed.
|
||||||
|
Removing access to
|
||||||
|
.IR mnt (3)
|
||||||
|
additionally prevents new mounts into the current namespace.
|
||||||
|
The following removes access to all drivers except
|
||||||
|
.IR draw (3),
|
||||||
|
.IR cons (3),
|
||||||
|
and
|
||||||
|
.IR fs (3):
|
||||||
|
.IP
|
||||||
|
.EX
|
||||||
|
chdev & ick
|
||||||
|
.EE
|
||||||
|
.PP
|
||||||
The
|
The
|
||||||
.B hostdomain
|
.B hostdomain
|
||||||
file contains the name of the authentication domain that
|
file contains the name of the authentication domain that
|
||||||
|
|
|
@ -1272,7 +1272,7 @@ nameerror(char *name, char *err)
|
||||||
Chan*
|
Chan*
|
||||||
namec(char *aname, int amode, int omode, ulong perm)
|
namec(char *aname, int amode, int omode, ulong perm)
|
||||||
{
|
{
|
||||||
int len, n, t, nomount;
|
int len, n, t, nomount, devunmount;
|
||||||
Chan *c;
|
Chan *c;
|
||||||
Chan *volatile cnew;
|
Chan *volatile cnew;
|
||||||
Path *volatile path;
|
Path *volatile path;
|
||||||
|
@ -1291,6 +1291,24 @@ namec(char *aname, int amode, int omode, ulong perm)
|
||||||
}
|
}
|
||||||
name = aname;
|
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
|
* Find the starting off point (the current slash, the root of
|
||||||
* a device tree, or the current dot) as well as the name to
|
* a device tree, or the current dot) as well as the name to
|
||||||
|
@ -1313,24 +1331,13 @@ namec(char *aname, int amode, int omode, ulong perm)
|
||||||
up->genbuf[n++] = *name++;
|
up->genbuf[n++] = *name++;
|
||||||
}
|
}
|
||||||
up->genbuf[n] = '\0';
|
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;
|
n = chartorune(&r, up->genbuf+1)+1;
|
||||||
if(up->pgrp->noattach && utfrune("|decp", r)==nil)
|
|
||||||
error(Enoattach);
|
|
||||||
t = devno(r, 1);
|
t = devno(r, 1);
|
||||||
if(t == -1)
|
if(t == -1)
|
||||||
error(Ebadsharp);
|
error(Ebadsharp);
|
||||||
|
if(!devunmount && !devallowed(up->pgrp, r))
|
||||||
|
error(Enoattach);
|
||||||
|
|
||||||
c = devtab[t]->attach(up->genbuf+n);
|
c = devtab[t]->attach(up->genbuf+n);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,63 @@ devno(int c, int user)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
void
|
||||||
devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db)
|
devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db)
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,6 +39,16 @@ Cmdtab rebootmsg[] =
|
||||||
CMrdb, "rdb", 0,
|
CMrdb, "rdb", 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CMchdev,
|
||||||
|
};
|
||||||
|
|
||||||
|
Cmdtab drivermsg[] =
|
||||||
|
{
|
||||||
|
CMchdev, "chdev", 0,
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
printinit(void)
|
printinit(void)
|
||||||
{
|
{
|
||||||
|
@ -332,7 +342,7 @@ static Dirtab consdir[]={
|
||||||
"cons", {Qcons}, 0, 0660,
|
"cons", {Qcons}, 0, 0660,
|
||||||
"consctl", {Qconsctl}, 0, 0220,
|
"consctl", {Qconsctl}, 0, 0220,
|
||||||
"cputime", {Qcputime}, 6*NUMSIZE, 0444,
|
"cputime", {Qcputime}, 6*NUMSIZE, 0444,
|
||||||
"drivers", {Qdrivers}, 0, 0444,
|
"drivers", {Qdrivers}, 0, 0666,
|
||||||
"hostdomain", {Qhostdomain}, DOMLEN, 0664,
|
"hostdomain", {Qhostdomain}, DOMLEN, 0664,
|
||||||
"hostowner", {Qhostowner}, 0, 0664,
|
"hostowner", {Qhostowner}, 0, 0664,
|
||||||
"kmesg", {Qkmesg}, 0, 0440,
|
"kmesg", {Qkmesg}, 0, 0440,
|
||||||
|
@ -583,9 +593,15 @@ consread(Chan *c, void *buf, long n, vlong off)
|
||||||
case Qdrivers:
|
case Qdrivers:
|
||||||
b = smalloc(READSTR);
|
b = smalloc(READSTR);
|
||||||
k = 0;
|
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",
|
k += snprint(b+k, READSTR-k, "#%C %s\n",
|
||||||
devtab[i]->dc, devtab[i]->name);
|
devtab[i]->dc, devtab[i]->name);
|
||||||
|
}
|
||||||
|
runlock(&up->pgrp->ns);
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
free(b);
|
free(b);
|
||||||
nexterror();
|
nexterror();
|
||||||
|
@ -620,6 +636,7 @@ conswrite(Chan *c, void *va, long n, vlong off)
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
long l, bp;
|
long l, bp;
|
||||||
|
int invert;
|
||||||
char *a;
|
char *a;
|
||||||
Mach *mp;
|
Mach *mp;
|
||||||
int id;
|
int id;
|
||||||
|
@ -676,6 +693,41 @@ conswrite(Chan *c, void *va, long n, vlong off)
|
||||||
error(Eperm);
|
error(Eperm);
|
||||||
break;
|
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:
|
case Qreboot:
|
||||||
if(!iseve())
|
if(!iseve())
|
||||||
error(Eperm);
|
error(Eperm);
|
||||||
|
|
|
@ -464,7 +464,7 @@ shrcreate(Chan *c, char *name, int omode, ulong perm)
|
||||||
cclose(c);
|
cclose(c);
|
||||||
return nc;
|
return nc;
|
||||||
case Qcroot:
|
case Qcroot:
|
||||||
if(up->pgrp->noattach)
|
if(!canmount(up->pgrp))
|
||||||
error(Enoattach);
|
error(Enoattach);
|
||||||
if((perm & DMDIR) == 0 || mode != OREAD)
|
if((perm & DMDIR) == 0 || mode != OREAD)
|
||||||
error(Eperm);
|
error(Eperm);
|
||||||
|
@ -498,7 +498,7 @@ shrcreate(Chan *c, char *name, int omode, ulong perm)
|
||||||
sch->shr = shr;
|
sch->shr = shr;
|
||||||
break;
|
break;
|
||||||
case Qcshr:
|
case Qcshr:
|
||||||
if(up->pgrp->noattach)
|
if(!canmount(up->pgrp))
|
||||||
error(Enoattach);
|
error(Enoattach);
|
||||||
if((perm & DMDIR) != 0 || mode != OWRITE)
|
if((perm & DMDIR) != 0 || mode != OWRITE)
|
||||||
error(Eperm);
|
error(Eperm);
|
||||||
|
@ -731,7 +731,7 @@ shrwrite(Chan *c, void *va, long n, vlong)
|
||||||
Mhead *h;
|
Mhead *h;
|
||||||
Mount *m;
|
Mount *m;
|
||||||
|
|
||||||
if(up->pgrp->noattach)
|
if(!canmount(up->pgrp))
|
||||||
error(Enoattach);
|
error(Enoattach);
|
||||||
sch = tosch(c);
|
sch = tosch(c);
|
||||||
if(sch->level != Qcmpt)
|
if(sch->level != Qcmpt)
|
||||||
|
|
|
@ -78,6 +78,9 @@ END{
|
||||||
if(ARGC < 2)
|
if(ARGC < 2)
|
||||||
exit "usage"
|
exit "usage"
|
||||||
|
|
||||||
|
if(ndev >= 256)
|
||||||
|
exit "device count will overflow Pgrp.notallowed"
|
||||||
|
|
||||||
printf "#include \"u.h\"\n";
|
printf "#include \"u.h\"\n";
|
||||||
printf "#include \"../port/lib.h\"\n";
|
printf "#include \"../port/lib.h\"\n";
|
||||||
printf "#include \"mem.h\"\n";
|
printf "#include \"mem.h\"\n";
|
||||||
|
|
|
@ -121,6 +121,7 @@ enum
|
||||||
Amount, /* to be mounted or mounted upon */
|
Amount, /* to be mounted or mounted upon */
|
||||||
Acreate, /* is to be created */
|
Acreate, /* is to be created */
|
||||||
Aremove, /* will be removed by caller */
|
Aremove, /* will be removed by caller */
|
||||||
|
Aunmount, /* unmount arg[0] */
|
||||||
|
|
||||||
COPEN = 0x0001, /* for i/o */
|
COPEN = 0x0001, /* for i/o */
|
||||||
CMSG = 0x0002, /* the message channel for a mount */
|
CMSG = 0x0002, /* the message channel for a mount */
|
||||||
|
@ -484,7 +485,7 @@ struct Pgrp
|
||||||
{
|
{
|
||||||
Ref;
|
Ref;
|
||||||
RWlock ns; /* Namespace n read/one write lock */
|
RWlock ns; /* Namespace n read/one write lock */
|
||||||
int noattach;
|
u64int notallowed[4]; /* Room for 256 devices */
|
||||||
Mhead *mnthash[MNTHASH];
|
Mhead *mnthash[MNTHASH];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -413,6 +413,9 @@ uint nhgetl(void*);
|
||||||
ushort nhgets(void*);
|
ushort nhgets(void*);
|
||||||
ulong µs(void);
|
ulong µs(void);
|
||||||
long lcycles(void);
|
long lcycles(void);
|
||||||
|
void devmask(Pgrp*,int,char*);
|
||||||
|
int devallowed(Pgrp*, int);
|
||||||
|
int canmount(Pgrp*);
|
||||||
|
|
||||||
#pragma varargck argpos iprint 1
|
#pragma varargck argpos iprint 1
|
||||||
#pragma varargck argpos panic 1
|
#pragma varargck argpos panic 1
|
||||||
|
|
|
@ -1048,7 +1048,7 @@ bindmount(int ismount, int fd, int afd, char* arg0, char* arg1, int flag, char*
|
||||||
nexterror();
|
nexterror();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(up->pgrp->noattach)
|
if(!canmount(up->pgrp))
|
||||||
error(Enoattach);
|
error(Enoattach);
|
||||||
|
|
||||||
ac = nil;
|
ac = nil;
|
||||||
|
@ -1160,14 +1160,8 @@ sysunmount(va_list list)
|
||||||
nexterror();
|
nexterror();
|
||||||
}
|
}
|
||||||
if(name != nil) {
|
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);
|
validaddr((uintptr)name, 1, 0);
|
||||||
cmounted = namec(name, Aopen, OREAD, 0);
|
cmounted = namec(name, Aunmount, OREAD, 0);
|
||||||
}
|
}
|
||||||
cunmount(cmount, cmounted);
|
cunmount(cmount, cmounted);
|
||||||
poperror();
|
poperror();
|
||||||
|
|
|
@ -34,6 +34,7 @@ sysrfork(va_list list)
|
||||||
Egrp *oeg;
|
Egrp *oeg;
|
||||||
ulong pid, flag;
|
ulong pid, flag;
|
||||||
Mach *wm;
|
Mach *wm;
|
||||||
|
char *devs;
|
||||||
|
|
||||||
flag = va_arg(list, ulong);
|
flag = va_arg(list, ulong);
|
||||||
/* Check flags before we commit */
|
/* Check flags before we commit */
|
||||||
|
@ -44,6 +45,11 @@ sysrfork(va_list list)
|
||||||
if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG))
|
if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG))
|
||||||
error(Ebadarg);
|
error(Ebadarg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Code using RFNOMNT expects to block all but
|
||||||
|
* the following devices.
|
||||||
|
*/
|
||||||
|
devs = "|decp";
|
||||||
if((flag&RFPROC) == 0) {
|
if((flag&RFPROC) == 0) {
|
||||||
if(flag & (RFMEM|RFNOWAIT))
|
if(flag & (RFMEM|RFNOWAIT))
|
||||||
error(Ebadarg);
|
error(Ebadarg);
|
||||||
|
@ -60,12 +66,12 @@ sysrfork(va_list list)
|
||||||
up->pgrp = newpgrp();
|
up->pgrp = newpgrp();
|
||||||
if(flag & RFNAMEG)
|
if(flag & RFNAMEG)
|
||||||
pgrpcpy(up->pgrp, opg);
|
pgrpcpy(up->pgrp, opg);
|
||||||
/* inherit noattach */
|
/* inherit notallowed */
|
||||||
up->pgrp->noattach = opg->noattach;
|
memmove(up->pgrp->notallowed, opg->notallowed, sizeof up->pgrp->notallowed);
|
||||||
closepgrp(opg);
|
closepgrp(opg);
|
||||||
}
|
}
|
||||||
if(flag & RFNOMNT)
|
if(flag & RFNOMNT)
|
||||||
up->pgrp->noattach = 1;
|
devmask(up->pgrp, 1, devs);
|
||||||
if(flag & RFREND) {
|
if(flag & RFREND) {
|
||||||
org = up->rgrp;
|
org = up->rgrp;
|
||||||
up->rgrp = newrgrp();
|
up->rgrp = newrgrp();
|
||||||
|
@ -177,15 +183,15 @@ sysrfork(va_list list)
|
||||||
p->pgrp = newpgrp();
|
p->pgrp = newpgrp();
|
||||||
if(flag & RFNAMEG)
|
if(flag & RFNAMEG)
|
||||||
pgrpcpy(p->pgrp, up->pgrp);
|
pgrpcpy(p->pgrp, up->pgrp);
|
||||||
/* inherit noattach */
|
/* inherit notallowed */
|
||||||
p->pgrp->noattach = up->pgrp->noattach;
|
memmove(p->pgrp->notallowed, up->pgrp->notallowed, sizeof p->pgrp->notallowed);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
p->pgrp = up->pgrp;
|
p->pgrp = up->pgrp;
|
||||||
incref(p->pgrp);
|
incref(p->pgrp);
|
||||||
}
|
}
|
||||||
if(flag & RFNOMNT)
|
if(flag & RFNOMNT)
|
||||||
p->pgrp->noattach = 1;
|
devmask(p->pgrp, 1, devs);
|
||||||
|
|
||||||
if(flag & RFREND)
|
if(flag & RFREND)
|
||||||
p->rgrp = newrgrp();
|
p->rgrp = newrgrp();
|
||||||
|
|
Loading…
Reference in a new issue