Un système d'exploitation dispose de nombreux mécanismes de surveillance et de collecte de données permettant de suivre la viabilité des composants clés, la sécurité et les performances. Dans un vaste réseau informatique, la collecte de ce type de données est indispensable pour réagir rapidement à divers types d'événements et d'incidents.
Sur le plan architectural, cette tâche peut être réalisée de différentes manières, Linux Il existe un mécanisme de noyau BPF de bas niveau permettant d'implémenter du code arbitraire dans un espace privilégié. Il est utilisé par les modules Snort/Suricata pour filtrer le trafic entrant, et par tcpdump pour le supprimer avant qu'il n'atteigne la pile TCP/IP. Examinons l'algorithme de fonctionnement et les principaux avantages de cette solution !
Que sont BPF et eBPF ?
BPF (Berkley Packet Filter) est une machine virtuelle intégrée au noyau du système d'exploitation, permettant d'y charger du code arbitraire. L'algorithme de cette solution est lié aux événements système. Tout programme BPF ne sera lancé qu'après la survenue de l'événement auquel il est lié.
Les programmes sont généralement écrits en langage C à l'aide de bibliothèques et de fichiers d'en-tête spécifiques fournis par le projet LLVM et la communauté eBPF. Le fichier est ensuite compilé dans un fichier program.o et chargé dans le noyau via l'appel système bpf().

Il est important de souligner que l'objectif principal d'un programme BPF est la surveillance et le suivi des données d'entrée/sortie des fonctions de la bibliothèque/application, ainsi que le suivi des hooks système. Ceci est utile pour la collecte de statistiques, l'évaluation des performances et le développement de sous-systèmes de sécurité.
Sa version étendue est eBPF, qui a des fonctionnalités similaires, cependant, elle est présentée dans les versions ultérieures du noyau.
Comment fonctionnent les programmes et les objets bpf ?
Préinstallons les outils nécessaires pour générer des appels système liés à la pile bpf. Pour cela, saisissez la commande suivante :
dnf install bpftool bpftrace -y
Après avoir examiné les fonctionnalités et la syntaxe de l’outil à notre disposition :
bpftool
La gestion d'objets tels que les programmes BPF, les cartes BPF, les liens et le réseau est disponible.
Programmes BPF
Plusieurs types de programmes avec des mécanismes différents sont utilisés pour la surveillance et le traçage :
- uprobe - vous permet de créer des points d'arrêt dans n'importe quel processus de l'espace utilisateur, sans modifier le code source ;
- kprobe - utilisé pour tracer les événements dans le noyau et les modules, ne nécessite pas de points d'arrêt spéciaux dans le code ;
- points de trace - utilisés pour suivre les événements dans le noyau et les modules, nécessitent des points spéciaux dans le code ;
- perf_event - permet de collecter diverses métriques telles que le temps d'exécution de la fonction, l'utilisation des ressources (CPU, mémoire, etc.) et les analyser pour optimiser les performances.
Examinons de plus près le mécanisme à travers un exemple pratique de surveillance du processus d'authentification des utilisateurs. Nous utiliserons uprobe, qui nous permettra de nous connecter à une fonction de bibliothèque et de lire les données transférées. Examinons le chemin complet vers sshd :
nano /usr/lib/systemd/system/system/sshd.service 
Pour le démon, trouvons les bibliothèques qu'il charge, classiquement de nombreuses solutions utilisent PAM dans Linux:
ldd /usr/sbin/sshd 
PAM est également présent dans sshd ; nous l'utiliserons donc pour récupérer les identifiants. Examinons les fonctions internes pouvant contenir le processus d'authentification :
readelf -Ws /lib64/libpam.so.0 | grep auth 
Parmi les fonctions présentées, la plus intéressante est pam_get_authtok, qui utilise le jeton utilisateur. Utilisons bpftrace pour charger le programme et vérifier l'exactitude de la fonction trouvée :
bpftrace -e 'uprobe:/lib64/libpam.so.0:pam_get_authtok { printf(“target call execute\n”); }' 
Parfait, le programme BPF s'est exécuté car la fonction pam_get_authtok a été appelée et son contexte était disponible ! Cela signifie que le programme a pu extraire les informations d'identification de la fonction et les stocker.
Cartes BPF
Ici, on les appelle des cartes BPF ; elles stockent toutes les données sous la forme clé:valeur. Vous pouvez les visualiser avec la commande :
bpftool map show 
Le PID peut ensuite utiliser un appel système pour accéder aux cellules et exporter les identifiants ! Différents programmes BPF peuvent également communiquer avec les cartes. Il est donc important de comprendre que l'accès à ce type de mécanisme doit être restreint aux utilisateurs normaux.
Lier des objets
La communication entre un programme et un point de surveillance est possible grâce à l'objet Lien, vous pouvez visualiser les liens existants entre les programmes et les points de surveillance avec la commande :
bpftool link show
Le type d'attachement indique que les valeurs peuvent être modifiées par le programme pendant la transmission, et le traçage prog 2 indique que la trace appartient au programme avec l'ID 2. Voyons-le avec la commande :
bpftools prog show id 2 
Il modifie probablement les requêtes du périphérique d'interface humaine, il peut être vidé avec la commande :
bpftool dump xlated id 2
Nous obtenons ainsi les instructions désassemblées utilisées dans le programme. Ce type d'analyse est utile pour identifier des solutions malveillantes et comprendre le fonctionnement des mécanismes de surveillance de bas niveau tels que tcpdump et autres !
FAQ : BPF et eBPF dans Linux
- Q1 : Qu'est-ce que le BPF dans Linux?
A1 : BPF (Berkeley Packet Filter) est une machine virtuelle au niveau du noyau qui permet d'exécuter des programmes personnalisés déclenchés par des événements système. Elle est principalement utilisée pour la surveillance, le traçage et la collecte de statistiques sur les performances et la sécurité du système. - Q2 : Quelle est la différence entre BPF et eBPF ?
A2 : eBPF (BPF étendu) est une version améliorée de BPF disponible dans les systèmes modernes Linux noyaux. Il offre davantage de fonctionnalités, une plus grande flexibilité et permet d'exécuter des programmes en toute sécurité dans le noyau sans compromettre la stabilité. - Q3 : Comment fonctionnent les programmes BPF ?
A3 : Les programmes BPF sont généralement écrits en C et compilés dans des fichiers .o. Ils sont chargés dans le noyau via l'appel système bpf(). Les programmes ne s'exécutent que lorsqu'un événement spécifique se produit, tel qu'un appel système, un appel de fonction noyau ou un événement de processus utilisateur. - Q4 : Quels sont les principaux types de programmes BPF ?
A4 : Les types courants incluent :
uprobe - s'attache aux fonctions de l'espace utilisateur sans modifier le code source
kprobe - trace les fonctions et les modules du noyau
tracepoints - suit les événements à des points prédéfinis dans le code du noyau
perf_event - collecte des mesures de performance telles que CPU et l'utilisation de la mémoire - Q5 : Que sont les cartes et les liens BPF ?
A5 : Les cartes BPF stockent les données au format clé-valeur, ce qui permet la communication entre les programmes BPF. Les objets de liaison connectent les programmes BPF aux points de surveillance, contrôlant la façon dont ils lisent et modifient les données tracées. - Q6 : Quels sont les cas d’utilisation pratiques de BPF/eBPF ?
A6 : BPF est utilisé dans des outils comme tcpdump, Snort et Suricata pour le filtrage du trafic, la surveillance des appels système, l'analyse des performances et la création de solutions de sécurité. Il permet une collecte de données précise sans modifier le comportement du système. - Q7 : Le BPF est-il sûr à utiliser en tant qu'utilisateur régulier ?
A7 : L'accès aux mécanismes BPF doit être restreint. Une utilisation inappropriée peut exposer des données sensibles ou affecter la stabilité du système. Des privilèges d'administrateur sont généralement requis pour charger et gérer les programmes BPF.