2011-10-08 2 views
4

dlopen() 내부에서 발생하는 모든 파일 시스템 액세스를 차단하려고합니다. 처음에는 실행 가능한 솔루션이 될 것입니다 LD_PRELOAD 또는 -Wl,-wrap,처럼 보일 것입니다,하지만 때문에 몇 가지 기술적 인 이유에 작업에 어려움이 있었다 :dlopen() 내부에서 파일 시스템 액세스를 차단하는 방법은 무엇입니까?

  • ld.so 이미 시간 LD_PRELOAD에 의해 자신의 문자 매핑 한 것입니다 처리됨. 초기 로딩을 가로채는 것은 중요하지 않지만, 지금은 _dl_* 작업자 기능이 해결되므로 이후 호출이 처리됩니다. 나는 LD_PRELOAD이 너무 늦었다 고 생각한다.

  • 은 어떻게 든 malloc는 그냥 memset()를 호출 ld.so의 내부 malloc()이 기능 free()이 없기 때문에 위의 문제를 우회.

  • 파일 시스템 작업자 기능. 에 포함 된 __libc_read()은 정적이므로 -Wl,-wrap,__libc_read으로 차단할 수 없습니다.

이 모두 내 자신의 ld.so 직접 소스 대신 래퍼로 연결로 구축 할 필요가 있음을 의미 할 수 있습니다. 도전 과제는 동일한 소스에서 libcrtld-libc을 모두 구축하는 것입니다. 나는 IS_IN_rtld 매크로가 rtld-libc을 빌드 할 때 정의되었지만 공용 인터페이스 함수를 내보내는 동안 정적 데이터 구조의 사본이 하나만 있다는 것을 어떻게 보장 할 수 있습니까? (이것은 glibc 빌드 시스템 질문이지만,이 세부 사항에 대한 문서를 찾지 못했습니다.) dlopen()에 들어가는 더 좋은 방법이 있습니까?

참고 : 과 같은 Linux 전용 솔루션을 사용할 수 없습니다. 이는 이러한 것들을 지원하지 않는 최소한의 "계산 노드"커널 용이기 때문입니다. 그것은 정적 링크시에만 작동하고 ld.so :

+0

이것은 귀하의 질문에 대한 답변이 아니기 때문에 하나의 게시자는 아니지만 일반적으로 신뢰할 수있는 방법은 아닙니다. 파일 시스템을 직접 호출하지 않고 syscall을 호출하여 파일 시스템에 접근 할 수 있습니다. 동적 라이브러리 인터페이스. 로드하려는 라이브러리가 컴파일 된 방법에 대한 절대적인 제어 권한이없는 경우 운이 좋지 않을 수 있습니다. 이 기술을 사용하는 fakeroot와 같은 프로그램은 대부분의 경우 잘 작동하며 일부 상황에서는 무시 무시합니다. –

+0

즉, 자신의 프로세스에서 동적 라이브러리 코드를 실행하고'ptrace '를 사용하여 시스템 호출을 가로채는 방식으로이 작업을 할 수 있습니다. 나는 큰 성공을 거두었고 공유 된 모든 라이브러리의 말도 안되는 것을 완전히 피할 수있었습니다. 하지만 ptrace 항목을 수행하는 마스터 프로세스와 동적 라이브러리 항목을 처리하는 종속 프로세스를 갖기 위해서는 논리를 완전히 다시 설계해야합니다. –

+0

음, 제대로 작동하려면'dlopen' /'dlsym'이 필요하지만, 파일 시스템에 다르게 접근해야합니다. 특히 Blue Gene과 같은 HPC 환경에서는 커널 파일 디스크립터와 관련된 모든 작업이 컴퓨팅 노드 IO 노드에서 제공됩니다. 이로 인해 높은 노드 동시성에서 심각한 경합 문제가 발생합니다. 예를 들어 컴파일 된 공유 라이브러리를 참조하는 Python 응용 프로그램을로드하면 65k 코어에서 약 4 시간이 소요됩니다. 말할 것도없이, 사람들은 그들의 프로그램을로드하기 위해 4 천 5 백만의 핵심 시간을 태우는 것에 대해 흥분하지 않습니다. – Jed

답변

3

이 LD_PRELOAD 또는 -Wl처럼 보일 것이다 -wrap, 실행 가능한 솔루션

--wrap 솔루션을 가능하게 가능한 수 없습니다 것 libc.so.6libdl.so.2은 모두 이미 연결되었으므로 이제는 --wrap을 사용하기에는 너무 늦었습니다.

LD_PRELOAD은 ... 은 내부 구현 세부 사항이입니다. 따라서, PLT을 우회하는 내부 __open 함수를 호출하고 open을 삽입 할 수 있습니다. libc은 (디버깅 목적으로, 예를 들어) 자신의 malloc 구현하는 사용자를 지원하기 때문에

은 어떻게 든 malloc에이야 문제

을 우회. 따라서 예를 들어 은 dlopen에서 PLT을 거치며 LD_PRELOAD을 통해 삽입 할 수 있습니다.

이 모든 것은 랩퍼에 연결하지 않고 소스에서 직접 내 자신의 ld.so를 빌드해야한다는 것을 의미합니다.

ld.so은 무엇을 다시 작성합니까? 나는 당신이 __llibc_open (libc.so.6)에 전화하기를 원한다고 생각하지만, 분명한 이유 때문에 작동하지 않을 수도 있습니다. ld.soopenlibc.so.6 (프로세스 시작시)입니다.

에 대한 호출로 대체 된 __open에 대한 호출로 ld.so을 다시 작성할 수 있습니다. 그러면 ld.soPLT을 거쳐 LD_PRELOAD 개재로 노출됩니다.

당신이 그 경로를가는 경우, 당신은 새로운 복사본으로 시스템 ld.so을 덮어 쓰지 않는 것이 좋습니다 (실수로 시스템을 부팅 할 수없는 기회가 너무 많음). 대신, 예를 들어 /usr/local/my-ld.so을 입력 한 다음 바이너리를 -Wl,--dynamic-linker=/usr/local/my-ld.so으로 연결하십시오.

다른 대안 : 런타임 패치. 이것은 조금은 해킹이지만, 일단 주 제어를 얻으면 .textld.so으로 스캔하고 CALL __open 명령어를 찾으십시오. ld.so을 제거하지 않은 경우 내부 __open과 패치 할 기능 (예 : open_verify : dl-load.c)을 모두 찾을 수 있습니다. 흥미로운 CALL, mprotect을 포함하고있는 페이지가 쓰기 가능하고 자신의 인터 포저 (해당되는 경우 __libc_open)에 주소를 패치 한 다음 mprotect을 다시 찾습니다. 앞으로 모든 dlopen()은 인터 포저를 통과하게됩니다.

+0

첫 번째 아이디어는 유용하지만'dlopen()'에서'PLT' 호출로 전환하면 segfaults가 발생하므로 두 번째 옵션을 살펴 보겠습니다 ... –