Skip to content

Commit c2e8904

Browse files
j6tttaylorr
authored andcommitted
git-gui: treat file names beginning with "|" as relative paths
The Tcl 'open' function has a very wide interface. It can open files as well as pipes to external processes. The difference is made only by the first character of the file name: if it is "|", a process is spawned. We have a number of calls of Tcl 'open' that take a file name from the environment in which Git GUI is running. Be prepared that insane values are injected. In particular, when we intend to open a file, do not take a file name that happens to begin with "|" as a request to run a process. Signed-off-by: Johannes Sixt <[email protected]> Signed-off-by: Taylor Blau <[email protected]>
1 parent 8255167 commit c2e8904

File tree

11 files changed

+44
-32
lines changed

11 files changed

+44
-32
lines changed

git-gui.sh

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,18 @@ proc open {args} {
170170
uplevel 1 real_open $args
171171
}
172172
173+
# Wrap open to sanitize arguments
174+
175+
proc safe_open_file {filename flags} {
176+
# a file name starting with "|" would attempt to run a process
177+
# but such a file name must be treated as a relative path
178+
# hide the "|" behind "./"
179+
if {[string index $filename 0] eq "|"} {
180+
set filename [file join . $filename]
181+
}
182+
open $filename $flags
183+
}
184+
173185
######################################################################
174186
##
175187
## locate our library
@@ -494,7 +506,7 @@ proc _git_cmd {name} {
494506
# Tcl on Windows doesn't know it.
495507
#
496508
set p [gitexec git-$name]
497-
set f [open $p r]
509+
set f [safe_open_file $p r]
498510
set s [gets $f]
499511
close $f
500512

@@ -527,7 +539,7 @@ proc _git_cmd {name} {
527539
# Test a file for a hashbang to identify executable scripts on Windows.
528540
proc is_shellscript {filename} {
529541
if {![file exists $filename]} {return 0}
530-
set f [open $filename r]
542+
set f [safe_open_file $filename r]
531543
fconfigure $f -encoding binary
532544
set magic [read $f 2]
533545
close $f
@@ -683,7 +695,7 @@ proc sq {value} {
683695
proc load_current_branch {} {
684696
global current_branch is_detached
685697

686-
set fd [open [gitdir HEAD] r]
698+
set fd [safe_open_file [gitdir HEAD] r]
687699
fconfigure $fd -translation binary -encoding utf-8
688700
if {[gets $fd ref] < 1} {
689701
set ref {}
@@ -1045,7 +1057,7 @@ You are using [git-version]:
10451057
## configure our library
10461058

10471059
set idx [file join $oguilib tclIndex]
1048-
if {[catch {set fd [open $idx r]} err]} {
1060+
if {[catch {set fd [safe_open_file $idx r]} err]} {
10491061
catch {wm withdraw .}
10501062
tk_messageBox \
10511063
-icon error \
@@ -1382,7 +1394,7 @@ proc repository_state {ctvar hdvar mhvar} {
13821394
set merge_head [gitdir MERGE_HEAD]
13831395
if {[file exists $merge_head]} {
13841396
set ct merge
1385-
set fd_mh [open $merge_head r]
1397+
set fd_mh [safe_open_file $merge_head r]
13861398
while {[gets $fd_mh line] >= 0} {
13871399
lappend mh $line
13881400
}
@@ -1530,7 +1542,7 @@ proc load_message {file {encoding {}}} {
15301542

15311543
set f [gitdir $file]
15321544
if {[file isfile $f]} {
1533-
if {[catch {set fd [open $f r]}]} {
1545+
if {[catch {set fd [safe_open_file $f r]}]} {
15341546
return 0
15351547
}
15361548
fconfigure $fd -eofchar {}
@@ -1554,23 +1566,23 @@ proc run_prepare_commit_msg_hook {} {
15541566
# it will be .git/MERGE_MSG (merge), .git/SQUASH_MSG (squash), or an
15551567
# empty file but existent file.
15561568

1557-
set fd_pcm [open [gitdir PREPARE_COMMIT_MSG] a]
1569+
set fd_pcm [safe_open_file [gitdir PREPARE_COMMIT_MSG] a]
15581570

15591571
if {[file isfile [gitdir MERGE_MSG]]} {
15601572
set pcm_source "merge"
1561-
set fd_mm [open [gitdir MERGE_MSG] r]
1573+
set fd_mm [safe_open_file [gitdir MERGE_MSG] r]
15621574
fconfigure $fd_mm -encoding utf-8
15631575
puts -nonewline $fd_pcm [read $fd_mm]
15641576
close $fd_mm
15651577
} elseif {[file isfile [gitdir SQUASH_MSG]]} {
15661578
set pcm_source "squash"
1567-
set fd_sm [open [gitdir SQUASH_MSG] r]
1579+
set fd_sm [safe_open_file [gitdir SQUASH_MSG] r]
15681580
fconfigure $fd_sm -encoding utf-8
15691581
puts -nonewline $fd_pcm [read $fd_sm]
15701582
close $fd_sm
15711583
} elseif {[file isfile [get_config commit.template]]} {
15721584
set pcm_source "template"
1573-
set fd_sm [open [get_config commit.template] r]
1585+
set fd_sm [safe_open_file [get_config commit.template] r]
15741586
fconfigure $fd_sm -encoding utf-8
15751587
puts -nonewline $fd_pcm [read $fd_sm]
15761588
close $fd_sm
@@ -2271,7 +2283,7 @@ proc do_quit {{rc {1}}} {
22712283
if {![string match amend* $commit_type]
22722284
&& $msg ne {}} {
22732285
catch {
2274-
set fd [open $save w]
2286+
set fd [safe_open_file $save w]
22752287
fconfigure $fd -encoding utf-8
22762288
puts -nonewline $fd $msg
22772289
close $fd
@@ -4032,7 +4044,7 @@ if {[winfo exists $ui_comm]} {
40324044
}
40334045
} elseif {$m} {
40344046
catch {
4035-
set fd [open [gitdir GITGUI_BCK] w]
4047+
set fd [safe_open_file [gitdir GITGUI_BCK] w]
40364048
fconfigure $fd -encoding utf-8
40374049
puts -nonewline $fd $msg
40384050
close $fd

lib/blame.tcl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ method _load {jump} {
481481
if {$do_textconv ne 0} {
482482
set fd [open_cmd_pipe $textconv $path]
483483
} else {
484-
set fd [open $path r]
484+
set fd [safe_open_file $path r]
485485
}
486486
fconfigure $fd -eofchar {}
487487
} else {

lib/choose_repository.tcl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -641,8 +641,8 @@ method _do_clone2 {} {
641641
set pwd [pwd]
642642
if {[catch {
643643
file mkdir [gitdir objects info]
644-
set f_in [open [file join $objdir info alternates] r]
645-
set f_cp [open [gitdir objects info alternates] w]
644+
set f_in [safe_open_file [file join $objdir info alternates] r]
645+
set f_cp [safe_open_file [gitdir objects info alternates] w]
646646
fconfigure $f_in -translation binary -encoding binary
647647
fconfigure $f_cp -translation binary -encoding binary
648648
cd $objdir
@@ -727,7 +727,7 @@ method _do_clone2 {} {
727727
[cb _do_clone_tags]
728728
}
729729
shared {
730-
set fd [open [gitdir objects info alternates] w]
730+
set fd [safe_open_file [gitdir objects info alternates] w]
731731
fconfigure $fd -translation binary
732732
puts $fd $objdir
733733
close $fd
@@ -760,8 +760,8 @@ method _copy_files {objdir tocopy} {
760760
}
761761
foreach p $tocopy {
762762
if {[catch {
763-
set f_in [open [file join $objdir $p] r]
764-
set f_cp [open [file join .git objects $p] w]
763+
set f_in [safe_open_file [file join $objdir $p] r]
764+
set f_cp [safe_open_file [file join .git objects $p] w]
765765
fconfigure $f_in -translation binary -encoding binary
766766
fconfigure $f_cp -translation binary -encoding binary
767767

@@ -823,7 +823,7 @@ method _clone_refs {} {
823823
{--format=list %(refname) %(objectname) %(*objectname)}]
824824
cd $pwd
825825

826-
set fd [open [gitdir packed-refs] w]
826+
set fd [safe_open_file [gitdir packed-refs] w]
827827
fconfigure $fd -translation binary
828828
puts $fd "# pack-refs with: peeled"
829829
while {[gets $fd_in line] >= 0} {
@@ -877,7 +877,7 @@ method _do_clone_full_end {ok} {
877877

878878
set HEAD {}
879879
if {[file exists [gitdir FETCH_HEAD]]} {
880-
set fd [open [gitdir FETCH_HEAD] r]
880+
set fd [safe_open_file [gitdir FETCH_HEAD] r]
881881
while {[gets $fd line] >= 0} {
882882
if {[regexp "^(.{40})\t\t" $line line HEAD]} {
883883
break

lib/choose_rev.tcl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ method _reflog_last {name} {
579579

580580
set last {}
581581
if {[catch {set last [file mtime [gitdir $name]]}]
582-
&& ![catch {set g [open [gitdir logs $name] r]}]} {
582+
&& ![catch {set g [safe_open_file [gitdir logs $name] r]}]} {
583583
fconfigure $g -translation binary
584584
while {[gets $g line] >= 0} {
585585
if {[regexp {> ([1-9][0-9]*) } $line line when]} {

lib/commit.tcl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ A good commit message has the following format:
225225
# -- Build the message file.
226226
#
227227
set msg_p [gitdir GITGUI_EDITMSG]
228-
set msg_wt [open $msg_p w]
228+
set msg_wt [safe_open_file $msg_p w]
229229
fconfigure $msg_wt -translation lf
230230
setup_commit_encoding $msg_wt
231231
puts $msg_wt $msg
@@ -409,7 +409,7 @@ A rescan will be automatically started now.
409409
if {$commit_type ne {normal}} {
410410
append reflogm " ($commit_type)"
411411
}
412-
set msg_fd [open $msg_p r]
412+
set msg_fd [safe_open_file $msg_p r]
413413
setup_commit_encoding $msg_fd 1
414414
gets $msg_fd subject
415415
close $msg_fd

lib/diff.tcl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ proc show_other_diff {path w m cont_info} {
202202
set sz [string length $content]
203203
}
204204
file {
205-
set fd [open $path r]
205+
set fd [safe_open_file $path r]
206206
fconfigure $fd \
207207
-eofchar {} \
208208
-encoding [get_path_encoding $path]

lib/merge.tcl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ method _start {} {
9393
set spec [$w_rev get_tracking_branch]
9494
set cmit [$w_rev get_commit]
9595

96-
set fh [open [gitdir FETCH_HEAD] w]
96+
set fh [safe_open_file [gitdir FETCH_HEAD] w]
9797
fconfigure $fh -translation lf
9898
if {$spec eq {}} {
9999
set remote .

lib/mergetool.tcl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ proc merge_tool_get_stages {target stages} {
293293
foreach fname $stages {
294294
if {$merge_stages($i) eq {}} {
295295
file delete $fname
296-
catch { close [open $fname w] }
296+
catch { close [safe_open_file $fname w] }
297297
} else {
298298
# A hack to support autocrlf properly
299299
git checkout-index -f --stage=$i -- $target

lib/remote.tcl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ proc load_all_remotes {} {
7575

7676
foreach name $all_remotes {
7777
catch {
78-
set fd [open [file join $rm_dir $name] r]
78+
set fd [safe_open_file [file join $rm_dir $name] r]
7979
while {[gets $fd line] >= 0} {
8080
if {[regexp {^URL:[ ]*(.+)$} $line line url]} {
8181
set remote_url($name) $url
@@ -145,7 +145,7 @@ proc add_fetch_entry {r} {
145145
}
146146
} else {
147147
catch {
148-
set fd [open [gitdir remotes $r] r]
148+
set fd [safe_open_file [gitdir remotes $r] r]
149149
while {[gets $fd n] >= 0} {
150150
if {[regexp {^Pull:[ \t]*([^:]+):} $n]} {
151151
set enable 1
@@ -182,7 +182,7 @@ proc add_push_entry {r} {
182182
}
183183
} else {
184184
catch {
185-
set fd [open [gitdir remotes $r] r]
185+
set fd [safe_open_file [gitdir remotes $r] r]
186186
while {[gets $fd n] >= 0} {
187187
if {[regexp {^Push:[ \t]*([^:]+):} $n]} {
188188
set enable 1

lib/shortcut.tcl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ proc do_macosx_app {} {
8383

8484
file mkdir $MacOS
8585

86-
set fd [open [file join $Contents Info.plist] w]
86+
set fd [safe_open_file [file join $Contents Info.plist] w]
8787
puts $fd {<?xml version="1.0" encoding="UTF-8"?>
8888
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
8989
<plist version="1.0">
@@ -108,7 +108,7 @@ proc do_macosx_app {} {
108108
</plist>}
109109
close $fd
110110

111-
set fd [open $exe w]
111+
set fd [safe_open_file $exe w]
112112
puts $fd "#!/bin/sh"
113113
foreach name [lsort [array names env]] {
114114
set value $env($name)

0 commit comments

Comments
 (0)