From 8d26fdd6709ba341570bf665f1ace0556bdcf5cb Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 20 Sep 2022 14:52:43 -0400 Subject: [PATCH] skip checkRepoConfigInaccessible when git directory specified explicitly Fix a reversion that prevented git-annex from working in a repository when --git-dir or GIT_DIR is specified to relocate the git directory to somewhere else. (Introduced in version 10.20220525) checkRepoConfigInaccessible could still run git config --list, just passing --git-dir. It seems not necessary, because I know that passing --git-dir bypasses git's check for repo ownership. I suppose it might be that git eventually changes to check something about the ownership of the working tree, so passing --git-dir without --work-tree would still be worth doing. But for now this is the simple fix. Sponsored-by: Nicholas Golder-Manning on Patreon --- CHANGELOG | 4 +++ Git/Config.hs | 30 +++++++++-------- Git/Construct.hs | 1 + Git/CurrentRepo.hs | 9 +++--- Git/Types.hs | 2 ++ .../When_--git-dir_is_not_in_--work-tree.mdwn | 32 +++++++++++++++++++ 6 files changed, 61 insertions(+), 17 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c054007290..56593f35cc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -23,6 +23,10 @@ git-annex (10.20220823) UNRELEASED; urgency=medium that it had changed, due to only accepting the inode+mtime of one file (that was since modified or deleted) and not accepting the inode+mtime of other duplicate files. + * Fix a reversion that prevented git-annex from working in a + repository when --git-dir or GIT_DIR is specified to relocate the git + directory to somewhere else. + (Introduced in version 10.20220525) -- Joey Hess Mon, 29 Aug 2022 15:03:04 -0400 diff --git a/Git/Config.hs b/Git/Config.hs index 7fd096d1f8..7bf2793778 100644 --- a/Git/Config.hs +++ b/Git/Config.hs @@ -282,16 +282,20 @@ unset ck@(ConfigKey k) r = ifM (Git.Command.runBool ps r) - repo. -} checkRepoConfigInaccessible :: Repo -> IO Bool -checkRepoConfigInaccessible r = do - -- Cannot use gitCommandLine here because specifying --git-dir - -- will bypass the git security check. - let p = (proc "git" ["config", "--local", "--list"]) - { cwd = Just (fromRawFilePath (repoPath r)) - , env = gitEnv r - } - (out, ok) <- processTranscript' p Nothing - if not ok - then do - debug (DebugSource "Git.Config") ("config output: " ++ out) - return True - else return False +checkRepoConfigInaccessible r + -- When --git-dir or GIT_DIR is used to specify the git + -- directory, git does not check for CVE-2022-24765. + | gitDirSpecifiedExplicitly r = return False + | otherwise = do + -- Cannot use gitCommandLine here because specifying --git-dir + -- will bypass the git security check. + let p = (proc "git" ["config", "--local", "--list"]) + { cwd = Just (fromRawFilePath (repoPath r)) + , env = gitEnv r + } + (out, ok) <- processTranscript' p Nothing + if not ok + then do + debug (DebugSource "Git.Config") ("config output: " ++ out) + return True + else return False diff --git a/Git/Construct.hs b/Git/Construct.hs index a5e825e7c3..27123e337d 100644 --- a/Git/Construct.hs +++ b/Git/Construct.hs @@ -277,5 +277,6 @@ newFrom l = Repo , gitEnv = Nothing , gitEnvOverridesGitDir = False , gitGlobalOpts = [] + , gitDirSpecifiedExplicitly = False } diff --git a/Git/CurrentRepo.hs b/Git/CurrentRepo.hs index 9261eabca1..bd1ab5cd4b 100644 --- a/Git/CurrentRepo.hs +++ b/Git/CurrentRepo.hs @@ -1,6 +1,6 @@ {- The current git repository. - - - Copyright 2012-2020 Joey Hess + - Copyright 2012-2022 Joey Hess - - Licensed under the GNU AGPL version 3 or higher. -} @@ -80,9 +80,10 @@ get = do , worktree = Just curr } r <- Git.Config.read $ newFrom loc - return $ if Git.Config.isBare r - then r { location = (location r) { worktree = Nothing } } - else r + let r' = r { gitDirSpecifiedExplicitly = True } + return $ if Git.Config.isBare r' + then r' { location = (location r) { worktree = Nothing } } + else r' configure Nothing Nothing = giveup "Not in a git repository." addworktree w r = changelocation r $ Local diff --git a/Git/Types.hs b/Git/Types.hs index 68045fc027..ce1818e71c 100644 --- a/Git/Types.hs +++ b/Git/Types.hs @@ -51,6 +51,8 @@ data Repo = Repo , gitEnvOverridesGitDir :: Bool -- global options to pass to git when running git commands , gitGlobalOpts :: [CommandParam] + -- True only when --git-dir or GIT_DIR was used + , gitDirSpecifiedExplicitly :: Bool } deriving (Show, Eq, Ord) newtype ConfigKey = ConfigKey S.ByteString diff --git a/doc/bugs/When_--git-dir_is_not_in_--work-tree.mdwn b/doc/bugs/When_--git-dir_is_not_in_--work-tree.mdwn index 35d13758a2..dbc430b22c 100644 --- a/doc/bugs/When_--git-dir_is_not_in_--work-tree.mdwn +++ b/doc/bugs/When_--git-dir_is_not_in_--work-tree.mdwn @@ -18,3 +18,35 @@ Simple test case: failed +And --debug shows: + + [2022-09-20 14:17:56.238686901] (Utility.Process) process [1284622] read: git ["config","--local","--list"] + [2022-09-20 14:17:56.240836887] (Utility.Process) process [1284622] done ExitFailure 128 + [2022-09-20 14:17:56.24107763] (Git.Config) config output: fatal: --local can only be used inside a git repository + +So passing --git-dir to that command will make it succeeed. The problem +though is that passing --git-dir to that command also bypasses git's +fix for CVE-2022-24765. The command would even succeed if the directory +were owned by someone else then. + + joey@darkstar:/tmp/foo>sudo chown -R root.root . + [sudo] password for joey: + joey@darkstar:/tmp/foo>git --git-dir=`pwd`/.dotfiles config --local --list + core.repositoryformatversion=0 + core.filemode=true + core.bare=false + core.logallrefupdates=true + core.worktree=/tmp/foo + joey@darkstar:/tmp/foo>git config --local --list + fatal: --local can only be used inside a git repository + +But, if the user runs git-annex with an explicit --git-dir, +it's actually ok for git-annex to bypass the CVE-2022-24765 check. +Because --git-dir actually bypasses that check. + +So, the fix for this seems like it will involve it remembering +when the git repo was originally specified using --git-dir (or `GIT_DIR`), +and if so, guardSafeToUseRepo can skip the check, or pass --git-dir to +`git config --local --list`. + +> [[fixed|done]] --[[Joey]]