Cet article est l'article du 10ème jour du Linux Advent Calendar 2016.
Uprobes utilisables depuis ftrace, eBPF / bcc, Systemtap, etc. Je ne trouve pas d'exemple (module du noyau) qui puisse être exécuté par des uprobes seuls comme kprobes. Donc, Noël est proche, donc cette fois, je vais vous présenter un échantillon d'uprobes que tout le monde peut facilement utiliser (je ne dis pas que vous devriez vous sentir libre de faire un module de noyau). L'explication détaillée de l'implémentation est omise, mais l'instruction correspondante est réécrite en 0xcc et ignorée.
Distribution: Ubuntu 16.04 Noyau utilisé pour l'investigation et la vérification: 4.4.0-45-generic
uprobes est un mécanisme du noyau Linux qui sonde les processus utilisateur à partir de l'espace noyau. Les uprobes sont généralement utilisés à partir d'interfaces configurables dans l'espace utilisateur telles que ftrace Un module du noyau qui utilise des uprobes est généré à partir d'un script unique comme Systemtap, et y est utilisé.
Puisque Noël approche de cette heure, j'écrirai un module noyau pour un contact direct avec les uprobes.
Tout d'abord, jetons un coup d'œil à l'API côté noyau pour utiliser le mécanisme uprobes.
/*
* uprobe_register - register a probe
* @inode: the file in which the probe has to be placed.
* @offset: offset from the start of the file.
* @uc: information on howto handle the probe..
*
* Apart from the access refcount, uprobe_register() takes a creation
* refcount (thro alloc_uprobe) if and only if this @uprobe is getting
* inserted into the rbtree (i.e first consumer for a @inode:@offset
* tuple). Creation refcount stops uprobe_unregister from freeing the
* @uprobe even before the register operation is complete. Creation
* refcount is released when the last @uc for the @uprobe
* unregisters.
*
* Return errno if it cannot successully install probes
* else return 0 (success)
*/
int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
On peut voir que les informations qui doivent être définies sont à peu près l'inode du fichier cible de la sonde, le décalage de la cible de la sonde du fichier de la cible de la sonde et le gestionnaire à exécuter lorsque la sonde est effectuée.
Ensuite, regardons la structure uprobe_consumer qui définit la fonction au moment de la sonde.
struct uprobe_consumer {
int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs);
int (*ret_handler)(struct uprobe_consumer *self,
unsigned long func,
struct pt_regs *regs);
bool (*filter)(struct uprobe_consumer *self,
enum uprobe_filter_ctx ctx,
struct mm_struct *mm);
struct uprobe_consumer *next;
};
A partir de la définition de la structure uprobe_consumer, on peut voir que la structure pt_regs est passée via le gestionnaire au moment de la sonde.
Cette fois, exécutez l'exemple d'application C approprié ci-dessous pour analyser l'appel de fonction debuggee_func.
#include <stdio.h>
int debuggee_func(int a, int b)
{
int result;
result = a + b;
return result;
}
void main()
{
int result;
result = debuggee_func(1, 2);
printf("result: %d", result);
}
Ensuite, l'exemple de module de noyau qui utilise des uprobes est placé ci-dessous. Veuillez vérifier l'exemple de code ci-dessous pour un traitement tel que la conversion du chemin du fichier en inode.
https://github.com/kentaost/uprobes_sample/blob/master/uprobes_sample.c
Le DEBUGGEE_FILE suivant dans cet exemple de module de noyau uprobes représente le fichier à déboguer et DEBUGGEE_FILE_OFFSET représente le décalage. Le décalage est obtenu à partir de l'adresse de la fonction cible et de l'adresse de début du segment de texte pour le binaire cible en utilisant readelf ou analogue. Dans mon environnement, la fonction debuggee_func était 0x526 (0x400526 --0x400000), j'ai donc intégré cette valeur et l'ai créée.
#define DEBUGGEE_FILE "/home/kentaost/debuggee_app"
#define DEBUGGEE_FILE_OFFSET (0x526)
Après avoir insmodé cet exemple de module de noyau, exécutez l'exemple d'application et regardez dmesg, et vous verrez des preuves de sondage comme indiqué ci-dessous.
…
[xxxx.xxxxxx] handler is executed
[xxxx.xxxxxx] ret_handler is executed
Comme vous pouvez le voir dans la fonction uprobe_register, ce n'est pas un mécanisme pour définir la sonde pour chaque processus utilisateur. Par exemple, on peut voir que même si le même programme est lancé plusieurs fois, il sera sondé.
En passant, si vous faites de votre mieux, vous pouvez préparer une trace de la pile de l'espace utilisateur comme le robinet Système ci-dessous. (Systemtap prépare le tapset pour que vous n'ayez pas à travailler dur, donc utilisez généralement Systemtap et tapset)
http://qiita.com/kentaost/items/a2e882d2978fba9e17d3
Bien que cette fois-ci omis, si vous comprenez également l'implémentation interne des uprobes, vous pouvez comprendre le comportement lors de l'analyse d'un processus utilisateur avec Systemtap etc. (lors de l'utilisation d'uprobes). Il n'y a aucune utilité pour une utilisation directe, mais vous devez utiliser ftrace et Systemtap docilement sauf pour Noël.
Recommended Posts