opendev(3) should not be called by pledged processes, so the pledge of
dumpfs(8) needs to be redone: opendev is called in a loop over argv.
As dumpfs spews a whole lot of potentially untrusted data to stdout,
fork, read the data in the child and pipe it to the pledged parent
that writes it to stdout. pledge the child before dumping the last fs.
Thus the common case of dumping a single fs runs almost entirely
under pledge.
The loop in printdata() is taken from raw_cat() in cat(1).
Index: sbin/dumpfs/dumpfs.c
===================================================================
RCS file: /var/cvs/src/sbin/dumpfs/dumpfs.c,v
retrieving revision 1.33
diff -u -p -r1.33 dumpfs.c
--- sbin/dumpfs/dumpfs.c 23 Nov 2015 19:19:29 -0000 1.33
+++ sbin/dumpfs/dumpfs.c 13 May 2016 20:40:08 -0000
@@ -40,6 +40,7 @@
#include <sys/param.h> /* DEV_BSIZE MAXBSIZE isset */
#include <sys/time.h>
+#include <sys/wait.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
@@ -73,6 +74,7 @@ int dumpcg(const char *, int, int);
int marshal(const char *);
int open_disk(const char *);
void pbits(void *, int);
+void printdata(void);
__dead void usage(void);
int
@@ -80,7 +82,9 @@ main(int argc, char *argv[])
{
struct fstab *fs;
const char *name;
- int ch, domarshal, eval, fd;
+ pid_t pid, wpid;
+ int p[2];
+ int ch, domarshal, eval, fd, pstat;
domarshal = eval = 0;
@@ -100,10 +104,34 @@ main(int argc, char *argv[])
if (argc < 1)
usage();
- if (pledge("stdio rpath disklabel", NULL) == -1)
- err(1, "pledge");
+ if (pipe(p) < 0)
+ err(1, "pipe");
- for (; *argv != NULL; argv++) {
+ switch(pid = fork()) {
+ case -1:
+ err(1, "fork");
+
+ case 0:
+ close(p[0]);
+ dup2(p[1], STDOUT_FILENO);
+ close(p[1]);
+ break;
+
+ default:
+ if (pledge("stdio", NULL) == -1)
+ err(1, "pledge");
+ close(p[1]);
+ dup2(p[0], STDIN_FILENO);
+ close(p[0]);
+ printdata();
+ do {
+ wpid = waitpid(pid, &pstat, 0);
+ } while (wpid == -1 && errno == EINTR);
+
+ return (wpid == -1 || WEXITSTATUS(pstat));
+ }
+
+ for (; *argv != NULL; argv++, argc--) {
if ((fs = getfsfile(*argv)) != NULL)
name = fs->fs_spec;
else
@@ -112,13 +140,19 @@ main(int argc, char *argv[])
eval |= 1;
continue;
}
+ if (argc == 1)
+ if (pledge("stdio", NULL) == -1)
+ err(1, "pledge");
if (domarshal)
eval |= marshal(name);
else
eval |= dumpfs(fd, name);
close(fd);
}
- exit(eval);
+
+ if (fclose(stdout))
+ err(1, "fclose");
+ _exit(eval);
}
int
@@ -458,6 +492,24 @@ pbits(void *vp, int max)
printf("-%d", i);
}
printf("\n");
+}
+
+void
+printdata(void)
+{
+ int nr, nw, off;
+ char buf[1024];
+
+ while ((nr = read(STDIN_FILENO, buf, sizeof(buf))) != -1 && nr != 0) {
+ for (off = 0; nr; nr -= nw, off += nw) {
+ if ((nw = write(STDOUT_FILENO, buf + off, nr)) == 0 ||
+ nw == -1)
+ err(1, "stdout");
+ }
+ }
+
+ if (nr < 0)
+ warn("read");
}
__dead void