Boken "BPF for Linux Monitoring"

Boken "BPF for Linux Monitoring"Hei Khabro-beboere! Den virtuelle BPF-maskinen er en av de viktigste komponentene i Linux-kjernen. Riktig bruk vil tillate systemingeniører å finne feil og løse selv de mest komplekse problemene. Du vil lære hvordan du skriver programmer som overvåker og endrer oppførselen til kjernen, hvordan du trygt implementerer kode for å overvåke hendelser i kjernen, og mye mer. David Calavera og Lorenzo Fontana vil hjelpe deg å låse opp kraften til BPF. Utvid kunnskapen din om ytelsesoptimalisering, nettverk, sikkerhet. - Bruk BPF til å overvåke og endre oppførselen til Linux-kjernen. - Injiser kode for å overvåke kjernehendelser på en sikker måte uten å måtte kompilere kjernen på nytt eller starte systemet på nytt. — Bruk praktiske kodeeksempler i C, Go eller Python. - Ta kontroll ved å eie BPF-programmets livssyklus.

Linux Kernel Security, dens funksjoner og Secomp

BPF gir en kraftig måte å utvide kjernen uten å ofre stabilitet, sikkerhet eller hastighet. Av denne grunn trodde kjerneutviklerne at det ville være en god idé å bruke allsidigheten til å forbedre prosessisolasjonen i Seccomp ved å implementere Seccomp-filtre støttet av BPF-programmer, også kjent som Seccomp BPF. I dette kapittelet vil vi forklare hva Secomp er og hvordan det brukes. Deretter vil du lære hvordan du skriver Secomp-filtre ved hjelp av BPF-programmer. Etter det skal vi se på de innebygde BPF-krokene som er inkludert i kjernen for Linux-sikkerhetsmoduler.

Linux Security Modules (LSM) er et rammeverk som gir et sett med funksjoner som kan brukes til å implementere ulike sikkerhetsmodeller på en standardisert måte. LSM kan brukes direkte i kjernekildetreet, slik som Apparmor, SELinux og Tomoyo.

La oss starte med å diskutere mulighetene til Linux.

Evner

Essensen av Linuxs muligheter er at du må gi en uprivilegert prosesstillatelse for å utføre en bestemt oppgave, men uten å bruke suid til det formålet, eller på annen måte gjøre prosessen privilegert, noe som reduserer muligheten for angrep og lar prosessen utføre visse oppgaver. For eksempel, hvis applikasjonen din trenger å åpne en privilegert port, for eksempel 80, i stedet for å kjøre prosessen som root, kan du ganske enkelt gi den CAP_NET_BIND_SERVICE-funksjonen.

Tenk på et Go-program kalt main.go:

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

Dette programmet betjener en HTTP-server på port 80 (dette er en privilegert port). Vanligvis kjører vi det umiddelbart etter kompilering:

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

Men siden vi ikke gir root-privilegier, vil denne koden gi en feilmelding når porten bindes:

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

capsh (shell manager) er et verktøy som kjører et skall med et spesifikt sett med funksjoner.

I dette tilfellet, som allerede nevnt, i stedet for å gi fulle rotrettigheter, kan du aktivere privilegert portbinding ved å tilby cap_net_bind_service-funksjonen sammen med alt annet som allerede er i programmet. For å gjøre dette kan vi legge ved programmet vårt 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"

La oss forstå dette laget litt.

  • capsh - bruk capsh som et skall.
  • —caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' - siden vi må endre brukeren (vi vil ikke kjøre som root), spesifiserer vi cap_net_bind_service og muligheten til å faktisk endre bruker-ID fra rot til ingen, nemlig cap_setuid og cap_setgid.
  • —keep=1 — vi ønsker å beholde de installerte egenskapene når vi bytter fra root-kontoen.
  • —user=“ingen” — sluttbrukeren som kjører programmet vil være ingen.
  • —addamb=cap_net_bind_service — angi sletting av relaterte funksjoner etter bytte fra rotmodus.
  • - -c "./capabilities" - bare kjør programmet.

Koblede evner er en spesiell type funksjoner som arves av underordnede programmer når det gjeldende programmet kjører dem ved hjelp av execve(). Kun kapasiteter som tillates assosiert, eller med andre ord, som miljøegenskaper, kan arves.

Du lurer sikkert på hva +eip betyr etter å ha spesifisert muligheten i --caps-alternativet. Disse flaggene brukes til å fastslå at kapasiteten:

-må aktiveres (p);

- tilgjengelig for bruk (e);

-kan arves av underordnede prosesser (i).

Siden vi ønsker å bruke cap_net_bind_service, må vi gjøre dette med e-flagget. Deretter starter vi skallet i kommandoen. Dette vil kjøre funksjonene binær, og vi må merke den med i-flagget. Til slutt ønsker vi at funksjonen skal være aktivert (vi gjorde dette uten å endre UID) med p. Det ser ut som cap_net_bind_service+eip.

Du kan sjekke resultatet ved å bruke ss. La oss forkorte utgangen litt for å passe på siden, men den vil vise den tilhørende porten og bruker-IDen annet enn 0, i dette tilfellet 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 eksemplet brukte vi capsh, men du kan skrive et skall ved å bruke libcap. For mer informasjon, se man 3 libcap.

Når du skriver programmer, vet ofte ikke utvikleren på forhånd alle funksjonene programmet trenger under kjøretid; Dessuten kan disse funksjonene endres i nye versjoner.

For bedre å forstå funksjonene til programmet vårt, kan vi ta det BCC-kompatible verktøyet, som setter kprobe for cap_capable-kjernefunksjonen:

/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 oppnå det samme ved å bruke bpftrace med en one-liner kprobe i cap_capable kjernefunksjonen:

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 gi ut noe sånt som følgende hvis programmets funksjoner er aktivert etter 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 kolonnen er egenskapene som prosessen trenger, og siden denne utgangen inkluderer ikke-revisjonshendelser, ser vi alle ikke-revisjonssjekker og til slutt den nødvendige evnen med revisjonsflagget (sist i utdataene) satt til 1. Capability. en vi er interessert i er CAP_NET_BIND_SERVICE, den er definert som en konstant i kjernekildekoden 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">

Muligheter er ofte aktivert under kjøretid for containere som runC eller Docker for å la dem kjøre i uprivilegert modus, men de tillates bare de egenskapene som trengs for å kjøre de fleste applikasjoner. Når en applikasjon krever visse funksjoner, kan Docker gi dem ved hjelp av --cap-add:

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

Denne kommandoen vil gi beholderen CAP_NET_ADMIN-funksjonen, slik at den kan konfigurere en nettverkskobling for å legge til dummy0-grensesnittet.

Den neste delen viser hvordan du bruker funksjoner som filtrering, men ved å bruke en annen teknikk som lar oss implementere våre egne filtre programmatisk.

Secomp

Secomp står for Secure Computing og er et sikkerhetslag implementert i Linux-kjernen som lar utviklere filtrere visse systemanrop. Selv om Secomp kan sammenlignes med Linux, gjør dens evne til å administrere visse systemanrop den mye mer fleksibel sammenlignet med dem.

Secomp- og Linux-funksjoner utelukker ikke hverandre og brukes ofte sammen for å dra nytte av begge tilnærmingene. Det kan for eksempel være lurt å gi en prosess CAP_NET_ADMIN-funksjonen, men ikke tillate at den godtar socket-tilkoblinger, og blokkerer godta og godta4-systemanrop.

Secomp-filtreringsmetoden er basert på BPF-filtre som opererer i SECCOMP_MODE_FILTER-modus, og systemanropsfiltrering utføres på samme måte som for pakker.

Seccomp-filtre lastes ved hjelp av prctl gjennom PR_SET_SECCOMP-operasjonen. Disse filtrene har form av et BPF-program som kjøres for hver Seccomp-pakke representert av seccomp_data-strukturen. Denne strukturen inneholder referansearkitekturen, en peker til prosessorinstruksjoner på tidspunktet for systemanropet, og maksimalt seks systemkallargumenter, uttrykt som uint64.

Slik ser seccomp_data-strukturen ut fra kjernekildekoden i linux/seccomp.h-filen:

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

Som du kan se fra denne strukturen, kan vi filtrere etter systemkallet, dets argumenter eller en kombinasjon av begge.

Etter å ha mottatt hver Seccomp-pakke, må filteret utføre behandling for å ta en endelig avgjørelse og fortelle kjernen hva de skal gjøre videre. Den endelige avgjørelsen uttrykkes av en av returverdiene (statuskoder).

- SECCOMP_RET_KILL_PROCESS - dreper hele prosessen umiddelbart etter filtrering av et systemanrop som ikke blir utført på grunn av dette.

- SECCOMP_RET_KILL_THREAD - avslutter gjeldende tråd umiddelbart etter filtrering av et systemanrop som ikke blir utført på grunn av dette.

— SECCOMP_RET_KILL — alias for SECCOMP_RET_KILL_THREAD, venstre for bakoverkompatibilitet.

- SECCOMP_RET_TRAP - systemanropet er forbudt, og SIGSYS-signalet (Bad System Call) sendes til oppgaven som kaller det.

- SECCOMP_RET_ERRNO - Systemkallet blir ikke utført, og en del av SECCOMP_RET_DATA-filterreturverdien sendes til brukerområdet som feilverdien. Avhengig av årsaken til feilen, returneres forskjellige feilverdier. En liste over feilnumre er gitt i neste avsnitt.

- SECCOMP_RET_TRACE - Brukes til å varsle ptrace-sporeren ved å bruke - PTRACE_O_TRACESECCOMP for å avskjære når et systemanrop utføres for å se og kontrollere den prosessen. Hvis en sporer ikke er tilkoblet, returneres en feil, errno settes til -ENOSYS, og systemkallet blir ikke utført.

- SECCOMP_RET_LOG - systemanropet løses og logges.

- SECCOMP_RET_ALLOW - systemanropet er ganske enkelt tillatt.

ptrace er et systemkall for å implementere sporingsmekanismer i en prosess kalt tracee, med muligheten til å overvåke og kontrollere utførelsen av prosessen. Sporingsprogrammet kan effektivt påvirke utførelsen og modifisere sporingens minneregistre. I Secomp-konteksten brukes ptrace når den utløses av SECCOMP_RET_TRACE-statuskoden, slik at traceren kan forhindre systemanropet fra å utføre og implementere sin egen logikk.

Secomp feil

Fra tid til annen, mens du arbeider med Seccomp, vil du støte på forskjellige feil, som identifiseres av en returverdi av typen SECCOMP_RET_ERRNO. For å rapportere en feil vil seccomp-systemanropet returnere -1 i stedet for 0.

Følgende feil er mulige:

- TILGANG - Den som ringer har ikke lov til å foreta et systemanrop. Dette skjer vanligvis fordi det ikke har CAP_SYS_ADMIN-privilegier eller no_new_privs ikke er satt med prctl (vi skal snakke om dette senere);

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

— EINVAL — det kan være fire grunner her:

-den forespurte operasjonen er ukjent eller ikke støttet av kjernen i gjeldende konfigurasjon;

-de angitte flaggene er ikke gyldige for den forespurte operasjonen;

-operasjon inkluderer BPF_ABS, men det er problemer med den spesifiserte offset, som kan overstige størrelsen på secomp_data-strukturen;

-antallet instruksjoner som sendes til filteret overstiger maksimum;

— ENOMEM — ikke nok minne til å kjøre programmet;

- EOPNOTSUPP - operasjonen indikerte at med SECCOMP_GET_ACTION_AVAIL var handlingen tilgjengelig, men kjernen støtter ikke returer i argumenter;

— ESRCH — et problem oppstod ved synkronisering av en annen strøm;

- ENOSYS - Det er ingen sporing knyttet til SECCOMP_RET_TRACE-handlingen.

prctl er et systemkall som lar et brukerromsprogram manipulere (sette og hente) spesifikke aspekter av en prosess, for eksempel byte-endianness, trådnavn, sikker beregningsmodus (Seccomp), privilegier, Perf-hendelser, etc.

Secomp kan virke som en sandkasseteknologi for deg, men det er det ikke. Secomp er et verktøy som lar brukere utvikle en sandkassemekanisme. La oss nå se på hvordan brukerinteraksjonsprogrammer opprettes ved å bruke et filter som kalles direkte av Secomp-systemanropet.

Eksempel på BPF Secomp-filter

Her vil vi vise hvordan du kombinerer de to handlingene som er diskutert tidligere, nemlig:

— vi skal skrive et Secomp BPF-program, som skal brukes som et filter med forskjellige returkoder avhengig av beslutningene som tas;

— last filteret med prctl.

Først trenger du overskrifter fra standardbiblioteket og Linux-kjernen:

#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 prøver dette eksemplet, må vi sørge for at kjernen er kompilert med CONFIG_SECCOMP og CONFIG_SECCOMP_FILTER satt til y. På en fungerende maskin kan du sjekke dette slik:

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

Resten av koden er en todelt install_filter-funksjon. Den første delen inneholder vår liste over BPF-filtreringsinstruksjoner:

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

Instruksjonene er satt ved hjelp av makroene BPF_STMT og BPF_JUMP definert i linux/filter.h-filen.
La oss gå gjennom instruksjonene.

- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, arch))) - systemet laster og akkumulerer fra BPF_LD i form av ordet BPF_W, pakkedata er lokalisert ved en fast offset BPF_ABS.

- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, bue, 0, 3) - sjekker ved hjelp av BPF_JEQ om arkitekturverdien i akkumulatorkonstanten BPF_K er lik bue. I så fall, hopper på offset 0 til neste instruksjon, ellers hopper på offset 3 (i dette tilfellet) for å kaste en feil fordi buen ikke stemmer.

- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, nr))) - Laster og akkumulerer fra BPF_LD i form av ordet BPF_W, som er systemanropsnummeret som ligger i den faste offset av BPF_ABS.

— BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1) — sammenligner systemanropsnummeret med verdien av nr-variabelen. Hvis de er like, går du videre til neste instruksjon og deaktiverer systemanropet, ellers tillater systemanropet med SECCOMP_RET_ALLOW.

- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (error & SECCOMP_RET_DATA)) - avslutter programmet med BPF_RET og produserer som et resultat en feil SECCOMP_RET_ERRNO med tallet fra feilvariabelen.

- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW) - avslutter programmet med BPF_RET og lar systemkallet utføres ved å bruke SECCOMP_RET_ALLOW.

SECCOMP ER CBPF
Du lurer kanskje på hvorfor en liste med instruksjoner brukes i stedet for et kompilert ELF-objekt eller et JIT-kompilert C-program.

Det er to grunner til dette.

• For det første bruker Secomp cBPF (klassisk BPF) og ikke eBPF, noe som betyr: den har ingen registre, men kun en akkumulator for å lagre det siste resultatet av beregningen, som kan ses i eksempelet.

• For det andre godtar Secomp en peker til en rekke BPF-instruksjoner direkte og ingenting annet. Makroene vi har brukt hjelper ganske enkelt med å spesifisere disse instruksjonene på en programmerervennlig måte.

Hvis du trenger mer hjelp til å forstå denne sammenstillingen, bør du vurdere pseudokoden som gjø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;

Etter å ha definert filterkoden i socket_filter-strukturen, må du definere en sock_fprog som inneholder koden og den beregnede lengden på filteret. Denne datastrukturen er nødvendig som et argument for å erklære at prosessen skal kjøres senere:

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

Det er bare én ting igjen å gjøre i install_filter-funksjonen - last selve programmet! For å gjøre dette bruker vi prctl, og tar PR_SET_SECCOMP som et alternativ for å gå inn i sikker datamodus. Deretter ber vi modusen om å laste filteret ved å bruke SECCOMP_MODE_FILTER, som er inneholdt i prog-variabelen av typen sock_fprog:

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

Til slutt kan vi bruke funksjonen install_filter, men før det må vi bruke prctl for å sette PR_SET_NO_NEW_PRIVS for gjeldende utførelse og dermed unngå situasjonen der barneprosesser får flere privilegier enn foreldrene. Med dette kan vi gjøre følgende prctl-kall i install_filter-funksjonen uten å ha root-rettigheter.

Nå kan vi kalle install_filter-funksjonen. La oss blokkere alle skrivesystemanrop relatert til X86-64-arkitekturen og ganske enkelt gi en tillatelse som blokkerer alle forsøk. Etter å ha installert filteret, fortsetter vi kjøringen ved å bruke det første argumentet:

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

La oss komme i gang. For å kompilere programmet vårt kan vi bruke enten clang eller gcc, uansett er det bare å kompilere main.c-filen uten spesielle alternativer:

clang main.c -o filter-write

Som nevnt har vi blokkert alle oppføringer i programmet. For å teste dette trenger du et program som gir ut noe - det virker som en god kandidat. Slik oppfører hun seg vanligvis:

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

Herlig! Slik ser bruken av innpakningsprogrammet vårt ut: Vi passerer ganske enkelt programmet vi vil teste som det første argumentet:

./filter-write "ls -la"

Når det kjøres, produserer dette programmet helt tomt utdata. Vi kan imidlertid bruke strace for å se hva som skjer:

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

Resultatet av arbeidet er sterkt forkortet, men den tilsvarende delen av det viser at poster er blokkert med EPERM-feilen - den samme som vi konfigurerte. Dette betyr at programmet ikke sender ut noe fordi det ikke får tilgang til skrivesystemkallet:

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

Nå forstår du hvordan Secomp BPF fungerer og har en god ide om hva du kan gjøre med den. Men vil du ikke oppnå det samme med eBPF i stedet for cBPF for å utnytte dens fulle kraft?

Når de tenker på eBPF-programmer, tror de fleste at de ganske enkelt skriver dem og laster dem med administratorrettigheter. Selv om denne uttalelsen generelt er sann, implementerer kjernen et sett med mekanismer for å beskytte eBPF-objekter på forskjellige nivåer. Disse mekanismene kalles BPF LSM-feller.

BPF LSM feller

For å gi arkitekturuavhengig overvåking av systemhendelser implementerer LSM konseptet med feller. En hook call ligner teknisk sett på et system call, men er systemuavhengig og integrert med infrastrukturen. LSM gir et nytt konsept der et abstraksjonslag kan bidra til å unngå problemer som oppstår når man håndterer systemanrop på forskjellige arkitekturer.

I skrivende stund har kjernen syv kroker knyttet til BPF-programmer, og SELinux er den eneste innebygde LSM som implementerer dem.

Kildekoden for fellene er plassert i kjernetreet 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 av dem vil bli kalt på forskjellige stadier av henrettelse:

— security_bpf — utfører en innledende sjekk av utførte BPF-systemanrop;

- security_bpf_map - sjekker når kjernen returnerer en filbeskrivelse for kartet;

- security_bpf_prog - sjekker når kjernen returnerer en filbeskrivelse for eBPF-programmet;

— security_bpf_map_alloc — sjekker om sikkerhetsfeltet i BPF-kart er initialisert;

- security_bpf_map_free - sjekker om sikkerhetsfeltet er tømt inne i BPF-kart;

— security_bpf_prog_alloc — sjekker om sikkerhetsfeltet er initialisert i BPF-programmer;

- security_bpf_prog_free - sjekker om sikkerhetsfeltet er tømt inne i BPF-programmer.

Nå, når vi ser alt dette, forstår vi: ideen bak LSM BPF-avskjærere er at de kan gi beskyttelse til hvert eBPF-objekt, og sikre at bare de med de riktige privilegiene kan utføre operasjoner på kort og programmer.

Oppsummering

Sikkerhet er ikke noe du kan implementere på en enhetlig måte for alt du ønsker å beskytte. Det er viktig å kunne beskytte systemer på ulike nivåer og på ulike måter. Tro det eller ei, den beste måten å sikre et system på er å organisere ulike nivåer av beskyttelse fra forskjellige posisjoner, slik at reduksjon av sikkerheten til ett nivå ikke gir tilgang til hele systemet. Kjerneutviklerne har gjort en god jobb med å gi oss et sett med forskjellige lag og berøringspunkter. Vi håper vi har gitt deg en god forståelse av hva lag er og hvordan du bruker BPF-programmer for å jobbe med dem.

Om forfattere

David Calavera er CTO i Netlify. Han jobbet i Docker-støtte og bidro til utviklingen av Runc-, Go- og BCC-verktøy, samt andre åpen kildekode-prosjekter. Kjent for sitt arbeid med Docker-prosjekter og utvikling av Docker-plugin-økosystemet. David er veldig lidenskapelig opptatt av flammegrafer og er alltid ute etter å optimalisere ytelsen.

Lorenzo Fontana jobber på åpen kildekode-teamet hos Sysdig, hvor han primært er fokusert på Falco, et Cloud Native Computing Foundation-prosjekt som gir containerkjøringssikkerhet og avviksdeteksjon gjennom en kjernemodul og eBPF. Han er lidenskapelig opptatt av distribuerte systemer, programvaredefinert nettverk, Linux-kjernen og ytelsesanalyse.

» For mer informasjon om boken, vennligst besøk forlagets nettside
» innholdsfortegnelsen
» Utdrag

For Khabrozhiteli 25% rabatt på kupongen - Linux

Ved betaling av papirutgaven av boken sendes en e-bok til e-post.

Kilde: www.habr.com

Legg til en kommentar