commit c7feb3c0836d28bd168f4ddc8f74aff8b82f8da9 from: Stefan Sperling via: Thomas Adam date: Fri Mar 21 13:22:46 2025 UTC send protected references from gotd parent process to repo_write process As a result, the repo_write process no longer needs to read gotd.conf. This ensures consistent run-time behaviour with respect to protected references if gotd.conf is edited while gotd is running. commit - 249ee0fae6ee00f317cd78c35c316483d91e6cf3 commit + c7feb3c0836d28bd168f4ddc8f74aff8b82f8da9 blob - 950189160202e577dc24dd86a202ef76f5860cb0 blob + d38e54c3db9b765517f47b5637cc471be106016f --- gotd/gotd.c +++ gotd/gotd.c @@ -2005,6 +2005,99 @@ connect_notifier_and_session(struct gotd_client *clien return NULL; } +static const struct got_error * +send_protected_ref(struct gotd_imsgev *iev, const char *refname, + int imsg_type) +{ + struct gotd_imsg_pathlist_elem ielem; + struct ibuf *wbuf = NULL; + + memset(&ielem, 0, sizeof(ielem)); + ielem.path_len = strlen(refname); + + wbuf = imsg_create(&iev->ibuf, imsg_type, GOTD_PROC_GOTD, gotd.pid, + sizeof(ielem) + ielem.path_len); + if (wbuf == NULL) + return got_error_from_errno_fmt("imsg_create %d", imsg_type); + + if (imsg_add(wbuf, &ielem, sizeof(ielem)) == -1) + return got_error_from_errno_fmt("imsg_add %d", imsg_type); + if (imsg_add(wbuf, refname, ielem.path_len) == -1) + return got_error_from_errno_fmt("imsg_add %d", imsg_type); + + imsg_close(&iev->ibuf, wbuf); + return gotd_imsg_flush(&iev->ibuf); +} + +static const struct got_error * +send_protected_refs(struct gotd_imsgev *iev, const char *repo_name) +{ + const struct got_error *err = NULL; + struct got_pathlist_entry *pe; + struct gotd_imsg_pathlist ilist; + struct gotd_repo *repo; + + memset(&ilist, 0, sizeof(ilist)); + + repo = gotd_find_repo_by_name(repo_name, &gotd.repos); + if (repo == NULL) + return got_error(GOT_ERR_NOT_GIT_REPO); + + ilist.nelem = repo->nprotected_tag_namespaces; + if (ilist.nelem > 0) { + if (gotd_imsg_compose_event(iev, + GOTD_IMSG_PROTECTED_TAG_NAMESPACES, + GOTD_PROC_GOTD, -1, &ilist, sizeof(ilist)) == -1) { + return got_error_from_errno("imsg compose " + "PROTECTED_TAG_NAMESPACES"); + } + + RB_FOREACH(pe, got_pathlist_head, + &repo->protected_tag_namespaces) { + err = send_protected_ref(iev, pe->path, + GOTD_IMSG_PROTECTED_TAG_NAMESPACES_ELEM); + if (err) + return err; + } + } + + ilist.nelem = repo->nprotected_branch_namespaces; + if (ilist.nelem > 0) { + if (gotd_imsg_compose_event(iev, + GOTD_IMSG_PROTECTED_BRANCH_NAMESPACES, + GOTD_PROC_GOTD, -1, &ilist, sizeof(ilist)) == -1) { + return got_error_from_errno("imsg compose " + "PROTECTED_BRANCH_NAMESPACES"); + } + + RB_FOREACH(pe, got_pathlist_head, + &repo->protected_branch_namespaces) { + err = send_protected_ref(iev, pe->path, + GOTD_IMSG_PROTECTED_BRANCH_NAMESPACES_ELEM); + if (err) + return err; + } + } + + ilist.nelem = repo->nprotected_branches; + if (ilist.nelem > 0) { + if (gotd_imsg_compose_event(iev, GOTD_IMSG_PROTECTED_BRANCHES, + GOTD_PROC_GOTD, -1, &ilist, sizeof(ilist)) == -1) { + return got_error_from_errno("imsg compose " + "PROTECTED_BRANCH_NAMESPACES"); + } + + RB_FOREACH(pe, got_pathlist_head, &repo->protected_branches) { + err = send_protected_ref(iev, pe->path, + GOTD_IMSG_PROTECTED_BRANCHES_ELEM); + if (err) + return err; + } + } + + return NULL; +} + static void gotd_dispatch_repo_child(int fd, short event, void *arg) { @@ -2060,6 +2153,11 @@ gotd_dispatch_repo_child(int fd, short event, void *ar err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_REPO_CHILD_READY: + if (client_is_writing(client)) { + err = send_protected_refs(iev, proc->repo_name); + if (err) + break; + } err = connect_session(client); if (err) break; @@ -2618,7 +2716,8 @@ main(int argc, char **argv) } } - if (proc_id != GOTD_PROC_LISTEN && proc_id != GOTD_PROC_AUTH) { + if (proc_id != GOTD_PROC_LISTEN && proc_id != GOTD_PROC_AUTH && + proc_id != GOTD_PROC_REPO_WRITE) { if (gotd_parse_config(confpath, proc_id, secrets, &gotd) != 0) return 1; @@ -2866,23 +2965,8 @@ main(int argc, char **argv) err(1, "pledge"); #endif apply_unveil_repo_readonly(repo_path, 0); - repo = gotd_find_repo_by_path(repo_path, &gotd); - if (repo == NULL) - fatalx("no repository for path %s", repo_path); - - if (enter_chroot(repo_path)) { - free(repo_path); - repo_path = strdup("/"); - if (repo_path == NULL) - fatal("strdup"); - } - drop_privs(pw); - repo_write_main(title, repo_path, pack_fds, temp_fds, - tmp_f1, tmp_f2, diff_f1, diff_f2, diff_fd1, diff_fd2, - &repo->protected_tag_namespaces, - &repo->protected_branch_namespaces, - &repo->protected_branches); + tmp_f1, tmp_f2, diff_f1, diff_f2, diff_fd1, diff_fd2); /* NOTREACHED */ exit(0); case GOTD_PROC_NOTIFY: blob - e8a8beadf6b0e0a90e63de7897b2f255dde741ee blob + c69c5aec37b51fc7e27c92cc522073adf6e92d7a --- gotd/gotd.h +++ gotd/gotd.h @@ -134,8 +134,11 @@ struct gotd_repo { struct gotd_access_rule_list rules; struct got_pathlist_head protected_tag_namespaces; + size_t nprotected_tag_namespaces; struct got_pathlist_head protected_branch_namespaces; + size_t nprotected_branch_namespaces; struct got_pathlist_head protected_branches; + size_t nprotected_branches; struct got_pathlist_head notification_refs; struct got_pathlist_head notification_ref_namespaces; @@ -258,6 +261,14 @@ enum gotd_imsg_type { GOTD_IMSG_AUTHENTICATE, GOTD_IMSG_ACCESS_GRANTED, + /* Protected references. */ + GOTD_IMSG_PROTECTED_TAG_NAMESPACES, + GOTD_IMSG_PROTECTED_TAG_NAMESPACES_ELEM, + GOTD_IMSG_PROTECTED_BRANCH_NAMESPACES, + GOTD_IMSG_PROTECTED_BRANCH_NAMESPACES_ELEM, + GOTD_IMSG_PROTECTED_BRANCHES, + GOTD_IMSG_PROTECTED_BRANCHES_ELEM, + /* Notify child process. */ GOTD_IMSG_CONNECT_NOTIFIER, GOTD_IMSG_CONNECT_SESSION, @@ -532,6 +543,32 @@ struct gotd_imsg_auth_access_rule { /* Followed by identifier_len bytes. */ }; +/* + * Structure for sending path lists over imsg. Used with: + * GOTD_IMSG_PROTECTED_TAG_NAMESPACES + * GOTD_IMSG_PROTECTED_BRANCH_NAMESPACES + * GOTD_IMSG_PROTECTED_BRANCHES + */ +struct gotd_imsg_pathlist { + size_t nelem; + + /* Followed by nelem path list elements. */ +}; + +/* + * Structure for a path list element. Used with: + * GOTD_IMSG_PROTECTED_TAG_NAMESPACES_ELEM + * GOTD_IMSG_PROTECTED_BRANCH_NAMESPACES_ELEM + * GOTD_IMSG_PROTECTED_BRANCHES_ELEM + */ +struct gotd_imsg_pathlist_elem { + size_t path_len; + size_t data_len; + + /* Followed by path_len bytes. */ + /* Followed by data_len bytes. */ +}; + /* Structures for GOTD_IMSG_NOTIFY. */ enum gotd_notification_action { GOTD_NOTIF_ACTION_CREATED, blob - 59eefa496ed735676eba3ea4452d4c8f9b595802 blob + 4bf1400741232fd1549cacb7f3b0cd4cdd95cf25 --- gotd/parse.y +++ gotd/parse.y @@ -290,8 +290,7 @@ protectflags_l : protectflags optnl protectflags_l ; protectflags : TAG NAMESPACE STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_REPO_WRITE) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_protect_tag_namespace(new_repo, $3)) { free($3); YYERROR; @@ -300,8 +299,7 @@ protectflags : TAG NAMESPACE STRING { free($3); } | BRANCH NAMESPACE STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_REPO_WRITE) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_protect_branch_namespace(new_repo, $3)) { free($3); @@ -311,8 +309,7 @@ protectflags : TAG NAMESPACE STRING { free($3); } | BRANCH STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_REPO_WRITE) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_protect_branch(new_repo, $2)) { free($2); YYERROR; @@ -707,7 +704,6 @@ repository : REPOSITORY STRING { } if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_REPO_WRITE || gotd_proc_id == GOTD_PROC_SESSION_WRITE || gotd_proc_id == GOTD_PROC_GITWRAPPER | gotd_proc_id == GOTD_PROC_NOTIFY) { @@ -720,7 +716,6 @@ repository : REPOSITORY STRING { repoopts1 : PATH STRING { if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_REPO_WRITE || gotd_proc_id == GOTD_PROC_SESSION_WRITE || gotd_proc_id == GOTD_PROC_GITWRAPPER || gotd_proc_id == GOTD_PROC_NOTIFY) { @@ -1421,6 +1416,7 @@ conf_protect_tag_namespace(struct gotd_repo *repo, cha if (conf_protect_ref_namespace(&new, &repo->protected_tag_namespaces, namespace) == -1) return -1; + repo->nprotected_tag_namespaces++; RB_FOREACH(pe, got_pathlist_head, &repo->protected_branch_namespaces) { if (strcmp(pe->path, new) == 0) { @@ -1441,6 +1437,7 @@ conf_protect_branch_namespace(struct gotd_repo *repo, if (conf_protect_ref_namespace(&new, &repo->protected_branch_namespaces, namespace) == -1) return -1; + repo->nprotected_branch_namespaces++; RB_FOREACH(pe, got_pathlist_head, &repo->protected_tag_namespaces) { if (strcmp(pe->path, new) == 0) { @@ -1487,6 +1484,7 @@ conf_protect_branch(struct gotd_repo *repo, char *bran yyerror("duplicate protect branch %s", branchname); return -1; } + repo->nprotected_branches++; return 0; } blob - 7e68d8f979591910805c9909459afde378e3afb8 blob + 7d8e2cf8d5bc2251c71eadad35e0d5e810910b00 --- gotd/repo_write.c +++ gotd/repo_write.c @@ -76,9 +76,9 @@ static struct repo_write { FILE *accum_file; int session_fd; struct gotd_imsgev session_iev; - struct got_pathlist_head *protected_tag_namespaces; - struct got_pathlist_head *protected_branch_namespaces; - struct got_pathlist_head *protected_branches; + struct got_pathlist_head protected_tag_namespaces; + struct got_pathlist_head protected_branch_namespaces; + struct got_pathlist_head protected_branches; struct { FILE *f1; FILE *f2; @@ -87,6 +87,9 @@ static struct repo_write { } diff; int refs_listed; int have_packfile; + struct got_pathlist_head *protected_refs_cur; + size_t nprotected_refs_needed; + size_t nprotected_refs_received; } repo_write; struct gotd_ref_update { @@ -1412,7 +1415,7 @@ verify_packfile(void) continue; RB_FOREACH(pe, got_pathlist_head, - repo_write.protected_tag_namespaces) { + &repo_write.protected_tag_namespaces) { err = protect_tag_namespace(pe->path, &client->pack, client->packidx, ref_update); if (err) @@ -1445,14 +1448,14 @@ verify_packfile(void) } RB_FOREACH(pe, got_pathlist_head, - repo_write.protected_branch_namespaces) { + &repo_write.protected_branch_namespaces) { err = protect_branch_namespace(pe->path, &client->pack, client->packidx, ref_update); if (err) goto done; } RB_FOREACH(pe, got_pathlist_head, - repo_write.protected_branches) { + &repo_write.protected_branches) { err = protect_branch(pe->path, &client->pack, client->packidx, ref_update); if (err) @@ -1483,21 +1486,21 @@ protect_refs_from_deletion(void) refname = got_ref_get_name(ref_update->ref); RB_FOREACH(pe, got_pathlist_head, - repo_write.protected_tag_namespaces) { + &repo_write.protected_tag_namespaces) { err = protect_ref_namespace(refname, pe->path); if (err) return err; } RB_FOREACH(pe, got_pathlist_head, - repo_write.protected_branch_namespaces) { + &repo_write.protected_branch_namespaces) { err = protect_ref_namespace(refname, pe->path); if (err) return err; } RB_FOREACH(pe, got_pathlist_head, - repo_write.protected_branches) { + &repo_write.protected_branches) { if (strcmp(refname, pe->path) == 0) { return got_error_fmt(GOT_ERR_REF_PROTECTED, "%s", refname); @@ -1528,21 +1531,21 @@ protect_refs_from_moving(void) refname = got_ref_get_name(ref_update->ref); RB_FOREACH(pe, got_pathlist_head, - repo_write.protected_tag_namespaces) { + &repo_write.protected_tag_namespaces) { err = protect_ref_namespace(refname, pe->path); if (err) return err; } RB_FOREACH(pe, got_pathlist_head, - repo_write.protected_branch_namespaces) { + &repo_write.protected_branch_namespaces) { err = protect_ref_namespace(refname, pe->path); if (err) return err; } RB_FOREACH(pe, got_pathlist_head, - repo_write.protected_branches) { + &repo_write.protected_branches) { if (strcmp(refname, pe->path) == 0) { return got_error_fmt(GOT_ERR_REF_PROTECTED, "%s", refname); @@ -2728,6 +2731,51 @@ recv_connect(struct imsg *imsg) return NULL; } +static const struct got_error * +recv_pathlist(size_t *npaths, struct imsg *imsg) +{ + struct gotd_imsg_pathlist ilist; + size_t datalen; + + datalen = imsg->hdr.len - IMSG_HEADER_SIZE; + if (datalen != sizeof(ilist)) + return got_error(GOT_ERR_PRIVSEP_LEN); + memcpy(&ilist, imsg->data, sizeof(ilist)); + + if (ilist.nelem == 0) + return got_error(GOT_ERR_PRIVSEP_LEN); + + *npaths = ilist.nelem; + return NULL; +} + +static const struct got_error * +recv_pathlist_elem(struct imsg *imsg, struct got_pathlist_head *paths) +{ + const struct got_error *err = NULL; + struct gotd_imsg_pathlist_elem ielem; + size_t datalen; + char *path; + struct got_pathlist_entry *pe; + + datalen = imsg->hdr.len - IMSG_HEADER_SIZE; + if (datalen < sizeof(ielem)) + return got_error(GOT_ERR_PRIVSEP_LEN); + memcpy(&ielem, imsg->data, sizeof(ielem)); + + if (datalen != sizeof(ielem) + ielem.path_len) + return got_error(GOT_ERR_PRIVSEP_LEN); + + path = strndup(imsg->data + sizeof(ielem), ielem.path_len); + if (path == NULL) + return got_error_from_errno("strndup"); + + err = got_pathlist_insert(&pe, paths, path, NULL); + if (err || pe == NULL) + free(path); + return err; +} + static void repo_write_dispatch(int fd, short event, void *arg) { @@ -2738,6 +2786,7 @@ repo_write_dispatch(int fd, short event, void *arg) ssize_t n; int shut = 0; struct repo_write_client *client = &repo_write_client; + size_t npaths; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) @@ -2764,6 +2813,68 @@ repo_write_dispatch(int fd, short event, void *arg) break; switch (imsg.hdr.type) { + case GOTD_IMSG_PROTECTED_TAG_NAMESPACES: + if (repo_write.protected_refs_cur != NULL || + repo_write.nprotected_refs_needed != 0) { + err = got_error(GOT_ERR_PRIVSEP_MSG); + break; + } + err = recv_pathlist(&npaths, &imsg); + if (err) + break; + repo_write.protected_refs_cur = + &repo_write.protected_tag_namespaces; + repo_write.nprotected_refs_needed = npaths; + repo_write.nprotected_refs_received = 0; + break; + case GOTD_IMSG_PROTECTED_BRANCH_NAMESPACES: + if (repo_write.protected_refs_cur != NULL || + repo_write.nprotected_refs_needed != 0) { + err = got_error(GOT_ERR_PRIVSEP_MSG); + break; + } + err = recv_pathlist(&npaths, &imsg); + if (err) + break; + repo_write.protected_refs_cur = + &repo_write.protected_branch_namespaces; + repo_write.nprotected_refs_needed = npaths; + repo_write.nprotected_refs_received = 0; + break; + case GOTD_IMSG_PROTECTED_BRANCHES: + if (repo_write.protected_refs_cur != NULL || + repo_write.nprotected_refs_needed != 0) { + err = got_error(GOT_ERR_PRIVSEP_MSG); + break; + } + err = recv_pathlist(&npaths, &imsg); + if (err) + break; + repo_write.protected_refs_cur = + &repo_write.protected_branches; + repo_write.nprotected_refs_needed = npaths; + repo_write.nprotected_refs_received = 0; + break; + case GOTD_IMSG_PROTECTED_TAG_NAMESPACES_ELEM: + case GOTD_IMSG_PROTECTED_BRANCH_NAMESPACES_ELEM: + case GOTD_IMSG_PROTECTED_BRANCHES_ELEM: + if (repo_write.protected_refs_cur == NULL || + repo_write.nprotected_refs_needed == 0 || + repo_write.nprotected_refs_received >= + repo_write.nprotected_refs_needed) { + err = got_error(GOT_ERR_PRIVSEP_MSG); + break; + } + err = recv_pathlist_elem(&imsg, + repo_write.protected_refs_cur); + if (err) + break; + if (++repo_write.nprotected_refs_received >= + repo_write.nprotected_refs_needed) { + repo_write.protected_refs_cur = NULL; + repo_write.nprotected_refs_needed = 0; + } + break; case GOTD_IMSG_CONNECT_REPO_CHILD: err = recv_connect(&imsg); break; @@ -2792,10 +2903,7 @@ done: void repo_write_main(const char *title, const char *repo_path, int *pack_fds, int *temp_fds, FILE *base_file, FILE *accum_file, - FILE *diff_f1, FILE *diff_f2, int diff_fd1, int diff_fd2, - struct got_pathlist_head *protected_tag_namespaces, - struct got_pathlist_head *protected_branch_namespaces, - struct got_pathlist_head *protected_branches) + FILE *diff_f1, FILE *diff_f2, int diff_fd1, int diff_fd2) { const struct got_error *err = NULL; struct repo_write_client *client = &repo_write_client; @@ -2814,9 +2922,9 @@ repo_write_main(const char *title, const char *repo_pa repo_write.accum_file = accum_file; repo_write.session_fd = -1; repo_write.session_iev.ibuf.fd = -1; - repo_write.protected_tag_namespaces = protected_tag_namespaces; - repo_write.protected_branch_namespaces = protected_branch_namespaces; - repo_write.protected_branches = protected_branches; + RB_INIT(&repo_write.protected_tag_namespaces); + RB_INIT(&repo_write.protected_branch_namespaces); + RB_INIT(&repo_write.protected_branches); repo_write.diff.f1 = diff_f1; repo_write.diff.f2 = diff_f2; repo_write.diff.fd1 = diff_fd1; blob - b92737cd240dcff0ac723596bfbc5d355bb11aa8 blob + b60cc96d640f93ce59db0435e68a97ba1dfa1138 --- gotd/repo_write.h +++ gotd/repo_write.h @@ -15,7 +15,5 @@ */ void repo_write_main(const char *, const char *, int *, int *, - FILE *, FILE *, FILE *, FILE *, int, int, - struct got_pathlist_head *, struct got_pathlist_head *, - struct got_pathlist_head *); + FILE *, FILE *, FILE *, FILE *, int, int); void repo_write_shutdown(void);