2009-07-01 1 views
2

우리는 메모리 추적 라이브러리 인 mprotect을 사용하여 대부분의 프로그램 메모리에 대한 액세스를 제거하고 SIGSEGV 핸들러를 사용하여 개별 페이지가 프로그램에 접근 할 때 액세스를 복원하려고합니다. 이것은 시간의 대부분을 잘 작동합니다.보호 된 메모리가 주어지면 어떻게 시스템 호출이 내 SIGSEGV 핸들러를 호출하게 할 수 있습니까?

내 문제는 내 라이브러리가 아무런 액세스도 표시하지 않은 메모리가있는 시스템 호출 (예 : read)을 호출하면 시스템 호출이 -1을 반환하고 errnoEFAULT으로 설정한다는 것입니다. 이것은 이상한 방법으로 테스트중인 프로그램의 동작을 변경합니다. 나는 실제로 커널에 가기 전에 시스템 호출에 주어진 메모리의 각 페이지에 대한 액세스를 복원 할 수 있기를 원한다.

현재 나의 접근 방식은 메모리에 닿는 각 시스템 호출에 대한 래퍼를 만드는 것이다. 각 래퍼는 실제 시스템 호출에 전달하기 전에 주어진 모든 메모리를 건드립니다. 이것은 프로그램에서 직접 호출 한 경우에는 작동하지만 libc에서 호출 한 경우에는 작동하지 않는 것 같습니다 (예 : fread은 랩퍼를 사용하지 않고 read을 직접 호출합니다). 더 좋은 접근 방법이 있습니까? 어떻게이 행동을 취하는 것이 가능합니까?

+0

글쎄, 바보 같아. 시스템 호출에 잘못된 메모리를 부여 할 때 segfault 대신 EFAULT를 예상하는 사람은 누구입니까? : P 시스템 호출과 사용자 공간 함수 사이에 무작위적인 불일치처럼 보입니다 ... –

답변

5

이렇게하려면 ptrace(2)을 사용할 수 있습니다. 프로세스를 모니터하고 특정 이벤트가 발생할 때마다 알림을받을 수 있습니다. 귀하의 목적을 위해, PTRACE_SYSCALL을보고 syscall 입력 및 종료시 프로세스를 중지 할 수 있습니다.

그러나 메모리 추적 인프라의 일부를 변경해야합니다 (예 : ptrace). 부모 프로세스가 하위 프로세스를 모니터링하도록 운영되므로 하위 프로세스와 관련하여 모니터링되는 이벤트 발생합니다. 그런 말로하면, 당신은 :

  • (최소한) PTRACE_SYSCALL을 모니터링하는 설치 ptrace 부모와 자식의 라인을 따라 뭔가를 할 수 있어야합니다.
  • 하위 프로세스는 syscall을 수행합니다. 부모에게 통지됩니다.
  • 부모는 요청 된 syscall 정보를 저장합니다. syscall을 호출하는 대신 하위 상태를 변경하려면 PTRACE_GETREGSPTRACE_SETREGS을 사용합니다. 하위 프로세스는 '메모리 비보호'루틴을 호출합니다.
  • 아동 보호가 필요 없습니다. 그런 다음 SIGUSR1 또는 그와 비슷한 값을 올리면 제어 작업중인 부모에게 메모리 작업이 완료되었음을 알립니다.
  • 상위 캐치 SIGUSRPTRACE_SETREGS을 사용하여 이전에 저장된 syscall 정보를 복원하고 하위를 다시 시작합니다.
  • 자식은 orignal syscall을 다시 시작하고 실행합니다.
+0

http://lkml.org/lkml/2008/8/25/40 자신의 시스템 호출을 잡기 위해 ptrace를 허용하는 실험이있었습니다. ..하지만 네,이 다중 프로세스 댄스가 일반적으로 필요할 것입니다. – ephemient

+0

이것이 올바른 해결책이라고 생각하지만 지정된대로 작동하지 않습니다. 시스템 콜에서 자식을 중지 시키면 eip 값은 sysenter 명령어가 아닌 시스템 콜 리턴 포인트 (__kernel_vsyscall의 스택에서 꺼지는 레지스터)에서 발생합니다. 따라서 부모가 그것을 잡았을 때 시스템 호출은 이미 시작되었다 (그리고 실패 할 운명이다). 나는 그것이 돌아올 때 그것을 잡을 수 있으며, 보호되지 않는 루틴을 호출 한 다음 호출을 다시 시작합니다. –

+0

@ 제이 : 코드를 게시 할 수있는 기회가 있습니까? 당신은 실제로 syscall을 수행하기 전에 아이를 잡을 수 있어야합니다 ... – DaveR

관련 문제