From owner-p4-projects@FreeBSD.ORG Mon Nov 5 17:56:00 2012 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 24641ED3; Mon, 5 Nov 2012 17:56:00 +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 D041CECB for ; Mon, 5 Nov 2012 17:55:59 +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 AEC348FC0C for ; Mon, 5 Nov 2012 17:55:59 +0000 (UTC) Received: from skunkworks.freebsd.org (localhost [127.0.0.1]) by skunkworks.freebsd.org (8.14.4/8.14.4) with ESMTP id qA5Htxxe021262 for ; Mon, 5 Nov 2012 17:55:59 GMT (envelope-from brooks@freebsd.org) Received: (from perforce@localhost) by skunkworks.freebsd.org (8.14.4/8.14.4/Submit) id qA5Htx9h021259 for perforce@freebsd.org; Mon, 5 Nov 2012 17:55:59 GMT (envelope-from brooks@freebsd.org) Date: Mon, 5 Nov 2012 17:55:59 GMT Message-Id: <201211051755.qA5Htx9h021259@skunkworks.freebsd.org> X-Authentication-Warning: skunkworks.freebsd.org: perforce set sender to brooks@freebsd.org using -f From: Brooks Davis Subject: PERFORCE change 219606 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: Mon, 05 Nov 2012 17:56:00 -0000 http://p4web.freebsd.org/@@219606?ac=10 Change 219606 by brooks@brooks_zenith on 2012/11/05 17:55:40 Checkpoint a seemingly working refactor that supports capsicum sandboxes in addition to unsandboxed, threaded operation. Affected files ... .. //depot/projects/ctsrd/beribsd/src/ctsrd-lib/libimagebox/Makefile#2 edit .. //depot/projects/ctsrd/beribsd/src/ctsrd-lib/libimagebox/iboxpriv.h#1 add .. //depot/projects/ctsrd/beribsd/src/ctsrd-lib/libimagebox/imagebox.h#2 edit .. //depot/projects/ctsrd/beribsd/src/ctsrd-lib/libimagebox/pngbox.c#2 edit .. //depot/projects/ctsrd/beribsd/src/ctsrd-lib/libimagebox/readpng/Makefile#1 add .. //depot/projects/ctsrd/beribsd/src/ctsrd-lib/libimagebox/readpng/readpng.c#1 add Differences ... ==== //depot/projects/ctsrd/beribsd/src/ctsrd-lib/libimagebox/Makefile#2 (text+ko) ==== @@ -2,7 +2,7 @@ # $FreeBSD$ # -#CC=clang +.include LIB= imagebox SHLIB_MAJOR= 1 @@ -11,6 +11,14 @@ INCS= imagebox.h -CFLAGS+= -I${.CURDIR}/../libvuln_png/ +.if ${MACHINE_ARCH} == "amd64" +CFLAGS+= -I/usr/local/include +.else +CFLAGS+= -I${.CURDIR}/../libvuln_png/ +.endif + +#WARNS?= 6 + +SUBDIR= readpng .include ==== //depot/projects/ctsrd/beribsd/src/ctsrd-lib/libimagebox/imagebox.h#2 (text+ko) ==== @@ -38,6 +38,7 @@ }; struct iboxstate { + enum sbtype sb; uint32_t width; uint32_t height; volatile uint32_t valid_rows; ==== //depot/projects/ctsrd/beribsd/src/ctsrd-lib/libimagebox/pngbox.c#2 (text+ko) ==== @@ -31,6 +31,9 @@ #include #include +#include +#include +#include #include #include @@ -42,61 +45,48 @@ #include #include "imagebox.h" +#include "iboxpriv.h" static void read_row_callback(png_structp, png_uint_32, int); static void read_png_from_fd(png_structp, png_bytep, png_size_t); -struct ibox_decode_state +struct pthr_decode_private { - enum sbtype sb; - int fd; - struct iboxstate *ps; + pthread_t pthr; }; -struct pthr_decode_private +struct fork_decode_private { - pthread_t pthr; + pid_t pid; }; -static void * -pthr_decode_png(void *arg) +void +decode_png(struct ibox_decode_state *ids) { int bit_depth, color_type, interlace_type; png_uint_32 r, width, height; - struct ibox_decode_state *pds = arg; - png_structp png_ptr; - png_infop info_ptr; - png_infop end_info; - png_bytep *rows; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_infop end_info = NULL; + png_bytep *rows = NULL; if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL) { - pds->ps->error = 1; - close(pds->fd); - free(pds); - pthread_exit(NULL); + ids->is->error = 1; + goto error; } if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) { - png_destroy_read_struct(&png_ptr, NULL, NULL); - pds->ps->error = 1; - close(pds->fd); - free(pds); - pthread_exit(NULL); + ids->is->error = 1; + goto error; } if ((end_info = png_create_info_struct(png_ptr)) == NULL) { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - pds->ps->error = 1; - close(pds->fd); - free(pds); - pthread_exit(NULL); + ids->is->error = 1; + goto error; } if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - pds->ps->error = 1; - close(pds->fd); - free(pds); - pthread_exit(NULL); + ids->is->error = 1; + goto error; } #if 0 @@ -115,7 +105,7 @@ png_set_user_limits(png_ptr, width, height); #endif - png_set_read_fn(png_ptr, pds, read_png_from_fd); + png_set_read_fn(png_ptr, ids, read_png_from_fd); png_read_info(png_ptr, info_ptr); @@ -124,35 +114,185 @@ printf("bit_depth = %d, color_type = %d\n", bit_depth, color_type); - if (width != pds->ps->width || height != pds->ps->height) { - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - pds->ps->error = 1; - close(pds->fd); - free(pds); - pthread_exit(NULL); + if (width != ids->is->width || height != ids->is->height) { + ids->is->error = 1; + goto error; } png_set_gray_to_rgb(png_ptr); png_set_bgr(png_ptr); png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); - pds->ps->passes_remaining = png_set_interlace_handling(png_ptr); + ids->is->passes_remaining = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); if ((rows = malloc(height*sizeof(png_bytep))) == NULL) png_error(png_ptr, "failed to malloc row array"); for (r = 0; r < height; r++) - rows[r] = __DEVOLATILE(png_bytep, - pds->ps->buffer + (width * r)); + rows[r] = (png_bytep)(ids->buffer + (width * r)); png_read_rows(png_ptr, rows, NULL, height); png_read_end(png_ptr, end_info); + +error: png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + close(ids->fd); free(rows); +} + +static void * +pthr_decode_png(void *arg) +{ + struct ibox_decode_state *ids = arg; + + decode_png(ids); + + free(ids); pthread_exit(NULL); } +static struct iboxstate* +pthr_png_read_start(int pfd, uint32_t width, uint32_t height, enum sbtype sb) +{ + struct iboxstate *is = NULL; + struct ibox_decode_state *ids = NULL; + struct pthr_decode_private *pdp; + + if ((is = malloc(sizeof(struct iboxstate))) == NULL) + goto error; + memset(is, 0, sizeof(struct iboxstate)); + is->sb = sb; + is->width = width; + is->height = height; + is->passes_remaining = UINT32_MAX; + + if ((pdp = malloc(sizeof(*pdp))) == NULL) + goto error; + is->private = pdp; + + if ((ids = malloc(sizeof(*ids))) == NULL) + goto error; + memset(ids, 0, sizeof(*ids)); + ids->is = is; + ids->fd = pfd; + + if ((ids->buffer = malloc(is->width * is->height * + sizeof(*ids->buffer))) == NULL) + goto error; + is->buffer = ids->buffer; + + if (pthread_create(&(pdp->pthr), NULL, pthr_decode_png, ids) != 0) + goto error; + goto started; + +error: + close(pfd); + free(is); + is = NULL; + if (ids != NULL) { + free(ids->buffer); + free(ids); + } +started: + return is; +} + +static struct iboxstate* +capsicum_png_read_start(int pfd, uint32_t width, uint32_t height, + enum sbtype sb) +{ + int bfd, isfd, highfd; + int nbfd, nisfd, npfd; + struct iboxstate *is = NULL; + struct fork_decode_private *fdp = NULL; + + bfd = isfd = -1; + + if ((isfd = shm_open(SHM_ANON, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) + == -1) + goto error; + if (ftruncate(isfd, sizeof(struct iboxstate)) == -1) + goto error; + if ((is = mmap(NULL, sizeof(*is), PROT_READ | PROT_WRITE, MAP_SHARED, + isfd, 0)) == MAP_FAILED) + goto error; + memset(is, 0, sizeof(struct iboxstate)); + is->sb = sb; + is->width = width; + is->height = height; + is->passes_remaining = UINT32_MAX; + + if ((bfd = shm_open(SHM_ANON, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) + == -1) + goto error; + if (ftruncate(bfd, width * height * sizeof(uint32_t)) == -1) + goto error; + if ((is->buffer = mmap(NULL, width * height * sizeof(uint32_t), + PROT_READ | PROT_WRITE, MAP_SHARED, bfd, 0)) == MAP_FAILED) + goto error; + + if ((fdp = malloc(sizeof(struct fork_decode_private))) == NULL) + goto error; + is->private = fdp; + + if ((fdp->pid = fork()) == 0) { + /* + * Relocate pfd, bfd, and isfd to fd's 3, 4, 5 for the + * worker process. First, move them to new, higher locations + * to ensure none are in the range 3-5 (assumes stdin, out, + * err) are open.. Second, install them in the expected + * locations. Third, close all higher FDs. + */ + highfd = pfd; + if (bfd > highfd) + highfd = bfd; + if (isfd > highfd) + highfd = isfd; + npfd = highfd + 1; + nbfd = highfd + 2; + nisfd = highfd + 3; + if (dup2(pfd, npfd) == -1) + exit(1); + if (dup2(bfd, nbfd) == -1) + exit(1); + if (dup2(isfd, nisfd) == -1) + exit(1); + close(pfd); + close(bfd); + close(isfd); + if (dup2(npfd, 3) == -1) + exit(1); + if (dup2(nbfd, 4) == -1) + exit(1); + if (dup2(nisfd, 5) == -1) + exit(1); + closefrom(6); + + if (execl("/usr/libexec/readpng", "readpng", NULL) == -1) + exit(1); + } else if (fdp->pid > 0) + goto started; + +error: + if (is != NULL) { + if (is->buffer != NULL) + munmap(__DEVOLATILE(void*, is->buffer), + width * height * sizeof(uint32_t)); + munmap(is, sizeof(*is)); + is = NULL; + } + free(fdp); +started: + close(pfd); + if (bfd >= 0) + close(bfd); + if (isfd >= 0) + close(isfd); + + return (is); +} + /* * Begin decoding a stream containing a PNG image. Reads will proceed * in the background. The file descriptor will be under the control of @@ -161,25 +301,14 @@ struct iboxstate* png_read_start(int pfd, uint32_t maxw, uint32_t maxh, enum sbtype sb) { - uint32_t header[9]; + uint32_t header[9], width, height; char *cheader = (char *)header; char ihdr[] = {0x00, 0x00, 0x00, 0x0d, 'I', 'H', 'D', 'R'}; - struct iboxstate *ps; - struct ibox_decode_state *pds; - struct pthr_decode_private *pdp; - /* XXX: add more types */ - if (sb != SB_NONE) - return (NULL); - if (read(pfd, header, sizeof(header)) != sizeof(header)) { close(pfd); return (NULL); } - /* - * XXX: Should store data in a struct to be retrieved in - * read_png_from_fd() to support non-seekable streams. - */ if (lseek(pfd, 0, SEEK_SET) != 0) { close(pfd); return (NULL); @@ -187,107 +316,107 @@ if (png_sig_cmp(cheader, 0, 8) != 0) { errno = EINVAL; + close(pfd); return (NULL); } if (memcmp(header + 2, ihdr, sizeof(ihdr)) != 0) { errno = EINVAL; - return (NULL); - } - - if ((ps = malloc(sizeof(struct iboxstate))) == NULL) { close(pfd); return (NULL); } - memset(ps, 0, sizeof(struct iboxstate)); - ps->width = be32toh(*(header + 4)); - ps->height = be32toh(*(header + 5)); - if (ps->width > maxw || ps->height > maxh) { + width = be32toh(*(header + 4)); + height = be32toh(*(header + 5)); + if (width > maxw || height > maxh) { close(pfd); - free(ps); - return (NULL); + return NULL; } - ps->passes_remaining = UINT32_MAX; - if ((ps->buffer = malloc(ps->width * ps->height * sizeof(*ps->buffer))) - == NULL) { + switch (sb) { + case SB_NONE: + return pthr_png_read_start(pfd, width, height, sb); + case SB_CAPSICUM: + return capsicum_png_read_start(pfd, width, height, sb); + default: close(pfd); - free(ps); - return (NULL); - } - - if ((pds = malloc(sizeof(struct ibox_decode_state))) == NULL) { - close(pfd); - free(__DEVOLATILE(void*, ps->buffer)); - free(ps); - return (NULL); + return NULL; } - pds->ps = ps; - pds->fd = pfd; - - if ((pdp = malloc(sizeof(struct pthr_decode_private))) == NULL) { - close(pfd); - free(__DEVOLATILE(void*, ps->buffer)); - free(ps); - free(pds); - } - ps->private = pdp; - - if (pthread_create(&(pdp->pthr), NULL, pthr_decode_png, pds) != 0) { - close(pfd); - free(__DEVOLATILE(void*, ps->buffer)); - free(ps); - free(pds); - free(pdp); - } - - return (ps); } /* * Return when the png has finished decoding. */ int -png_read_finish(struct iboxstate *ps) +png_read_finish(struct iboxstate *is) { - int error; - struct pthr_decode_private *pdp = ps->private; + int error, status; + struct pthr_decode_private *pdp; + struct fork_decode_private *fdp = NULL; + + switch (is->sb) { + case SB_NONE: + pdp = is->private; + error = pthread_join(pdp->pthr, NULL); + free(pdp); + is->private = NULL; + break; + case SB_CAPSICUM: + fdp = is->private; + waitpid(fdp->pid, &status, 0); + free(fdp); + is->private = NULL; + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + error = 1; + else + error = 0; + break; + default: + error = 1; + } - error = pthread_join(pdp->pthr, NULL); - free(pdp); - ps->private = NULL; return (error); } void -iboxstate_free(struct iboxstate *ps) +iboxstate_free(struct iboxstate *is) { - if (ps->private != NULL) - png_read_finish(ps); - free(__DEVOLATILE(void*, ps->buffer)); - free(ps); + if (is->private != NULL) + png_read_finish(is); + switch (is->sb){ + case SB_NONE: + free(__DEVOLATILE(void *, is->buffer)); + free(is); + break; + case SB_CAPSICUM: + munmap(__DEVOLATILE(void *, is->buffer), + is->width * is->height * sizeof(uint32_t)); + munmap(is, sizeof(*is)); + break; + default: + break; + } } static void read_row_callback(png_structp png_ptr, png_uint_32 row, int pass __unused) { - struct ibox_decode_state *pds; + struct ibox_decode_state *ids; - pds = png_get_io_ptr(png_ptr); - if (pds->ps->valid_rows < row) - pds->ps->valid_rows = row; - if (row == pds->ps->height) - pds->ps->passes_remaining--; + ids = png_get_io_ptr(png_ptr); + if (ids->is->valid_rows < row) + ids->is->valid_rows = row; + if (row == ids->is->height) + ids->is->passes_remaining--; } static void read_png_from_fd(png_structp png_ptr, png_bytep data, png_size_t length) { - struct ibox_decode_state *pds; + struct ibox_decode_state *ids; ssize_t rlen; - pds = png_get_io_ptr(png_ptr); - rlen = read(pds->fd, data, length); + ids = png_get_io_ptr(png_ptr); + rlen = read(ids->fd, data, length); if (rlen < 0 || (png_size_t)rlen != length) png_error(png_ptr, "read error"); }