Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 5 Nov 2012 17:55:59 GMT
From:      Brooks Davis <brooks@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 219606 for review
Message-ID:  <201211051755.qA5Htx9h021259@skunkworks.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <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");
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201211051755.qA5Htx9h021259>