Manuel de surveillance BPF pour Linux

imageBonjour les Habitants! La machine virtuelle BPF est l'un des composants les plus importants du noyau Linux. Son application intelligente permettra aux ingénieurs système de détecter les pannes et de résoudre les problèmes les plus complexes. Vous apprendrez à écrire des programmes qui surveillent et modifient le comportement du noyau, serez capable d'injecter du code en toute sécurité pour observer les événements dans le noyau, et bien plus encore. David Calavera et Lorenzo Fontana vous aideront à libérer la puissance de BPF. Développez vos connaissances sur l'optimisation des performances, la mise en réseau et la sécurité. - Utilisez BPF pour suivre et modifier le comportement du noyau Linux. - Injectez du code pour surveiller en toute sécurité les événements dans le noyau - sans avoir besoin de recompiler le noyau ou de redémarrer le système. - Utilisez des exemples de code pratiques en C, Go ou Python. - Gérer la situation en s'appropriant le cycle de vie du programme BPF.





Sécurité du noyau Linux, fonctionnalités et Seccomp



BPF fournit un moyen puissant d'étendre le noyau sans compromettre la stabilité, la sécurité ou la vitesse. Pour cette raison, les développeurs du noyau ont pensé que ce serait une bonne idée de tirer parti de sa polyvalence pour améliorer l'isolation des processus dans Seccomp en implémentant des filtres Seccomp pris en charge par les programmes BPF alias Seccomp BPF. Dans ce chapitre, nous expliquerons ce qu'est Seccomp et comment il est appliqué. Ensuite, vous apprendrez à écrire des filtres Seccomp à l'aide de programmes BPF. Après cela, regardons les hooks BPF intégrés que le noyau a pour les modules de sécurité Linux.



Les modules de sécurité Linux (LSM) sont une plate-forme qui fournit un ensemble de fonctions pouvant être utilisées pour standardiser la mise en œuvre de divers modèles de sécurité. LSM peut être utilisé directement dans l'arborescence des sources du noyau comme Apparmor, SELinux et Tomoyo.



Commençons par discuter des fonctionnalités de Linux.



Capacités



L'essence des capacités de Linux est que vous devez accorder à un processus non privilégié l'autorisation d'exécuter une tâche spécifique, mais sans suid à cette fin, ou rendre le processus privilégié, réduisant ainsi la possibilité d'attaques et permettant au processus d'effectuer certaines tâches. Par exemple, si votre application doit ouvrir un port privilégié, disons 80, au lieu d'exécuter le processus en tant que root, vous pouvez simplement lui donner la capacité CAP_NET_BIND_SERVICE.



Considérez un programme Go nommé main.go:



package main
import (
            "net/http"
            "log"
)
func main() {
     log.Fatalf("%v", http.ListenAndServe(":80", nil))
}


Ce programme sert un serveur HTTP sur le port 80 (c'est un port privilégié). Nous l'exécutons généralement juste après la compilation:



$ go build -o capabilities main.go
$ ./capabilities


Cependant, comme nous n'accordons pas de privilèges root, ce code générera une erreur lors de la liaison du port:



2019/04/25 23:17:06 listen tcp :80: bind: permission denied
exit status 1


capsh (outil de contrôle du shell) est un outil qui lance un shell avec un ensemble spécifique de capacités.


Dans ce cas, comme déjà mentionné, au lieu d'accorder des privilèges root complets, vous pouvez activer les liaisons de port privilégiées en activant cap_net_bind_service avec tout ce qui est déjà dans le programme. Pour ce faire, nous pouvons envelopper notre programme en capsh:



# capsh --caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' \
   --keep=1 --user="nobody" \
   --addamb=cap_net_bind_service -- -c "./capabilities"


Comprenons un peu cette commande.



  • capsh - utilise capsh comme shell.
  • --caps = 'cap_net_bind_service + eip cap_setpcap, cap_setuid, cap_setgid + ep' - puisque nous devons changer d'utilisateur (nous ne voulons pas exécuter en tant que root), nous allons spécifier cap_net_bind_service et la possibilité de changer l'ID utilisateur de root à personne, à savoir cap_setuid et cap_setgid ...
  • --keep=1 — , root.
  • --user=«nobody» — , , nobody.
  • --addamb=cap_net_bind_service — root.
  • — -c "./capabilities" — .


— , , execve(). , , , , .


Vous vous demandez probablement ce que signifie + eip après avoir spécifié une capacité dans l'option --caps. Ces drapeaux sont utilisés pour spécifier que la fonction:



-doit être activée (p);



-disponible pour l'application (e);



-peut être hérité par les processus enfants (i).



Puisque nous voulons utiliser cap_net_bind_service, nous devons le faire avec l'indicateur e. Ensuite, nous démarrons le shell dans la commande. Cela lancera le binaire des capacités et nous devons le marquer avec le drapeau i. Enfin, nous voulons que la fonctionnalité soit activée (nous l'avons fait sans changer l'UID) avec p. Cela ressemble à cap_net_bind_service + eip.



Vous pouvez vérifier le résultat avec ss. Réduisez un peu la sortie pour l'adapter à la page, mais elle affichera le port associé et l'ID utilisateur autres que 0, dans ce cas 65 534:



# ss -tulpn -e -H | cut -d' ' -f17-
128 *:80 *:*
users:(("capabilities",pid=30040,fd=3)) uid:65534 ino:11311579 sk:2c v6only:0


Dans cet exemple, nous avons utilisé capsh, mais vous pouvez écrire un shell en utilisant libcap. Voir man 3 libcap pour plus d'informations.



Lors de l'écriture de programmes, le développeur ne connaît souvent pas à l'avance toutes les capacités requises par le programme lors de l'exécution; de plus, ces caractéristiques peuvent changer dans les nouvelles versions.



Pour mieux comprendre les capacités de notre programme, nous pouvons utiliser l'outil compatible BCC, qui définit kprobe pour la fonction du noyau cap_capable:



/usr/share/bcc/tools/capable
TIME      UID  PID   TID   COMM               CAP    NAME           AUDIT
10:12:53 0 424     424     systemd-udevd 12 CAP_NET_ADMIN         1
10:12:57 0 1103   1101   timesync        25 CAP_SYS_TIME         1
10:12:57 0 19545 19545 capabilities       10 CAP_NET_BIND_SERVICE 1


Nous pouvons réaliser la même chose en utilisant bpftrace avec le kprobe sur une ligne dans la fonction du noyau cap_capable:



bpftrace -e \
   'kprobe:cap_capable {
      time("%H:%M:%S ");
      printf("%-6d %-6d %-16s %-4d %d\n", uid, pid, comm, arg2, arg3);
    }' \
    | grep -i capabilities


Cela affichera quelque chose comme ce qui suit si les capacités de notre programme sont activées après kprobe:



12:01:56 1000 13524 capabilities 21 0
12:01:56 1000 13524 capabilities 21 0
12:01:56 1000 13524 capabilities 21 0
12:01:56 1000 13524 capabilities 12 0
12:01:56 1000 13524 capabilities 12 0
12:01:56 1000 13524 capabilities 12 0
12:01:56 1000 13524 capabilities 12 0
12:01:56 1000 13524 capabilities 10 1


La cinquième colonne contient les capacités dont le processus a besoin, et comme cette sortie inclut des événements non liés à l'audit, nous voyons toutes les vérifications non liées à l'audit et enfin la capacité requise avec l'indicateur d'audit (le dernier dans la sortie) défini sur 1. Capacité. qui nous intéresse est CAP_NET_BIND_SERVICE, il est défini comme une constante dans le code source du noyau dans le fichier include / uapi / linux / ability.h avec l'ID 10:



/* Allows binding to TCP/UDP sockets below 1024 */
/* Allows binding to ATM VCIs below 32 */
#define CAP_NET_BIND_SERVICE 10<source lang="go">


Les fonctionnalités sont souvent utilisées lors de l'exécution pour que les conteneurs tels que runC ou Docker s'exécutent en mode non privilégié, mais ne sont autorisées que pour les fonctionnalités nécessaires à l'exécution de la plupart des applications. Lorsqu'une application nécessite des capacités spécifiques, Docker peut leur fournir --cap-add:



docker run -it --rm --cap-add=NET_ADMIN ubuntu ip link add dummy0 type dummy


Cette commande fournira au conteneur la capacité CAP_NET_ADMIN, qui lui permettra de configurer un lien réseau pour ajouter l'interface dummy0.



La section suivante montre l'utilisation de fonctionnalités telles que le filtrage, mais avec une méthode différente qui nous permet d'implémenter par programme nos propres filtres.



Seccomp



Seccomp signifie Secure Computing, c'est une couche de sécurité implémentée dans le noyau Linux qui permet aux développeurs de filtrer certains appels système. Bien que Seccomp soit comparable aux capacités de Linux, sa capacité à gérer des appels système spécifiques le rend beaucoup plus flexible qu'il ne l'est.



Les capacités de Seccomp et de Linux ne sont pas mutuellement exclusives et sont souvent utilisées ensemble pour bénéficier des deux approches. Par exemple, vous pouvez donner à un processus la capacité CAP_NET_ADMIN, mais ne pas l'autoriser à accepter les connexions de socket en bloquant les appels système accept et accept4.



La méthode de filtrage Seccomp est basée sur des filtres BPF fonctionnant en mode SECCOMP_MODE_FILTER, et le filtrage des appels système est effectué de la même manière que pour les paquets.



Les filtres Seccomp sont chargés à l'aide de prctl via l'opération PR_SET_SECCOMP. Ces filtres se présentent sous la forme d'un programme BPF qui s'exécute pour chaque package Seccomp représenté par la structure seccomp_data. Cette structure contient l'architecture de référence, un pointeur vers les instructions du processeur lors de l'appel système et un maximum de six arguments d'appel système, exprimés en uint64.



Voici à quoi ressemble la structure seccomp_data à partir de la source du noyau dans le fichier linux / seccomp.h:



struct seccomp_data {
int nr;
      __u32 arch;
      __u64 instruction_pointer;
      __u64 args[6];
};


Comme vous pouvez le voir dans cette structure, nous pouvons filtrer par l'appel système, ses arguments ou une combinaison des deux.



Après avoir reçu chaque paquet Seccomp, le filtre doit effectuer un traitement pour prendre une décision finale et dire au noyau ce qu'il doit faire ensuite. La décision finale est exprimée dans l'une des valeurs de retour (codes d'état).



- SECCOMP_RET_KILL_PROCESS - arrêt de l'ensemble du processus immédiatement après le filtrage d'un appel système qui n'est pas exécuté à cause de cela.



- SECCOMP_RET_KILL_THREAD - arrêt du thread en cours immédiatement après le filtrage d'un appel système, qui à cause de cela n'est pas exécuté.



- SECCOMP_RET_KILL - alias pour SECCOMP_RET_KILL_THREAD, à gauche pour compatibilité ascendante.



- SECCOMP_RET_TRAP - L'appel système est désactivé et le signal SIGSYS (Bad System Call) est envoyé à la tâche appelante.



- SECCOMP_RET_ERRNO - L'appel système n'est pas exécuté et une partie de la valeur de retour du filtre SECCOMP_RET_DATA est transmise à l'espace utilisateur sous la forme errno. Différentes valeurs errno sont renvoyées en fonction de la cause de l'erreur. Les numéros d'erreur sont répertoriés dans la section suivante.



- SECCOMP_RET_TRACE - Utilisé pour notifier le ptrace avec - PTRACE_O_TRACESECCOMP pour intercepter lorsqu'un appel système est effectué pour voir et contrôler ce processus. Si un traceur n'est pas connecté, une erreur est renvoyée, errno est défini sur -ENOSYS et l'appel système n'est pas exécuté.



- SECCOMP_RET_LOG - L'appel système est autorisé et est enregistré.



- SECCOMP_RET_ALLOW - l'appel système est simplement autorisé.



ptrace est un appel système pour implémenter des mécanismes de trace dans un processus appelé tracee, avec la possibilité de surveiller et de contrôler l'exécution du processus. Le programme de trace peut effectivement influencer l'exécution et modifier les registres de mémoire de l'observé. Dans le contexte de Seccomp, ptrace est utilisé lorsqu'il est déclenché par le code d'état SECCOMP_RET_TRACE, afin que le traceur puisse empêcher l'exécution de l'appel système et implémenter sa propre logique.


Erreurs Seccomp



De temps en temps, lorsque vous travaillez avec Seccomp, vous rencontrez diverses erreurs, qui sont identifiées par une valeur de retour de type SECCOMP_RET_ERRNO. Pour signaler une erreur, l'appel système seccomp renverra -1 au lieu de 0.



Les erreurs suivantes sont possibles:



- EACCESS - L'appelant n'est pas autorisé à effectuer un appel système. Cela se produit généralement parce qu'il n'a pas le privilège CAP_SYS_ADMIN ou que no_new_privs n'est pas défini avec prctl (nous en reparlerons plus tard);



- EFAULT - les arguments passés (args dans la structure seccomp_data) n'ont pas d'adresse valide;



- EINVAL - il peut y avoir quatre raisons ici: - l'



opération demandée est inconnue ou n'est pas prise en charge par le noyau dans la configuration actuelle;



-les indicateurs spécifiés ne sont pas valides pour l'opération demandée;



-operation inclut BPF_ABS, mais il y a des problèmes avec le décalage spécifié, qui peut dépasser la taille de la structure seccomp_data;



- le nombre d'instructions passées au filtre dépasse le maximum;



- ENOMEM - pas assez de mémoire pour exécuter le programme;



- EOPNOTSUPP - l'opération a indiqué qu'une action était disponible avec SECCOMP_GET_ACTION_AVAIL, mais le noyau ne prend pas en charge le retour dans les arguments;



- ESRCH - un problème est survenu lors de la synchronisation d'un autre flux;



- ENOSYS - aucun traceur n'est attaché à l'action SECCOMP_RET_TRACE.



prctl est un appel système qui permet à un programme de l'espace utilisateur de manipuler (définir et obtenir) des aspects spécifiques d'un processus, tels que la séquence d'octets, les noms de threads, le mode informatique sécurisé (Seccomp), les privilèges, les événements Perf, etc.


Seccomp peut vous sembler être une technologie sandbox, mais ce n'est pas le cas. Seccomp est un utilitaire qui permet aux utilisateurs de développer un mécanisme de sandboxing. Voyons maintenant comment créer des programmes d'interaction personnalisés à l'aide d'un filtre appelé directement par l'appel système Seccomp.



Exemple de filtre BPF Seccomp



Nous montrerons ici comment combiner les deux actions évoquées précédemment, à savoir:



- écrire le programme Seccomp BPF, qui servira de filtre avec des codes de retour différents en fonction des décisions prises;



- charger le filtre avec prctl.



Vous avez d'abord besoin des en-têtes de la bibliothèque standard et du noyau Linux:



#include <errno.h>
#include <linux/audit.h>
#include <linux/bpf.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <linux/unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <unistd.h>


Avant d'essayer cet exemple, nous devons nous assurer que le noyau est compilé avec CONFIG_SECCOMP et CONFIG_SECCOMP_FILTER définis sur y. Sur une machine de production, vous pouvez le tester comme ceci:



cat /proc/config.gz| zcat | grep -i CONFIG_SECCOMP



Le reste du code est une fonction install_filter en deux parties. La première partie contient notre liste d'instructions de filtrage BPF:



static int install_filter(int nr, int arch, int error) {
  struct sock_filter filter[] = {
    BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, arch))),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arch, 0, 3),
    BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, nr))),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (error & SECCOMP_RET_DATA)),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
  };


Les instructions sont définies à l'aide des macros BPF_STMT et BPF_JUMP définies dans le fichier linux / filter.h.

Passons en revue les instructions.



- BPF_STMT (BPF_LD + BPF_W + BPF_ABS (offsetof (struct seccomp_data, arch))) - le système se charge et s'accumule avec BPF_LD sous la forme du mot BPF_W, les données du paquet sont situées à un offset fixe BPF_ABS.



- BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, arch, 0, 3) - vérifie à l'aide de BPF_JEQ si la valeur d'architecture dans la constante d'accumulateur BPF_K est égale à arch. Si tel est le cas, il saute à l'offset 0 à l'instruction suivante; sinon, il saute à l'offset 3 (dans ce cas) pour générer une erreur, car l'arche ne correspond pas.



- BPF_STMT (BPF_LD + BPF_W + BPF_ABS (offsetof (struct seccomp_data, nr))) - télécharge et s'accumule avec BPF_LD sous la forme du mot BPF_W, qui est le numéro d'appel système contenu dans l'offset fixe BPF_ABS.



- BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1) - compare le numéro d'appel système avec la valeur de la variable nr. S'ils sont égaux, il passe à l'instruction suivante et interdit l'appel système; sinon, active l'appel système avec SECCOMP_RET_ALLOW.



- BPF_STMT (BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (error & SECCOMP_RET_DATA)) - termine le programme avec BPF_RET et, par conséquent, émet une erreur SECCOMP_RET_ERRNO avec un numéro de la variable err.



- BPF_STMT (BPF_RET + BPF_K, SECCOMP_RET_ALLOW) - termine le programme avec BPF_RET et permet l'exécution d'un appel système à l'aide de SECCOMP_RET_ALLOW.



SECCOMP IS CBPF Vous

vous demandez peut-être pourquoi une liste d'instructions est utilisée à la place d'un objet ELF compilé ou d'un programme C compilé JIT.



Il y a deux raisons à cela.



• Premièrement, Seccomp utilise cBPF (BPF classique), pas eBPF, ce qui signifie qu'il n'a pas de registres, mais seulement un accumulateur pour stocker le dernier résultat de calcul, comme vous pouvez le voir dans l'exemple.



• Deuxièmement, Seccomp prend directement un pointeur vers un tableau d'instructions BPF et rien d'autre. Les macros que nous avons utilisées permettent uniquement de spécifier ces instructions sous une forme pratique pour les programmeurs.


Si vous avez besoin de plus d'aide pour comprendre cet assemblage, envisagez un pseudocode qui fait de même:



if (arch != AUDIT_ARCH_X86_64) {
    return SECCOMP_RET_ALLOW;
}
if (nr == __NR_write) {
    return SECCOMP_RET_ERRNO;
}
return SECCOMP_RET_ALLOW;


Après avoir défini le code de filtre dans la structure socket_filter, vous devez définir un sock_fprog contenant le code et la longueur de filtre calculée. Cette structure de données est nécessaire comme argument pour déclarer le travail du processus dans le futur:



struct sock_fprog prog = {
   .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
   .filter = filter,
};


Il ne reste qu'une chose à faire dans la fonction install_filter - télécharger le programme lui-même! Pour ce faire, nous utilisons prctl, en prenant PR_SET_SECCOMP comme option pour entrer en mode informatique sécurisé. Ensuite, nous disons au mode de charger le filtre en utilisant SECCOMP_MODE_FILTER, qui est contenu dans la variable prog de type sock_fprog:



  if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
    perror("prctl(PR_SET_SECCOMP)");
    return 1;
  }
  return 0;
}


Enfin, nous pouvons utiliser notre fonction install_filter, mais avant cela, nous devons utiliser prctl pour définir PR_SET_NO_NEW_PRIVS pour l'exécution en cours et éviter ainsi une situation où les processus enfants obtiennent plus de privilèges que leur parent. Avec cela, nous pouvons faire les appels suivants à prctl dans la fonction install_filter sans avoir les droits root.



Nous pouvons maintenant appeler la fonction install_filter. Bloquons tous les appels système d'écriture liés à l'architecture X86-64 et accordons simplement la permission, ce qui bloque toutes les tentatives. Après avoir installé le filtre, continuez l'exécution en utilisant le premier argument:



int main(int argc, char const *argv[]) {
  if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
   perror("prctl(NO_NEW_PRIVS)");
   return 1;
  }
   install_filter(__NR_write, AUDIT_ARCH_X86_64, EPERM);
  return system(argv[1]);
 }


Commençons. Nous pouvons utiliser clang ou gcc pour compiler notre programme, de toute façon, il s'agit simplement de compiler le fichier main.c sans options spéciales:



clang main.c -o filter-write


Comme indiqué, nous avons bloqué toutes les entrées du programme. Pour tester cela, vous avez besoin d'un programme qui produit quelque chose - ls semble être un bon candidat. Voici comment elle se comporte habituellement:



ls -la
total 36
drwxr-xr-x 2 fntlnz users 4096 Apr 28 21:09 .
drwxr-xr-x 4 fntlnz users 4096 Apr 26 13:01 ..
-rwxr-xr-x 1 fntlnz users 16800 Apr 28 21:09 filter-write
-rw-r--r-- 1 fntlnz users 19 Apr 28 21:09 .gitignore
-rw-r--r-- 1 fntlnz users 1282 Apr 28 21:08 main.c


À la perfection! Voici à quoi ressemble notre programme shell: nous passons simplement le programme que nous voulons tester comme premier argument:



./filter-write "ls -la"


Lorsqu'il est exécuté, ce programme produit une sortie complètement vide. Cependant, nous pouvons utiliser strace pour voir ce qui se passe:



strace -f ./filter-write "ls -la"


Le résultat du travail est considérablement raccourci, mais la partie correspondante montre que les enregistrements sont bloqués avec l'erreur EPERM - la même que nous avons configurée. Cela signifie que le programme ne produit rien car il ne peut pas accéder à l'appel système d'écriture:



[pid 25099] write(2, "ls: ", 4) = -1 EPERM (Operation not permitted)
[pid 25099] write(2, "write error", 11) = -1 EPERM (Operation not permitted)
[pid 25099] write(2, "\n", 1) = -1 EPERM (Operation not permitted)


Vous comprenez maintenant comment fonctionne Seccomp BPF et avez une bonne idée de ce qui peut être fait avec. Mais ne voudriez-vous pas faire la même chose avec eBPF au lieu de cBPF afin d'utiliser toute sa puissance?



Lorsqu'ils pensent aux programmes eBPF, la plupart des gens pensent qu'ils ne font que les écrire et les charger avec des privilèges d'administrateur. Bien que cette affirmation soit généralement vraie, le noyau implémente un ensemble de mécanismes pour protéger les objets eBPF à différents niveaux. Ces mécanismes sont appelés pièges BPF LSM.



Pièges BPF LSM



Pour fournir une surveillance indépendante de l'architecture des événements système, LSM met en œuvre le concept d'interruptions. Un crochet d'appel est techniquement similaire à un appel système, mais il est indépendant du système et intégré à l'infrastructure. LSM fournit un nouveau concept dans lequel la couche d'abstraction peut aider à éviter les problèmes qui surviennent lors du traitement d'appels système sur différentes architectures.



Au moment d'écrire ces lignes, le noyau a sept hooks associés aux programmes BPF, et SELinux est le seul LSM intégré qui les implémente.



Le code source des hooks se trouve dans l'arborescence du noyau dans le fichier include / linux / security.h:



extern int security_bpf(int cmd, union bpf_attr *attr, unsigned int size);
extern int security_bpf_map(struct bpf_map *map, fmode_t fmode);
extern int security_bpf_prog(struct bpf_prog *prog);
extern int security_bpf_map_alloc(struct bpf_map *map);
extern void security_bpf_map_free(struct bpf_map *map);
extern int security_bpf_prog_alloc(struct bpf_prog_aux *aux);
extern void security_bpf_prog_free(struct bpf_prog_aux *aux);


Chacun d'eux sera appelé à différents stades d'exécution:



- security_bpf - effectue les vérifications initiales des appels système BPF exécutés;



- security_bpf_map - vérifie quand le noyau renvoie un descripteur de fichier pour la carte;



- security_bpf_prog - Vérifie quand le noyau renvoie un descripteur de fichier pour le programme eBPF;



- security_bpf_map_alloc - vérifie si le champ de sécurité à l'intérieur des mappes BPF est initialisé;



- security_bpf_map_free - vérifie si le champ de sécurité à l'intérieur des cartes BPF est effacé;



- security_bpf_prog_alloc - vérifie si le champ de sécurité est initialisé dans les programmes BPF;



- security_bpf_prog_free - vérifie si le champ de sécurité est effacé dans les programmes BPF.



Maintenant, voyant tout cela, nous comprenons que l'idée derrière les intercepteurs LSM BPF est qu'ils peuvent fournir une protection pour chaque objet eBPF, garantissant que seuls ceux qui disposent des privilèges appropriés peuvent effectuer des opérations sur les cartes et les programmes.



Résumé



La sécurité n'est pas quelque chose que vous pouvez appliquer de manière unique pour tout ce que vous souhaitez protéger. Il est important de pouvoir protéger les systèmes à différents niveaux et de différentes manières. Croyez-le ou non, la meilleure façon de sécuriser un système est d'organiser différents niveaux de protection à partir de différentes positions afin que la dégradation de la sécurité d'un niveau empêche l'accès à l'ensemble du système. Les développeurs du noyau ont fait un excellent travail en nous fournissant un ensemble de couches et de points de contact différents. Nous espérons que nous vous avons donné une bonne compréhension de ce que sont les couches et comment utiliser les programmes BPF pour travailler avec elles.



À propos des auteurs



David Calavera est CTO chez Netlify. Il a travaillé pour Docker Support et a contribué au développement des outils Runc, Go et BCC, ainsi qu'à d'autres projets open source. Connu pour son travail sur les projets Docker et le développement de l'écosystème de plugins Docker. David aime beaucoup les graphiques de flamme et s'efforce toujours d'optimiser les performances.



Lorenzo Fontana fait partie de l'équipe de développement open source de Sysdig, où il est principalement impliqué dans Falco, un projet Cloud Native Computing Foundation qui fournit la sécurité d'exécution des conteneurs et la détection des anomalies via le module du noyau et eBPF. Il est passionné par les systèmes distribués, les réseaux définis par logiciel, le noyau Linux et l'analyse des performances.



»Plus de détails sur le livre peuvent être trouvés sur le site de la maison d'édition

» Table des matières

» Extrait



Pour Habitants une réduction de 25% sur le coupon - Linux



Lors du paiement de la version papier du livre, un e-book est envoyé par e-mail.



All Articles