gitk: treat file names beginning with "|" as relative paths

The Tcl 'open' function has a vary 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 "|", an process is spawned. We have a number of calls of Tcl 'open' that take a file name from the environment in which Gitk is running. Be prepared that insane values are injected. In particular, when we intend to open a file, do not mistake a file name that happens to begin with "|" as a request to run a process. Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Taylor Blau <me@ttaylorr.com>

Johannes Sixt committed Mar 17, 2025 at 20:36 UTC b966b738e1923badc788b9111cc81653b50ff164
1 file changed +18 -5
gitk
+18 -5
@@ -9,6 +9,19 @@ exec wish "$0" -- "$@"
9
10 package require Tk
11
12 +
13 +# Wrap open to sanitize arguments
14 +
15 +proc safe_open_file {filename flags} {
16 + # a file name starting with "|" would attempt to run a process
17 + # but such a file name must be treated as a relative path
18 + # hide the "|" behind "./"
19 + if {[string index $filename 0] eq "|"} {
20 + set filename [file join . $filename]
21 + }
22 + open $filename $flags
23 +}
24 +
25 proc hasworktree {} {
26 return [expr {[exec git rev-parse --is-bare-repository] == "false" &&
27 [exec git rev-parse --is-inside-git-dir] == "false"}]
@@ -2874,7 +2887,7 @@ proc savestuff {w} {
2887 set remove_tmp 0
2888 if {[catch {
2889 set try_count 0
2877 - while {[catch {set f [open $config_file_tmp {WRONLY CREAT EXCL}]}]} {
2890 + while {[catch {set f [safe_open_file $config_file_tmp {WRONLY CREAT EXCL}]}]} {
2891 if {[incr try_count] > 50} {
2892 error "Unable to write config file: $config_file_tmp exists"
2893 }
@@ -3869,7 +3882,7 @@ proc show_line_source {} {
3882 # must be a merge in progress...
3883 if {[catch {
3884 # get the last line from .git/MERGE_HEAD
3872 - set f [open [file join $gitdir MERGE_HEAD] r]
3885 + set f [safe_open_file [file join $gitdir MERGE_HEAD] r]
3886 set id [lindex [split [read $f] "\n"] end-1]
3887 close $f
3888 } err]} {
@@ -7723,7 +7736,7 @@ proc showfile {f} {
7736 return
7737 }
7738 if {$diffids eq $nullid} {
7726 - if {[catch {set bf [open $f r]} err]} {
7739 + if {[catch {set bf [safe_open_file $f r]} err]} {
7740 puts "oops, can't read $f: $err"
7741 return
7742 }
@@ -10200,7 +10213,7 @@ proc getallcommits {} {
10213 set cachedarcs 0
10214 set allccache [file join $gitdir "gitk.cache"]
10215 if {![catch {
10203 - set f [open $allccache r]
10216 + set f [safe_open_file $allccache r]
10217 set allcwait 1
10218 getcache $f
10219 }]} return
@@ -10624,7 +10637,7 @@ proc savecache {} {
10637 set cachearc 0
10638 set cachedarcs $nextarc
10639 catch {
10627 - set f [open $allccache w]
10640 + set f [safe_open_file $allccache w]
10641 puts $f [list 1 $cachedarcs]
10642 run writecache $f
10643 }