Skip to content

Commit d552f8d

Browse files
committed
Merge branch 'sg/archive-restrict-remote'
Allow loosening remote "git archive" invocation security check that refuses to serve tree-ish not at the tip of any ref. * sg/archive-restrict-remote: add uploadarchive.allowUnreachable option docs: clarify remote restrictions for git-upload-archive
2 parents c89eb98 + 7671b63 commit d552f8d

File tree

5 files changed

+63
-3
lines changed

5 files changed

+63
-3
lines changed

Documentation/config.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2336,6 +2336,13 @@ transfer.unpackLimit::
23362336
not set, the value of this variable is used instead.
23372337
The default value is 100.
23382338

2339+
uploadarchive.allowUnreachable::
2340+
If true, allow clients to use `git archive --remote` to request
2341+
any tree, whether reachable from the ref tips or not. See the
2342+
discussion in the `SECURITY` section of
2343+
linkgit:git-upload-archive[1] for more details. Defaults to
2344+
`false`.
2345+
23392346
uploadpack.hiderefs::
23402347
String(s) `upload-pack` uses to decide which refs to omit
23412348
from its initial advertisement. Use more than one

Documentation/git-archive.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ OPTIONS
6565

6666
--remote=<repo>::
6767
Instead of making a tar archive from the local repository,
68-
retrieve a tar archive from a remote repository.
68+
retrieve a tar archive from a remote repository. Note that the
69+
remote repository may place restrictions on which sha1
70+
expressions may be allowed in `<tree-ish>`. See
71+
linkgit:git-upload-archive[1] for details.
6972

7073
--exec=<git-upload-archive>::
7174
Used with --remote to specify the path to the

Documentation/git-upload-archive.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,38 @@ This command is usually not invoked directly by the end user. The UI
2020
for the protocol is on the 'git archive' side, and the program pair
2121
is meant to be used to get an archive from a remote repository.
2222

23+
SECURITY
24+
--------
25+
26+
In order to protect the privacy of objects that have been removed from
27+
history but may not yet have been pruned, `git-upload-archive` avoids
28+
serving archives for commits and trees that are not reachable from the
29+
repository's refs. However, because calculating object reachability is
30+
computationally expensive, `git-upload-archive` implements a stricter
31+
but easier-to-check set of rules:
32+
33+
1. Clients may request a commit or tree that is pointed to directly by
34+
a ref. E.g., `git archive --remote=origin v1.0`.
35+
36+
2. Clients may request a sub-tree within a commit or tree using the
37+
`ref:path` syntax. E.g., `git archive --remote=origin v1.0:Documentation`.
38+
39+
3. Clients may _not_ use other sha1 expressions, even if the end
40+
result is reachable. E.g., neither a relative commit like `master^`
41+
nor a literal sha1 like `abcd1234` is allowed, even if the result
42+
is reachable from the refs.
43+
44+
Note that rule 3 disallows many cases that do not have any privacy
45+
implications. These rules are subject to change in future versions of
46+
git, and the server accessed by `git archive --remote` may or may not
47+
follow these exact rules.
48+
49+
If the config option `uploadArchive.allowUnreachable` is true, these
50+
rules are ignored, and clients may use arbitrary sha1 expressions.
51+
This is useful if you do not care about the privacy of unreachable
52+
objects, or if your object database is already publicly available for
53+
access via non-smart-http.
54+
2355
OPTIONS
2456
-------
2557
<directory>::

archive.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ static char const * const archive_usage[] = {
1717
static const struct archiver **archivers;
1818
static int nr_archivers;
1919
static int alloc_archivers;
20+
static int remote_allow_unreachable;
2021

2122
void register_archiver(struct archiver *ar)
2223
{
@@ -257,7 +258,7 @@ static void parse_treeish_arg(const char **argv,
257258
unsigned char sha1[20];
258259

259260
/* Remotes are only allowed to fetch actual refs */
260-
if (remote) {
261+
if (remote && !remote_allow_unreachable) {
261262
char *ref = NULL;
262263
const char *colon = strchr(name, ':');
263264
int refnamelen = colon ? colon - name : strlen(name);
@@ -401,6 +402,14 @@ static int parse_archive_args(int argc, const char **argv,
401402
return argc;
402403
}
403404

405+
static int git_default_archive_config(const char *var, const char *value,
406+
void *cb)
407+
{
408+
if (!strcmp(var, "uploadarchive.allowunreachable"))
409+
remote_allow_unreachable = git_config_bool(var, value);
410+
return git_default_config(var, value, cb);
411+
}
412+
404413
int write_archive(int argc, const char **argv, const char *prefix,
405414
int setup_prefix, const char *name_hint, int remote)
406415
{
@@ -411,7 +420,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
411420
if (setup_prefix && prefix == NULL)
412421
prefix = setup_git_directory_gently(&nongit);
413422

414-
git_config(git_default_config, NULL);
423+
git_config(git_default_archive_config, NULL);
415424
init_tar_archiver();
416425
init_zip_archiver();
417426

t/t5000-tar-tree.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,15 @@ test_expect_success 'clients cannot access unreachable commits' '
213213
test_must_fail git archive --remote=. $sha1 >remote.tar
214214
'
215215

216+
test_expect_success 'upload-archive can allow unreachable commits' '
217+
test_commit unreachable1 &&
218+
sha1=`git rev-parse HEAD` &&
219+
git reset --hard HEAD^ &&
220+
git archive $sha1 >remote.tar &&
221+
test_config uploadarchive.allowUnreachable true &&
222+
git archive --remote=. $sha1 >remote.tar
223+
'
224+
216225
test_expect_success 'setup tar filters' '
217226
git config tar.tar.foo.command "tr ab ba" &&
218227
git config tar.bar.command "tr ab ba" &&

0 commit comments

Comments
 (0)