Git.pm: trust rev-parse to find bare repositories
When initializing a repository object, we run "git rev-parse --git-dir" to let the C version of Git find the correct directory. But curiously, if this fails we don't automatically say "not a git repository". Instead, we do our own pure-perl check to see if we're in a bare repository. This makes little sense, as rev-parse will report both bare and non-bare directories. This logic comes fromd5c7721d58
(Git.pm: Add support for subdirectories inside of working copies, 2006-06-24), but I don't see any reason given why we can't just rely on rev-parse. Worse, because we treat any non-error response from rev-parse as a non-bare repository, we'll erroneously set the object's WorkingCopy, even in a bare repository. But it gets worse. Since8959555cee
(setup_git_directory(): add an owner check for the top-level directory, 2022-03-02), it's actively wrong (and dangerous). The perl code doesn't implement the same ownership checks. And worse, after "finding" the bare repository, it sets GIT_DIR in the environment, which tells any subsequent Git commands that we've confirmed the directory is OK, and to trust us. I.e., it re-opens the vulnerability plugged by8959555cee
when using Git.pm's repository discovery code. We can fix this by just relying on rev-parse to tell us when we're not in a repository, which fixes the vulnerability. Furthermore, we'll ask its --is-bare-repository function to tell us if we're bare or not, and rely on that. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
77a1310e6b
commit
20da61f25f
36
perl/Git.pm
36
perl/Git.pm
@ -177,16 +177,27 @@ sub repository {
|
||||
-d $opts{Directory} or throw Error::Simple("Directory not found: $opts{Directory} $!");
|
||||
|
||||
my $search = Git->repository(WorkingCopy => $opts{Directory});
|
||||
my $dir;
|
||||
|
||||
# This rev-parse will throw an exception if we're not in a
|
||||
# repository, which is what we want, but it's kind of noisy.
|
||||
# Ideally we'd capture stderr and relay it, but doing so is
|
||||
# awkward without depending on it fitting in a pipe buffer. So
|
||||
# we just reproduce a plausible error message ourselves.
|
||||
my $out;
|
||||
try {
|
||||
$dir = $search->command_oneline(['rev-parse', '--git-dir'],
|
||||
STDERR => 0);
|
||||
# Note that "--is-bare-repository" must come first, as
|
||||
# --git-dir output could contain newlines.
|
||||
$out = $search->command([qw(rev-parse --is-bare-repository --git-dir)],
|
||||
STDERR => 0);
|
||||
} catch Git::Error::Command with {
|
||||
$dir = undef;
|
||||
throw Error::Simple("fatal: not a git repository: $opts{Directory}");
|
||||
};
|
||||
|
||||
chomp $out;
|
||||
my ($bare, $dir) = split /\n/, $out, 2;
|
||||
|
||||
require Cwd;
|
||||
if ($dir) {
|
||||
if ($bare ne 'true') {
|
||||
require File::Spec;
|
||||
File::Spec->file_name_is_absolute($dir) or $dir = $opts{Directory} . '/' . $dir;
|
||||
$opts{Repository} = Cwd::abs_path($dir);
|
||||
@ -204,21 +215,6 @@ sub repository {
|
||||
$opts{WorkingSubdir} = $prefix;
|
||||
|
||||
} else {
|
||||
# A bare repository? Let's see...
|
||||
$dir = $opts{Directory};
|
||||
|
||||
unless (-d "$dir/refs" and -d "$dir/objects" and -e "$dir/HEAD") {
|
||||
# Mimic git-rev-parse --git-dir error message:
|
||||
throw Error::Simple("fatal: Not a git repository: $dir");
|
||||
}
|
||||
my $search = Git->repository(Repository => $dir);
|
||||
try {
|
||||
$search->command('symbolic-ref', 'HEAD');
|
||||
} catch Git::Error::Command with {
|
||||
# Mimic git-rev-parse --git-dir error message:
|
||||
throw Error::Simple("fatal: Not a git repository: $dir");
|
||||
};
|
||||
|
||||
$opts{Repository} = Cwd::abs_path($dir);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user