Kdykoliv jsem v poslední době mluvil o SELinuxu, nechal jsem všechny lidi vstát a říct „SELinux je ‚štítkovací‘ systém“. Každý proces má štítek, každý objekt v systému má štítek. Soubory, adresáře, síťové porty… Politika SELinuxu určuje, jak štítky procesů pracují s dalšími štítky v systému. Jádro dohlíží na dodržování pravidel dané politiky.

Poznámka: Původně vyšlo jako Audit2allow should be your third option not the first v blogu Dana Walshe.

Z toho vyplývá, že pokud se setkáte s odmítnutím, tak první věc, která by vás měla napadnout, je, že je některý ze štítků CHYBNÝ. Nedávno jsem napsal článek, který jsem nazval Čtyři věci SELinuxu. Vyjmenovávám tam čtyři důvody odmítnutí spojených s SELinuxem:

  1. Máte problém se štítky.
  2. Změnili jste nastavení procesu a zapomněli o tom SELinuxu říct.
  3. Máte chybu buď v aplikaci, nebo v politice SELinuxu. Buď politika SELinuxu nevěděla, že aplikace něco smí dělat, nebo je aplikace vadná.
  4. Někdo vás hacknul.

Řešení č. 3 je náhlasit bug a použít audit2allow pro vygenerování lokálního modulu s politikou, který nainstalujete, dokud nebude opravená aplikace nebo se do politiky SELinuxu nedoplní pravidla, která činnost povolí.

Potíž je v tom, že administrátoři po této možnosti často sahají, kdykoliv nějaké odmítnutí spatří. Podívejme se jeden nedávný příklad, který mi přistál v poště.

Ve zprávě do [email protected] Richard hlásil: „Mám CGI aplikaci pojmenovanou ‚mapserv‘, která potřebuje zapisovat na specifické místo: /rwg/mapserver/tmp“. Přišel na to, že obsah, který jde přes Apache, je obyčejně oštítkován jako httpd_sys_content_t, což byl krok správným směrem. Předpokládám tedy, že dal tomuto adresářovému stromu štítek httpd_sys_content_t.

Pak se ptal na sepsání politiky, která vypadala takto:

module test 1.0;

require {
        type httpd_sys_content_t;
        type httpd_sys_script_t;
        class dir add_name;
        class file { write create };
}

#============= httpd_sys_script_t ==============
allow httpd_sys_script_t httpd_sys_content_t:dir add_name;
allow httpd_sys_script_t httpd_sys_content_t:file { write create };

To samozřejmě pochází z audit2allow a fungovalo by to, až na pár problémů, z nichž největší je ten, že by pak všechny CGI skripty mohly číst a zapisovat všechen Apache obsah. Navíc ta politika není moc robustní, protože můžete dostat AVC jako „httpd_sys_script_t is not allowed to append to httpd_sys_content_t“. Lepší by bylo:

manage_files_pattern(httpd_sys_script_t, httpd_sys_content_t, httpd_sys_content_t)

Mohl jsem použít lepší štítek?

Hlavní pointou tohoto zápisku je však to, že Richard neměl vůbec používat audit2allow. Mohl použít httpd_sys_rw_content_t pro ten adresář tmp.

# semanage fcontext -a -t httpd_sys_rw_content_t "/rwg/mapserver/tmp(/.*?)"
# restorecon -R -v /rwg/mapserver/tmp

To by odpovídalo možnosti č. 1 výše – chybný jeden štítek.

Mohl jsem změnit štítek procesu?

Dominic Grift v reakci navrhl další možné řešení:

cat > mywebapp.te << EOF
policy_module(mywebappp, 1.0.0)
apache_content_template(mywebapp)
EOF

make -f /usr/share/selinux/devel/Makefile mywebapp.pp
sudo semodule -i mywebapp

Teď můžeš použít následující nové typy:

httpd_mywebapp_script_t (mywebapp process type)
httpd_mywebapp_script_exec_t (mywebapp cgi executable file type)
httpd_mywebapp_content_t (mywebapp readonly file type)
httpd_mywebapp_content_rw_t (mywebapp read/write file type)
httpd_mywebapp_content_ra_t (mywebapp read/append file type)
httpd_mywebapp_htaccess_t (mywebapp htaccess file types)

Jednoduše můžeš dát cgi skriptu štítek podle typu
spustitelného souboru skriptu mywebapp a proces
mywebapp pak bude vytvářet soubory podle typu mywebapp.

Toto řešení odpovídá možnosti č. 1, protože mění jak štítek procesu, tak cíle. Je to patrně nejlepší způsob, protože pokud by na svém stroji Richard použil další CGI skripty, pouze skript mapserver by mohl zapisovat mapserver cgi obsah a pravidla by byla lépe oddělená.

Poznámka: pro vygenerování politiky bych použil sepolicy generate --cgi PATHTO/mapserver.cgi.

Mohl bych upravit nastavení SELinuxu, aby tento přístup povolovalo?

Třetí možnost by bylo zapnout booleovskou volbu httpd_unified (šlo by o řešení podle možnosti č. 2, i když ne nejlepší řešení situace).

httpd_unified je popsaná jako „Unify HTTPD handling of all content files.“ (Sjednotit, jak HTTPD zachází se všemi obsahovými soubory).

# setsebool -P httpd_unified 1

To znamená, že se procesu Apache a výchozím Apache skriptům povolí část/zapisovat/spouštět všechen Apache obsah z výchozími štítky.

Podtrženo, sečteno, když se objeví SELinux AVC, měli byste se rozhodovat asi takto:

  1. Běží proces, který je odmítán, se správným štítkem? Mohl by běžet s lepším štítkem?
  2. Má cílový objekt správný štítek nebo bylo by možné mu přiřadit štítek, který by umožnil přístup se štítkem procesu?
  3. Neexistuje SELinuxová booleovská volba, která by umožnila přístup?
  4. Pokud jde o odmítnutí síťového portu, upravil jsem výchozí nastavení a mohl bych upravit štítky síťových paketů pomocí semanage port?
  5. Myslím si, že jde o chybu v aplikaci? Pokud ano, neměl bych ji nahlásit?
  6. Jde o chybu v politice SELinuxu a přístup by měl být ve výchozím nastavení povolený? V tom případě bych měl nainstalovat lokální modifikaci a nahlásit to jako chybu.
  7. Někdo mě hacknul?

setroubleshoot se bude snažit vás tímto postupem provést. Novější verze audit2allow vám ukáží booleovské volby a možné štítky, které lze použít.