Boka "BPF för Linux-övervakning"

Boka "BPF för Linux-övervakning"Hej alla Khabrobor! Den virtuella BPF-maskinen Ă€r en av de viktigaste komponenterna i Linux-kĂ€rnan. Dess korrekta anvĂ€ndning gör det möjligt för systemingenjörer att hitta fel och lösa Ă€ven de mest komplexa problem. Du kommer att lĂ€ra dig hur man skriver program som övervakar och modifierar kĂ€rnans beteende, hur man sĂ€kert implementerar kod för att övervaka hĂ€ndelser i kĂ€rnan och mycket mer. David Calavera och Lorenzo Fontana hjĂ€lper dig att lĂ„sa upp kraften hos BPF. Utöka din kunskap om prestandaoptimering, nĂ€tverk, sĂ€kerhet. - AnvĂ€nd BPF för att övervaka och Ă€ndra beteendet hos LinuxkĂ€rnan. - Injicera kod för att sĂ€kert övervaka kĂ€rnhĂ€ndelser utan att behöva kompilera om kĂ€rnan eller starta om systemet. — AnvĂ€nd praktiska kodexempel i C, Go eller Python. - Ta kontroll genom att Ă€ga BPF-programmets livscykel.

Linux Kernel Security, dess funktioner och Secomp

BPF ger ett kraftfullt sÀtt att utöka kÀrnan utan att offra stabilitet, sÀkerhet eller hastighet. Av denna anledning tyckte kÀrnutvecklarna att det skulle vara en bra idé att anvÀnda dess mÄngsidighet för att förbÀttra processisoleringen i Seccomp genom att implementera Seccomp-filter som stöds av BPF-program, Àven kÀnda som Seccomp BPF. I det hÀr kapitlet kommer vi att förklara vad Secomp Àr och hur det anvÀnds. Sedan kommer du att lÀra dig hur du skriver Secomp-filter med BPF-program. Efter det ska vi titta pÄ de inbyggda BPF-krokarna som ingÄr i kÀrnan för Linux-sÀkerhetsmoduler.

Linux Security Modules (LSM) Àr ett ramverk som tillhandahÄller en uppsÀttning funktioner som kan anvÀndas för att implementera olika sÀkerhetsmodeller pÄ ett standardiserat sÀtt. LSM kan anvÀndas direkt i kÀrnans kÀlltrÀd, sÄsom Apparmor, SELinux och Tomoyo.

LÄt oss börja med att diskutera funktionerna hos Linux.

Capabilities

KÀrnan i Linuxs möjligheter Àr att du behöver ge en oprivilegierad processbehörighet för att utföra en viss uppgift, men utan att anvÀnda suid för det ÀndamÄlet, eller pÄ annat sÀtt göra processen privilegierad, vilket minskar risken för attack och tillÄter processen att utföra vissa uppgifter. Till exempel, om din applikation behöver öppna en privilegierad port, sÀg 80, istÀllet för att köra processen som root, kan du helt enkelt ge den CAP_NET_BIND_SERVICE-kapaciteten.

ÖvervĂ€g ett Go-program som heter main.go:

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

Detta program betjÀnar en HTTP-server pÄ port 80 (detta Àr en privilegierad port). Vanligtvis kör vi det direkt efter kompilering:

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

Men eftersom vi inte beviljar root-privilegier kommer den hÀr koden att ge ett fel nÀr porten binds:

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

capsh (skalhanterare) Àr ett verktyg som kör ett skal med en specifik uppsÀttning funktioner.

I det hÀr fallet, som redan nÀmnts, istÀllet för att ge fullstÀndiga rotrÀttigheter, kan du aktivera privilegierad portbindning genom att tillhandahÄlla cap_net_bind_service-kapaciteten tillsammans med allt annat som redan finns i programmet. För att göra detta kan vi bifoga vÄrt program i 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"

LÄt oss förstÄ det hÀr laget lite.

  • capsh - anvĂ€nd capsh som ett skal.
  • —caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' - eftersom vi behöver Ă€ndra anvĂ€ndaren (vi vill inte köra som root), kommer vi att specificera cap_net_bind_service och möjligheten att faktiskt Ă€ndra anvĂ€ndar-ID frĂ„n rot till ingen, nĂ€mligen cap_setuid och cap_setgid.
  • —keep=1 — vi vill behĂ„lla de installerade funktionerna nĂ€r vi byter frĂ„n root-kontot.
  • —user=“ingen” — slutanvĂ€ndaren som kör programmet kommer att vara ingen.
  • —addamb=cap_net_bind_service — stĂ€ll in rensningen av relaterade funktioner efter byte frĂ„n rotlĂ€ge.
  • - -c "./capabilities" - kör bara programmet.

LÀnkade funktioner Àr en speciell typ av funktioner som Àrvs av underordnade program nÀr det aktuella programmet kör dem med execve(). Endast förmÄgor som tillÄts associeras, eller med andra ord, som miljöförmÄgor, kan Àrvas.

Du undrar förmodligen vad +eip betyder efter att ha angett förmÄgan i --caps-alternativet. Dessa flaggor anvÀnds för att faststÀlla att kapaciteten:

-mÄste aktiveras (p);

-tillgÀnglig för anvÀndning (e);

-kan Àrvas av underordnade processer (i).

Eftersom vi vill anvÀnda cap_net_bind_service mÄste vi göra detta med e-flaggan. Sedan startar vi skalet i kommandot. Detta kommer att köra funktionerna binÀr och vi mÄste markera den med flaggan i. Slutligen vill vi att funktionen ska vara aktiverad (vi gjorde detta utan att Àndra UID) med p. Det ser ut som cap_net_bind_service+eip.

Du kan kontrollera resultatet med ss. LÄt oss förkorta utgÄngen lite för att passa pÄ sidan, men den kommer att visa tillhörande port och anvÀndar-ID annat Àn 0, i det hÀr fallet 65:

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

I det hÀr exemplet anvÀnde vi capsh, men du kan skriva ett skal med libcap. För mer information, se man 3 libcap.

NÀr man skriver program kÀnner inte utvecklaren ofta till alla funktioner som programmet behöver vid körning; Dessutom kan dessa funktioner Àndras i nya versioner.

För att bÀttre förstÄ funktionerna i vÄrt program kan vi ta BCC-kapabla verktyget, som stÀller in kprobe för cap_capable-kÀrnfunktionen:

/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

Vi kan uppnÄ samma sak genom att anvÀnda bpftrace med en one-liner kprobe i kÀrnfunktionen 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

Detta kommer att mata ut nÄgot i stil med följande om vÄrt programs funktioner Àr aktiverade efter 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

Den femte kolumnen Àr de möjligheter som processen behöver, och eftersom denna utdata inkluderar icke-revisionshÀndelser, ser vi alla icke-revisionskontroller och slutligen den erforderliga förmÄgan med revisionsflaggan (sist i utgÄngen) instÀlld pÄ 1. Capability. en vi Àr intresserade av Àr CAP_NET_BIND_SERVICE, den definieras som en konstant i kÀrnans kÀllkod i filen include/uapi/linux/ability.h med identifierare 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">

Funktioner Àr ofta aktiverade under körning för behÄllare som runC eller Docker för att tillÄta dem att köra i oprivilegierat lÀge, men de tillÄts bara de funktioner som behövs för att köra de flesta applikationer. NÀr en applikation krÀver vissa funktioner kan Docker tillhandahÄlla dem med --cap-add:

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

Detta kommando ger behÄllaren CAP_NET_ADMIN-förmÄgan, vilket gör att den kan konfigurera en nÀtverkslÀnk för att lÀgga till dummy0-grÀnssnittet.

NÀsta avsnitt visar hur man anvÀnder funktioner som filtrering, men med en annan teknik som gör att vi kan implementera vÄra egna filter programmatiskt.

Secomp

Secomp stĂ„r för Secure Computing och Ă€r ett sĂ€kerhetslager implementerat i Linux-kĂ€rnan som lĂ„ter utvecklare filtrera vissa systemanrop. Även om Secomp Ă€r jĂ€mförbar i kapacitet med Linux, gör dess förmĂ„ga att hantera vissa systemanrop det mycket mer flexibelt jĂ€mfört med dem.

Secomp- och Linux-funktioner utesluter inte varandra och anvÀnds ofta tillsammans för att dra nytta av bÄda metoderna. Du kanske till exempel vill ge en process förmÄgan CAP_NET_ADMIN men inte tillÄta den att acceptera socket-anslutningar, vilket blockerar acceptera och acceptera4 systemanrop.

Secomp-filtreringsmetoden Àr baserad pÄ BPF-filter som arbetar i SECCOMP_MODE_FILTER-lÀget, och systemanropsfiltrering utförs pÄ samma sÀtt som för paket.

Seccomp-filter laddas med prctl via PR_SET_SECCOMP-operationen. Dessa filter har formen av ett BPF-program som exekveras för varje Seccomp-paket som representeras av seccomp_data-strukturen. Denna struktur innehÄller referensarkitekturen, en pekare till processorinstruktioner vid tidpunkten för systemanropet och maximalt sex systemanropsargument, uttryckta som uint64.

SÄ hÀr ser strukturen secomp_data ut frÄn kÀrnans kÀllkod i filen linux/seccomp.h:

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

Som du kan se frÄn den hÀr strukturen kan vi filtrera efter systemanropet, dess argument eller en kombination av bÄda.

Efter att ha tagit emot varje Seccomp-paket mÄste filtret utföra bearbetning för att fatta ett slutgiltigt beslut och tala om för kÀrnan vad som ska göras hÀrnÀst. Det slutliga beslutet uttrycks av ett av returvÀrdena (statuskoder).

- SECCOMP_RET_KILL_PROCESS - dödar hela processen omedelbart efter filtrering av ett systemanrop som inte exekveras pÄ grund av detta.

- SECCOMP_RET_KILL_THREAD - avslutar den aktuella trÄden omedelbart efter filtrering av ett systemanrop som inte exekveras pÄ grund av detta.

— SECCOMP_RET_KILL — alias för SECCOMP_RET_KILL_THREAD, vĂ€nster för bakĂ„tkompatibilitet.

- SECCOMP_RET_TRAP - systemanropet Àr förbjudet, och SIGSYS-signalen (Bad System Call) skickas till uppgiften som anropar den.

- SECCOMP_RET_ERRNO - Systemanropet exekveras inte, och en del av SECCOMP_RET_DATA-filtrets returvÀrde skickas till anvÀndarutrymmet som felvÀrdet. Beroende pÄ orsaken till felet returneras olika felvÀrden. En lista över felnummer finns i nÀsta avsnitt.

- SECCOMP_RET_TRACE - AnvÀnds för att meddela ptrace-spÄraren med - PTRACE_O_TRACESECCOMP för att avlyssna nÀr ett systemanrop exekveras för att se och kontrollera den processen. Om en spÄrare inte Àr ansluten returneras ett fel, errno sÀtts till -ENOSYS och systemanropet exekveras inte.

- SECCOMP_RET_LOG - systemanropet löses och loggas.

- SECCOMP_RET_ALLOW - systemanropet Àr helt enkelt tillÄtet.

ptrace Àr ett systemanrop för att implementera spÄrningsmekanismer i en process som kallas tracee, med förmÄgan att övervaka och kontrollera exekveringen av processen. SpÄrningsprogrammet kan effektivt pÄverka exekveringen och modifiera spÄrningens minnesregister. I Secomp-sammanhang anvÀnds ptrace nÀr den triggas av SECCOMP_RET_TRACE-statuskoden, sÄ spÄraren kan förhindra systemanropet frÄn att exekvera och implementera sin egen logik.

Secomp-fel

DÄ och dÄ, nÀr du arbetar med Seccomp, kommer du att stöta pÄ olika fel, som identifieras av ett returvÀrde av typen SECCOMP_RET_ERRNO. För att rapportera ett fel kommer seccomp-systemanropet att returnera -1 istÀllet för 0.

Följande fel Àr möjliga:

- EACCESS - Den som ringer fÄr inte ringa ett systemsamtal. Detta hÀnder vanligtvis eftersom det inte har CAP_SYS_ADMIN-privilegier eller att no_new_privs inte Àr instÀllt med prctl (vi ska prata om detta senare);

— EFAULT — de godkĂ€nda argumenten (args i seccomp_data-strukturen) har inte en giltig adress;

— EINVAL — det kan finnas fyra anledningar hĂ€r:

-den begÀrda operationen Àr okÀnd eller stöds inte av kÀrnan i den aktuella konfigurationen;

-de angivna flaggorna Àr inte giltiga för den begÀrda operationen;

-operation inkluderar BPF_ABS, men det finns problem med den specificerade offseten, som kan överstiga storleken pÄ seccomp_data-strukturen;

-antalet instruktioner som skickas till filtret överstiger det maximala;

— ENOMEM — inte tillrĂ€ckligt med minne för att köra programmet;

- EOPNOTSUPP - operationen indikerade att med SECCOMP_GET_ACTION_AVAIL var ÄtgÀrden tillgÀnglig, men kÀrnan stöder inte returer i argument;

— ESRCH — ett problem uppstod vid synkronisering av en annan ström;

- ENOSYS - Det finns ingen spÄrare kopplad till SECCOMP_RET_TRACE-ÄtgÀrden.

prctl Àr ett systemanrop som tillÄter ett anvÀndarutrymmesprogram att manipulera (stÀlla in och hÀmta) specifika aspekter av en process, sÄsom byte endianness, trÄdnamn, sÀkert berÀkningslÀge (Seccomp), privilegier, Perf-hÀndelser, etc.

Secomp kan verka som en sandlÄdeteknik för dig, men det Àr det inte. Secomp Àr ett verktyg som lÄter anvÀndare utveckla en sandlÄdemekanism. LÄt oss nu titta pÄ hur anvÀndarinteraktionsprogram skapas med ett filter som anropas direkt av Secommp-systemanropet.

BPF Secomp Filter Exempel

HÀr kommer vi att visa hur man kombinerar de tvÄ ÄtgÀrder som diskuterats tidigare, nÀmligen:

— vi kommer att skriva ett Seccomp BPF-program, som kommer att anvĂ€ndas som ett filter med olika returkoder beroende pĂ„ vilka beslut som fattas;

— ladda filtret med prctl.

Först behöver du rubriker frÄn standardbiblioteket och Linux-kÀrnan:

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

Innan vi försöker det hÀr exemplet mÄste vi se till att kÀrnan Àr kompilerad med CONFIG_SECCOMP och CONFIG_SECCOMP_FILTER satt till y. PÄ en fungerande maskin kan du kontrollera detta sÄ hÀr:

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

Resten av koden Àr en tvÄdelad install_filter-funktion. Den första delen innehÄller vÄr lista med BPF-filtreringsinstruktioner:

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

Instruktionerna stÀlls in med hjÀlp av makrona BPF_STMT och BPF_JUMP som definieras i filen linux/filter.h.
LÄt oss gÄ igenom instruktionerna.

- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, arch))) - systemet laddar och ackumuleras frÄn BPF_LD i form av ordet BPF_W, paketdata Àr lokaliserad vid en fast offset BPF_ABS.

- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, bÄge, 0, 3) - kontrollerar med hjÀlp av BPF_JEQ om arkitekturvÀrdet i ackumulatorkonstanten BPF_K Àr lika med bÄge. Om sÄ Àr fallet, hoppar vid offset 0 till nÀsta instruktion, annars hoppar vid offset 3 (i detta fall) för att kasta ett fel eftersom bÄgen inte matchar.

- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, nr))) - Laddar och ackumuleras frÄn BPF_LD i form av ordet BPF_W, vilket Àr systemanropsnumret som ingÄr i den fasta offseten av BPF_ABS.

— BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1) — jĂ€mför systemanropsnumret med vĂ€rdet pĂ„ variabeln nr. Om de Ă€r lika, gĂ„r du vidare till nĂ€sta instruktion och inaktiverar systemanropet, annars tillĂ„ter systemanropet med SECCOMP_RET_ALLOW.

- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (error & SECCOMP_RET_DATA)) - avslutar programmet med BPF_RET och ger som ett resultat ett fel SECCOMP_RET_ERRNO med numret frÄn felvariabeln.

- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW) - avslutar programmet med BPF_RET och tillÄter att systemanropet exekveras med SECCOMP_RET_ALLOW.

SECCOMP ÄR CBPF
Du kanske undrar varför en lista med instruktioner anvÀnds istÀllet för ett kompilerat ELF-objekt eller ett JIT-kompilerat C-program.

Det finns tvÄ skÀl till detta.

‱ För det första anvĂ€nder Seccomp cBPF (klassisk BPF) och inte eBPF, vilket betyder: den har inga register, utan bara en ackumulator för att lagra det senaste berĂ€kningsresultatet, som kan ses i exemplet.

‱ För det andra accepterar Secomp en pekare till en uppsĂ€ttning BPF-instruktioner direkt och inget annat. Makron vi har anvĂ€nt hjĂ€lper helt enkelt till att specificera dessa instruktioner pĂ„ ett programmerarvĂ€nligt sĂ€tt.

Om du behöver mer hjÀlp med att förstÄ denna sammansÀttning, övervÀg pseudokoden som gör samma sak:

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

Efter att ha definierat filterkoden i socket_filter-strukturen mÄste du definiera en sock_fprog som innehÄller koden och den berÀknade lÀngden pÄ filtret. Denna datastruktur behövs som ett argument för att förklara att processen ska köras senare:

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

Det finns bara en sak kvar att göra i install_filter-funktionen - ladda sjÀlva programmet! För att göra detta anvÀnder vi prctl, med PR_SET_SECCOMP som ett alternativ för att gÄ in i sÀkert datorlÀge. Sedan sÀger vi till lÀget att ladda filtret med SECCOMP_MODE_FILTER, som finns i progvariabeln av typen sock_fprog:

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

Slutligen kan vi anvÀnda vÄr install_filter-funktion, men innan dess mÄste vi anvÀnda prctl för att stÀlla in PR_SET_NO_NEW_PRIVS för den aktuella exekveringen och dÀrmed undvika situationen dÀr underordnade processer fÄr fler privilegier Àn sina förÀldrar. Med detta kan vi göra följande prctl-anrop i install_filter-funktionen utan att ha root-rÀttigheter.

Nu kan vi anropa funktionen install_filter. LÄt oss blockera alla skrivsystemanrop relaterade till X86-64-arkitekturen och helt enkelt ge en behörighet som blockerar alla försök. Efter att ha installerat filtret fortsÀtter vi körningen med det första argumentet:

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

LÄt oss börja. För att kompilera vÄrt program kan vi anvÀnda antingen clang eller gcc, hur som helst Àr det bara att kompilera filen main.c utan speciella alternativ:

clang main.c -o filter-write

Som nÀmnts har vi blockerat alla poster i programmet. För att testa detta behöver du ett program som matar ut nÄgot - det verkar vara en bra kandidat. SÄ hÀr beter hon sig vanligtvis:

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

Underbar! SÄ hÀr ser det ut att anvÀnda vÄrt omslagsprogram: Vi klarar helt enkelt programmet vi vill testa som första argument:

./filter-write "ls -la"

NÀr det körs producerar det hÀr programmet helt tomt utdata. Men vi kan anvÀnda strace för att se vad som hÀnder:

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

Resultatet av arbetet förkortas avsevÀrt, men motsvarande del av det visar att poster Àr blockerade med EPERM-felet - samma som vi konfigurerade. Detta betyder att programmet inte matar ut nÄgot eftersom det inte kan komma Ät skrivsystemanropet:

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

Nu förstÄr du hur Secomp BPF fungerar och har en god uppfattning om vad du kan göra med det. Men skulle du inte vilja uppnÄ samma sak med eBPF istÀllet för cBPF för att utnyttja dess fulla kraft?

NĂ€r man tĂ€nker pĂ„ eBPF-program tror de flesta att de helt enkelt skriver dem och laddar dem med administratörsrĂ€ttigheter. Även om detta pĂ„stĂ„ende generellt Ă€r sant, implementerar kĂ€rnan en uppsĂ€ttning mekanismer för att skydda eBPF-objekt pĂ„ olika nivĂ„er. Dessa mekanismer kallas BPF LSM-fĂ€llor.

BPF LSM-fÀllor

För att tillhandahÄlla arkitekturoberoende övervakning av systemhÀndelser implementerar LSM konceptet med fÀllor. Ett hook call liknar tekniskt sett ett systemsamtal, men Àr systemoberoende och integrerat med infrastrukturen. LSM tillhandahÄller ett nytt koncept dÀr ett abstraktionsskikt kan hjÀlpa till att undvika problem som uppstÄr vid hantering av systemanrop pÄ olika arkitekturer.

I skrivande stund har kÀrnan sju krokar associerade med BPF-program, och SELinux Àr den enda inbyggda LSM som implementerar dem.

KÀllkoden för fÀllorna finns i kÀrntrÀdet i filen 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);

Var och en av dem kommer att anropas i olika skeden av utförande:

— security_bpf — utför en första kontroll av exekverade BPF-systemanrop;

- security_bpf_map - kontrollerar nÀr kÀrnan returnerar en filbeskrivning för kartan;

- security_bpf_prog - kontrollerar nÀr kÀrnan returnerar en filbeskrivning för eBPF-programmet;

— security_bpf_map_alloc — kontrollerar om sĂ€kerhetsfĂ€ltet inuti BPF-kartor Ă€r initierat;

- security_bpf_map_free - kontrollerar om sÀkerhetsfÀltet Àr rensat inuti BPF-kartor;

— security_bpf_prog_alloc — kontrollerar om sĂ€kerhetsfĂ€ltet Ă€r initialiserat i BPF-program;

- security_bpf_prog_free - kontrollerar om sÀkerhetsfÀltet Àr rensat i BPF-program.

Nu nÀr vi ser allt detta förstÄr vi: tanken bakom LSM BPF-interceptorer Àr att de kan ge skydd till varje eBPF-objekt, vilket sÀkerstÀller att endast de med lÀmpliga privilegier kan utföra operationer pÄ kort och program.

Sammanfattning

SÀkerhet Àr inget du kan implementera pÄ ett enhetligt sÀtt för allt du vill skydda. Det Àr viktigt att kunna skydda system pÄ olika nivÄer och pÄ olika sÀtt. Tro det eller ej, det bÀsta sÀttet att sÀkra ett system Àr att organisera olika skyddsnivÄer frÄn olika positioner, sÄ att en minskning av sÀkerheten pÄ en nivÄ inte tillÄter Ätkomst till hela systemet. KÀrnutvecklarna har gjort ett bra jobb med att ge oss en uppsÀttning olika lager och beröringspunkter. Vi hoppas att vi har gett dig en bra förstÄelse för vad lager Àr och hur du anvÀnder BPF-program för att arbeta med dem.

Om författare

David Calavera Àr CTO pÄ Netlify. Han arbetade i Docker-support och bidrog till utvecklingen av Runc-, Go- och BCC-verktyg, samt andra projekt med öppen kÀllkod. KÀnd för sitt arbete med Docker-projekt och utveckling av Docker-plugin-ekosystemet. David Àr mycket passionerad nÀr det gÀller flamgrafer och Àr alltid ute efter att optimera prestanda.

Lorenzo Fontana arbetar i open source-teamet pÄ Sysdig, dÀr han frÀmst Àr fokuserad pÄ Falco, ett Cloud Native Computing Foundation-projekt som tillhandahÄller containerruntime-sÀkerhet och avvikelsedetektering genom en kÀrnmodul och eBPF. Han brinner för distribuerade system, mjukvarudefinierat nÀtverk, Linux-kÀrnan och prestandaanalys.

» Mer information om boken finns pÄ förlagets webbplats
» innehÄllsförteckning
» Utdrag

För Khabrozhiteley 25% rabatt med kupong - Linux

Vid betalning av pappersversionen av boken skickas en elektronisk bok via e-post.

KĂ€lla: will.com

LĂ€gg en kommentar