Knjiga "BPF za praćenje Linuxa"

Knjiga "BPF za praćenje Linuxa"Pozdrav, stanovnici Khabra! BPF virtualni stroj jedna je od najvažnijih komponenti Linux kernela. Njegova pravilna uporaba omogućit će inženjerima sustava pronalaženje grešaka i rješavanje čak i najsloženijih problema. Naučit ćete kako napisati programe koji nadziru i modificiraju ponašanje jezgre, kako sigurno implementirati kod za praćenje događaja u jezgri i još mnogo toga. David Calavera i Lorenzo Fontana pomoći će vam da otključate snagu BPF-a. Proširite svoje znanje o optimizaciji performansi, umrežavanju, sigurnosti. - Koristite BPF za praćenje i modificiranje ponašanja Linux kernela. - Ubacite kod za sigurno praćenje događaja u jezgri bez potrebe za rekompajliranjem jezgre ili ponovnog pokretanja sustava. — Koristite prikladne primjere koda u C-u, Go-u ili Pythonu. - Preuzmite kontrolu posjedovanjem životnog ciklusa BPF programa.

Sigurnost Linux kernela, njegove značajke i Seccomp

BPF pruža moćan način za proširenje kernela bez žrtvovanja stabilnosti, sigurnosti ili brzine. Iz tog razloga, programeri kernela smatrali su da bi bilo dobro iskoristiti njegovu svestranost za poboljšanje izolacije procesa u Seccompu implementacijom Seccomp filtara koje podržavaju BPF programi, također poznati kao Seccomp BPF. U ovom poglavlju ćemo objasniti što je Seccomp i kako se koristi. Zatim ćete naučiti kako napisati Seccomp filtre koristeći BPF programe. Nakon toga, pogledat ćemo ugrađene BPF kuke koje su uključene u kernel za sigurnosne module Linuxa.

Sigurnosni moduli Linuxa (LSM) okvir su koji pruža skup funkcija koje se mogu koristiti za implementaciju različitih sigurnosnih modela na standardiziran način. LSM se može koristiti izravno u izvornom stablu kernela, kao što su Apparmor, SELinux i Tomoyo.

Počnimo s raspravom o mogućnostima Linuxa.

Sposobnosti

Bit mogućnosti Linuxa je da neprivilegiranom procesu trebate dodijeliti dopuštenje za obavljanje određenog zadatka, ali bez korištenja suid-a za tu svrhu, ili na neki drugi način učiniti proces privilegiranim, smanjujući mogućnost napada i dopuštajući procesu da izvrši određene zadatke. Na primjer, ako vaša aplikacija treba otvoriti povlašteni port, recimo 80, umjesto pokretanja procesa kao root, možete joj jednostavno dati mogućnost CAP_NET_BIND_SERVICE.

Razmotrite Go program pod nazivom main.go:

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

Ovaj program poslužuje HTTP poslužitelj na portu 80 (ovo je privilegirani port). Obično ga pokrećemo odmah nakon kompilacije:

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

Međutim, budući da ne dodjeljujemo root povlastice, ovaj kod će izbaciti pogrešku prilikom povezivanja porta:

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

capsh (shell manager) je alat koji pokreće shell s određenim skupom mogućnosti.

U ovom slučaju, kao što je već spomenuto, umjesto dodjele potpunih root prava, možete omogućiti privilegirano povezivanje porta pružanjem mogućnosti cap_net_bind_service zajedno sa svim ostalim što je već u programu. Da bismo to učinili, možemo priložiti naš program u 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"

Hajdemo malo razumjeti ovu ekipu.

  • capsh - koristite capsh kao školjku.
  • —caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' - budući da moramo promijeniti korisnika (ne želimo raditi kao root), navest ćemo cap_net_bind_service i mogućnost stvarne promjene ID-a korisnika iz root nikome, naime cap_setuid i cap_setgid.
  • —keep=1 — želimo zadržati instalirane mogućnosti prilikom prelaska s root računa.
  • —user=“nitko” — krajnji korisnik koji pokreće program bit će nitko.
  • —addamb=cap_net_bind_service — postavite brisanje povezanih mogućnosti nakon prebacivanja iz root načina.
  • - -c "./capabilities" - samo pokrenite program.

Povezane mogućnosti su posebna vrsta mogućnosti koje nasljeđuju podređeni programi kada ih trenutni program izvršava pomoću execve(). Samo sposobnosti koje je dopušteno pridružiti, ili drugim riječima, kao mogućnosti okoline, mogu se naslijediti.

Vjerojatno se pitate što znači +eip nakon navođenja mogućnosti u opciji --caps. Ove zastavice se koriste za utvrđivanje da je sposobnost:

-mora biti aktiviran (p);

- dostupno za korištenje (e);

-mogu naslijediti podređeni procesi (i).

Budući da želimo koristiti cap_net_bind_service, moramo to učiniti s oznakom e. Zatim ćemo pokrenuti ljusku u naredbi. Ovo će pokrenuti binarne mogućnosti i moramo to označiti zastavicom i. Konačno, želimo da značajka bude omogućena (učinili smo to bez promjene UID-a) s p. Izgleda kao cap_net_bind_service+eip.

Možete provjeriti rezultat koristeći ss. Skratimo malo izlaz da stane na stranicu, ali će prikazati pridruženi port i korisnički ID koji nije 0, u ovom slučaju 65:

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

U ovom smo primjeru koristili capsh, ali možete napisati ljusku koristeći libcap. Za više informacija pogledajte man 3 libcap.

Pri pisanju programa vrlo često programer ne zna unaprijed sve značajke koje program treba tijekom izvođenja; Štoviše, te se značajke mogu promijeniti u novim verzijama.

Da bismo bolje razumjeli mogućnosti našeg programa, možemo uzeti BCC sposoban alat, koji postavlja kprobe za cap_capable kernel funkciju:

/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

Istu stvar možemo postići korištenjem bpftracea s kprobeom u jednom retku u funkciji jezgre 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

Ovo će ispisati nešto poput sljedećeg ako su mogućnosti našeg programa omogućene nakon 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

Peti stupac su sposobnosti koje su potrebne procesu, a budući da ovaj izlaz uključuje događaje koji nisu povezani s revizijom, vidimo sve provjere koje nisu povezane s revizijom i na kraju potrebnu sposobnost s oznakom revizije (zadnja u izlazu) postavljenom na 1. Sposobnost. jedan koji nas zanima je CAP_NET_BIND_SERVICE, definiran je kao konstanta u izvornom kodu kernela u datoteci include/uapi/linux/ability.h s identifikatorom 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">

Mogućnosti su često omogućene tijekom izvođenja za spremnike kao što su runC ili Docker kako bi im se omogućilo izvođenje u neprivilegiranom načinu rada, ali dopuštene su im samo mogućnosti potrebne za pokretanje većine aplikacija. Kada aplikacija zahtijeva određene mogućnosti, Docker ih može pružiti koristeći --cap-add:

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

Ova naredba će spremniku dati mogućnost CAP_NET_ADMIN, dopuštajući mu da konfigurira mrežnu vezu za dodavanje dummy0 sučelja.

Sljedeći odjeljak pokazuje kako koristiti značajke kao što je filtriranje, ali koristeći drugu tehniku ​​koja nam omogućuje programsku implementaciju vlastitih filtara.

Seccomp

Seccomp je kratica za Secure Computing i sigurnosni je sloj implementiran u Linux kernelu koji programerima omogućuje filtriranje određenih poziva sustava. Iako je Seccomp po mogućnostima usporediv s Linuxom, njegova mogućnost upravljanja određenim sistemskim pozivima čini ga mnogo fleksibilnijim u usporedbi s njima.

Značajke Seccompa i Linuxa međusobno se ne isključuju i često se koriste zajedno kako bi imali koristi od oba pristupa. Na primjer, možda biste željeli dati procesu sposobnost CAP_NET_ADMIN, ali mu ne dopustiti prihvaćanje socket veza, blokirajući accept i accept4 sistemske pozive.

Metoda filtriranja Seccomp temelji se na BPF filterima koji rade u SECCOMP_MODE_FILTER modu, a filtriranje sistemskih poziva se izvodi na isti način kao i za pakete.

Seccomp filtri se učitavaju korištenjem prctl preko PR_SET_SECCOMP operacije. Ovi filteri imaju oblik BPF programa koji se izvršava za svaki Seccomp paket predstavljen strukturom seccomp_data. Ova struktura sadrži referentnu arhitekturu, pokazivač na instrukcije procesora u vrijeme sistemskog poziva i maksimalno šest argumenata sistemskog poziva, izraženih kao uint64.

Ovako izgleda struktura seccomp_data iz izvornog koda kernela u datoteci linux/seccomp.h:

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

Kao što možete vidjeti iz ove strukture, možemo filtrirati prema pozivu sustava, njegovim argumentima ili kombinaciji oba.

Nakon primanja svakog Seccomp paketa, filtar mora izvršiti obradu kako bi donio konačnu odluku i rekao kernelu što treba učiniti sljedeće. Konačna odluka se izražava jednom od povratnih vrijednosti (statusni kodovi).

- SECCOMP_RET_KILL_PROCESS - ubija cijeli proces odmah nakon filtriranja sistemskog poziva koji se zbog toga ne izvršava.

- SECCOMP_RET_KILL_THREAD - prekida trenutnu nit odmah nakon filtriranja sistemskog poziva koji se zbog toga ne izvršava.

— SECCOMP_RET_KILL — pseudonim za SECCOMP_RET_KILL_THREAD, ostavljen radi kompatibilnosti s prethodnim verzijama.

- SECCOMP_RET_TRAP - sistemski poziv je zabranjen, a SIGSYS (Bad System Call) signal se šalje zadatku koji ga poziva.

- SECCOMP_RET_ERRNO - Sistemski poziv se ne izvršava, a dio povratne vrijednosti filtra SECCOMP_RET_DATA prosljeđuje se korisničkom prostoru kao errno vrijednost. Ovisno o uzroku pogreške, vraćaju se različite errno vrijednosti. Popis brojeva pogrešaka nalazi se u sljedećem odjeljku.

- SECCOMP_RET_TRACE - Koristi se za obavještavanje ptrace tragača pomoću - PTRACE_O_TRACESECCOMP za presretanje kada se izvrši sistemski poziv kako bi se vidio i kontrolirao taj proces. Ako tracer nije spojen, vraća se pogreška, errno je postavljen na -ENOSYS i sistemski poziv se ne izvršava.

- SECCOMP_RET_LOG - sistemski poziv je riješen i zapisan.

- SECCOMP_RET_ALLOW - poziv sustava je jednostavno dopušten.

ptrace je sistemski poziv za implementaciju mehanizama praćenja u proces koji se zove tracee, uz mogućnost praćenja i kontrole izvršenja procesa. Program za praćenje može učinkovito utjecati na izvođenje i modificirati memorijske registre za praćenje. U Seccomp kontekstu, ptrace se koristi kada ga aktivira statusni kod SECCOMP_RET_TRACE, tako da praćenje može spriječiti izvršavanje sistemskog poziva i implementirati vlastitu logiku.

Seccomp pogreške

S vremena na vrijeme, dok radite sa Seccompom, naići ćete na razne greške, koje se identificiraju povratnom vrijednošću tipa SECCOMP_RET_ERRNO. Za prijavu pogreške, sistemski poziv seccomp vratit će -1 umjesto 0.

Moguće su sljedeće greške:

- EACCESS - Pozivatelju nije dopušteno uspostaviti sistemski poziv. To se obično događa jer nema privilegije CAP_SYS_ADMIN ili no_new_privs nije postavljen pomoću prctl (o tome ćemo kasnije);

— EFAULT — proslijeđeni argumenti (argovi u strukturi seccomp_data) nemaju valjanu adresu;

— EINVAL — ovdje mogu postojati četiri razloga:

-tražena operacija je nepoznata ili jezgra ne podržava u trenutnoj konfiguraciji;

-navedene oznake nisu važeće za traženu operaciju;

-operacija uključuje BPF_ABS, ali postoje problemi s navedenim pomakom, koji može premašiti veličinu strukture seccomp_data;

-broj instrukcija proslijeđenih filtru premašuje maksimum;

— ENOMEM — nema dovoljno memorije za izvođenje programa;

- EOPNOTSUPP - operacija je pokazala da je sa SECCOMP_GET_ACTION_AVAIL akcija dostupna, ali kernel ne podržava vraćanje u argumentima;

— ESRCH — pojavio se problem prilikom sinkronizacije drugog toka;

- ENOSYS - Nema tragača pridruženog radnji SECCOMP_RET_TRACE.

prctl je sistemski poziv koji omogućuje programu korisničkog prostora da manipulira (postavi i dobije) specifične aspekte procesa, kao što su bajtovi, nazivi niti, način sigurnog računanja (Seccomp), privilegije, Perf događaji, itd.

Seccomp vam se možda čini kao sandbox tehnologija, ali nije. Seccomp je uslužni program koji korisnicima omogućuje razvoj mehanizma sandboxa. Sada pogledajmo kako se kreiraju programi za interakciju s korisnikom pomoću filtra koji se izravno poziva Seccomp sistemskim pozivom.

Primjer filtra BPF Seccomp

Ovdje ćemo pokazati kako kombinirati dvije radnje o kojima smo ranije govorili, naime:

— napisat ćemo Seccomp BPF program koji će se koristiti kao filter s različitim povratnim kodovima ovisno o donesenim odlukama;

— učitati filtar pomoću prctl.

Najprije su vam potrebna zaglavlja iz standardne biblioteke i Linux kernela:

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

Prije pokušaja ovog primjera, moramo osigurati da je kernel kompajliran s CONFIG_SECCOMP i CONFIG_SECCOMP_FILTER postavljenim na y. Na radnom stroju to možete provjeriti ovako:

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

Ostatak koda dvodijelna je funkcija install_filter. Prvi dio sadrži naš popis uputa za filtriranje BPF-a:

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

Upute se postavljaju pomoću makronaredbi BPF_STMT i BPF_JUMP definiranih u datoteci linux/filter.h.
Prođimo kroz upute.

- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, arch))) - sustav učitava i akumulira iz BPF_LD u obliku riječi BPF_W, paketni podaci nalaze se na fiksnom pomaku BPF_ABS.

- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arch, 0, 3) - provjerava pomoću BPF_JEQ je li vrijednost arhitekture u konstanti akumulatora BPF_K jednaka arch. Ako je tako, skače na pomaku 0 na sljedeću instrukciju, inače skače na pomaku 3 (u ovom slučaju) da bi se javila pogreška jer se arch ne podudara.

- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, nr))) - Učitava i akumulira iz BPF_LD u obliku riječi BPF_W, što je broj poziva sustava sadržan u fiksnom pomaku BPF_ABS.

— BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1) — uspoređuje broj poziva sustava s vrijednošću varijable nr. Ako su jednaki, prelazi na sljedeću instrukciju i onemogućuje sistemski poziv, inače dopušta sistemski poziv sa SECCOMP_RET_ALLOW.

- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (greška & SECCOMP_RET_DATA)) - prekida program s BPF_RET i kao rezultat proizvodi grešku SECCOMP_RET_ERRNO s brojem iz varijable err.

- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW) - prekida program s BPF_RET i dopušta da se sistemski poziv izvrši pomoću SECCOMP_RET_ALLOW.

SECCOMP JE CBPF
Možda se pitate zašto se koristi popis uputa umjesto prevedenog ELF objekta ili JIT prevedenog C programa.

Dva su razloga za to.

• Prvo, Seccomp koristi cBPF (klasični BPF), a ne eBPF, što znači: nema registre, već samo akumulator za pohranjivanje zadnjeg rezultata izračuna, kao što se može vidjeti u primjeru.

• Drugo, Seccomp izravno prihvaća pokazivač na niz BPF instrukcija i ništa drugo. Makronaredbe koje smo koristili jednostavno pomažu specificirati ove upute na programerski prihvatljiv način.

Ako vam je potrebna dodatna pomoć u razumijevanju ovog sklopa, razmislite o pseudokodu koji radi istu stvar:

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

Nakon definiranja koda filtra u strukturi socket_filter, trebate definirati sock_fprog koji sadrži kod i izračunatu duljinu filtra. Ova struktura podataka je potrebna kao argument za deklariranje procesa za kasnije pokretanje:

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

U funkciji install_filter preostaje još samo jedno - učitati sam program! Da bismo to učinili, koristimo prctl, uzimajući PR_SET_SECCOMP kao opciju za ulazak u sigurni računalni način rada. Zatim kažemo modu da učita filtar koristeći SECCOMP_MODE_FILTER, koji je sadržan u prog varijabli tipa sock_fprog:

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

Konačno, možemo upotrijebiti našu install_filter funkciju, ali prije toga moramo upotrijebiti prctl da postavimo PR_SET_NO_NEW_PRIVS za trenutno izvođenje i time izbjegnemo situaciju u kojoj podređeni procesi dobivaju više privilegija od svojih roditelja. S ovime možemo izvršiti sljedeće prctl pozive u funkciji install_filter bez posjedovanja root prava.

Sada možemo pozvati funkciju install_filter. Blokirajmo sve sistemske pozive pisanja koji se odnose na arhitekturu X86-64 i jednostavno dajmo dozvolu koja blokira sve pokušaje. Nakon instaliranja filtra, nastavljamo s izvođenjem koristeći prvi 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]);
 }

Započnimo. Za prevođenje našeg programa možemo koristiti ili clang ili gcc, u svakom slučaju to je samo prevođenje datoteke main.c bez posebnih opcija:

clang main.c -o filter-write

Kao što je navedeno, blokirali smo sve unose u programu. Da biste ovo testirali, potreban vam je program koji nešto ispisuje - čini se kao dobar kandidat. Ovako se ona obično ponaša:

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

Predivno! Evo kako izgleda korištenje našeg programa omotača: Jednostavno prosljeđujemo program koji želimo testirati kao prvi argument:

./filter-write "ls -la"

Kada se izvrši, ovaj program proizvodi potpuno prazan izlaz. Međutim, možemo koristiti strace da vidimo što se događa:

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

Rezultat rada je znatno skraćen, ali odgovarajući dio pokazuje da su zapisi blokirani s greškom EPERM - istom onom koju smo mi konfigurirali. To znači da program ne ispisuje ništa jer ne može pristupiti sistemskom pozivu write:

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

Sada razumijete kako Seccomp BPF radi i imate dobru predodžbu o tome što možete učiniti s njim. Ali ne biste li željeli postići istu stvar s eBPF-om umjesto cBPF-om kako biste iskoristili njegovu punu snagu?

Kada razmišljaju o eBPF programima, većina ljudi misli da ih jednostavno pišu i učitavaju s administratorskim ovlastima. Iako je ova izjava općenito točna, kernel implementira skup mehanizama za zaštitu eBPF objekata na različitim razinama. Ti se mehanizmi nazivaju BPF LSM zamke.

BPF LSM zamke

Kako bi osigurao praćenje događaja sustava neovisno o arhitekturi, LSM implementira koncept zamki. Poziv za spajanje tehnički je sličan pozivu sustava, ali je neovisan o sustavu i integriran je s infrastrukturom. LSM pruža novi koncept u kojem sloj apstrakcije može pomoći u izbjegavanju problema koji se javljaju kada se radi sa sistemskim pozivima na različitim arhitekturama.

U vrijeme pisanja, jezgra ima sedam spojnica povezanih s BPF programima, a SELinux je jedini ugrađeni LSM koji ih implementira.

Izvorni kod za zamke nalazi se u stablu kernela u datoteci 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);

Svaki od njih bit će pozvan u različitim fazama izvršenja:

— security_bpf — izvodi početnu provjeru izvršenih BPF sistemskih poziva;

- security_bpf_map - provjerava kada kernel vraća deskriptor datoteke za kartu;

- security_bpf_prog - provjerava kada kernel vraća deskriptor datoteke za eBPF program;

— security_bpf_map_alloc — provjerava je li sigurnosno polje unutar BPF mapa inicijalizirano;

- security_bpf_map_free - provjerava je li sigurnosno polje izbrisano unutar BPF mapa;

— security_bpf_prog_alloc — provjerava je li sigurnosno polje inicijalizirano unutar BPF programa;

- security_bpf_prog_free - provjerava je li sigurnosno polje izbrisano unutar BPF programa.

Sada, kada vidimo sve ovo, razumijemo: ideja iza LSM BPF presretača je da oni mogu pružiti zaštitu svakom eBPF objektu, osiguravajući da samo oni s odgovarajućim privilegijama mogu izvoditi operacije na karticama i programima.

Rezime

Sigurnost nije nešto što možete implementirati na univerzalan način za sve što želite zaštititi. Važno je moći zaštititi sustave na različitim razinama i na različite načine. Vjerovali ili ne, najbolji način za osiguranje sustava je organiziranje različitih razina zaštite s različitih pozicija, tako da smanjenje sigurnosti jedne razine ne omogući pristup cijelom sustavu. Glavni programeri obavili su sjajan posao dajući nam skup različitih slojeva i dodirnih točaka. Nadamo se da smo vam dobro razumjeli što su slojevi i kako koristiti BPF programe za rad s njima.

O autorima

David Calavera je CTO u Netlifyju. Radio je u Docker podršci i pridonio razvoju Runc, Go i BCC alata, kao i drugih open source projekata. Poznat po svom radu na Docker projektima i razvoju ekosustava Docker dodataka. David je vrlo strastven prema grafovima plamena i uvijek želi optimizirati performanse.

Lorenzo Fontana radi u timu otvorenog izvornog koda u Sysdigu, gdje je prvenstveno fokusiran na Falco, projekt Zaklade za izvorno računalstvo u oblaku koji pruža sigurnost izvođenja spremnika i otkrivanje anomalija putem modula kernela i eBPF-a. On je strastven prema distribuiranim sustavima, softverski definiranom umrežavanju, Linux kernelu i analizi performansi.

» Više detalja o knjizi možete pronaći na web stranica izdavača
» pregled sadržaja
» Izvod

Za Khabrozhiteley 25% popusta korištenjem kupona - Linux

Po uplati papirnate verzije knjige, elektronička knjiga bit će poslana e-mailom.

Izvor: www.habr.com

Dodajte komentar