Não é seguro se o código não for interpretado na mesma localidade em que foi gerado (ou se o nome da localidade for o mesmo, mas a definição dessa localidade difere entre o ssh host do cliente e host do servidor).
Particularmente importante é a codificação de caracteres e associação de caracteres nas categorias blank
, alpha
e alnum
.
Por exemplo, o caractere α
(letra minúscula grega alfa) no conjunto de caracteres BIG5 é codificado como 0xa3 0x5c, sendo 0x5c \
em ASCII (e todos os conjuntos de caracteres incluindo BIG5).
Então, se você tiver uma função foo
definida nesse conjunto de caracteres como:
foo() {
echo α
}
typeset -f
fará a saída como tal, mas se for interpretado em uma localidade diferente como C, 0xa3 0x5c não será considerada como α
, mas como um caractere 0xa3 desconhecido seguido por uma barra invertida. Isso pode ser explorado como com:
$ env LC_ALL=zh_TW.big5 $'BASH_FUNC_foo%%=() { echo \xa3\\;}; echo gotcha; }' bash -c 'typeset -f foo' | bash
gotcha
bash: line 5: syntax error near unexpected token '}'
bash: line 5: '}'
O foo() { echo α\;}; echo gotcha; }
tornou-se foo() { echo <0xa3>\; }; echo gotcha; }
quando interpretado na localidade diferente.
Outros problemas:
O caractere à
em UTF-8 é codificado como 0xc3 0xa0. Em iso8859-1 e vários outros conjuntos de caracteres iso8859
, 0xa0 é o caractere de espaço sem quebra. Em alguns sistemas, esse caractere é incluído na classe de caracteres blank , portanto, honrado pelo bash como um delimitador de tokens em sua sintaxe.
O Solaris é um desses sistemas em que U + 00A0 é considerado em branco:
$ env $'BASH_FUNC_foo%%=() { nawk -v x=àBEGIN\'{system("echo gotcha")}\' 1;}' bash -c 'typeset -f foo; echo foo' | ssh solaris LC_ALL=en_GB.ISO8859-1 bash
gotcha
Veja como:
nawk -v x=àBEGIN... 1
foi interpretado como:
nawk -v x=<0xc3> 'BEGIN{system("...")}' 1
Note que se a função foi definida em uma localidade onde 0xa0 não era um espaço em branco ou onde 0xa3 0x5c era alfa, typeset -f
ainda produziria o mesmo mesmo se chamado em uma localidade onde é um espaço em branco (produzindo uma saída diferente quando interpretado)
$ LC_ALL=zh_TW.big5 bash -c $'f() { echo \xa3\x5c$(uname); }; export LC_ALL=C; typeset -f f | bash'
bash: line 3: syntax error near unexpected token '('
bash: line 3: ' echo �\$(uname)'
Mais geralmente, a saída de typeset
, alias
, export -p
, set
, locale
são todos significados para serem adequados para reinputação em uma casca, mas além desses questões locais, várias implementações são conhecidas por terem vários problemas, e eu não ficaria surpreso se ainda houvesse muito mais.
Então, sim, eu concordo que você está certo em considerá-lo perigoso, e é uma boa ideia usá-los apenas no contexto em que você sabe de onde vêm os dados gerados. Por exemplo, no caso de typeset -f foo
, use-o apenas em uma função foo
que você definiu (e evite usar caracteres não-ASCII nele).