* [9fans] Enterable namespaces: /proc/pid/$ns/srv
@ 2025-12-14 0:54 ori
2025-12-14 2:58 ` [9fans] Re: [9front] " Frank D. Engel, Jr.
0 siblings, 1 reply; 2+ messages in thread
From: ori @ 2025-12-14 0:54 UTC (permalink / raw)
To: 9front, 9fans
This patch makes it possible to enter a namespace through
/proc/$pid/ns, like so:
auth/newns -n /proc/$pid/ns $cmd
or through procesing the namespace file any other way
that they want.
with the hope it'll be useful for things like fixing up
tab completion in rio, making the plumber responsive to
the local namespace that we are plumbing from, and other
things that we haven't figured out yet.
It works by making the chans for a proc's mounts available
via /proc/$pid/srv/$id, and changing /proc/$pid/ns to use
the channel name rather than files other procs can't access,
such as '#|'.
Hopefully folks will be able to experiment a bit with this,
and figure out some good uses for it.
diff 4341e26ac5d5cb86af2e1d88dd85365e7feb3a59 uncommitted
--- a/sys/man/3/proc
+++ b/sys/man/3/proc
@@ -22,6 +22,7 @@
.BI /proc/ n /profile
.BI /proc/ n /regs
.BI /proc/ n /segment
+.BI /proc/ n /srv/ chan
.BI /proc/ n /status
.BI /proc/ n /text
.BI /proc/ n /wait
@@ -127,6 +128,15 @@
for read-only, if any;
starting virtual address, in hexadecimal;
ending virtual address, and reference count.
+.PP
+The
+.B srv
+directory provides a directory holding already-open channels
+to services in the style of
+.IR srv (3).
+This allows a process with appropriate permissions to execute the
+.I ns
+file and accurately reproduce the namespace of the process that is running.
.PP
The read-only
.B status
--- a/sys/src/9/port/devproc.c
+++ b/sys/src/9/port/devproc.c
@@ -28,6 +28,8 @@
Qnoteid,
Qnotepg,
Qns,
+ Qsrv,
+ Qchan,
Qppid,
Qproc,
Qregs,
@@ -100,6 +102,7 @@
"noteid", {Qnoteid}, 0, 0664,
"notepg", {Qnotepg}, 0, 0000,
"ns", {Qns}, 0, 0444,
+ "srv", {Qsrv,0,QTDIR}, 0, 0555,
"ppid", {Qppid}, 0, 0444,
"proc", {Qproc}, 0, 0400,
"regs", {Qregs}, sizeof(Ureg), 0000,
@@ -154,8 +157,8 @@
* in vers,
* 32 bits of pid, for consistency checking
*/
-#define QSHIFT 5 /* location in qid of proc slot # */
-
+#define QSHIFT 5 /* location in qid of proc slot # */
+#define CSHIFT (26+5) /* location in qid of chan # */
#define QID(q) ((((ulong)(q).path)&0x0000001F)>>0)
#define SLOTMAX 0x4000000
#define SLOT(q) (((((ulong)(q).path)>>QSHIFT)&(SLOTMAX-1))-1)
@@ -175,6 +178,39 @@
static int lenwatchpt(Proc *);
+static Chan*
+mntchan(Proc *p, Chan *c)
+{
+ char *s, *t, buf[32];
+ Chan *nc, *mc;
+ Pgrp *pg;
+ Mount *f;
+
+ s = c->path->s;
+ if((t = strrchr(s, '/')) != nil)
+ s = t+1;
+
+ pg = p->pgrp;
+ if(pg == nil)
+ error(Eprocdied);
+
+ nc = nil;
+ rlock(&pg->ns);
+ for(f = pg->mntorder; f != nil; f = f->order){
+ if(strcmp(f->to->path->s, "#M") != 0)
+ continue;
+ mc = f->to->mchan;
+ snprint(buf, sizeof(buf), "%ld.%x.%llx", mc->dev, mc->type, mc->qid.path);
+ if(strcmp(s, buf) == 0){
+ nc = f->to->mchan;
+ incref(nc);
+ break;
+ }
+ }
+ runlock(&pg->ns);
+ return nc;
+}
+
static int
procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
{
@@ -182,7 +218,13 @@
Proc *p;
char *ename;
Segment *q;
- ulong pid, path, perm, len;
+ Mount *f;
+ Chan *mc;
+ Pgrp *pg;
+ ulong pid, perm, len;
+ uvlong path;
+ char *e, *t;
+ int i;
if(s == DEVDOTDOT){
mkqid(&qid, Qdir, 0, QTDIR);
@@ -226,9 +268,46 @@
devdir(c, qid, up->genbuf, 0, p->user, 0555, dp);
return 1;
}
+ if(QID(c->qid) == Qsrv){
+ i = 0;
+ p = proctab(SLOT(c->qid));
+ pg = p->pgrp;
+ if(pg == nil || p->dot == nil || p->pid != PID(c->qid))
+ error(Eprocdied);
+ rlock(&pg->ns);
+ for(f = pg->mntorder; f != nil; f = f->order){
+ if(strcmp(f->to->path->s, "#M") != 0)
+ continue;
+ if(i++ >= s)
+ break;
+ }
+ if(f == nil){
+ runlock(&pg->ns);
+ return -1;
+ }
+ mc = f->to->mchan;
+ path = ((uvlong)i<<CSHIFT) | c->qid.path&~((1<<QSHIFT)-1);
+ snprint(up->genbuf, sizeof(up->genbuf), "%ld.%x.%llx", mc->dev, mc->type, mc->qid.path);
+ mkqid(&qid, path | Qchan, p->pid, QTFILE);
+ devdir(c, qid, up->genbuf, 0, p->user, 0400, dp);
+ runlock(&pg->ns);
+ return 1;
+ }
+ if(QID(c->qid) == Qchan){
+ p = proctab(SLOT(c->qid));
+ if(p->dot == nil || p->pid != PID(c->qid))
+ error(Eprocdied);
+ e = c->path->s;
+ if((t = strrchr(e, '/')) != nil)
+ e = t+1;
+ snprint(up->genbuf, sizeof(up->genbuf), "%s", e);
+ mkqid(&qid, c->qid.path, p->pid, QTFILE);
+ devdir(c, qid, up->genbuf, 0, eve, 0400, dp);
+ return 1;
+ }
if(c->qid.path == Qtrace){
strcpy(up->genbuf, "trace");
- mkqid(&qid, Qtrace, -1, QTFILE);
+ mkqid(&qid, c->qid.path, -1, QTFILE);
devdir(c, qid, up->genbuf, 0, eve, 0400, dp);
return 1;
}
@@ -265,7 +344,7 @@
break;
}
- mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
+ mkqid(&qid, path|tab->qid.path, c->qid.vers, tab->qid.type);
devdir(c, qid, tab->name, len, p->user, perm, dp);
return 1;
}
@@ -398,6 +477,7 @@
c->offset = 0;
return c;
}
+
p = proctab(SLOT(c->qid));
eqlock(&p->debug);
@@ -436,7 +516,13 @@
if(omode != OREAD)
error(Eperm);
break;
-
+ case Qchan:
+ tc = mntchan(p, c);
+ if(tc == nil)
+ error(Eshutdown);
+ devpermcheck(p->user, c->mode, omode);
+ nonone(p);
+ goto Found;
case Qctl:
case Qargs:
case Qwait:
@@ -488,8 +574,8 @@
clearwatchpt(p);
break;
}
-
poperror();
+Found:
qunlock(&p->debug);
poperror();
@@ -641,10 +727,11 @@
static int
readns1(Chan *c, Proc *p, char *buf, int nbuf)
{
+ char flag[10], srv[32];
Pgrp *pg;
Mount *f;
- char flag[10], *srv;
- int i;
+ Chan *mc;
+ int i, n;
pg = p->pgrp;
if(pg == nil || p->dot == nil || p->pid != PID(c->qid))
@@ -656,32 +743,33 @@
rlock(&pg->ns);
i = 0;
- for(f = pg->mntorder; f != nil; f = f->order) {
+ for(f = pg->mntorder; f != nil; f = f->order)
if(i++ >= c->nrock)
break;
- }
if(f == nil) {
c->nrock = -1;
- i = snprint(buf, nbuf, "cd %q\n", p->dot->path->s);
+ n = snprint(buf, nbuf, "cd %q\n", p->dot->path->s);
} else {
c->nrock = i;
int2flag(f->mflag, flag);
if(strcmp(f->to->path->s, "#M") == 0){
- srv = f->to->mchan->srvname;
- if(srv == nil)
- srv = f->to->mchan->path->s;
- i = snprint(buf, nbuf, *f->spec?
- "mount %s %q %q %q\n": "mount %s %q %q\n", flag,
- srv, f->umh->from->path->s, f->spec);
+ mc = f->to->mchan;
+ snprint(srv, sizeof(srv), "%ld.%x.%llx", mc->dev, mc->type, mc->qid.path);
+ if(f->spec[0] != 0)
+ n = snprint(buf, nbuf, "mount %s /proc/%lud/srv/%q %q %q\n",
+ flag, p->pid, srv, f->umh->from->path->s, f->spec);
+ else
+ n = snprint(buf, nbuf, "mount %s /proc/%lud/srv/%q %q\n",
+ flag, p->pid, srv, f->umh->from->path->s);
}else{
- i = snprint(buf, nbuf, "bind %s %q %q\n", flag,
+ n = snprint(buf, nbuf, "bind %s %q %q\n", flag,
f->to->path->s, f->umh->from->path->s);
}
}
runlock(&pg->ns);
- return i;
+ return n;
}
int
------------------------------------------
9fans: 9fans
Permalink: https://9fans.topicbox.com/groups/9fans/Tdf1407e79f217ea2-M4ee7de06944875b04c453002
Delivery options: https://9fans.topicbox.com/groups/9fans/subscription
^ permalink raw reply [flat|nested] 2+ messages in thread* [9fans] Re: [9front] Enterable namespaces: /proc/pid/$ns/srv
2025-12-14 0:54 [9fans] Enterable namespaces: /proc/pid/$ns/srv ori
@ 2025-12-14 2:58 ` Frank D. Engel, Jr.
0 siblings, 0 replies; 2+ messages in thread
From: Frank D. Engel, Jr. @ 2025-12-14 2:58 UTC (permalink / raw)
To: 9front, 9fans
Doesn't that create a security hole by making it possible to access to
private ramdisks and factotum instances and the like which were
previously not accessible to the process?
On 12/13/25 19:54, ori@eigenstate.org wrote:
> This patch makes it possible to enter a namespace through
> /proc/$pid/ns, like so:
>
> auth/newns -n /proc/$pid/ns $cmd
>
> or through procesing the namespace file any other way
> that they want.
>
> with the hope it'll be useful for things like fixing up
> tab completion in rio, making the plumber responsive to
> the local namespace that we are plumbing from, and other
> things that we haven't figured out yet.
>
> It works by making the chans for a proc's mounts available
> via /proc/$pid/srv/$id, and changing /proc/$pid/ns to use
> the channel name rather than files other procs can't access,
> such as '#|'.
>
> Hopefully folks will be able to experiment a bit with this,
> and figure out some good uses for it.
>
>
> diff 4341e26ac5d5cb86af2e1d88dd85365e7feb3a59 uncommitted
> --- a/sys/man/3/proc
> +++ b/sys/man/3/proc
> @@ -22,6 +22,7 @@
> .BI /proc/ n /profile
> .BI /proc/ n /regs
> .BI /proc/ n /segment
> +.BI /proc/ n /srv/ chan
> .BI /proc/ n /status
> .BI /proc/ n /text
> .BI /proc/ n /wait
> @@ -127,6 +128,15 @@
> for read-only, if any;
> starting virtual address, in hexadecimal;
> ending virtual address, and reference count.
> +.PP
> +The
> +.B srv
> +directory provides a directory holding already-open channels
> +to services in the style of
> +.IR srv (3).
> +This allows a process with appropriate permissions to execute the
> +.I ns
> +file and accurately reproduce the namespace of the process that is running.
> .PP
> The read-only
> .B status
> --- a/sys/src/9/port/devproc.c
> +++ b/sys/src/9/port/devproc.c
> @@ -28,6 +28,8 @@
> Qnoteid,
> Qnotepg,
> Qns,
> + Qsrv,
> + Qchan,
> Qppid,
> Qproc,
> Qregs,
> @@ -100,6 +102,7 @@
> "noteid", {Qnoteid}, 0, 0664,
> "notepg", {Qnotepg}, 0, 0000,
> "ns", {Qns}, 0, 0444,
> + "srv", {Qsrv,0,QTDIR}, 0, 0555,
> "ppid", {Qppid}, 0, 0444,
> "proc", {Qproc}, 0, 0400,
> "regs", {Qregs}, sizeof(Ureg), 0000,
> @@ -154,8 +157,8 @@
> * in vers,
> * 32 bits of pid, for consistency checking
> */
> -#define QSHIFT 5 /* location in qid of proc slot # */
> -
> +#define QSHIFT 5 /* location in qid of proc slot # */
> +#define CSHIFT (26+5) /* location in qid of chan # */
> #define QID(q) ((((ulong)(q).path)&0x0000001F)>>0)
> #define SLOTMAX 0x4000000
> #define SLOT(q) (((((ulong)(q).path)>>QSHIFT)&(SLOTMAX-1))-1)
> @@ -175,6 +178,39 @@
>
> static int lenwatchpt(Proc *);
>
> +static Chan*
> +mntchan(Proc *p, Chan *c)
> +{
> + char *s, *t, buf[32];
> + Chan *nc, *mc;
> + Pgrp *pg;
> + Mount *f;
> +
> + s = c->path->s;
> + if((t = strrchr(s, '/')) != nil)
> + s = t+1;
> +
> + pg = p->pgrp;
> + if(pg == nil)
> + error(Eprocdied);
> +
> + nc = nil;
> + rlock(&pg->ns);
> + for(f = pg->mntorder; f != nil; f = f->order){
> + if(strcmp(f->to->path->s, "#M") != 0)
> + continue;
> + mc = f->to->mchan;
> + snprint(buf, sizeof(buf), "%ld.%x.%llx", mc->dev, mc->type, mc->qid.path);
> + if(strcmp(s, buf) == 0){
> + nc = f->to->mchan;
> + incref(nc);
> + break;
> + }
> + }
> + runlock(&pg->ns);
> + return nc;
> +}
> +
> static int
> procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
> {
> @@ -182,7 +218,13 @@
> Proc *p;
> char *ename;
> Segment *q;
> - ulong pid, path, perm, len;
> + Mount *f;
> + Chan *mc;
> + Pgrp *pg;
> + ulong pid, perm, len;
> + uvlong path;
> + char *e, *t;
> + int i;
>
> if(s == DEVDOTDOT){
> mkqid(&qid, Qdir, 0, QTDIR);
> @@ -226,9 +268,46 @@
> devdir(c, qid, up->genbuf, 0, p->user, 0555, dp);
> return 1;
> }
> + if(QID(c->qid) == Qsrv){
> + i = 0;
> + p = proctab(SLOT(c->qid));
> + pg = p->pgrp;
> + if(pg == nil || p->dot == nil || p->pid != PID(c->qid))
> + error(Eprocdied);
> + rlock(&pg->ns);
> + for(f = pg->mntorder; f != nil; f = f->order){
> + if(strcmp(f->to->path->s, "#M") != 0)
> + continue;
> + if(i++ >= s)
> + break;
> + }
> + if(f == nil){
> + runlock(&pg->ns);
> + return -1;
> + }
> + mc = f->to->mchan;
> + path = ((uvlong)i<<CSHIFT) | c->qid.path&~((1<<QSHIFT)-1);
> + snprint(up->genbuf, sizeof(up->genbuf), "%ld.%x.%llx", mc->dev, mc->type, mc->qid.path);
> + mkqid(&qid, path | Qchan, p->pid, QTFILE);
> + devdir(c, qid, up->genbuf, 0, p->user, 0400, dp);
> + runlock(&pg->ns);
> + return 1;
> + }
> + if(QID(c->qid) == Qchan){
> + p = proctab(SLOT(c->qid));
> + if(p->dot == nil || p->pid != PID(c->qid))
> + error(Eprocdied);
> + e = c->path->s;
> + if((t = strrchr(e, '/')) != nil)
> + e = t+1;
> + snprint(up->genbuf, sizeof(up->genbuf), "%s", e);
> + mkqid(&qid, c->qid.path, p->pid, QTFILE);
> + devdir(c, qid, up->genbuf, 0, eve, 0400, dp);
> + return 1;
> + }
> if(c->qid.path == Qtrace){
> strcpy(up->genbuf, "trace");
> - mkqid(&qid, Qtrace, -1, QTFILE);
> + mkqid(&qid, c->qid.path, -1, QTFILE);
> devdir(c, qid, up->genbuf, 0, eve, 0400, dp);
> return 1;
> }
> @@ -265,7 +344,7 @@
> break;
> }
>
> - mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
> + mkqid(&qid, path|tab->qid.path, c->qid.vers, tab->qid.type);
> devdir(c, qid, tab->name, len, p->user, perm, dp);
> return 1;
> }
> @@ -398,6 +477,7 @@
> c->offset = 0;
> return c;
> }
> +
>
> p = proctab(SLOT(c->qid));
> eqlock(&p->debug);
> @@ -436,7 +516,13 @@
> if(omode != OREAD)
> error(Eperm);
> break;
> -
> + case Qchan:
> + tc = mntchan(p, c);
> + if(tc == nil)
> + error(Eshutdown);
> + devpermcheck(p->user, c->mode, omode);
> + nonone(p);
> + goto Found;
> case Qctl:
> case Qargs:
> case Qwait:
> @@ -488,8 +574,8 @@
> clearwatchpt(p);
> break;
> }
> -
> poperror();
> +Found:
> qunlock(&p->debug);
> poperror();
>
> @@ -641,10 +727,11 @@
> static int
> readns1(Chan *c, Proc *p, char *buf, int nbuf)
> {
> + char flag[10], srv[32];
> Pgrp *pg;
> Mount *f;
> - char flag[10], *srv;
> - int i;
> + Chan *mc;
> + int i, n;
>
> pg = p->pgrp;
> if(pg == nil || p->dot == nil || p->pid != PID(c->qid))
> @@ -656,32 +743,33 @@
> rlock(&pg->ns);
>
> i = 0;
> - for(f = pg->mntorder; f != nil; f = f->order) {
> + for(f = pg->mntorder; f != nil; f = f->order)
> if(i++ >= c->nrock)
> break;
> - }
>
> if(f == nil) {
> c->nrock = -1;
> - i = snprint(buf, nbuf, "cd %q\n", p->dot->path->s);
> + n = snprint(buf, nbuf, "cd %q\n", p->dot->path->s);
> } else {
> c->nrock = i;
> int2flag(f->mflag, flag);
> if(strcmp(f->to->path->s, "#M") == 0){
> - srv = f->to->mchan->srvname;
> - if(srv == nil)
> - srv = f->to->mchan->path->s;
> - i = snprint(buf, nbuf, *f->spec?
> - "mount %s %q %q %q\n": "mount %s %q %q\n", flag,
> - srv, f->umh->from->path->s, f->spec);
> + mc = f->to->mchan;
> + snprint(srv, sizeof(srv), "%ld.%x.%llx", mc->dev, mc->type, mc->qid.path);
> + if(f->spec[0] != 0)
> + n = snprint(buf, nbuf, "mount %s /proc/%lud/srv/%q %q %q\n",
> + flag, p->pid, srv, f->umh->from->path->s, f->spec);
> + else
> + n = snprint(buf, nbuf, "mount %s /proc/%lud/srv/%q %q\n",
> + flag, p->pid, srv, f->umh->from->path->s);
> }else{
> - i = snprint(buf, nbuf, "bind %s %q %q\n", flag,
> + n = snprint(buf, nbuf, "bind %s %q %q\n", flag,
> f->to->path->s, f->umh->from->path->s);
> }
> }
> runlock(&pg->ns);
>
> - return i;
> + return n;
> }
>
> int
>
------------------------------------------
9fans: 9fans
Permalink: https://9fans.topicbox.com/groups/9fans/Tdf1407e79f217ea2-Ma80db8de7eb2ec3200ae6890
Delivery options: https://9fans.topicbox.com/groups/9fans/subscription
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-12-14 4:26 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-14 0:54 [9fans] Enterable namespaces: /proc/pid/$ns/srv ori
2025-12-14 2:58 ` [9fans] Re: [9front] " Frank D. Engel, Jr.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).