Kniha "BPF pro monitorování Linuxu"

Kniha "BPF pro monitorování Linuxu"Ahoj, komunitě Habr! Virtuální stroj BPF je jednou z nejdůležitějších součástí jádra Linuxu. Jeho správné využití umožní systémovým inženýrům detekovat chyby a řešit i ty nejnáročnější problémy. Naučíte se vytvářet programy, které sledují a modifikují chování jádra, bezpečně implementovat kód pro sledování událostí v jádře a mnohem více. David Calavera a Lorenzo Fontana vám pomohou odhalit potenciál BPF. Rozšiřte své znalosti o optimalizaci výkonu, sítích a bezpečnosti. — Používejte BPF k sledování a modifikaci chování jádra Linuxu. — Implementujte kód pro bezpečné sledování událostí v jádře — bez nutnosti překompilace jádra nebo restartu systému. — Využívejte pohodlné ukázky kódu v C, Go nebo Pythonu. — Řiďte situaci ovládáním životního cyklu programu BPF.

Bezpečnost jádra Linuxu, jeho možnosti a Seccomp

BPF poskytuje mocný způsob, jak rozšířit jádro bez zkreslení stability, bezpečnosti a rychlosti. Z tohoto důvodu vývojáři jádra považovali za rozumné využít jeho univerzálnost k zlepšení izolace procesů v Seccomp implementací filtrů Seccomp, které podporují programy BPF, známé také jako Seccomp BPF. V této kapitole si povíme, co je Seccomp a jak funguje. Poté se naučíte, jak psát filtry Seccomp pomocí programů BPF. Následně prozkoumáme integrované háčky BPF, které existují v jádře pro bezpečnostní moduly Linuxu.

Bezpečnostní moduly Linuxu (LSM) jsou platforma, která poskytuje sadu funkcí použitelných pro standardizovanou implementaci různých modelů bezpečnosti. LSM může být přímo použito v stromě zdrojového kódu jádra, například Apparmor, SELinux a Tomoyo.

Začněme diskusí o možnostech Linuxu.

Funkce

Podstatu možnosti Linux představuje, že potřebujete poskytnout neprivilegovanému procesu oprávnění k vykonání určité úlohy, ale bez využití suid k tomuto účelu, nebo jinak učinit proces privilegovaným, čímž se snižuje možnost útoků a umožňuje procesu vykonávat určité úkoly. Například, pokud vaše aplikace potřebuje otevřít privilegovaný port, dejme tomu 80, místo spuštění procesu pod uživatelským účtem root, můžete jí jednoduše poskytnout oprávnění CAP_NET_BIND_SERVICE.

Zvažme program Go s názvem main.go:

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

Tento program obsluhuje HTTP server na portu 80 (to je privilegovaný port). Obvykle ho spouštíme hned po kompilaci:

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

Nicméně, protože neposkytujeme privilegium root, tento kód vyvolá chybu při pokusu o připojení portu:

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

capsh (nástroj pro správu shellu) je nástroj, který spouští shell s určitým nastavením možností.

V tomto případě, jak již bylo řečeno, místo poskytování plných práv root můžeme povolit vazbu privilegovaných portů tím, že poskytneme možnost cap_net_bind_service spolu se všemi ostatními, které má program již. K tomu můžeme náš program obalit do 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"

Pojďme se podívat blíže na tento příkaz.

  • capsh — používáme capsh jako shell.
  • —caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' — protože potřebujeme změnit uživatele (nechceme běžet s právy root), specifikujme cap_net_bind_service a možnost skutečně změnit identifikátor uživatele z root na nobody, konkrétně cap_setuid a cap_setgid.
  • —keep=1 — chceme zachovat nastavené možnosti, když dojde ke přepnutí z účtu root.
  • —user="nobody" — konečným uživatelem, který spouští program, bude nobody.
  • —addamb=cap_net_bind_service — určíme vyčištění souvisejících možností po přepnutí z režimu root.
  • — -c "./capabilities" — prostě spouštíme program.

Související možnosti jsou zvláštním typem možností, které dědí podprogramy, když aktuální program je vykonává pomocí execve(). Dědit mohou pouze možnosti, které jsou definovány jako související, nebo jinými slovy, jako možnosti prostředí.

Pravděpodobně vás zajímá, co znamená +eip po určení možnosti v parametru —caps. Tyto příznaky se používají k určení, že možnost:

-musí být aktivována (p);

-je k dispozici pro aplikaci (e);

-může být zděděna podřízenými procesy (i).

Protože chceme použít cap_net_bind_service, musíme to provést s příznakem e. Poté spustíme shell v příkazu. Jako výsledek se spustí binární soubor capabilities a musíme ho označit příznakem i. Nakonec chceme, aby byla možnost aktivována (to jsme udělali, aniž bychom měnili UID) pomocí p. Vypadá to jako cap_net_bind_service+eip.

Výsledek můžete zkontrolovat pomocí ss. Trochu zkrátíme výstup, aby se vešel na stránku, ale zobrazí přidružený port a identifikátor uživatele, který se liší od 0, v tomto případě 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

V tomto příkladu jsme použili capsh, ale můžete napsat shell pomocí libcap. Pro další informace se podívejte na man 3 libcap.

Při psaní programů toho vývojář často předem nezná všechny schopnosti, které program potřebuje během běhu; navíc v nových verzích se tyto schopnosti mohou měnit.

Abychom lépe porozuměli schopnostem našeho programu, můžeme použít nástroj BCC capable, který nastavuje kprobe pro funkci jádra 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

Téhož můžeme dosáhnout pomocí bpftrace s jednorázovým kprobe v funkci jádra cap_capable:

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

To vyústí v něco jako následující, pokud budou schopnosti našeho programu aktivovány 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

Pátý sloupec obsahuje schopnosti, které proces potřebuje, a protože tyto výstupy zahrnují také neauditní události, vidíme všechny neauditní kontroly a nakonec požadovanou schopnost s příznakem auditu (poslední ve výstupu), nastaveným na 1. Schopnost, která nás zajímá, je CAP_NET_BIND_SERVICE, je definována jako konstanta ve zdrojovém kódu jádra v souboru include/uapi/linux/ability.h s identifikátorem 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">

Možnosti se často využívají během běhu kontejnerů, jako jsou runC nebo Docker, aby fungovaly v neprivilegovaném režimu, ale byly jim povoleny pouze ty možnosti, které jsou nezbytné pro spuštění většiny aplikací. Když aplikace vyžaduje určité možnosti, lze je v Dockeru zajistit pomocí —cap-add:

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

Tento příkaz udělí kontejneru možnost CAP_NET_ADMIN, což mu umožní nastavit síťový odkaz pro přidání rozhraní dummy0.

V následující části je ukázáno používání takových možností, jako je filtrování, ale pomocí jiné metody, která nám umožní programově implementovat vlastní filtry.

Seccomp

Seccomp znamená Secure Computing, což je úroveň bezpečnosti implementovaná v jádře Linuxu, která umožňuje vývojářům filtrovat určité systémové volání. Ačkoliv je Seccomp srovnatelný s možnostmi Linuxu, jeho schopnost řídit určitá systémová volání jej dělá výrazně flexibilnějším než ony.

Seccomp a možnosti Linuxu se navzájem nevylučují, často se používají společně, aby využily výhody obou přístupů. Například můžete chtít udělit procesu možnost CAP_NET_ADMIN, ale neumožnit mu přijímat spojení přes sockety, blokováním systémových volání accept a accept4.

Způsob filtrování Seccomp je založen na filtrech BPF, které fungují v režimu SECCOMP_MODE_FILTER, a filtrování systémových volání probíhá stejně jako u paketů.

Filtry Seccomp se načítají pomocí prctl prostřednictvím operace PR_SET_SECCOMP. Tyto filtry mají formu programu BPF, který se provádí pro každý paket Seccomp předložený pomocí struktury seccomp_data. Tato struktura obsahuje architekturu, ukazatel na instrukce procesoru během systémového volání a maximálně šest argumentů systémového volání vyjádřených jako uint64.

Takto vypadá struktura seccomp_data z původního kódu jádra v souboru linux/seccomp.h:

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

Jak je patrné z této struktury, můžeme filtrovat na základě systémového volání, jeho argumentů nebo jejich kombinace.

Po obdržení každého balíčku musí filtr Seccomp provést zpracování, aby přijal konečné rozhodnutí a informoval jádro, co má dělat dál. Konečné rozhodnutí je vyjádřeno jednou z vracených hodnot (stavových kódů).

— SECCOMP_RET_KILL_PROCESS — okamžité ukončení celého procesu po filtrování systémového volání, které se tak neprovádí.

— SECCOMP_RET_KILL_THREAD — okamžité ukončení aktuálního vlákna po filtrování systémového volání, které se tak neprovádí.

— SECCOMP_RET_KILL — alias pro SECCOMP_RET_KILL_THREAD, ponecháno pro zpětnou kompatibilitu.

— SECCOMP_RET_TRAP — systémové volání je zakázáno a signál SIGSYS (Bad System Call) je odeslán úkole, který ho zavolal.

— SECCOMP_RET_ERRNO — systémové volání se neprovádí a část vracené hodnoty filtru SECCOMP_RET_DATA je předána do uživatelského prostoru jako hodnota errno. Různé hodnoty errno jsou vraceny v závislosti na důvodu chyby. Seznam chybových čísel je uveden v následující části.

— SECCOMP_RET_TRACE — používá se k upozornění debugggera ptrace pomocí — PTRACE_O_TRACESECCOMP pro zachycení, když se vykonává systémové volání, aby bylo možné vidět a kontrolovat tento proces. Pokud není debugger připojen, vrací se chyba, errno se nastaví na -ENOSYS a systémové volání se neprovádí.

— SECCOMP_RET_LOG — systémové volání je povoleno a zaregistrováno v protokolu.

— SECCOMP_RET_ALLOW — systémové volání je jednoduše povoleno.

ptrace je systémové volání pro implementaci mechanismů sledování v procesu nazývaném tracee, s možností sledovat a kontrolovat vykonávání procesu. Program sledování může efektivně ovlivnit vykonávání a měnit registry paměti tracee. V kontextu Seccomp se ptrace používá, když je spuštěn kódem stavu SECCOMP_RET_TRACE, a tudíž může debugger zabránit provádění systémového volání a realizovat vlastní logiku.

Chyby Seccomp

Při práci se Seccomp se občas setkáte s různými chybami, které jsou identifikovány vracenou hodnotou typu SECCOMP_RET_ERRNO. Aby bylo chybě hlášeno, systémové volání seccomp vrátí -1 místo 0.

Možné chyby jsou následující:

— EACCESS — volající straně není povoleno provádět systémový hovor. Obvykle se to stane, protože nemá oprávnění CAP_SYS_ADMIN nebo nebyl nastaven no_new_privs pomocí prctl (o tom si povíme později);

— EFAULT — předané argumenty (args ve struktuře seccomp_data) nemají platnou adresu;

— EINVAL — zde může být čtyři důvody:

- požadovaná operace je neznámá nebo není jádrem podporována v současné konfiguraci;

- uvedené příznaky jsou neplatné pro požadovanou operaci;

- operace zahrnuje BPF_ABS, ale jsou problémy s uvedeným posunem, který může přesahovat velikost struktury seccomp_data;

- počet instrukcí předaných do filtru přesahuje maximální;

— ENOMEM — nedostatek paměti pro provedení programu;

— EOPNOTSUPP — operace uvedla, že s SECCOMP_GET_ACTION_AVAIL byl akční kód dostupný, avšak jádro nepodporuje návratové hodnoty v argumentech;

— ESRCH — nastal problém při synchronizaci jiného vlákna;

— ENOSYS — není připojen sledovač k akci SECCOMP_RET_TRACE.

prctl — to je systémový hovor, který umožňuje programu uživatelského prostoru řídit (nastavovat a získávat) konkrétní aspekty procesu, jako jsou pořadová čísla bajtů, názvy vláken, režim chráněného výpočtu (Seccomp), privilegium, události Perf apod.

Seccomp se může zdát jako technologie písku, ale není tomu tak. Seccomp je nástroj, který uživatelům umožňuje vyvíjet mechanismus pískoviště. Nyní se podívejme, jak se vytvářejí programy pro interakci uživatelů pomocí filtru vyvolaného přímo systémovým voláním Seccomp.

Příklad filtru BPF Seccomp

Zde ukážeme, jak spojit dvě dříve probírané akce, a to:

— napíšeme program Seccomp BPF, který bude použit jako filtr s různými návratovými kódy v závislosti na přijímaných rozhodnutích;

— načteme filtr pomocí prctl.

Nejdříve potřebujeme hlavičky ze standardní knihovny a jádra Linuxu:

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

Než se pokusíme provést tento příklad, musíme se ujistit, že je jádro zkompilováno s CONFIG_SECCOMP a CONFIG_SECCOMP_FILTER nastavenými na y. Na pracovní stanici to můžeme zkontrolovat takto:

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

Zbytek kódu představuje funkci install_filter, která se skládá ze dvou částí. První část obsahuje náš seznam pokynů pro filtrování 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),
  };

Pokyny jsou nastaveny pomocí makra BPF_STMT a BPF_JUMP, definovaných v souboru linux/filter.h.
Podívejme se na pokyny.

— BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, arch))) — systém načítá a ukládá s BPF_LD ve formě slova BPF_W, paketová data se nacházejí na pevném offsetu BPF_ABS.

— BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arch, 0, 3) — kontroluje pomocí BPF_JEQ, zda je hodnota architektury v akumulátoru BPF_K rovna arch. Pokud ano, přejde s offsetem 0 k dalšímu pokynu, jinak přeskočí s offsetem 3 (v tomto případě), protože arch se neshoduje.

— BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, nr))) — načítá a ukládá s BPF_LD ve formě slova BPF_W, které je číslem systémového volání obsaženým na pevném offsetu BPF_ABS.

— BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1) — porovnává číslo systémového volání s hodnotou proměnné nr. Pokud jsou rovny, přechází k dalšímu pokynu a zakazuje systémové volání, jinak povolí systémové volání s SECCOMP_RET_ALLOW.

— BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (error & SECCOMP_RET_DATA)) — ukončuje program s BPF_RET a vydává chybu SECCOMP_RET_ERRNO s číslem z proměnné err.

— BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW) — ukončuje program s BPF_RET a povoluje provádění systémového volání pomocí SECCOMP_RET_ALLOW.

SECCOMP — JE TO CBPF
Možná vás zajímá, proč se místo zkompilovaného objektu ELF nebo programu v C, zkompilovaného s JIT, používá seznam pokynů.

Na to jsou dva důvody.

• Za prvé, Seccomp aplikuje cBPF (klasický BPF), nikoli eBPF, což znamená: nemá registry, je tu pouze akumulátor pro uložení posledního výsledku výpočtu, jak lze vidět v příkladu.

• Za prvé, Seccomp přímo přijímá ukazatel na pole instrukcí BPF a nic jiného. Makra, která jsme použili, pouze pomáhají vyjádřit tyto instrukce v programátorsky přívětivé formě.

Pokud potřebujete další pomoc při pochopení této sestavy, zvažte pseudo-kód, který dělá to samé:

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

Po definici kódu filtru v rámci socket_filter je třeba definovat sock_fprog, která obsahuje kód a vypočítanou délku filtru. Tato datová struktura je nezbytná jako argument pro prohlášení o práci procesu v dalším kroku:

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

Zbývá pouze jedno, co je třeba udělat ve funkci install_filter, — načíst samotný program! K tomu použijeme prctl, vezmeme PR_SET_SECCOMP jako volbu, abychom přešli do režimu chráněných výpočtů. Poté nastavíme režim tak, aby načítal filtr pomocí SECCOMP_MODE_FILTER, který je obsažen v proměnné prog typu sock_fprog:

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

Nakonec můžeme využít naši funkci install_filter, ale předtím je třeba použít prctl k nastavení PR_SET_NO_NEW_PRIVS pro aktuální provádění, a tím se vyhnout situaci, kdy potomci získávají širší oprávnění než jejich rodiče. Při tom můžeme provádět následující volání prctl ve funkci install_filter, aniž bychom měli práva root.

Nyní můžeme volat funkci install_filter. Zablokujeme všechny systémové volání write vztahující se k architektuře X86-64 a jednoduše povolíme blokující všechny pokusy. Po nastavení filtru pokračujeme v provádění pomocí první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]);
 }

Pojďme na to. Pro kompilaci našeho programu můžeme použít buď clang, nebo gcc, v každém případě to bude jen kompilace souboru main.c bez speciálních voleb:

clang main.c -o filter-write

Jak bylo zmíněno, zablokovali jsme všechny zápisy v programu. Abychom to zkontrolovali, potřebujeme program, který něco vypisuje, — ls se zdá být dobrým kandidátem. Takto se obvykle chová:

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

Skvěle! Takto vypadá používání našeho shell programu: jednoduše předáme program, který chceme otestovat, jako první argument:

./filter-write "ls -la"

Po provedení tento program vydává zcela prázdný výstup. Nicméně můžeme použít strace, abychom viděli, co se děje:

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

Výsledek je značně zkrácen, ale jeho odpovídající část ukazuje, že zápisy jsou blokovány s chybou EPERM — tou, kterou jsme nastavili. To znamená, že program nic nevydává, protože nemůže přistupovat k systémovému volání write:

[pid 25099] write(2, "ls: ", 4) = -1 EPERM (Operace nebyla povolena)
[pid 25099] write(2, "write error", 11) = -1 EPERM (Operace nebyla povolena)
[pid 25099] write(2, "n", 1) = -1 EPERM (Operace nebyla povolena)

Nyní rozumíte, jak funguje Seccomp BPF, a dobře si představujete, co s ním lze udělat. Ale nebylo by skvělé dosáhnout téhož pomocí eBPF místo cBPF, abychom využili jeho plnou moc?

Když se mluví o programech eBPF, většina lidí si myslí, že je prostě napíší a načtou s administrátorskými právy. Ačkoli je toto tvrzení v zásadě pravdivé, jádro realizuje sadu mechanismů pro ochranu objektů eBPF na různých úrovních. Tyto mechanismy se nazývají BPF LSM háčky.

BPF LSM háčky

Aby bylo zajištěno architektuře nezávislé sledování systémových událostí, LSM realizuje koncept háčků. Technicky vzato je volání háčku podobné systémovému volání, nicméně je nezávislé na systému a integrované s infrastrukturou. LSM poskytuje novou koncepci, kde je úroveň abstrakce schopna vyhnout se problémům, které vznikají při práci se systémovými voláními na různých architekturách.

V době psaní této knihy mělo jádro sedm háčků souvisejících s BPF programy a SELinux — jediný vestavěný LSM, který je realizuje.

Zdrojový kód háčků je umístěn ve stromu jádra v souboru 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 volán v různých fázích provádění:

— security_bpf — provádí počáteční kontrolu provedených systémových volání BPF;

— security_bpf_map — kontroluje, kdy jádro vrací souborový deskriptor pro mapu;

— security_bpf_prog — kontroluje, kdy jádro vrací deskriptor souboru pro eBPF program;

— security_bpf_map_alloc — kontroluje, zda je pole zabezpečení uvnitř BPF mapy inicializováno;

— security_bpf_map_free — kontroluje, zda probíhá uvolnění pole zabezpečení uvnitř BPF mapy;

— security_bpf_prog_alloc — kontroluje, zda je pole zabezpečení uvnitř BPF programů inicializováno;

— security_bpf_prog_free — kontroluje, zda je pole zabezpečení uvnitř BPF programů uvolněno.

Nyní, když vidíme to vše, rozumíme: myšlenka LSM BPF zachytávačů spočívá v tom, že mohou zajistit ochranu každého objektu eBPF, a zaručit, že pouze ti, kteří mají odpovídající oprávnění, mohou provádět operace nad mapami a programy.

Shrnutí

Bezpečnost není něco, co můžete implementovat univerzálním způsobem pro vše, co chcete chránit. Je důležité mít možnost chránit systémy na různých úrovních a různými způsoby. Chcete-li věřit nebo ne, nejlepší způsob, jak zabezpečit systém, je organizovat různé úrovně ochrany z různých pozic, abychom zajistili, že oslabení bezpečnosti jedné úrovně neumožní přístup k celému systému. Vývojáři jádra udělali velkou práci, aby nám poskytli sadu různých vrstev a interakčních bodů. Doufáme, že jsme vám poskytli dobrý přehled o tom, co jsou vrstvy a jak používat programy BPF k práci s nimi.

O autorech

David Calavera je technický ředitel ve společnosti Netlify. Pracoval v podpoře Dockeru a podílel se na vývoji nástrojů Runc, Go a BCC, jakož i dalších projektů s otevřeným zdrojovým kódem. Je znám svou prací na projektech Docker a rozvojem ekosystému pluginů Docker. David velmi rád sleduje plamenové grafy a vždy usiluje o optimalizaci výkonu.

Lorenzo Fontana Pracuje v týmu vývojářů softwaru s otevřeným zdrojovým kódem ve společnosti Sysdig, kde se převážně věnuje projektu Falco – projektu Cloud Native Computing Foundation, který zajišťuje bezpečnost prostředí kontejnerů a detekci anomálií prostřednictvím jádrového modulu a eBPF. Je fascinován distribuovanými systémy, softwarově definovanými sítěmi, jádrem Linuxu a analýzou výkonnosti.

» Podrobnosti o knize naleznete na webových stránkách vydavatelství
» Obsah
» Úryvek

Pro uživatele Habr sleva 25 % s kupónem — Linux

Po uhrazení tištěné verze knihy bude elektronická kniha zaslána na e-mail.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster