Commit 2967a784ac51b6b48cb8165fd90ec290094455c8

Stefan Sperling 2018-04-24T13:30:34

verify size of blob received from privsep child

diff --git a/lib/got_lib_privsep.h b/lib/got_lib_privsep.h
index c594b65..3497719 100644
--- a/lib/got_lib_privsep.h
+++ b/lib/got_lib_privsep.h
@@ -123,6 +123,11 @@ struct got_imsg_tree_object {
 	int nentries; /* This many TREE_ENTRY messages follow. */
 };
 
+/* Structure for GOT_IMSG_BLOB. */
+struct got_imsg_blob {
+	size_t size;
+};
+
 void got_privsep_send_error(struct imsgbuf *, const struct got_error *);
 const struct got_error *got_privsep_send_obj(struct imsgbuf *,
     struct got_object *, int);
@@ -136,7 +141,7 @@ const struct got_error *got_privsep_recv_tree(struct got_tree_object **,
     struct imsgbuf *);
 const struct got_error *got_privsep_send_tree(struct imsgbuf *,
     struct got_tree_object *);
-const struct got_error *got_privsep_send_blob(struct imsgbuf *);
-const struct got_error *got_privsep_recv_blob(struct imsgbuf *);
+const struct got_error *got_privsep_send_blob(struct imsgbuf *, size_t);
+const struct got_error *got_privsep_recv_blob(size_t *, struct imsgbuf *);
 
 /* TODO: Implement the above, and then add more message data types here. */
diff --git a/lib/object.c b/lib/object.c
index f3845e1..6a88075 100644
--- a/lib/object.c
+++ b/lib/object.c
@@ -1016,11 +1016,9 @@ got_object_tree_close(struct got_tree_object *tree)
 }
 
 static const struct got_error *
-read_blob_object(int outfd, int infd)
+read_blob_object(size_t *size, int outfd, int infd)
 {
-	size_t size;
-
-	return got_inflate_to_fd(&size, infd, outfd);
+	return got_inflate_to_fd(size, infd, outfd);
 }
 
 static const struct got_error *
@@ -1029,6 +1027,7 @@ read_blob_object_privsep_child(int outfd, int infd, int imsg_fds[2])
 	const struct got_error *err = NULL;
 	struct imsgbuf ibuf;
 	int status = 0;
+	size_t size;
 
 	setproctitle("got: read blob object");
 	close(imsg_fds[0]);
@@ -1040,12 +1039,12 @@ read_blob_object_privsep_child(int outfd, int infd, int imsg_fds[2])
 		goto done;
 	}
 
-	err = read_blob_object(outfd, infd);
+	err = read_blob_object(&size, outfd, infd);
 	close(infd);
 	if (err)
 		goto done;
 
-	err = got_privsep_send_blob(&ibuf);
+	err = got_privsep_send_blob(&ibuf, size);
 done:
 	if (err) {
 		got_privsep_send_error(&ibuf, err);
@@ -1058,7 +1057,7 @@ done:
 }
 
 static const struct got_error *
-read_blob_object_privsep(int outfd, int infd)
+read_blob_object_privsep(size_t *size, int outfd, int infd)
 {
 	struct imsgbuf parent_ibuf;
 	int imsg_fds[2];
@@ -1079,7 +1078,7 @@ read_blob_object_privsep(int outfd, int infd)
 
 	close(imsg_fds[1]);
 	imsg_init(&parent_ibuf, imsg_fds[0]);
-	err = got_privsep_recv_blob(&parent_ibuf);
+	err = got_privsep_recv_blob(size, &parent_ibuf);
 	imsg_clear(&parent_ibuf);
 	waitpid(pid, &child_status, 0);
 	close(imsg_fds[0]);
@@ -1115,6 +1114,8 @@ got_object_blob_open(struct got_blob_object **blob,
 			goto done;
 	} else {
 		int infd, outfd;
+		size_t size;
+		struct stat sb;
 
 		err = open_loose_object(&infd, obj, repo);
 		if (err)
@@ -1128,11 +1129,29 @@ got_object_blob_open(struct got_blob_object **blob,
 			goto done;
 		}
 
-		err = read_blob_object_privsep(outfd, infd);
+		err = read_blob_object_privsep(&size, outfd, infd);
 		close(infd);
 		if (err)
 			goto done;
 
+		if (size != obj->hdrlen + obj->size) {
+			err = got_error(GOT_ERR_BAD_OBJ_HDR);
+			close(outfd);
+			goto done;
+		}
+
+		if (fstat(outfd, &sb) == -1) {
+			err = got_error_from_errno();
+			close(outfd);
+			goto done;
+		}
+
+		if (sb.st_size != size) {
+			err = got_error(GOT_ERR_PRIVSEP_LEN);
+			close(outfd);
+			goto done;
+		}
+
 		(*blob)->f = fdopen(outfd, "rb");
 		if ((*blob)->f == NULL) {
 			err = got_error_from_errno();
diff --git a/lib/privsep.c b/lib/privsep.c
index da7628f..b542a8d 100644
--- a/lib/privsep.c
+++ b/lib/privsep.c
@@ -609,20 +609,26 @@ done:
 }
 
 const struct got_error *
-got_privsep_send_blob(struct imsgbuf *ibuf)
+got_privsep_send_blob(struct imsgbuf *ibuf, size_t size)
 {
+	struct got_imsg_blob iblob;
+
+	iblob.size = size;
 	/* Data has already been written to file descriptor. */
-	if (imsg_compose(ibuf, GOT_IMSG_BLOB, 0, 0, -1, NULL, 0) == -1)
+
+	if (imsg_compose(ibuf, GOT_IMSG_BLOB, 0, 0, -1, &iblob, sizeof(iblob))
+	    == -1)
 		return got_error_from_errno();
 
 	return flush_imsg(ibuf);
 }
 
 const struct got_error *
-got_privsep_recv_blob(struct imsgbuf *ibuf)
+got_privsep_recv_blob(size_t *size, struct imsgbuf *ibuf)
 {
 	const struct got_error *err = NULL;
 	struct imsg imsg;
+	struct got_imsg_blob iblob;
 	size_t datalen;
 
 	err = recv_one_imsg(&imsg, ibuf, 0);
@@ -636,8 +642,10 @@ got_privsep_recv_blob(struct imsgbuf *ibuf)
 		err = recv_imsg_error(&imsg, datalen);
 		break;
 	case GOT_IMSG_BLOB:
-		if (datalen != 0)
+		if (datalen != sizeof(iblob))
 			err = got_error(GOT_ERR_PRIVSEP_LEN);
+		memcpy(&iblob, imsg.data, sizeof(iblob));
+		*size = iblob.size;
 		/* Data has been written to file descriptor. */
 		break;
 	default: