auth/box: build restricted namespaces using components from the parent.
This commit is contained in:
parent
f4840cdba5
commit
056ad652a4
3 changed files with 230 additions and 0 deletions
|
@ -60,6 +60,20 @@ changeuser, convkeys, printnetkey, status, enable, disable, authsrv, guard.srv,
|
||||||
.I arg
|
.I arg
|
||||||
\&...
|
\&...
|
||||||
.PP
|
.PP
|
||||||
|
.B auth/box
|
||||||
|
[
|
||||||
|
.B -d
|
||||||
|
] [
|
||||||
|
.B -rc
|
||||||
|
.I file
|
||||||
|
] [
|
||||||
|
.B -e
|
||||||
|
.I devs
|
||||||
|
]
|
||||||
|
.I command
|
||||||
|
.I arg
|
||||||
|
\&...
|
||||||
|
.PP
|
||||||
.B auth/as
|
.B auth/as
|
||||||
[
|
[
|
||||||
.B -d
|
.B -d
|
||||||
|
@ -264,6 +278,29 @@ If there are no arguments, it
|
||||||
It's an easy way to run a command as
|
It's an easy way to run a command as
|
||||||
.IR none .
|
.IR none .
|
||||||
.PP
|
.PP
|
||||||
|
.I Box
|
||||||
|
sets up a restricted namespace and
|
||||||
|
.IR exec's
|
||||||
|
its arguments as the user
|
||||||
|
.IR none .
|
||||||
|
Components of the current namespace are bound
|
||||||
|
into the child namespace with the
|
||||||
|
.B -r
|
||||||
|
and
|
||||||
|
.B -c
|
||||||
|
flags, using either
|
||||||
|
.I MREPL
|
||||||
|
or
|
||||||
|
.I MCREATE
|
||||||
|
respectively. The only components
|
||||||
|
in the child namespace will be those
|
||||||
|
defined this way.
|
||||||
|
By default all further kernel driver
|
||||||
|
access is blocked. The
|
||||||
|
.B -e
|
||||||
|
flag specifies a string of driver
|
||||||
|
characters to keep in the child namespace.
|
||||||
|
.PP
|
||||||
.I As
|
.I As
|
||||||
executes
|
executes
|
||||||
.I command
|
.I command
|
||||||
|
|
192
sys/src/cmd/auth/box.c
Normal file
192
sys/src/cmd/auth/box.c
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <auth.h>
|
||||||
|
|
||||||
|
static int debug;
|
||||||
|
|
||||||
|
static void
|
||||||
|
binderr(char *new, char *old, int flag)
|
||||||
|
{
|
||||||
|
char dash[4] = { '-' };
|
||||||
|
|
||||||
|
if(debug){
|
||||||
|
if(flag & MCREATE){
|
||||||
|
dash[2] = 'c';
|
||||||
|
flag &= ~MCREATE;
|
||||||
|
}
|
||||||
|
switch(flag){
|
||||||
|
case MREPL:
|
||||||
|
dash[0] = ' ';
|
||||||
|
if(dash[2] == 'c')
|
||||||
|
dash[1] = '-';
|
||||||
|
else
|
||||||
|
dash[1] = ' ';
|
||||||
|
break;
|
||||||
|
case MBEFORE:
|
||||||
|
dash[1] = 'b';
|
||||||
|
break;
|
||||||
|
case MAFTER:
|
||||||
|
dash[1] = 'a';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
print("bind %s %s %s\n", dash, new, old);
|
||||||
|
}
|
||||||
|
if(bind(new, old, flag) < 0)
|
||||||
|
sysfatal("bind: %r");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
resolvenames(char **names, int nname)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char buf[8192];
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open(".", OREAD|OCEXEC);
|
||||||
|
if(fd < 0)
|
||||||
|
sysfatal("could not open .: %r");
|
||||||
|
fd2path(fd, buf, sizeof buf);
|
||||||
|
for(i = 0; i < nname; i++){
|
||||||
|
if(names[i] == nil)
|
||||||
|
continue;
|
||||||
|
cleanname(names[i]);
|
||||||
|
switch(names[i][0]){
|
||||||
|
case '#':
|
||||||
|
case '/':
|
||||||
|
break;
|
||||||
|
case '.':
|
||||||
|
if(names[i][1] == '/')
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
names[i] = cleanname(smprint("%s/%s", buf, names[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sandbox(char **names, int *flags, int nname)
|
||||||
|
{
|
||||||
|
char *parts[32];
|
||||||
|
char rootskel[128];
|
||||||
|
char src[8192], targ[8192], dir[8192], skel[8192];
|
||||||
|
char name[8192];
|
||||||
|
char *newroot;
|
||||||
|
Dir *d;
|
||||||
|
int i, j, n;
|
||||||
|
|
||||||
|
snprint(rootskel, sizeof rootskel, "#zd/newroot.%d", getpid());
|
||||||
|
binderr(rootskel, "/", MBEFORE);
|
||||||
|
|
||||||
|
newroot = rootskel + strlen("#zd");
|
||||||
|
|
||||||
|
for(j = 0; j < nname; j++){
|
||||||
|
if(names[j] == nil)
|
||||||
|
continue;
|
||||||
|
utfecpy(name, &name[sizeof name-1], names[j]);
|
||||||
|
n = gettokens(name, parts, nelem(parts), "/");
|
||||||
|
utfecpy(targ, &targ[sizeof targ-1], newroot);
|
||||||
|
memset(src, 0, sizeof src);
|
||||||
|
for(i = 0; i < n; i++){
|
||||||
|
utfecpy(dir, &dir[sizeof dir-1], targ);
|
||||||
|
snprint(targ, sizeof targ, "%s/%s", targ, parts[i]);
|
||||||
|
snprint(src, sizeof src, "%s/%s", src, parts[i]);
|
||||||
|
d = dirstat(targ);
|
||||||
|
if(d != nil){
|
||||||
|
free(d);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
d = dirstat(src);
|
||||||
|
if(d == nil)
|
||||||
|
continue;
|
||||||
|
if(d->mode & DMDIR)
|
||||||
|
snprint(skel, sizeof skel, "#zd/%s", parts[i]);
|
||||||
|
else
|
||||||
|
snprint(skel, sizeof skel, "#zf/%s", parts[i]);
|
||||||
|
free(d);
|
||||||
|
binderr(skel, dir, MBEFORE);
|
||||||
|
}
|
||||||
|
binderr(names[j], targ, flags[j]);
|
||||||
|
}
|
||||||
|
binderr(newroot, "/", MREPL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
run(char **a)
|
||||||
|
{
|
||||||
|
exec(a[0], a);
|
||||||
|
|
||||||
|
if(a[0][0] != '/' && a[0][0] != '#' &&
|
||||||
|
(a[0][0] != '.' || (a[0][1] != '/' &&
|
||||||
|
(a[0][1] != '.' || a[0][2] != '/'))))
|
||||||
|
exec(smprint("/bin/%s", a[0]), a);
|
||||||
|
|
||||||
|
sysfatal("exec: %s: %r", a[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprint(2, "usage %s: [ -d ] [ -r file ] [ -c dir ] [ -e devs ] cmd args...\n", argv0);
|
||||||
|
exits("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char devs[1024];
|
||||||
|
int dfd;
|
||||||
|
char *parts[256];
|
||||||
|
int mflags[256];
|
||||||
|
int nparts;
|
||||||
|
|
||||||
|
nparts = 0;
|
||||||
|
memset(devs, 0, sizeof devs);
|
||||||
|
ARGBEGIN{
|
||||||
|
case 'd':
|
||||||
|
debug = 1;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
parts[nparts] = EARGF(usage());
|
||||||
|
mflags[nparts++] = MREPL;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
parts[nparts] = EARGF(usage());
|
||||||
|
mflags[nparts++] = MCREATE|MREPL;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
snprint(devs, sizeof devs, "%s%s", devs, EARGF(usage()));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
break;
|
||||||
|
}ARGEND
|
||||||
|
if(argc == 0)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
rfork(RFNAMEG|RFENVG);
|
||||||
|
dfd = open("/dev/drivers", OWRITE|OCEXEC);
|
||||||
|
if(dfd < 0)
|
||||||
|
sysfatal("could not /dev/drivers: %r");
|
||||||
|
|
||||||
|
resolvenames(parts, nparts);
|
||||||
|
|
||||||
|
if(procsetuser("none") < 0)
|
||||||
|
sysfatal("cant become none: %r");
|
||||||
|
putenv("user", "none");
|
||||||
|
|
||||||
|
sandbox(parts, mflags, nparts);
|
||||||
|
|
||||||
|
if(debug)
|
||||||
|
print("chdev %s\n", devs);
|
||||||
|
|
||||||
|
if(devs[0] != '\0'){
|
||||||
|
if(fprint(dfd, "chdev & %s", devs) <= 0)
|
||||||
|
sysfatal("could not write chdev: %r");
|
||||||
|
} else {
|
||||||
|
if(fprint(dfd, "chdev ~") <= 0)
|
||||||
|
sysfatal("could not write chdev: %r");
|
||||||
|
}
|
||||||
|
close(dfd);
|
||||||
|
run(argv);
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ TARG=\
|
||||||
asn1dump\
|
asn1dump\
|
||||||
asn12rsa\
|
asn12rsa\
|
||||||
authsrv\
|
authsrv\
|
||||||
|
box\
|
||||||
changeuser\
|
changeuser\
|
||||||
convkeys\
|
convkeys\
|
||||||
cron\
|
cron\
|
||||||
|
|
Loading…
Reference in a new issue