Este é o Ubuntu 9.04, 2.6.28-11-server, 32bit x86
$ cat test.c
main() { int *dt = (int *)0x08049f18; *dt = 1; }
$ readelf -S ./test
...
[18] .dtors PROGBITS 08049f14 000f14 000008 00 WA 0 0 4
...
$ ./test
Segmentation fault
$
Para os não iniciados: gcc cria um segmento destruidor .dtors
, no executável elf, chamado após main()
saídas. Esta tabela tem sido gravável e parece que deveria estar no meu caso (consulte a readelf
saída). Mas tentar gravar na tabela causa um segfault.
Sei que tem havido um movimento em direção a médicos, somente leitura, recentemente, mas o que não entendo é a incompatibilidade entre o readelf
e o segfault.
memory
gcc
segmentation-fault
Fixee
fonte
fonte
Respostas:
Essas seções são marcadas como GNU_RELRO (realocações somente leitura), o que significa que, assim que o carregador dinâmico for consertado (no momento do carregamento, não houver realocações preguiçosas), todas as relocações serão marcadas como somente leitura. Observe que a maioria
.got.plt
está em outra página, portanto não recebe o tratamento.Você pode ver o script do vinculador
ld --verbose
, se procurar por RELRO, encontrará algo semelhante a:o que significa que as seções RELRO terminam com 12 bytes
.got.plt
(os ponteiros para as funções do vinculador dinâmico já estão resolvidos e podem ser marcados como somente leitura).O projeto Gentoo reforçado possui alguma documentação sobre o RELRO em http://www.gentoo.at/proj/en/hardened/hardened-toolchain.xml#RELRO .
fonte
Eu posso dizer por que está falhando, embora eu realmente não saiba qual parte do sistema é responsável. Embora
.dtors
esteja marcado como gravável no binário, parece que ele (junto com.ctors
o GOT e algumas outras coisas) está sendo mapeado em uma página separada, não gravável na memória. No meu sistema,.dtors
está sendo colocado em0x8049f14
:Se eu executar o executável e verificar
/proc/PID/maps
, vejo:.data
/.bss
ainda são graváveis em sua própria página, mas os outros0x8049000-0x804a000
não. Eu assumo que este é um recurso de segurança no kernel (como você disse, "houve um movimento em direção a somente .dtors, plt, recentemente)", mas não sei especificamente o que é chamado (o OpenBSD tem algo muito semelhante chamado W ^ X ; o Linux possui PaX , mas não está embutido na maioria dos kernels)Você pode contornar isso
mprotect
, o que permite alterar os atributos na memória de uma página:Com isso, meu programa de teste não falha, mas se eu tentar sobrescrever o sentinela final de
.dtors
(0x8049f18
) pelo endereço de outra função, essa função ainda não será executada; essa parte eu não consigo descobrir.Espero que alguém saiba o que é responsável por tornar a página somente leitura e por que modificar
.dtors
não parece fazer nada no meu sistemafonte
mprotect
não puder tornar uma página executável gravável ou executável antes, a menos que esse recurso esteja desativadopaxctl -m
.