Como faço para forçar, de forma explícita e segura, o uso de um comando interno no bash

19

Há uma pergunta semelhante que lida com o cenário 'wrapping', no qual você deseja substituir, por exemplo, cd por um comando que chama o cd incorporado.

No entanto, à luz do shellshock et al e sabendo que o bash importa funções do ambiente, fiz alguns testes e não consigo encontrar uma maneira de chamar o cd do meu script com segurança.

Considere isso

cd() { echo "muahaha"; }
export -f cd

Qualquer script chamado neste ambiente usando cd será interrompido (considere os efeitos de algo como cd dir && rm -rf . ).

Existem comandos para verificar o tipo de comando (convenientemente chamado type ) e os comandos para executar a versão incorporada em vez de uma função ( builtin e command ). Mas, eis que, estes podem ser substituídos usando funções também

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 o bash a usar o comando incorporado, ou pelo menos detectar que um comando não está embutido, sem limpar todo o ambiente?

Percebo que, se alguém controla o seu ambiente, você provavelmente está ferrando mesmo assim, mas pelo menos para aliases você tem a opção de não chamar o alias inserindo um \ antes dele.

    
por falstro 05.03.2015 / 11:07

3 respostas

15

Olivier D está quase correto, mas você deve definir POSIXLY_CORRECT=1 antes de executar unset . POSIX tem uma noção de Especial Built-ins e bash suporta isso . unset é um desses recursos internos. Pesquise SPECIAL_BUILTIN em builtins/*.c na fonte bash de uma lista, ele inclui set , unset , export , eval e source .

$ unset() { echo muahaha-unset; }
$ unset unset
muahaha-unset
$ POSIXLY_CORRECT=1
$ unset unset

O rogue unset foi agora removido do ambiente, se você não selecionar command , type , builtin , então poderá continuar, mas unset POSIXLY_CORRECT se estiver contando com não-POSIX comportamento ou recursos avançados do bash.

Este não endereça aliases, então você deve usar \unset para ter certeza de que funciona no shell interativo (ou sempre, no caso de expand_aliases estar em vigor).

Para o paranoico, isso deve corrigir tudo, eu acho:

POSIXLY_CORRECT=1
\unset -f help read unset
\unset POSIXLY_CORRECT
re='^([a-z:.\[]+):' # =~ is troublesome to escape
while \read cmd; do 
    [[ "$cmd" =~ $re ]] && \unset -f ${BASH_REMATCH[1]}; 
done < <( \help -s "*" )

( while , do , done e [[ são palavras reservadas e não precisam de precauções.) Note que estamos usando unset -f para ter certeza de descomprimir funções, embora variáveis e funções compartilhem o mesmo espaço de nomes, é possível que ambas existam simultaneamente (graças a Etan Reisner). Nesse caso, descomplicar duas vezes também funcionaria. Você pode marcar uma função readonly, bash não impede que você desabilite uma função readonly até e incluindo o bash-4.2, o bash-4.3 impede você, mas ainda honra os comandos especiais quando POSIXLY_CORRECT está definido .

Um readonly POSIXLY_CORRECT não é um problema real, isto não é um booleano ou sinaliza sua presença ativa o modo POSIX, então se ele existir como um readonly você pode confiar nos recursos POSIX, mesmo se o valor está vazio ou 0. Você simplesmente precisará desfazer funções problemáticas de uma maneira diferente da acima, talvez com alguns recortes e colagens:

\help -s "*" | while IFS=": " read cmd junk; do echo \unset -f $cmd; done

(e ignore os erros) ou participe de outros scriptsobáticos .

Outras notas:

  • function é uma palavra reservada, pode ser aliada, mas não substituída por uma função. (Aliasing function é levemente problemático porque \function não é aceitável como uma maneira de contornar isso)
  • [[ , ]] são palavras reservadas, elas podem ter um alias (que serão ignoradas), mas não substituídas por uma função (embora as funções possam ser assim nomeadas)
  • (( não é um nome válido para uma função, nem um alias
por 05.03.2015 / 14:17
6

I realize if someone controls your environment you're probably screwed anyway

Sim, isso. Se você executar um script em um ambiente desconhecido, todos os tipos de coisas podem dar errado, começando com LD_PRELOAD fazendo com que o processo do shell execute um código arbitrário antes mesmo de ler seu script. Tentar proteger-se contra um ambiente hostil de dentro do script é inútil.

O Sudo vem higienizando o ambiente removendo qualquer coisa que se pareça com uma definição de função bash por mais de uma década. Desde 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 tenha sido definido por uma entidade não confiável. Então, se preocupar com definições de funções não é produtivo. Sanitize seu ambiente e, ao fazer isso, variáveis que o bash interpretaria como definições de função.

    
por 06.03.2015 / 01:05
1

Você pode usar unset -f para remover as funções incorporadas, comando e tipo.

    
por 05.03.2015 / 12:58

Tags