refs: reject ref updates while GIT_QUARANTINE_PATH is set
authorJeff King <peff@peff.net>
Mon, 10 Apr 2017 22:14:12 +0000 (18:14 -0400)
committerJunio C Hamano <gitster@pobox.com>
Mon, 17 Apr 2017 01:19:18 +0000 (18:19 -0700)
As documented in git-receive-pack(1), updating a ref from
within the pre-receive hook is dangerous and can corrupt
your repo. This patch forbids ref updates entirely during
the hook to make it harder for adventurous hook writers to
shoot themselves in the foot.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-receive-pack.txt
refs.c
t/t5547-push-quarantine.sh
index 7267ecfbe85b6c8246af79d1fb1fcf3dadf74764..86a4b32f0f1cbb8b69ff8b935edade6f14e7d5e2 100644 (file)
@@ -239,7 +239,8 @@ This has a few user-visible effects and caveats:
   3. The `pre-receive` hook MUST NOT update any refs to point to
      quarantined objects. Other programs accessing the repository will
      not be able to see the objects (and if the pre-receive hook fails,
-     those refs would become corrupted).
+     those refs would become corrupted). For safety, any ref updates
+     from within `pre-receive` are automatically rejected.
 
 
 SEE ALSO
diff --git a/refs.c b/refs.c
index 5ffdd778d9766cad21e251e9020e2be2ce677acf..916b0d5fa53fda935d1ef220c1652fb07212f4f6 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1465,6 +1465,12 @@ int ref_transaction_commit(struct ref_transaction *transaction,
 {
        struct ref_store *refs = get_ref_store(NULL);
 
+       if (getenv(GIT_QUARANTINE_ENVIRONMENT)) {
+               strbuf_addstr(err,
+                             _("ref updates forbidden inside quarantine environment"));
+               return -1;
+       }
+
        return refs->be->transaction_commit(refs, transaction, err);
 }
 
index 1e5d32d068539098598b23fb3b489688ac140169..462bfc9cba81e0db9a8a97b94d32dcb96de6eec7 100755 (executable)
@@ -33,4 +33,15 @@ test_expect_success 'rejected objects are removed' '
        test_cmp expect actual
 '
 
+test_expect_success 'updating a ref from quarantine is forbidden' '
+       git init --bare update.git &&
+       write_script update.git/hooks/pre-receive <<-\EOF &&
+       read old new refname
+       git update-ref refs/heads/unrelated $new
+       exit 1
+       EOF
+       test_must_fail git push update.git HEAD &&
+       git -C update.git fsck
+'
+
 test_done