Product SiteDocumentation Site

14.5. Introduksjon til SELinux

14.5.1. Prinsipper

SELinux (Security Enhanced Linux) er et Mandatory Access Control-system som bygger på Linux sin LSM (Linux Security Modules)-grensesnitt. I praksis spør kjernen SELinux før hver systempåkalling for å vite om prosessen er autorisert til å gjøre den gitte operasjonen.
SELinux bruker et sett med regler - kollektivt kjent som en policy - for å godkjenne eller forby operasjoner. Disse reglene er vanskelige å lage. Heldigvis er to standardregler (targeted (målrettet) og strict (strengt)) laget for å unngå mesteparten av oppsettsarbeidet.
Med SELinux er håndteringen av rettighetene helt forskjellig fra tradisjonelle Unix-systemer. Rettighetene til en prosess er avhengig av sin sikkerhetskontekst . Denne konteksten er definert av identitet til brukeren som startet prosessen, rolle og domene som brukeren hadde med seg på det tidspunktet. Rettighetene er egentlig avhengig av domenet, men overgangene mellom domenene er kontrollert av rollene. Til slutt; de mulige overgangene mellom roller avhenger av identiteten.
Sikkerhetskontekster og Unix-brukere

Figur 14.3. Sikkerhetskontekster og Unix-brukere

I praksis får brukeren, under innlogging, tildelt en standard sikkerhetskontekst (avhengig av hvilke roller de skal være i stand til å støtte). Dette definerer det gjeldende domenet, og dermed domenet som alle nye avleggerprosesser vil ha. Hvis du ønsker å endre nåværende rolle og tilhørende domene, må du påkalle newrole -r rolle_r -t domene_t (det er vanligvis bare ett enkelt domene som er tillatt for en gitt rolle, -t-parameteren kan derfor utelates). Denne kommandoen godkjenner du ved å be deg skrive inn passordet ditt. Denne funksjonen forbyr programmer å automatisk bytte roller. Slike endringer kan bare skje dersom de er uttrykkelig tillatt i SELinux-politikk.
Selvsagt gjelder ikke rettighetene for alle objekter (filer, kataloger, stikkontakter, enheter, etc.). De kan variere fra objekt til objekt. For å oppnå dette blir hvert objekt assosiert med en type (dette kalles merking). Domenene sine rettigheter er dermed uttrykt med sett av (ikke-)tillatte operasjoner for disse typene (og, indirekte, for alle objekter som er merket med den gitte typen).
Som standard arver et program sitt domene fra brukeren som startet det, men standard SELinux-politikk forventer at mange viktige programmer kjører i øremerkede domener. For å oppnå dette er disse kjørbare filer merket med en øremerket type (for eksempel er ssh_t merket med ssh_exec_t, og når et program starter, skifter det automatisk til ssh_t-domenet). Denne automatiske domene-overgangsmekanismen gjør det mulig å gi bare de rettigheter som kreves av hvert program. Dette er et grunnleggende prinsipp for SELinux.
Automatiske overganger mellom domener

Figur 14.4. Automatiske overganger mellom domener

14.5.2. Oppsett av SELinux

SELinux-støtte er innebygd i standardkjernene som følger med Debian. Kjernen i Unix-verktøyet støtter SELinux uten noen modifikasjoner. Det er dermed relativt enkelt å aktivere SELinux.
Kommandoen apt install selinux-basics selinux-policy-default vil automatisk installere de nødvendige pakkene til å sette opp et SELinux-system.
Pakken selinux-policy-default inneholder et sett med vanlige regler. Som standard begrenser disse reglene kun tilgang til noen allment synlige tjenester. Brukersesjoner er ikke begrenset, og det er derfor usannsynlig at SELinux ville blokkere legitime brukeroperasjoner. Men dette forbedrer sikkerheten i systemtjenester som kjører på maskinen. For å sette opp et opplegg som tilsvarer de gamle «strenge» reglene, er det bare å deaktivere unconfined-modulen (modulhåndtering er beskrevet nærmere i denne seksjonen).
Når opplegget er installert, bør du merke alle tilgjengelige filer (som betyr å tildele dem en type). Denne operasjonen må startes manuelt med fixfiles relabel.
SELinux-systemet er nå klart. For å aktivere det bør du legge selinux=1 security=selinux-parameteret til Linux-kjernen. Parameteret audit=1 aktiverer SELinux-logging med registrering av alle de nektede operasjonene. Endelig tar enforcing=1-parameteret reglene i bruk: Uten det virker SELinux i sin standard permissive/givende-modus der avviste handlinger logges, men fremdeles blir utført. Du bør derfor endre GRUBs oppsettsfil for oppstart ved å legge til de ønskede parametere. En enkel måte å gjøre dette på er å modifisere GRUB_CMDLINE_LINUX-variabelen i /etc/default/grub, og å kjøre update-grub. SELinux vil være aktivert etter en omstart.
Det er verdt å merke seg at selinux-activate-skriptet automatiserer disse operasjonene, og tvinger en merking ved neste oppstart (som unngår nye ikke-merkede filer som er opprettet mens SELinux ennå ikke var aktiv, og mens merking skjer).

14.5.3. Å håndtere SELinux-system

SELinux-opplegget er et modulbasert sett med regler, og installasjonen oppdager og aktiverer automatisk alle relevante moduler basert på den allerede installerte tjenesten. Systemet er dermed umiddelbart i drift. Men når en tjeneste er installert etter SELinux-opplegget, må du klare å aktivere den tilsvarende modulen manuelt. Det er hensikten med semodule-kommandoen. Videre kan du klare å definere rollene som hver bruker kan slutte seg til, og dette kan gjøres med semanage-kommandoen.
De to kommandoer kan dermed brukes til å endre den gjeldende SELinux-oppsettet, lagret i /etc/selinux/default/. I motsetning til andre oppsettfiler du finner i /etc/, skal ikke alle disse filene endres for hånd. Du bør bruke programmer som er laget til dette formålet.

14.5.3.1. Å håndtere SELinux-moduler

Tilgjengelige SELinux-moduler er lagret i /usr/share/selinux/default/-mappen. For å aktivere en av disse modulene i det gjeldende oppsettet bør du bruke semodule -i modul.pp.bz2. Forlengelsen pp.bz2 står for policy package (pakke) (komprimert med bzip2).
Å fjerne en modul fra det gjeldende oppsettet gjøres med semodule -r modul. Til slutt, lister semodule -l-kommandoen modulene som er installert. De gir også sine versjonsnumre. Moduler kan selektivt aktiveres med semodule -e, og slås av med semodule -d.
# semodule -i /usr/share/selinux/default/abrt.pp.bz2
# semodule -l
abrt    1.5.0   Disabled
accountsd       1.1.0   
acct    1.6.0   
[...]
# semodule -e abrt
# semodule -d accountsd
# semodule -l
abrt    1.5.0
accountsd       1.1.0   Disabled
acct    1.6.0   
[...]
# semodule -r abrt
# semodule -l
accountsd       1.1.0   Disabled
acct    1.6.0   
[...]
semodule laster umiddelbart det nye oppsettet om ikke du bruker dens -n-valg. Det er verdt å merke seg at programmet er standard på det gjeldende oppsettet (som er angitt av SELINUXTYPE-variabelen i /etc/selinux/config), men at du kan endre en annen ved å spesifisere den med -s-valget.

14.5.3.2. Å håndtere identiteter

Hver gang en bruker logger inn, får de tildelt en SELinux-identitet. Denne identiteten definerer rollene de kan støtte. Disse to adressingene (fra brukeren til identiteten, og fra denne identiteten til roller) kan settes opp med semanage-kommandoen.
Du bør absolutt lese manualsiden semanage(8), selv om kommando-syntaksen tenderer til å være lik for alle begrepene som håndteres. Du vil finne vanlige valg til alle underkommandoer:-a for å legge til, -d for å trekke fra (slette), -m for å modifisere, -l til å liste, og -t for å indikere en type (eller et domene).
semanage login -l lister gjeldende adressering mellom brukeridentifikatorer og SELinux-identiteter. Brukere som ikke har noen eksplisitt inngang, får identiteten angitt i __default__-inngangen. semanage login -a -s user_u bruker-kommandoen vil knytte user_u-identiteten til den gitte brukeren. Tilslutt, semanage login -d bruker dropper asdresseringsinngangen knyttet til denne brukeren.
# semanage login -a -s user_u rhertzog
# semanage login -l

Login Name           SELinux User         MLS/MCS Range        Service

__default__          unconfined_u         SystemLow-SystemHigh *
rhertzog             user_u               SystemLow            *
root                 unconfined_u         SystemLow-SystemHigh *
system_u             system_u             SystemLow-SystemHigh *
# semanage login -d rhertzog
semanage user -l viser adresseringen mellom SELinux-brukeridentiteter og tillatte roller. Å legge til en ny identitet krever å definere både de tilsvarende rollene og en merkingsforstavelse som brukes til å tilordne en type til personlige filer (/home/bruker/*). Forstavelsen må velges mellom user, staff, og sysadm. «staff»-forstavelsen resulterer i filer av typen «staff_home_dir_t». Å lage en ny SELinux-brukeridentitet gjøres med semanage user -a -R roller -P prefiks identitet. Til slutt; du kan fjerne en SELinux-brukeridentitet med semanage user -d identitet.
# semanage user -a -R 'staff_r user_r' -P staff test_u
# semanage user -l

                Labeling   MLS/       MLS/                          
SELinux User    Prefix     MCS Level  MCS Range             SELinux Roles

root            sysadm     SystemLow  SystemLow-SystemHigh  staff_r sysadm_r system_r
staff_u         staff      SystemLow  SystemLow-SystemHigh  staff_r sysadm_r
sysadm_u        sysadm     SystemLow  SystemLow-SystemHigh  sysadm_r
system_u        user       SystemLow  SystemLow-SystemHigh  system_r
test_u          staff      SystemLow  SystemLow             staff_r user_r
unconfined_u    unconfined SystemLow  SystemLow-SystemHigh  system_r unconfined_r
user_u          user       SystemLow  SystemLow             user_r
# semanage user -d test_u

14.5.3.3. Å håndtere filkontekster, porter og boolske verdier

Hver SELinux-modul har et sett av filmerkingsregler, men det er også mulig å legge til egendefinerte regler for merking for å ta hensyn til et bestemt tilfelle. For eksempel, hvis du vil at nett-tjeneren, for å kunne lese filene i /srv/www/-filhierarkiet, kan du kjøre semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?" fulgt av restorecon -R /srv/www/. Førstnevnte kommando registrerer nye regler for merking, og sistnevnte tilbakestiller filtypene etter gjeldende regler for merking.
Tilsvarende er TCP/UDP-portene merket på en måte som sikrer at bare de tilsvarende bakgrunnsprosessene kan lytte til dem. For eksempel, hvis du vil at nett-tjeneren skal kunne lytte på port 8080, bør du kjøre semanage port -m -t http_port_t -p tcp 8080.
Noen SELinux-moduler eksporterer boolske valg som du kan justere for å endre gjøremålene til standardreglene. getsebool-verktøyet kan brukes til å inspisere disse valgene (getsebool boolsk viser ett valg, og getsebool -a alle). setsebool boolsk verdt-kommandoen endrer den gjeldende verdien av et boolsk alternativ. -P-valget gjør endringen permanent. Det betyr at den nye verdien blir standard, og blir beholdt etter restart. Eksempelet nedenfor gir nett-tjenere tilgang til hjemmeområder (dette er nyttig når brukerne har personlige nettsteder i ~/public_html/).
# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> off
# setsebool -P httpd_enable_homedirs on
# getsebool httpd_enable_homedirs 
httpd_enable_homedirs --> on

14.5.4. Å tilpasse reglene

Siden SELinux-opplegget er modulbasert, kan det være interessant å utvikle nye moduler for (muligens tilpassede) programmer som mangler dem. Disse nye modulene vil da komplettere referanseregler.
For å lage nye moduler kreves selinux-policy-dev-pakken så vel som selinux-policy-doc. Den siste inneholder dokumentasjonen om standardreglene (/usr/share/doc/selinux-policy-doc/html/) og eksempelfiler som kan brukes som maler for å lage nye moduler. Installer disse filene, og studer dem nærmere:
$ cp /usr/share/doc/selinux-policy-doc/Makefile.example Makefile
$ cp /usr/share/doc/selinux-policy-doc/example.fc ./
$ cp /usr/share/doc/selinux-policy-doc/example.if ./
$ cp /usr/share/doc/selinux-policy-doc/example.te ./
Filen .te er den viktigste. Den definerer reglene. Filen .fc definerer «filkonteksten»; det er typene som er tilordnet filer knyttet til denne modulen. Dataene innenfor .fc-filen brukes under filmerkingstrinnet. Endelig definerer .if-filen modulens grensesnitt. Det er et sett med «offentlige funksjoner» som andre moduler kan bruke til en riktig samhandling med modulen du oppretter.

14.5.4.1. Å skrive en .fc-fil

Å lese eksemplet nedenfor bør være tilstrekkelig til å forstå strukturen i en slik fil. Du kan bruke vanlige uttrykk for å tilordne den samme sikkerhetskonteksten til flere filer, eller til og med til et helt katalogtre.

Eksempel 14.2. eksempel.fc-file

# myapp executable will have:
# label: system_u:object_r:myapp_exec_t
# MLS sensitivity: s0
# MCS categories: <none>

/usr/sbin/myapp         --      gen_context(system_u:object_r:myapp_exec_t,s0)

14.5.4.2. Å skrive en .if-fil

I eksemplet nedenfor kontrollerer det første grensesnittet (“myapp_domtrans”) hvem som kan kjøre programmet. Det andre («myapp_read_log») gir leserettigheter til programmets loggfiler.
Hvert grensesnitt må generere et gyldig sett med regler som kan legges inn i en .te-fil. Du bør derfor formidle alle typene du bruker (med gen_require-makro), og bruke standard direktiver for å gi rettigheter. Vær imidlertid oppmerksom på at du kan bruke grensesnitt som tilbys av andre moduler. Den neste seksjonen vil gi flere forklaringer om hvordan disse rettighetene skal uttrykkes.

Eksempel 14.3. eksempel.if-fil

## <summary>Myapp example policy</summary>
## <desc>
##      <p>
##              More descriptive text about myapp.  The <desc>
##              tag can also use <p>, <ul>, and <ol>
##              html tags for formatting.
##      </p>
##      <p>
##              This policy supports the following myapp features:
##              <ul>
##              <li>Feature A</li>
##              <li>Feature B</li>
##              <li>Feature C</li>
##              </ul>
##      </p>
## </desc>
#

########################################
## <summary>
##      Execute a domain transition to run myapp.
## </summary>
## <param name="domain">
##      Domain allowed to transition.
## </param>
#
interface(`myapp_domtrans',`
        gen_require(`
                type myapp_t, myapp_exec_t;
        ')

        domtrans_pattern($1,myapp_exec_t,myapp_t)
')

########################################
## <summary>
##      Read myapp log files.
## </summary>
## <param name="domain">
##      Domain allowed to read the log files.
## </param>
#
interface(`myapp_read_log',`
        gen_require(`
                type myapp_log_t;
        ')

        logging_search_logs($1)
        allow $1 myapp_log_t:file r_file_perms;
')

14.5.4.3. Å skrive en .te-fil

Se på eksempel.te-filen:
policy_module(myapp,1.0.0) 1

########################################
#
# Declarations
#

type myapp_t; 2
type myapp_exec_t;
domain_type(myapp_t)
domain_entry_file(myapp_t, myappLikewise, some rights are in fact sets of rights which are replaced by their values at compilation time._exec_t) 3

type myapp_log_t;
logging_log_file(myapp_log_t) 4

type myapp_tmp_t;
files_tmp_file(myapp_tmp_t)

########################################
#
# Myapp local policy
#

allow myapp_t myapp_log_t:file { read_file_perms append_file_perms }; 5

allow myapp_t myapp_tmp_t:file manage_file_perms;
files_tmp_filetrans(myapp_t,myapp_tmp_t,file)

1

Modulen må identifiseres med navn og versjonsnummer. Dette direktivet er nødvendig.

2

Hvis modulen introduserer nye typer, må den si ifra om dem med direktiver som dette. Ikke nøl med å lage så mange typer som kreves i stedet for å gi for mange ubrukelige rettigheter.

3

Disse grensesnittene definerer myapp_t-typen som et prosessdomene som skal brukes av alle kjørbare merket med myapp_exec_t. Implisitt legger de til en exec_type-attributt til disse objektene, som igjen tillater andre moduler å tildele rettigheter til å kjøre disse programmene, for eksempel tillater userdomain-modulen prosesser med domene user_t, staff_t, og sysadm_t til å kjøre dem. Domenene til andre avstengte programmer vil ikke ha rettigheter til å kjøre dem, med mindre reglene gir dem lignende rettigheter (dette er tilfelle, for eksempel, med dpkg med sitt dpkg_t-domene).

4

logging_log_file er et grensesnitt som tilbys av referanseopplegget. Det indikerer at filene som er merket med den gitte typen er loggfiler¸ som burde dra nytte av de tilhørende reglene (for eksempel å gi rettigheter til logrotate slik at den kan håndtere dem).

5

Direktivet allow er basen direktivet bruker til å godkjenne en operasjon. Den første parameteren er prosessdomenet som har lov til å utføre operasjonen. Det andre definerer objektet som en prosess som det tidligere domenet kan håndtere. Denne parameteren har formen «type:klasse» der type er dens SELinux-type, og klasse beskriver hva slags objekt (fil, mappe, socket, fifo, etc.). Til slutt beskriver den siste parameteren tillatelsene (de tillatte operasjonene).
Tillatelser er definert som et sett av tillatte operasjoner, og følger denne malen: { operasjon1 operasjon2 }. Men du kan også bruke makroer som representerer de nyttigste tillatelsene./usr/share/selinux/devel/include/support/obj_perm_sets.spt lister/viser dem.
Følgende nettside gir en relativt uttømmende liste over objektklasser og tillatelser som kan gis.
Nå er det bare å finne det minimale settet med regler som kreves for å sikre at målprogrammet eller tjenesten fungerer som det skal. For å oppnå dette bør du ha god kunnskap om hvordan programmet fungerer, og hva slags data det styrer og/eller genererer.
Imidlertid er en empirisk tilnærming mulig. Etter at de relevante objektene er korrekt merket, kan du bruke programmet i tillatelsesmodus: Operasjonene som vil bli forbudt blir logget, men vil likevel lykkes. Ved å analysere loggene kan du nå identifisere operasjoner som skal tillates. Her er et eksempel på en slik loggoppføring :
avc:  denied  { read write } for  pid=1876 comm="syslogd" name="xconsole" dev=tmpfs ino=5510 scontext=system_u:system_r:syslogd_t:s0 tcontext=system_u:object_r:device_t:s0 tclass=fifo_file permissive=1
For bedre å forstå dette budskapet, la oss studere det bit for bit.

Tabell 14.1. Analyse av et SELinux-spor

BudskapBeskrivelse
avc: deniedEn operasjon er nektet.
{ read write }Denne operasjonen krevde read og write-tillatelsene.
pid=1876Prosessen med PID 1876 kjørte operasjonen (eller forsøkt å utføre den).
comm="syslogd"Prosessen var et tilfelle med syslogd-programmet.
name="xconsole"Målobjektet ble navngitt xconsole. Noen ganger kan du også ha en «sti»-variabel - med hele banen - i stedet.
dev=tmpfsEnheten som er vert for målobjektet er et tmpfs (et i-minne filsystem). Med en ekte disk kan du se at partisjonen er vert for objektet (for eksempel: «sda3»).
ino=5510Objektet er identifisert med inode-nummer 5510.
scontext=system_u:system_r:syslogd_t:s0Dette er sikkerhetskonteksten for prosessen som utførte operasjonen.
tcontext=system_u:object_r:device_t:s0Dette er sikkerhetskontektsen til målobjektet.
tclass=fifo_fileMålobjektet er en FIFO-fil.
Ved å observere dette i loggen er det mulig å bygge en regel som ville tillate denne operasjonen. For eksempel: allow syslogd_t device_t:fifo_file { read write }. Denne prosessen kan automatiseres, og det er akkurat hva audit2allow-kommandoen (i policycoreutils-pakken) tilbyr. Denne tilnærmingen er bare nyttig hvis de ulike objektene allerede er korrekt merket med det som måtte være begrenset. I alle fall må du lese nøye gjennom de genererte reglene, og validere dem i henhold til dine kunnskaper om programmet. Faktisk tenderer denne tilnærmingen til å gi flere rettigheter enn det som virkelig er nødvendig. Den riktige løsningen er ofte å lage nye typer, og for å tildele rettigheter bare til disse typene. Det hender også at en nektet operasjon er fatalt for programmet, og da kan det være bedre å bare legge til «dontaudit» en regel for å unngå loggoppføringen til tross for en effektiv nektelse.

14.5.4.4. Å kompilere filene

Så snart de 3 filene (eksempel.if, eksempel.fc, og eksempel.te) svarer til dine forventninger for de nye reglene, er det bare å kjøre make NAME=devel for å generere en modul i eksempel.pp-filen (du kan umiddelbart laste den med semodule -i example.pp). Hvis flere moduler er definert vil make lage alle de korresponderende .pp-filene.