BPF : qu’est-ce que le Berkeley Packet Filter ?

Le Berkeley Packet Filter (BPF) ou Berkeley-Filter est intéressant pour tous les systèmes d’exploitation unixoïdes tels que Linux. L’action principale de la « machine virtuelle à usage spécial », développée en 1992, est de filtrer les paquets de données des réseaux et les intégrer dans le noyau du système d’exploitation. Le BPF constitue une interface pour la sauvegarde des couches d’unités de données ou de programmes. Les couches de sécurité ont pour tâche d’assurer la transmission fiable des paquets de données et de contrôler l’accès à ces paquets.

Lorsqu’un de ces paquets de données parvient au destinataire, le BPF lit les données des couches de sauvegarde du paquet et recherche les erreurs, par exemple. Cela permet au destinataire de les corriger. Il peut également comparer les données avec les définitions des filtres et ainsi accepter ou rejeter un paquet qui n’est pas considéré comme pertinent. Ceci peut permettre d’économiser beaucoup de capacité de calcul.

Comment fonctionne le Berkeley Packet Filter?

Pour intégrer ses fonctions, le Berkeley Packet Filter a été intégré comme interprète de langage machine au sein d’une machine virtuelle. En conséquence, le BPF exécute un format prédéfini d’instructions. En tant qu’interprète, le filtre de Berkeley lit les fichiers sources, les analyses et exécute instruction par instruction. Il traduit ensuite les instructions en code machine pour une exécution directe.

Le filtre de Berkeley utilise les SysCalls, qui sont des appels à des fonctions spécifiques du système, prêtes à l’emploi, afin de faire des requêtes au noyau. Le noyau vérifie les droits d’accès avant d’accepter ou rejeter la demande. Les quelques 330 Linux SysCalls sont les suivants :

  • read : autorisation de lecture, avec laquelle un fichier peut être lu
  • write : autorisation d’écrire, afin qu’un dossier puisse être écrit
  • open : les fichiers ou les dispositifs peuvent être ouverts
  • close : les fichiers ou les dispositifs peuvent être fermés
  • stat : le statut d’un dossier est récupéré
Note

Le Berkeley-Filter peut fonctionner à la fois en mode noyau (accès maximal aux ressources de la machine) et en mode utilisateur (accès limité aux ressources informatiques)

Avantages du Berkeley-Filter

Avec eBPF, vous pouvez filtrer les paquets de données pour éviter que des données non pertinentes ne ralentissent les performances de votre PC. Les enregistrements de données inutilisables ou incorrects peuvent ainsi être rejetés ou réparés dès le départ. En outre, le BPF étendu offre une sécurité accrue grâce aux SysCalls (appels systématiques) - vous pouvez facilement mesurer vos performances ou les suivre grâce aux appels du système.

En 2007 déjà, la mise en œuvre du BPF a été étendue par les « Zero copy buffer extensions ». Grâce à ces extensions, les pilotes de périphériques peuvent enregistrer les paquets de données capturés directement dans le programme sans avoir à copier les données au préalable.

Programmer des filtres avec BPF

En mode utilisateur, vous pouvez définir des filtres individuels pour l'interface du Berkeley-Filter à tout moment. Dans le passé, les codes correspondants étaient écrits manuellement et traduits en un bytecode BPF. Aujourd'hui, grâce au LLVM Clang Compiler, il est possible de traduire directement les bytecodes.

Les bibliothèques du noyau d'exploitation contiennent également des exemples de programmes qui simplifient la définition des programmes eBPF. Diverses fonctions d’aide vous simplifient le travail.

Les vérificateurs de sécurité de l'eBPF

L’exécution d’appels système dans le noyau est toujours associée à certains risques de sécurité et de stabilité. Avant qu’un eBPF SysCall ne se charge, il doit passer un certain nombre de contrôles :

  1. On vérifie tout d’abord si l’appel système a été interrompu et ne contient pas de boucles. Cela pourrait conduire à un crash du noyau. Le graphique de flux de contrôle du programme est vérifié pour trouver les déclarations inaccessibles qui ne sont pas chargées par la suite.
  2. Avant et après l’exécution d’une instruction, l’état de l’appel au système eBPF est vérifié. Cela permet de garantir que le BPF étendu ne fonctionne que dans les limites autorisées et n'accède pas aux données en dehors de la Sandbox. Il n’est pas nécessaire de vérifier chaque voie individuellement. Un sous-ensemble est généralement suffisant pour cela.
  3. Enfin, le type de SysCall est également défini. Cette étape est importante pour limiter les fonctions du noyau qui peuvent être appelées depuis le SysCall et les structures de données auxquelles on peut accéder. Par exemple, vous pouvez utiliser des appels système qui accèdent directement aux données par paquets du réseau.

Les types SysCall traitent en gros quatre fonctions : où le programme peut être joint, quelles fonctions d'aide du noyau peuvent être appelées, si les données par paquets du réseau sont accessibles directement ou non et quel type d’objet est transmis avec priorité dans un appel système.

Actuellement, les types de SysCall eBPF suivants sont pris en charge par le noyau :

  • BPF_PROG_TYPE_SOCKET_FILTER
  • BPF_PROG_TYPE_KPROBE
  • BPF_PROG_TYPE_SCHED_CLS
  • BPF_PROG_TYPE_SCHED_ACT
  • BPF_PROG_TYPE_TRACEPOINT
  • BPF_PROG_TYPE_XDP
  • BPF_PROG_TYPE_PERF_EVENT
  • BPF_PROG_TYPE_CGROUP_SKB
  • BPF_PROG_TYPE_CGROUP_SOCK
  • BPF_PROG_TYPE_LWT_ *
  • BPF_PROG_TYPE_SOCK_OPS
  • BPF_PROG_TYPE_SK_SKB
  • BPF_PROG_CGROUP_DEVICE