2015-11-11 1 views
7

Je travaille sur un projet dans lequel je dois raccorder 80% -90% des fonctions d'appel système sur OSX (10.10.5). Je fais ceci à partir d'une extension de noyau. Comme je dois (dé) hooker beaucoup de fonctions, je veux stocker la fonction originale du noyau dans un tableau de pointeurs de fonction, pour que je puisse faire une recherche rapide dans le tableau afin de restaurer la fonction d'origine lors du décrochage.Stockage des fonctions SYSCALL dans un tableau de pointeurs de fonction

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; 

Cela fonctionne, la fonction kern_open est utilisée pour stocker la fonction du noyau original qui s fait appel à un appel système. mon_open est ma fonction d'accrochage.

Ce que je veux réaliser est le suivant; de sorte que lors du décrochage, je peux juste itérer à travers le tableau KernSysCall et restaurer les fonctions.

// 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; 

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

Cependant, le stockage de la fonction de noyau d'origine à l'intérieur de la matrice de pointeurs de fonctions est à l'origine d'une panique du noyau. Je n'ai pas encore pu attacher le lldb, en raison d'une erreur error: KDP_REATTACH failed. J'espère que quelqu'un sait ce qui cause la panique du noyau.

Vous trouverez ci-dessous un journal de la panique du noyau.

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] 

Dans la demande, le code de 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); 
} 

Merci beaucoup à l'avance!

+0

Une question raisonnablement bien écrite! Êtes-vous sûr que c'est la ligne 'KernSysCall [SYS_open] = sysent [SYS_open] .sy_call;' qui provoque la panique? (Je suppose que '[SYS_open]' dans la question devait être 'sysent [SYS_open]') – immibis

+0

Merci. C'est correct Je suis presque sûr à 100%. Déclarer le tableau statique ne provoque pas la panique. Faire la même chose avec des primitives (e.x. int) ne provoque pas de panique. Seulement quand j'attribue 'KernSysCall [SYS_open] = sysent [SYS_open] .sy_call;' Le reste est à peu près le même que l'horrible "sans tableau" solution. – Joseph

+0

Notez que DTrace modifie également le sy_call des différentes entrées sysent, donc si quelque chose dans votre système utilise DTrace, lui et votre hook peuvent marcher sur les orteils des autres. Est-ce qu'il plante sur * décharger * votre kext, ou décrochez-vous sans décharger? Avez-vous symbolisé la panique de votre noyau pour vérifier exactement ce qui se passe? (avec un argument noyau de 'keepsyms = 1' le noyau symbolisera le crash pour vous) Pour vous aider à diagnostiquer votre échec LLDB, vous allez devoir nous donner un peu plus d'informations sur votre configuration. – pmdj

Répondre

0

Étonnamment stupide, j'ai oublié de pointer kern_open (la valeur de retour de mon_open) au pointeur de fonction dans le tableau. kern_open était NULL, donc cela provoquait l'exception NULL -pointer. Maintenant, le tableau des pointeurs de fonction fonctionne correctement.

@pmdj, merci beaucoup pour votre aide.

+0

Content de l'avoir réparé. Heureux d'entendre que je n'aboyais pas complètement le mauvais arbre. :-) – pmdj

0

La ligne 0x0 dans le journal de panique indique qu'un pointeur de fonction NULL est appelé (plus probablement dans ce cas) ou que vous avez écrasé la pile et avez remplacé un pointeur de retour par NULL. Etes-vous sûr de ne pas "restaurer" les syscalls que vous n'avez jamais accrochés en premier lieu?

Pour que lldb fonctionne avec des machines virtuelles, les exigences dépendent des différents environnements de virtualisation. Avec VMWare Fusion, cela devrait fonctionner, en supposant que vous utilisiez le mode 'host-only network' ou le mode ponté. Avec VirtualBox, il n'a fonctionné qu'avec le périphérique réseau Virtio la dernière fois que j'ai essayé, et je ne pouvais pas le faire fonctionner sur Parallels, mais c'était il y a quelques années. Notez que si vous ajoutez un port série à votre machine virtuelle, en écrivant dans un fichier texte, vous pouvez vous connecter à kprintf() - cela peut vous aider ici car vous pouvez imprimer vos valeurs de pointeur lorsque vous accrochez et décrochez.

+0

La panique se produit lorsque ceux-ci sont exécutés: 'KernSysCall [SYS_open] = sysent [SYS_open] .sy_call; sysent [SYS_open] .sy_call = mon_open; Je ne fais que "restaurer" en déchargeant le kext. Comme je le fais manuellement, je sais que la restauration ne provoque pas la panique. Pourrait-il avoir à faire quelque chose avec un mauvais pointage de déréférencement? (Je suis un peu C-Noob). – Joseph

+0

Il plante parce qu'un processus (xpcproxy) fait un syscall, et qu'il appelle une fonction NULL, ou que la fonction appelée contient une erreur. Quel est le code de 'mon_open'? (Si vous préférez ne pas le poster, réduisez-le à quelque chose de minimal qui devrait encore fonctionner, c.-à-d. Appelez la fonction sauvegardée ptr, puis testez-la.) Votre déclaration de tableau me semble correcte mais difficile à dire car le pointeur de fonction C la syntaxe est confuse. Je 'typedef' le type de pointeur de fonction, puis déclarer le tableau comme un tableau de ces types, juste pour être sûr. – pmdj

+0

J'ai ajouté le code pour mon_open(), mais je doute fortement que le problème soit dans cette fonction, puisque la même fonction est utilisée dans la solution supérieure et fonctionne très bien. J'ai créé un typedef: 'typedef int (* kern_f) (struct proc *, struct args *, int *); static kern_f array [SYS_MAXSYSCALL]; 'et ensuite dans une autre fonction:' array [SYS_open] = sysent [SYS_open] .sy_call; ' – Joseph