To jest 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
$
Dla niewtajemniczonych: gcc tworzy segment destruktora .dtors
w pliku wykonywalnym elfa, który jest wywoływany po main()
wyjściu. Ta tabela od dawna jest zapisywalna i wygląda na to, że powinna być w moim przypadku (patrz readelf
dane wyjściowe). Ale próba zapisu do tabeli powoduje awarię.
Zdaję sobie sprawę, że ostatnio nastąpił ruch w kierunku readonly .dtors, plt, ale nie rozumiem, co to jest rozbieżność między readelf
segfault.
memory
gcc
segmentation-fault
Fixee
źródło
źródło
Odpowiedzi:
Sekcje te są oznaczone GNU_RELRO (relokacje tylko do odczytu), co oznacza, że jak tylko dynamiczny moduł ładujący naprawi się (w czasie ładowania nie ma tam leniwych relokacji) wszystkie relokacje, oznacza to, że sekcje są tylko do odczytu. Pamiętaj, że większość z nich
.got.plt
znajduje się na innej stronie, więc nie otrzymujesz leczenia.Możesz zobaczyć skrypt linkera
ld --verbose
, jeśli szukasz RELRO, znajdziesz coś podobnego do:co oznacza, że sekcje RELRO kończą 12 bajtów na
.got.plt
(wskaźniki funkcji dynamicznego linkera są już rozwiązane, więc można je oznaczyć jako tylko do odczytu).Projekt hartowanego Gentoo zawiera dokumentację dotyczącą RELRO pod adresem http://www.gentoo.at/proj/en/hardened/hardened-toolchain.xml#RELRO .
źródło
Mogę powiedzieć, dlaczego zawodzi, chociaż tak naprawdę nie wiem, która część systemu jest odpowiedzialna. Chociaż
.dtors
jest zapisany w pliku binarnym, wygląda na to, że (wraz z.ctors
GOT i kilkoma innymi rzeczami) jest mapowany na osobną, nie zapisywalną stronę w pamięci. W moim systemie.dtors
ustawia się na0x8049f14
:Jeśli uruchomię plik wykonywalny i sprawdzę
/proc/PID/maps
, zobaczę:.data
/.bss
są nadal zapisywalne na własnej stronie, ale inni na0x8049000-0x804a000
nich nie. Zakładam, że jest to funkcja bezpieczeństwa w jądrze (jak powiedziałeś: „nastąpił ruch w kierunku readonly .dtors, plt, ostatnio”), ale nie wiem dokładnie, jak się nazywa (OpenBSD ma coś bardzo podobnego o nazwie W ^ X ; Linux ma PaX , ale nie jest wbudowany w większość jąder)Możesz obejść to za pomocą
mprotect
, co pozwala zmienić atrybuty strony w pamięci:Dzięki temu mój program testowy nie ulega awarii, ale jeśli spróbuję zastąpić końcową wartę
.dtors
(0x8049f18
) adresem innej funkcji, funkcja ta nadal się nie uruchamia; tej części, której nie mogę zrozumieć.Mam nadzieję, że ktoś inny wie, co jest odpowiedzialne za wykonanie strony tylko do odczytu i dlaczego modyfikowanie
.dtors
wydaje się nie robić nic w moim systemieźródło
mprotect
nie może sprawić, by strona wykonywalna była zapisywalna lub uczynić stronę wykonywalną, która była wcześniej zapisywalna, chyba że ta funkcja zostanie wyłączona za pomocąpaxctl -m
.