Il Berkeley Packet Filter (BPF) o Berkeley Filter interessa tutti i sistemi operativi Unix, come Linux. Il compito prin­ci­pa­le della “macchina virtuale per compiti speciali” (in inglese "Special Purpose Virtual Machine"), svi­lup­pa­ta nel 1992, è quello di filtrare i pacchetti di dati dalle reti e di in­cor­po­rar­li nel kernel del sistema operativo. Il BPF rap­pre­sen­ta un’in­ter­fac­cia con i livelli di sicurezza di unità di dati o programmi. I livelli di sicurezza hanno il compito di garantire la tra­smis­sio­ne af­fi­da­bi­le dei pacchetti di dati e di re­go­la­men­tar­ne l’accesso.

Quando un tale pacchetto di dati raggiunge il de­sti­na­ta­rio, il BPF legge i dati dei livelli di sicurezza dal pacchetto e cerca, ad esempio, gli errori. In questo modo il de­sti­na­ta­rio può cor­reg­ge­re e con­fron­ta­re i dati con le de­fi­ni­zio­ni dei filtri e quindi accettare o rifiutare un pacchetto che non è con­si­de­ra­to per­ti­nen­te. In questo modo si può ri­spar­mia­re molta capacità di calcolo.

Come funziona il Berkeley Packet Filter?

Per svolgere le sue funzioni, il Berkeley Packet Filter è stato integrato come in­ter­pre­te in lin­guag­gio macchina all’interno di una macchina virtuale. Di con­se­guen­za, il BPF esegue un formato pre­de­fi­ni­to di istru­zio­ni. In qualità di in­ter­pre­te, il Berkeley Filter legge i file sorgente, li analizza ed esegue un’istru­zio­ne dopo l’altra. Poi traduce le istru­zio­ni in codice macchina per l’ese­cu­zio­ne diretta.

Grazie alle SysCalls, che sono chiamate di funzioni di sistema speciali e pronte all’uso, il Berkeley Filter invia richieste al centro del sistema operativo, chiamato anche kernel. Quest’ultimo controlla i permessi di accesso prima di accettare o rifiutare la richiesta. Tra le circa 330 SysCalls di Linux vi sono ad esempio:

  • read – permesso di lettura, con il quale si può leggere un file
  • write – permesso di scrittura, che consente la scrittura di un file
  • open – consente di aprire i file o i di­spo­si­ti­vi
  • close – consente di chiudere i file o i di­spo­si­ti­vi
  • stat – consente di re­cu­pe­ra­re lo stato di un file

Grazie a un continuo e costante sviluppo, oggi il BPF funziona come una macchina virtuale uni­ver­sa­le di­ret­ta­men­te nel kernel del sistema operativo, dove si svolge l’intero processo e l’or­ga­niz­za­zio­ne dei dati. Con l’aggiunta di nuove ca­rat­te­ri­sti­che, il filtro è noto come Extended BPF, ab­bre­via­to eBPF. Questo è in grado di eseguire qualsiasi codice in­ter­me­dio (byte code) uti­liz­za­to in modo sicuro e durante il runtime (com­pi­la­zio­ne just-in-time) di­ret­ta­men­te nel kernel operativo. L’Extended BPF funziona nel kernel operativo all’interno di un ambiente isolato ed è per tale motivo protetto. Il modello di ambiente noto come Sandbox minimizza il rischio che il sistema abbia un effetto negativo sulla logica del kernel operativo.

N.B.

Il Berkeley Filter può fun­zio­na­re sia in modalità kernel (massimo accesso alle risorse della macchina), sia in modalità utente (accesso limitato alle risorse di calcolo).

Vantaggi del Berkeley Filter

Con l’eBPF è possibile filtrare i pacchetti di dati e quindi evitare che dati ir­ri­le­van­ti ral­len­ti­no le pre­sta­zio­ni del PC. I record di dati inu­ti­liz­za­bi­li o non corretti possono quindi essere rifiutati o riparati fin dall’inizio. Inoltre, l’Extended BPF fornisce una maggiore sicurezza grazie alle SysCalls, chiamate di sistema che con­sen­to­no di misurare o tracciare fa­cil­men­te le pre­sta­zio­ni del vostro sistema operativo.

Già nel 2007 l’im­ple­men­ta­zio­ne del BPF è stata estesa con le “Zero copy buffer ex­ten­sions”. Grazie a queste esten­sio­ni, i driver dei di­spo­si­ti­vi possono salvare i pacchetti di dati catturati di­ret­ta­men­te nel programma, senza dover prima copiare i dati.

Pro­gram­ma­zio­ne dei filtri con BPF

In modalità utente, è possibile definire in qualsiasi momento i singoli filtri per l’in­ter­fac­cia del Berkeley Filter. In passato i codici cor­ri­spon­den­ti venivano scritti ma­nual­men­te e tradotti in un byte code BPF. Oggi, grazie al com­pi­la­to­re LLVM Clang Compiler, è possibile tradurre di­ret­ta­men­te i byte code.

Le librerie del kernel operativo con­ten­go­no anche programmi di esempio che sem­pli­fi­ca­no la de­fi­ni­zio­ne dei programmi eBPF. Diverse funzioni di guida sem­pli­fi­ca­no il vostro lavoro.

I ve­ri­fi­ca­to­ri eBPF per la sicurezza

L’ese­cu­zio­ne di chiamate di sistema nel kernel è sempre associata ad alcuni rischi per la sicurezza e la stabilità. Prima che una eBPF SysCall si carichi, deve superare una serie di controlli:

  1. In primo luogo viene ve­ri­fi­ca­to che la chiamata di sistema sia completa e non contenga loop, cosa che potrebbe portare a un crash del kernel. Il grafico del flusso di controllo del programma viene esaminato per rin­trac­cia­re le istru­zio­ni non rag­giun­gi­bi­li che non vengono caricate suc­ces­si­va­men­te.
  2. Prima e dopo l’ese­cu­zio­ne di un’istru­zio­ne viene con­trol­la­to lo stato della chiamata di sistema eBPF. Questo per garantire che l’Extended BPF operi solo negli ambiti con­sen­ti­ti e non acceda ai dati al di fuori della Sandbox. Non è ne­ces­sa­rio con­trol­la­re ogni percorso sin­go­lar­men­te, in quanto di solito è suf­fi­cien­te un sot­toin­sie­me.
  3. Infine, viene impostato anche il tipo di SysCall. Questo passaggio è im­por­tan­te per definire quali funzioni del kernel possono essere ri­chia­ma­te dalla SysCall e quali strutture dati possono essere ac­ces­si­bi­li. Ad esempio, è possibile uti­liz­za­re chiamate di sistema che accedono di­ret­ta­men­te ai pacchetti di dati della rete.

I tipi di SysCall esaminano ap­pros­si­ma­ti­va­men­te quattro funzioni: dove il programma può essere allegato, quali funzioni di guida del kernel possono essere ri­chia­ma­te, se i pacchetti di dati di rete sono ac­ces­si­bi­li di­ret­ta­men­te o meno, e quale tipo di oggetto viene trasmesso con priorità in una chiamata di sistema.

At­tual­men­te sono sup­por­ta­ti dal kernel i seguenti tipi di eBPF SysCall:

  • BPF_PROG_TYPE_SOCKET_FILTER
  • BPF_PROG_TYPE_KPROBE
  • BPF_PROG_TYPE_SCHED_CLS
  • BPF_PROG_TYPE_SCHED_ACT
  • BPF_PROG_TYPE_TRA­CE­POINT
  • BPF_PROG_TYPE_XDP
  • BPF_PROG_TYPE_PERF_EVENT
  • BPF_PROG_TYPE_CGROUP_SKB
  • BPF_PROG_TYPE_CGROUP_SOCK
  • BPF_PROG_TYPE_LWT_ *
  • BPF_PROG_TYPE_SOCK_OPS
  • BPF_PROG_TYPE_SK_SKB
  • BPF_PROG_CGROUP_DEVICE
Vai al menu prin­ci­pa­le