Skip to content

Commit 6a57e74

Browse files
committed
Merge branch 'bc/allow-upload-pack-from-other-people' into seen
Loosen overly strict ownership check introduced in the recent past, to keep the promise "cloning a suspicious repository is a safe first step to inspect it". Comments? * bc/allow-upload-pack-from-other-people: Allow cloning from repositories owned by another user
2 parents c544568 + 0ffb5a6 commit 6a57e74

File tree

7 files changed

+49
-11
lines changed

7 files changed

+49
-11
lines changed

Documentation/git-clone.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ symbolic link, the clone will fail. This is a security measure to
6363
prevent the unintentional copying of files by dereferencing the symbolic
6464
links.
6565
+
66+
This option does not work with repositories owned by other users for security
67+
reasons, and `--no-local` must be specified for the clone to succeed.
68+
+
6669
*NOTE*: this operation can race with concurrent modification to the
6770
source repository, similar to running `cp -r <src> <dst>` while modifying
6871
_<src>_.
@@ -384,6 +387,12 @@ $ cd my-linux
384387
$ git clone --bare -l /home/proj/.git /pub/scm/proj.git
385388
------------
386389

390+
* Clone a local repository from a different user:
391+
+
392+
------------
393+
$ git clone --no-local /home/otheruser/proj.git /pub/scm/proj.git
394+
------------
395+
387396
CONFIGURATION
388397
-------------
389398

builtin/upload-pack.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ int cmd_upload_pack(int argc,
3939
N_("interrupt transfer after <n> seconds of inactivity")),
4040
OPT_END()
4141
};
42+
unsigned enter_repo_flags = ENTER_REPO_ANY_OWNER_OK;
4243

4344
packet_trace_identity("upload-pack");
4445
disable_replace_refs();
@@ -54,7 +55,9 @@ int cmd_upload_pack(int argc,
5455

5556
dir = argv[0];
5657

57-
if (!enter_repo(dir, strict))
58+
if (strict)
59+
enter_repo_flags |= ENTER_REPO_STRICT;
60+
if (!enter_repo(dir, enter_repo_flags))
5861
die("'%s' does not appear to be a git repository", dir);
5962

6063
switch (determine_protocol_version_server()) {

daemon.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ static const char *path_ok(const char *directory, struct hostinfo *hi)
152152
size_t rlen;
153153
const char *path;
154154
const char *dir;
155+
unsigned enter_repo_flags;
155156

156157
dir = directory;
157158

@@ -242,14 +243,15 @@ static const char *path_ok(const char *directory, struct hostinfo *hi)
242243
dir = rpath;
243244
}
244245

245-
path = enter_repo(dir, strict_paths);
246+
enter_repo_flags = strict_paths ? ENTER_REPO_STRICT : 0;
247+
path = enter_repo(dir, enter_repo_flags);
246248
if (!path && base_path && base_path_relaxed) {
247249
/*
248250
* if we fail and base_path_relaxed is enabled, try without
249251
* prefixing the base path
250252
*/
251253
dir = directory;
252-
path = enter_repo(dir, strict_paths);
254+
path = enter_repo(dir, enter_repo_flags);
253255
}
254256

255257
if (!path) {

path.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -684,15 +684,15 @@ char *interpolate_path(const char *path, int real_home)
684684
* links. User relative paths are also returned as they are given,
685685
* except DWIM suffixing.
686686
*/
687-
const char *enter_repo(const char *path, int strict)
687+
const char *enter_repo(const char *path, unsigned flags)
688688
{
689689
static struct strbuf validated_path = STRBUF_INIT;
690690
static struct strbuf used_path = STRBUF_INIT;
691691

692692
if (!path)
693693
return NULL;
694694

695-
if (!strict) {
695+
if (!(flags & ENTER_REPO_STRICT)) {
696696
static const char *suffix[] = {
697697
"/.git", "", ".git/.git", ".git", NULL,
698698
};
@@ -736,7 +736,8 @@ const char *enter_repo(const char *path, int strict)
736736
if (!suffix[i])
737737
return NULL;
738738
gitfile = read_gitfile(used_path.buf);
739-
die_upon_dubious_ownership(gitfile, NULL, used_path.buf);
739+
if (!(flags & ENTER_REPO_ANY_OWNER_OK))
740+
die_upon_dubious_ownership(gitfile, NULL, used_path.buf);
740741
if (gitfile) {
741742
strbuf_reset(&used_path);
742743
strbuf_addstr(&used_path, gitfile);
@@ -747,7 +748,8 @@ const char *enter_repo(const char *path, int strict)
747748
}
748749
else {
749750
const char *gitfile = read_gitfile(path);
750-
die_upon_dubious_ownership(gitfile, NULL, path);
751+
if (!(flags & ENTER_REPO_ANY_OWNER_OK))
752+
die_upon_dubious_ownership(gitfile, NULL, path);
751753
if (gitfile)
752754
path = gitfile;
753755
if (chdir(path))

path.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,22 @@ int calc_shared_perm(int mode);
156156
int adjust_shared_perm(const char *path);
157157

158158
char *interpolate_path(const char *path, int real_home);
159-
const char *enter_repo(const char *path, int strict);
159+
160+
/* The bits are as follows:
161+
*
162+
* - ENTER_REPO_STRICT: callers that require exact paths (as opposed
163+
* to allowing known suffixes like ".git", ".git/.git" to be
164+
* omitted) can set this bit.
165+
*
166+
* - ENTER_REPO_ANY_OWNER_OK: callers that are willing to run without
167+
* ownership check can set this bit.
168+
*/
169+
enum {
170+
ENTER_REPO_STRICT = (1<<0),
171+
ENTER_REPO_ANY_OWNER_OK = (1<<1),
172+
};
173+
174+
const char *enter_repo(const char *path, unsigned flags);
160175
const char *remove_leading_path(const char *in, const char *prefix);
161176
const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);
162177
int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);

t/t0411-clone-from-partial.sh

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ test_expect_success 'local clone must not fetch from promisor remote and execute
2828
test_must_fail git clone \
2929
--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
3030
evil clone1 2>err &&
31-
test_grep "detected dubious ownership" err &&
3231
test_grep ! "fake-upload-pack running" err &&
3332
test_path_is_missing script-executed
3433
'
@@ -38,7 +37,6 @@ test_expect_success 'clone from file://... must not fetch from promisor remote a
3837
test_must_fail git clone \
3938
--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
4039
"file://$(pwd)/evil" clone2 2>err &&
41-
test_grep "detected dubious ownership" err &&
4240
test_grep ! "fake-upload-pack running" err &&
4341
test_path_is_missing script-executed
4442
'
@@ -48,7 +46,6 @@ test_expect_success 'fetch from file://... must not fetch from promisor remote a
4846
test_must_fail git fetch \
4947
--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
5048
"file://$(pwd)/evil" 2>err &&
51-
test_grep "detected dubious ownership" err &&
5249
test_grep ! "fake-upload-pack running" err &&
5350
test_path_is_missing script-executed
5451
'

t/t5605-clone-local.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,16 @@ test_expect_success 'cloning a local path with --no-local does not hardlink' '
153153
! repo_is_hardlinked force-nonlocal
154154
'
155155

156+
test_expect_success 'cloning a local path with --no-local from a different user succeeds' '
157+
git clone --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
158+
--no-local a nonlocal-otheruser 2>err &&
159+
! repo_is_hardlinked nonlocal-otheruser &&
160+
# Verify that this is a git repository.
161+
git -C nonlocal-otheruser rev-parse --show-toplevel &&
162+
! test_grep "detected dubious ownership" err
163+
164+
'
165+
156166
test_expect_success 'cloning locally respects "-u" for fetching refs' '
157167
test_must_fail git clone --bare -u false a should_not_work.git
158168
'

0 commit comments

Comments
 (0)