Skip to content

Commit 1e4119c

Browse files
rhansengitster
authored andcommitted
git-prompt.sh: don't assume the shell expands the value of PS1
Not all shells subject the prompt string to parameter expansion. Test whether the shell will expand the value of PS1, and use the result to control whether raw ref names are included directly in PS1. This fixes a regression introduced in commit 8976500 ("git-prompt.sh: don't put unsanitized branch names in $PS1"): zsh does not expand PS1 by default, but that commit assumed it did. The bug resulted in prompts containing the literal string '${__git_ps1_branch_name}' instead of the actual branch name. Reported-by: Caleb Thompson <[email protected]> Signed-off-by: Richard Hansen <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 8976500 commit 1e4119c

File tree

2 files changed

+42
-20
lines changed

2 files changed

+42
-20
lines changed

contrib/completion/git-prompt.sh

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,7 @@ __git_ps1_show_upstream ()
209209
if [[ -n "$count" && -n "$name" ]]; then
210210
__git_ps1_upstream_name=$(git rev-parse \
211211
--abbrev-ref "$upstream" 2>/dev/null)
212-
if [ $pcmode = yes ]; then
213-
# see the comments around the
214-
# __git_ps1_branch_name variable below
212+
if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
215213
p="$p \${__git_ps1_upstream_name}"
216214
else
217215
p="$p ${__git_ps1_upstream_name}"
@@ -301,6 +299,43 @@ __git_ps1 ()
301299
;;
302300
esac
303301

302+
# ps1_expanded: This variable is set to 'yes' if the shell
303+
# subjects the value of PS1 to parameter expansion:
304+
#
305+
# * bash does unless the promptvars option is disabled
306+
# * zsh does not unless the PROMPT_SUBST option is set
307+
# * POSIX shells always do
308+
#
309+
# If the shell would expand the contents of PS1 when drawing
310+
# the prompt, a raw ref name must not be included in PS1.
311+
# This protects the user from arbitrary code execution via
312+
# specially crafted ref names. For example, a ref named
313+
# 'refs/heads/$(IFS=_;cmd=sudo_rm_-rf_/;$cmd)' might cause the
314+
# shell to execute 'sudo rm -rf /' when the prompt is drawn.
315+
#
316+
# Instead, the ref name should be placed in a separate global
317+
# variable (in the __git_ps1_* namespace to avoid colliding
318+
# with the user's environment) and that variable should be
319+
# referenced from PS1. For example:
320+
#
321+
# __git_ps1_foo=$(do_something_to_get_ref_name)
322+
# PS1="...stuff...\${__git_ps1_foo}...stuff..."
323+
#
324+
# If the shell does not expand the contents of PS1, the raw
325+
# ref name must be included in PS1.
326+
#
327+
# The value of this variable is only relevant when in pcmode.
328+
#
329+
# Assume that the shell follows the POSIX specification and
330+
# expands PS1 unless determined otherwise. (This is more
331+
# likely to be correct if the user has a non-bash, non-zsh
332+
# shell and safer than the alternative if the assumption is
333+
# incorrect.)
334+
#
335+
local ps1_expanded=yes
336+
[ -z "$ZSH_VERSION" ] || [[ -o PROMPT_SUBST ]] || ps1_expanded=no
337+
[ -z "$BASH_VERSION" ] || shopt -q promptvars || ps1_expanded=no
338+
304339
local repo_info rev_parse_exit_code
305340
repo_info="$(git rev-parse --git-dir --is-inside-git-dir \
306341
--is-bare-repository --is-inside-work-tree \
@@ -450,21 +485,8 @@ __git_ps1 ()
450485
fi
451486

452487
b=${b##refs/heads/}
453-
if [ $pcmode = yes ]; then
454-
# In pcmode (and only pcmode) the contents of
455-
# $gitstring are subject to expansion by the shell.
456-
# Avoid putting the raw ref name in the prompt to
457-
# protect the user from arbitrary code execution via
458-
# specially crafted ref names (e.g., a ref named
459-
# '$(IFS=_;cmd=sudo_rm_-rf_/;$cmd)' would execute
460-
# 'sudo rm -rf /' when the prompt is drawn). Instead,
461-
# put the ref name in a new global variable (in the
462-
# __git_ps1_* namespace to avoid colliding with the
463-
# user's environment) and reference that variable from
464-
# PS1.
488+
if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
465489
__git_ps1_branch_name=$b
466-
# note that the $ is escaped -- the variable will be
467-
# expanded later (when it's time to draw the prompt)
468490
b="\${__git_ps1_branch_name}"
469491
fi
470492

t/t9903-bash-prompt.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -578,12 +578,12 @@ test_expect_success 'prompt - bash color pc mode - untracked files status indica
578578
'
579579

580580
test_expect_success 'prompt - zsh color pc mode' '
581-
printf "BEFORE: (%%F{green}\${__git_ps1_branch_name}%%f):AFTER\\nmaster" >expected &&
581+
printf "BEFORE: (%%F{green}master%%f):AFTER" >expected &&
582582
(
583583
ZSH_VERSION=5.0.0 &&
584584
GIT_PS1_SHOWCOLORHINTS=y &&
585-
__git_ps1 "BEFORE:" ":AFTER" >"$actual"
586-
printf "%s\\n%s" "$PS1" "${__git_ps1_branch_name}" >"$actual"
585+
__git_ps1 "BEFORE:" ":AFTER" &&
586+
printf "%s" "$PS1" >"$actual"
587587
) &&
588588
test_cmp expected "$actual"
589589
'

0 commit comments

Comments
 (0)