Há uma pergunta semelhante que lida com o cenário de 'quebra automática', em que você deseja substituir, por exemplo, cd
um comando que chama o builtin cd
.
No entanto, à luz do shellshock et al e sabendo que o bash importa funções do ambiente, eu fiz alguns testes e não consigo encontrar uma maneira de chamar com segurança o builtin cd
do meu script.
Considere isto
cd() { echo "muahaha"; }
export -f cd
Quaisquer scripts chamados neste ambiente usando cd
serão interrompidos (considere os efeitos de algo como cd dir && rm -rf .
).
Existem comandos para verificar o tipo de um comando (convenientemente chamado type
) e comandos para executar a versão interna em vez de uma função ( builtin
e command
). Mas eis que eles também podem ser substituídos usando funções
builtin() { "$@"; }
command() { "$@"; }
type() { echo "$1 is a shell builtin"; }
Produzirá o seguinte:
$ type cd
cd is a shell builtin
$ cd x
muahaha
$ builtin cd x
muahaha
$ command cd x
muahaha
Existe alguma maneira de forçar com segurança o bash a usar o comando embutido, ou pelo menos detectar que um comando não é um embutido, sem limpar o ambiente inteiro?
Sei que, se alguém controla seu ambiente, você provavelmente está ferrado de qualquer maneira, mas pelo menos para aliases, você tem a opção de não chamar o alias, inserindo um \
antes dele.
env
comando anterior, desta forma:env -i <SCRIPT.sh>
env
não for redefinido como uma função também. Isso é aterrorizante. Primeiro pensei que caracteres especiais ajudariam - chamando com o caminho completo que inclui/
, usar.
a fonte e assim por diante. Mas esses também podem ser usados para nomes de funções! Você pode redefinir qualquer função que desejar, mas é difícil voltar a chamar o comando original.#/bin/sh
se este não for o shell interativo padrão.Respostas:
Olivier D está quase correto, mas você deve definir
POSIXLY_CORRECT=1
antes de executarunset
. O POSIX possui uma noção de Built-ins especiais e o bash suporta isso .unset
é um desses embutidos. ProcurarSPECIAL_BUILTIN
embuiltins/*.c
na fonte do bash para uma lista, incluiset
,unset
,export
,eval
esource
.O ladino
unset
foi agora removido do ambiente, se você unsetcommand
,type
,builtin
então você deve ser capaz de prosseguir, masunset POSIXLY_CORRECT
se você está confiando em comportamento não-POSIX ou recursos avançados festança.No entanto, isso não resolve aliases, portanto, você deve usar
\unset
para garantir que ele funcione no shell interativo (ou sempre, casoexpand_aliases
esteja em vigor).Para os paranóicos, isso deve consertar tudo, acho:
(
while
,do
,done
E[[
são palavras reservadas e não precisam de precauções.) Note que estamos usandounset -f
para ter certeza de funções não definidas, embora as variáveis e funções compartilham o mesmo espaço de nomes é possível tanto para existir simultaneamente (graças a Etan Reisner), caso em que desarmar duas vezes também faria o truque. Você pode marcar uma função somente leitura, o bash não impede que você desative uma função somente leitura, incluindo o bash-4.2, o bash-4.3 impede você, mas ainda respeita os recursos especiais especiais quandoPOSIXLY_CORRECT
definido.Um readonly
POSIXLY_CORRECT
não é um problema real, não é um booleano ou sinaliza que sua presença ativa o modo POSIX; portanto, se ele existir como um readonly, você poderá confiar nos recursos do POSIX, mesmo que o valor esteja vazio ou 0. Você simplesmente precisará funções problemáticas não configuradas de uma maneira diferente da anterior, talvez com alguns recortar e colar:(e ignore quaisquer erros) ou participe de outros scripts .
Outras notas:
function
é uma palavra reservada, pode ser aliasada, mas não substituída por uma função. (Aliasingfunction
é levemente problemático porque\function
não é aceitável como forma de contorná-lo)[[
,]]
são palavras reservadas, elas podem ter alias (que serão ignoradas), mas não substituídas por uma função (embora as funções possam ter esse nome)((
não é um nome válido para uma função, nem um aliasfonte
unset
et al de serem substituídos.-f
argumentounset
, não é? Caso contrário, se uma variável e uma função com o mesmo nome de um builtin forem definidas,unset
escolherá a variável para desabilitar primeiro. Além disso, isso falha se alguma das funções obscurecedoras estiver definidareadonly
, não é? (Embora seja detectável e possa ser cometido um erro fatal.) Isso também perde o[
que parece estar embutido.\unset -f unset
faz sentido, já que isso será feito no ciclo de leitura. Seunset
for uma função, você\unset
normalmente a resolveria em vez da incorporada, mas você pode usá-la\unset
com segurança enquanto o modo POSIX estiver em vigor. Explicitamente chamando\unset -f
on[
,.
e:
pode ser uma boa idéia, porém, como seus exclui regex eles. Eu também adicionaria-f
ao\unset
loop e\unset POSIXLY_CORRECT
depois do loop, em vez de antes.\unalias -a
(after\unset -f unalias
) também permite renunciar com segurança à fuga em comandos subseqüentes.[[ ${POSIXLY_CORRECT?non-POSIX mode shell is untrusted}x ]]
isso fará com que um script não interativo saia com o erro indicado se a variável estiver desabilitada ou continuará se estiver definido (vazio ou qualquer valor).\unset
" ... Note-se que a citação de qualquer caractere funcionaria para evitar a expansão do alias, não apenas o primeiro.un"se"t
funcionaria tão bem, com menos legibilidade. "A primeira palavra de cada comando simples, se não estiver entre aspas, é verificada para ver se há um apelido." - Bash RefIsso. Se você executar um script em um ambiente desconhecido, todos os tipos de coisas podem dar errado, começando com
LD_PRELOAD
a execução do código do shell por um processo arbitrário antes mesmo de ele ler o script. Tentar se proteger contra um ambiente hostil de dentro do script é inútil.O Sudo desinfeta o ambiente removendo qualquer coisa que se parece com uma definição de função do bash há mais de uma década. Desde o Shellshock , outros ambientes que executam o shell script em um ambiente não totalmente confiável seguiram o exemplo.
Você não pode executar com segurança um script em um ambiente que foi definido por uma entidade não confiável. Portanto, preocupar-se com as definições de função não é produtivo. Higienize seu ambiente e, ao fazer isso, variáveis que o bash interpretaria como definições de função.
fonte
/bin/cat
um chroot pode estar chamando qualquer coisa.) A higienização do ambiente dá a você uma sensatezPATH
(supondo que você esteja fazendo o certo, é claro). Eu ainda não estou entendendo o seu ponto.Você pode usar
unset -f
para remover as funções internas, comando e tipo.fonte
unset() { true; }
cuida disso.