
libtalloc est un script Python destiné à être utilisé avec GDB, qui permet d'analyser l'« allocateur trivial » (talloc).
libtalloc est un script Python destiné à GDB, qui peut être utilisé pour analyser l'« allocateur trivial » (talloc). Une introduction à talloc est disponible ici :
https://talloc.samba.org/talloc/doc/html/index.html
libtalloc s'inspire d'autres scripts Python pour gdb analysant les tas, comme unmask_jemalloc et libheap. Certaines fonctionnalités de base sont identiques à celles de ces projets.
https://github.com/cloudburst/libheap
https://github.com/argp/unmask_jemalloc
Veuillez noter que je ne suis pas un gourou de Python et que la qualité du code en témoigne. Si vous voyez quelque chose qui vous déplaît, n'hésitez pas à envoyer un correctif ou à me faire des suggestions. Tous les retours sont les bienvenus.
libtalloc a été testé sur plusieurs versions 2.x de talloc et prend en charge la détection dynamique de version afin de tenter de pallier les différentes différences structurelles entre les versions. Il a été testé en 32 bits et en 64 bits, mais pas de manière exhaustive, alors ne soyez pas surpris s'il casse de temps en temps.
Il a été testé dans une certaine mesure sur x86 et x64 :
Si vous le testez avec une autre version, merci de me dire si cela a fonctionné, ou ce qui a cassé, et j'essaierai de le mettre à jour et/ou de mettre à jour la documentation en conséquence.
Le script nécessite simplement une version relativement récente de GDB avec le support de Python.
Certaines distributions LTS, comme Ubuntu 12.04, utilisent encore GDB avec Python 2.7, tandis que les versions plus récentes comme 14.04 utilisent Python 3.0. J'ai essayé de faire fonctionner ce script avec les deux, vous devriez donc simplement avoir besoin de :
(gdb) source libtalloc.py
La plupart des fonctionnalités sont calquées sur l'approche d'unmask_jemalloc, où une commande GDB distincte est fournie plutôt qu'un ensemble complexe d'options.
Un certain nombre de méthodes conçues spécifiquement pour imiter les fonctions C de la bibliothèque talloc sont disponibles, afin d'aider ceux qui cherchent à étendre libtalloc s'ils sont déjà familiers avec la bibliothèque.
Pour voir la liste complète des commandes, vous pouvez lancer la commande tchelp :
(gdb) tchelp
[libtalloc] talloc commands for gdb
[libtalloc] tcchunk -v -x <addr> : show chunk contents (-v for verbose, -x for data dump)
[libtalloc] tcvalidate -a <addr> : validate chunk (-a for whole heap)
[libtalloc] tcsearch <addr> : search heap for hex value or address
[libtalloc] tcwalk <func> : walk whole heap calling func on every chunk
[libtalloc] tcreport <addr> : give talloc_report_full() info on memory context
[libtalloc] tcdump -s <addr> : dump chunks linked to memory context (-s for sorted by addr)
[libtalloc] tcparents <addr> : show all parents of chunk
[libtalloc] tcchildren <addr> : show all children of chunk
[libtalloc] tcinfo : show information known about heap
[libtalloc] tcprobe : try to collect information about talloc version
[libtalloc] tchelp : this help message
L'une des commandes les plus importantes est tcprobe. Elle doit être exécutée afin de déterminer quelle version de talloc est réellement installée. La disposition des structures peut varier considérablement selon les versions ; par conséquent, pour que la plupart des fonctions fonctionnent, la version doit être connue.
Si la commande fonctionne, elle devrait vous indiquer la version détectée :
(gdb) tcprobe
Version: 2.1.1
File: /usr/lib/libtalloc.so.2.1.1
La commande tcinfo est destinée à afficher autant d'informations que possible collectées sur le tas, comme les informations de tcprobe, la structure null_context si elle a été trouvée, et plus encore. Pour l'instant, elle n'affiche que la version et si null_context est défini. null_context est requis pour la plupart des fonctions qui parcourent réellement la hiérarchie, et pour le trouver, la plupart des autres fonctionnalités, comme tchunk, etc., tenteront de le localiser automatiquement.
Après avoir exécuté tcprobe mais avant d'utiliser réellement tchunk :
(gdb) tcinfo [libtalloc] null_context not yet found yet [libtalloc] Version: 2.0.7 [libtalloc] File: /usr/lib/i386-linux-gnu/libtalloc.so.2.0.7
Puis après avoir analysé un chunk, comme ceci :
(gdb) tcchunk 0xb94a52b0 WARNING: 0xb94a52b0 not a talloc_chunk. Assuming ptr to chunk data 0xb94a5280 sz:0x0000003c, flags:...., name:struct tevent_context
Vous pouvez confirmer qu'il a été trouvé après coup en utilisant tcinfo.
(gdb) tcinfo [libtalloc] null_context: 0xb94a5028 [libtalloc] Version: 2.0.7 [libtalloc] File: /usr/lib/i386-linux-gnu/libtalloc.so.2.0.7
Maintenant que null_context est défini, vous pouvez exécuter d'autres commandes qui se plaindraient normalement qu'il n'est pas défini, comme la commande tcsearch.
tcchunk peut vous fournir un résumé du chunk, une sortie plus verbeuse de chaque champ, ou des informations extrêmement verbeuses sur chaque chunk environnant.
NOTE : Un point important à noter à propos de tcchunk est qu'il utilise en interne la méthode tc_chunk(), qui tente de corriger les erreurs commises lors de la transmission de l'adresse du chunk. Plus précisément, si vous transmettez l'adresse des données du chunk lui-même et qu'il ne trouve pas la valeur magique talloc attendue, il recherchera un en-tête de chunk légitime un peu plus tôt en mémoire. Cela peut vous jouer des tours dans les scénarios de corruption, alors assurez-vous toujours de transmettre l'adresse explicite, sauf si vous effectuez une analyse superficielle.
Sortie du résumé :
(gdb) tcchunk 0x80a13c88
0x80a13c88 sz:0x00000020, flags:..p., name:struct netr_ServerPasswordSet
Voici une légende pour les chunks dans la sortie du résumé :
p - Member of a pool (POOLMEM flag)
P - Chunk is a pool (POOL flag)
F - Chunk is free (FREE flag)
L - Chunk is looped (LOOP flag)
Sortie verbeuse :
(gdb) tcchunk -v 0x80a13c88
struct talloc_chunk @ 0x80a13c88 {
next = 0x0
prev = 0x80a140c8
parent = 0x0
child = 0x80a14088
refs = 0x0
destructor = 0x0
name = 0x807d9f2f (struct netr_ServerPasswordSet)
size = 0x20
flags = 0xe8150c78 (POOLMEM)
limit = 0x0
pool = 0x80a13248
Les chunks talloc contiennent des valeurs magiques qui peuvent être utilisées pour valider leur intégrité. La commande tcvalidate analyse un chunk pour s'assurer que la valeur magique du chunk est celle attendue. De plus, elle analyse tous les autres pointeurs membres pour s'assurer qu'ils se trouvent bien dans des plages mémoire (telles que connues par gdb), que la taille est valide, etc.
(gdb) tcvalidate 0x80a13c88
Chunk header is valid
Nous allons utiliser une méthode intégrée pour modifier une valeur afin de montrer comment cela pourrait échouer :
(gdb) python set_destructor(tc_chunk(0x80a13c88), 0x41414141)
(gdb) tcchunk -v 0x80a13c88
struct talloc_chunk @ 0x80a13c88 {
next = 0x0
prev = 0x80a140c8
parent = 0x0
child = 0x80a14088
refs = 0x0
destructor = 0x41414141
name = 0x807d9f2f (struct netr_ServerPasswordSet)
size = 0x20
flags = 0xe8150c78 (POOLMEM)
limit = 0x0
pool = 0x80a13248
(gdb) tcvalidate 0x80a13c88
Chunk header is invalid:
0x80a13c88: Chunk has bad destructor pointer 0x41414141
tcparents peut être utilisé pour afficher tous les parents du chunk fourni :