summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2020-12-13 16:04:09 +0100
committercinap_lenrek <cinap_lenrek@felloff.net>2020-12-13 16:04:09 +0100
commit0b33b3b8adf95bcf6cf0764fe425169ee0b8be0e (patch)
tree08aba9ebf384974079de17fffd1c1e3139cfaf38
parentb2b2d2cb4c5cb3153760084a55584817a2c58a24 (diff)
downloadplan9front-0b33b3b8adf95bcf6cf0764fe425169ee0b8be0e.tar.xz
kernel: implement per file descriptor OCEXEC flag, reject ORCLOSE when opening /fd, /srv and /shr
The OCEXEC flag used to be maintained per channel, making it shared between all the file desciptors. This has a unexpected side effects with regard to channel passing drivers such as devdup (/fd), devsrv (/srv) and devshr (/shr). For example, opening a /srv file with OCEXEC makes it impossible to be remounted by exportfs as it internally does a exec() to mount and re-export it. There is no way to reset the flag. This change makes the OCEXEC flag per file descriptor, so a open with the OCEXEC flag only affects the fd group of the calling process, and not the channel itself. On rfork(RFFDG), the per file descriptor flags get copied. On dup(), the per file descriptor flags are reset. The second modification is that /fd, /srv and /shr should reject the ORCLOSE flag, as the files that are returned have already been opend.
-rw-r--r--sys/man/2/dup13
-rw-r--r--sys/src/9/port/auth.c5
-rw-r--r--sys/src/9/port/chan.c7
-rw-r--r--sys/src/9/port/devdup.c2
-rw-r--r--sys/src/9/port/devshr.c2
-rw-r--r--sys/src/9/port/devsrv.c4
-rw-r--r--sys/src/9/port/lib.h2
-rw-r--r--sys/src/9/port/pgrp.c14
-rw-r--r--sys/src/9/port/portdat.h3
-rw-r--r--sys/src/9/port/portfns.h2
-rw-r--r--sys/src/9/port/sysfile.c50
11 files changed, 74 insertions, 30 deletions
diff --git a/sys/man/2/dup b/sys/man/2/dup
index cd3414106..1eca0a713 100644
--- a/sys/man/2/dup
+++ b/sys/man/2/dup
@@ -32,6 +32,19 @@ requires that
.I newfd
be no greater than 20 more than the highest file descriptor ever used by
the program.
+.PP
+.I Dup
+does not copy the per file descriptor
+.B OCEXEC
+flag,
+meaning that
+.I newfd
+will not be closed on
+.IR exec(2)
+syscall,
+when
+.I oldfd
+had been previously opend with it.
.SH SOURCE
.B /sys/src/libc/9syscall
.SH SEE ALSO
diff --git a/sys/src/9/port/auth.c b/sys/src/9/port/auth.c
index 2cc54c657..b6b19bd63 100644
--- a/sys/src/9/port/auth.c
+++ b/sys/src/9/port/auth.c
@@ -97,13 +97,12 @@ sysfauth(va_list list)
nexterror();
}
- fd = newfd(ac);
+ /* always mark it close on exec */
+ fd = newfd(ac, OCEXEC);
if(fd < 0)
error(Enofd);
poperror(); /* ac */
- /* always mark it close on exec */
- ac->flag |= CCEXEC;
return (uintptr)fd;
}
diff --git a/sys/src/9/port/chan.c b/sys/src/9/port/chan.c
index 58a47cc83..e60561d1a 100644
--- a/sys/src/9/port/chan.c
+++ b/sys/src/9/port/chan.c
@@ -1468,9 +1468,6 @@ namec(char *aname, int amode, int omode, ulong perm)
saveregisters();
c = devtab[c->type]->open(c, omode&~OCEXEC);
-
- if(omode & OCEXEC)
- c->flag |= CCEXEC;
if(omode & ORCLOSE)
c->flag |= CRCLOSE;
break;
@@ -1571,11 +1568,9 @@ namec(char *aname, int amode, int omode, ulong perm)
incref(cnew->path);
cnew = devtab[cnew->type]->create(cnew, e.elems[e.nelems-1], omode&~(OEXCL|OCEXEC), perm);
- poperror();
- if(omode & OCEXEC)
- cnew->flag |= CCEXEC;
if(omode & ORCLOSE)
cnew->flag |= CRCLOSE;
+ poperror();
putmhead(m);
cclose(c);
c = cnew;
diff --git a/sys/src/9/port/devdup.c b/sys/src/9/port/devdup.c
index 2ba718729..79c7d90ff 100644
--- a/sys/src/9/port/devdup.c
+++ b/sys/src/9/port/devdup.c
@@ -63,6 +63,8 @@ dupopen(Chan *c, int omode)
Chan *f;
int fd, twicefd;
+ if(omode & ORCLOSE)
+ error(Eperm);
if(c->qid.type & QTDIR){
if(omode != 0)
error(Eisdir);
diff --git a/sys/src/9/port/devshr.c b/sys/src/9/port/devshr.c
index 96e319221..225ba6c93 100644
--- a/sys/src/9/port/devshr.c
+++ b/sys/src/9/port/devshr.c
@@ -396,6 +396,8 @@ shropen(Chan *c, int omode)
case Qcmpt:
if(omode&OTRUNC)
error(Eexist);
+ if(omode&ORCLOSE)
+ error(Eperm);
shr = sch->shr;
mpt = sch->mpt;
devpermcheck(mpt->owner, mpt->perm, mode);
diff --git a/sys/src/9/port/devsrv.c b/sys/src/9/port/devsrv.c
index 193fa6c8b..8128569a1 100644
--- a/sys/src/9/port/devsrv.c
+++ b/sys/src/9/port/devsrv.c
@@ -135,6 +135,8 @@ srvopen(Chan *c, int omode)
if(omode&OTRUNC)
error(Eexist);
+ if(omode&ORCLOSE)
+ error(Eperm);
if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR)
error(Eperm);
devpermcheck(sp->owner, sp->perm, omode);
@@ -338,8 +340,6 @@ srvwrite(Chan *c, void *va, long n, vlong)
cclose(c1);
nexterror();
}
- if(c1->flag & (CCEXEC|CRCLOSE))
- error("posted fd has remove-on-close or close-on-exec");
if(c1->qid.type & QTAUTH)
error("cannot post auth file in srv");
sp = srvlookup(nil, c->qid.path);
diff --git a/sys/src/9/port/lib.h b/sys/src/9/port/lib.h
index 1f7bf7d1d..06b423d9d 100644
--- a/sys/src/9/port/lib.h
+++ b/sys/src/9/port/lib.h
@@ -176,7 +176,7 @@ extern void qsort(void*, long, long, int (*)(void*, void*));
#define ORDWR 2 /* read and write */
#define OEXEC 3 /* execute, == read but check execute permission */
#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */
-#define OCEXEC 32 /* or'ed in, close on exec */
+#define OCEXEC 32 /* or'ed in (per file descriptor), close on exec */
#define ORCLOSE 64 /* or'ed in, remove on close */
#define OEXCL 0x1000 /* or'ed in, exclusive create */
diff --git a/sys/src/9/port/pgrp.c b/sys/src/9/port/pgrp.c
index 5576acc57..408370d35 100644
--- a/sys/src/9/port/pgrp.c
+++ b/sys/src/9/port/pgrp.c
@@ -140,7 +140,8 @@ dupfgrp(Fgrp *f)
new = smalloc(sizeof(Fgrp));
if(f == nil){
- new->fd = smalloc(DELTAFD*sizeof(Chan*));
+ new->flag = smalloc(DELTAFD*sizeof(new->flag[0]));
+ new->fd = smalloc(DELTAFD*sizeof(new->fd[0]));
new->nfd = DELTAFD;
new->ref = 1;
return new;
@@ -152,12 +153,19 @@ dupfgrp(Fgrp *f)
i = new->nfd%DELTAFD;
if(i != 0)
new->nfd += DELTAFD - i;
- new->fd = malloc(new->nfd*sizeof(Chan*));
+ new->fd = malloc(new->nfd*sizeof(new->fd[0]));
if(new->fd == nil){
unlock(f);
free(new);
error("no memory for fgrp");
}
+ new->flag = malloc(new->nfd*sizeof(new->flag[0]));
+ if(new->flag == nil){
+ unlock(f);
+ free(new->fd);
+ free(new);
+ error("no memory for fgrp");
+ }
new->ref = 1;
new->maxfd = f->maxfd;
@@ -165,6 +173,7 @@ dupfgrp(Fgrp *f)
if((c = f->fd[i]) != nil){
incref(c);
new->fd[i] = c;
+ new->flag[i] = f->flag[i];
}
}
unlock(f);
@@ -194,6 +203,7 @@ closefgrp(Fgrp *f)
up->closingfgrp = nil;
free(f->fd);
+ free(f->flag);
free(f);
}
diff --git a/sys/src/9/port/portdat.h b/sys/src/9/port/portdat.h
index 7c9aa7193..a5cdafa6a 100644
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -125,7 +125,7 @@ enum
COPEN = 0x0001, /* for i/o */
CMSG = 0x0002, /* the message channel for a mount */
/*rsc CCREATE = 0x0004, /* permits creation if c->mnt */
- CCEXEC = 0x0008, /* close on exec */
+ CCEXEC = 0x0008, /* close on exec (per file descriptor) */
CFREE = 0x0010, /* not in use */
CRCLOSE = 0x0020, /* remove on close */
CCACHE = 0x0080, /* client cache */
@@ -509,6 +509,7 @@ struct Fgrp
Ref;
Lock;
Chan **fd;
+ uchar *flag; /* per file-descriptor flags (CCEXEC) */
int nfd; /* number allocated */
int maxfd; /* highest fd in use */
int exceed; /* debugging */
diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h
index 04550987f..00c7e8b96 100644
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -201,7 +201,7 @@ Chan* namec(char*, int, int, ulong);
void nameerror(char*, char*);
int needpages(void*);
Chan* newchan(void);
-int newfd(Chan*);
+int newfd(Chan*, int);
Mhead* newmhead(Chan*);
Mount* newmount(Chan*, int, char*);
Page* newpage(int, Segment **, uintptr);
diff --git a/sys/src/9/port/sysfile.c b/sys/src/9/port/sysfile.c
index ed8e5c7ad..a503b2cca 100644
--- a/sys/src/9/port/sysfile.c
+++ b/sys/src/9/port/sysfile.c
@@ -25,33 +25,45 @@ int
growfd(Fgrp *f, int fd) /* fd is always >= 0 */
{
Chan **newfd, **oldfd;
+ uchar *newflag, *oldflag;
+ int nfd;
- if(fd < f->nfd)
+ nfd = f->nfd;
+ if(fd < nfd)
return 0;
- if(fd >= f->nfd+DELTAFD)
+ if(fd >= nfd+DELTAFD)
return -1; /* out of range */
/*
* Unbounded allocation is unwise; besides, there are only 16 bits
* of fid in 9P
*/
- if(f->nfd >= 5000){
+ if(nfd >= 5000){
Exhausted:
print("no free file descriptors\n");
return -1;
}
- newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*));
+ oldfd = f->fd;
+ oldflag = f->flag;
+ newfd = malloc((nfd+DELTAFD)*sizeof(newfd[0]));
if(newfd == nil)
goto Exhausted;
- oldfd = f->fd;
- memmove(newfd, oldfd, f->nfd*sizeof(Chan*));
+ memmove(newfd, oldfd, nfd*sizeof(newfd[0]));
+ newflag = malloc((nfd+DELTAFD)*sizeof(newflag[0]));
+ if(newflag == nil){
+ free(newfd);
+ goto Exhausted;
+ }
+ memmove(newflag, oldflag, nfd*sizeof(newflag[0]));
f->fd = newfd;
- free(oldfd);
- f->nfd += DELTAFD;
+ f->flag = newflag;
+ f->nfd = nfd+DELTAFD;
if(fd > f->maxfd){
if(fd/100 > f->maxfd/100)
f->exceed = (fd/100)*100;
f->maxfd = fd;
}
+ free(oldfd);
+ free(oldflag);
return 1;
}
@@ -72,9 +84,9 @@ findfreefd(Fgrp *f, int start)
}
int
-newfd(Chan *c)
+newfd(Chan *c, int mode)
{
- int fd;
+ int fd, flag;
Fgrp *f;
f = up->fgrp;
@@ -87,6 +99,13 @@ newfd(Chan *c)
if(fd > f->maxfd)
f->maxfd = fd;
f->fd[fd] = c;
+
+ /* per file-descriptor flags */
+ flag = 0;
+ if(mode & OCEXEC)
+ flag |= CCEXEC;
+ f->flag[fd] = flag;
+
unlockfgrp(f);
return fd;
}
@@ -112,6 +131,8 @@ newfd2(int fd[2], Chan *c[2])
f->maxfd = fd[1];
f->fd[fd[0]] = c[0];
f->fd[fd[1]] = c[1];
+ f->flag[fd[0]] = 0;
+ f->flag[fd[1]] = 0;
unlockfgrp(f);
return 0;
}
@@ -247,6 +268,7 @@ sysdup(va_list list)
oc = f->fd[fd];
f->fd[fd] = c;
+ f->flag[fd] = 0;
unlockfgrp(f);
if(oc != nil)
cclose(oc);
@@ -255,7 +277,7 @@ sysdup(va_list list)
cclose(c);
nexterror();
}
- fd = newfd(c);
+ fd = newfd(c, 0);
if(fd < 0)
error(Enofd);
poperror();
@@ -280,7 +302,7 @@ sysopen(va_list list)
cclose(c);
nexterror();
}
- fd = newfd(c);
+ fd = newfd(c, mode);
if(fd < 0)
error(Enofd);
poperror();
@@ -295,7 +317,7 @@ fdclose(int fd, int flag)
lock(f);
c = fd <= f->maxfd ? f->fd[fd] : nil;
- if(c == nil || (flag != 0 && (c->flag&flag) == 0)){
+ if(c == nil || (flag != 0 && ((f->flag[fd]|c->flag)&flag) == 0)){
unlock(f);
return;
}
@@ -1166,7 +1188,7 @@ syscreate(va_list list)
cclose(c);
nexterror();
}
- fd = newfd(c);
+ fd = newfd(c, mode);
if(fd < 0)
error(Enofd);
poperror();