Работя върху библиотека за проследяване на паметта, където използваме 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.