Bogen "BPF til overvÄgning af Linux"

Bogen "BPF til overvĂ„gning af Linux"Hej, Habr-beboere! BPF-virtuelle maskiner er en af de vigtigste komponenter i Linux-kernen. Korrekt anvendelse gĂžr det muligt for systemingeniĂžrer at finde fejl og lĂžse selv de mest komplekse problemer. Du vil lĂŠre at oprette programmer, der overvĂ„ger og modificerer kerneladfĂŠrd, kan sikkert implementere kode til at overvĂ„ge begivenheder i kernen og meget mere. David Calavera og Lorenzo Fontana vil hjĂŠlpe dig med at udforske BPF's muligheder. Udvid din viden om ydeevneoptimering, netvĂŠrk, sikkerhed. — Brug BPF til at overvĂ„ge og modificere adfĂŠrd i Linux-kernen. — Implementer kode til sikker overvĂ„gning af begivenheder i kernen — uden at skulle recompilere kernen eller genstarte systemet. — Benyt dig af nyttige eksempler pĂ„ kode i C, Go eller Python. — Tag kontrol over situationen ved at forstĂ„ livscyklussen for et BPF-program.

Sikkerhed i Linux-kernen, dens muligheder og Seccomp

BPF giver en kraftfuld mÄde at udvide kernen pÄ uden at gÄ pÄ kompromis med stabilitet, sikkerhed og hastighed. Af denne grund mente kerneludviklerne, 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 Seccomp er, og hvordan det anvendes. Derefter vil du lÊre at skrive Seccomp-filtre med BPF-programmer. Til sidst vil vi se pÄ de indbyggede BPF-fÊlder i kernen til sikkerhedsmoduler i Linux.

Linux-sikkerhedsmoduler (LSM) er en platform, der giver et sĂŠt funktioner, der kan anvendes til standardiseret implementering af forskellige sikkerhedsmodeller. LSM kan anvendes direkte i kildetrĂŠet for kernen, f.eks. AppArmor, SELinux og Tomoyo.

Lad os begynde med at diskutere Linux' muligheder.

Muligheder

Essensen af mulighederne i Linux er, at du skal give en ikke-privilegeret proces tilladelse til at udfÞre en bestemt opgave, men uden at bruge suid til dette formÄl, eller pÄ anden mÄde gÞre processen privilegeret, hvilket reducerer muligheden for angreb og giver processen mulighed for at udfÞre specifikke opgaver. For eksempel, hvis din applikation har brug for at Äbne en privilegeret port, lad os sige 80, kan du i stedet for at kÞre processen som root blot give den muligheden CAP_NET_BIND_SERVICE.

Lad os overveje et Go-program ved navn main.go:

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

Dette program serverer en HTTP-server pÄ port 80 (dette er en privilegeret port). Normalt kÞrer vi det straks efter kompilering:

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

Men da vi ikke giver root-rettigheder, vil denne kode returnere en fejl ved binding til porten:

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

capsh (shell management tool) er et vĂŠrktĂžj, der starter en shell med et bestemt sĂŠt af muligheder.

I dette tilfĂŠlde, som allerede nĂŠvnt, i stedet for at give fulde root-rettigheder kan vi tillade binding af privilegerede porte ved at give muligheden cap_net_bind_service sammen med alle de andre, der allerede er i programmet. For at gĂžre dette kan vi indkapsle 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 se nÊrmere pÄ denne kommando.

  • capsh — brug capsh som shell.
  • —caps=’cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep’ — da vi skal skifte bruger (vi Ăžnsker ikke at kĂžre med root-rettigheder), angiver vi cap_net_bind_service og muligheden for faktisk at ĂŠndre bruger-id fra root til nobody, nemlig cap_setuid og cap_setgid.
  • —keep=1 — vi Ăžnsker at bevare de indstillede muligheder, nĂ„r der skiftes fra root-kontoen.
  • —user=«nobody» — den endelige bruger, der kĂžrer programmet, vil vĂŠre nobody.
  • —addamb=cap_net_bind_service — vi angiver, at relaterede muligheder skal rydde op efter at have skiftet fra root-tilstand.
  • — -c ". /capabilities" — vi kĂžrer blot programmet.

Relaterede muligheder er en sÊrlig type muligheder, der arves af datterprogrammer, nÄr det nuvÊrende program udfÞrer dem via execve(). Kun muligheder, der er godkendt som relaterede, kan arves, eller med andre ord, som miljÞmuligheder.

Du er sikkert nysgerrig efter, hvad +eip betyder efter angivelsen af en mulighed i kommandoen —caps. Disse flag bruges til at definere, hvad muligheden:

-skal vĂŠre aktiveret (p);

-er tilgĂŠngelig til anvendelse (e);

-kan arves af datterprocesser (i).

Da vi Ăžnsker at bruge cap_net_bind_service, skal vi gĂžre dette med flaget e. Derefter skal vi starte shell'en i kommandoen. Som resultat vil binĂŠre fil capabilities blive startet, og vi skal markere det med flaget i. Endelig Ăžnsker vi, at muligheden skal vĂŠre aktiveret (vi gjorde dette uden at ĂŠndre UID) ved hjĂŠlp af p. Dette ser ud som cap_net_bind_service+eip.

Du kan kontrollere resultatet med ss. Vi forkorter output noget, sÄ det passer pÄ siden, men det vil vise den tilknyttede port og bruger-id, der er forskellig fra 0, i dette tilfÊlde 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

I dette eksempel brugte vi capsh, men du kan skrive en shell ved hjĂŠlp af libcap. For mere information, henvises der til man 3 libcap.

NÄr programmÞrer skriver programmer, ved de ofte ikke pÄ forhÄnd, hvilke muligheder programmet vil have brug for under kÞrsel; desuden kan disse muligheder Êndre sig i nye versioner.

For bedre at forstÄ mulighederne i vores program, kan vi tage vÊrktÞjet BCC capable, som sÊtter kprobe for kernel-funktionen 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

Vi kan opnÄ det samme ved at bruge bpftrace med en engangskprobe i kernel-funktionen 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 udskrive noget som fĂžlger, hvis mulighederne i vores program 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 angiver de muligheder, processen har brug for, og da disse output inkluderer ikke-revisionerede begivenheder, ser vi alle ikke-revisionerede kontroller og til sidst den nĂždvendige mulighed med revisionsflaget (den sidste i outputtet), der er sat til 1. Den mulighed, vi er interesseret i, er CAP_NET_BIND_SERVICE, som er defineret som en konstant i kernens kildekode i filen include/uapi/linux/ability.h med identifikatoren 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">

Muligheder anvendes ofte under udfĂžrelsen af containere som runC eller Docker, sĂ„ de kan kĂžre i uhĂŠmmet tilstand, men kun fĂ„r tildelt de nĂždvendige muligheder for at kĂžre de fleste applikationer. NĂ„r en applikation har brug for specifikke muligheder, kan disse gives i Docker ved hjĂŠlp af —cap-add:

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

Denne kommando giver containeren mulighed for CAP_NET_ADMIN, hvilket gĂžr det muligt for den at konfigurere et netvĂŠrkslink til at tilfĂžje dummy0-interfacet.

I det fÞlgende afsnit vises brugen af sÄdanne muligheder som filtrering, men med en anden metode, der giver os mulighed for programmatiske implementeringer af vores egne filtre.

Seccomp

Seccomp stÄr for Secure Computing, og det er et sikkerhedsniveau, der er implementeret i Linux-kernen, som gÞr det muligt for udviklere at filtrere bestemte systemopkald. Selvom Seccomp er sammenligneligt med Linux-muligheder, gÞr dets evne til at styre bestemte systemopkald det langt mere fleksibelt end dem.

Seccomp og Linux-muligheder udelukker ikke hinanden, og de bruges ofte sammen for at drage fordel af begge tilgange. For eksempel kan du Ăžnske at give en proces mulighed for CAP_NET_ADMIN, men ikke tillade den at tage forbindelser via socket, ved at blokere systemopkald som accept og accept4.

Seccomp-filtermetoden er baseret pÄ BPF-filtre, der kÞrer i SECCOMP_MODE_FILTER-tilstand, og filtreringen af systemopkald udfÞres ligesom for pakker.

Seccomp-filtre indlĂŠses ved hjĂŠlp af prctl via operationen PR_SET_SECCOMP. Disse filtre er i form af et BPF-program, der udfĂžres for hver Seccomp-pakke, der prĂŠsenteres med struktur seccomp_data. Denne struktur indeholder referencearkitekturen, en peger til processorens instruktioner under systemopkaldet og op til seks argumenter for systemopkaldet, udtrykt som uint64.

SÄdan ser strukturen seccomp_data ud fra kildekoden til kernen i filen linux/seccomp.h:

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

Som det ses i denne struktur, kan vi filtrere efter systemopkaldet, dets argumenter eller deres kombination.

Efter modtagelse af hver pakke skal Seccomp-filteret udfĂžre behandling for at trĂŠffe en endelig beslutning og informere kernen om, hvad der skal ske derefter. Den endelige beslutning udtrykkes med en af de returnerede vĂŠrdier (statuskoder).

— SECCOMP_RET_KILL_PROCESS — afslutning af hele processen straks efter filtrering af systemopkaldet, som derfor ikke udfþres.

— SECCOMP_RET_KILL_THREAD — afslutning af den aktuelle trĂ„d straks efter filtrering af systemopkaldet, som derfor ikke udfĂžres.

— SECCOMP_RET_KILL — alias for SECCOMP_RET_KILL_THREAD, tilbageholdt for bagudkompatibilitet.

— SECCOMP_RET_TRAP — systemopkaldet er forbudt, og signalet SIGSYS (Bad System Call) sendes til den kaldende opgave.

— SECCOMP_RET_ERRNO — systemopkaldet udfĂžres ikke, og en del af den returnerede vĂŠrdi fra filteret SECCOMP_RET_DATA overfĂžres til brugerrummet som errno-vĂŠrdien. AfhĂŠngigt af fejlĂ„rsagen returneres forskellige errno-vĂŠrdier. Listen over fejlnumre prĂŠsenteres i den fĂžlgende sektion.

— SECCOMP_RET_TRACE — bruges til at underrette traceren ptrace med — PTRACE_O_TRACESECCOMP for at opfange, nĂ„r et systemopkald udfĂžres, for at se og kontrollere denne proces. Hvis traceren ikke er tilsluttet, returneres en fejl, errno sĂŠttes til -ENOSYS, og systemopkaldet udfĂžres ikke.

— SECCOMP_RET_LOG — systemopkaldet er tilladt og registreret i loggen.

— SECCOMP_RET_ALLOW — systemopkaldet er blot tilladt.

ptrace er et systemopkald til implementering af sporingsmekanismer i en proces, der kaldes tracee, med mulighed for at observere og kontrollere udfÞrelsen af processen. Sporingsprogrammet kan effektivt pÄvirke udfÞrelsen og Êndre tracee's hukommelsesregistre. I konteksten af Seccomp bruges ptrace, nÄr den aktiveres af SECCOMP_RET_TRACE-statuskoden, sÄledes at tracer kan forhindre udfÞrelsen af systemopkaldet og implementere sin egen logik.

Seccomp-fejl

Fra tid til anden, nÄr du arbejder med Seccomp, vil du stÞde pÄ forskellige fejl, som identificeres af den returnerede vÊrdi af typen SECCOMP_RET_ERRNO. For at rapportere en fejl vil systemopkaldet seccomp returnere -1 i stedet for 0.

FĂžlgende fejl kan forekomme:

— EACCESS — den kaldende part har ikke tilladelse til at foretage systemopkald. Dette sker normalt fordi den ikke har CAP_SYS_ADMIN privilegier eller fordi no_new_privs ikke er sat med prctl (dette vil vi tale om senere);

— EFAULT — de overfþrte argumenter (args i seccomp_data strukturen) har ikke en gyldig adresse;

— EINVAL — der kan vĂŠre fire Ă„rsager her:

- den anmodede operation er ukendt eller understĂžttes ikke af kernen i den nuvĂŠrende konfiguration;

- de angivne flag er ugyldige for den anmodede operation;

- operationen inkluderer BPF_ABS, men der er problemer med den angivne forskydning, der kan overskride stĂžrrelsen af seccomp_data strukturen;

- antallet af instruktioner, der er givet til filteret, overskrider maksimum;

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

— EOPNOTSUPP — operationen angav, at SECCOMP_GET_ACTION_AVAIL-handlingen var tilgéngelig, men kernen understþtter ikke tilbagevenden i argumenterne;

— ESRCH — der opstod et problem med synkronisering af en anden trĂ„d;

— ENOSYS — der er ingen tracer knyttet til SECCOMP_RET_TRACE-handlingen.

prctl er et systemopkald, som gÞr det muligt for et brugerprogram at administrere (sÊtte og fÄ) specifikke aspekter af processen, sÄsom byteorden, trÄdnavne, beskyttelsesmitteringsmodus (Seccomp), privilegier, Perf-begivenheder osv.

Seccomp kan synes at vĂŠre en sandkasse teknologi, men det er ikke tilfĂŠldet. Seccomp er et vĂŠrktĂžj, der gĂžr det muligt for brugerne at udvikle en sandkassemekanisme. Lad os nu se, hvordan brugerinteraktionsprogrammer skabes ved hjĂŠlp af et filter, der kaldes direkte med seccomp-systemopkaldet.

Eksempel pÄ Seccomp BPF-filter

Her vil vi vise, hvordan man forbinder de to tidligere nĂŠvnte handlinger, nemlig:

— vi vil skrive et Seccomp BPF-program, der vil blive anvendt som filter med forskellige returkoder afhéngigt af de trufne beslutninger;

— vi vil indlése filteret ved hjélp af prctl.

Til at begynde med skal vi have 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 at udfÞre dette eksempel, skal vi sikre os, at kernen er kompileret med CONFIG_SECCOMP og CONFIG_SECCOMP_FILTER sat til y. PÄ en arbejdsstation kan dette kontrolleres sÄdan:

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

Den Þvrige del af koden udgÞr funktionen install_filter, som bestÄr af to dele. Den fÞrste del indeholder vores liste over BPF-filter instruktioner:

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 sĂŠttes med makroerne BPF_STMT og BPF_JUMP, som 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éser og akkumulerer med BPF_LD i form af ord BPF_W, pakkedataene er placeret med et fast offset BPF_ABS.

— BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arch, 0, 3) — kontrollerer med BPF_JEQ, om vĂŠrdien af arkitekturen i konstantakkumulatoren BPF_K er lig med arch. Hvis ja, gĂ„r det videre til den nĂŠste instruktion med offset 0; ellers springes der til offset 3 for at give en fejl (i dette tilfĂŠlde), fordi arch ikke stemmer overens.

— BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, nr))) — indlĂŠser og akkumulerer med BPF_LD i form af ord BPF_W, som er nummeret pĂ„ systemkaldet, der findes pĂ„ et fast offset BPF_ABS.

— BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1) — sammenligner nummeret pĂ„ systemkaldet med vĂŠrdien af variablen nr. Hvis de er ens, gĂ„r det videre til den nĂŠste instruktion og forbyder systemkaldet; ellers tillader det systemkaldet med SECCOMP_RET_ALLOW.

— BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (error & SECCOMP_RET_DATA)) — afslutter programmet med BPF_RET og resulterer i at give fejlen SECCOMP_RET_ERRNO med nummeret fra variablen err.

— BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW) — afslutter programmet med BPF_RET og tillader udfþrelsen af systemkaldet ved hjélp af SECCOMP_RET_ALLOW.

SECCOMP — DETTE ER CBPF
MÄske undrer du dig over, hvorfor der i stedet for et kompileret ELF-objekt eller et program skrevet i C, kompilert med JIT, bruges en liste over instruktioner.

Der er to grunde til dette.

‱ For det fþrste anvender Seccomp cBPF (klassisk BPF) og ikke eBPF, hvilket betyder: den har ikke registre, men kun en akkumulator til at opbevare det sidste resultat af beregningerne, som man kan se i eksemplet.

‱ For det andet accepterer Seccomp en peger til et array af BPF-instruktioner direkte og intet andet. De makroer, vi har brugt, hjélper blot med at angive disse instruktioner i en programmerervenlig form.

Hvis du har brug for yderligere hjÊlp til at forstÄ denne opbygning, sÄ overvej pseudokoden, som 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 sock_fprog, som indeholder koden og den beregnede lĂŠngde af filteret. Denne datakonstruktion er nĂždvendig som et argument til erklĂŠringen om at fortsĂŠtte processen:

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

Der er kun Ă©n ting, der er tilbage at gĂžre i funktionen install_filter — at indlĂŠse selve programmet! Til dette bruger vi prctl med PR_SET_SECCOMP som option for at gĂ„ ind i beskyttede beregninger. Vi angiver derefter tilstanden til at indlĂŠse filteret ved hjĂŠlp af SECCOMP_MODE_FILTER, som er indeholdt i variablen prog 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 benytte vores funktion install_filter, men fÞrst skal prctl anvendes for at indstille PR_SET_NO_NEW_PRIVS for den aktuelle udfÞrelse og dermed undgÄ, at bÞrneprocesser fÄr bredere rettigheder end forÊldrene. I den forbindelse kan vi foretage fÞlgende prctl-opkald i funktionen install_filter uden root-rettigheder.

Nu kan vi kalde funktionen install_filter. Vi blokerer alle systemopkald, der vedrĂžrer skrivninger relateret til X86-64-arkitekturen, og giver blot tilladelse, der blokerer alle forsĂžg. Efter at have indstillet filteret fortsĂŠtter vi udfĂžrelsen ved at bruge 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 i gang. Til at kompilere vores program kan vi bruge enten clang eller gcc; i begge tilfĂŠlde er det blot kompilering af filen main.c uden specielle indstillinger:

clang main.c -o filter-write

Som névnt har vi blokeret alle skrivninger i programmet. For at teste dette har vi brug for et program, der outputter noget — ls ser ud til at vére en god kandidat. Her er, hvordan det normalt opfþrer sig:

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

Fantastisk! SÄdan ser det ud at bruge vores shell-program: vi sender blot programmet, vi Þnsker at teste, som det fÞrste argument:

./filter-write "ls -la"

Efter udfĂžrelsen giver dette program helt tom output. Ikke desto mindre kan vi anvende strace for at se, hvad der sker:

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

Resultatet er betydeligt forkortet, men den relevante del viser, at optegnelserne blokeres med fejl EPERM — den samme, vi har konfigureret. Det betyder, at programmet ikke giver noget output, fordi det ikke kan fĂ„ adgang til systemkaldet write:

[pid 25099] write(2, "ls: ", 4) = -1 EPERM (Operation ikke tilladt)
[pid 25099] write(2, "skrivningsfejl", 11) = -1 EPERM (Operation ikke tilladt)
[pid 25099] write(2, "n", 1) = -1 EPERM (Operation ikke tilladt)

Nu forstÄr du, hvordan Seccomp BPF fungerer, og du har en god idé om, hvad der kan gÞres med det. Men ville det ikke vÊre fantastisk at opnÄ det samme med eBPF i stedet for cBPF for at udnytte hele dens kraft?

NÄr man tÊnker pÄ eBPF-programmer, tÊnker de fleste pÄ, at de blot skriver dem og uploader dem med administratorrettigheder. Selvom denne pÄstand generelt er sand, implementerer kernen et sÊt mekanismer til at beskytte eBPF-objekter pÄ forskellige niveauer. Disse mekanismer kaldes BPF LSM fÊlter.

BPF LSM fĂŠlter

For at sikre en arkitektur-uafhÊngig kontrol af systembegivenheder implementerer LSM konceptet med fÊlter. Teknisk set ligner et felts kald et systemkald, men er uafhÊngigt af systemet og integreret med infrastrukturen. LSM prÊsenterer et nyt koncept, hvor abstraheringsniveauet er i stand til at hjÊlpe med at undgÄ problemer, der opstÄr ved hÄndtering af systemkald pÄ forskellige arkitekturer.

PĂ„ tidspunktet for bogens skrivning havde kernen syv fĂŠlter relateret til BPF-programmer og SELinux — den eneste indbyggede LSM, der implementerer dem.

Kildekoden til fĂŠlterne er placeret i kernel-trĂŠ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 tidspunkter i udfÞrelsen:

— security_bpf — udfþrer en indledende kontrol af udfþrte systemopkald fra BPF;

— security_bpf_map — kontrollerer, nĂ„r kernen returnerer en fildescriptor for en kortlĂŠgning;

— security_bpf_prog — kontrollerer, nĂ„r kernen returnerer en fildescriptor for et eBPF-program;

— security_bpf_map_alloc — kontrollerer, om sikkerhedsfeltet er initialiseret inden for BPF-kortlégninger;

— security_bpf_map_free — kontrollerer, om sikkerhedsfeltet renses inden for BPF-kortlégninger;

— security_bpf_prog_alloc — kontrollerer, om sikkerhedsfeltet initialiseres inden for BPF-programmer;

— security_bpf_prog_free — kontrollerer, om sikkerhedsfeltet renses inden for BPF-programmer.

Nu, ved at se alt dette, forstÄr vi: Ideen med LSM BPF-holdere er, at de kan sikre hver eBPF-objekt, hvilket sikrer, at kun de med de nÞdvendige privilegier kan udfÞre operationer pÄ kortlÊgninger og programmer.

CV

Sikkerhed er ikke noget, du kan implementere pÄ en universel mÄde for alt, hvad du Þnsker at beskytte. Det er vigtigt at have mulighed for at 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 beskyttelseslag fra forskellige positioner, sÄ reduktion af sikkerheden i et lag ikke Äbner adgangen til hele systemet. Kerneludviklerne har gjort et stort stykke arbejde for at give os et sÊt forskellige lag og interaktionspunkter. Vi hÄber, at vi har givet dig en god forstÄelse af, hvad lag er, og hvordan man bruger BPF-programmer til at arbejde med dem.

Om forfatterne

David Calavera er teknisk direktĂžr hos Netlify. Han har arbejdet i Docker-support og har vĂŠret involveret i udviklingen af vĂŠrktĂžjer som Runc, Go og BCC samt andre open source-projekter. Han er kendt for sit arbejde med Docker-projekter og udvikling af Docker-plugin-Ăžkosystemet. David elsker flamegrafer og strĂŠber altid efter at optimere ydeevnen.

Lorenzo Fontana arbejder i et team af softwareudviklere med open source i Sysdig, hvor han primĂŠrt arbejder med Falco - et projekt under Cloud Native Computing Foundation, der sikrer sikkerheden i containerkĂžrselsmiljĂžer og opdager anomalier gennem kernelmodul og eBPF. Han er passioneret omkring distribuerede systemer, softwaredefinerede netvĂŠrk, Linux-kernen og ydeevneanalyse.

» Mere information om bogen kan findes pÄ forlagets hjemmeside
» Indholdsfortegnelse
» Uddrag

For Habr-lésere er der 25% rabat med koden — Linux

Ved betaling af den fysiske version af bogen sendes e-bogen til e-mail.

Kilde: habr.com

KĂžb pĂ„lidelig webhosting med DDoS-beskyttelse, VPS VDS-servere đŸ”„ KĂžb pĂ„lidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster