[unix] .dtors는 쓰기 가능해 보이지만 segfault를 쓰려고 시도합니다.

이것은 우분투 9.04, 2.6.28-11 서버, 32 비트 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
$

시작되지 않은 경우 : gcc .dtors는 엘프 실행 파일에 소멸자 세그먼트를 작성합니다 main(). 이 테이블은 오랫동안 쓸 수 있었으며 필자의 경우에는 readelf출력 해야합니다 . 그러나 테이블에 쓰려고하면 segfault가 발생합니다.

읽기 전용 .dtors, plt로 최근에 움직 였다는 것을 알고 있지만 이해하지 못하는 readelf것은 segfault 와의 불일치 입니다.



답변

이러한 섹션은 GNU_RELRO (읽기 전용 재배치)로 표시됩니다. 즉, 동적 로더가 모든 재배치를 수정 한 직후 (로드 시간에 지연된 재배치가 없음) 해당 섹션을 읽기 전용으로 표시합니다. 대부분은 .got.plt다른 페이지에 있으므로 치료를받지 않습니다.

ld --verboseRELRO를 검색하면 다음과 유사한 링커 스크립트를 볼 수 있습니다 .

.got            : { *(.got) }
. = DATA_SEGMENT_RELRO_END (12, .);
.got.plt        : { *(.got.plt) }

이는 RELRO 섹션이 12 바이트로 끝나는 것을 의미합니다 .got.plt(동적 링커 기능에 대한 포인터는 이미 해결되었으므로 읽기 전용으로 표시 될 수 있음).

강화 된 젠투 프로젝트에는 http://www.gentoo.at/proj/en/hardened/hardened-toolchain.xml#RELRO 에 RELRO에 대한 문서가 있습니다.


답변

실제로 시스템의 어떤 부분이 책임이 있는지 알지 못하지만 왜 실패했는지 알 수 있습니다. .dtors바이너리에서 쓰기 가능으로 표시되어 있지만 ( .ctorsGOT 및 기타 몇 가지 와 함께) 바이너리 에서 메모리에 별도의 쓰기 불가능한 페이지에 매핑되는 것처럼 보입니다 . 내 시스템 .dtors에서 0x8049f14다음을 수행 하고 있습니다 .

$ readelf -S test
  [17] .ctors            PROGBITS        08049f0c 000f0c 000008 00  WA  0   0  4
  [18] .dtors            PROGBITS        08049f14 000f14 000008 00  WA  0   0  4
  [19] .jcr              PROGBITS        08049f1c 000f1c 000004 00  WA  0   0  4
  [20] .dynamic          DYNAMIC         08049f20 000f20 0000d0 08  WA  6   0  4
  [21] .got              PROGBITS        08049ff0 000ff0 000004 04  WA  0   0  4
  [22] .got.plt          PROGBITS        08049ff4 000ff4 00001c 04  WA  0   0  4
  [23] .data             PROGBITS        0804a010 001010 000008 00  WA  0   0  4
  [24] .bss              NOBITS          0804a018 001018 000008 00  WA  0   0  4

실행 파일을 실행하고 확인 /proc/PID/maps하면 다음이 표시됩니다.

08048000-08049000 r-xp 00000000 08:02 163678     /tmp/test
08049000-0804a000 r--p 00000000 08:02 163678     /tmp/test
0804a000-0804b000 rw-p 00001000 08:02 163678     /tmp/test

.data/ .bss여전히 자신의 페이지에 쓸 수 있지만 다른 페이지에는 쓸 0x8049000-0x804a000수 없습니다. 나는 이것이 커널의 보안 기능이라고 가정한다. W ^ X ; Linux에는 PaX 가 있지만 대부분의 커널에는 내장되어 있지 않습니다)

mprotect페이지의 메모리 내 속성을 변경할 수있는으로 해결할 수 있습니다 .

mprotect((void*)0x8049000, 4096, PROT_WRITE);

이로 인해 테스트 프로그램이 충돌하지 않지만 다른 함수의 주소로 .dtors( 0x8049f18) 의 끝 센티넬을 덮어 쓰려고 해도 해당 함수는 여전히 실행되지 않습니다. 그 부분은 알아낼 수 없습니다.

다른 사람이 페이지를 읽기 전용으로 만드는 책임이 무엇인지, 그리고 왜 수정 .dtors이 내 시스템에서 아무런 영향을 미치지 않는지 알고 싶습니다.


답변