Move the `_which` function (almost) to the top

We are about to make use of the `_which` function to address CVE-2022-41953 by overriding Tcl/Tk's unsafe PATH lookup on Windows. In preparation for that, let's move it close to the top of the file to make sure that even early `exec` calls that happen during the start-up of Git GUI benefit from the fix. This commit is best viewed with `--color-moved`. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Pratyush Yadav <me@yadavpratyush.com>

Johannes Schindelin committed Dec 5, 2022 at 14:37 UTC fd477a1d3bab580c2fcdc435f551dca3094286ae
1 file changed +46 -42
git-gui.sh
+46 -42
@@ -75,6 +75,52 @@ proc is_Cygwin {} {
75 return $_iscygwin
76 }
77
78 +######################################################################
79 +##
80 +## PATH lookup
81 +
82 +set _search_path {}
83 +proc _which {what args} {
84 + global env _search_exe _search_path
85 +
86 + if {$_search_path eq {}} {
87 + if {[is_Cygwin] && [regexp {^(/|\.:)} $env(PATH)]} {
88 + set _search_path [split [exec cygpath \
89 + --windows \
90 + --path \
91 + --absolute \
92 + $env(PATH)] {;}]
93 + set _search_exe .exe
94 + } elseif {[is_Windows]} {
95 + set gitguidir [file dirname [info script]]
96 + regsub -all ";" $gitguidir "\\;" gitguidir
97 + set env(PATH) "$gitguidir;$env(PATH)"
98 + set _search_path [split $env(PATH) {;}]
99 + # Skip empty `PATH` elements
100 + set _search_path [lsearch -all -inline -not -exact \
101 + $_search_path ""]
102 + set _search_exe .exe
103 + } else {
104 + set _search_path [split $env(PATH) :]
105 + set _search_exe {}
106 + }
107 + }
108 +
109 + if {[is_Windows] && [lsearch -exact $args -script] >= 0} {
110 + set suffix {}
111 + } else {
112 + set suffix $_search_exe
113 + }
114 +
115 + foreach p $_search_path {
116 + set p [file join $p $what$suffix]
117 + if {[file exists $p]} {
118 + return [file normalize $p]
119 + }
120 + }
121 + return {}
122 +}
123 +
124 ######################################################################
125 ##
126 ## locate our library
@@ -194,7 +240,6 @@ set _isbare {}
240 set _gitexec {}
241 set _githtmldir {}
242 set _reponame {}
197 -set _search_path {}
243 set _shellpath {@@SHELL_PATH@@}
244
245 set _trace [lsearch -exact $argv --trace]
@@ -444,47 +489,6 @@ proc _git_cmd {name} {
489 return $v
490 }
491
447 -proc _which {what args} {
448 - global env _search_exe _search_path
449 -
450 - if {$_search_path eq {}} {
451 - if {[is_Cygwin] && [regexp {^(/|\.:)} $env(PATH)]} {
452 - set _search_path [split [exec cygpath \
453 - --windows \
454 - --path \
455 - --absolute \
456 - $env(PATH)] {;}]
457 - set _search_exe .exe
458 - } elseif {[is_Windows]} {
459 - set gitguidir [file dirname [info script]]
460 - regsub -all ";" $gitguidir "\\;" gitguidir
461 - set env(PATH) "$gitguidir;$env(PATH)"
462 - set _search_path [split $env(PATH) {;}]
463 - # Skip empty `PATH` elements
464 - set _search_path [lsearch -all -inline -not -exact \
465 - $_search_path ""]
466 - set _search_exe .exe
467 - } else {
468 - set _search_path [split $env(PATH) :]
469 - set _search_exe {}
470 - }
471 - }
472 -
473 - if {[is_Windows] && [lsearch -exact $args -script] >= 0} {
474 - set suffix {}
475 - } else {
476 - set suffix $_search_exe
477 - }
478 -
479 - foreach p $_search_path {
480 - set p [file join $p $what$suffix]
481 - if {[file exists $p]} {
482 - return [file normalize $p]
483 - }
484 - }
485 - return {}
486 -}
487 -
492 # Test a file for a hashbang to identify executable scripts on Windows.
493 proc is_shellscript {filename} {
494 if {![file exists $filename]} {return 0}