Seccomp

seccomp (zkráceně z anglického  secure computing mode ) je jedním z bezpečnostních mechanismů linuxového jádra , který poskytuje možnost omezit sadu dostupných systémových volání pro aplikace a také pomocí mechanismu BPF ( Berkeley Packet Filter ) provádět složité filtrování. hovorů a jejich argumentů. Poprvé se objevil ve verzi jádra 2.6.12 v roce 2005 [1] [2] .

Pro práci s nedůvěryhodnými nebo neověřenými, a tedy potenciálně nebezpečnými programy, je vhodné používat speciálně vyhrazená prostředí, ze kterých není možné poškodit výkon systému jako celku. V takových prostředích (sandboxy, kontejnery) je mnoho funkcí systému omezeno pro spouštění programů, jako je přístup k síti, I/O zařízení a interakce s operačním systémem. Mechanismus seccomp určuje sadu povolených systémových volání pro proces a blokuje ta, která nebyla dříve deklarována. V současnosti se používá v řadě prohlížečů , operačních systémech podobných Linuxu a některých virtualizačních systémech .

Historie

Mechanismus seccomp vyvinul Andrea Arcangeli ( Ital  Andrea Arcangeli ) jako součást komerčního projektu CPUShare, jehož hlavní myšlenkou bylo určit schopnosti a vyvinout řešení pro poskytování výpočetních zdrojů počítačům, zejména s OS Linux, pro provádění kódu třetí strany. Poprvé se objevil v linuxovém jádře v březnu 2005 (verze 2.6.12). V první verzi, aby seccomp povolil, musel proces zapsat "1" do souboru /proc/PID/seccomp. Poté byla pro kód hosta dostupná pouze čtyři systémová volání: read(), write(), exit()a sigreturn()[3] . V roce 2007 byla ve verzi 2.6.23 přidána možnost povolit seccomp prostřednictvím systémového volání prctl()pomocí operace PR_SET_SECCOMP a rozhraní /proc bylo odstraněno [4] .

Navzdory tomu, že projekt CPUShare, pro který byl seccomp vyvinut, nebyl vyvinut a uzavřen, zůstal v linuxovém jádře [3] . V únoru 2009 byla objevena chyba zabezpečení v kódu seccomp. Bylo to způsobeno tím, že v 32bitových a 64bitových verzích Linuxu odpovídala různá systémová volání stejným číslům. Například povolené volání read()z 64bitové verze odpovídalo zakázanému volání restart_syscall()z 32bitové verze. Poté vyvstala otázka odstranění seccompu z Linuxu a Linus Torvalds navrhl, že seccomp nikdo nepoužívá [5] .

Vzhledem k tomu, že seccomp byl dostatečně jednoduchý na používání, vývojáři prohlížeče Google Chrome měli nápad implementovat nástroj pro spouštění pluginů třetích stran založených na něm . K dosažení tohoto cíle však pouhé zablokování všech povolených systémových volání kromě čtyř nestačilo. Výsledkem bylo, že v roce 2012 byl mechanismus BPF (Berkeley Packet Filter) integrován se seccomp (ve verzi 3.5 byl přidán druhý režim provozu - SECCOMP_MODE_FILTER), což výrazně rozšířilo možnosti mechanismu - po inovaci host proces mohl flexibilněji zvolit sadu povolených a zakázaných systémových volání připojením příslušného programu BPF. V roce 2012 se objevila i knihovna libseccomp, která poskytuje jednoduché a pohodlné API pro filtrování systémových volání [4] .

Pro zjednodušení použití seccomp přidala v roce 2013 verze 3.8 do /proc/PID/status pole "Seccomp", které umožňuje zjistit stav seccomp (po odstranění zahrnutí z /proc nebylo možné zjistit, zda již povolený seccomp běžel bez ukončení procesu). V roce 2014 byla ve verzi 3.17 přidáno speciální systémové volání - seccomp(), které částečně opakuje funkcionalitu prctl()[4] .

V listopadu 2017, s vydáním knihovny glibc verze 2.26, se objevil nový problém: protože v programech C se systémová volání neprovádějí přímo, ale prostřednictvím wrapperů standardní knihovny, jejíž názvy se nemusí shodovat s názvy systémových volání, zákaz volání může neočekávaně ovlivnit program. Například funkce open()ze standardní knihovny glibc verze 2.26 je implementována prostřednictvím systémového volání openat(), které není totéž jako volání open()a může být autorem filtru chybně zablokováno [6] .

Popis

K povolení seccomp ve vašem programu můžete použít systémové volání seccomp()nebo prctl(). V současnosti existují dva režimy provozu pro seccomp: SECCOMP_MODE_STRICT a SECCOMP_MODE_FILTER. Zda je seccomp povolen a v jakém režimu, zjistíte z pole "Seccomp" v souboru /proc/[pid]/status. Pole nabývá hodnot 0, 1 nebo 2: 0 — seccomp není pro proces povolen, 1 — seccomp v režimu SECCOMP_MODE_STRICT, 2 — v režimu SECCOMP_MODE_FILTER [4] . Nemůžete povolit seccomp pro jiné procesy [7] .

Režim SECCOMP_MODE_STRICT

Byl to jediný režim provozu před Linuxem 3.5. Chcete-li jej použít, musí být jádro nakonfigurováno pomocí klíče CONFIG_SECCOMP=y [2] .

Chcete-li vstoupit do tohoto režimu, musíte uskutečnit hovor prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT)nebo ekvivalentně seccomp(SECCOMP_SET_MODE_STRICT, 0, NULL). Nyní může proces používat pouze čtyři systémová volání: read(), write(), _exit()a sigreturn()[3] . Ostatní systémová volání povedou k ukončení procesu signálem SIGKILL. Protože je systémové volání open()zakázáno, pokud se má zkontrolovat seccomp, musí být stavový soubor z procfs otevřen s oprávněním pro čtení, než se v procesu povolí seccomp [4] .

Režim SECCOMP_MODE_FILTER

Provozní režim představený v jádře Linuxu verze 3.5 [8] . Dostupné, pokud byl při sestavování jádra nastaven příznak CONFIG_SECCOMP_FILTER=y.

Před vstupem do tohoto režimu musí být provedeno volání prctl(PR_SET_NO_NEW_PRIVS, 1)a tedy musí být pro proces nastaven bit no_new_privs. Důvodem tohoto požadavku je, že jinak by neprivilegovaný proces mohl spustit privilegovaný program s execve(). Pokud tak neučiníte, přechod do režimu SECCOMP_MODE_FILTER se nezdaří [4] .

Po nastavení bitu no_new_privs, abyste mohli připojit filtr k procesu, musíte zavolat prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, args)nebo seccomp(SECCOMP_SET_MODE_FILTER, 0, args), kde args je ukazatel na strukturu sock_fprog, která se skládá z pole instrukcí BPF a její délky. Filtr se spustí pokaždé, když proces provede systémové volání. Po spuštění filtr obdrží jako vstup strukturu s údaji o systémovém volacím čísle, architektuře, aktuálním stavu programového čítače a argumentech volání [7] [8] . Filtr musí vrátit 32bitovou hodnotu, ve které horních 16 bitů obsahuje kód akce, která má být provedena, a spodních 16 bitů obsahuje data. Pokud algoritmus filtru omylem neposkytne návratovou hodnotu, neprojde statickou analýzou a takový filtr nebude připojen [9] .

Pokud je k procesu připojeno více filtrů, budou jednotlivě propojeny a spuštěny v opačném pořadí, v jakém byly přidány, i když by jeden z filtrů měl proces ukončit [7] . V takovém případě bude návratová hodnota systémového volání určena první (v pořadí, v jakém jsou spuštěny filtry) návratovou hodnotou s nejvyšší prioritou, podle tabulky (v sestupném pořadí priority) [10] :

Akce Výsledek
SECCOMP_RET_KILL Systémové volání se nezdaří, proces bude ukončen signálem SIGSYS [4]
SECCOMP_RET_TRAP Systémové volání se nezdaří, proces přijímá signál SIGSYS, obsluha signálu má přístup k informacím o systémovém volání, které vytvořilo tento výsledek
SECCOMP_RET_ERRNO Systémové volání se neprovede, errnonávratová hodnota filtru je v proměnné
SECCOMP_RET_TRACE Pokud ptrace()je pro proces s nápovědou určen sledovač, bude upozorněn na volání. Pokud není zadáno, systémové volání se neprovede.
SECCOMP_RET_ALLOW Probíhá systémové volání

Příklady použití

Povolení SECCOMP_MODE_STRICT [4]

# include <stdio.h> # include <unistd.h> # include <linux/seccomp.h> # include <sys/prctl.h> # include <fcntl.h> int main () { int fd ; prctl ( PR_SET_SECCOMP , SECCOMP_MODE_STRICT ); fprintf ( stderr , "zkuste otevřít \n " ); fd = otevřít ( "test_file" , O_CREAT ); fprintf ( stderr , "fd = %d" , fd ); návrat 0 ; }

Výsledek práce:

$ gcc test_seccomp.c -o test_seccomp $ ./test_seccomp zkuste otevřít Zabitý

Ve výše uvedeném příkladu po volání prctl()proces běží přesně do okamžiku, kdy se pokusí zavolat na open().

Příklady použití v softwaru

Poznámky

  1. 1 2 3 Imamjafar Borate, Chavan RK, 2016 .
  2. 12 Kroah -Hartman, 2007 .
  3. 1 2 3 Kurt Dietrich, Johannes Winter, 2011 .
  4. 1 2 3 4 5 6 7 8 Jake Edge, Michael Kerrisk, 2015 .
  5. Jonathan Corbet. Seccomp a sandboxing  // LWN.net. - 2009. - 13. května. Archivováno z originálu 12. listopadu 2017.
  6. Jonathan Corbet. Inherentní křehkost seccomp()  // LWN.net. - 2017. - 1. listopadu. Archivováno z originálu 9. prosince 2017.
  7. 1 2 3 Lingguang Lei, Jianhua Sun, Kun Sun, Chris Shenefiel, Rui Ma, Yuewu Wang, Qi Li, 2017 .
  8. 1 2 Taesoo Kim, Nickolai Zeldovich, 2013 .
  9. Steven McCanne, Van Jacobson, 1993 .
  10. SECure COMPuting s filtry . Archivy jádra Linuxu . Organizace Linuxového jádra. Získáno 3. března 2018. Archivováno z originálu 13. října 2017.
  11. Anto.Y, 2012 .
  12. Adrian Mouat, 2015 .
  13. Senthil Kumaran S., 2017 .

Literatura

Odkazy