Buch "BPF fir Linux Iwwerwaachung"

Buch "BPF fir Linux Iwwerwaachung"Moien, Khabro Awunner! D'BPF virtuell Maschinn ass ee vun de wichtegste Komponente vum Linux Kernel. Seng korrekt Notzung erlaabt Systemingenieuren Feeler ze fannen an och déi komplexst Problemer ze léisen. Dir léiert wéi Dir Programmer schreift déi d'Behuele vum Kernel iwwerwaachen an änneren, wéi Dir Code sécher implementéiert fir Eventer am Kernel ze iwwerwaachen, a vill méi. Den David Calavera an de Lorenzo Fontana hëllefen Iech d'Kraaft vu BPF opzemaachen. Erweidert Äert Wëssen iwwer Leeschtungsoptimiséierung, Netzwierker, Sécherheet. - Benotzt BPF fir d'Behuele vum Linux Kernel ze iwwerwaachen an z'änneren. - Injizéieren Code fir sécher Kernelevenementer ze iwwerwaachen ouni de Kernel nei ze kompiléieren oder de System nei ze starten. - Benotzt praktesch Code Beispiller am C, Go oder Python. - Huelt d'Kontroll andeems Dir de BPF Programm Liewenszyklus besëtzt.

Linux Kernel Sécherheet, seng Features a Secomp

BPF bitt e mächtege Wee fir de Kernel ze verlängeren ouni Stabilitéit, Sécherheet oder Geschwindegkeet ofzeschafen. Aus dësem Grond hunn d'Kernel Entwéckler geduecht datt et eng gutt Iddi wier seng Villsäitegkeet ze benotzen fir d'Prozessisolatioun am Seccomp ze verbesseren andeems se Seccomp Filteren implementéiert, ënnerstëtzt vu BPF Programmer, och bekannt als Seccomp BPF. An dësem Kapitel wäerte mir erkläre wat Secomp ass a wéi et benotzt gëtt. Da léiert Dir wéi Dir Secomp Filtere schreift mat BPF Programmer. Duerno wäerte mir déi agebaute BPF Haken kucken, déi am Kernel fir Linux Sécherheetsmoduler abegraff sinn.

Linux Sécherheetsmoduler (LSM) sinn e Kader deen eng Rei vu Funktiounen ubitt déi benotzt kënne fir verschidde Sécherheetsmodeller op standardiséierter Manéier ëmzesetzen. LSM kann direkt am Kernel Quellbaum benotzt ginn, wéi Apparmor, SELinux an Tomoyo.

Loosst eis ufänken mat der Diskussioun iwwer d'Fäegkeete vu Linux.

Features

D'Essenz vun de Fäegkeeten vu Linux ass datt Dir en onprivilegéierte Prozesserlaabnis muss ginn fir eng bestëmmten Aufgab auszeféieren, awer ouni suid fir dësen Zweck ze benotzen, oder soss de Prozess privilegiéiert maachen, d'Méiglechkeet vum Attack ze reduzéieren an de Prozess erlaabt verschidden Aufgaben auszeféieren. Zum Beispill, wann Är Applikatioun muss e privilegiéierten Hafen opmaachen, sot 80, anstatt de Prozess als Root ze lafen, kënnt Dir et einfach d'CAP_NET_BIND_SERVICE Fäegkeet ginn.

Betruecht e Go Programm mam Numm main.go:

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

Dëse Programm servéiert en HTTP-Server um Hafen 80 (dëst ass e privilegiéierten Hafen). Normalerweis lafe mir et direkt no der Kompiléierung:

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

Wéi och ëmmer, well mir keng Root Privilegien ginn, wäert dëse Code e Feeler werfen wann Dir den Hafen verbënnt:

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

capsh (Shell Manager) ass en Tool dat eng Shell mat engem spezifesche Set vu Fäegkeeten leeft.

An dësem Fall, wéi schonn erwähnt, anstatt voll Root Rechter ze ginn, kënnt Dir privilegiéierten Hafenverbindung aktivéieren andeems Dir d'cap_net_bind_service Kapazitéit zesumme mat alles wat scho am Programm ass. Fir dëst ze maachen, kënne mir eise Programm an capsh zoumaachen:

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

Loosst eis dës Equipe e bëssen verstoen.

  • capsh - benotzt Capsh als Shell.
  • —caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' - well mir de Benotzer mussen änneren (mir wëllen net als Root lafen), spezifizéiere mir cap_net_bind_service an d'Fäegkeet fir d'Benotzer ID tatsächlech z'änneren root fir keen, nämlech cap_setuid an cap_setgid.
  • -keep=1 - mir wëllen déi installéiert Fäegkeeten halen wann Dir vum Root Kont wiesselt.
  • —user=“keen” — den Endbenotzer deen de Programm leeft wäert kee sinn.
  • -addamb = cap_net_bind_service - setzt d'Läschung vun de verwandte Fäegkeeten nom Wiessel vum Root-Modus.
  • - -c "./capabilities" - einfach de Programm lafen.

Verlinkt Fäegkeeten sinn eng speziell Aart vu Fäegkeeten, déi vu Kannerprogrammer ierflecher sinn, wann den aktuelle Programm se mat execve () ausféiert. Nëmme Fäegkeeten, déi erlaabt sinn ze verbonnen, oder an anere Wierder, als Ëmweltfäegkeeten, kënnen ierflecher ginn.

Dir frot Iech wahrscheinlech wat +eip heescht nodeems Dir d'Fäegkeet an der --caps Optioun uginn hutt. Dës Fändelen gi benotzt fir ze bestëmmen datt d'Fäegkeet:

-muss aktivéiert ginn (p);

- verfügbar fir ze benotzen (e);

-kann duerch Kand Prozesser ierflecher ginn (i).

Well mir cap_net_bind_service benotze wëllen, musse mir dat mam e Fändel maachen. Da starten mir d'Schuel am Kommando. Dëst wäert d'Fäegkeeten binär lafen a mir mussen et mam i Fändel markéieren. Schlussendlech wëlle mir d'Feature aktivéiert ginn (mir hunn dat gemaach ouni d'UID z'änneren) mat p. Et gesäit aus wéi cap_net_bind_service+eip.

Dir kënnt d'Resultat iwwerpréiwen mat ss. Loosst eis d'Ausgab e bësse verkierzen fir op d'Säit ze passen, awer et wäert den assoziéierten Hafen a Benotzer ID anescht wéi 0 weisen, an dësem Fall 65:

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

An dësem Beispill hu mir Capsh benotzt, awer Dir kënnt eng Shell mat libcap schreiwen. Fir méi Informatiounen, gesinn Mann 3 libcap.

Wann Dir Programmer schreift, weess den Entwéckler dacks net am Viraus all d'Features, déi de Programm während der Lafzäit brauch; Ausserdeem kënnen dës Funktiounen an neie Versiounen änneren.

Fir d'Fäegkeete vun eisem Programm besser ze verstoen, kënne mir de BCC-fähig Tool huelen, deen d'kprobe fir d'cap_capable Kernelfunktioun setzt:

/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

Mir kënnen datselwecht erreechen andeems Dir bpftrace mat enger One-Liner kprobe an der cap_capable Kernel Funktioun benotzt:

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

Dëst wäert eppes wéi déi folgend erausginn wann d'Fäegkeete vun eisem Programm no kprobe aktivéiert sinn:

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

Déi fënneft Kolonn ass d'Fäegkeeten, déi de Prozess brauch, a well dës Ausgang net-Audit-Evenementer enthält, gesi mir all Net-Auditkontrolle a schliisslech déi erfuerderlech Fähigkeit mat der Auditflagg (lescht am Ausgang) op 1. Kapazitéit Den een an deem mir interesséiert sinn ass CAP_NET_BIND_SERVICE, et ass definéiert als Konstant am Kernel Quellcode an der Datei include/uapi/linux/ability.h mat Identifizéierer 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">

D'Kapazitéite ginn dacks während der Runtime fir Container wéi runC oder Docker aktivéiert fir datt se an onprivilegéierte Modus lafen, awer si sinn nëmmen erlaabt déi Fäegkeeten déi néideg sinn fir déi meescht Uwendungen ze lafen. Wann eng Applikatioun bestëmmte Fäegkeeten erfuerdert, kann Docker se mat --cap-add ubidden:

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

Dëse Kommando gëtt dem Container d'CAP_NET_ADMIN Fähigkeit, wat et erlaabt en Netzverbindung ze konfiguréieren fir den Dummy0 Interface ze addéieren.

Déi nächst Sektioun weist wéi Dir Features benotzt wéi Filteren, awer mat enger anerer Technik déi eis erlaabt eis eegen Filteren programmatesch ëmzesetzen.

Secomp

Secomp steet fir Secure Computing an ass eng Sécherheetsschicht, déi am Linux Kernel implementéiert ass, déi d'Entwéckler erlaabt bestëmmte Systemriff ze filteren. Och wann Secomp a Fäegkeeten mat Linux vergläichbar ass, mécht seng Fäegkeet fir verschidde Systemriff ze managen et vill méi flexibel am Verglach mat hinnen.

Secomp a Linux Feature sinn net géigesäiteg exklusiv a ginn dacks zesumme benotzt fir vu béide Approche ze profitéieren. Zum Beispill wëllt Dir e Prozess d'CAP_NET_ADMIN Fäegkeet ginn, awer net erlaben et Socketverbindungen ze akzeptéieren, blockéiert d'Acceptéieren an accept4 System Uriff.

D'Secomp Filtermethod baséiert op BPF Filteren déi am SECCOMP_MODE_FILTER Modus funktionnéieren, a System Uruff Filterung gëtt op déiselwecht Manéier gemaach wéi fir Päckchen.

Seccomp Filtere ginn mat prctl iwwer d'PR_SET_SECCOMP Operatioun gelueden. Dës Filtere huelen d'Form vun engem BPF Programm dee fir all Seccomp Paket ausgefouert gëtt, representéiert vun der seccomp_data Struktur. Dës Struktur enthält d'Referenzarchitektur, e Pointer op Prozessorinstruktiounen zur Zäit vum Systemruff, a maximal sechs Systemruffargumenter, ausgedréckt als uint64.

Dëst ass wéi d'secomp_data Struktur aus dem Kernel Quellcode an der linux/secomp.h Datei ausgesäit:

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

Wéi Dir aus dëser Struktur gesitt, kënne mir duerch de Systemruff filteren, seng Argumenter oder eng Kombinatioun vun deenen zwee.

Nodeems Dir all Seccomp Paket kritt hutt, muss de Filter d'Veraarbechtung ausféieren fir eng definitiv Entscheedung ze treffen an dem Kernel ze soen wat et duerno maache soll. Déi definitiv Entscheedung gëtt duerch ee vun de Retourwäerter ausgedréckt (Statuscodes).

- SECCOMP_RET_KILL_PROCESS - killt de ganze Prozess direkt nodeems Dir e Systemruff filtert deen net ausgefouert gëtt.

- SECCOMP_RET_KILL_THREAD - terminéiert den aktuelle Fuedem direkt nodeems Dir e Systemruff filtert deen net ausgefouert gëtt wéinst dësem.

— SECCOMP_RET_KILL — Alias ​​fir SECCOMP_RET_KILL_THREAD, lénks fir Réckkompatibilitéit.

- SECCOMP_RET_TRAP - de System Uruff ass verbueden, an der SIGSYS (Bad System Call) Signal gëtt un d'Aufgab geschéckt datt et rifft.

- SECCOMP_RET_ERRNO - De System Uruff gëtt net ausgefouert, an en Deel vum SECCOMP_RET_DATA Filter Retour Wäert gëtt als Errno Wäert un de Benotzerraum weiderginn. Ofhängeg vun der Ursaach vum Feeler, gi verschidde Feelerwäerter zréckginn. Eng Lëscht vu Feelernummeren gëtt an der nächster Sektioun geliwwert.

- SECCOMP_RET_TRACE - Benotzt fir de ptrace Tracer z'informéieren benotzt - PTRACE_O_TRACESECCOMP fir z'ënnerscheeden wann e Systemruff ausgefouert gëtt fir dëse Prozess ze gesinn an ze kontrolléieren. Wann e Tracer net ugeschloss ass, gëtt e Feeler zréck, errno gëtt op -ENOSYS gesat, an de Systemruff gëtt net ausgefouert.

- SECCOMP_RET_LOG - de System Uruff gëtt geléist a protokolléiert.

- SECCOMP_RET_ALLOW - de System Uruff ass einfach erlaabt.

ptrace ass e System Uruff fir Tracing Mechanismen an engem Prozess genannt Tracee ëmzesetzen, mat der Fäegkeet fir d'Ausféierung vum Prozess ze iwwerwaachen an ze kontrolléieren. De Spuerprogramm kann effektiv d'Ausféierung beaflossen an d'Erënnerungsregistre vum Tracee änneren. Am Secomp Kontext gëtt ptrace benotzt wann se vum SECCOMP_RET_TRACE Statuscode ausgeléist ginn, sou datt de Tracer kann verhënneren datt de System Uruff ausféiert an seng eege Logik ëmsetzt.

Secomp Feeler

Vun Zäit zu Zäit, während Dir mat Seccomp schafft, fannt Dir verschidde Feeler, déi duerch e Retourwäert vum Typ SECCOMP_RET_ERRNO identifizéiert ginn. Fir e Feeler ze berichten, gëtt de seccomp System Uruff -1 anstatt 0 zréck.

Déi folgend Feeler si méiglech:

- EACCESS - Den Uruffer ass net erlaabt e System Uruff ze maachen. Dëst geschitt normalerweis well et keng CAP_SYS_ADMIN Privilegien huet oder no_new_privs net mat prctl gesat gëtt (mir wäerte méi spéit doriwwer schwätzen);

- EFAULT - déi passéiert Argumenter (args an der seccomp_data Struktur) hu keng gëlteg Adress;

- EINVAL - et kënne véier Grënn hei sinn:

- déi ugefrote Operatioun ass onbekannt oder net ënnerstëtzt vum Kernel an der aktueller Konfiguratioun;

- déi spezifizéiert Fändelen sinn net valabel fir déi ugefrote Operatioun;

-Operatioun enthält BPF_ABS, awer et gi Problemer mat der spezifizéierter Offset, déi d'Gréisst vun der seccomp_data Struktur iwwerschreiden kann;

-d'Zuel vun den Instruktiounen, déi un de Filter passéiert sinn, iwwerschreift de Maximum;

- ENOMEM - net genuch Erënnerung fir de Programm auszeféieren;

- EOPNOTSUPP - d'Operatioun huet uginn datt mat SECCOMP_GET_ACTION_AVAIL d'Aktioun verfügbar war, awer de Kernel ënnerstëtzt keng Retouren an Argumenter;

— ESRCH — e Problem geschitt beim Synchroniséierung vun engem anere Stream;

- ENOSYS - Et gëtt keen Tracer un der SECCOMP_RET_TRACE Aktioun verbonnen.

prctl ass e Systemruff deen e Benotzerraumprogramm erlaabt spezifesch Aspekter vun engem Prozess ze manipuléieren (setze a kréien), wéi Byte Endianness, Thread Nimm, séchere Berechnungsmodus (Seccomp), Privilegien, Perf Eventer, etc.

Secomp kann Iech wéi eng Sandbox Technologie schéngen, awer et ass net. Secomp ass en Utility dat d'Benotzer erlaabt e Sandbox Mechanismus z'entwéckelen. Loosst eis elo kucken wéi d'Benotzerinteraktiounsprogrammer erstallt ginn mat engem Filter direkt vum Secomp System Uruff.

BPF Secomp Filter Beispill

Hei wäerte mir weisen wéi déi zwou Aktiounen, déi virdru diskutéiert goufen, kombinéieren, nämlech:

- mir schreiwen e Secomp BPF Programm, deen als Filter mat verschiddene Retourcodes benotzt gëtt ofhängeg vun den Entscheedungen déi getraff ginn;

- lued de Filter mat prctl.

Als éischt braucht Dir Header aus der Standardbibliothéik an dem Linux Kernel:

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

Ier Dir dëst Beispill probéiert, musse mir suergen datt de Kernel mat CONFIG_SECCOMP an CONFIG_SECCOMP_FILTER op y gesat ass. Op enger Aarbechtsmaschinn kënnt Dir dëst esou kontrolléieren:

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

De Rescht vum Code ass eng zwee-Deel install_filter Funktioun. Den éischten Deel enthält eis Lëscht vu BPF Filterinstruktiounen:

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

D'Instruktioune gi mat der BPF_STMT- a BPF_JUMP-Makroen an der Linux/filter.h-Datei definéiert.
Loosst eis duerch d'Instruktioune goen.

- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, arch))) - de System lued a accumuléiert vu BPF_LD a Form vum Wuert BPF_W, Paketdaten sinn op engem fixen Offset BPF_ABS.

- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arch, 0, 3) - kontrolléiert mat BPF_JEQ ob den Architekturwäert an der BPF_K Akkumulatorkonstant gläich ass wéi den Arch. Wann jo, spréngt op Offset 0 op déi nächst Instruktioun, soss spréngt op Offset 3 (an dësem Fall) fir e Feeler ze werfen, well den Arch net passt.

- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, nr))) - Luet a accumuléiert vu BPF_LD a Form vum Wuert BPF_W, wat d'Systemruffnummer ass, déi am fixen Offset vu BPF_ABS enthale sinn.

— BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1) — vergläicht d'Systemruffnummer mam Wäert vun der Variabel nr. Wann se gläich sinn, geet op déi nächst Instruktioun an deaktivéiert de System Opruff, soss erlaabt de System Opruff mat SECCOMP_RET_ALLOW.

- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (Feeler & SECCOMP_RET_DATA)) - schléisst de Programm mat BPF_RET of a produzéiert als Resultat e Feeler SECCOMP_RET_ERRNO mat der Zuel vun der Feelervariabel.

- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW) - schléisst de Programm mat BPF_RET of an erlaabt de Systemruff mat SECCOMP_RET_ALLOW auszeféieren.

SECCOMP ASS CBPF
Dir kënnt Iech froen firwat eng Lëscht vun Instruktioune benotzt gëtt amplaz vun engem kompiléierten ELF Objet oder engem JIT kompiléierte C Programm.

Et ginn zwee Grënn dofir.

• Als éischt benotzt Seccomp cBPF (klassesch BPF) an net eBPF, dat heescht: et huet keng Registere, awer nëmmen en Akkumulator fir dat lescht Berechnungsresultat ze späicheren, wéi et am Beispill gesi ka ginn.

• Zweetens, Secomp akzeptéiert e Pointer op eng Rei vu BPF Instruktiounen direkt an näischt anescht. D'Makroen, déi mir benotzt hunn, hëllefen einfach dës Instruktiounen op eng Programméiererfrëndlech Manéier ze spezifizéieren.

Wann Dir méi Hëllef braucht fir dës Versammlung ze verstoen, betruecht de Pseudocode deen datselwecht mécht:

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

Nodeems Dir de Filtercode an der Socket_filter Struktur definéiert hutt, musst Dir e sock_fprog definéieren deen de Code an déi berechent Längt vum Filter enthält. Dës Datestruktur ass gebraucht als Argument fir de Prozess ze deklaréieren fir méi spéit ze lafen:

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

Et bleift nëmmen eng Saach ze maachen an der install_filter Funktioun - lued de Programm selwer! Fir dëst ze maachen, benotze mir prctl, huelen PR_SET_SECCOMP als Optioun fir de séchere Rechenmodus anzeginn. Da soen mir de Modus fir de Filter mat SECCOMP_MODE_FILTER ze lueden, deen an der Prog Variabel vum Typ sock_fprog enthält:

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

Schlussendlech kënne mir eis install_filter Funktioun benotzen, awer virdru musse mir prctl benotzen fir PR_SET_NO_NEW_PRIVS fir déi aktuell Ausféierung ze setzen an doduerch d'Situatioun ze vermeiden wou Kannerprozesser méi Privilegien kréien wéi hir Elteren. Mat dësem kënne mir déi folgend prctl Uriff an der install_filter Funktioun maachen ouni Root Rechter ze hunn.

Elo kënne mir d'install_filter Funktioun nennen. Loosst eis all Schreifsystem Uruff am Zesummenhang mat der X86-64 Architektur blockéieren an einfach eng Erlaabnis ginn déi all Versuche blockéiert. Nodeems Dir de Filter installéiert hutt, fuere mir weider mat dem éischten 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]);
 }

Loosst eis ufänken. Fir eise Programm ze kompiléieren kënne mir entweder clang oder gcc benotzen, egal wéi et ass just d'Main.c Datei ze kompiléieren ouni speziell Optiounen:

clang main.c -o filter-write

Wéi bemierkt, hu mir all Entréen am Programm blockéiert. Fir dëst ze testen, brauch Dir e Programm deen eppes erausgëtt - ls schéngt wéi e gudde Kandidat. Dëst ass wéi si normalerweis behält:

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

Wonnerbar! Hei ass wéi d'Benotzung vun eisem Wrapper Programm ausgesäit: Mir passéieren einfach de Programm dee mir testen wëllen als éischt Argument:

./filter-write "ls -la"

Wann ausgefouert gëtt, produzéiert dëse Programm komplett eidel Output. Wéi och ëmmer, mir kënne Strace benotzen fir ze kucken wat lass ass:

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

D'Resultat vun der Aarbecht ass staark verkierzt, awer de entspriechende Deel dovun weist datt d'Records mam EPERM-Fehler blockéiert sinn - dee selwechte dee mir konfiguréiert hunn. Dëst bedeit datt de Programm näischt ausgëtt well et net op de Schreifsystem Uruff kënnt:

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

Elo verstitt Dir wéi Secomp BPF funktionnéiert an hutt eng gutt Iddi wat Dir domat maache kënnt. Awer wéilt Dir net datselwecht mat eBPF erreechen anstatt cBPF fir seng voll Kraaft ze profitéieren?

Wann Dir un eBPF Programmer denkt, denken déi meescht Leit datt se se einfach schreiwen an se mat Administrator Privilegien lueden. Och wann dës Ausso allgemeng richteg ass, implementéiert de Kernel eng Rei vu Mechanismen fir eBPF Objekter op verschiddenen Niveauen ze schützen. Dës Mechanismen ginn BPF LSM Fallen genannt.

BPF LSM Fallen

Fir eng Architektur-onofhängeg Iwwerwaachung vu Systemevenementer ze bidden, implementéiert LSM d'Konzept vu Fallen. En Hook Call ass technesch ähnlech wéi e System Uruff, awer ass systemonofhängeg an integréiert mat der Infrastruktur. LSM liwwert en neit Konzept an deem eng Abstraktiounsschicht hëllefe kann Probleemer ze vermeiden, déi opstinn wann Dir mat Systemappellen op verschidden Architekturen handelt.

Zu der Zäit vum Schreiwen huet de Kernel siwe Haken verbonne mat BPF Programmer, an SELinux ass deen eenzegen agebaute LSM deen se implementéiert.

De Quellcode fir d'Fallen ass am Kernelbaum an der Datei 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);

Jiddereng vun hinnen gëtt op verschidden Etappe vun Ausféierung genannt ginn:

- security_bpf - mécht eng initial Kontroll vun ausgefouerten BPF System Uriff;

- security_bpf_map - kontrolléiert wann de Kernel e Dateideskriptor fir d'Kaart zréckkënnt;

- security_bpf_prog - kontrolléiert wann de Kernel e Dateideskriptor fir den eBPF Programm zréckkënnt;

- security_bpf_map_alloc - kontrolléiert ob d'Sécherheetsfeld bannent BPF Kaarten initialiséiert ass;

- security_bpf_map_free - kontrolléiert ob d'Sécherheetsfeld bannent BPF Kaarten geläscht ass;

- security_bpf_prog_alloc - kontrolléiert ob d'Sécherheetsfeld bannent BPF Programmer initialiséiert ass;

- security_bpf_prog_free - kontrolléiert ob d'Sécherheetsfeld bannent BPF Programmer geläscht ass.

Elo, all dëst ze gesinn, verstinn mir: d'Iddi hannert LSM BPF Interceptoren ass datt se Schutz fir all eBPF Objet kënne bidden, fir datt nëmmen déi mat de passenden Privilegien Operatiounen op Kaarten a Programmer kënne maachen.

Summary

Sécherheet ass net eppes wat Dir op eng eenzeg Gréisst passt-all Manéier implementéiere kënnt fir alles wat Dir wëllt schützen. Et ass wichteg fir Systemer op verschidden Niveauen a verschidde Manéieren ze schützen. Gleeft et oder net, de beschte Wee fir e System ze sécheren ass verschidde Schutzniveauen aus verschiddene Positiounen ze organiséieren, sou datt d'Reduktioun vun der Sécherheet vun engem Niveau den Zougang zum ganze System net erlaabt. D'Kärentwéckler hunn eng super Aarbecht gemaach fir eis eng Rei vu verschiddene Schichten an Touchpoints ze ginn. Mir hoffen, datt mir Iech e gutt Verständnis ginn hunn wat Schichten sinn a wéi Dir BPF Programmer benotzt fir mat hinnen ze schaffen.

Iwwer d'Auteuren

David Calavera ass den CTO bei Netlify. Hien huet an Docker Support geschafft an huet zu der Entwécklung vu Runc, Go a BCC Tools bäigedroen, wéi och aner Open Source Projeten. Bekannt fir seng Aarbecht op Docker Projeten an Entwécklung vum Docker Plugin Ökosystem. Den David ass ganz passionéiert iwwer Flamgrafiken a sicht ëmmer d'Performance ze optimiséieren.

Lorenzo Fontana schafft am Open Source Team bei Sysdig, wou hien haaptsächlech op Falco konzentréiert ass, e Cloud Native Computing Foundation Projet deen Container Runtime Sécherheet an Anomalie Detektioun duerch e Kernel Modul an eBPF ubitt. Hien ass passionéiert iwwer verdeelt Systemer, Software definéiert Netzwierker, de Linux Kernel, a Performance Analyse.

» Méi Detailer iwwert d'Buch fannt Dir op Websäit vum Verlag
» Inhaltsverzeechnes
» Auszuch

Fir Khabrozhiteley 25% Remise mat Coupon - Linux

Beim Bezuelen vun der Pabeierversioun vum Buch gëtt en elektronescht Buch per E-Mail geschéckt.

Source: will.com

Setzt e Commentaire