/ / Как мога да направя системни повиквания да извикат моя манипулатор SIGSEGV, когато ми е дадена защитена памет? - linux, памет, системни повиквания, sigsegv

Как мога да осъществявам системни повиквания, призовавам моя SIGSEGV манипулатор при дадена защитена памет? - Linux, памет, системни повиквания, sigsegv

Работя върху библиотека за проследяване на паметта, където използваме mprotect за премахване на достъпа до по-голямата част от паметта на програмата и манипулатор SIGSEGV за възстановяване на достъпа до отделни страници, докато програмата ги докосне. Това работи чудесно през повечето време.

Проблемът ми е, че когато програмата извика системно повикване (да речем read) с памет, че моята библиотека не е отбелязала достъп, системното повикване просто връща -1 и задава errno да се EFAULT. Това променя поведението на програмите, които се тестват по странни начини. Бих искал да мога да възстановя достъпа до всяка страница памет, дадена на системно повикване, преди тя действително да премине към ядрото.

Моят настоящ подход е да създам обвивка завсяко системно повикване, което докосва паметта. Всяка обвивка ще докосне цялата памет, която му е дадена, преди да я предаде на реалния системен разговор. Изглежда, че това ще работи за обаждания, направени директно от програмата, но не и за тези, направени от libc (например, fread ще звънна read директно, без да използвам моята обвивка). Има ли по-добър подход? Как е възможно да се постигне това поведение?

Отговори:

5 за отговор № 1

Можеш да използваш ptrace(2) за да постигнете това. Позволява ви да наблюдавате даден процес и да получавате съобщения, когато се случат определени събития. За вашите цели вижте PTRACE_SYSCALL което ви позволява да спрете процеса при влизане и излизане от syscall.

Ще трябва да промените някои от вашата инфраструктура за проследяване на паметта, обаче, както ptrace работи така, че родителски процес наблюдава aдетски процес и що се отнася до детето, той няма видимост кога се наблюдава наблюдавано събитие. Като казахте това, трябва да можете да направите нещо по подобие на:

  • Настройване на ptrace родител и дете, наблюдение (поне) PTRACE_SYSCALL.
  • Процесът на детето прави системно повикване; и родителят е уведомен.
  • Родителят запазва исканата информация за syscall; и използва PTRACE_GETREGS и PTRACE_SETREGS да промените дъщерно състояние, така че вместо да извикате syscall; дъщерният процес извиква рутината "незащита на паметта".
  • Дете премахнете защитата на паметта "s it"; след това вдига SIGUSR1 или подобно, за да каже на контролиращия родител, че работата с паметта е завършена.
  • Родителски улов SIGUSR, използва PTRACE_SETREGS за възстановяване на предварително запазената информация за системния извикване и възобновяване на детето.
  • Детето възобновява и изпълнява първоначалния syscall.