Por que o bash analisa / executa coisas colocadas na variável de ambiente?

9

O bug do shellshock no bash funciona por meio de variáveis ​​de ambiente. Honestamente, fiquei surpreso pelo fato de existir um recurso como:

"transmissão de definições de funções via env vars"

Portanto, essa pergunta, embora talvez não esteja perfeitamente formulada, é pedir um exemplo ou um caso em que seria necessário ter esse recurso?

Bônus. Outros shells zsh, dash etc. também possuem esse recurso?

humanidade e paz
fonte
Ele usa os envários para transmitir as definições de função. O que você quer dizer com "Por que simplesmente não mantém as variáveis ​​de ambiente disponíveis / acessíveis?" ?
Anthon
@ Anthon Obrigado pelo comentário. Talvez eu deva ser mais claro e reformular. Por que razão é necessário poder passar as definições de função por meio de env?
humanityANDpeace
1
Não tenho 100% de certeza, mas acho que, por exemplo, é assim que o GNU parallelobtém as definições de funções distribuídas se invocar várias instâncias do bash. Se não, dessa forma, seria necessário gravá-los em um arquivo, para que cada instância invocada lesse e você tivesse que lidar com problemas como quando esse arquivo pode ser removido.
Anthon
2
esse tópico tem um pouco de história. funções exportadas, no entanto, são loucas . se você deseja que um novo shell herde os comandos executáveis ​​do shell antigo, você .dotcria o mesmo arquivo que o shell antigo fez. é assim que é feito - e isso faz sentido - ou você alimenta o novo shell com o arquivo como entrada quando execing. assim que for lido, o arquivo será armazenado em cache pelo kernel de qualquer maneira.
mikeserv
@mikeserv Eu entendi direito, que grande parte do shellshock está relacionada a esse recurso, que não é tão essencial assim?
humanityANDpeace

Respostas:

4

Quando um script chama outro script, as variáveis ​​do script pai podem ser exportadas e, em seguida, ficam visíveis no script filho. Exportar funções é uma generalização óbvia: exporte a função do pai, torne-a visível no filho.

O ambiente é a única maneira conveniente de um processo passar dados arbitrários para seus filhos. Os dados devem ser empacotados em cadeias que não contenham bytes nulos, o que não é uma dificuldade para as funções do shell. Existem outros métodos possíveis, como blocos de memória compartilhada ou arquivos temporários transmitidos por meio de descritores de arquivos, mas eles podem causar problemas com programas intermediários que não sabem o que fazer com eles ou os fechariam. Os programas esperam ser executados em um ambiente que contém variáveis ​​que eles não conhecem ou não se importam, para não substituí-las ou apagá-las.

A escolha de usar o nome da função como o nome da variável de ambiente é estranha. Por um lado, significa que uma variável exportada entra em conflito com uma função exportada com o mesmo nome.

As funções exportadas são um recurso antigo. Funções foram adicionadas ao shell Bourne no SVR2 e funções exportadas no shell Versão 8 lançadas no mesmo ano (1984). Nesse shell, variáveis ​​e funções usavam o mesmo espaço para nome. Não sei como funcionou a exportação de funções. O shell Heirloom é baseado em uma variante Bourne que possui funções, mas não as exporta.

O ATT ksh supostamente suporta funções de exportação, mas olhando para a fonte ou brincando com ela, não consigo ver isso, a partir do ksh93u.

env -i /usr/bin/ksh -c 'f=variable; f () { echo function; }; typeset -fx f; /usr/bin/env; ksh -c f'
_=*25182*/usr/bin/env
PWD=/home/gilles
SHLVL=1
A__z="*SHLVL
ksh: f: not found

Os clones de domínio público do Ksh (pdksh, mksh), dash e zsh não suportam funções de exportação.

Gilles 'SO- parar de ser mau'
fonte
1
obrigado! Portanto, sem exportar funções, a funcionalidade do recurso é perdida, mas existem alguns shell, como dash, zsh e pdksh etc. que não possuem essa funcionalidade, eu li isso corretamente?
humanityANDpeace
Mas quando eu exporto uma função no bash, ela entra em uma variável como BASH_FUNC_f%%=() { echo hi }. Por que o bash analisaria outras variáveis ​​de ambiente? Por que ele iria analisar BASH_FUNC_g%%quando estou apenas ligando f? (Aparentemente, pré-shellshock, a variável de ambiente foi chamado apenas de fou g- mas eu ainda estou querendo saber por que gteria sido analisado se eu não nunca chamar gno meu script)
metamórfica
@ Met É necessário examinar todas as variáveis ​​de ambiente para descobrir quais são as definições de funções. Ele poderia memorizar esse fato e evitar a análise do código de uma função até a primeira vez que for necessário, mas isso seria complexidade adicional para pouquíssimo ganho. É mais fácil ter apenas um tipo de função e não dois ("função normal" e "função de uma variável de ambiente que precisa de um pouco de análise").
Gilles 'SO- stop be evil'
Não está claro. Estou sugerindo que a coisa mais óbvia a ser feita seria quando, ao executar algo chamado f, (1) verificar uma função shell chamada f, (2) verificar uma variável de ambiente chamada fe tentar analisá-la, (3) verificar cada PATHcomponente para um executável chamado f. Como a análise de cada variável de ambiente como código do shell, na inicialização do shell, parece um design menos complicado?
Metamórfico
@ Metamórfico Você está sugerindo adicionar outra etapa que deve ser executada em todos os comandos. Você também teria que adicionar outra etapa ao definir ou indefinir funções (depois unset -f foo, o bash não deve mais procurar uma definição de função foono ambiente), ao listar funções (como você lida com declare -foutras coisas além de ler todas as variáveis ​​de ambiente?) e o que mais estiver pensando. Seu design só parece mais fácil porque você deixou de fora a maior parte. Por outro lado, fazer tudo na inicialização é um único pedaço de código e, depois disso, tudo simplesmente funciona.
Gilles 'SO- stop be evil'