Version in base suite: 2.39.5-0+deb12u2 Base version: git_2.39.5-0+deb12u2 Target version: git_2.39.5-0+deb12u3 Base file: /srv/ftp-master.debian.org/ftp/pool/main/g/git/git_2.39.5-0+deb12u2.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/g/git/git_2.39.5-0+deb12u3.dsc changelog | 11 gbp.conf | 10 patches/CVE-2025-27613.patch | 697 ++++++++++++++++++++++++++ patches/CVE-2025-46835.patch | 1123 +++++++++++++++++++++++++++++++++++++++++++ patches/CVE-2025-48384.patch | 69 ++ patches/CVE-2025-48385.patch | 62 ++ patches/series | 4 7 files changed, 1976 insertions(+) Unrecognised file line in .dsc: -----BEGIN PGP SIGNATURE----- gpgv: Signature made Tue Oct 7 12:37:29 2025 UTC gpgv: using RSA key D847C62510A9C2FF242CE02CD604A1C4823EE0F8 gpgv: Note: signatures using the SHA1 algorithm are rejected gpgv: WARNING: signing subkey D604A1C4823EE0F8 has an invalid cross-certification gpgv: Can't check signature: General error dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpft82yuw4/git_2.39.5-0+deb12u3.dsc: no acceptable signature found diff -Nru git-2.39.5/debian/changelog git-2.39.5/debian/changelog --- git-2.39.5/debian/changelog 2025-01-11 19:46:03.000000000 +0000 +++ git-2.39.5/debian/changelog 2025-10-07 12:22:08.000000000 +0000 @@ -1,3 +1,14 @@ +git (1:2.39.5-0+deb12u3) bookworm; urgency=medium + + * Non-maintainer upload by the LTS Security Team. + * Add debian/gbp.conf + * Fix CVE-2025-27613 + * Fix CVE-2025-46835 + * Fix CVE-2025-48384 + * Fix CVE-2025-48385 + + -- Lee Garrett Tue, 07 Oct 2025 14:22:08 +0200 + git (1:2.39.5-0+deb12u2) bookworm-security; urgency=high * Non-maintainer upload by the Security Team. diff -Nru git-2.39.5/debian/gbp.conf git-2.39.5/debian/gbp.conf --- git-2.39.5/debian/gbp.conf 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/debian/gbp.conf 2025-10-07 11:44:37.000000000 +0000 @@ -0,0 +1,10 @@ +# Configuration for git-buildpackage and affiliated tools + +[DEFAULT] +debian-branch = debian/bookworm +pristine-tar = True +sign-tags = True +upstream-branch = upstream/bookworm + +[import-orig] +merge-mode = replace diff -Nru git-2.39.5/debian/patches/CVE-2025-27613.patch git-2.39.5/debian/patches/CVE-2025-27613.patch --- git-2.39.5/debian/patches/CVE-2025-27613.patch 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/debian/patches/CVE-2025-27613.patch 2025-10-07 11:44:37.000000000 +0000 @@ -0,0 +1,697 @@ +--- a/gitk-git/gitk ++++ b/gitk-git/gitk +@@ -9,6 +9,92 @@ + + package require Tk + ++ ++# Wrap exec/open to sanitize arguments ++ ++# unsafe arguments begin with redirections or the pipe or background operators ++proc is_arg_unsafe {arg} { ++ regexp {^([<|>&]|2>)} $arg ++} ++ ++proc make_arg_safe {arg} { ++ if {[is_arg_unsafe $arg]} { ++ set arg [file join . $arg] ++ } ++ return $arg ++} ++ ++proc make_arglist_safe {arglist} { ++ set res {} ++ foreach arg $arglist { ++ lappend res [make_arg_safe $arg] ++ } ++ return $res ++} ++ ++# executes one command ++# no redirections or pipelines are possible ++# cmd is a list that specifies the command and its arguments ++# calls `exec` and returns its value ++proc safe_exec {cmd} { ++ eval exec [make_arglist_safe $cmd] ++} ++ ++# executes one command with redirections ++# no pipelines are possible ++# cmd is a list that specifies the command and its arguments ++# redir is a list that specifies redirections (output, background, constant(!) commands) ++# calls `exec` and returns its value ++proc safe_exec_redirect {cmd redir} { ++ eval exec [make_arglist_safe $cmd] $redir ++} ++ ++proc safe_open_file {filename flags} { ++ # a file name starting with "|" would attempt to run a process ++ # but such a file name must be treated as a relative path ++ # hide the "|" behind "./" ++ if {[string index $filename 0] eq "|"} { ++ set filename [file join . $filename] ++ } ++ open $filename $flags ++} ++ ++# opens a command pipeline for reading ++# cmd is a list that specifies the command and its arguments ++# calls `open` and returns the file id ++proc safe_open_command {cmd} { ++ open |[make_arglist_safe $cmd] r ++} ++ ++# opens a command pipeline for reading and writing ++# cmd is a list that specifies the command and its arguments ++# calls `open` and returns the file id ++proc safe_open_command_rw {cmd} { ++ open |[make_arglist_safe $cmd] r+ ++} ++ ++# opens a command pipeline for reading with redirections ++# cmd is a list that specifies the command and its arguments ++# redir is a list that specifies redirections ++# calls `open` and returns the file id ++proc safe_open_command_redirect {cmd redir} { ++ set cmd [make_arglist_safe $cmd] ++ open |[concat $cmd $redir] r ++} ++ ++# opens a pipeline with several commands for reading ++# cmds is a list of lists, each of which specifies a command and its arguments ++# calls `open` and returns the file id ++proc safe_open_pipeline {cmds} { ++ set cmd {} ++ foreach subcmd $cmds { ++ set cmd [concat $cmd | [make_arglist_safe $subcmd]] ++ } ++ open $cmd r ++} ++ ++# End exec/open wrappers ++ + proc hasworktree {} { + return [expr {[exec git rev-parse --is-bare-repository] == "false" && + [exec git rev-parse --is-inside-git-dir] == "false"}] +@@ -134,7 +220,7 @@ + set mlist {} + set nr_unmerged 0 + if {[catch { +- set fd [open "| git ls-files -u" r] ++ set fd [safe_open_command {git ls-files -u}] + } err]} { + show_error {} . "[mc "Couldn't get list of unmerged files:"] $err" + exit 1 +@@ -296,7 +382,7 @@ + } elseif {[lsearch -exact $revs --all] >= 0} { + lappend revs HEAD + } +- if {[catch {set ids [eval exec git rev-parse $revs]} err]} { ++ if {[catch {set ids [safe_exec [concat git rev-parse $revs]]} err]} { + # we get stdout followed by stderr in $err + # for an unknown rev, git rev-parse echoes it and then errors out + set errlines [split $err "\n"] +@@ -374,7 +460,7 @@ + set args $viewargs($view) + if {$viewargscmd($view) ne {}} { + if {[catch { +- set str [exec sh -c $viewargscmd($view)] ++ set str [safe_exec [list sh -c $viewargscmd($view)]] + } err]} { + error_popup "[mc "Error executing --argscmd command:"] $err" + return 0 +@@ -411,8 +497,9 @@ + } + + if {[catch { +- set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \ +- --parents --boundary $args "--" $files] r] ++ set fd [safe_open_command_redirect [concat git log --no-color -z --pretty=raw $show_notes \ ++ --parents --boundary $args --stdin] \ ++ [list "<<[join [concat $revs "--" $vfilelimit($view)] "\n"]"]] + } err]} { + error_popup "[mc "Error executing git log:"] $err" + return 0 +@@ -446,9 +533,9 @@ + set pid [pid $fd] + + if {$::tcl_platform(platform) eq {windows}} { +- exec taskkill /pid $pid ++ safe_exec [list taskkill /pid $pid] + } else { +- exec kill $pid ++ safe_exec [list kill $pid] + } + } + catch {close $fd} +@@ -1527,8 +1614,8 @@ + # and if we already know about it, using the rewritten + # parent as a substitute parent for $id's children. + if {![catch { +- set rwid [exec git rev-list --first-parent --max-count=1 \ +- $id -- $vfilelimit($view)] ++ set rwid [safe_exec [list git rev-list --first-parent --max-count=1 \ ++ $id -- $vfilelimit($view)]] + }]} { + if {$rwid ne {} && [info exists varcid($view,$rwid)]} { + # use $rwid in place of $id +@@ -1648,7 +1735,7 @@ + global tclencoding + + # Invoke git-log to handle automatic encoding conversion +- set fd [open [concat | git log --no-color --pretty=raw -1 $id] r] ++ set fd [safe_open_command [concat git log --no-color --pretty=raw -1 $id]] + # Read the results using i18n.logoutputencoding + fconfigure $fd -translation lf -eofchar {} + if {$tclencoding != {}} { +@@ -1784,7 +1871,7 @@ + foreach v {tagids idtags headids idheads otherrefids idotherrefs} { + unset -nocomplain $v + } +- set refd [open [list | git show-ref -d] r] ++ set refd [safe_open_command [list git show-ref -d]] + if {$tclencoding != {}} { + fconfigure $refd -encoding $tclencoding + } +@@ -1832,7 +1919,7 @@ + set selectheadid {} + if {$selecthead ne {}} { + catch { +- set selectheadid [exec git rev-parse --verify $selecthead] ++ set selectheadid [safe_exec [list git rev-parse --verify $selecthead]] + } + } + } +@@ -2092,7 +2179,7 @@ + {mc "Reread re&ferences" command rereadrefs} + {mc "&List references" command showrefs -accelerator F2} + {xx "" separator} +- {mc "Start git &gui" command {exec git gui &}} ++ {mc "Start git &gui" command {safe_exec_redirect [list git gui] [list &]}} + {xx "" separator} + {mc "&Quit" command doquit -accelerator Meta1-Q} + }} +@@ -2874,7 +2961,7 @@ + set remove_tmp 0 + if {[catch { + set try_count 0 +- while {[catch {set f [open $config_file_tmp {WRONLY CREAT EXCL}]}]} { ++ while {[catch {set f [safe_open_file $config_file_tmp {WRONLY CREAT EXCL}]}]} { + if {[incr try_count] > 50} { + error "Unable to write config file: $config_file_tmp exists" + } +@@ -3590,7 +3677,7 @@ + set tmpdir $gitdir + } + set gitktmpformat [file join $tmpdir ".gitk-tmp.XXXXXX"] +- if {[catch {set gitktmpdir [exec mktemp -d $gitktmpformat]}]} { ++ if {[catch {set gitktmpdir [safe_exec [list mktemp -d $gitktmpformat]]}]} { + set gitktmpdir [file join $gitdir [format ".gitk-tmp.%s" [pid]]] + } + if {[catch {file mkdir $gitktmpdir} err]} { +@@ -3612,7 +3699,7 @@ + proc save_file_from_commit {filename output what} { + global nullfile + +- if {[catch {exec git show $filename -- > $output} err]} { ++ if {[catch {safe_exec_redirect [list git show $filename --] [list > $output]} err]} { + if {[string match "fatal: bad revision *" $err]} { + return $nullfile + } +@@ -3677,7 +3764,7 @@ + + if {$difffromfile ne {} && $difftofile ne {}} { + set cmd [list [shellsplit $extdifftool] $difffromfile $difftofile] +- if {[catch {set fl [open |$cmd r]} err]} { ++ if {[catch {set fl [safe_open_command $cmd]} err]} { + file delete -force $diffdir + error_popup "$extdifftool: [mc "command failed:"] $err" + } else { +@@ -3781,7 +3868,7 @@ + # Find the SHA1 ID of the blob for file $fname in the index + # at stage 0 or 2 + proc index_sha1 {fname} { +- set f [open [list | git ls-files -s $fname] r] ++ set f [safe_open_command [list git ls-files -s $fname]] + while {[gets $f line] >= 0} { + set info [lindex [split $line "\t"] 0] + set stage [lindex $info 2] +@@ -3841,7 +3928,7 @@ + # being given an absolute path... + set f [make_relative $f] + lappend cmdline $base_commit $f +- if {[catch {eval exec $cmdline &} err]} { ++ if {[catch {safe_exec_redirect $cmdline [list &]} err]} { + error_popup "[mc "git gui blame: command failed:"] $err" + } + } +@@ -3869,7 +3956,7 @@ + # must be a merge in progress... + if {[catch { + # get the last line from .git/MERGE_HEAD +- set f [open [file join $gitdir MERGE_HEAD] r] ++ set f [safe_open_file [file join $gitdir MERGE_HEAD] r] + set id [lindex [split [read $f] "\n"] end-1] + close $f + } err]} { +@@ -3892,19 +3979,17 @@ + } + set line [lindex $h 1] + } +- set blameargs {} ++ set blamefile [file join $cdup $flist_menu_file] + if {$from_index ne {}} { +- lappend blameargs | git cat-file blob $from_index +- } +- lappend blameargs | git blame -p -L$line,+1 +- if {$from_index ne {}} { +- lappend blameargs --contents - ++ set blameargs [list \ ++ [list git cat-file blob $from_index] \ ++ [list git blame -p -L$line,+1 --contents - -- $blamefile]] + } else { +- lappend blameargs $id ++ set blameargs [list \ ++ [list git blame -p -L$line,+1 $id -- $blamefile]] + } +- lappend blameargs -- [file join $cdup $flist_menu_file] + if {[catch { +- set f [open $blameargs r] ++ set f [safe_open_pipeline $blameargs] + } err]} { + error_popup [mc "Couldn't start git blame: %s" $err] + return +@@ -4829,8 +4914,8 @@ + # must be "containing:", i.e. we're searching commit info + return + } +- set cmd [concat | git diff-tree -r -s --stdin $gdtargs] +- set filehighlight [open $cmd r+] ++ set cmd [concat git diff-tree -r -s --stdin $gdtargs] ++ set filehighlight [safe_open_command_rw $cmd] + fconfigure $filehighlight -blocking 0 + filerun $filehighlight readfhighlight + set fhl_list {} +@@ -5259,8 +5344,8 @@ + global viewmainheadid vfilelimit viewinstances mainheadid + + catch { +- set rfd [open [concat | git rev-list -1 $mainheadid \ +- -- $vfilelimit($view)] r] ++ set rfd [safe_open_command [concat git rev-list -1 $mainheadid \ ++ -- $vfilelimit($view)]] + set j [reg_instance $rfd] + lappend viewinstances($view) $j + fconfigure $rfd -blocking 0 +@@ -5325,14 +5410,14 @@ + if {!$showlocalchanges || !$hasworktree} return + incr lserial + if {[package vcompare $git_version "1.7.2"] >= 0} { +- set cmd "|git diff-index --cached --ignore-submodules=dirty HEAD" ++ set cmd "git diff-index --cached --ignore-submodules=dirty HEAD" + } else { +- set cmd "|git diff-index --cached HEAD" ++ set cmd "git diff-index --cached HEAD" + } + if {$vfilelimit($curview) ne {}} { + set cmd [concat $cmd -- $vfilelimit($curview)] + } +- set fd [open $cmd r] ++ set fd [safe_open_command $cmd] + fconfigure $fd -blocking 0 + set i [reg_instance $fd] + filerun $fd [list readdiffindex $fd $lserial $i] +@@ -5357,11 +5442,11 @@ + } + + # now see if there are any local changes not checked in to the index +- set cmd "|git diff-files" ++ set cmd "git diff-files" + if {$vfilelimit($curview) ne {}} { + set cmd [concat $cmd -- $vfilelimit($curview)] + } +- set fd [open $cmd r] ++ set fd [safe_open_command $cmd] + fconfigure $fd -blocking 0 + set i [reg_instance $fd] + filerun $fd [list readdifffiles $fd $serial $i] +@@ -7150,8 +7235,8 @@ + global web_browser + + if {$web_browser eq {}} return +- # Use eval here in case $web_browser is a command plus some arguments +- if {[catch {eval exec $web_browser [list $url] &} err]} { ++ # Use concat here in case $web_browser is a command plus some arguments ++ if {[catch {safe_exec_redirect [concat $web_browser [list $url]] [list &]} err]} { + error_popup "[mc "Error starting web browser:"] $err" + } + } +@@ -7653,13 +7738,13 @@ + if {![info exists treefilelist($id)]} { + if {![info exists treepending]} { + if {$id eq $nullid} { +- set cmd [list | git ls-files] ++ set cmd [list git ls-files] + } elseif {$id eq $nullid2} { +- set cmd [list | git ls-files --stage -t] ++ set cmd [list git ls-files --stage -t] + } else { +- set cmd [list | git ls-tree -r $id] ++ set cmd [list git ls-tree -r $id] + } +- if {[catch {set gtf [open $cmd r]}]} { ++ if {[catch {set gtf [safe_open_command $cmd]}]} { + return + } + set treepending $id +@@ -7723,13 +7808,13 @@ + return + } + if {$diffids eq $nullid} { +- if {[catch {set bf [open $f r]} err]} { ++ if {[catch {set bf [safe_open_file $f r]} err]} { + puts "oops, can't read $f: $err" + return + } + } else { + set blob [lindex $treeidlist($diffids) $i] +- if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} { ++ if {[catch {set bf [safe_open_command [concat git cat-file blob $blob]]} err]} { + puts "oops, error reading blob $blob: $err" + return + } +@@ -7879,7 +7964,7 @@ + if {$i >= 0} { + if {[llength $ids] > 1 && $j < 0} { + # comparing working directory with some specific revision +- set cmd [concat | git diff-index $flags] ++ set cmd [concat git diff-index $flags] + if {$i == 0} { + lappend cmd -R [lindex $ids 1] + } else { +@@ -7887,7 +7972,7 @@ + } + } else { + # comparing working directory with index +- set cmd [concat | git diff-files $flags] ++ set cmd [concat git diff-files $flags] + if {$j == 1} { + lappend cmd -R + } +@@ -7896,7 +7981,7 @@ + if {[package vcompare $git_version "1.7.2"] >= 0} { + set flags "$flags --ignore-submodules=dirty" + } +- set cmd [concat | git diff-index --cached $flags] ++ set cmd [concat git diff-index --cached $flags] + if {[llength $ids] > 1} { + # comparing index with specific revision + if {$j == 0} { +@@ -7912,7 +7997,7 @@ + if {$log_showroot} { + lappend flags --root + } +- set cmd [concat | git diff-tree -r $flags $ids] ++ set cmd [concat git diff-tree -r $flags $ids] + } + return $cmd + } +@@ -7924,7 +8009,7 @@ + if {$limitdiffs && $vfilelimit($curview) ne {}} { + set cmd [concat $cmd -- $vfilelimit($curview)] + } +- if {[catch {set gdtf [open $cmd r]}]} return ++ if {[catch {set gdtf [safe_open_command $cmd]}]} return + + set treepending $ids + set treediff {} +@@ -8044,7 +8129,7 @@ + if {$limitdiffs && $vfilelimit($curview) ne {}} { + set cmd [concat $cmd -- $vfilelimit($curview)] + } +- if {[catch {set bdf [open $cmd r]} err]} { ++ if {[catch {set bdf [safe_open_command $cmd]} err]} { + error_popup [mc "Error getting diffs: %s" $err] + return + } +@@ -8761,7 +8846,7 @@ + set id [lindex $matches 0] + } + } else { +- if {[catch {set id [exec git rev-parse --verify $sha1string]}]} { ++ if {[catch {set id [safe_exec [list git rev-parse --verify $sha1string]]}]} { + error_popup [mc "Revision %s is not known" $sha1string] + return + } +@@ -9067,10 +9152,8 @@ + + if {![info exists patchids($id)]} { + set cmd [diffcmd [list $id] {-p --root}] +- # trim off the initial "|" +- set cmd [lrange $cmd 1 end] + if {[catch { +- set x [eval exec $cmd | git patch-id] ++ set x [safe_exec_redirect $cmd [list | git patch-id]] + set patchids($id) [lindex $x 0] + }]} { + set patchids($id) "error" +@@ -9166,14 +9249,14 @@ + set fna [file join $tmpdir "commit-[string range $a 0 7]"] + set fnb [file join $tmpdir "commit-[string range $b 0 7]"] + if {[catch { +- exec git diff-tree -p --pretty $a >$fna +- exec git diff-tree -p --pretty $b >$fnb ++ safe_exec_redirect [list git diff-tree -p --pretty $a] [list >$fna] ++ safe_exec_redirect [list git diff-tree -p --pretty $b] [list >$fnb] + } err]} { + error_popup [mc "Error writing commit to file: %s" $err] + return + } + if {[catch { +- set fd [open "| diff -U$diffcontext $fna $fnb" r] ++ set fd [safe_open_command "diff -U$diffcontext $fna $fnb"] + } err]} { + error_popup [mc "Error diffing commits: %s" $err] + return +@@ -9313,10 +9396,7 @@ + set newid [$patchtop.tosha1 get] + set fname [$patchtop.fname get] + set cmd [diffcmd [list $oldid $newid] -p] +- # trim off the initial "|" +- set cmd [lrange $cmd 1 end] +- lappend cmd >$fname & +- if {[catch {eval exec $cmd} err]} { ++ if {[catch {safe_exec_redirect $cmd [list >$fname &]} err]} { + error_popup "[mc "Error creating patch:"] $err" $patchtop + } + catch {destroy $patchtop} +@@ -9385,9 +9465,9 @@ + } + if {[catch { + if {$msg != {}} { +- exec git tag -a -m $msg $tag $id ++ safe_exec [list git tag -a -m $msg $tag $id] + } else { +- exec git tag $tag $id ++ safe_exec [list git tag $tag $id] + } + } err]} { + error_popup "[mc "Error creating tag:"] $err" $mktagtop +@@ -9455,7 +9535,7 @@ + if {$autosellen < 40} { + lappend cmd --abbrev=$autosellen + } +- set reference [eval exec $cmd $rowmenuid] ++ set reference [safe_exec [concat $cmd $rowmenuid]] + + clipboard clear + clipboard append $reference +@@ -9505,7 +9585,7 @@ + set id [$wrcomtop.sha1 get] + set cmd "echo $id | [$wrcomtop.cmd get]" + set fname [$wrcomtop.fname get] +- if {[catch {exec sh -c $cmd >$fname &} err]} { ++ if {[catch {safe_exec_redirect [list sh -c $cmd] [list >$fname &]} err]} { + error_popup "[mc "Error writing commit:"] $err" $wrcomtop + } + catch {destroy $wrcomtop} +@@ -9609,7 +9689,7 @@ + nowbusy newbranch + update + if {[catch { +- eval exec git branch $cmdargs ++ safe_exec [concat git branch $cmdargs] + } err]} { + notbusy newbranch + error_popup $err +@@ -9650,7 +9730,7 @@ + nowbusy renamebranch + update + if {[catch { +- eval exec git branch $cmdargs ++ safe_exec [concat git branch $cmdargs] + } err]} { + notbusy renamebranch + error_popup $err +@@ -9691,7 +9771,7 @@ + } + } + +- eval exec git citool $tool_args & ++ safe_exec_redirect [concat git citool $tool_args] [list &] + + array unset env GIT_AUTHOR_* + array set env $save_env +@@ -9714,7 +9794,7 @@ + update + # Unfortunately git-cherry-pick writes stuff to stderr even when + # no error occurs, and exec takes that as an indication of error... +- if {[catch {exec sh -c "git cherry-pick -r $rowmenuid 2>&1"} err]} { ++ if {[catch {safe_exec [list sh -c "git cherry-pick -r $rowmenuid 2>&1"]} err]} { + notbusy cherrypick + if {[regexp -line \ + {Entry '(.*)' (would be overwritten by merge|not uptodate)} \ +@@ -9776,7 +9856,7 @@ + nowbusy revert [mc "Reverting"] + update + +- if [catch {exec git revert --no-edit $rowmenuid} err] { ++ if [catch {safe_exec [list git revert --no-edit $rowmenuid]} err] { + notbusy revert + if [regexp {files would be overwritten by merge:(\n(( |\t)+[^\n]+\n)+)}\ + $err match files] { +@@ -9852,8 +9932,8 @@ + bind $w "grab $w; focus $w" + tkwait window $w + if {!$confirm_ok} return +- if {[catch {set fd [open \ +- [list | git reset --$resettype $rowmenuid 2>@1] r]} err]} { ++ if {[catch {set fd [safe_open_command_redirect \ ++ [list git reset --$resettype $rowmenuid] [list 2>@1]]} err]} { + error_popup $err + } else { + dohidelocalchanges +@@ -9924,7 +10004,7 @@ + + # check the tree is clean first?? + set newhead $headmenuhead +- set command [list | git checkout] ++ set command [list git checkout] + if {[string match "remotes/*" $newhead]} { + set remote $newhead + set newhead [string range $newhead [expr [string last / $newhead] + 1] end] +@@ -9938,12 +10018,11 @@ + } else { + lappend command $newhead + } +- lappend command 2>@1 + nowbusy checkout [mc "Checking out"] + update + dohidelocalchanges + if {[catch { +- set fd [open $command r] ++ set fd [safe_open_command_redirect $command [list 2>@1]] + } err]} { + notbusy checkout + error_popup $err +@@ -10009,7 +10088,7 @@ + } + nowbusy rmbranch + update +- if {[catch {exec git branch -D $head} err]} { ++ if {[catch {safe_exec [list git branch -D $head]} err]} { + notbusy rmbranch + error_popup $err + return +@@ -10200,7 +10279,7 @@ + set cachedarcs 0 + set allccache [file join $gitdir "gitk.cache"] + if {![catch { +- set f [open $allccache r] ++ set f [safe_open_file $allccache r] + set allcwait 1 + getcache $f + }]} return +@@ -10209,7 +10288,7 @@ + if {$allcwait} { + return + } +- set cmd [list | git rev-list --parents] ++ set cmd [list git rev-list --parents] + set allcupdate [expr {$seeds ne {}}] + if {!$allcupdate} { + set ids "--all" +@@ -10234,7 +10313,13 @@ + } + } + if {$ids ne {}} { +- set fd [open [concat $cmd $ids] r] ++ if {$ids eq "--all"} { ++ set cmd [concat $cmd "--all"] ++ set fd [safe_open_command $cmd] ++ } else { ++ set cmd [concat $cmd --stdin] ++ set fd [safe_open_command_redirect $cmd [list "<<[join $ids "\n"]"]] ++ } + fconfigure $fd -blocking 0 + incr allcommits + nowbusy allcommits +@@ -10624,7 +10709,7 @@ + set cachearc 0 + set cachedarcs $nextarc + catch { +- set f [open $allccache w] ++ set f [safe_open_file $allccache w] + puts $f [list 1 $cachedarcs] + run writecache $f + } +@@ -11327,7 +11412,7 @@ + + if {![info exists cached_tagcontent($tag)]} { + catch { +- set cached_tagcontent($tag) [exec git cat-file -p $tag] ++ set cached_tagcontent($tag) [safe_exec [list git cat-file -p $tag]] + } + } + $ctext insert end "[mc "Tag"]: $tag\n" bold +@@ -12213,7 +12298,7 @@ + set r $path_attr_cache($attr,$path) + } else { + set r "unspecified" +- if {![catch {set line [exec git check-attr $attr -- $path]}]} { ++ if {![catch {set line [safe_exec [list git check-attr $attr -- $path]]}]} { + regexp "(.*): $attr: (.*)" $line m f r + } + set path_attr_cache($attr,$path) $r +@@ -12240,7 +12325,7 @@ + while {$newlist ne {}} { + set head [lrange $newlist 0 [expr {$lim - 1}]] + set newlist [lrange $newlist $lim end] +- if {![catch {set rlist [eval exec git check-attr $attr -- $head]}]} { ++ if {![catch {set rlist [safe_exec [concat git check-attr $attr -- $head]]}]} { + foreach row [split $rlist "\n"] { + if {[regexp "(.*): $attr: (.*)" $row m path value]} { + if {[string index $path 0] eq "\""} { +@@ -12293,11 +12378,11 @@ + + # on OSX bring the current Wish process window to front + if {[tk windowingsystem] eq "aqua"} { +- exec osascript -e [format { ++ safe_exec [list osascript -e [format { + tell application "System Events" + set frontmost of processes whose unix id is %d to true + end tell +- } [pid] ] ++ } [pid] ]] + } + + # Unset GIT_TRACE var if set +@@ -12542,7 +12627,7 @@ + if {$i >= [llength $argv] && $revtreeargs ne {}} { + # no -- on command line, but some arguments (other than --argscmd) + if {[catch { +- set f [eval exec git rev-parse --no-revs --no-flags $revtreeargs] ++ set f [safe_exec [concat git rev-parse --no-revs --no-flags $revtreeargs]] + set cmdline_files [split $f "\n"] + set n [llength $cmdline_files] + set revtreeargs [lrange $revtreeargs 0 end-$n] diff -Nru git-2.39.5/debian/patches/CVE-2025-46835.patch git-2.39.5/debian/patches/CVE-2025-46835.patch --- git-2.39.5/debian/patches/CVE-2025-46835.patch 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/debian/patches/CVE-2025-46835.patch 2025-10-07 11:44:37.000000000 +0000 @@ -0,0 +1,1123 @@ +--- a/git-gui/git-gui.sh ++++ b/git-gui/git-gui.sh +@@ -152,6 +152,56 @@ + } + } + ++# Wrap exec/open to sanitize arguments ++ ++# unsafe arguments begin with redirections or the pipe or background operators ++proc is_arg_unsafe {arg} { ++ regexp {^([<|>&]|2>)} $arg ++} ++ ++proc make_arg_safe {arg} { ++ if {[is_arg_unsafe $arg]} { ++ set arg [file join . $arg] ++ } ++ return $arg ++} ++ ++proc make_arglist_safe {arglist} { ++ set res {} ++ foreach arg $arglist { ++ lappend res [make_arg_safe $arg] ++ } ++ return $res ++} ++ ++# executes one command ++# no redirections or pipelines are possible ++# cmd is a list that specifies the command and its arguments ++# calls `exec` and returns its value ++proc safe_exec {cmd} { ++ eval exec [make_arglist_safe $cmd] ++} ++ ++# executes one command in the background ++# no redirections or pipelines are possible ++# cmd is a list that specifies the command and its arguments ++# calls `exec` and returns its value ++proc safe_exec_bg {cmd} { ++ eval exec [make_arglist_safe $cmd] & ++} ++ ++proc safe_open_file {filename flags} { ++ # a file name starting with "|" would attempt to run a process ++ # but such a file name must be treated as a relative path ++ # hide the "|" behind "./" ++ if {[string index $filename 0] eq "|"} { ++ set filename [file join . $filename] ++ } ++ open $filename $flags ++} ++ ++# End exec/open wrappers ++ + ###################################################################### + ## + ## read only globals +@@ -418,7 +468,7 @@ + # Tcl on Windows doesn't know it. + # + set p [gitexec git-$name] +- set f [open $p r] ++ set f [safe_open_file $p r] + set s [gets $f] + close $f + +@@ -512,6 +562,7 @@ + } else { + set run [list [shellpath] -c "$cmd \"\$0\"" $path] + } ++ set run [make_arglist_safe $run] + return [open |$run r] + } + +@@ -521,7 +572,7 @@ + + if {![info exists _nice]} { + set _nice [_which nice] +- if {[catch {exec $_nice git version}]} { ++ if {[catch {safe_exec [list $_nice git version]}]} { + set _nice {} + } elseif {[is_Windows] && [file dirname $_nice] ne [file dirname $::_git]} { + set _nice {} +@@ -533,7 +584,11 @@ + } + + proc git {args} { +- set fd [eval [list git_read] $args] ++ git_redir $args {} ++} ++ ++proc git_redir {cmd redir} { ++ set fd [git_read $cmd $redir] + fconfigure $fd -translation binary -encoding utf-8 + set result [string trimright [read $fd] "\n"] + close $fd +@@ -543,111 +598,46 @@ + return $result + } + +-proc _open_stdout_stderr {cmd} { +- _trace_exec $cmd ++proc safe_open_command {cmd {redir {}}} { ++ set cmd [make_arglist_safe $cmd] ++ _trace_exec [concat $cmd $redir] + if {[catch { +- set fd [open [concat [list | ] $cmd] r] +- } err]} { +- if { [lindex $cmd end] eq {2>@1} +- && $err eq {can not find channel named "1"} +- } { +- # Older versions of Tcl 8.4 don't have this 2>@1 IO +- # redirect operator. Fallback to |& cat for those. +- # The command was not actually started, so its safe +- # to try to start it a second time. +- # +- set fd [open [concat \ +- [list | ] \ +- [lrange $cmd 0 end-1] \ +- [list |& cat] \ +- ] r] +- } else { +- error $err +- } ++ set fd [open [concat [list | ] $cmd $redir] r] ++ } err]} { ++ error $err + } + fconfigure $fd -eofchar {} + return $fd + } + +-proc git_read {args} { +- set opt [list] +- +- while {1} { +- switch -- [lindex $args 0] { +- --nice { +- _lappend_nice opt +- } +- +- --stderr { +- lappend args 2>@1 +- } +- +- default { +- break +- } +- +- } +- +- set args [lrange $args 1 end] +- } +- +- set cmdp [_git_cmd [lindex $args 0]] +- set args [lrange $args 1 end] +- +- return [_open_stdout_stderr [concat $opt $cmdp $args]] ++proc git_read {cmd {redir {}}} { ++ set cmdp [_git_cmd [lindex $cmd 0]] ++ set cmd [lrange $cmd 1 end] ++ return [safe_open_command [concat $cmdp $cmd] $redir] + } + +-proc git_write {args} { +- set opt [list] ++proc git_read_nice {cmd} { ++ set opt [list] + +- while {1} { +- switch -- [lindex $args 0] { +- --nice { +- _lappend_nice opt +- } ++ _lappend_nice opt + +- default { +- break +- } ++ set cmdp [_git_cmd [lindex $cmd 0]] ++ set cmd [lrange $cmd 1 end] + +- } +- +- set args [lrange $args 1 end] +- } ++ return [safe_open_command [concat $opt $cmdp $cmd]] ++} + +- set cmdp [_git_cmd [lindex $args 0]] +- set args [lrange $args 1 end] ++proc git_write {cmd} { ++ set cmd [make_arglist_safe $cmd] ++ set cmdp [_git_cmd [lindex $cmd 0]] ++ set cmd [lrange $cmd 1 end] + +- _trace_exec [concat $opt $cmdp $args] +- return [open [concat [list | ] $opt $cmdp $args] w] ++ _trace_exec [concat $cmdp $cmd] ++ return [open [concat [list | ] $cmdp $cmd] w] + } + + proc githook_read {hook_name args} { +- set pchook [gitdir hooks $hook_name] +- lappend args 2>@1 +- +- # On Windows [file executable] might lie so we need to ask +- # the shell if the hook is executable. Yes that's annoying. +- # +- if {[is_Windows]} { +- upvar #0 _sh interp +- if {![info exists interp]} { +- set interp [_which sh] +- } +- if {$interp eq {}} { +- error "hook execution requires sh (not in PATH)" +- } +- +- set scr {if test -x "$1";then exec "$@";fi} +- set sh_c [list $interp -c $scr $interp $pchook] +- return [_open_stdout_stderr [concat $sh_c $args]] +- } +- +- if {[file executable $pchook]} { +- return [_open_stdout_stderr [concat [list $pchook] $args]] +- } +- +- return {} ++ git_read [concat [list hook run --ignore-missing $hook_name --] $args] [list 2>@1] + } + + proc kill_file_process {fd} { +@@ -655,9 +645,9 @@ + + catch { + if {[is_Windows]} { +- exec taskkill /pid $process ++ safe_exec [list taskkill /pid $process] + } else { +- exec kill $process ++ safe_exec [list kill $process] + } + } + } +@@ -683,7 +673,7 @@ + proc load_current_branch {} { + global current_branch is_detached + +- set fd [open [gitdir HEAD] r] ++ set fd [safe_open_file [gitdir HEAD] r] + fconfigure $fd -translation binary -encoding utf-8 + if {[gets $fd ref] < 1} { + set ref {} +@@ -1045,7 +1035,7 @@ + ## configure our library + + set idx [file join $oguilib tclIndex] +-if {[catch {set fd [open $idx r]} err]} { ++if {[catch {set fd [safe_open_file $idx r]} err]} { + catch {wm withdraw .} + tk_messageBox \ + -icon error \ +@@ -1083,53 +1073,30 @@ + ## + ## config file parsing + +-git-version proc _parse_config {arr_name args} { +- >= 1.5.3 { +- upvar $arr_name arr +- array unset arr +- set buf {} +- catch { +- set fd_rc [eval \ +- [list git_read config] \ +- $args \ +- [list --null --list]] +- fconfigure $fd_rc -translation binary -encoding utf-8 +- set buf [read $fd_rc] +- close $fd_rc +- } +- foreach line [split $buf "\0"] { +- if {[regexp {^([^\n]+)\n(.*)$} $line line name value]} { +- if {[is_many_config $name]} { +- lappend arr($name) $value +- } else { +- set arr($name) $value +- } +- } elseif {[regexp {^([^\n]+)$} $line line name]} { +- # no value given, but interpreting them as +- # boolean will be handled as true +- set arr($name) {} +- } +- } +- } +- default { +- upvar $arr_name arr +- array unset arr +- catch { +- set fd_rc [eval [list git_read config --list] $args] +- while {[gets $fd_rc line] >= 0} { +- if {[regexp {^([^=]+)=(.*)$} $line line name value]} { +- if {[is_many_config $name]} { +- lappend arr($name) $value +- } else { +- set arr($name) $value +- } +- } elseif {[regexp {^([^=]+)$} $line line name]} { +- # no value given, but interpreting them as +- # boolean will be handled as true +- set arr($name) {} +- } ++proc _parse_config {arr_name args} { ++ upvar $arr_name arr ++ array unset arr ++ set buf {} ++ catch { ++ set fd_rc [git_read \ ++ [concat config \ ++ $args \ ++ --null --list]] ++ fconfigure $fd_rc -translation binary -encoding utf-8 ++ set buf [read $fd_rc] ++ close $fd_rc ++ } ++ foreach line [split $buf "\0"] { ++ if {[regexp {^([^\n]+)\n(.*)$} $line line name value]} { ++ if {[is_many_config $name]} { ++ lappend arr($name) $value ++ } else { ++ set arr($name) $value + } +- close $fd_rc ++ } elseif {[regexp {^([^\n]+)$} $line line name]} { ++ # no value given, but interpreting them as ++ # boolean will be handled as true ++ set arr($name) {} + } + } + } +@@ -1412,7 +1379,7 @@ + set merge_head [gitdir MERGE_HEAD] + if {[file exists $merge_head]} { + set ct merge +- set fd_mh [open $merge_head r] ++ set fd_mh [safe_open_file $merge_head r] + while {[gets $fd_mh line] >= 0} { + lappend mh $line + } +@@ -1431,7 +1398,7 @@ + return $p + } + if {$empty_tree eq {}} { +- set empty_tree [git mktree << {}] ++ set empty_tree [git_redir [list mktree] [list << {}]] + } + return $empty_tree + } +@@ -1490,12 +1457,12 @@ + } else { + set rescan_active 1 + ui_status [mc "Refreshing file status..."] +- set fd_rf [git_read update-index \ ++ set fd_rf [git_read [list update-index \ + -q \ + --unmerged \ + --ignore-missing \ + --refresh \ +- ] ++ ]] + fconfigure $fd_rf -blocking 0 -translation binary + fileevent $fd_rf readable \ + [list rescan_stage2 $fd_rf $after] +@@ -1551,11 +1518,11 @@ + set rescan_active 2 + ui_status [mc "Scanning for modified files ..."] + if {[git-version >= "1.7.2"]} { +- set fd_di [git_read diff-index --cached --ignore-submodules=dirty -z [PARENT]] ++ set fd_di [git_read [list diff-index --cached --ignore-submodules=dirty -z [PARENT]]] + } else { +- set fd_di [git_read diff-index --cached -z [PARENT]] ++ set fd_di [git_read [list diff-index --cached -z [PARENT]]] + } +- set fd_df [git_read diff-files -z] ++ set fd_df [git_read [list diff-files -z]] + + fconfigure $fd_di -blocking 0 -translation binary -encoding binary + fconfigure $fd_df -blocking 0 -translation binary -encoding binary +@@ -1564,7 +1531,7 @@ + fileevent $fd_df readable [list read_diff_files $fd_df $after] + + if {[is_config_true gui.displayuntracked]} { +- set fd_lo [eval git_read ls-files --others -z $ls_others] ++ set fd_lo [git_read [concat ls-files --others -z $ls_others]] + fconfigure $fd_lo -blocking 0 -translation binary -encoding binary + fileevent $fd_lo readable [list read_ls_others $fd_lo $after] + incr rescan_active +@@ -1576,7 +1543,7 @@ + + set f [gitdir $file] + if {[file isfile $f]} { +- if {[catch {set fd [open $f r]}]} { ++ if {[catch {set fd [safe_open_file $f r]}]} { + return 0 + } + fconfigure $fd -eofchar {} +@@ -1600,23 +1567,23 @@ + # it will be .git/MERGE_MSG (merge), .git/SQUASH_MSG (squash), or an + # empty file but existent file. + +- set fd_pcm [open [gitdir PREPARE_COMMIT_MSG] a] ++ set fd_pcm [safe_open_file [gitdir PREPARE_COMMIT_MSG] a] + + if {[file isfile [gitdir MERGE_MSG]]} { + set pcm_source "merge" +- set fd_mm [open [gitdir MERGE_MSG] r] ++ set fd_mm [safe_open_file [gitdir MERGE_MSG] r] + fconfigure $fd_mm -encoding utf-8 + puts -nonewline $fd_pcm [read $fd_mm] + close $fd_mm + } elseif {[file isfile [gitdir SQUASH_MSG]]} { + set pcm_source "squash" +- set fd_sm [open [gitdir SQUASH_MSG] r] ++ set fd_sm [safe_open_file [gitdir SQUASH_MSG] r] + fconfigure $fd_sm -encoding utf-8 + puts -nonewline $fd_pcm [read $fd_sm] + close $fd_sm + } elseif {[file isfile [get_config commit.template]]} { + set pcm_source "template" +- set fd_sm [open [get_config commit.template] r] ++ set fd_sm [safe_open_file [get_config commit.template] r] + fconfigure $fd_sm -encoding utf-8 + puts -nonewline $fd_pcm [read $fd_sm] + close $fd_sm +@@ -2206,7 +2173,7 @@ + unset env(GIT_DIR) + unset env(GIT_WORK_TREE) + } +- eval exec $cmd $revs "--" "--" & ++ safe_exec_bg [concat $cmd $revs "--" "--"] + + set env(GIT_DIR) $_gitdir + set env(GIT_WORK_TREE) $_gitworktree +@@ -2243,7 +2210,7 @@ + set pwd [pwd] + cd $current_diff_path + +- eval exec $exe gui & ++ safe_exec_bg [concat $exe gui] + + set env(GIT_DIR) $_gitdir + set env(GIT_WORK_TREE) $_gitworktree +@@ -2272,16 +2239,18 @@ + + proc do_explore {} { + global _gitworktree +- set explorer [get_explorer] +- eval exec $explorer [list [file nativename $_gitworktree]] & ++ set cmd [get_explorer] ++ lappend cmd [file nativename $_gitworktree] ++ safe_exec_bg $cmd + } + + # Open file relative to the working tree by the default associated app. + proc do_file_open {file} { + global _gitworktree +- set explorer [get_explorer] ++ set cmd [get_explorer] + set full_file_path [file join $_gitworktree $file] +- exec $explorer [file nativename $full_file_path] & ++ lappend cmd [file nativename $full_file_path] ++ safe_exec_bg $cmd + } + + set is_quitting 0 +@@ -2315,7 +2284,7 @@ + if {![string match amend* $commit_type] + && $msg ne {}} { + catch { +- set fd [open $save w] ++ set fd [safe_open_file $save w] + fconfigure $fd -encoding utf-8 + puts -nonewline $fd $msg + close $fd +@@ -4134,7 +4103,7 @@ + } + } elseif {$m} { + catch { +- set fd [open [gitdir GITGUI_BCK] w] ++ set fd [safe_open_file [gitdir GITGUI_BCK] w] + fconfigure $fd -encoding utf-8 + puts -nonewline $fd $msg + close $fd +--- a/git-gui/lib/blame.tcl ++++ b/git-gui/lib/blame.tcl +@@ -481,14 +481,14 @@ + if {$do_textconv ne 0} { + set fd [open_cmd_pipe $textconv $path] + } else { +- set fd [open $path r] ++ set fd [safe_open_file $path r] + } + fconfigure $fd -eofchar {} + } else { + if {$do_textconv ne 0} { +- set fd [git_read cat-file --textconv "$commit:$path"] ++ set fd [git_read [list cat-file --textconv "$commit:$path"]] + } else { +- set fd [git_read cat-file blob "$commit:$path"] ++ set fd [git_read [list cat-file blob "$commit:$path"]] + } + } + fconfigure $fd \ +@@ -617,7 +617,7 @@ + } + + lappend options -- $path +- set fd [eval git_read --nice blame $options] ++ set fd [git_read_nice [concat blame $options]] + fconfigure $fd -blocking 0 -translation lf -encoding utf-8 + fileevent $fd readable [cb _read_blame $fd $cur_w $cur_d] + set current_fd $fd +@@ -986,7 +986,7 @@ + if {[catch {set msg $header($cmit,message)}]} { + set msg {} + catch { +- set fd [git_read cat-file commit $cmit] ++ set fd [git_read [list cat-file commit $cmit]] + fconfigure $fd -encoding binary -translation lf + # By default commits are assumed to be in utf-8 + set enc utf-8 +@@ -1134,7 +1134,7 @@ + } else { + set diffcmd [list diff-tree --unified=0 $cparent $cmit -- $new_path] + } +- if {[catch {set fd [eval git_read $diffcmd]} err]} { ++ if {[catch {set fd [git_read $diffcmd]} err]} { + $status_operation stop [mc "Unable to display parent"] + error_popup [strcat [mc "Error loading diff:"] "\n\n$err"] + return +--- a/git-gui/lib/branch.tcl ++++ b/git-gui/lib/branch.tcl +@@ -7,7 +7,7 @@ + set rh refs/heads + set rh_len [expr {[string length $rh] + 1}] + set all_heads [list] +- set fd [git_read for-each-ref --format=%(refname) $rh] ++ set fd [git_read [list for-each-ref --format=%(refname) $rh]] + fconfigure $fd -translation binary -encoding utf-8 + while {[gets $fd line] > 0} { + if {!$some_heads_tracking || ![is_tracking_branch $line]} { +@@ -21,10 +21,10 @@ + + proc load_all_tags {} { + set all_tags [list] +- set fd [git_read for-each-ref \ ++ set fd [git_read [list for-each-ref \ + --sort=-taggerdate \ + --format=%(refname) \ +- refs/tags] ++ refs/tags]] + fconfigure $fd -translation binary -encoding utf-8 + while {[gets $fd line] > 0} { + if {![regsub ^refs/tags/ $line {} name]} continue +--- a/git-gui/lib/browser.tcl ++++ b/git-gui/lib/browser.tcl +@@ -196,7 +196,7 @@ + lappend browser_stack [list $tree_id $name] + $w conf -state disabled + +- set fd [git_read ls-tree -z $tree_id] ++ set fd [git_read [list ls-tree -z $tree_id]] + fconfigure $fd -blocking 0 -translation binary -encoding utf-8 + fileevent $fd readable [cb _read $fd] + } +--- a/git-gui/lib/checkout_op.tcl ++++ b/git-gui/lib/checkout_op.tcl +@@ -304,12 +304,12 @@ + _readtree $this + } else { + ui_status [mc "Refreshing file status..."] +- set fd [git_read update-index \ ++ set fd [git_read [list update-index \ + -q \ + --unmerged \ + --ignore-missing \ + --refresh \ +- ] ++ ]] + fconfigure $fd -blocking 0 -translation binary + fileevent $fd readable [cb _refresh_wait $fd] + } +@@ -345,14 +345,15 @@ + [mc "Updating working directory to '%s'..." [_name $this]] \ + [mc "files checked out"]] + +- set fd [git_read --stderr read-tree \ ++ set fd [git_read [list read-tree \ + -m \ + -u \ + -v \ + --exclude-per-directory=.gitignore \ + $HEAD \ + $new_hash \ +- ] ++ ] \ ++ [list 2>@1]] + fconfigure $fd -blocking 0 -translation binary + fileevent $fd readable [cb _readtree_wait $fd $status_bar_operation] + } +@@ -510,18 +511,8 @@ + delete_this + } + +-git-version proc _detach_HEAD {log new} { +- >= 1.5.3 { +- git update-ref --no-deref -m $log HEAD $new +- } +- default { +- set p [gitdir HEAD] +- file delete $p +- set fd [open $p w] +- fconfigure $fd -translation lf -encoding utf-8 +- puts $fd $new +- close $fd +- } ++proc _detach_HEAD {log new} { ++ git update-ref --no-deref -m $log HEAD $new + } + + method _confirm_reset {cur} { +@@ -582,7 +573,7 @@ + pack $w.buttons.cancel -side right -padx 5 + pack $w.buttons -side bottom -fill x -pady 10 -padx 10 + +- set fd [git_read rev-list --pretty=oneline $cur ^$new_hash] ++ set fd [git_read [list rev-list --pretty=oneline $cur ^$new_hash]] + while {[gets $fd line] > 0} { + set abbr [string range $line 0 7] + set subj [string range $line 41 end] +--- a/git-gui/lib/choose_repository.tcl ++++ b/git-gui/lib/choose_repository.tcl +@@ -662,8 +662,8 @@ + set pwd [pwd] + if {[catch { + file mkdir [gitdir objects info] +- set f_in [open [file join $objdir info alternates] r] +- set f_cp [open [gitdir objects info alternates] w] ++ set f_in [safe_open_file [file join $objdir info alternates] r] ++ set f_cp [safe_open_file [gitdir objects info alternates] w] + fconfigure $f_in -translation binary -encoding binary + fconfigure $f_cp -translation binary -encoding binary + cd $objdir +@@ -752,7 +752,7 @@ + [cb _do_clone_tags] + } + shared { +- set fd [open [gitdir objects info alternates] w] ++ set fd [safe_open_file [gitdir objects info alternates] w] + fconfigure $fd -translation binary + puts $fd $objdir + close $fd +@@ -785,8 +785,8 @@ + } + foreach p $tocopy { + if {[catch { +- set f_in [open [file join $objdir $p] r] +- set f_cp [open [file join .git objects $p] w] ++ set f_in [safe_open_file [file join $objdir $p] r] ++ set f_cp [safe_open_file [file join .git objects $p] w] + fconfigure $f_in -translation binary -encoding binary + fconfigure $f_cp -translation binary -encoding binary + +@@ -843,12 +843,12 @@ + error_popup [mc "Not a Git repository: %s" [file tail $origin_url]] + return 0 + } +- set fd_in [git_read for-each-ref \ ++ set fd_in [git_read [list for-each-ref \ + --tcl \ +- {--format=list %(refname) %(objectname) %(*objectname)}] ++ {--format=list %(refname) %(objectname) %(*objectname)}]] + cd $pwd + +- set fd [open [gitdir packed-refs] w] ++ set fd [safe_open_file [gitdir packed-refs] w] + fconfigure $fd -translation binary + puts $fd "# pack-refs with: peeled" + while {[gets $fd_in line] >= 0} { +@@ -902,7 +902,7 @@ + + set HEAD {} + if {[file exists [gitdir FETCH_HEAD]]} { +- set fd [open [gitdir FETCH_HEAD] r] ++ set fd [safe_open_file [gitdir FETCH_HEAD] r] + while {[gets $fd line] >= 0} { + if {[regexp "^(.{40})\t\t" $line line HEAD]} { + break +@@ -978,13 +978,14 @@ + [mc "files"]] + + set readtree_err {} +- set fd [git_read --stderr read-tree \ ++ set fd [git_read [list read-tree \ + -m \ + -u \ + -v \ + HEAD \ + HEAD \ +- ] ++ ] \ ++ [list 2>@1]] + fconfigure $fd -blocking 0 -translation binary + fileevent $fd readable [cb _readtree_wait $fd] + } +--- a/git-gui/lib/choose_rev.tcl ++++ b/git-gui/lib/choose_rev.tcl +@@ -146,14 +146,14 @@ + append fmt { %(*subject)} + append fmt {]} + set all_refn [list] +- set fr_fd [git_read for-each-ref \ ++ set fr_fd [git_read [list for-each-ref \ + --tcl \ + --sort=-taggerdate \ + --format=$fmt \ + refs/heads \ + refs/remotes \ + refs/tags \ +- ] ++ ]] + fconfigure $fr_fd -translation lf -encoding utf-8 + while {[gets $fr_fd line] > 0} { + set line [eval $line] +@@ -176,7 +176,7 @@ + close $fr_fd + + if {$unmerged_only} { +- set fr_fd [git_read rev-list --all ^$::HEAD] ++ set fr_fd [git_read [list rev-list --all ^$::HEAD]] + while {[gets $fr_fd sha1] > 0} { + if {[catch {set rlst $cmt_refn($sha1)}]} continue + foreach refn $rlst { +@@ -579,7 +579,7 @@ + + set last {} + if {[catch {set last [file mtime [gitdir $name]]}] +- && ![catch {set g [open [gitdir logs $name] r]}]} { ++ && ![catch {set g [safe_open_file [gitdir logs $name] r]}]} { + fconfigure $g -translation binary + while {[gets $g line] >= 0} { + if {[regexp {> ([1-9][0-9]*) } $line line when]} { +--- a/git-gui/lib/commit.tcl ++++ b/git-gui/lib/commit.tcl +@@ -27,7 +27,7 @@ + if {[catch { + set name "" + set email "" +- set fd [git_read cat-file commit $curHEAD] ++ set fd [git_read [list cat-file commit $curHEAD]] + fconfigure $fd -encoding binary -translation lf + # By default commits are assumed to be in utf-8 + set enc utf-8 +@@ -225,7 +225,7 @@ + # -- Build the message file. + # + set msg_p [gitdir GITGUI_EDITMSG] +- set msg_wt [open $msg_p w] ++ set msg_wt [safe_open_file $msg_p w] + fconfigure $msg_wt -translation lf + setup_commit_encoding $msg_wt + puts $msg_wt $msg +@@ -325,7 +325,7 @@ + + proc commit_writetree {curHEAD msg_p} { + ui_status [mc "Committing changes..."] +- set fd_wt [git_read write-tree] ++ set fd_wt [git_read [list write-tree]] + fileevent $fd_wt readable \ + [list commit_committree $fd_wt $curHEAD $msg_p] + } +@@ -350,7 +350,7 @@ + # -- Verify this wasn't an empty change. + # + if {$commit_type eq {normal}} { +- set fd_ot [git_read cat-file commit $PARENT] ++ set fd_ot [git_read [list cat-file commit $PARENT]] + fconfigure $fd_ot -encoding binary -translation lf + set old_tree [gets $fd_ot] + close $fd_ot +@@ -388,8 +388,8 @@ + foreach p [concat $PARENT $MERGE_HEAD] { + lappend cmd -p $p + } +- lappend cmd <$msg_p +- if {[catch {set cmt_id [eval git $cmd]} err]} { ++ set msgtxt [list <$msg_p] ++ if {[catch {set cmt_id [git_redir $cmd $msgtxt]} err]} { + catch {file delete $msg_p} + error_popup [strcat [mc "commit-tree failed:"] "\n\n$err"] + ui_status [mc "Commit failed."] +@@ -409,7 +409,7 @@ + if {$commit_type ne {normal}} { + append reflogm " ($commit_type)" + } +- set msg_fd [open $msg_p r] ++ set msg_fd [safe_open_file $msg_p r] + setup_commit_encoding $msg_fd 1 + gets $msg_fd subject + close $msg_fd +--- a/git-gui/lib/console.tcl ++++ b/git-gui/lib/console.tcl +@@ -92,10 +92,9 @@ + + method exec {cmd {after {}}} { + if {[lindex $cmd 0] eq {git}} { +- set fd_f [eval git_read --stderr [lrange $cmd 1 end]] ++ set fd_f [git_read [lrange $cmd 1 end] [list 2>@1]] + } else { +- lappend cmd 2>@1 +- set fd_f [_open_stdout_stderr $cmd] ++ set fd_f [safe_open_command $cmd [list 2>@1]] + } + fconfigure $fd_f -blocking 0 -translation binary + fileevent $fd_f readable [cb _read $fd_f $after] +--- a/git-gui/lib/database.tcl ++++ b/git-gui/lib/database.tcl +@@ -3,7 +3,7 @@ + + proc do_stats {} { + global use_ttk NS +- set fd [git_read count-objects -v] ++ set fd [git_read [list count-objects -v]] + while {[gets $fd line] > 0} { + if {[regexp {^([^:]+): (\d+)$} $line _ name value]} { + set stats($name) $value +--- a/git-gui/lib/diff.tcl ++++ b/git-gui/lib/diff.tcl +@@ -202,7 +202,7 @@ + set sz [string length $content] + } + file { +- set fd [open $path r] ++ set fd [safe_open_file $path r] + fconfigure $fd \ + -eofchar {} \ + -encoding [get_path_encoding $path] +@@ -226,7 +226,7 @@ + $ui_diff insert end \ + "* [mc "Git Repository (subproject)"]\n" \ + d_info +- } elseif {![catch {set type [exec file $path]}]} { ++ } elseif {![catch {set type [safe_exec [list file $path]]}]} { + set n [string length $path] + if {[string equal -length $n $path $type]} { + set type [string range $type $n end] +@@ -338,7 +338,7 @@ + } + } + +- if {[catch {set fd [eval git_read --nice $cmd]} err]} { ++ if {[catch {set fd [git_read_nice $cmd]} err]} { + set diff_active 0 + unlock_index + ui_status [mc "Unable to display %s" [escape_path $path]] +@@ -617,7 +617,7 @@ + + if {[catch { + set enc [get_path_encoding $current_diff_path] +- set p [eval git_write $apply_cmd] ++ set p [git_write $apply_cmd] + fconfigure $p -translation binary -encoding $enc + puts -nonewline $p $wholepatch + close $p} err]} { +@@ -853,7 +853,7 @@ + + if {[catch { + set enc [get_path_encoding $current_diff_path] +- set p [eval git_write $apply_cmd] ++ set p [git_write $apply_cmd] + fconfigure $p -translation binary -encoding $enc + puts -nonewline $p $current_diff_header + puts -nonewline $p $wholepatch +@@ -890,7 +890,7 @@ + + if {[catch { + set enc $last_revert_enc +- set p [eval git_write $apply_cmd] ++ set p [git_write $apply_cmd] + fconfigure $p -translation binary -encoding $enc + puts -nonewline $p $last_revert + close $p} err]} { +--- a/git-gui/lib/index.tcl ++++ b/git-gui/lib/index.tcl +@@ -75,7 +75,7 @@ + if {$batch > 25} {set batch 25} + + set status_bar_operation [$::main_status start $msg [mc "files"]] +- set fd [git_write update-index -z --index-info] ++ set fd [git_write [list update-index -z --index-info]] + fconfigure $fd \ + -blocking 0 \ + -buffering full \ +@@ -144,7 +144,7 @@ + if {$batch > 25} {set batch 25} + + set status_bar_operation [$::main_status start $msg [mc "files"]] +- set fd [git_write update-index --add --remove -z --stdin] ++ set fd [git_write [list update-index --add --remove -z --stdin]] + fconfigure $fd \ + -blocking 0 \ + -buffering full \ +@@ -218,13 +218,13 @@ + if {$batch > 25} {set batch 25} + + set status_bar_operation [$::main_status start $msg [mc "files"]] +- set fd [git_write checkout-index \ ++ set fd [git_write [list checkout-index \ + --index \ + --quiet \ + --force \ + -z \ + --stdin \ +- ] ++ ]] + fconfigure $fd \ + -blocking 0 \ + -buffering full \ +--- a/git-gui/lib/merge.tcl ++++ b/git-gui/lib/merge.tcl +@@ -93,7 +93,7 @@ + set spec [$w_rev get_tracking_branch] + set cmit [$w_rev get_commit] + +- set fh [open [gitdir FETCH_HEAD] w] ++ set fh [safe_open_file [gitdir FETCH_HEAD] w] + fconfigure $fh -translation lf + if {$spec eq {}} { + set remote . +@@ -118,7 +118,7 @@ + set cmd [list git] + lappend cmd merge + lappend cmd --strategy=recursive +- lappend cmd [git fmt-merge-msg <[gitdir FETCH_HEAD]] ++ lappend cmd [git_redir [list fmt-merge-msg] [list <[gitdir FETCH_HEAD]]] + lappend cmd HEAD + lappend cmd $name + } +@@ -239,7 +239,7 @@ + } + + if {[ask_popup $op_question] eq {yes}} { +- set fd [git_read --stderr read-tree --reset -u -v HEAD] ++ set fd [git_read [list read-tree --reset -u -v HEAD] [list 2>@1]] + fconfigure $fd -blocking 0 -translation binary + set status_bar_operation [$::main_status \ + start \ +--- a/git-gui/lib/mergetool.tcl ++++ b/git-gui/lib/mergetool.tcl +@@ -88,7 +88,7 @@ + set merge_stages(3) {} + set merge_stages_buf {} + +- set merge_stages_fd [eval git_read ls-files -u -z -- {$path}] ++ set merge_stages_fd [git_read [list ls-files -u -z -- $path]] + + fconfigure $merge_stages_fd -blocking 0 -translation binary -encoding binary + fileevent $merge_stages_fd readable [list read_merge_stages $merge_stages_fd $cont] +@@ -293,7 +293,7 @@ + foreach fname $stages { + if {$merge_stages($i) eq {}} { + file delete $fname +- catch { close [open $fname w] } ++ catch { close [safe_open_file $fname w] } + } else { + # A hack to support autocrlf properly + git checkout-index -f --stage=$i -- $target +@@ -343,9 +343,9 @@ + + # Force redirection to avoid interpreting output on stderr + # as an error, and launch the tool +- lappend cmdline {2>@1} ++ set redir [list {2>@1}] + +- if {[catch { set mtool_fd [_open_stdout_stderr $cmdline] } err]} { ++ if {[catch { set mtool_fd [safe_open_command $cmdline $redir] } err]} { + delete_temp_files $mtool_tmpfiles + error_popup [mc "Could not start the merge tool:\n\n%s" $err] + return +--- a/git-gui/lib/remote.tcl ++++ b/git-gui/lib/remote.tcl +@@ -32,7 +32,7 @@ + } + + if {$pat ne {}} { +- set fd [eval git_read for-each-ref --format=%(refname) $cmd] ++ set fd [git_read [concat for-each-ref --format=%(refname) $cmd]] + while {[gets $fd n] > 0} { + foreach spec $pat { + set dst [string range [lindex $spec 0] 0 end-2] +@@ -75,7 +75,7 @@ + + foreach name $all_remotes { + catch { +- set fd [open [file join $rm_dir $name] r] ++ set fd [safe_open_file [file join $rm_dir $name] r] + while {[gets $fd line] >= 0} { + if {[regexp {^URL:[ ]*(.+)$} $line line url]} { + set remote_url($name) $url +@@ -145,7 +145,7 @@ + } + } else { + catch { +- set fd [open [gitdir remotes $r] r] ++ set fd [safe_open_file [gitdir remotes $r] r] + while {[gets $fd n] >= 0} { + if {[regexp {^Pull:[ \t]*([^:]+):} $n]} { + set enable 1 +@@ -182,7 +182,7 @@ + } + } else { + catch { +- set fd [open [gitdir remotes $r] r] ++ set fd [safe_open_file [gitdir remotes $r] r] + while {[gets $fd n] >= 0} { + if {[regexp {^Push:[ \t]*([^:]+):} $n]} { + set enable 1 +--- a/git-gui/lib/remote_branch_delete.tcl ++++ b/git-gui/lib/remote_branch_delete.tcl +@@ -308,7 +308,7 @@ + set full_list [list] + set head_cache($cache) [list] + set full_cache($cache) [list] +- set active_ls [git_read ls-remote $uri] ++ set active_ls [git_read [list ls-remote $uri]] + fconfigure $active_ls \ + -blocking 0 \ + -translation lf \ +--- a/git-gui/lib/shortcut.tcl ++++ b/git-gui/lib/shortcut.tcl +@@ -86,7 +86,7 @@ + + file mkdir $MacOS + +- set fd [open [file join $Contents Info.plist] w] ++ set fd [safe_open_file [file join $Contents Info.plist] w] + puts $fd { + + +@@ -111,7 +111,7 @@ + } + close $fd + +- set fd [open $exe w] ++ set fd [safe_open_file $exe w] + puts $fd "#!/bin/sh" + foreach name [lsort [array names env]] { + set value $env($name) +--- a/git-gui/lib/sshkey.tcl ++++ b/git-gui/lib/sshkey.tcl +@@ -7,7 +7,7 @@ + ~/.ssh/id_rsa.pub ~/.ssh/identity.pub + } { + if {[file exists $name]} { +- set fh [open $name r] ++ set fh [safe_open_file $name r] + set cont [read $fh] + close $fh + return [list $name $cont] +@@ -85,7 +85,7 @@ + + set cmdline [list sh -c {echo | ssh-keygen -q -t rsa -f ~/.ssh/id_rsa 2>&1}] + +- if {[catch { set sshkey_fd [_open_stdout_stderr $cmdline] } err]} { ++ if {[catch { set sshkey_fd [safe_open_command $cmdline] } err]} { + error_popup [mc "Could not start ssh-keygen:\n\n%s" $err] + return + } +--- a/git-gui/lib/tools.tcl ++++ b/git-gui/lib/tools.tcl +@@ -130,8 +130,7 @@ + } + + proc tools_run_silent {cmd after} { +- lappend cmd 2>@1 +- set fd [_open_stdout_stderr $cmd] ++ set fd [safe_open_command $cmd [list 2>@1]] + + fconfigure $fd -blocking 0 -translation binary + fileevent $fd readable [list tools_consume_input $fd $after] +--- a/git-gui/lib/win32.tcl ++++ b/git-gui/lib/win32.tcl +@@ -2,11 +2,11 @@ + # Copyright (C) 2007 Shawn Pearce + + proc win32_read_lnk {lnk_path} { +- return [exec cscript.exe \ ++ return [safe_exec [list cscript.exe \ + /E:jscript \ + /nologo \ + [file join $::oguilib win32_shortcut.js] \ +- $lnk_path] ++ $lnk_path]] + } + + proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { +@@ -15,12 +15,13 @@ + set lnk_args [lrange $lnk_exec 1 end] + set lnk_exec [lindex $lnk_exec 0] + +- eval [list exec wscript.exe \ ++ set cmd [list wscript.exe \ + /E:jscript \ + /nologo \ + [file nativename [file join $oguilib win32_shortcut.js]] \ + $lnk_path \ + [file nativename [file join $oguilib git-gui.ico]] \ + $lnk_dir \ +- $lnk_exec] $lnk_args ++ $lnk_exec] ++ safe_exec [concat $cmd $lnk_args] + } diff -Nru git-2.39.5/debian/patches/CVE-2025-48384.patch git-2.39.5/debian/patches/CVE-2025-48384.patch --- git-2.39.5/debian/patches/CVE-2025-48384.patch 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/debian/patches/CVE-2025-48384.patch 2025-10-07 11:44:37.000000000 +0000 @@ -0,0 +1,69 @@ +--- a/config.c ++++ b/config.c +@@ -3023,7 +3023,7 @@ + if (value[0] == ' ') + quote = "\""; + for (i = 0; value[i]; i++) +- if (value[i] == ';' || value[i] == '#') ++ if (value[i] == ';' || value[i] == '#' || value[i] == '\r') + quote = "\""; + if (i && value[i - 1] == ' ') + quote = "\""; +--- a/t/t1300-config.sh ++++ b/t/t1300-config.sh +@@ -2552,4 +2552,15 @@ + grep "fatal: remote URLs cannot be configured in file directly or indirectly included by includeIf.hasconfig:remote.*.url" err + ' + ++test_expect_success 'writing value with trailing CR not stripped on read' ' ++ test_when_finished "rm -rf cr-test" && ++ ++ printf "bar\r\n" >expect && ++ git init cr-test && ++ git -C cr-test config core.foo $(printf "bar\r") && ++ git -C cr-test config core.foo >actual && ++ ++ test_cmp expect actual ++' ++ + test_done +--- a/t/t7450-bad-git-dotfiles.sh ++++ b/t/t7450-bad-git-dotfiles.sh +@@ -345,4 +345,37 @@ + test_path_is_missing nested_checkout/thing2/.git + ' + ++test_expect_success SYMLINKS,!WINDOWS,!MINGW 'submodule must not checkout into different directory' ' ++ test_when_finished "rm -rf sub repo bad-clone" && ++ ++ git init sub && ++ write_script sub/post-checkout <<-\EOF && ++ touch "$PWD/foo" ++ EOF ++ git -C sub add post-checkout && ++ git -C sub commit -m hook && ++ ++ git init repo && ++ git -C repo -c protocol.file.allow=always submodule add "$PWD/sub" sub && ++ git -C repo mv sub $(printf "sub\r") && ++ ++ # Ensure config values containing CR are wrapped in quotes. ++ git config --unset -f repo/.gitmodules submodule.sub.path && ++ printf "\tpath = \"sub\r\"\n" >>repo/.gitmodules && ++ ++ git config --unset -f repo/.git/modules/sub/config core.worktree && ++ { ++ printf "[core]\n" && ++ printf "\tworktree = \"../../../sub\r\"\n" ++ } >>repo/.git/modules/sub/config && ++ ++ ln -s .git/modules/sub/hooks repo/sub && ++ git -C repo add -A && ++ git -C repo commit -m submodule && ++ ++ git -c protocol.file.allow=always clone --recurse-submodules repo bad-clone && ++ ! test -f "$PWD/foo" && ++ test -f $(printf "bad-clone/sub\r/post-checkout") ++' ++ + test_done diff -Nru git-2.39.5/debian/patches/CVE-2025-48385.patch git-2.39.5/debian/patches/CVE-2025-48385.patch --- git-2.39.5/debian/patches/CVE-2025-48385.patch 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/debian/patches/CVE-2025-48385.patch 2025-10-07 11:44:37.000000000 +0000 @@ -0,0 +1,62 @@ +--- a/bundle-uri.c ++++ b/bundle-uri.c +@@ -229,6 +229,28 @@ + struct strbuf line = STRBUF_INIT; + int found_get = 0; + ++ /* ++ * The protocol we speak with git-remote-https(1) uses a space to ++ * separate between URI and file, so the URI itself must not contain a ++ * space. If it did, an adversary could change the location where the ++ * downloaded file is being written to. ++ * ++ * Similarly, we use newlines to separate commands from one another. ++ * Consequently, neither the URI nor the file must contain a newline or ++ * otherwise an adversary could inject arbitrary commands. ++ * ++ * TODO: Restricting newlines in the target paths may break valid ++ * usecases, even if those are a bit more on the esoteric side. ++ * If this ever becomes a problem we should probably think about ++ * alternatives. One alternative could be to use NUL-delimited ++ * requests in git-remote-http(1). Another alternative could be ++ * to use URL quoting. ++ */ ++ if (strpbrk(uri, " \n")) ++ return error("bundle-uri: URI is malformed: '%s'", file); ++ if (strchr(file, '\n')) ++ return error("bundle-uri: filename is malformed: '%s'", file); ++ + strvec_pushl(&cp.args, "git-remote-https", uri, NULL); + cp.err = -1; + cp.in = -1; +--- a/t/t5558-clone-bundle-uri.sh ++++ b/t/t5558-clone-bundle-uri.sh +@@ -350,6 +350,28 @@ + test_cmp expect actual + ' + ++test_expect_success 'bundles with space in URI are rejected' ' ++ test_when_finished "rm -rf busted repo" && ++ mkdir -p "$HOME/busted/ /$HOME/repo/.git/objects/bundles" && ++ git clone --bundle-uri="$HTTPD_URL/bogus $HOME/busted/" "$HTTPD_URL/smart/fetch.git" repo 2>err && ++ test_grep "error: bundle-uri: URI is malformed: " err && ++ find busted -type f >files && ++ test_must_be_empty files ++' ++ ++test_expect_success 'bundles with newline in URI are rejected' ' ++ test_when_finished "rm -rf busted repo" && ++ git clone --bundle-uri="$HTTPD_URL/bogus\nget $HTTPD_URL/bogus $HOME/busted" "$HTTPD_URL/smart/fetch.git" repo 2>err && ++ test_grep "error: bundle-uri: URI is malformed: " err && ++ test_path_is_missing "$HOME/busted" ++' ++ ++test_expect_success 'bundles with newline in target path are rejected' ' ++ git clone --bundle-uri="$HTTPD_URL/bogus" "$HTTPD_URL/smart/fetch.git" "$(printf "escape\nget $HTTPD_URL/bogus .")" 2>err && ++ test_grep "error: bundle-uri: filename is malformed: " err && ++ test_path_is_missing escape ++' ++ + # Do not add tests here unless they use the HTTP server, as they will + # not run unless the HTTP dependencies exist. + diff -Nru git-2.39.5/debian/patches/series git-2.39.5/debian/patches/series --- git-2.39.5/debian/patches/series 2025-01-11 19:42:07.000000000 +0000 +++ git-2.39.5/debian/patches/series 2025-10-07 11:44:37.000000000 +0000 @@ -1,3 +1,7 @@ credential_format-also-encode-host-port.patch credential-sanitize-the-user-prompt.patch credential-disallow-Carriage-Returns-in-the-protocol.patch +CVE-2025-27613.patch +CVE-2025-46835.patch +CVE-2025-48384.patch +CVE-2025-48385.patch