PERFORCE change 219606 for review
Brooks Davis
brooks at FreeBSD.org
Mon Nov 5 17:56:00 UTC 2012
http://p4web.freebsd.org/@@219606?ac=10
Change 219606 by brooks at 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 <bsd.own.mk>
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 <bsd.lib.mk>
==== //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 <sys/types.h>
#include <sys/endian.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
@@ -42,61 +45,48 @@
#include <unistd.h>
#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");
}
More information about the p4-projects
mailing list