Bog "BPF for Linux Monitoring"

Bog "BPF for Linux Monitoring"Hej Khabro beboere! Den virtuelle BPF-maskine er en af ​​de vigtigste komponenter i Linux-kernen. Dens korrekte brug vil give systemingeniører mulighed for at finde fejl og løse selv de mest komplekse problemer. Du lærer, hvordan du skriver programmer, der overvåger og ændrer kernens adfærd, hvordan du sikkert implementerer kode til at overvåge hændelser i kernen og meget mere. David Calavera og Lorenzo Fontana vil hjælpe dig med at låse op for kraften i BPF. Udvid din viden om ydeevneoptimering, netværk, sikkerhed. - Brug BPF til at overvåge og ændre Linux-kernens adfærd. - Injicer kode for sikkert at overvåge kernehændelser uden at skulle kompilere kernen eller genstarte systemet. — Brug praktiske kodeeksempler i C, Go eller Python. - Tag kontrol ved at eje BPF-programmets livscyklus.

Linux Kernel Security, dens funktioner og Secomp

BPF giver en effektiv måde at udvide kernen på uden at ofre stabilitet, sikkerhed eller hastighed. Af denne grund mente kerneudviklerne, at det ville være en god idé at bruge dens alsidighed til at forbedre procesisolering i Seccomp ved at implementere Seccomp-filtre understøttet af BPF-programmer, også kendt som Seccomp BPF. I dette kapitel vil vi forklare, hvad Secomp er, og hvordan det bruges. Så lærer du, hvordan du skriver Secomp-filtre ved hjælp af BPF-programmer. Derefter vil vi se på de indbyggede BPF-hooks, der er inkluderet i kernen til Linux-sikkerhedsmoduler.

Linux Security Modules (LSM) er en ramme, der giver et sæt funktioner, der kan bruges til at implementere forskellige sikkerhedsmodeller på en standardiseret måde. LSM kan bruges direkte i kernekildetræet, såsom Apparmor, SELinux og Tomoyo.

Lad os starte med at diskutere mulighederne i Linux.

Capabilities

Essensen af ​​Linux's muligheder er, at du skal give en uprivilegeret procestilladelse til at udføre en bestemt opgave, men uden at bruge suid til det formål, eller på anden måde gøre processen privilegeret, hvilket reducerer muligheden for angreb og tillader processen at udføre bestemte opgaver. For eksempel, hvis din applikation skal åbne en privilegeret port, f.eks. 80, i stedet for at køre processen som root, kan du blot give den CAP_NET_BIND_SERVICE-kapaciteten.

Overvej et Go-program ved navn main.go:

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

Dette program betjener en HTTP-server på port 80 (dette er en privilegeret port). Normalt kører vi det umiddelbart efter kompilering:

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

Men da vi ikke giver root-privilegier, vil denne kode give en fejl, når porten bindes:

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

capsh (shell manager) er et værktøj, der kører en shell med et specifikt sæt af muligheder.

I dette tilfælde, som allerede nævnt, kan du i stedet for at give fulde rodrettigheder aktivere privilegeret portbinding ved at levere cap_net_bind_service-kapaciteten sammen med alt andet, der allerede er i programmet. For at gøre dette kan vi vedlægge vores program i 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"

Lad os forstå dette hold lidt.

  • capsh - brug capsh som en skal.
  • —caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' - da vi skal ændre brugeren (vi ønsker ikke at køre som root), specificerer vi cap_net_bind_service og muligheden for faktisk at ændre bruger-id'et fra root til ingen, nemlig cap_setuid og cap_setgid.
  • —keep=1 — vi ønsker at beholde de installerede funktioner, når vi skifter fra root-kontoen.
  • —user=“ingen” — slutbrugeren, der kører programmet, vil være ingen.
  • —addamb=cap_net_bind_service — indstil rydningen af ​​relaterede funktioner efter skift fra rodtilstand.
  • - -c "./capabilities" - bare kør programmet.

Sammenkædede egenskaber er en speciel form for egenskaber, der nedarves af underordnede programmer, når det aktuelle program udfører dem ved hjælp af execve(). Kun kapaciteter, der har lov til at blive associeret, eller med andre ord som miljøkapaciteter, kan nedarves.

Du spekulerer sikkert på, hvad +eip betyder efter at have specificeret kapaciteten i --caps-indstillingen. Disse flag bruges til at bestemme, at kapaciteten:

-skal aktiveres (p);

- tilgængelig til brug (e);

-kan nedarves af underordnede processer (i).

Da vi ønsker at bruge cap_net_bind_service, skal vi gøre dette med e-flaget. Så starter vi skallen i kommandoen. Dette vil køre funktionerne binære, og vi skal markere det med i-flaget. Endelig ønsker vi, at funktionen skal være aktiveret (vi gjorde dette uden at ændre UID) med p. Det ligner cap_net_bind_service+eip.

Du kan tjekke resultatet ved hjælp af ss. Lad os forkorte outputtet lidt, så det passer på siden, men det vil vise den tilknyttede port og bruger-ID andet end 0, i dette tilfælde 65:

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

I dette eksempel brugte vi capsh, men du kan skrive en shell ved hjælp af libcap. For mere information, se man 3 libcap.

Når man skriver programmer, kender udvikleren ofte ikke på forhånd alle de funktioner, programmet har brug for, når det køres; Desuden kan disse funktioner ændre sig i nye versioner.

For bedre at forstå vores programs muligheder kan vi tage det BCC-kompatible værktøj, som indstiller kprobe for cap_capable-kernefunktionen:

/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

Vi kan opnå det samme ved at bruge bpftrace med en one-liner kprobe i kernefunktionen cap_capable:

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

Dette vil udsende noget i stil med følgende, hvis vores programs muligheder er aktiveret efter 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

Den femte kolonne er de kapaciteter, som processen har brug for, og da dette output inkluderer ikke-revisionsbegivenheder, ser vi alle ikke-revisionskontroller og til sidst den nødvendige kapacitet med revisionsflaget (sidst i outputtet) sat til 1. Kapacitet. en vi er interesseret i er CAP_NET_BIND_SERVICE, den er defineret som en konstant i kernens kildekode i filen include/uapi/linux/ability.h med identifikator 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">

Funktioner er ofte aktiveret under kørsel for containere såsom runC eller Docker for at tillade dem at køre i uprivilegeret tilstand, men de tillades kun de nødvendige funktioner til at køre de fleste applikationer. Når en applikation kræver visse egenskaber, kan Docker give dem ved hjælp af --cap-add:

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

Denne kommando vil give containeren CAP_NET_ADMIN-kapaciteten, så den kan konfigurere et netværkslink for at tilføje dummy0-grænsefladen.

Det næste afsnit viser, hvordan man bruger funktioner såsom filtrering, men ved at bruge en anden teknik, der giver os mulighed for at implementere vores egne filtre programmatisk.

Secomp

Seccomp står for Secure Computing og er et sikkerhedslag implementeret i Linux-kernen, der giver udviklere mulighed for at filtrere bestemte systemkald. Selvom Secomp kan sammenlignes med Linux, gør dens evne til at administrere visse systemopkald den meget mere fleksibel sammenlignet med dem.

Secomp- og Linux-funktioner udelukker ikke hinanden og bruges ofte sammen for at drage fordel af begge tilgange. For eksempel vil du måske give en proces CAP_NET_ADMIN-kapaciteten, men ikke tillade den at acceptere socketforbindelser, hvilket blokerer for accept og accept4 systemopkald.

Secomp-filtreringsmetoden er baseret på BPF-filtre, der fungerer i SECCOMP_MODE_FILTER-tilstanden, og systemopkaldsfiltrering udføres på samme måde som for pakker.

Seccomp-filtre indlæses ved hjælp af prctl via PR_SET_SECCOMP-operationen. Disse filtre har form af et BPF-program, der udføres for hver Seccomp-pakke repræsenteret af seccomp_data-strukturen. Denne struktur indeholder referencearkitekturen, en pointer til processorinstruktioner på tidspunktet for systemkaldet og maksimalt seks systemkaldsargumenter, udtrykt som uint64.

Sådan ser strukturen seccomp_data ud fra kernekildekoden i filen linux/secomp.h:

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

Som du kan se fra denne struktur, kan vi filtrere efter systemkaldet, dets argumenter eller en kombination af begge.

Efter at have modtaget hver Seccomp-pakke, skal filteret udføre behandling for at træffe en endelig beslutning og fortælle kernen, hvad det næste skal gøre. Den endelige beslutning er udtrykt ved en af ​​returværdierne (statuskoder).

- SECCOMP_RET_KILL_PROCESS - dræber hele processen umiddelbart efter filtrering af et systemkald, der ikke udføres på grund af dette.

- SECCOMP_RET_KILL_THREAD - afslutter den aktuelle tråd umiddelbart efter filtrering af et systemkald, der ikke udføres på grund af dette.

— SECCOMP_RET_KILL — alias for SECCOMP_RET_KILL_THREAD, venstre for bagudkompatibilitet.

- SECCOMP_RET_TRAP - systemkaldet er forbudt, og SIGSYS-signalet (Bad System Call) sendes til den opgave, der kalder det.

- SECCOMP_RET_ERRNO - Systemkaldet udføres ikke, og en del af SECCOMP_RET_DATA-filterreturværdien sendes til brugerområdet som fejlværdien. Afhængigt af årsagen til fejlen returneres forskellige fejlværdier. En liste over fejlnumre findes i næste afsnit.

- SECCOMP_RET_TRACE - Bruges til at underrette ptrace-sporeren ved hjælp af - PTRACE_O_TRACESECCOMP til at opsnappe, når et systemkald udføres for at se og kontrollere denne proces. Hvis sporingen ikke er tilsluttet, returneres en fejl, errno sættes til -ENOSYS, og systemkaldet udføres ikke.

- SECCOMP_RET_LOG - systemkaldet er løst og logget.

- SECCOMP_RET_ALLOW - systemkaldet er simpelthen tilladt.

ptrace er et systemkald til at implementere sporingsmekanismer i en proces kaldet tracee, med evnen til at overvåge og kontrollere udførelsen af ​​processen. Sporingsprogrammet kan effektivt påvirke udførelsen og ændre sporingens hukommelsesregistre. I Secomp-konteksten bruges ptrace, når den udløses af SECCOMP_RET_TRACE-statuskoden, så sporeren kan forhindre systemkaldet i at udføre og implementere sin egen logik.

Secomp fejl

Fra tid til anden, mens du arbejder med Seccomp, vil du støde på forskellige fejl, som identificeres af en returværdi af typen SECCOMP_RET_ERRNO. For at rapportere en fejl vil seccomp-systemkaldet returnere -1 i stedet for 0.

Følgende fejl er mulige:

- EACCESS - Den, der ringer, må ikke foretage et systemopkald. Dette sker normalt, fordi det ikke har CAP_SYS_ADMIN-privilegier eller no_new_privs ikke er indstillet ved hjælp af prctl (vi vil tale om dette senere);

— EFAULT — de beståede argumenter (args i seccomp_data-strukturen) har ikke en gyldig adresse;

— EINVAL — der kan være fire grunde her:

-den anmodede operation er ukendt eller understøttes ikke af kernen i den aktuelle konfiguration;

-de angivne flag er ikke gyldige for den anmodede operation;

-operation inkluderer BPF_ABS, men der er problemer med den specificerede offset, som kan overstige størrelsen af ​​seccomp_data-strukturen;

-antallet af instruktioner, der sendes til filteret, overstiger maksimum;

— ENOMEM — ikke nok hukommelse til at udføre programmet;

- EOPNOTSUPP - operationen indikerede, at med SECCOMP_GET_ACTION_AVAIL var handlingen tilgængelig, men kernen understøtter ikke returneringer i argumenter;

— ESRCH — et problem opstod ved synkronisering af en anden strøm;

- ENOSYS - Der er ingen sporstof knyttet til SECCOMP_RET_TRACE handlingen.

prctl er et systemkald, der tillader et brugerrumsprogram at manipulere (indstille og hente) specifikke aspekter af en proces, såsom byte endianness, trådnavne, sikker beregningstilstand (Seccomp), privilegier, Perf-begivenheder osv.

Secomp kan virke som en sandkasseteknologi for dig, men det er den ikke. Secomp er et værktøj, der giver brugerne mulighed for at udvikle en sandkassemekanisme. Lad os nu se på, hvordan brugerinteraktionsprogrammer oprettes ved hjælp af et filter, der kaldes direkte af Secomp-systemkaldet.

Eksempel på BPF Secomp-filter

Her vil vi vise, hvordan man kombinerer de to handlinger, der er diskuteret tidligere, nemlig:

— vi vil skrive et Secomp BPF-program, som vil blive brugt som et filter med forskellige returkoder afhængigt af de trufne beslutninger;

— indlæs filteret med prctl.

Først skal du bruge overskrifter fra standardbiblioteket og Linux-kernen:

#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>

Før vi forsøger dette eksempel, skal vi sikre, at kernen er kompileret med CONFIG_SECCOMP og CONFIG_SECCOMP_FILTER sat til y. På en fungerende maskine kan du kontrollere dette på denne måde:

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

Resten af ​​koden er en todelt install_filter-funktion. Den første del indeholder vores liste over BPF-filtreringsinstruktioner:

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),
  };

Instruktionerne er indstillet ved hjælp af makroerne BPF_STMT og BPF_JUMP, der er defineret i filen linux/filter.h.
Lad os gennemgå instruktionerne.

- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, arch))) - systemet indlæses og akkumuleres fra BPF_LD i form af ordet BPF_W, pakkedata er placeret ved en fast offset BPF_ABS.

- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, bue, 0, 3) - kontrollerer ved hjælp af BPF_JEQ, om arkitekturværdien i BPF_K-akkumulatorkonstanten er lig med bue. Hvis det er tilfældet, hopper på offset 0 til den næste instruktion, ellers springer på offset 3 (i dette tilfælde) for at kaste en fejl, fordi buen ikke matcher.

- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, nr))) - Indlæser og akkumuleres fra BPF_LD i form af ordet BPF_W, som er systemets opkaldsnummer indeholdt i den faste offset af BPF_ABS.

— BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1) — sammenligner systemets opkaldsnummer med værdien af ​​nr-variablen. Hvis de er ens, går du videre til næste instruktion og deaktiverer systemkaldet, ellers tillader systemkaldet med SECCOMP_RET_ALLOW.

- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (fejl & SECCOMP_RET_DATA)) - afslutter programmet med BPF_RET og producerer som et resultat en fejl SECCOMP_RET_ERRNO med tallet fra fejlvariablen.

- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW) - afslutter programmet med BPF_RET og tillader, at systemkaldet udføres ved hjælp af SECCOMP_RET_ALLOW.

SECCOMP ER CBPF
Du undrer dig måske over, hvorfor en liste med instruktioner bruges i stedet for et kompileret ELF-objekt eller et JIT-kompileret C-program.

Det er der to grunde til.

• For det første bruger Seccomp cBPF (klassisk BPF) og ikke eBPF, hvilket betyder: den har ingen registre, men kun en akkumulator til at gemme det sidste beregningsresultat, som det kan ses i eksemplet.

• For det andet accepterer Secomp en pointer til en række BPF-instruktioner direkte og intet andet. De makroer, vi har brugt, hjælper simpelthen med at specificere disse instruktioner på en programmørvenlig måde.

Hvis du har brug for mere hjælp til at forstå denne samling, så overvej pseudokoden, der gør det samme:

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

Efter at have defineret filterkoden i socket_filter-strukturen, skal du definere en sock_fprog, der indeholder koden og den beregnede længde af filteret. Denne datastruktur er nødvendig som et argument for at erklære processen til at køre senere:

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

Der er kun én ting tilbage at gøre i install_filter-funktionen - indlæs selve programmet! For at gøre dette bruger vi prctl og tager PR_SET_SECCOMP som en mulighed for at gå ind i sikker computertilstand. Derefter fortæller vi tilstanden at indlæse filteret ved hjælp af SECCOMP_MODE_FILTER, som er indeholdt i prog-variablen af ​​typen sock_fprog:

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

Endelig kan vi bruge vores install_filter funktion, men før det skal vi bruge prctl til at indstille PR_SET_NO_NEW_PRIVS til den aktuelle udførelse og derved undgå situationen, hvor underordnede processer får flere privilegier end deres forældre. Med dette kan vi lave følgende prctl-kald i install_filter-funktionen uden at have root-rettigheder.

Nu kan vi kalde funktionen install_filter. Lad os blokere alle skrivesystemkald relateret til X86-64-arkitekturen og blot give en tilladelse, der blokerer alle forsøg. Efter installation af filteret fortsætter vi eksekveringen med det første 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]);
 }

Lad os komme igang. For at kompilere vores program kan vi bruge enten clang eller gcc, uanset hvad er det bare at kompilere main.c-filen uden særlige muligheder:

clang main.c -o filter-write

Som nævnt har vi blokeret alle poster i programmet. For at teste dette har du brug for et program, der udsender noget - det virker som en god kandidat. Sådan opfører hun sig normalt:

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

Vidunderlig! Sådan ser det ud at bruge vores wrapper-program: Vi giver simpelthen det program, vi vil teste, som det første argument:

./filter-write "ls -la"

Når det udføres, producerer dette program helt tomt output. Vi kan dog bruge strace til at se, hvad der sker:

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

Resultatet af arbejdet er stærkt forkortet, men den tilsvarende del af det viser, at poster er blokeret med EPERM-fejlen - den samme, som vi konfigurerede. Det betyder, at programmet ikke udsender noget, fordi det ikke kan få adgang til skrivesystemkaldet:

[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)

Nu forstår du, hvordan Secomp BPF fungerer, og har en god idé om, hvad du kan gøre med det. Men vil du ikke gerne opnå det samme med eBPF i stedet for cBPF for at udnytte dens fulde kraft?

Når de tænker på eBPF-programmer, tror de fleste, at de simpelthen skriver dem og indlæser dem med administratorrettigheder. Selvom denne erklæring generelt er sand, implementerer kernen et sæt mekanismer til at beskytte eBPF-objekter på forskellige niveauer. Disse mekanismer kaldes BPF LSM-fælder.

BPF LSM fælder

For at give arkitektur-uafhængig overvågning af systemhændelser implementerer LSM konceptet med fælder. Et hook call ligner teknisk set et system call, men er systemuafhængigt og integreret med infrastrukturen. LSM giver et nyt koncept, hvor et abstraktionslag kan hjælpe med at undgå problemer, man støder på, når man håndterer systemkald på forskellige arkitekturer.

I skrivende stund har kernen syv kroge forbundet med BPF-programmer, og SELinux er den eneste indbyggede LSM, der implementerer dem.

Kildekoden til fælderne er placeret i kernetræet i filen 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);

Hver af dem vil blive kaldt på forskellige stadier af henrettelse:

— security_bpf — udfører en indledende kontrol af udførte BPF-systemkald;

- security_bpf_map - kontrollerer, hvornår kernen returnerer en filbeskrivelse for kortet;

- security_bpf_prog - kontrollerer, hvornår kernen returnerer en filbeskrivelse for eBPF-programmet;

— security_bpf_map_alloc — kontrollerer, om sikkerhedsfeltet inde i BPF-kort er initialiseret;

- security_bpf_map_free - kontrollerer, om sikkerhedsfeltet er ryddet inde i BPF-kort;

— security_bpf_prog_alloc — kontrollerer, om sikkerhedsfeltet er initialiseret i BPF-programmer;

- security_bpf_prog_free - kontrollerer om sikkerhedsfeltet er ryddet inde i BPF-programmer.

Nu, når vi ser alt dette, forstår vi: ideen bag LSM BPF-interceptorer er, at de kan yde beskyttelse til alle eBPF-objekter og sikre, at kun dem med de relevante privilegier kan udføre operationer på kort og programmer.

Resumé

Sikkerhed er ikke noget, du kan implementere på en ensartet måde for alt, hvad du ønsker at beskytte. Det er vigtigt at kunne beskytte systemer på forskellige niveauer og på forskellige måder. Tro det eller ej, den bedste måde at sikre et system på er at organisere forskellige niveauer af beskyttelse fra forskellige positioner, så reduktion af sikkerheden på et niveau ikke giver adgang til hele systemet. Kerneudviklerne har gjort et godt stykke arbejde med at give os et sæt af forskellige lag og berøringspunkter. Vi håber, vi har givet dig en god forståelse af, hvad lag er, og hvordan du bruger BPF-programmer til at arbejde med dem.

Om forfattere

David Calavera er CTO hos Netlify. Han arbejdede i Docker-support og bidrog til udviklingen af ​​Runc-, Go- og BCC-værktøjer samt andre open source-projekter. Kendt for sit arbejde med Docker-projekter og udvikling af Docker-plugin-økosystemet. David er meget passioneret omkring flammegrafer og søger altid at optimere ydeevnen.

Lorenzo Fontana arbejder på open source-teamet hos Sysdig, hvor han primært er fokuseret på Falco, et Cloud Native Computing Foundation-projekt, der giver container runtime-sikkerhed og anomalidetektion gennem et kernemodul og eBPF. Han brænder for distribuerede systemer, softwaredefineret netværk, Linux-kernen og præstationsanalyse.

» Flere detaljer om bogen kan findes på forlagets hjemmeside
» indholdsfortegnelse
» Uddrag

For Khabrozhiteley 25% rabat ved brug af kupon - Linux

Ved betaling af papirversionen af ​​bogen fremsendes en elektronisk bog på e-mail.

Kilde: www.habr.com

Tilføj en kommentar