2015-11-11 19 views
7

Pracuję nad projektem, w którym muszę podłączyć 80% -90% funkcji wywołania systemowego na OSX (10.10.5). Robię to z rozszerzenia jądra. Ponieważ muszę (nie) przechwytywać wiele funkcji, chcę zapisać oryginalną funkcję jądra w tablicy wskaźników funkcji, tak, żebym mógł szybko przejrzeć tablicę, aby przywrócić pierwotną funkcję po odhaczeniu.Przechowywanie funkcji SYSCALL w tablicy wskaźników funkcji

int (*kern_open)(struct proc *, struct open_args *, int *); 
    int mon_open(struct proc *p, struct open_args *uap, int *retval) { 
    kern_open = sysent[SYS_open].sy_call; 
    sysent[SYS_open].sy_call = mon_open; 

działa ta funkcja kern_open służy do przechowywania pierwotnej funkcji jądra, który nazywa po wywołania systemowego. mon_open jest moją funkcją zahaczania.

Co chcę osiągnąć, to co następuje; tak, że po odhaczeniu mogę po prostu wykonać iterację w tablicy KernSysCall i przywrócić funkcje.

// global array of function pointers that all have the same func def. 
    static int (*KernSysCall[SYS_MAXSYSCALL])(struct proc *, struct args *, int *); 
    KernSysCall[SYS_open] = sysent[SYS_open].sy_call; 
    sysent[SYS_open].sy_call = mon_open; 

przywracanie: sysent[SYS_open].sy_call = KernSysCall[SYS_open];

Jednak przechowywanie pierwotną funkcję jądra wewnątrz tablicy wskaźników funkcji powoduje paniki jądra. Nie udało mi się jeszcze dołączyć lldb z powodu błędu error: KDP_REATTACH failed. Mam nadzieję, że ktoś wie, co powoduje panikę jądra.

Poniżej znajduje się dziennik stanu paniki jądra.

Anonymous UUID:  052D64D2-A43C-99F8-D221-B591991E54AF 

Wed Nov 11 12:55:06 2015 

*** Panic Report *** 
panic(cpu 0 caller 0xffffff80093f0024): Kernel trap at 0x0000000000000000, type 14=page fault, registers: 
CR0: 0x0000000080010033, CR2: 0x0000000000000000, CR3: 0x00000000769bb018, CR4: 0x00000000001606e0 
RAX: 0x0000000000000000, RBX: 0xffffff80115e3fc0, RCX: 0x0000000000000001, RDX: 0xffffff80115e3fc0 
RSP: 0xffffff8068dabaf8, RBP: 0xffffff8068dabf50, RSI: 0xffffff80115e3f80, RDI: 0xffffff8010059cf0 
R8: 0xffffff7f8afaccdf, R9: 0xffffff8009ae2a18, R10: 0xffffff8009939740, R11: 0x0000000000000000 
R12: 0xffffff8010059cf0, R13: 0x0000000000000005, R14: 0xffffff80115e3f80, R15: 0xffffff801188b480 
RFL: 0x0000000000010282, RIP: 0x0000000000000000, CS: 0x0000000000000008, SS: 0x0000000000000010 
Fault CR2: 0x0000000000000000, Error code: 0x0000000000000010, Fault CPU: 0x0 VMM 

Backtrace (CPU 0), Frame : Return Address 
0xffffff8068dab790 : 0xffffff80092e4ed1 mach_kernel : _panic + 0xd1 
0xffffff8068dab810 : 0xffffff80093f0024 mach_kernel : _kernel_trap + 0x664 
0xffffff8068dab9e0 : 0xffffff800940de53 mach_kernel : trap_from_kernel + 0x26 
0xffffff8068daba00 : 0x0 
0xffffff8068dabf50 : 0xffffff800982c0c1 mach_kernel : _unix_syscall64 + 0x2f1 
0xffffff8068dabfb0 : 0xffffff800940e656 mach_kernel : _hndl_unix_scall64 + 0x16 

BSD process name corresponding to current thread: xpcproxy 
Boot args: debug=0x14e kext-dev-mode=1 -v keepsyms=1 kmem=1 

Mac OS version: 
14F27 

Kernel version: 
Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53 PDT 2015; root:xnu-2782.40.9~1/DEVELOPMENT_X86_64 
Kernel UUID: C75BDFDD-9F27-3694-BB80-73CF991C13D8 
Kernel slide:  0x0000000009000000 
Kernel text base: 0xffffff8009200000 
__HIB text base: 0xffffff8009100000 
System model name: VMware7,1 (Mac-66F35F19FE2A0D05) 

System uptime in nanoseconds: 251264993940 
last loaded kext at 249789197520: my.kext 1 (addr 0xffffff7f8afa9000, size 57344) 
last unloaded kext at 116769666233: com.apple.driver.AppleFileSystemDriver 3.0.1 (addr 0xffffff7f8aed3000, size 16384) 
loaded kexts: 
my.kext 1 

[more kexts here] 

Na żądanie kodu dla mon_open():

int 
mon_open(struct proc *p, struct open_args *uap, int *r) { 
    int error; 
    char processname[MAXCOMLEN+1]; 
    char intercepted_path[MAXPATHLEN]; 

    pid_t pid = proc_pid(p); 

    proc_name(pid, processname, sizeof(processname)); 

    size_t dummy = 0; 
    error = copyinstr((void *)uap->path, (void *)intercepted_path, MAXPATHLEN, &dummy); 
    if (!error) { 
     printf("[MYKEXT] open called with path: %s, PID: %d, processname: %s\n", intercepted_path, pid, processname); 
    } 

    return kern_open(p, uap, r); 
} 

Dziękuję bardzo z góry!

+0

Dość dobrze napisane pytanie! Jesteś pewien, że to linia 'KernSysCall [SYS_open] = sysent [SYS_open] .sy_call;' która powoduje panikę? (Zakładam, że '[SYS_open]' w pytaniu miało być 'sysent [SYS_open]') – immibis

+0

Dziękuję. To jest poprawne. Jestem prawie w 100% pewien. Deklaracja tablicy statycznej nie powoduje paniki. Wykonywanie tej samej operacji macierzowej z prymitywami (np. Int) nie wywołuje paniki. Dopiero gdy przypiszę 'KernSysCall [SYS_open] = sysent [SYS_open] .sy_call;' Reszta jest prawie taka sama jak brzydkie rozwiązanie "bez tablicy". – Joseph

+0

Zauważ, że DTrace zmienia także sy_call różnych wpisów sysent, więc jeśli cokolwiek w twoim systemie używa DTrace, to i twój hak może nadepnąć na palce u nóg. Czy to się rozbija * rozładowując * twój kext, czy odpinasz bez rozładowywania? Czy symbolizowałeś panikę w kernelu, aby dokładnie sprawdzić, co się dzieje? (z argumentem jądra 'keepsyms = 1' jądro wskaże ci awarię) Aby pomóc Ci zdiagnozować awarię LLDB, będziesz musiał podać nam trochę więcej informacji na temat twojej instalacji. – pmdj

Odpowiedz

0

Zadziwiająco głupi, zapomniałem wskazać kern_open (wartość zwracana mon_open) na wskaźnik funkcji w tablicy. kern_open był NULL, więc spowodowało to wyjątek NULL -pointer. Teraz tablica wskaźników funkcji działa poprawnie.

@pmdj, dziękuję bardzo za pomoc.

+0

Cieszę się, że to naprawiono. Miło mi było usłyszeć, że zupełnie nie szczekałem niewłaściwego drzewa. :-) – pmdj

0

Linia 0x0 w dzienniku paniki wskazuje, że wywoływany jest wskaźnik NULL (bardziej prawdopodobne w tym przypadku) lub zniszczyłeś stos i nadpisałeś wskaźnik powrotu NULL. Jesteś pewien, że nie "przywracasz" linków, na które nigdy się nie połączyłeś?

Aby lldb pracował z maszynami wirtualnymi, wymagania zależą od różnych środowisk wirtualizacji. W przypadku VMWare Fusion to powinno działać, zakładając, że używasz "sieci tylko do hosta" lub trybu mostowego. Dzięki VirtualBox działało to tylko z urządzeniem sieciowym Virtio ostatnim razem, kiedy próbowałem, i nie mogłem go uruchomić w ogóle na Parallels, ale to było kilka lat temu.

Należy pamiętać, że jeśli dodasz port szeregowy do maszyny wirtualnej, zapisując do pliku tekstowego, możesz zalogować się do tego przy użyciu kprintf() - może ci to pomóc, ponieważ możesz wydrukować wartości wskaźników podczas zahaczania i odczepiania.

+0

Występuje panika, gdy zostaną wykonane: 'KernSysCall [SYS_open] = sysent [SYS_open] .sy_call; sysent [SYS_open] .sy_call = mon_open; '. "Przywracam" tylko po rozładowaniu keksta. Ponieważ robię to ręcznie, wiem, że przywracanie nie powoduje paniki. Czy to możliwe, aby zrobić coś ze złą rozmową pointeru? (Jestem trochę C-noob). – Joseph

+0

To zawiesza się, ponieważ proces (xpcproxy) tworzy podsystem i wywołuje funkcję NULL lub wywoływana funkcja zawiera błąd. Jaki jest kod dla 'mon_open'? (Jeśli wolisz go nie publikować, zredukuj go do czegoś minimalnego, co powinno jeszcze zadziałać, tj. Przejdź do zapisanej funkcji ptr, a następnie przetestuj to.) Twoja deklaracja tablicowa wygląda mi na poprawną, ale trudno powiedzieć, ponieważ wskaźnik funkcji C Składnia jest myląca. Chciałbym 'typedef' typ wskaźnika funkcji, a następnie zadeklarować tablicę jako tablicę tych typów, aby mieć pewność. – pmdj

+0

Zgłaszałem kod dla mon_open(), ale bardzo wątpię, że problem dotyczy tej funkcji, ponieważ ta sama funkcja jest używana w górnym rozwiązaniu i działa dobrze. Stworzyłem typedef: 'typedef int (* kern_f) (struct proc *, struct args *, int *); statyczna tablica kern_f [SYS_MAXSYSCALL] ;, a następnie w innej funkcji: tablica [SYS_open] = sysent [SYS_open] .sy_call; ' – Joseph

Powiązane problemy