From owner-p4-projects@FreeBSD.ORG Fri Nov 30 02:36:08 2012 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 920B96F; Fri, 30 Nov 2012 02:36:08 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 375486D for ; Fri, 30 Nov 2012 02:36:08 +0000 (UTC) (envelope-from brooks@freebsd.org) Received: from skunkworks.freebsd.org (skunkworks.freebsd.org [IPv6:2001:4f8:fff6::2d]) by mx1.freebsd.org (Postfix) with ESMTP id 197E28FC0C for ; Fri, 30 Nov 2012 02:36:08 +0000 (UTC) Received: from skunkworks.freebsd.org (localhost [127.0.0.1]) by skunkworks.freebsd.org (8.14.5/8.14.5) with ESMTP id qAU2a7h7061534 for ; Fri, 30 Nov 2012 02:36:07 GMT (envelope-from brooks@freebsd.org) Received: (from perforce@localhost) by skunkworks.freebsd.org (8.14.5/8.14.5/Submit) id qAU2a74r061531 for perforce@freebsd.org; Fri, 30 Nov 2012 02:36:07 GMT (envelope-from brooks@freebsd.org) Date: Fri, 30 Nov 2012 02:36:07 GMT Message-Id: <201211300236.qAU2a74r061531@skunkworks.freebsd.org> X-Authentication-Warning: skunkworks.freebsd.org: perforce set sender to brooks@freebsd.org using -f From: Brooks Davis Subject: PERFORCE change 219865 for review To: Perforce Change Reviews Precedence: bulk X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.14 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 30 Nov 2012 02:36:08 -0000 http://p4web.freebsd.org/@@219865?ac=10 Change 219865 by brooks@brooks_zenith on 2012/11/30 02:35:07 Convert the capsicum sandbox support in minifile to use an exec'd helper program in prepration for the creation of a CHERI sandbox. Affected files ... .. //depot/projects/ctsrd/cheribsd/src/ctsrd/minifile/Makefile#2 edit .. //depot/projects/ctsrd/cheribsd/src/ctsrd/minifile/capsicum/Makefile#1 add .. //depot/projects/ctsrd/cheribsd/src/ctsrd/minifile/capsicum/minifile-capsicum.c#1 add .. //depot/projects/ctsrd/cheribsd/src/ctsrd/minifile/minifile.c#4 edit .. //depot/projects/ctsrd/cheribsd/src/ctsrd/minifile/minifile.h#1 add Differences ... ==== //depot/projects/ctsrd/cheribsd/src/ctsrd/minifile/Makefile#2 (text+ko) ==== @@ -1,6 +1,8 @@ # @(#)Makefile 8.1 (Berkeley) 5/31/93 # $FreeBSD$ +SUBDIR+= capsicum + PROG= minifile MAN= ==== //depot/projects/ctsrd/cheribsd/src/ctsrd/minifile/minifile.c#4 (text+ko) ==== @@ -9,13 +9,14 @@ #include #include #include -#define _WITH_DPRINTF #include #include #include #include #include +#include "minifile.h" + enum _sbtype { SB_NONE = 0, SB_CAPSICUM, @@ -31,22 +32,131 @@ errx(1, "usage: minifile [-s ] ...\n"); } +/* + * prep_fds() moves the file descriptors in curfds around such that they + * are at the corresponding target fd values in preperation for an exec + * into a capsicum or similar sandbox. All fd's above the largest value + * specified in the targetfds array are closed. It is expected that the + * values will fall within the range (3 .. ). Otherwise an + * unpredictiable set of files may remain open and information leaks may + * result unless specifc descriptors were already placed in the other + * slots. The programmer should seperately ensure that fds 0, 1, and 2 + * are either the usual stdin, stdout, and stderror or fd's to /dev/null. + */ int +prep_fds(int *curfds, int *targetfds, int nfds) +{ + int i, maxfd = -1, tmpfd; + + /* Find the largest fd in either the current or target lists */ + for (i = 0; i < nfds; i++) + if (maxfd < curfds[i]) + maxfd = curfds[i]; + for (i = 0; i < nfds; i++) + if (maxfd < targetfds[i]) + maxfd = targetfds[i]; + + /* Move all the fds up above the largest one */ + for (i = 0; i < nfds; i++) { + tmpfd = maxfd + 1 + i; + if (dup2(curfds[i], tmpfd) == -1) + return (-1); + close(curfds[i]); + } + + /* Move them all into their assigned locations. */ + for (i = 0; i < nfds; i++) { + tmpfd = maxfd + 1 + i; + if (dup2(tmpfd, targetfds[i]) == -1) + return (-1); + close(tmpfd); + } + + /* Close everything above are new maximum descriptor */ + maxfd = -1; + for (i = 0; i < nfds; i++) + if (maxfd < targetfds[i]) + maxfd = targetfds[i]; + closefrom(maxfd + 1); + + return (0); +} + +const char * +capsicum_magic_descriptor(int mfd, int fd) +{ + int status; + pid_t pid; + ssize_t rlen; + static char buf[4096]; + char *type, *ttype; + int pfd[2]; + int curfds[3], targetfds[3]; + + if (pipe(pfd) == -1) + err(1, "pipe()"); + pid = fork(); + if (pid < 0) + err(1, "fork()"); + else if (pid == 0) { + close(pfd[0]); + + /* XXX: use cap_new() to limit further */ + curfds[0] = fd; + targetfds[0] = MINIFILE_FILE_FD; + curfds[1] = mfd; + targetfds[1] = MINIFILE_MAGIC_FD; + curfds[2] = pfd[1]; + targetfds[2] = MINIFILE_OUT_FD; + + if (prep_fds(curfds, targetfds, 3) == -1) + err(1, "pred_fds()"); + + execl("/usr/libexec/minifile-capsicum", "readpng", NULL); + err(1, "exec /usr/libexec/minifile-capsicum"); + } else { + close(pfd[1]); + while (wait4(pid, &status, 0, NULL) == -1) + if (errno != EINTR) + err(1, "wait4()"); + if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { + warnx("child exited with %d", WEXITSTATUS(status)); + close(pfd[0]); + type = "badmagic"; + } else if(WIFSIGNALED(status)) { + warn("child killed by signal %d", WTERMSIG(status)); + close(pfd[0]); + type = "badmagic"; + } else { + rlen = read(pfd[0], buf, 128); + close(pfd[0]); + if (rlen == -1) + type = "read error"; + else if (rlen == 0 || rlen == 1) + type = "unknown"; + else { + /* Don't trust the result */ + ttype = buf + rlen; + strvisx(ttype, buf, rlen, 0); + type = ttype; + } + } + } + + return type; +} + +int main(int argc, char **argv) { char ch; void *magicbuf; const char *fname; - int mfd, fd, status; - ssize_t rlen; - pid_t pid; + int mfd, fd; const char *type; struct magic_set *magic; struct stat sb; - char buf[4096], *ttype; - int pfd[2]; - while ((ch = getopt(argc, argv, "s:")) != -1) { switch(ch) { case 's': @@ -65,38 +175,41 @@ argc -= optind; argv += optind; - magic = magic_open(MAGIC_MIME_TYPE); - if (magic == NULL) - errx(1, "magic_open()"); + if (argc <= 0) + usage(); + mfd = open(MAGIC_FILE, O_RDONLY); if (mfd == -1) { warn("open(%s)", MAGIC_FILE); magic_close(magic); exit(1); } - if (fstat(mfd, &sb) == -1) { - warn("fstat(%s)", MAGIC_FILE); - magic_close(magic); - exit(1); + + if (sbtype == SB_NONE) { + magic = magic_open(MAGIC_MIME_TYPE); + if (magic == NULL) + errx(1, "magic_open()"); + if (fstat(mfd, &sb) == -1) { + warn("fstat(%s)", MAGIC_FILE); + magic_close(magic); + exit(1); + } + magicbuf = mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, + MAP_PRIVATE, mfd, 0); + if (magicbuf == MAP_FAILED) { + warn("mmap(%s)", MAGIC_FILE); + magic_close(magic); + exit(1); + } + close(mfd); + if (magic_load_buffers(magic, &magicbuf, &sb.st_size, 1) == + -1) { + warnx("magic_load() %s", magic_error(magic)); + magic_close(magic); + exit(1); + } } - magicbuf = mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, - mfd, 0); - if (magicbuf == MAP_FAILED) { - warn("mmap(%s)", MAGIC_FILE); - magic_close(magic); - exit(1); - } - close(mfd); - if (magic_load_buffers(magic, &magicbuf, &sb.st_size, 1) == -1) { - warnx("magic_load() %s", magic_error(magic)); - magic_close(magic); - exit(1); - } - - if (argc <= 0) - usage(); - for (; argc >= 1; argc--, argv++) { fname = argv[0]; fd = open(fname, O_RDONLY); @@ -106,58 +219,12 @@ case SB_NONE: type = magic_descriptor(magic, fd); if (type == NULL) - errx(1, "magic_file(): %s", - magic_error(magic)); + errx(1, "magic_file(): %s", magic_error(magic)); break; case SB_CAPSICUM: - if (pipe(pfd) == -1) - err(1, "pipe()"); - pid = fork(); - if (pid < 0) - err(1, "fork()"); - else if (pid == 0) { - close(fd); - close(pfd[0]); - /* XXX: do more cleanup here */ - cap_enter(); - type = magic_descriptor(magic, fd); - if (type == NULL) - dprintf(pfd[1], "badmagic"); - else - dprintf(pfd[1], "%s", type); - close(pfd[1]); - exit(0); - } else { - close(pfd[1]); - while (wait4(pid, &status, 0, NULL) == -1) - if (errno != EINTR) - err(1, "wait4()"); - if (WIFEXITED(status) && - WEXITSTATUS(status) != 0) { - warnx("child exited with %d", - WEXITSTATUS(status)); - close(pfd[0]); - type = "badmagic"; - } else if(WIFSIGNALED(status)) { - warn("child killed by signal %d", - WTERMSIG(status)); - close(pfd[0]); - type = "badmagic"; - } else { - rlen = read(pfd[0], buf, 128); - close(pfd[0]); - if (rlen == -1) - type = "read error"; - else if (rlen == 0 || rlen == 1) - type = "unknown"; - else { - /* Don't trust the result */ - ttype = buf + rlen; - strvisx(ttype, buf, rlen, 0); - type = ttype; - } - } - } + type = capsicum_magic_descriptor(mfd, fd); + if (type == NULL) + errx(1, "capsicum_magic_descriptor()"); break; case SB_CHERI: errx(1, "no cheri capability support yet");