commit ff6b18f831d03b1f4944716195089ced3e9b9fd8 from: Stefan Sperling date: Tue Apr 24 10:50:21 2018 UTC read blobs through privsep commit - 068fd2bf0c2848bb0ee960b1178e229560cadc0c commit + ff6b18f831d03b1f4944716195089ced3e9b9fd8 blob - 76986d61d779c996002c47abcc96117f7c5c7a9d blob + c594b658e1e12ce3a540b0176746a00706b16290 --- lib/got_lib_privsep.h +++ lib/got_lib_privsep.h @@ -21,9 +21,8 @@ * This behaviour is transparent to users of the library. * * We generally transmit data in imsg buffers, split across several messages - * if necessary. File descriptor passing is used in cases where this is - * impractical, such as when accessing pack files or when transferring - * large blobs. + * if necessary. File descriptors are used in cases where this is impractical, + * such as when accessing pack files or when transferring large blobs. * * We currently do not exec(2) after a fork(2). * To achieve fork+exec, relevant parts of our library functionality could @@ -137,5 +136,7 @@ const struct got_error *got_privsep_recv_tree(struct g 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 *); /* TODO: Implement the above, and then add more message data types here. */ blob - 3a874e61bc0c9fade6d20095e6be681ad8b584a9 blob + f3845e17342adbffaf8c43ffc2b8143331bc475c --- lib/object.c +++ lib/object.c @@ -1022,7 +1022,72 @@ read_blob_object(int outfd, int infd) return got_inflate_to_fd(&size, infd, outfd); } + +static const struct got_error * +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; + + setproctitle("got: read blob object"); + close(imsg_fds[0]); + imsg_init(&ibuf, imsg_fds[1]); + /* revoke access to most system calls */ + if (pledge("stdio", NULL) == -1) { + err = got_error_from_errno(); + goto done; + } + + err = read_blob_object(outfd, infd); + close(infd); + if (err) + goto done; + + err = got_privsep_send_blob(&ibuf); +done: + if (err) { + got_privsep_send_error(&ibuf, err); + status = 1; + } + close(outfd); + imsg_clear(&ibuf); + close(imsg_fds[1]); + _exit(status); +} + +static const struct got_error * +read_blob_object_privsep(int outfd, int infd) +{ + struct imsgbuf parent_ibuf; + int imsg_fds[2]; + const struct got_error *err = NULL; + pid_t pid; + int child_status; + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) + return got_error_from_errno(); + + pid = fork(); + if (pid == -1) + return got_error_from_errno(); + else if (pid == 0) { + read_blob_object_privsep_child(outfd, infd, imsg_fds); + /* not reached */ + } + + close(imsg_fds[1]); + imsg_init(&parent_ibuf, imsg_fds[0]); + err = got_privsep_recv_blob(&parent_ibuf); + imsg_clear(&parent_ibuf); + waitpid(pid, &child_status, 0); + close(imsg_fds[0]); + if (lseek(outfd, SEEK_SET, 0) == -1) + err = got_error_from_errno(); + return err; +} + const struct got_error * got_object_blob_open(struct got_blob_object **blob, struct got_repository *repo, struct got_object *obj, size_t blocksize) @@ -1063,7 +1128,7 @@ got_object_blob_open(struct got_blob_object **blob, goto done; } - err = read_blob_object(outfd, infd); + err = read_blob_object_privsep(outfd, infd); close(infd); if (err) goto done; blob - 71bf646c05ae45da7a0b1a9da854bcbebd59404a blob + da7628fd90ec8c45df94754fbc19460724c4828b --- lib/privsep.c +++ lib/privsep.c @@ -603,7 +603,49 @@ done: err = got_error(GOT_ERR_PRIVSEP_LEN); got_object_tree_close(*tree); *tree = NULL; + } + + return err; +} + +const struct got_error * +got_privsep_send_blob(struct imsgbuf *ibuf) +{ + /* Data has already been written to file descriptor. */ + if (imsg_compose(ibuf, GOT_IMSG_BLOB, 0, 0, -1, NULL, 0) == -1) + return got_error_from_errno(); + + return flush_imsg(ibuf); +} + +const struct got_error * +got_privsep_recv_blob(struct imsgbuf *ibuf) +{ + const struct got_error *err = NULL; + struct imsg imsg; + size_t datalen; + + err = recv_one_imsg(&imsg, ibuf, 0); + if (err) + return err; + + datalen = imsg.hdr.len - IMSG_HEADER_SIZE; + + switch (imsg.hdr.type) { + case GOT_IMSG_ERROR: + err = recv_imsg_error(&imsg, datalen); + break; + case GOT_IMSG_BLOB: + if (datalen != 0) + err = got_error(GOT_ERR_PRIVSEP_LEN); + /* Data has been written to file descriptor. */ + break; + default: + err = got_error(GOT_ERR_PRIVSEP_MSG); + break; } + imsg_free(&imsg); + return err; }