Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package git-lfs for openSUSE:Factory checked 
in at 2022-04-26 20:15:50
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/git-lfs (Old)
 and      /work/SRC/openSUSE:Factory/.git-lfs.new.1538 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "git-lfs"

Tue Apr 26 20:15:50 2022 rev:10 rq:972854 version:3.1.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/git-lfs/git-lfs.changes  2022-02-17 
23:41:38.215700363 +0100
+++ /work/SRC/openSUSE:Factory/.git-lfs.new.1538/git-lfs.changes        
2022-04-26 20:17:46.736761439 +0200
@@ -1,0 +2,6 @@
+Thu Apr 21 13:23:07 UTC 2022 - [email protected]
+
+- Update to version 3.1.4:
+  https://github.com/git-lfs/git-lfs/releases/tag/v3.1.4
+
+-------------------------------------------------------------------

Old:
----
  git-lfs-3.1.2.tar.gz

New:
----
  git-lfs-3.1.4.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ git-lfs.spec ++++++
--- /var/tmp/diff_new_pack.Kpd4of/_old  2022-04-26 20:17:47.144761932 +0200
+++ /var/tmp/diff_new_pack.Kpd4of/_new  2022-04-26 20:17:47.144761932 +0200
@@ -26,12 +26,12 @@
 %endif
 
 Name:           git-lfs
-Version:        3.1.2
+Version:        3.1.4
 Release:        0
 Summary:        Git extension for versioning large files
 License:        MIT
 Group:          Development/Tools/Version Control
-URL:            https://git-lfs.github.com/
+URL:            https://github.com/git-lfs/git-lfs
 Source0:        
https://github.com/git-lfs/git-lfs/releases/download/v%{version}/git-lfs-v%{version}.tar.gz#/%{name}-%{version}.tar.gz
 BuildRequires:  curl
 BuildRequires:  fdupes

++++++ git-lfs-3.1.2.tar.gz -> git-lfs-3.1.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/.github/workflows/ci.yml 
new/git-lfs-3.1.4/.github/workflows/ci.yml
--- old/git-lfs-3.1.2/.github/workflows/ci.yml  2022-02-16 18:49:01.000000000 
+0100
+++ new/git-lfs-3.1.4/.github/workflows/ci.yml  2022-04-19 22:31:26.000000000 
+0200
@@ -48,7 +48,7 @@
     - run: script/cibuild
   build-windows:
     name: Build on Windows
-    runs-on: windows-latest
+    runs-on: windows-2019
     steps:
     - uses: actions/checkout@v1
     - uses: actions/setup-ruby@v1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/.github/workflows/release.yml 
new/git-lfs-3.1.4/.github/workflows/release.yml
--- old/git-lfs-3.1.2/.github/workflows/release.yml     2022-02-16 
18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/.github/workflows/release.yml     2022-04-19 
22:31:26.000000000 +0200
@@ -6,7 +6,7 @@
 jobs:
   build-windows:
     name: Build Windows Assets
-    runs-on: windows-latest
+    runs-on: windows-2019
     strategy:
       matrix:
         go: ['1.17.x']
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/CHANGELOG.md 
new/git-lfs-3.1.4/CHANGELOG.md
--- old/git-lfs-3.1.2/CHANGELOG.md      2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/CHANGELOG.md      2022-04-19 22:31:26.000000000 +0200
@@ -1,5 +1,49 @@
 # Git LFS Changelog
 
+## 3.1.4 (19 Apr 2022)
+
+This release is a bugfix release to fix some problems during the build of
+v3.1.3.  There are otherwise no substantial changes from v3.1.3.
+
+### Misc
+
+* Use only Windows Server 2019 runners for CI in GitHub Actions #4883 
(@chrisd8088)
+* remove unused `Pipe[Media]Command()` functions #4942 (@chrisd8088)
+
+## 3.1.3 (19 Apr 2022)
+
+This release introduces a security fix for Windows systems, which has been
+assigned CVE-2022-24826.
+
+On Windows, if Git LFS operates on a malicious repository with a `..exe` file 
as
+well as a file named `git.exe`, and `git.exe` is not found in PATH, the `..exe`
+program will be executed, permitting the attacker to execute arbitrary code.
+Similarly, if the malicious repository contains files named `..exe` and
+`cygpath.exe`, and `cygpath.exe` is not found in PATH, the `..exe` program will
+be executed when certain Git LFS commands are run.
+
+This security problem does not affect Unix systems.  This is the same issue as
+CVE-2020-27955 and CVE-2021-21237, but the fix for those issue was incomplete
+and certain options can still cause the problem to occur.
+
+This occurs because on Windows, Go includes (and prefers) the current directory
+when the name of a command run does not contain a directory separator, and it
+continues to search for programs even when the specified program name is empty.
+This has been solved by failing if the path is empty or not found.
+
+We would like to extend a special thanks to the following open-source
+contributors:
+
+* @yuske for reporting this to us responsibly
+
+### Bugs
+
+* Report errors when finding executables and revise PATH search tests 
(@chrisd8088)
+
+### Misc
+
+* Update Windows signing certificate SHA hash in Makefile (@chrisd8088)
+
 ## 3.1.2 (16 Feb 2022)
 
 This is a bugfix release which fixes a bug in `git lfs install` and some issues
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/commands/command_clone.go 
new/git-lfs-3.1.4/commands/command_clone.go
--- old/git-lfs-3.1.2/commands/command_clone.go 2022-02-16 18:49:01.000000000 
+0100
+++ new/git-lfs-3.1.4/commands/command_clone.go 2022-04-19 22:31:26.000000000 
+0200
@@ -118,8 +118,11 @@
        // Use `git submodule foreach --recursive` to cascade into nested 
submodules
        // Also good to call a new instance of git-lfs rather than do things
        // inside this instance, since that way we get a clean env in that 
subrepo
-       cmd := subprocess.ExecCommand("git", "submodule", "foreach", 
"--recursive",
+       cmd, err := subprocess.ExecCommand("git", "submodule", "foreach", 
"--recursive",
                "git lfs pull")
+       if err != nil {
+               return err
+       }
        cmd.Stderr = os.Stderr
        cmd.Stdin = os.Stdin
        cmd.Stdout = os.Stdout
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/commands/command_ls_files.go 
new/git-lfs-3.1.4/commands/command_ls_files.go
--- old/git-lfs-3.1.2/commands/command_ls_files.go      2022-02-16 
18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/commands/command_ls_files.go      2022-04-19 
22:31:26.000000000 +0200
@@ -4,6 +4,7 @@
        "os"
        "strings"
 
+       "github.com/git-lfs/git-lfs/v3/errors"
        "github.com/git-lfs/git-lfs/v3/git"
        "github.com/git-lfs/git-lfs/v3/lfs"
        "github.com/git-lfs/git-lfs/v3/tools/humanize"
@@ -50,7 +51,11 @@
        } else {
                fullref, err := git.CurrentRef()
                if err != nil {
-                       ref = git.EmptyTree()
+                       ref, err = git.EmptyTree()
+                       if err != nil {
+                               ExitWithError(errors.Wrap(
+                                       err, tr.Tr.Get("Could not read empty 
Git tree object")))
+                       }
                } else {
                        ref = fullref.Sha
                }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/commands/command_status.go 
new/git-lfs-3.1.4/commands/command_status.go
--- old/git-lfs-3.1.2/commands/command_status.go        2022-02-16 
18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/commands/command_status.go        2022-04-19 
22:31:26.000000000 +0200
@@ -28,8 +28,12 @@
        ref, _ := git.CurrentRef()
 
        scanIndexAt := "HEAD"
+       var err error
        if ref == nil {
-               scanIndexAt = git.EmptyTree()
+               scanIndexAt, err = git.EmptyTree()
+               if err != nil {
+                       ExitWithError(err)
+               }
        }
 
        scanner, err := lfs.NewPointerScanner(cfg.GitEnv(), cfg.OSEnv())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/commands/commands.go 
new/git-lfs-3.1.4/commands/commands.go
--- old/git-lfs-3.1.2/commands/commands.go      2022-02-16 18:49:01.000000000 
+0100
+++ new/git-lfs-3.1.4/commands/commands.go      2022-04-19 22:31:26.000000000 
+0200
@@ -281,18 +281,6 @@
        }
 }
 
-func PipeMediaCommand(name string, args ...string) error {
-       return PipeCommand("bin/"+name, args...)
-}
-
-func PipeCommand(name string, args ...string) error {
-       cmd := subprocess.ExecCommand(name, args...)
-       cmd.Stdin = os.Stdin
-       cmd.Stderr = os.Stderr
-       cmd.Stdout = os.Stdout
-       return cmd.Run()
-}
-
 func requireStdin(msg string) {
        var out string
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/commands/path_windows.go 
new/git-lfs-3.1.4/commands/path_windows.go
--- old/git-lfs-3.1.2/commands/path_windows.go  2022-02-16 18:49:01.000000000 
+0100
+++ new/git-lfs-3.1.4/commands/path_windows.go  2022-04-19 22:31:26.000000000 
+0200
@@ -48,7 +48,10 @@
 
        if len(winBashPrefix) < 1 {
                // cmd.Path is something like C:\Program 
Files\Git\usr\bin\pwd.exe
-               cmd := subprocess.ExecCommand("pwd")
+               cmd, err := subprocess.ExecCommand("pwd")
+               if err != nil {
+                       return pattern
+               }
                winBashPrefix = 
strings.Replace(filepath.Dir(filepath.Dir(filepath.Dir(cmd.Path))), `\`, "/", 
-1) + "/"
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/commands/pull.go 
new/git-lfs-3.1.4/commands/pull.go
--- old/git-lfs-3.1.2/commands/pull.go  2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/commands/pull.go  2022-04-19 22:31:26.000000000 +0200
@@ -147,7 +147,10 @@
 
        if i.cmd == nil {
                // Fire up the update-index command
-               cmd := git.UpdateIndexFromStdin()
+               cmd, err := git.UpdateIndexFromStdin()
+               if err != nil {
+                       return err
+               }
                cmd.Stdout = &i.output
                cmd.Stderr = &i.output
                stdin, err := cmd.StdinPipe()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/config/version.go 
new/git-lfs-3.1.4/config/version.go
--- old/git-lfs-3.1.2/config/version.go 2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/config/version.go 2022-04-19 22:31:26.000000000 +0200
@@ -13,7 +13,7 @@
 )
 
 const (
-       Version = "3.1.2"
+       Version = "3.1.4"
 )
 
 func init() {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/creds/creds.go 
new/git-lfs-3.1.4/creds/creds.go
--- old/git-lfs-3.1.2/creds/creds.go    2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/creds/creds.go    2022-04-19 22:31:26.000000000 +0200
@@ -241,7 +241,11 @@
 
        // 'cmd' will run the GIT_ASKPASS (or core.askpass) command prompting
        // for the desired valueType (`Username` or `Password`)
-       cmd := subprocess.ExecCommand(a.Program, a.args(fmt.Sprintf("%s for 
%q", valueString, u))...)
+       cmd, errVal := subprocess.ExecCommand(a.Program, a.args(fmt.Sprintf("%s 
for %q", valueString, u))...)
+       if errVal != nil {
+               tracerx.Printf("creds: failed to find GIT_ASKPASS command: %s", 
a.Program)
+               return "", errVal
+       }
        cmd.Stderr = &err
        cmd.Stdout = &value
 
@@ -301,7 +305,10 @@
 
 func (h *commandCredentialHelper) exec(subcommand string, input Creds) (Creds, 
error) {
        output := new(bytes.Buffer)
-       cmd := subprocess.ExecCommand("git", "credential", subcommand)
+       cmd, err := subprocess.ExecCommand("git", "credential", subcommand)
+       if err != nil {
+               return nil, errors.New(tr.Tr.Get("failed to find `git 
credential %s`: %v", subcommand, err))
+       }
        cmd.Stdin = bufferCreds(input)
        cmd.Stdout = output
        /*
@@ -316,7 +323,7 @@
        */
        cmd.Stderr = os.Stderr
 
-       err := cmd.Start()
+       err = cmd.Start()
        if err == nil {
                err = cmd.Wait()
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/debian/changelog 
new/git-lfs-3.1.4/debian/changelog
--- old/git-lfs-3.1.2/debian/changelog  2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/debian/changelog  2022-04-19 22:31:26.000000000 +0200
@@ -1,3 +1,15 @@
+git-lfs (3.1.4) stable; urgency=low
+
+  * New upstream version
+
+ -- brian m. carlson <[email protected]>  Tue, 19 Apr 2022 14:29:00 -0000
+
+git-lfs (3.1.3) stable; urgency=low
+
+  * New upstream version
+
+ -- brian m. carlson <[email protected]>  Tue, 19 Apr 2022 14:29:00 -0000
+
 git-lfs (3.1.2) stable; urgency=low
 
   * New upstream version
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/git/config.go 
new/git-lfs-3.1.4/git/config.go
--- old/git-lfs-3.1.2/git/config.go     2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/git/config.go     2022-04-19 22:31:26.000000000 +0200
@@ -199,7 +199,10 @@
 
 func (c *Configuration) gitConfig(args ...string) (string, error) {
        args = append([]string{"config", "--includes"}, args...)
-       cmd := subprocess.ExecCommand("git", args...)
+       cmd, err := subprocess.ExecCommand("git", args...)
+       if err != nil {
+               return "", err
+       }
        if len(c.GitDir) > 0 {
                cmd.Dir = c.GitDir
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/git/git.go new/git-lfs-3.1.4/git/git.go
--- old/git-lfs-3.1.2/git/git.go        2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/git/git.go        2022-04-19 22:31:26.000000000 +0200
@@ -148,17 +148,20 @@
        return false
 }
 
-func EmptyTree() string {
+func EmptyTree() (string, error) {
        emptyTreeMutex.Lock()
        defer emptyTreeMutex.Unlock()
 
        if len(emptyTree) == 0 {
-               cmd := gitNoLFS("hash-object", "-t", "tree", "/dev/null")
+               cmd, err := gitNoLFS("hash-object", "-t", "tree", "/dev/null")
+               if err != nil {
+                       return "", errors.New(tr.Tr.Get("failed to find `git 
hash-object`: %v", err))
+               }
                cmd.Stdin = nil
                out, _ := cmd.Output()
                emptyTree = strings.TrimSpace(string(out))
        }
-       return emptyTree
+       return emptyTree, nil
 }
 
 // Some top level information about a commit (only first line of message)
@@ -198,7 +201,7 @@
 }
 
 // Invoke Git with disabled LFS filters
-func gitNoLFS(args ...string) *subprocess.Cmd {
+func gitNoLFS(args ...string) (*subprocess.Cmd, error) {
        return subprocess.ExecCommand("git", gitConfigNoLFS(args...)...)
 }
 
@@ -211,7 +214,7 @@
 }
 
 // Invoke Git with enabled LFS filters
-func git(args ...string) *subprocess.Cmd {
+func git(args ...string) (*subprocess.Cmd, error) {
        return subprocess.ExecCommand("git", args...)
 }
 
@@ -253,7 +256,10 @@
 }
 
 func HashObject(r io.Reader) (string, error) {
-       cmd := gitNoLFS("hash-object", "--stdin")
+       cmd, err := gitNoLFS("hash-object", "--stdin")
+       if err != nil {
+               return "", errors.New(tr.Tr.Get("failed to find `git 
hash-object`: %v", err))
+       }
        cmd.Stdin = r
        out, err := cmd.Output()
        if err != nil {
@@ -381,7 +387,10 @@
 }
 
 func RemoteList() ([]string, error) {
-       cmd := gitNoLFS("remote")
+       cmd, err := gitNoLFS("remote")
+       if err != nil {
+               return nil, errors.New(tr.Tr.Get("failed to find `git remote`: 
%v", err))
+       }
 
        outp, err := cmd.StdoutPipe()
        if err != nil {
@@ -401,7 +410,10 @@
 }
 
 func RemoteURLs(push bool) (map[string][]string, error) {
-       cmd := gitNoLFS("remote", "-v")
+       cmd, err := gitNoLFS("remote", "-v")
+       if err != nil {
+               return nil, errors.New(tr.Tr.Get("failed to find `git remote 
-v`: %v", err))
+       }
 
        outp, err := cmd.StdoutPipe()
        if err != nil {
@@ -451,7 +463,10 @@
 // Refs returns all of the local and remote branches and tags for the current
 // repository. Other refs (HEAD, refs/stash, git notes) are ignored.
 func LocalRefs() ([]*Ref, error) {
-       cmd := gitNoLFS("show-ref")
+       cmd, err := gitNoLFS("show-ref")
+       if err != nil {
+               return nil, errors.New(tr.Tr.Get("failed to find `git 
show-ref`: %v", err))
+       }
 
        outp, err := cmd.StdoutPipe()
        if err != nil {
@@ -500,7 +515,10 @@
                args = append(args, "-m", reason)
        }
 
-       cmd := gitNoLFS(args...)
+       cmd, err := gitNoLFS(args...)
+       if err != nil {
+               return errors.New(tr.Tr.Get("failed to find `git update-ref`: 
%v", err))
+       }
        cmd.Dir = wd
 
        return cmd.Run()
@@ -578,7 +596,7 @@
        return fmt.Sprintf("file://%s%s", slash, filepath.ToSlash(path))
 }
 
-func UpdateIndexFromStdin() *subprocess.Cmd {
+func UpdateIndexFromStdin() (*subprocess.Cmd, error) {
        return git("update-index", "-q", "--refresh", "--stdin")
 }
 
@@ -588,10 +606,13 @@
 // includeRemoteBranches: true to include refs on remote branches
 // onlyRemote: set to non-blank to only include remote branches on a single 
remote
 func RecentBranches(since time.Time, includeRemoteBranches bool, onlyRemote 
string) ([]*Ref, error) {
-       cmd := gitNoLFS("for-each-ref",
+       cmd, err := gitNoLFS("for-each-ref",
                `--sort=-committerdate`,
                `--format=%(refname) %(objectname) %(committerdate:iso)`,
                "refs")
+       if err != nil {
+               return nil, errors.New(tr.Tr.Get("failed to find `git 
for-each-ref`: %v", err))
+       }
        outp, err := cmd.StdoutPipe()
        if err != nil {
                return nil, errors.New(tr.Tr.Get("failed to call `git 
for-each-ref`: %v", err))
@@ -687,8 +708,11 @@
 
 // Get summary information about a commit
 func GetCommitSummary(commit string) (*CommitSummary, error) {
-       cmd := gitNoLFS("show", "-s",
+       cmd, err := gitNoLFS("show", "-s",
                `--format=%H|%h|%P|%ai|%ci|%ae|%an|%ce|%cn|%s`, commit)
+       if err != nil {
+               return nil, errors.New(tr.Tr.Get("failed to find `git show`: 
%v", err))
+       }
 
        out, err := cmd.CombinedOutput()
        if err != nil {
@@ -722,7 +746,10 @@
 }
 
 func GitAndRootDirs() (string, string, error) {
-       cmd := gitNoLFS("rev-parse", "--git-dir", "--show-toplevel")
+       cmd, err := gitNoLFS("rev-parse", "--git-dir", "--show-toplevel")
+       if err != nil {
+               return "", "", errors.New(tr.Tr.Get("failed to find `git 
rev-parse --git-dir --show-toplevel`: %v", err))
+       }
        buf := &bytes.Buffer{}
        cmd.Stderr = buf
 
@@ -760,7 +787,10 @@
 }
 
 func RootDir() (string, error) {
-       cmd := gitNoLFS("rev-parse", "--show-toplevel")
+       cmd, err := gitNoLFS("rev-parse", "--show-toplevel")
+       if err != nil {
+               return "", errors.New(tr.Tr.Get("failed to find `git rev-parse 
--show-toplevel`: %v", err))
+       }
        out, err := cmd.Output()
        if err != nil {
                return "", errors.New(tr.Tr.Get("failed to call `git rev-parse 
--show-toplevel`: %v %v", err, string(out)))
@@ -775,7 +805,12 @@
 }
 
 func GitDir() (string, error) {
-       cmd := gitNoLFS("rev-parse", "--git-dir")
+       cmd, err := gitNoLFS("rev-parse", "--git-dir")
+       if err != nil {
+               // The %w format specifier is unique to fmt.Errorf(), so we
+               // do not pass it to tr.Tr.Get().
+               return "", fmt.Errorf("%s: %w", tr.Tr.Get("failed to find `git 
rev-parse --git-dir`"), err)
+       }
        buf := &bytes.Buffer{}
        cmd.Stderr = buf
        out, err := cmd.Output()
@@ -797,7 +832,10 @@
                return GitDir()
        }
 
-       cmd := gitNoLFS("rev-parse", "--git-common-dir")
+       cmd, err := gitNoLFS("rev-parse", "--git-common-dir")
+       if err != nil {
+               return "", errors.New(tr.Tr.Get("failed to find `git rev-parse 
--git-common-dir`: %v", err))
+       }
        out, err := cmd.Output()
        buf := &bytes.Buffer{}
        cmd.Stderr = buf
@@ -1055,14 +1093,17 @@
 
        // Now args
        cmdargs = append(cmdargs, args...)
-       cmd := gitNoLFS(cmdargs...)
+       cmd, err := gitNoLFS(cmdargs...)
+       if err != nil {
+               return errors.New(tr.Tr.Get("failed to find `git clone`: %v", 
err))
+       }
 
        // Assign all streams direct
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr
        cmd.Stdin = os.Stdin
 
-       err := cmd.Start()
+       err = cmd.Start()
        if err != nil {
                return errors.New(tr.Tr.Get("failed to start `git clone`: %v", 
err))
        }
@@ -1102,7 +1143,10 @@
 // currently cached locally. No remote request is made to verify them.
 func CachedRemoteRefs(remoteName string) ([]*Ref, error) {
        var ret []*Ref
-       cmd := gitNoLFS("show-ref")
+       cmd, err := gitNoLFS("show-ref")
+       if err != nil {
+               return nil, errors.New(tr.Tr.Get("failed to find `git 
show-ref`: %v", err))
+       }
 
        outp, err := cmd.StdoutPipe()
        if err != nil {
@@ -1157,7 +1201,10 @@
 // accessing the remote via git ls-remote.
 func RemoteRefs(remoteName string) ([]*Ref, error) {
        var ret []*Ref
-       cmd := gitNoLFS("ls-remote", "--heads", "--tags", "-q", remoteName)
+       cmd, err := gitNoLFS("ls-remote", "--heads", "--tags", "-q", remoteName)
+       if err != nil {
+               return nil, errors.New(tr.Tr.Get("failed to find `git 
ls-remote`: %v", err))
+       }
 
        outp, err := cmd.StdoutPipe()
        if err != nil {
@@ -1216,8 +1263,11 @@
 // the given working directory "wd", or an error if those references could not
 // be loaded.
 func AllRefsIn(wd string) ([]*Ref, error) {
-       cmd := gitNoLFS(
+       cmd, err := gitNoLFS(
                "for-each-ref", "--format=%(objectname)%00%(refname)")
+       if err != nil {
+               return nil, lfserrors.Wrap(err, tr.Tr.Get("failed to find `git 
for-each-ref`: %v", err))
+       }
        cmd.Dir = wd
 
        outp, err := cmd.StdoutPipe()
@@ -1262,12 +1312,15 @@
        rootWildcard := len(safePattern) < len(pattern) && 
strings.ContainsRune(safePattern, '*')
 
        var ret []string
-       cmd := gitNoLFS(
+       cmd, err := gitNoLFS(
                "-c", "core.quotepath=false", // handle special chars in 
filenames
                "ls-files",
                "--cached", // include things which are staged but not 
committed right now
                "--",       // no ambiguous patterns
                safePattern)
+       if err != nil {
+               return nil, errors.New(tr.Tr.Get("failed to find `git 
ls-files`: %v", err))
+       }
 
        outp, err := cmd.StdoutPipe()
        if err != nil {
@@ -1321,7 +1374,10 @@
        }
        args = append(args, "--") // no ambiguous patterns
 
-       cmd := gitNoLFS(args...)
+       cmd, err := gitNoLFS(args...)
+       if err != nil {
+               return nil, errors.New(tr.Tr.Get("failed to find `git 
diff-tree`: %v", err))
+       }
        outp, err := cmd.StdoutPipe()
        if err != nil {
                return nil, errors.New(tr.Tr.Get("failed to call `git diff`: 
%v", err))
@@ -1352,7 +1408,10 @@
                "--", // separator in case filename ambiguous
                filepath,
        }
-       cmd := git(args...)
+       cmd, err := git(args...)
+       if err != nil {
+               return false, lfserrors.Wrap(err, tr.Tr.Get("failed to find 
`git status`"))
+       }
        outp, err := cmd.StdoutPipe()
        if err != nil {
                return false, lfserrors.Wrap(err, tr.Tr.Get("Failed to call 
`git status`"))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/git/ls_files.go 
new/git-lfs-3.1.4/git/ls_files.go
--- old/git-lfs-3.1.2/git/ls_files.go   2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/git/ls_files.go   2022-04-19 22:31:26.000000000 +0200
@@ -35,7 +35,10 @@
        if untracked {
                args = append(args, "--others")
        }
-       cmd := gitNoLFS(args...)
+       cmd, err := gitNoLFS(args...)
+       if err != nil {
+               return nil, err
+       }
        cmd.Dir = workingDir
 
        tracerx.Printf("NewLsFiles: running in %s git %s",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/git/rev_list_scanner.go 
new/git-lfs-3.1.4/git/rev_list_scanner.go
--- old/git-lfs-3.1.2/git/rev_list_scanner.go   2022-02-16 18:49:01.000000000 
+0100
+++ new/git-lfs-3.1.4/git/rev_list_scanner.go   2022-04-19 22:31:26.000000000 
+0200
@@ -169,7 +169,10 @@
                return nil, err
        }
 
-       cmd := gitNoLFS(args...).Cmd
+       cmd, err := gitNoLFS(args...)
+       if err != nil {
+               return nil, err
+       }
        if len(opt.WorkingDir) > 0 {
                cmd.Dir = opt.WorkingDir
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/lfs/extension.go 
new/git-lfs-3.1.4/lfs/extension.go
--- old/git-lfs-3.1.2/lfs/extension.go  2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/lfs/extension.go  2022-04-19 22:31:26.000000000 +0200
@@ -76,7 +76,11 @@
                        arg := strings.Replace(value, "%f", request.fileName, 
-1)
                        args = append(args, arg)
                }
-               cmd := subprocess.ExecCommand(name, args...)
+               var cmd *subprocess.Cmd
+               cmd, err = subprocess.ExecCommand(name, args...)
+               if err != nil {
+                       return
+               }
                ec := &extCommand{cmd: cmd, result: &pipeExtResult{name: 
e.Name}}
                extcmds = append(extcmds, ec)
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/lfshttp/certs_darwin.go 
new/git-lfs-3.1.4/lfshttp/certs_darwin.go
--- old/git-lfs-3.1.2/lfshttp/certs_darwin.go   2022-02-16 18:49:01.000000000 
+0100
+++ new/git-lfs-3.1.4/lfshttp/certs_darwin.go   2022-04-19 22:31:26.000000000 
+0200
@@ -19,7 +19,11 @@
        // either, for consistency.
 
        // find system.keychain for user-added certs (don't assume location)
-       cmd := subprocess.ExecCommand("/usr/bin/security", "list-keychains")
+       cmd, err := subprocess.ExecCommand("/usr/bin/security", 
"list-keychains")
+       if err != nil {
+               tracerx.Printf("Error getting command to list keychains: %v", 
err)
+               return nil
+       }
        kcout, err := cmd.Output()
        if err != nil {
                tracerx.Printf("Error listing keychains: %v", err)
@@ -54,7 +58,11 @@
 }
 
 func appendRootCAsFromKeychain(pool *x509.CertPool, name, keychain string) 
*x509.CertPool {
-       cmd := subprocess.ExecCommand("/usr/bin/security", "find-certificate", 
"-a", "-p", "-c", name, keychain)
+       cmd, err := subprocess.ExecCommand("/usr/bin/security", 
"find-certificate", "-a", "-p", "-c", name, keychain)
+       if err != nil {
+               tracerx.Printf("Error getting command to read keychain %q: %v", 
keychain, err)
+               return pool
+       }
        data, err := cmd.Output()
        if err != nil {
                tracerx.Printf("Error reading keychain %q: %v", keychain, err)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/lfshttp/ssh.go 
new/git-lfs-3.1.4/lfshttp/ssh.go
--- old/git-lfs-3.1.2/lfshttp/ssh.go    2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/lfshttp/ssh.go    2022-04-19 22:31:26.000000000 +0200
@@ -80,7 +80,10 @@
        }
 
        exe, args := ssh.GetLFSExeAndArgs(c.os, c.git, &e.SSHMetadata, 
"git-lfs-authenticate", endpointOperation(e, method), false)
-       cmd := subprocess.ExecCommand(exe, args...)
+       cmd, err := subprocess.ExecCommand(exe, args...)
+       if err != nil {
+               return res, err
+       }
 
        // Save stdout and stderr in separate buffers
        var outbuf, errbuf bytes.Buffer
@@ -90,7 +93,7 @@
        now := time.Now()
 
        // Execute command
-       err := cmd.Start()
+       err = cmd.Start()
        if err == nil {
                err = cmd.Wait()
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/lfshttp/standalone/standalone.go 
new/git-lfs-3.1.4/lfshttp/standalone/standalone.go
--- old/git-lfs-3.1.2/lfshttp/standalone/standalone.go  2022-02-16 
18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/lfshttp/standalone/standalone.go  2022-04-19 
22:31:26.000000000 +0200
@@ -119,7 +119,10 @@
                return "", err
        }
 
-       cmd := subprocess.ExecCommand("git", "rev-parse", "--git-dir")
+       cmd, err := subprocess.ExecCommand("git", "rev-parse", "--git-dir")
+       if err != nil {
+               return "", errors.Wrap(err, tr.Tr.Get("failed to find `git 
rev-parse --git-dir`"))
+       }
        cmd.Cmd.Env = env
        out, err := cmd.Output()
        if err != nil {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/rpm/SPECS/git-lfs.spec 
new/git-lfs-3.1.4/rpm/SPECS/git-lfs.spec
--- old/git-lfs-3.1.2/rpm/SPECS/git-lfs.spec    2022-02-16 18:49:01.000000000 
+0100
+++ new/git-lfs-3.1.4/rpm/SPECS/git-lfs.spec    2022-04-19 22:31:26.000000000 
+0200
@@ -1,5 +1,5 @@
 Name:           git-lfs
-Version:        3.1.2
+Version:        3.1.4
 Release:        1%{?dist}
 Summary:        Git extension for versioning large files
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/ssh/connection.go 
new/git-lfs-3.1.4/ssh/connection.go
--- old/git-lfs-3.1.2/ssh/connection.go 2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/ssh/connection.go 2022-04-19 22:31:26.000000000 +0200
@@ -34,7 +34,10 @@
 
 func startConnection(id int, osEnv config.Environment, gitEnv 
config.Environment, meta *SSHMetadata, operation string) (*PktlineConnection, 
error) {
        exe, args := GetLFSExeAndArgs(osEnv, gitEnv, meta, "git-lfs-transfer", 
operation, true)
-       cmd := subprocess.ExecCommand(exe, args...)
+       cmd, err := subprocess.ExecCommand(exe, args...)
+       if err != nil {
+               return nil, err
+       }
        r, err := cmd.StdoutPipe()
        if err != nil {
                return nil, err
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/subprocess/subprocess.go 
new/git-lfs-3.1.4/subprocess/subprocess.go
--- old/git-lfs-3.1.2/subprocess/subprocess.go  2022-02-16 18:49:01.000000000 
+0100
+++ new/git-lfs-3.1.4/subprocess/subprocess.go  2022-04-19 22:31:26.000000000 
+0200
@@ -20,7 +20,10 @@
 // stdout & stderr pipes, wrapped in a BufferedCmd. The stdout buffer will be
 // of stdoutBufSize bytes.
 func BufferedExec(name string, args ...string) (*BufferedCmd, error) {
-       cmd := ExecCommand(name, args...)
+       cmd, err := ExecCommand(name, args...)
+       if err != nil {
+               return nil, err
+       }
        stdout, err := cmd.StdoutPipe()
        if err != nil {
                return nil, err
@@ -49,7 +52,11 @@
 
 // SimpleExec is a small wrapper around os/exec.Command.
 func SimpleExec(name string, args ...string) (string, error) {
-       return Output(ExecCommand(name, args...))
+       cmd, err := ExecCommand(name, args...)
+       if err != nil {
+               return "", err
+       }
+       return Output(cmd)
 }
 
 func Output(cmd *Cmd) (string, error) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/subprocess/subprocess_nix.go 
new/git-lfs-3.1.4/subprocess/subprocess_nix.go
--- old/git-lfs-3.1.2/subprocess/subprocess_nix.go      2022-02-16 
18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/subprocess/subprocess_nix.go      2022-04-19 
22:31:26.000000000 +0200
@@ -8,9 +8,13 @@
 )
 
 // ExecCommand is a small platform specific wrapper around os/exec.Command
-func ExecCommand(name string, arg ...string) *Cmd {
+func ExecCommand(name string, arg ...string) (*Cmd, error) {
        cmd := exec.Command(name, arg...)
-       cmd.Path, _ = LookPath(name)
+       var err error
+       cmd.Path, err = LookPath(name)
+       if err != nil {
+               return nil, err
+       }
        cmd.Env = fetchEnvironment()
-       return newCmd(cmd)
+       return newCmd(cmd), nil
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/subprocess/subprocess_windows.go 
new/git-lfs-3.1.4/subprocess/subprocess_windows.go
--- old/git-lfs-3.1.2/subprocess/subprocess_windows.go  2022-02-16 
18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/subprocess/subprocess_windows.go  2022-04-19 
22:31:26.000000000 +0200
@@ -9,10 +9,14 @@
 )
 
 // ExecCommand is a small platform specific wrapper around os/exec.Command
-func ExecCommand(name string, arg ...string) *Cmd {
+func ExecCommand(name string, arg ...string) (*Cmd, error) {
        cmd := exec.Command(name, arg...)
-       cmd.Path, _ = LookPath(name)
+       var err error
+       cmd.Path, err = LookPath(name)
+       if err != nil {
+               return nil, err
+       }
        cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
        cmd.Env = fetchEnvironment()
-       return newCmd(cmd)
+       return newCmd(cmd), nil
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/t/Makefile new/git-lfs-3.1.4/t/Makefile
--- old/git-lfs-3.1.2/t/Makefile        2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/t/Makefile        2022-04-19 22:31:26.000000000 +0200
@@ -13,6 +13,7 @@
 TEST_CMDS += ../bin/lfs-askpass$X
 TEST_CMDS += ../bin/lfs-ssh-echo$X
 TEST_CMDS += ../bin/lfs-ssh-proxy-test$X
+TEST_CMDS += ../bin/lfstest-badpathcheck$X
 TEST_CMDS += ../bin/lfstest-count-tests$X
 TEST_CMDS += ../bin/lfstest-customadapter$X
 TEST_CMDS += ../bin/lfstest-gitserver$X
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/t/cmd/lfstest-badpathcheck.go 
new/git-lfs-3.1.4/t/cmd/lfstest-badpathcheck.go
--- old/git-lfs-3.1.2/t/cmd/lfstest-badpathcheck.go     1970-01-01 
01:00:00.000000000 +0100
+++ new/git-lfs-3.1.4/t/cmd/lfstest-badpathcheck.go     2022-04-19 
22:31:26.000000000 +0200
@@ -0,0 +1,19 @@
+//go:build testtools
+// +build testtools
+
+package main
+
+import (
+       "fmt"
+       "os"
+)
+
+func main() {
+       fmt.Println("exploit")
+       fmt.Fprintln(os.Stderr, "exploit")
+
+       f, err := os.Create("exploit")
+       if err != nil {
+               f.Close()
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/t/t-credentials-no-prompt.sh 
new/git-lfs-3.1.4/t/t-credentials-no-prompt.sh
--- old/git-lfs-3.1.2/t/t-credentials-no-prompt.sh      2022-02-16 
18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/t/t-credentials-no-prompt.sh      2022-04-19 
22:31:26.000000000 +0200
@@ -45,8 +45,7 @@
 
   git config "credential.helper" ""
   GIT_TERMINAL_PROMPT=0 GIT_ASKPASS="lfs-askpass-2" SSH_ASKPASS="dont-call-me" 
GIT_TRACE=1 git push origin main 2>&1 | tee push.log
-  grep "filling with GIT_ASKPASS" push.log                     # attempt 
askpass
-  grep 'credential fill error: exec: "lfs-askpass-2"' push.log # askpass fails
+  grep "failed to find GIT_ASKPASS command" push.log           # attempt 
askpass
   grep "creds: git credential fill" push.log                   # attempt git 
credential
 )
 end_test
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/t/t-path.sh 
new/git-lfs-3.1.4/t/t-path.sh
--- old/git-lfs-3.1.2/t/t-path.sh       2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/t/t-path.sh       2022-04-19 22:31:26.000000000 +0200
@@ -9,16 +9,18 @@
   reponame="$(basename "$0" ".sh")"
   git init "$reponame"
   cd "$reponame"
-  export PATH="$(echo "$PATH" | sed -e "s/:.:/:/g" -e "s/::/:/g")"
 
-  printf "#!/bin/sh\necho exploit >&2\n" > git
-  chmod +x git || true
-  printf "echo exploit 1>&2\n" > git.bat
-
-  # This needs to succeed.  If it fails, that could be because our malicious
-  # "git" is broken but got invoked anyway.
-  git lfs env > output.log 2>&1
-  ! grep -q 'exploit' output.log
+  cp "$BINPATH/lfstest-badpathcheck$X" "git$X"
+
+  # This should always succeed, even if git-lfs is incorrectly searching for
+  # executables in the current directory first, because the "git-lfs env"
+  # command ignores all errors when it runs "git config".  So we should always
+  # pass this step and then, if our malicious Git was executed, detect
+  # its output below.  If this command does fail, something else is wrong.
+  PATH="$BINPATH" PATHEXT="$X" "git-lfs$X" env >output.log 2>&1
+
+  grep "exploit" output.log && false
+  [ ! -f exploit ]
 )
 end_test
 
@@ -30,32 +32,156 @@
   setup_remote_repo "$reponame"
 
   clone_repo "$reponame" credentials-1
-  export PATH="$(echo "$PATH" | sed -e "s/:.:/:/g" -e "s/::/:/g")"
-
-  printf "#!/bin/sh\necho exploit >&2\ntouch exploit\n" > git
-  chmod +x git || true
-  printf "echo exploit 1>&2\r\necho >exploit" > git.bat
 
   git lfs track "*.dat"
   printf abc > z.dat
   git add z.dat
   git add .gitattributes
-  git add git git.bat
-  git commit -m "Add files"
 
+  GITPATH="$(dirname "$(command -v git)")"
+
+  # We add our malicious Git to the index and then remove it from the
+  # work tree so it is not found early, before we perform our key test.
+  # Specifically, our "git push" below will run git-lfs, which then runs
+  # "git credential", so if we are looking for Git in the current directory
+  # first when running a credential helper, we will fail at that point
+  # because our malicious Git will be found first.
+  #
+  # We prefer to check for this behavior during our "git-lfs pull" further
+  # below when we are populating LFS objects into a clone of this repo
+  # (which contains the malicious Git), so for now we remove the malicious
+  # Git as soon as possible.
+  cp "$BINPATH/lfstest-badpathcheck$X" "git$X"
+  PATH="$BINPATH:$GITPATH" "$GITPATH/git$X" add "git$X"
+  rm "git$X"
+
+  git commit -m "Add files"
   git push origin HEAD
   cd ..
 
   unset GIT_ASKPASS SSH_ASKPASS
 
-  # This needs to succeed.  If it fails, that could be because our malicious
-  # "git" is broken but got invoked anyway.
-  GIT_LFS_SKIP_SMUDGE=1 clone_repo "$reponame" credentials-2
+  # When we call "git clone" below, it will run git-lfs as a smudge filter
+  # during the post-clone checkout phase, and specifically will run git-lfs
+  # in the newly cloned repository directory which contains a copy of our
+  # malicious Git.  So, if we are looking for Git in the current directory
+  # first in most cases (and not just when running a credential helper),
+  # then when git-lfs runs "git config" we will fail at that point because
+  # our malicious Git will be found first.  This occurs even if we specify
+  # GIT_LFS_SKIP_SMUDGE=1 because git-lfs will still run "git config".
+  #
+  # We could ignore errors from clone_repo() and then search for the output
+  # of our malicious Git in the t-path-credentials-2 directory; however,
+  # this may be somewhat fragile as clone_repo() performs other steps such
+  # as changing the current working directory to the new repo clone and
+  # attempting to run "git config" there.
+  #
+  # Instead, since our key check of "git-lfs pull" below will also detect
+  # the general failure case where we are looking for Git in the current
+  # directory first when running most commands, we temporarily uninstall
+  # Git LFS so no smudge filter will execute when "git clone" checks out the
+  # repository.
+  #
+  # We also remove any "exploit" file potentially created by our malicious
+  # Git in case it was run anywhere in clone_repo(), which may happen if
+  # PATH contains the "." directory already.  Note that we reset PATH
+  # to contain only the necessary directories in our key "git-lfs pull"
+  # check below.
+  git lfs uninstall
+  clone_repo "$reponame" t-path-credentials-2
+  rm -f exploit
+  pushd ..
+    git lfs install
+  popd
+
+  # As noted, if we are looking for Git in the current directory first
+  # only when running a credential helper, then when this runs
+  # "git credential", it will find our malicious Git in the current directory
+  # and execute it.
+  #
+  # If we are looking for Git in the current directory first when running
+  # most commands (and not just when running a credential helper), then this
+  # will also find our malicious Git.  However, in this case it will find it
+  # earlier when we try to run "git config" rather than later when we try
+  # to run "git credential".
+  #
+  # We use a pipeline with "tee" here so as to avoid an early failure in the
+  # case that our "git-lfs pull" command executes our malicious Git.
+  # Unlike "git-lfs env" in the other tests, "git-lfs pull" will halt when
+  # it does not receive the normal output from Git.  This in turn halts
+  # our test due to our use of the "set -e" option, unless we terminate a
+  # pipeline with successful command like "tee".
+  PATH="$BINPATH:$GITPATH" PATHEXT="$X" "git-lfs$X" pull 2>&1 | tee output.log
+
+  grep "exploit" output.log && false
+  [ ! -f exploit ]
+)
+end_test
+
+begin_test "does not look in current directory for wrong binary using PATHEXT"
+(
+  set -e
+
+  # Windows is the only platform where Go searches for executable files
+  # by appending file extensions from PATHEXT.
+  [ "$IS_WINDOWS" -eq 0 ] && exit 0
+
+  reponame="$(basename "$0" ".sh")-notfound"
+  git init "$reponame"
+  cd "$reponame"
+
+  # Go on Windows always looks in the current directory first when creating
+  # a command handler, so we need a dummy git.exe for it to find there since
+  # we will restrict PATH to exclude the real Git when we run "git-lfs env"
+  # below.  If our git-lfs incorrectly proceeds to run the command handler
+  # despite not finding Git in PATH either, Go may then search for a file
+  # named "." with any path extension from PATHEXT and execute that file
+  # instead, so we create a malicious file named "..exe" to check this case.
+  touch "git$X"
+  cp "$BINPATH/lfstest-badpathcheck$X" ".$X"
+
+  # This should always succeed, even if git-lfs is incorrectly searching for
+  # executables in the current directory first, because the "git-lfs env"
+  # command ignores all errors when it runs "git config".  So we should always
+  # pass this step and then, if our malicious program was executed, detect
+  # its output below.  If this command does fail, something else is wrong.
+  PATH="$BINPATH" PATHEXT="$X" "git-lfs$X" env >output.log 2>&1
+
+  grep "exploit" output.log && false
+  [ ! -f exploit ]
+)
+end_test
+
+begin_test "does not look in current directory for wrong binary using PATHEXT"
+(
+  set -e
+
+  # Windows is the only platform where Go searches for executable files
+  # by appending file extensions from PATHEXT.
+  [ "$IS_WINDOWS" -eq 0 ] && exit 0
+
+  reponame="$(basename "$0" ".sh")-notfound"
+  git init "$reponame"
+  cd "$reponame"
 
-  git lfs pull | tee output.log
+  # Go on Windows always looks in the current directory first when creating
+  # a command handler, so we need a dummy git.exe for it to find there since
+  # we will restrict PATH to exclude the real Git when we run "git-lfs env"
+  # below.  If our git-lfs incorrectly proceeds to run the command handler
+  # despite not finding Git in PATH either, Go may then search for a file
+  # named "." with any path extension from PATHEXT and execute that file
+  # instead, so we create a malicious file named "..exe" to check this case.
+  touch "git$X"
+  cp "$BINPATH/lfstest-badpathcheck$X" ".$X"
+
+  # This should always succeed, even if git-lfs is incorrectly searching for
+  # executables in the current directory first, because the "git-lfs env"
+  # command ignores all errors when it runs "git config".  So we should always
+  # pass this step and then, if our malicious program was executed, detect
+  # its output below.  If this command does fail, something else is wrong.
+  PATH="$BINPATH" PATHEXT="$X" "git-lfs$X" env >output.log 2>&1
 
-  ! grep -q 'exploit' output.log
-  [ ! -f ../exploit ]
+  grep "exploit" output.log && false
   [ ! -f exploit ]
 )
 end_test
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/t/testenv.sh 
new/git-lfs-3.1.4/t/testenv.sh
--- old/git-lfs-3.1.2/t/testenv.sh      2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/t/testenv.sh      2022-04-19 22:31:26.000000000 +0200
@@ -6,12 +6,14 @@
 UNAME=$(uname -s)
 IS_WINDOWS=0
 IS_MAC=0
+X=""
 SHASUM="shasum -a 256"
 PATH_SEPARATOR="/"
 
 if [[ $UNAME == MINGW* || $UNAME == MSYS* || $UNAME == CYGWIN* ]]
 then
   IS_WINDOWS=1
+  X=".exe"
 
   # Windows might be MSYS2 which does not have the shasum Perl wrapper
   # script by default, so use sha256sum directly. MacOS on the other hand
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/tools/cygwin_windows.go 
new/git-lfs-3.1.4/tools/cygwin_windows.go
--- old/git-lfs-3.1.2/tools/cygwin_windows.go   2022-02-16 18:49:01.000000000 
+0100
+++ new/git-lfs-3.1.4/tools/cygwin_windows.go   2022-04-19 22:31:26.000000000 
+0200
@@ -38,7 +38,10 @@
                return cygwinState.Enabled()
        }
 
-       cmd := subprocess.ExecCommand("uname")
+       cmd, err := subprocess.ExecCommand("uname")
+       if err != nil {
+               return false
+       }
        out, err := cmd.Output()
        if err != nil {
                return false
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/tools/os_tools.go 
new/git-lfs-3.1.4/tools/os_tools.go
--- old/git-lfs-3.1.2/tools/os_tools.go 2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/tools/os_tools.go 2022-04-19 22:31:26.000000000 +0200
@@ -28,7 +28,12 @@
 }
 
 func translateCygwinPath(path string) (string, error) {
-       cmd := subprocess.ExecCommand("cygpath", "-w", path)
+       cmd, err := subprocess.ExecCommand("cygpath", "-w", path)
+       if err != nil {
+               // If cygpath doesn't exist, that's okay: just return the paths
+               // as we got it.
+               return path, nil
+       }
        // cygpath uses ISO-8850-1 as the default encoding if the locale is not
        // set, resulting in breakage, since we want a UTF-8 path.
        env := make([]string, 0, len(cmd.Env)+1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/tq/custom.go 
new/git-lfs-3.1.4/tq/custom.go
--- old/git-lfs-3.1.2/tq/custom.go      2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/tq/custom.go      2022-04-19 22:31:26.000000000 +0200
@@ -125,7 +125,10 @@
        // If concurrent = false we have already dialled back workers to 1
        a.Trace("xfer: starting up custom transfer process %q for worker %d", 
a.name, workerNum)
        cmdName, cmdArgs := 
subprocess.FormatForShell(subprocess.ShellQuoteSingle(a.path), a.args)
-       cmd := subprocess.ExecCommand(cmdName, cmdArgs...)
+       cmd, err := subprocess.ExecCommand(cmdName, cmdArgs...)
+       if err != nil {
+               return nil, errors.New(tr.Tr.Get("failed to find custom 
transfer command %q remote: %v", a.path, err))
+       }
        outp, err := cmd.StdoutPipe()
        if err != nil {
                return nil, errors.New(tr.Tr.Get("failed to get stdout for 
custom transfer command %q remote: %v", a.path, err))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-lfs-3.1.2/versioninfo.json 
new/git-lfs-3.1.4/versioninfo.json
--- old/git-lfs-3.1.2/versioninfo.json  2022-02-16 18:49:01.000000000 +0100
+++ new/git-lfs-3.1.4/versioninfo.json  2022-04-19 22:31:26.000000000 +0200
@@ -4,7 +4,7 @@
                "FileVersion": {
                        "Major": 3,
                        "Minor": 1,
-                       "Patch": 2,
+                       "Patch": 4,
                        "Build": 0
                }
        },
@@ -13,7 +13,7 @@
                "FileDescription": "Git LFS",
                "LegalCopyright": "GitHub, Inc. and Git LFS contributors",
                "ProductName": "Git Large File Storage (LFS)",
-               "ProductVersion": "3.1.2"
+               "ProductVersion": "3.1.4"
        },
        "IconPath": "script/windows-installer/git-lfs-logo.ico"
 }

Reply via email to