git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 2/2] archive: loosen restrictions on remote object lookup

From
Jeff King <peff@peff.net>
Date
Jan 11, 2012, 19:42 UTC
Message-ID
<20120111194232.GB12441@sigill.intra.peff.net>
In-Reply-To
<20120111193916.GA12333@sigill.intra.peff.net>

Initially, "git upload-archive" would feed the tree specification from the remote side directly into get_sha1, giving the remote user the full power of the object name resolver. This was convenient, but it also meant that remote users could fetch disconnected trees by their sha1s, which violates the long-standing behavior of upload-pack not to make such objects available.

Later, commit ee27ca4 tightened this to use dwim_ref instead of get_sha1 for the remote case, allowing only the use of actual refs. Unfortunately, this broke some existing use cases, like fetching sub-trees with "$ref:subdir".

This patch loosens the restrictions to re-enable those use cases. It does this by using get_sha1_with_context for the object lookup, and checking that only allowable features were used.

Signed-off-by: Jeff King <peff@peff.net>
---
 archive.c                     |   34 ++++++++++++++-------
 t/t5002-archive-resolution.sh |   66 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 89 insertions(+), 11 deletions(-)
 create mode 100755 t/t5002-archive-resolution.sh
diff --git a/archive.c b/archive.c
index 164bbd0..a031bde 100644
--- a/archive.c
+++ b/archive.c
@@ -246,6 +246,25 @@ static void parse_pathspec_arg(const char **pathspec,
 	}
 }
 
+static int check_object_context(int remote, const struct object_context *oc)
+{
+	/* For local requests, allow anything */
+	if (!remote)
+		return 1;
+	/*
+	 * Otherwise, require that we accessed the object through a ref,
+	 * but not have used any of the advanced features like looking in
+	 * the reflog.
+	 */
+	return oc->used_ref &&
+	       !oc->used_reflog &&
+	       !oc->used_index &&
+	       !oc->used_nth_checkout &&
+	       !oc->used_describe_name &&
+	       !oc->used_oneline &&
+	       !oc->used_raw_hex;
+}
+
 static void parse_treeish_arg(const char **argv,
 		struct archiver_args *ar_args, const char *prefix,
 		int remote)
@@ -256,18 +275,11 @@ static void parse_treeish_arg(const char **argv,
 	struct tree *tree;
 	const struct commit *commit;
 	unsigned char sha1[20];
+	struct object_context oc;
 
-	/* Remotes are only allowed to fetch actual refs */
-	if (remote) {
-		char *ref = NULL;
-		if (!dwim_ref(name, strlen(name), sha1, &ref))
-			die("no such ref: %s", name);
-		free(ref);
-	}
-	else {
-		if (get_sha1(name, sha1))
-			die("Not a valid object name");
-	}
+	if (get_sha1_with_context(name, sha1, &oc) ||
+	    !check_object_context(remote, &oc))
+		die("Not a valid object name");
 
 	commit = lookup_commit_reference_gently(sha1, 1);
 	if (commit) {
diff --git a/t/t5002-archive-resolution.sh b/t/t5002-archive-resolution.sh
new file mode 100755
index 0000000..bf2b55c
--- /dev/null
+++ b/t/t5002-archive-resolution.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+test_description='test object resolution methods for local and remote archive'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	echo a >a &&
+	git add . &&
+	git commit -m one &&
+	sha1_one=`git rev-parse HEAD` &&
+	mkdir subdir &&
+	echo b >subdir/b &&
+	git add . &&
+	git commit -m two &&
+	git checkout -b other &&
+	git checkout master
+'
+
+while read desc where what expect; do
+	cmd="git archive --format=tar -o result.tar"
+	test "$where" = "remote" && cmd="$cmd --remote=."
+	cmd="$cmd $what"
+
+	if test "$expect" = "deny"; then
+		test_expect_success "archive $desc ($where, should deny)" "
+			test_must_fail $cmd
+		"
+	else
+		test_expect_success "archive $desc ($where, should work)" '
+			'"$cmd"' &&
+			for i in '"$expect"'; do
+				echo "$i:`basename $i`"
+			done >expect &&
+			rm -rf result &&
+			mkdir result &&
+			(cd result &&
+			tar xf ../result.tar &&
+			for i in `find * -type f`; do
+				echo "$i:`cat $i`"
+			done >../actual
+			) &&
+			test_cmp expect actual
+		'
+	fi
+done <<EOF
+ref local  master a subdir/b
+ref remote master a subdir/b
+parent local  master^ a
+parent remote master^ a
+tree local  master^{tree} a subdir/b
+tree remote master^{tree} a subdir/b
+subtree local  master:subdir b
+subtree remote master:subdir b
+sha1 local  $sha1_one a
+sha1 remote $sha1_one deny
+reflog local  master@{1} a
+reflog remote master@{1} deny
+oneline local  :/one a
+oneline remote :/one deny
+oneline-ref local  master^{/one} a
+oneline-ref remote master^{/one} deny
+nth-checkout local  @{-1} a subdir/b
+nth-checkout remote @{-1} deny
+EOF
+
+test_done
-- 
1.7.9.rc0.33.gd3c17
Previous: Jeff KingNext: Ian Harvey
Message 11 of 30 in “[BUG] git archive broken in 1.7.8.1”
  1. Albert Astals CidJan 10, 2012
  2. Carlos Martín NietoJan 10, 2012
  3. Albert Astals CidJan 10, 2012
  4. Carlos Martín NietoJan 10, 2012
  5. Jeff KingJan 10, 2012
  6. archive: re-allow HEAD:Documentation on a remote invocationCarlos Martín Nieto, Jan 11, 2012
  7. Jeff KingJan 11, 2012
  8. 1/2 get_sha1_with_context: report features used in resolutionJeff King, Jan 11, 2012
  9. Junio C HamanoJan 12, 2012
  10. Jeff KingJan 12, 2012
  11. 2/2 archive: loosen restrictions on remote object lookupJeff King, Jan 11, 2012
  12. Ian HarveyMay 29, 2013
  13. Jeff KingJun 5, 2013
  14. 0/4 real reachability checks for upload-archiveJeff King, Jun 5, 2013
  15. 1/4 clear parsed flag when we free tree buffersJeff King, Jun 5, 2013
  16. Junio C HamanoJun 6, 2013
  17. 2/4 upload-archive: restrict remote objects with reachability checkJeff King, Jun 5, 2013
  18. 3/4 list-objects: optimize "revs->blob_objects = 0" caseJeff King, Jun 5, 2013
  19. 4/4 archive: ignore blob objects when checking reachabilityJeff King, Jun 5, 2013
  20. Michael HaggertyJun 6, 2013
  21. Eric SunshineJun 7, 2013
  22. Junio C HamanoJun 6, 2013
  23. Junio C HamanoJan 12, 2012
  24. Jeff KingJan 12, 2012
  25. Jeff KingJan 12, 2012
  26. Junio C HamanoJan 12, 2012
  27. Jeff KingJan 12, 2012
  28. Junio C HamanoJan 12, 2012
  29. Allan WindJan 10, 2012
  30. Carlos Martín NietoJan 11, 2012

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.