commit - 86acc5664b2eab0c8e696d98336235c2b027229a
commit + e033d8037031ecafbf4a99c69c25f1be778ef9d3
blob - b1af4e2fa5b6fc7b4ebe696d93b8a7697eabff1e
blob + 4cfa4a51368b015a532f56d4588e182ad78b9e69
--- lib/got_lib_object.h
+++ lib/got_lib_object.h
};
struct got_commit_object *got_object_commit_alloc_partial(void);
+struct got_tree_entry *got_alloc_tree_entry_partial(void);
blob - 037cf653ad0247ae919e99902639f2ca2214069c
blob + 43af9dc4a56b8d4092240a2fe7610e3e90df9dac
--- lib/got_lib_privsep.h
+++ lib/got_lib_privsep.h
/* Structure for GOT_IMSG_TREE_ENTRY. */
struct got_imsg_tree_entry {
- struct got_object_id id;
+ char id[SHA1_DIGEST_LENGTH];
mode_t mode;
/* Followed by entry's name in remaining data of imsg buffer. */
} __attribute__((__packed__));
struct got_commit_object *);
const struct got_error *got_privsep_recv_commit_obj(struct got_commit_object **,
struct imsgbuf *);
+const struct got_error *got_privsep_recv_tree_obj(struct got_tree_object **,
+ struct imsgbuf *);
+const struct got_error *got_privsep_send_tree_obj(struct imsgbuf *,
+ struct got_tree_object *);
/* TODO: Implement the above, and then add more message data types here. */
blob - 94349e0a76159e5adea1b20e4fd51ce1bd252f6f
blob + 98e4f11e71887b6117bf17e88675d07c1a274080
--- lib/object.c
+++ lib/object.c
free(te);
}
+struct got_tree_entry *
+got_alloc_tree_entry_partial(void)
+{
+ struct got_tree_entry *te;
+
+ te = calloc(1, sizeof(*te));
+ if (te == NULL)
+ return NULL;
+
+ te->id = calloc(1, sizeof(*te->id));
+ if (te->id == NULL) {
+ free(te);
+ te = NULL;
+ }
+ return te;
+}
+
static const struct got_error *
parse_tree_entry(struct got_tree_entry **te, size_t *elen, char *buf,
size_t maxlen)
char *p = buf, *space;
const struct got_error *err = NULL;
- *te = calloc(1, sizeof(**te));
+ *te = got_alloc_tree_entry_partial();
if (*te == NULL)
return got_error_from_errno();
- (*te)->id = calloc(1, sizeof(*(*te)->id));
- if ((*te)->id == NULL) {
- err = got_error_from_errno();
- free(*te);
- *te = NULL;
- return err;
- }
-
*elen = strlen(buf) + 1;
if (*elen > maxlen) {
free(*te);
}
static const struct got_error *
-parse_tree_object(struct got_tree_object **tree, struct got_repository *repo,
- uint8_t *buf, size_t len)
+parse_tree_object(struct got_tree_object **tree, uint8_t *buf, size_t len)
{
const struct got_error *err;
size_t remain = len;
}
static const struct got_error *
-read_tree_object(struct got_tree_object **tree,
- struct got_repository *repo, struct got_object *obj, FILE *f)
+read_tree_object(struct got_tree_object **tree, struct got_object *obj, FILE *f)
{
const struct got_error *err = NULL;
size_t len;
/* Skip object header. */
len -= obj->hdrlen;
- err = parse_tree_object(tree, repo, p + obj->hdrlen, len);
+ err = parse_tree_object(tree, p + obj->hdrlen, len);
free(p);
+done:
+ return err;
+}
+
+static void
+read_tree_object_privsep_child(struct got_object *obj, int obj_fd,
+ int imsg_fds[2])
+{
+ const struct got_error *err = NULL;
+ struct got_tree_object *tree = NULL;
+ struct imsgbuf ibuf;
+ FILE *f = NULL;
+ int status = 0;
+
+ setproctitle("got: read tree 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;
+ }
+
+ f = fdopen(obj_fd, "rb");
+ if (f == NULL) {
+ err = got_error_from_errno();
+ close(obj_fd);
+ goto done;
+ }
+
+ err = read_tree_object(&tree, obj, f);
+ if (err)
+ goto done;
+
+ err = got_privsep_send_tree_obj(&ibuf, tree);
done:
+ if (tree)
+ got_object_tree_close(tree);
+ if (err) {
+ got_privsep_send_error(&ibuf, err);
+ status = 1;
+ }
+ if (f)
+ fclose(f);
+ imsg_clear(&ibuf);
+ close(imsg_fds[1]);
+ _exit(status);
+}
+
+static const struct got_error *
+read_tree_object_privsep(struct got_tree_object **tree, struct got_object *obj,
+ int fd)
+{
+ const struct got_error *err = NULL;
+ struct imsgbuf parent_ibuf;
+ int imsg_fds[2];
+ 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_tree_object_privsep_child(obj, fd, imsg_fds);
+ /* not reached */
+ }
+
+ close(imsg_fds[1]);
+ imsg_init(&parent_ibuf, imsg_fds[0]);
+ err = got_privsep_recv_tree_obj(tree, &parent_ibuf);
+ imsg_clear(&parent_ibuf);
+ waitpid(pid, &child_status, 0);
+ close(imsg_fds[0]);
return err;
}
if (err)
return err;
obj->size = len;
- err = parse_tree_object(tree, repo, buf, len);
+ err = parse_tree_object(tree, buf, len);
free(buf);
} else {
- FILE *f;
int fd;
err = open_loose_object(&fd, obj, repo);
if (err)
return err;
- f = fdopen(fd, "rb");
- if (f == NULL) {
- close(fd);
- return got_error_from_errno();
- }
- err = read_tree_object(tree, repo, obj, f);
- fclose(f);
+ err = read_tree_object_privsep(tree, obj, fd);
close(fd);
}
return err;
blob - 85b125e761c9349c488108b05a63bb914fbb644f
blob + 564d5af6f1afadb90372f6f97eba30bd81194107
--- lib/privsep.c
+++ lib/privsep.c
}
static const struct got_error *
-recv_one_imsg(struct imsg *imsg, struct imsgbuf *ibuf, size_t min_datalen)
+read_imsg(struct imsgbuf *ibuf)
{
const struct got_error *err;
- ssize_t n, m;
+ size_t n;
err = poll_fd(ibuf->fd, POLLIN, INFTIM);
if (err)
if (n == 0)
return got_error(GOT_ERR_PRIVSEP_PIPE);
- m = imsg_get(ibuf, imsg);
- if (m == 0)
+ return NULL;
+}
+
+static const struct got_error *
+recv_one_imsg(struct imsg *imsg, struct imsgbuf *ibuf, size_t min_datalen)
+{
+ const struct got_error *err;
+ ssize_t n;
+
+ err = read_imsg(ibuf);
+ if (err)
+ return err;
+
+ n = imsg_get(ibuf, imsg);
+ if (n == 0)
return got_error(GOT_ERR_PRIVSEP_READ);
if (imsg->hdr.len < IMSG_HEADER_SIZE + min_datalen)
getprogname(), err->code, err->msg, strerror(errno));
return;
}
+}
+
+static const struct got_error *
+flush_imsg(struct imsgbuf *ibuf)
+{
+ const struct got_error *err;
+
+ err = poll_fd(ibuf->fd, POLLOUT, INFTIM);
+ if (err)
+ return err;
+
+ if (imsg_flush(ibuf) == -1)
+ return got_error_from_errno();
+
+ return NULL;
}
const struct got_error *
got_privsep_send_obj(struct imsgbuf *ibuf, struct got_object *obj, int ndeltas)
{
- const struct got_error *err = NULL;
struct got_imsg_object iobj;
iobj.type = obj->type;
== -1)
return got_error_from_errno();
- err = poll_fd(ibuf->fd, POLLOUT, INFTIM);
- if (err)
- return err;
-
- if (imsg_flush(ibuf) == -1)
- return got_error_from_errno();
-
- return NULL;
+ return flush_imsg(ibuf);
}
const struct got_error *
goto done;
}
- err = poll_fd(ibuf->fd, POLLOUT, INFTIM);
- if (err)
- goto done;
-
- if (imsg_flush(ibuf) == -1) {
- err = got_error_from_errno();
- goto done;
- }
-
+ err = flush_imsg(ibuf);
done:
free(buf);
return err;
}
imsg_free(&imsg);
+
+ return err;
+}
+
+const struct got_error *
+got_privsep_send_tree_obj(struct imsgbuf *ibuf, struct got_tree_object *tree)
+{
+ const struct got_error *err = NULL;
+ struct got_imsg_tree_object itree;
+ struct got_tree_entry *te;
+
+ itree.nentries = tree->nentries;
+ if (imsg_compose(ibuf, GOT_IMSG_TREE, 0, 0, -1, &itree, sizeof(itree))
+ == -1)
+ return got_error_from_errno();
+
+ err = flush_imsg(ibuf);
+ if (err)
+ return err;
+
+ SIMPLEQ_FOREACH(te, &tree->entries, entry) {
+ struct got_imsg_tree_entry ite;
+ uint8_t *buf = NULL;
+ size_t len = sizeof(ite) + strlen(te->name);
+
+ if (len > MAX_IMSGSIZE)
+ return got_error(GOT_ERR_NO_SPACE);
+
+ buf = malloc(len);
+ if (buf == NULL)
+ return got_error_from_errno();
+
+ memcpy(ite.id, te->id->sha1, sizeof(ite.id));
+ ite.mode = te->mode;
+ memcpy(buf, &ite, sizeof(ite));
+ memcpy(buf + sizeof(ite), te->name, strlen(te->name));
+
+ if (imsg_compose(ibuf, GOT_IMSG_TREE_ENTRY, 0, 0, -1,
+ buf, len) == -1)
+ err = got_error_from_errno();
+ free(buf);
+ if (err)
+ return err;
+
+ err = flush_imsg(ibuf);
+ if (err)
+ return err;
+ }
+
+ return NULL;
+}
+
+const struct got_error *
+got_privsep_recv_tree_obj(struct got_tree_object **tree, struct imsgbuf *ibuf)
+{
+ const struct got_error *err = NULL;
+ const size_t min_datalen =
+ MIN(sizeof(struct got_imsg_error),
+ sizeof(struct got_imsg_tree_object));
+ struct got_imsg_tree_object itree = { 0 };
+ int nentries = 0;
+ *tree = NULL;
+get_more:
+ err = read_imsg(ibuf);
+ if (err)
+ return err;
+
+ while (1) {
+ struct imsg imsg;
+ size_t n;
+ uint8_t *data;
+ size_t datalen;
+ struct got_imsg_tree_entry ite;
+ struct got_tree_entry *te = NULL;
+
+ n = imsg_get(ibuf, &imsg);
+ if (n == 0) {
+ if (*tree && (*tree)->nentries != nentries)
+ goto get_more;
+ break;
+ }
+
+ if (imsg.hdr.len < IMSG_HEADER_SIZE + min_datalen)
+ return got_error(GOT_ERR_PRIVSEP_LEN);
+
+ data = imsg.data;
+ 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_TREE:
+ /* This message should only appear once. */
+ if (*tree != NULL) {
+ err = got_error(GOT_ERR_PRIVSEP_MSG);
+ break;
+ }
+ if (datalen != sizeof(itree)) {
+ err = got_error(GOT_ERR_PRIVSEP_LEN);
+ break;
+ }
+ memcpy(&itree, imsg.data, sizeof(itree));
+ *tree = calloc(1, sizeof(**tree));
+ if (*tree == NULL) {
+ err = got_error_from_errno();
+ break;
+ }
+ (*tree)->nentries = itree.nentries;
+ SIMPLEQ_INIT(&(*tree)->entries);
+ break;
+ case GOT_IMSG_TREE_ENTRY:
+ /* This message should be preceeded by GOT_IMSG_TREE. */
+ if (*tree == NULL) {
+ err = got_error(GOT_ERR_PRIVSEP_MSG);
+ break;
+ }
+ if (datalen < sizeof(ite) || datalen > MAX_IMSGSIZE) {
+ err = got_error(GOT_ERR_PRIVSEP_LEN);
+ break;
+ }
+
+ /* Remaining data contains the entry's name. */
+ datalen -= sizeof(ite);
+ memcpy(&ite, imsg.data, sizeof(ite));
+ if (datalen == 0 || datalen > MAX_IMSGSIZE) {
+ err = got_error(GOT_ERR_PRIVSEP_LEN);
+ break;
+ }
+ te = got_alloc_tree_entry_partial();
+ if (te == NULL) {
+ err = got_error_from_errno();
+ break;
+ }
+ te->name = malloc(datalen + 1);
+ if (te->name == NULL) {
+ free(te);
+ err = got_error_from_errno();
+ break;
+ }
+ memcpy(te->name, imsg.data, datalen);
+ te->name[datalen] = '\0';
+
+ memcpy(te->id->sha1, ite.id, SHA1_DIGEST_LENGTH);
+ te->mode = ite.mode;
+ SIMPLEQ_INSERT_TAIL(&(*tree)->entries, te, entry);
+ nentries++;
+ break;
+ default:
+ err = got_error(GOT_ERR_PRIVSEP_MSG);
+ break;
+ }
+
+ imsg_free(&imsg);
+ }
+
+ if (*tree && (*tree)->nentries != nentries) {
+ err = got_error(GOT_ERR_PRIVSEP_LEN);
+ got_object_tree_close(*tree);
+ *tree = NULL;
+ }
+
return err;
}