From 0ef3ddaa20b027c211debfaffe4c5b9e454f23b3 Mon Sep 17 00:00:00 2001 From: Stefan Sperling Date: Mon, 27 Jan 2025 08:05:48 +0000 Subject: [PATCH] fix gotd failing to protect references when the client sends an empty pack Found by martijn@ ok jamsek --- gotd/repo_write.c | 53 ++++++++++++++++++++++++++++++++++++ regress/gotd/repo_write_protected.sh | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/gotd/repo_write.c b/gotd/repo_write.c index 2f1b2189..4a593257 100644 --- a/gotd/repo_write.c +++ b/gotd/repo_write.c @@ -1503,6 +1503,51 @@ protect_refs_from_deletion(void) } static const struct got_error * +protect_refs_from_moving(void) +{ + const struct got_error *err = NULL; + struct repo_write_client *client = &repo_write_client; + struct gotd_ref_update *ref_update; + struct got_pathlist_entry *pe; + const char *refname; + + STAILQ_FOREACH(ref_update, &client->ref_updates, entry) { + if (ref_update->delete_ref) + continue; + + if (got_object_id_cmp(&ref_update->old_id, + &ref_update->new_id) == 0) + continue; + + refname = got_ref_get_name(ref_update->ref); + + RB_FOREACH(pe, got_pathlist_head, + 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) { + err = protect_ref_namespace(refname, pe->path); + if (err) + return err; + } + + RB_FOREACH(pe, got_pathlist_head, repo_write.protected_branches) + { + if (strcmp(refname, pe->path) == 0) { + return got_error_fmt(GOT_ERR_REF_PROTECTED, + "%s", refname); + } + } + } + + return NULL; +} + +static const struct got_error * install_packfile(struct gotd_imsgev *iev) { struct repo_write_client *client = &repo_write_client; @@ -2249,6 +2294,14 @@ repo_write_dispatch_session(int fd, short event, void *arg) */ repo_write.repo->pack_path_mtime.tv_sec = 0; repo_write.repo->pack_path_mtime.tv_nsec = 0; + } else { + /* + * Clients sending empty pack files might be + * attempting to move a protected reference. + */ + err = protect_refs_from_moving(); + if (err) + break; } err = update_refs(iev); if (err) { diff --git a/regress/gotd/repo_write_protected.sh b/regress/gotd/repo_write_protected.sh index ea1abadc..d1e70129 100644 --- a/regress/gotd/repo_write_protected.sh +++ b/regress/gotd/repo_write_protected.sh @@ -199,7 +199,7 @@ test_modify_protected_branch() { got checkout $testroot/repo-clone $testroot/wt >/dev/null - for i in 1 2 3; do + for i in 1 2; do echo "more alpha" >> $testroot/wt/alpha (cd $testroot/wt && got commit -m "more" >/dev/null) done -- 2.11.4.GIT