From 320e6e6f35bfbc2e37dbd079c8d6a9124bd9ac6c Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Tue, 24 Oct 2017 23:28:14 +0200 Subject: [PATCH] kern: clone $pid's namespace writing #p/$pid/ns Any process X can get a new copy of the namespace of a target process Y by writing the string "clone" to the ns file of Y. The same user must own both processes. The process writing the ns file must be allowed to mount. The Pgrp of the calling process is then replaced with a new copy of the Pgrp of the target process. After the operation, any change done by X to its own namespace does not affect Y. Also, if mount was forbidden for Y, it will also be forbidden for X after the clone. --- qa/kern/build.json | 3 +- qa/kern/nsclone.c | 92 +++++++++++++++++++++++++++++++++++++ sys/src/kern/port/devproc.c | 23 ++++++++-- 3 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 qa/kern/nsclone.c diff --git a/qa/kern/build.json b/qa/kern/build.json index c9cb96c..8d9b9a3 100644 --- a/qa/kern/build.json +++ b/qa/kern/build.json @@ -29,9 +29,10 @@ "memoryisolation.c", "memoryshare.c", "mixedfloat.c", + "nested_note.c", "noexecmem.c", "notify.c", - "nested_note.c", + "nsclone.c", "nsec.c", "pipering.c", "postnote.c", diff --git a/qa/kern/nsclone.c b/qa/kern/nsclone.c new file mode 100644 index 0000000..09fd300 --- /dev/null +++ b/qa/kern/nsclone.c @@ -0,0 +1,92 @@ +/* + * This file is part of Jehanne. + * + * Copyright (C) 2017 Giacomo Tesio + * + * Jehanne is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * Jehanne is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jehanne. If not, see . + */ +#include +#include + +int sync[2]; + +void +setup_ns(void) +{ + int fd; + if(bind("#|", "/", MREPL) < 0){ + print("FAIL: rfork\n"); + write(sync[0], "FAIL", 5); + return; + } + fd = open("/data", OWRITE); + if(fd < 0){ + print("FAIL: open(/data)\n"); + write(sync[0], "FAIL", 5); + return; + } + write(fd, "hi!", 4); + close(fd); + write(sync[0], "DONE", 5); + sleep(10); +} + +void +main(void) +{ + int child, fd; + char buf[64]; + + rfork(RFNOTEG|RFNAMEG); + + pipe(sync); + switch(child = rfork(RFPROC|RFCNAMEG|RFNOWAIT)){ + case -1: + print("FAIL: rfork\n"); + exits("FAIL"); + case 0: + setup_ns(); + exits(nil); + default: + break; + } + + read(sync[1], buf, sizeof(buf)); + if(strcmp("DONE", buf) != 0) + exits("FAIL"); + + snprint(buf, sizeof(buf), "/proc/%d/ns", child); + fd = open(buf, OWRITE); + if(fd < 0){ + print("FAIL: open(%s)\n", buf); + exits("FAIL"); + } + write(fd, "clone", 6); + close(fd); + + memset(buf, 0, sizeof(buf)); + fd = open("/data1", OREAD); + if(fd < 0){ + print("FAIL: open(/data1)\n"); + exits("FAIL"); + } + read(fd, buf, sizeof(buf)); + close(fd); + + if(strcmp("hi!", buf) == 0){ + print("PASS: read '%s' from /data1\n", buf); + exits("PASS"); + } + print("FAIL: unexpected string from %d: %s\n", child, buf); + exits("FAIL"); +} diff --git a/sys/src/kern/port/devproc.c b/sys/src/kern/port/devproc.c index 56bde82..6414c3c 100644 --- a/sys/src/kern/port/devproc.c +++ b/sys/src/kern/port/devproc.c @@ -101,7 +101,7 @@ Dirtab procdir[] = "note", {Qnote}, 0, 0000, "noteid", {Qnoteid}, 0, 0664, "notepg", {Qnotepg}, 0, 0000, - "ns", {Qns}, 0, 0440, + "ns", {Qns}, 0, 0640, "proc", {Qproc}, 0, 0400, "regs", {Qregs}, sizeof(Ureg), 0000, "segment", {Qsegment}, 0, 0444, @@ -426,9 +426,14 @@ procopen(Chan *c, unsigned long omode) break; case Qns: - if(omode != OREAD) + if(omode == OREAD){ + c->aux = jehanne_malloc(sizeof(Mntwalk)); + } else if(omode == OWRITE){ + if(up->pgrp->noattach || strcmp(up->user, p->user) != 0) + error(Eperm); + } else { error(Eperm); - c->aux = jehanne_malloc(sizeof(Mntwalk)); + } break; case Qnotepg: @@ -1142,6 +1147,7 @@ static long procwrite(Chan *c, void *va, long n, int64_t off) { Proc *p, *t; + Pgrp *opg; int i, id, l; char **args, buf[ERRMAX]; uintptr_t offset; @@ -1257,6 +1263,17 @@ procwrite(Chan *c, void *va, long n, int64_t off) case Qwdir: n = write_working_dir(p, va, n, off); break; + case Qns: + if(strcmp("clone", va) != 0) + error(Ebadarg); + opg = up->pgrp; + up->pgrp = newpgrp(); + pgrpcpy(up->pgrp, p->pgrp); + /* inherit noattach */ + up->pgrp->noattach = p->pgrp->noattach; + closepgrp(opg); + break; + default: poperror(); qunlock(&p->debug);