Existe um mecanismo que protege aplicativos durante a atualização da biblioteca?

10

Se o usuário trabalha em um aplicativo que está vinculado dinamicamente e o sistema está sendo atualizado, existe algum mecanismo de proteção que evita a corrupção do aplicativo?

Ou depende da aplicação?

sevo
fonte
Lembre-se de ler um livro do Linux sobre como você deve usar ln -sfao trocar de bibliotecas, porque isso -fpermite que você "sobrescreva" o destino existente do link simbólico por um novo, sem que ele nunca seja "quebrado" (diferente de se você rmseguisse a ln -s) Portanto, antes do comando, library.so apontou para a versão antiga, por exemplo. library.so.4 ... após o comando, ele simplesmente apontou para library.so.5 (ou qualquer outro) em vez - sem nunca não apontando para uma biblioteca válido.
Baard Kopperud

Respostas:

16

Conforme mencionado por @Kusalananda, geralmente as atualizações são feitas removendo o arquivo antigo e criando um novo com o mesmo nome. Na verdade, isso criará um novo arquivo com um novo inode, deixando o sistema livre para usar o antigo enquanto estiver aberto.

Como um exemplo simplificado, coisas como

rm /bin/cat
cp /new/version/of/cat /bin/cat

criará um arquivo logicamente novo e funcionará mesmo que catesteja em execução. O mesmo vale para as bibliotecas. (O exemplo acima é um exemplo, não uma maneira robusta de atualizar um arquivo no mundo real.)


Alguém poderia tentar alterar o binário no local em vez de criar um novo com o mesmo nome. Nesse caso, pelo menos o Linux realmente impede fazer alterações em um executável em uso:

window 1 # ./cat
window 2 # echo foobar > cat
-bash: cat: Text file busy

No entanto, isso não parece funcionar com bibliotecas carregadas dinamicamente ...

Fiz uma cópia libc.so.6para teste e a preenchi com zeros enquanto estava em uso:

window 1 /tmp/lib# LD_LIBRARY_PATH=/tmp/lib ldd ./cat
    linux-vdso.so.1 (0x00007ffcfaf30000)
    libc.so.6 => /tmp/lib/libc.so.6 (0x00007f1145e67000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f1146212000)

window 1 /tmp/lib# LD_LIBRARY_PATH=/tmp/lib ./cat
foo
foo

Segmentation fault

(Enquanto isso, em outra janela, após o foo, antes do segfault)

window 2 /tmp/lib# dd if=/dev/zero of=libc.so.6 bs=1024 count=2000

Não há realmente nada que o próprio programa possa fazer contra isso, desde que efetivamente editei seu código online.

(Isso provavelmente dependerá do sistema, testei no Debian Jessie 8.5, Linux 3.16.7-ckt25-2 + deb8u3. Os sistemas Windows IIRC em particular são ainda mais agressivos ao impedir a modificação de arquivos em uso.)


Portanto, acho que a resposta é que as atualizações geralmente são feitas de maneira a evitar problemas, e isso é ajudado pelos componentes internos do sistema de arquivos. Mas (no Linux) não parece haver nenhuma proteção contra bibliotecas dinâmicas realmente corrompidas.

ilkkachu
fonte
O installutilitário é comumente usado para coisas como esta. Você não precisa explicitamente rmo arquivo de destino. Além disso, ele preserva as permissões do arquivo existente, pode fazer uma cópia de segurança, definir um novo modo, etc. Exemplo de uso:install /new/version/of/cat /bin/cat
Patrick
Certo. O rm+ cpfoi usado como exemplo. Também pode ser inteligente colocar o novo arquivo no lugar atomicamente com uma renomeação, para evitar uma pequena janela na qual nenhuma versão está disponível. (Embora GNU installnão parece mesmo fazer isso, hmpf.)
ilkkachu
2
Gostaria de esclarecer algo que está nesta resposta: No Unixes, se um arquivo estiver aberto e removido ( rm), ele ainda não será excluído. Ele existirá no disco e ainda poderá ser lido por todos os processos que o abrirem. Ele será excluído apenas quando a contagem de links físicos atingir zero E o número de precesses com o arquivo aberto atingir zero.
CTRL-ALT-DELOR
@ Patrick: O installutilitário é especificamente inseguro! Ele substitui o arquivo de destino no lugar, em vez de substituí-lo atomicamente. mv(com origem e destino no mesmo diretório, fonte geralmente um arquivo temporário) é a única maneira segura de instalar arquivos.
R .. GitHub Pare de ajudar o gelo
1
O @Patrick, tanto quanto o meu tell strace, installno GNU coreutils desvincula o arquivo de destino e depois copia um novo em seu lugar. O que significa que existe uma janela curta durante a qual o arquivo é parcial. Ele não define o arquivo atomicamente no lugar com uma renomeação.
24516 ilkkachu
3

Os arquivos não serão "excluídos corretamente" se forem desvinculados enquanto ainda estão abertos. Quando eles estiverem fechados, o espaço em disco que eles usaram será considerado "livre" novamente. Isso vale para aplicativos em execução no momento e suas bibliotecas compartilhadas também.

A única coisa que eu via falha seria se um programa usasse dlopen()uma biblioteca compartilhada sob demanda ou se o programa precisasse acessar outros arquivos sob demanda, como dicionários, arquivos de temas ou outros arquivos que desapareceram repentinamente.

Para ilustrar: A execução vimem uma sessão de shell e a instalação de vimoutra sessão de shell não "corromperão" nem encerrarão a vimsessão atualmente em execução . Mas algumas coisas começam a falhar, como a verificação ortográfica, por exemplo, que requer vima abertura de arquivos em sua instalação.

Kusalananda
fonte