harden alias against foo; bar

If the first word of the alias body ends with a semicolon we need to
strip that character, and otherwise escape the extracted command, to
ensure the subsequent function definition is valid.

Fixes #3860
This commit is contained in:
Kurtis Rader 2017-02-20 20:23:55 -08:00
parent 992e1d0059
commit 9dd0c47d0b
4 changed files with 19 additions and 6 deletions

View file

@ -11,6 +11,7 @@ function alias --description 'Creates a function wrapping a command'
set -l body
set -l prefix
set -l first_word
set -l wrapped_cmd
switch (count $argv)
case 0
@ -43,11 +44,13 @@ function alias --description 'Creates a function wrapping a command'
return 1
end
# Extract the first command from the body
# This is supposed to replace all non-escaped (i.e. preceded by an odd number of `\`) spaces with a newline
# so it splits on them
# Extract the first command from the body. This is supposed to replace all non-escaped (i.e.
# preceded by an odd number of `\`) spaces with a newline so it splits on them. See issue #2220
# for why the following borderline incomprehensible code exists.
set -l tmp (string replace -ra "([^\\\ ])((\\\\\\\)*) " '$1\n' $body)
set first_word (string trim $tmp[1])
# If the user does something like `alias x 'foo; bar'` we need to strip the semicolon.
set wrapped_cmd (string trim -c ';' $first_word)
if set -q tmp[2]
set body $tmp[2..-1]
else
@ -56,8 +59,7 @@ function alias --description 'Creates a function wrapping a command'
# Prevent the alias from immediately running into an infinite recursion if
# $body starts with the same command as $name.
if test $first_word = $name
if test $wrapped_cmd = $name
if contains $name (builtin --names)
set prefix builtin
else
@ -65,5 +67,7 @@ function alias --description 'Creates a function wrapping a command'
end
end
set -l cmd_string (string escape "alias $argv")
echo "function $name --wraps $first_word --description $cmd_string; $prefix $first_word $body \$argv; end" | source
set wrapped_cmd (string escape $wrapped_cmd)
echo "function $name --wraps $wrapped_cmd --description $cmd_string; $prefix $first_word $body \$argv; end" | source
#echo "function $name --wraps $wrapped_cmd --description $cmd_string; $prefix $first_word $body \$argv; end"
end

0
tests/alias.err Normal file
View file

7
tests/alias.in Normal file
View file

@ -0,0 +1,7 @@
# Avoid regressions of issue #3860 wherein the first word of the alias ends
# with a semicolon.
function foo
echo ran foo
end
alias my_alias "foo; and echo foo ran"
my_alias

2
tests/alias.out Normal file
View file

@ -0,0 +1,2 @@
ran foo
foo ran