seccomp (förkortat från engelska secure computing mode ) är en av säkerhetsmekanismerna i Linux-kärnan , som ger möjlighet att begränsa uppsättningen av tillgängliga systemanrop för applikationer, och även använda BPF-mekanismen ( Berkeley Packet Filter ) för att utföra komplex filtrering samtal och deras argument. Dök upp först i kärnversion 2.6.12 2005 [1] [2] .
För att arbeta med opålitliga eller overifierade, och därför potentiellt farliga program, är det tillrådligt att använda speciellt dedikerade miljöer från vilka det är omöjligt att skada systemets prestanda som helhet. I sådana miljöer (sandlådor, behållare) är många systemfunktioner begränsade för att köra program, såsom åtkomst till nätverket, I/O-enheter och interaktion med operativsystemet. Seccomp-mekanismen bestämmer mängden tillåtna systemanrop för processen och blockerar de som inte tidigare deklarerats. Det används för närvarande i ett antal webbläsare , Linux-liknande operativsystem och vissa virtualiseringssystem .
Seccomp-mekanismen utvecklades av Andrea Arcangeli ( italienska Andrea Arcangeli ) som en del av det kommersiella CPUShare-projektet, vars huvudidé var att fastställa kapaciteten och utveckla lösningar för att tillhandahålla datorresurser till datorer, särskilt med Linux OS, för exekvera tredjepartskod. Dök upp först i Linux-kärnan i mars 2005 (version 2.6.12). I den första versionen, för att aktivera seccomp, var processen tvungen att skriva en "1" till filen /proc/PID/seccomp. Därefter var endast fyra systemsamtal tillgängliga för gästkoden: read(), write(), exit()och sigreturn()[3] . Under 2007 lade version 2.6.23 till möjligheten att aktivera seccomp via ett systemanrop prctl()med PR_SET_SECCOMP-operationen, och /proc-gränssnittet togs bort [4] .
Trots att CPUShare-projektet, för vilket seccomp utvecklades, inte utvecklades och stängdes, fanns det kvar i Linux-kärnan [3] . I februari 2009 upptäcktes en sårbarhet i seccomp-koden. Det berodde på att i 32-bitars och 64-bitarsversioner av Linux motsvarade olika systemanrop samma nummer. Till exempel read()motsvarade ett tillåtet anrop från 64-bitarsversionen ett förbjudet anrop restart_syscall()från 32-bitarsversionen. Efter det uppstod frågan om att ta bort seccomp från Linux, och Linus Torvalds föreslog att seccomp inte användes av någon [5] .
Eftersom seccomp var tillräckligt enkelt att använda, hade utvecklarna av Google Chrome idén att implementera ett verktyg för att köra plugins från tredje part baserat på det . Men för att uppnå detta mål var det inte tillräckligt att bara blockera alla utom de fyra tillåtna systemanropen. Som ett resultat, 2012, integrerades BPF-mekanismen (Berkeley Packet Filter) med seccomp (i version 3.5 lades ett andra driftläge till - SECCOMP_MODE_FILTER), vilket avsevärt utökade mekanismens kapacitet - efter innovationen, gästen processen kan mer flexibelt välja uppsättningen av tillåtna och förbjudna systemanrop genom att bifoga lämpligt BPF-program. 2012 dök även biblioteket libsecomp upp, som ger ett enkelt och bekvämt API för att filtrera systemanrop [4] .
För att förenkla användningen av seccomp lade version 3.8 2013 till "Seccomp"-fältet till /proc/PID/status, vilket låter dig ta reda på statusen för seccomp (efter att inkluderingen togs bort från /proc var det omöjligt att ta reda på om den redan aktiverade seccomp kördes utan att avsluta processen). Under 2014 lade version 3.17 till ett speciellt systemanrop - seccomp(), som delvis upprepar funktionen prctl()[4] .
I november 2017, med lanseringen av glibc- biblioteksversionen 2.26, dök ett nytt problem upp: eftersom i C -program görs systemanrop inte direkt, utan genom omslag av standardbiblioteket, vars namn kanske inte matchar namnen på systemanrop, förbudet mot ett samtal kan oväntat påverka programmet. Till exempel implementeras en funktion från glibc-standardbiblioteket version 2.26 via ett systemanrop , vilket inte är detsamma som ett anrop och som felaktigt kan blockeras av filterförfattaren [6] . open()openat()open()
Du kan använda systemanropet seccomp()eller för att aktivera seccomp i ditt program prctl(). Det finns för närvarande två driftslägen för seccomp: SECCOMP_MODE_STRICT och SECCOMP_MODE_FILTER. Du kan ta reda på om seccomp är aktiverat och i vilket läge från "Seccomp"-fältet i filen /proc/[pid]/status. Fältet tar värdena 0, 1 eller 2: 0 — seccomp är inte aktiverat för processen, 1 — seccomp i SECCOMP_MODE_STRICT-läge, 2 — i SECCOMP_MODE_FILTER-läge [4] . Du kan inte aktivera seccomp för andra processer [7] .
Var det enda driftsättet före Linux 3.5. För att använda den måste kärnan konfigureras med tangenten CONFIG_SECCOMP=y [2] .
För att gå in i detta läge måste du ringa ett samtal prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT)eller på motsvarande sätt seccomp(SECCOMP_SET_MODE_STRICT, 0, NULL). Nu kan en process bara använda fyra systemanrop: read(), write(), _exit()och sigreturn()[3] . Andra systemanrop kommer att resultera i att processen avslutas med en SIGKILL-signal. Eftersom systemanropet open()är inaktiverat om seccomp ska kontrolleras måste statusfilen från procfs öppnas med läsbehörigheter innan seccomp aktiveras i processen [4] .
Ett driftläge introducerat i Linux-kärnan version 3.5 [8] . Tillgänglig om CONFIG_SECCOMP_FILTER=y-flaggan sattes när kärnan byggdes.
Innan du går in i detta läge måste ett anrop göras prctl(PR_SET_NO_NEW_PRIVS, 1)och därför måste no_new_privs-biten ställas in för processen. Anledningen till detta krav är att annars skulle en oprivilegierad process kunna köra ett privilegierat program med execve(). Om detta inte görs kommer övergången till SECCOMP_MODE_FILTER-läget att misslyckas [4] .
Efter att ha ställt in no_new_privs-biten, för att koppla filtret till processen, måste du anropa prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, args)eller seccomp(SECCOMP_SET_MODE_FILTER, 0, args), där args är en pekare till strukturen sock_fprog, som består av en array av BPF-instruktioner och dess längd. Filtret körs varje gång processen gör ett systemanrop. När det startas får filtret som indata en struktur med data om systemets anropsnummer, arkitektur, aktuellt tillstånd för programräknaren och anropsargument [7] [8] . Filtret måste returnera ett 32-bitars värde, där de övre 16 bitarna innehåller koden för åtgärden som ska utföras, och de lägre 16 bitarna innehåller data. Om filteralgoritmen inte ger ett returvärde av misstag, kommer den inte att klara statisk analys och ett sådant filter kommer inte att bifogas [9] .
Om flera filter är kopplade till en process kommer de att länkas var för sig och köras i omvänd ordning som de lades till, även om ett av filtren skulle döda processen [7] . I ett sådant fall kommer returvärdet för systemanropet att bestämmas av det första (i den ordning som filtren körs) returvärdet med högst prioritet, enligt tabellen (i fallande prioritetsordning) [10] :
Handling | Resultat |
---|---|
SECCOMP_RET_KILL | Systemanrop misslyckas, processen kommer att dödas med signalen SIGSYS [4] |
SECCOMP_RET_TRAP | Systemanropet misslyckas, processen tar emot SIGSYS-signalen, signalhanteraren har tillgång till information om systemanropet som gav detta resultat |
SECCOMP_RET_ERRNO | Systemanropet exekveras inte, errnofiltrets returvärde finns i variabeln |
SECCOMP_RET_TRACE | Om ett ptrace()spårämne specificeras för en process med hjälp kommer det att meddelas om samtalet. Om det inte anges, exekveras inte systemanropet. |
SECCOMP_RET_ALLOW | Systemsamtal pågår |
Aktiverar SECCOMP_MODE_STRICT [4]
# include <stdio.h> # include <unistd.h> # include <linux/secomp.h> # include <sys/prctl.h> # include <fcntl.h> int main () { int fd ; prctl ( PR_SET_SECCOMP , SECCOMP_MODE_STRICT ); fprintf ( stderr , "försök öppna \n " ); fd = öppen ( "test_fil" , O_CREAT ); fprintf ( stderr , "fd = %d" , fd ); returnera 0 ; }Resultat av arbetet:
$ gcc test_seccomp.c -o test_seccomp $ ./test_secomp försök öppna DödadI exemplet ovan, efter samtalet, prctl()körs processen exakt till det ögonblick då den försöker ringa ett samtal till open().
Linux- projekt | |
---|---|
Allmän |
|
Spridning | |
Ansökningar |
|
Personligheter |
|
massmedia |
|
Listor |
|
Rörlighet | |
Övrig |