Kniha „BPF for Linux Monitoring“

Kniha „BPF for Linux Monitoring“Dobrý deň, obyvatelia Khabra! Virtuálny stroj BPF je jednou z najdôležitejších súčastí linuxového jadra. Jeho správne použitie umožní systémovým inžinierom nájsť chyby a vyriešiť aj tie najzložitejšie problémy. Dozviete sa, ako písať programy, ktoré monitorujú a upravujú správanie jadra, ako bezpečne implementovať kód na monitorovanie udalostí v jadre a oveľa viac. David Calavera a Lorenzo Fontana vám pomôžu odomknúť silu BPF. Rozšírte svoje znalosti v oblasti optimalizácie výkonu, sietí, bezpečnosti. - Použite BPF na monitorovanie a úpravu správania linuxového jadra. - Vložte kód na bezpečné monitorovanie udalostí jadra bez toho, aby ste museli znova kompilovať jadro alebo reštartovať systém. — Používajte praktické príklady kódu v jazykoch C, Go alebo Python. - Prevezmite kontrolu tým, že vlastníte životný cyklus programu BPF.

Linux Kernel Security, jeho funkcie a Seccomp

BPF poskytuje výkonný spôsob rozšírenia jadra bez obetovania stability, bezpečnosti alebo rýchlosti. Z tohto dôvodu si vývojári jadra mysleli, že by bolo dobré využiť jeho všestrannosť na zlepšenie izolácie procesov v Seccomp implementáciou filtrov Seccomp podporovaných programami BPF, tiež známymi ako Seccomp BPF. V tejto kapitole vysvetlíme, čo je Seccomp a ako sa používa. Potom sa naučíte písať filtre Seccomp pomocou programov BPF. Potom sa pozrieme na vstavané háčiky BPF, ktoré sú súčasťou jadra pre bezpečnostné moduly Linuxu.

Linux Security Modules (LSM) je rámec, ktorý poskytuje súbor funkcií, ktoré možno použiť na implementáciu rôznych bezpečnostných modelov štandardizovaným spôsobom. LSM je možné použiť priamo v zdrojovom strome jadra, ako je Apparmor, SELinux a Tomoyo.

Začnime diskusiou o možnostiach Linuxu.

Možnosti

Podstatou schopností Linuxu je, že musíte udeliť neprivilegovanému procesu povolenie na vykonanie určitej úlohy, ale bez použitia suid na tento účel, alebo inak urobiť proces privilegovaným, čím sa zníži možnosť útoku a umožní procesu vykonávať určité úlohy. Napríklad, ak vaša aplikácia potrebuje otvoriť privilegovaný port, povedzme 80, namiesto spustenia procesu ako root, môžete jej jednoducho poskytnúť schopnosť CAP_NET_BIND_SERVICE.

Zvážte program Go s názvom main.go:

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

Tento program obsluhuje HTTP server na porte 80 (toto je privilegovaný port). Zvyčajne ho spustíme ihneď po kompilácii:

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

Keďže však neudeľujeme oprávnenia root, tento kód vyvolá chybu pri viazaní portu:

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

capsh (shell manager) je nástroj, ktorý spúšťa shell so špecifickým súborom schopností.

V tomto prípade, ako už bolo spomenuté, namiesto udelenia úplných práv root môžete povoliť viazanie privilegovaného portu poskytnutím schopnosti cap_net_bind_service spolu so všetkým ostatným, čo už je v programe. Aby sme to dosiahli, môžeme náš program uzavrieť veľkými písmenami:

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

Poďme trochu pochopiť tento tím.

  • capsh - použite capsh ako škrupinu.
  • —caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' – keďže musíme zmeniť používateľa (nechceme bežať ako root), špecifikujeme cap_net_bind_service a možnosť skutočne zmeniť ID používateľa z root pre nikoho, menovite cap_setuid a cap_setgid.
  • —keep=1 — chceme zachovať nainštalované schopnosti pri prechode z účtu root.
  • —user=“nobody” — koncovým užívateľom spusteným programom nebude nikto.
  • —addamb=cap_net_bind_service — nastavte vymazanie súvisiacich schopností po prepnutí z režimu root.
  • - -c "./capabilities" - stačí spustiť program.

Prepojené schopnosti sú špeciálnym druhom schopností, ktoré dedia podriadené programy, keď ich aktuálny program vykonáva pomocou execve(). Zdediť možno iba schopnosti, ktoré je možné priradiť, alebo inými slovami ako schopnosti prostredia.

Pravdepodobne sa pýtate, čo znamená +eip po zadaní schopnosti vo voľbe --caps. Tieto príznaky sa používajú na určenie, že schopnosť:

-musí byť aktivovaný (p);

- k dispozícii na použitie (e);

-môžu byť zdedené podriadenými procesmi (i).

Keďže chceme použiť cap_net_bind_service, musíme to urobiť s príznakom e. Potom spustíme shell v príkaze. Tým sa spustí binárny súbor schopností a musíme ho označiť príznakom i. Nakoniec chceme, aby bola funkcia povolená (urobili sme to bez zmeny UID) pomocou p. Vyzerá to ako cap_net_bind_service+eip.

Výsledok môžete skontrolovať pomocou ss. Poďme trochu skrátiť výstup, aby sa zmestil na stránku, ale zobrazí príslušný port a ID používateľa iné ako 0, v tomto prípade 65:

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

V tomto príklade sme použili caph, ale shell môžete napísať pomocou libcap. Viac informácií nájdete v man 3 libcap.

Pri písaní programov často vývojár nepozná vopred všetky funkcie, ktoré program potrebuje v čase spustenia; Okrem toho sa tieto funkcie môžu v nových verziách zmeniť.

Aby sme lepšie pochopili možnosti nášho programu, môžeme použiť nástroj BCC, ktorý nastaví kprobe pre funkciu jadra 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

To isté môžeme dosiahnuť použitím bpftrace s jednoriadkovou kprobe vo funkcii jadra 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

Toto vypíše niečo ako nasledovné, ak sú možnosti nášho programu povolené po 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

V piatom stĺpci sú schopnosti, ktoré proces potrebuje, a keďže tento výstup zahŕňa neauditové udalosti, vidíme všetky neauditné kontroly a nakoniec požadovanú schopnosť s príznakom auditu (posledný vo výstupe) nastaveným na 1. Schopnosť. jeden, ktorý nás zaujíma, je CAP_NET_BIND_SERVICE, je definovaný ako konštanta v zdrojovom kóde jadra v súbore include/uapi/linux/ability.h s identifikátorom 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">

Schopnosti sú často povolené za behu pre kontajnery, ako je runC alebo Docker, aby im umožnili bežať v neprivilegovanom režime, ale majú povolené len schopnosti potrebné na spustenie väčšiny aplikácií. Ak aplikácia vyžaduje určité funkcie, Docker ich môže poskytnúť pomocou --cap-add:

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

Tento príkaz poskytne kontajneru schopnosť CAP_NET_ADMIN, čo mu umožní nakonfigurovať sieťové prepojenie na pridanie rozhrania dummy0.

Nasledujúca časť ukazuje, ako používať funkcie, ako je filtrovanie, ale pomocou inej techniky, ktorá nám umožňuje programovo implementovať naše vlastné filtre.

Seccomp

Seccomp je skratka pre Secure Computing a je to bezpečnostná vrstva implementovaná v jadre Linuxu, ktorá umožňuje vývojárom filtrovať určité systémové volania. Hoci je Seccomp svojimi schopnosťami porovnateľný s Linuxom, jeho schopnosť spravovať určité systémové volania ho robí v porovnaní s nimi oveľa flexibilnejším.

Funkcie Seccomp a Linuxu sa navzájom nevylučujú a často sa používajú spoločne, aby mali prospech z oboch prístupov. Môžete napríklad chcieť dať procesu schopnosť CAP_NET_ADMIN, ale nepovoliť mu prijímať soketové pripojenia, čím blokujete systémové volania accept a accept4.

Metóda filtrovania Seccomp je založená na BPF filtroch pracujúcich v režime SECCOMP_MODE_FILTER a filtrovanie systémových hovorov sa vykonáva rovnakým spôsobom ako pri paketoch.

Filtre Seccomp sa načítajú pomocou prctl cez operáciu PR_SET_SECCOMP. Tieto filtre majú formu programu BPF, ktorý sa vykonáva pre každý paket Seccomp reprezentovaný štruktúrou seccomp_data. Táto štruktúra obsahuje referenčnú architektúru, ukazovateľ na inštrukcie procesora v čase systémového volania a maximálne šesť argumentov systémového volania, vyjadrené ako uint64.

Takto vyzerá štruktúra seccomp_data zo zdrojového kódu jadra v súbore linux/seccomp.h:

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

Ako môžete vidieť z tejto štruktúry, môžeme filtrovať podľa systémového volania, jeho argumentov alebo kombinácie oboch.

Po prijatí každého paketu Seccomp musí filter vykonať spracovanie, aby urobil konečné rozhodnutie a povedal jadru, čo má robiť ďalej. Konečné rozhodnutie je vyjadrené jednou z návratových hodnôt (stavových kódov).

- SECCOMP_RET_KILL_PROCESS - ukončí celý proces ihneď po filtrovaní systémového volania, ktoré sa z tohto dôvodu nevykoná.

- SECCOMP_RET_KILL_THREAD - ukončí aktuálne vlákno ihneď po filtrovaní systémového volania, ktoré sa z tohto dôvodu nevykoná.

— SECCOMP_RET_KILL — alias pre SECCOMP_RET_KILL_THREAD, vľavo pre spätnú kompatibilitu.

- SECCOMP_RET_TRAP - systémové volanie je zakázané a signál SIGSYS (Bad System Call) je odoslaný úlohe, ktorá ho volá.

- SECCOMP_RET_ERRNO - Systémové volanie sa nevykoná a časť návratovej hodnoty filtra SECCOMP_RET_DATA sa odovzdá do užívateľského priestoru ako hodnota errno. V závislosti od príčiny chyby sa vrátia rôzne hodnoty errno. Zoznam čísiel chýb je uvedený v ďalšej časti.

- SECCOMP_RET_TRACE - Používa sa na upovedomenie sledovača ptrace pomocou - PTRACE_O_TRACESECCOMP na zachytenie, keď sa vykoná systémové volanie na zobrazenie a riadenie tohto procesu. Ak nie je pripojený sledovač, vráti sa chyba, errno sa nastaví na -ENOSYS a systémové volanie sa nevykoná.

- SECCOMP_RET_LOG - systémové volanie je vyriešené a zaprotokolované.

- SECCOMP_RET_ALLOW - systémové volanie je jednoducho povolené.

ptrace je systémové volanie na implementáciu sledovacích mechanizmov v procese nazývanom tracee, so schopnosťou monitorovať a kontrolovať vykonávanie procesu. Program sledovania môže efektívne ovplyvniť vykonávanie a modifikovať pamäťové registre sledovania. V kontexte Seccomp sa ptrace používa pri spustení stavovým kódom SECCOMP_RET_TRACE, takže sledovač môže zabrániť vykonaniu systémového volania a implementovať svoju vlastnú logiku.

Seccomp chyby

Z času na čas sa pri práci so Seccompom stretnete s rôznymi chybami, ktoré sú identifikované návratovou hodnotou typu SECCOMP_RET_ERRNO. Ak chcete nahlásiť chybu, systémové volanie seccomp vráti hodnotu -1 namiesto 0.

Možné sú nasledujúce chyby:

- EACCESS - Volajúcemu nie je dovolené uskutočniť systémové volanie. Zvyčajne sa to stane, pretože nemá privilégiá CAP_SYS_ADMIN alebo no_new_privs nie je nastavené pomocou prctl (o tom si povieme neskôr);

— EFAULT — odovzdané argumenty (argumenty v štruktúre seccomp_data) nemajú platnú adresu;

— EINVAL — tu môžu byť štyri dôvody:

-požadovaná operácia je neznáma alebo nie je podporovaná jadrom v aktuálnej konfigurácii;

-špecifikované príznaky nie sú platné pre požadovanú operáciu;

-operácia zahŕňa BPF_ABS, ale vyskytli sa problémy so zadaným posunom, ktorý môže presiahnuť veľkosť štruktúry seccomp_data;

-počet pokynov odovzdaných do filtra prekračuje maximum;

— ENOMEM — nedostatok pamäte na vykonanie programu;

- EOPNOTSUPP - operácia naznačila, že s SECCOMP_GET_ACTION_AVAIL bola akcia dostupná, ale jadro nepodporuje návraty v argumentoch;

— ESRCH — vyskytol sa problém pri synchronizácii iného prúdu;

- ENOSYS - K akcii SECCOMP_RET_TRACE nie je pripojený žiadny sledovač.

prctl je systémové volanie, ktoré umožňuje programu v užívateľskom priestore manipulovať (nastavovať a získavať) špecifické aspekty procesu, ako je bajtový koniec, názvy vlákien, režim bezpečného výpočtu (Seccomp), privilégiá, udalosti Perf atď.

Seccomp sa vám môže zdať ako sandboxová technológia, ale nie je to tak. Seccomp je nástroj, ktorý používateľom umožňuje vyvinúť mechanizmus sandboxu. Teraz sa pozrime na to, ako sa vytvárajú programy na interakciu s používateľmi pomocou filtra volaného priamo systémovým volaním Seccomp.

Príklad filtra BPF Seccomp

Tu ukážeme, ako skombinovať dve akcie, o ktorých sme hovorili vyššie, a to:

— napíšeme program Seccomp BPF, ktorý bude použitý ako filter s rôznymi návratovými kódmi v závislosti od prijatých rozhodnutí;

— naplňte filter pomocou prctl.

Najprv potrebujete hlavičky zo štandardnej knižnice a linuxového jadra:

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

Pred pokusom o tento príklad sa musíme uistiť, že jadro je kompilované s parametrami CONFIG_SECCOMP a CONFIG_SECCOMP_FILTER nastavenými na y. Na pracovnom stroji to môžete skontrolovať takto:

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

Zvyšok kódu je dvojdielna funkcia install_filter. Prvá časť obsahuje náš zoznam pokynov na filtrovanie BPF:

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

Inštrukcie sú nastavené pomocou makier BPF_STMT a BPF_JUMP definovaných v súbore linux/filter.h.
Poďme si prejsť pokyny.

- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, arch))) - systém sa načíta a akumuluje z BPF_LD vo forme slova BPF_W, paketové dáta sú umiestnené s pevným posunom BPF_ABS.

- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arch, 0, 3) - pomocou BPF_JEQ kontroluje, či sa hodnota architektúry v akumulátorovej konštante BPF_K rovná arch. Ak áno, preskočí na offset 0 na ďalšiu inštrukciu, v opačnom prípade skočí na offset 3 (v tomto prípade) a vyvolá chybu, pretože oblúk sa nezhoduje.

- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, nr))) - Načítava a akumuluje sa z BPF_LD vo forme slova BPF_W, čo je číslo systémového volania obsiahnuté v pevnom posune BPF_ABS.

— BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, číslo, 0, 1) — porovná telefónne číslo systému s hodnotou premennej nr. Ak sú rovnaké, prejde na ďalšiu inštrukciu a zakáže systémové volanie, inak povolí systémové volanie pomocou SECCOMP_RET_ALLOW.

- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (chyba & SECCOMP_RET_DATA)) - ukončí program s BPF_RET a výsledkom je chyba SECCOMP_RET_ERRNO s číslom z premennej err.

- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW) - ukončí program pomocou BPF_RET a umožní vykonať systémové volanie pomocou SECCOMP_RET_ALLOW.

SECCOMP JE CBPF
Možno sa čudujete, prečo sa namiesto kompilovaného objektu ELF alebo JIT kompilovaného C programu používa zoznam inštrukcií.

Má to dva dôvody.

• Po prvé, Seccomp používa cBPF (klasický BPF) a nie eBPF, čo znamená: nemá žiadne registre, ale iba akumulátor na uloženie posledného výsledku výpočtu, ako je možné vidieť na príklade.

• Po druhé, Seccomp akceptuje smerník na pole inštrukcií BPF priamo a nič iné. Makrá, ktoré sme použili, jednoducho pomáhajú špecifikovať tieto inštrukcie spôsobom, ktorý je pre programátora vhodný.

Ak potrebujete ďalšiu pomoc s pochopením tohto zhromaždenia, zvážte pseudokód, ktorý robí to isté:

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

Po definovaní kódu filtra v štruktúre socket_filter musíte definovať sock_fprog obsahujúci kód a vypočítanú dĺžku filtra. Táto dátová štruktúra je potrebná ako argument na deklarovanie neskoršieho spustenia procesu:

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

Vo funkcii install_filter zostáva urobiť len jedna vec – načítať samotný program! Aby sme to dosiahli, používame prctl, pričom PR_SET_SECCOMP berieme ako možnosť pre vstup do zabezpečeného výpočtového režimu. Potom povieme režimu, aby načítal filter pomocou SECCOMP_MODE_FILTER, ktorý je obsiahnutý v premennej prog typu sock_fprog:

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

Nakoniec môžeme použiť našu funkciu install_filter, ale predtým musíme pomocou prctl nastaviť PR_SET_NO_NEW_PRIVS pre aktuálne spustenie a vyhnúť sa tak situácii, keď podriadené procesy získajú viac privilégií ako ich rodičia. Pomocou toho môžeme vykonať nasledujúce volania prctl vo funkcii install_filter bez toho, aby sme mali práva root.

Teraz môžeme zavolať funkciu install_filter. Zablokujme všetky systémové volania týkajúce sa zápisu súvisiace s architektúrou X86-64 a jednoducho dáme povolenie, ktoré blokuje všetky pokusy. Po nainštalovaní filtra pokračujeme vo vykonávaní pomocou prvého argumentu:

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

Začnime. Na kompiláciu nášho programu môžeme použiť buď clang alebo gcc, v každom prípade je to len kompilácia súboru main.c bez špeciálnych možností:

clang main.c -o filter-write

Ako bolo uvedené, zablokovali sme všetky položky v programe. Aby ste to otestovali, potrebujete program, ktorý niečo vypíše - ls sa javí ako dobrý kandidát. Takto sa zvyčajne správa:

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

úžasné! Takto vyzerá používanie nášho wrapper programu: Ako prvý argument jednoducho odovzdáme program, ktorý chceme testovať:

./filter-write "ls -la"

Po spustení tento program vytvorí úplne prázdny výstup. Môžeme však použiť strace, aby sme videli, čo sa deje:

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

Výsledok práce je značne skrátený, ale zodpovedajúca časť ukazuje, že záznamy sú zablokované s chybou EPERM - rovnakou, akú sme nakonfigurovali. To znamená, že program nevypíše nič, pretože nemôže získať prístup k systémovému volaniu zápisu:

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

Teraz chápete, ako Seccomp BPF funguje, a máte dobrú predstavu o tom, čo s ním môžete robiť. Ale nechceli by ste dosiahnuť to isté s eBPF namiesto cBPF, aby ste využili jeho plnú silu?

Keď premýšľate o programoch eBPF, väčšina ľudí si myslí, že ich jednoducho napíšu a načítajú s oprávneniami správcu. Aj keď je toto tvrdenie vo všeobecnosti pravdivé, jadro implementuje súbor mechanizmov na ochranu objektov eBPF na rôznych úrovniach. Tieto mechanizmy sa nazývajú pasce BPF LSM.

BPF LSM pasce

Na zabezpečenie monitorovania systémových udalostí nezávislé od architektúry LSM implementuje koncept pascí. Hákové volanie je technicky podobné systémovému volaniu, ale je nezávislé od systému a je integrované s infraštruktúrou. LSM poskytuje nový koncept, v ktorom môže vrstva abstrakcie pomôcť vyhnúť sa problémom, ktoré sa vyskytujú pri riešení systémových volaní na rôznych architektúrach.

V čase písania tohto článku má jadro sedem hákov spojených s programami BPF a SELinux je jediný vstavaný LSM, ktorý ich implementuje.

Zdrojový kód pre pasce sa nachádza v strome jadra v súbore 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);

Každý z nich bude povolaný v rôznych fázach vykonávania:

— security_bpf — vykoná počiatočnú kontrolu vykonaných systémových volaní BPF;

- security_bpf_map - skontroluje, kedy jadro vráti deskriptor súboru pre mapu;

- security_bpf_prog - skontroluje, kedy jadro vráti deskriptor súboru pre program eBPF;

— security_bpf_map_alloc — skontroluje, či je inicializované pole zabezpečenia vo vnútri máp BPF;

- security_bpf_map_free - skontroluje, či je bezpečnostné pole vymazané vo vnútri máp BPF;

— security_bpf_prog_alloc — kontroluje, či je bezpečnostné pole inicializované v programoch BPF;

- security_bpf_prog_free - skontroluje, či je bezpečnostné pole v programoch BPF vymazané.

Teraz, keď to všetko vidíme, rozumieme: myšlienkou zachytávačov LSM BPF je, že môžu poskytnúť ochranu každému objektu eBPF, čím sa zabezpečí, že operácie s kartami a programami môžu vykonávať iba tí, ktorí majú príslušné privilégiá.

Zhrnutie

Bezpečnosť nie je niečo, čo môžete implementovať univerzálnym spôsobom pre všetko, čo chcete chrániť. Je dôležité vedieť chrániť systémy na rôznych úrovniach a rôznymi spôsobmi. Verte či nie, najlepší spôsob, ako zabezpečiť systém, je zorganizovať rôzne úrovne ochrany z rôznych pozícií tak, aby zníženie bezpečnosti jednej úrovne neumožnilo prístup do celého systému. Vývojári odviedli skvelú prácu, keď nám poskytli súbor rôznych vrstiev a dotykových bodov. Dúfame, že sme vám dobre porozumeli tomu, čo sú vrstvy a ako používať programy BPF na prácu s nimi.

O autoroch

Dávid Calavera je CTO v Netlify. Pracoval v podpore Docker a podieľal sa na vývoji nástrojov Runc, Go a BCC, ako aj ďalších open source projektov. Známy svojou prácou na projektoch Docker a vývojom ekosystému doplnkov Docker. David je veľmi zanietený pre grafy plameňov a vždy sa snaží optimalizovať výkon.

Lorenzo Fontana pracuje v tíme open source v spoločnosti Sysdig, kde sa primárne zameriava na Falco, projekt Cloud Native Computing Foundation, ktorý poskytuje bezpečnosť pri behu kontajnerov a detekciu anomálií prostredníctvom modulu jadra a eBPF. Je nadšený pre distribuované systémy, softvérovo definované siete, linuxové jadro a analýzu výkonu.

» Viac podrobností o knihe nájdete na webová stránka vydavateľa
» obsah
» Úryvok

Pre Khabrozhitely zľavu 25 % pomocou kupónu - Linux

Po zaplatení papierovej verzie knihy bude elektronická kniha zaslaná e-mailom.

Zdroj: hab.com

Pridať komentár