martedì, settembre 18, 2007

SELinux - personalizzare una policy - Centos 5 - RHEL - Freshclam - caso concreto

- post<li> - Permalink


SELinux è sempre stato la mia croce / delizia.

SELinux è un argomento complesso, ma in poche parole è un sistema che permette in ambienti Linux un maggior controllo su quello che un programma / utente può o non può fare aumentando sensibilmente il livello di sicurezza raggiungibile su un server.

Tra le idee di base vi è quella del contesto, ovvero è permessa o non permessa una operazione in base alla situazione in cui questa viene eseguita. Esempio è perfettamente lecito girare in costume da bagno nel contesto "spiaggia", mentre non lo è mentre si gira nel contesto"tribunale" :D.

Per ulteriori approfondimenti in appendice diversi riferimenti a SELinux

Problema:
Nell'articolo "CentOS5 + QmailToaster Mailserver Setup - simple howto", se non si disabilitasse SELinux, l'installazione di QmailToaster non andrebbe a buon fine perchè durante l'installazione del pacchetto clamav-toaster-0.xx.x viene avviato il servizio freshclam che permette l'aggiornamento dell'antivirus stesso. Il servizio all'avvio semplicemente si blocca senza generare nessun errore. Il demone stesso clamd ha problemi nella lettura del db virus.

Soluzione 1:
Disabilitare SELinux - Questa è l'idea proposta da chiunque, forum, how-to. Qui per esempio l'how-to ufficiale per l'installazione di QmailToaster su CentoOS 4.3 :
Firewall Configuration:

Select "No firewall"

Select "Disabled" mode for SELinux

Per me questa è una NON-soluzione.

Perchè è come lasciare la macchina chiusa a chiave ma con i finestrini appena socchiusi. Abbiamo lasciato la macchina aperta alla mercè dei ladri? Sicuramente no, però abbiamo lasciato loro una via d'entrata in più.

Per esperienza personale SELinux mi ha, per usare un termine tecnico, parato il XXXX più di una volta. Specialmente in presenza degli immancabili bachi di cui i software, per definizione, sono portatori.

Soluzione 2:
Per fortuna (e perseveranza) mia seguo SELinux dalla sua introduzione in Fedora Core 3 e posso dire che da allora la tecnologia è migliorata e di molto fornendo via via strumenti più potenti.
Uno di questi è un log che pochi conoscono audit.log. Il suo contenuto è finito dentro a /var/log/messages in Fedora Core 5, ma in CentOS 5 lo troviamo nel percorso originario /var/log/audit/audit.log.

Un esempio del contenuto di questo log è:


type=AVC msg=audit(1190013769.595:958064): avc: denied { write } for pid=11794 comm="clamd" name="clamav" dev=dm-0 ino=4030584 scontext=system_u:system_r:clamd_t:s0 tcontext=system_u:object_r:usr_t:s0 tclass=dir
type=SYSCALL msg=audit(1190013769.595:958064): arch=40000003 syscall=5 success=no exit=-13 a0=96a369c a1=242 a2=1fc a3=96a3698 items=0 ppid=2187 pid=11794 auid=4294967295 uid=46 gid=46 euid=46 suid=46 fsuid=46 egid=46 sgid=46 fsgid=46 tty=(none) comm="clamd" exe="/usr/sbin/clamd" subj=system_u:system_r:clamd_t:s0 key=(null)
type=AVC msg=audit(1190013769.596:958065): avc: denied { read } for pid=11794 comm="clamd" name="main.cvd" dev=dm-0 ino=4030636 scontext=system_u:system_r:clamd_t:s0 tcontext=system_u:object_r:usr_t:s0 tclass=file
type=SYSCALL msg=audit(1190013769.596:958065): arch=40000003 syscall=5 success=no exit=-13 a0=96a37a8 a1=0 a2=1b6 a3=969efc0 items=0 ppid=2187 pid=11794 auid=4294967295 uid=46 gid=46 euid=46 suid=46 fsuid=46 egid=46 sgid=46 fsgid=46 tty=(none) comm="clamd" exe="/usr/sbin/clamd" subj=system_u:system_r:clamd_t:s0 key=(null)
type=AVC msg=audit(1190013770.175:958066): avc: denied { read write } for pid=11808 comm="freshclam" name="0" dev=devpts ino=2 scontext=root:system_r:freshclam_t:s0 tcontext=root:object_r:devpts_t:s0 tclass=chr_file
type=AVC msg=audit(1190013770.175:958066): avc: denied { read write } for pid=11808 comm="freshclam" name="0" dev=devpts ino=2 scontext=root:system_r:freshclam_t:s0 tcontext=root:object_r:devpts_t:s0 tclass=chr_file
type=AVC msg=audit(1190013770.175:958066): avc: denied { read write } for pid=11808 comm="freshclam" name="0" dev=devpts ino=2 scontext=root:system_r:freshclam_t:s0 tcontext=root:object_r:devpts_t:s0 tclass=chr_file
type=AVC msg=audit(1190013770.175:958066): avc: denied { read write } for pid=11808 comm="freshclam" name="0" dev=devpts ino=2 scontext=root:system_r:freshclam_t:s0 tcontext=root:object_r:devpts_t:s0 tclass=chr_file
type=SYSCALL msg=audit(1190013770.175:958066): arch=40000003 syscall=11 success=yes exit=0 a0=832aa88 a1=832acc0 a2=832abb8 a3=832a6d8 items=0 ppid=11807 pid=11808 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) comm="freshclam" exe="/usr/bin/freshclam" subj=root:system_r:freshclam_t:s0 key=(null)
type=AVC_PATH msg=audit(1190013770.175:958066): path="/dev/pts/0"
type=AVC_PATH msg=audit(1190013770.175:958066): path="/dev/pts/0"
type=AVC_PATH msg=audit(1190013770.175:958066): path="/dev/pts/0"
type=AVC msg=audit(1190013770.280:958067): avc: denied { append } for pid=11808 comm="freshclam" name="freshclam.log" dev=dm-0 ino=10158808 scontext=root:system_r:freshclam_t:s0 tcontext=root:object_r:clamd_var_log_t:s0 tclass=file
type=SYSCALL msg=audit(1190013770.280:958067): arch=40000003 syscall=5 success=no exit=-13 a0=9af6448 a1=441 a2=1b6 a3=9af70b8 items=0 ppid=11807 pid=11808 auid=0 uid=46 gid=46 euid=46 suid=46 fsuid=46 egid=46 sgid=46 fsgid=46 tty=(none) comm="freshclam" exe="/usr/bin/freshclam" subj=root:system_r:freshclam_t:s0 key=(null)
type=AVC msg=audit(1190013770.626:958068): avc: denied { write } for pid=11810 comm="clamd" name="clamav" dev=dm-0 ino=4030584 scontext=system_u:system_r:clamd_t:s0 tcontext=system_u:object_r:usr_t:s0 tclass=dir
type=SYSCALL msg=audit(1190013770.626:958068): arch=40000003 syscall=5 success=no exit=-13 a0=8d6169c a1=242 a2=1fc a3=8d61698 items=0 ppid=2187 pid=11810 auid=4294967295 uid=46 gid=46 euid=46 suid=46 fsuid=46 egid=46 sgid=46 fsgid=46 tty=(none) comm="clamd" exe="/usr/sbin/clamd" subj=system_u:system_r:clamd_t:s0 key=(null)
type=AVC msg=audit(1190013770.627:958069): avc: denied { read } for pid=11810 comm="clamd" name="main.cvd" dev=dm-0 ino=4030636 scontext=system_u:system_r:clamd_t:s0 tcontext=system_u:object_r:usr_t:s0 tclass=file

Si possono notare delle linee con la dicitura "denied" -negato- ovvero una operazione non permessa dalle attuali policy di sicurezza. Bene noi partendo da queste indicazioni andremmo a costruire la nostra politica personalizzata.

Versione Veloce:
- Ci spostiamo dentro la cartella $home con il comando
>cd
creiamo una cartella my_policies con il comando
>mkdir my_policies
e ci spostiamo dentro con
>cd my_policies
adesso lanciamo il comando

1> audit2allow -i /var/log/audit/audit.log -M myClamdPolicies

Generazione file tipo enforcement: myClamdPolicies.te
Compilazione policy
checkmodule -M -m -o myClamdPolicies.mod myClamdPolicies.te
semodule_package -o myClamdPolicies.pp -m myClamdPolicies.mod

******************** IMPORTANTE **********************

Per poter caricare questo pacchetto di policy appena creato nel kernel,
vi è richiesto di eseguire

semodule -i myClamdPolicies.pp


Ora, come consigliato dal programma lanciamo:
2>semodule -i myClamdPolicies.pp


Controlliamo se siamo ancora con SELinux abilitato con:

>sestatus

SELinux status: enabled
SELinuxfs mount: /selinux
Current mode: enforcing
Mode from config file: enforcing
Policy version: 21
Policy from config file: targeted


dove vediamo che è abilitato e attivo.

Bene se ora proviamo a lanciare
service freshclam start
ci darà OK, altrimenti ripetere i passaggi 1 e 2 finchè non lo farà !

Versione Meditata:
Nella soluzione veloce non abbiamo ben capito cosa è successo, ma ogni buon sistemista vuol capire come funziona, per avere pieno controllo su quello che sta facendo e non lasciare (involontariamente) la porta aperta a intrusioni.

Con il comando precedente se osserviamo dentro alla cartella che abbiamo creato, troviamo 3 file:
>ll

totale 24
-rw-r--r-- 1 root root 2137 17 set 10:03 myClamdPolicies.mod
-rw-r--r-- 1 root root 2153 17 set 10:03 myClamdPolicies.pp
-rw-r--r-- 1 root root 598 17 set 10:03 myClamdPolicies.te


adesso vedremo come creare e manipolare con cognizione di causa questi tre file.
In particolare vedremo come (rif. audit2allow):
  1. Generare il file di policies .te;
  2. Compilare il binario .mod;
  3. Pacchettizzare il policy package .pp;
Cominciamo.

  1. Per creare il file di policies .te il modo migliore è sempre quello di usare il comando audit2allow:
    >audit2allow -i /var/log/audit/audit.log -m myClamdPolicies2 > myClamdPolicies2.te

    Questa volta possiamo guardare dentro il file myClamdPolicies2.te con il comando
    > vi myClamdPolicies2.te
    Ci troveremo davanti un contenuto del genere:

    module myClamdPolicies2 1.0;

    require {
    class chr_file { read write };
    class dir { add_name setattr write };
    class file { append create getattr lock read write };
    class sock_file create;
    type clamd_t;
    type clamd_var_log_t;
    type devpts_t;
    type freshclam_t;
    type proc_t;
    type tmp_t;
    type usr_t;
    role system_r;
    };

    allow clamd_t proc_t:file { getattr read };
    allow clamd_t tmp_t:sock_file create;
    allow clamd_t usr_t:dir { add_name write };
    allow clamd_t usr_t:file { create getattr read write };
    allow freshclam_t clamd_var_log_t:file { append getattr lock };
    allow freshclam_t devpts_t:chr_file { read write };
    allow freshclam_t usr_t:dir { setattr write };
    allow freshclam_t usr_t:file read;

    Qualora trovassimo qualche riga con programmi che non hanno a che fare con il problema che stiamo cercando di risolvere, possiamo rimuoverle. Se una volta installato il modulo, volessimo vedere le modifiche dall'ultimo caricamento delle policies possiamo usare lo switch -l di audit2allow:
    > audit2allow -h
    audit2allow [-adhilrv] [-t file ] [ -f fcfile ] [-i  ] [[-m|-M]  ] [-o ]
    -a, --all read input from audit and message log, conflicts with -i
    -d, --dmesg read input from output of /bin/dmesg
    -h, --help display this message
    -i, --input read input from conflicts with -a
    -l, --lastreload read input only after last "load_policy"
    -m, --module generate module/require output
    -M generate loadable module package, conflicts with -o
    -o, --output append output to , conflicts with -M
    -r, --requires generate require output
    -t, --tefile Add input from Existing Type Enforcement file
    -f, --fcfile Existing Type Enforcement file, requires -M
    -v, --verbose verbose output
    -A, --analyze Analyze output

  2. Ora possiamo compilarlo in binario con il comando
    >checkmodule -M -m -o myClamdPolicies2.mod myClamdPolicies2.te
  3. Infine possiamo pacchettizzarlo
    >semodule_package -o myClamdPolicies2.pp -m myClamdPolicies2.mod
  4. Lo carichiamo con (come abbiamo fatto prima)
    >semodule -i myClamdPolicies2
  5. Se è andato tutto per il meglio adesso possiamo controllare se il nostro pacchetto è tra quelli caricati con
    >semodule -l

    amavis 1.1.0
    ccs 1.0.0
    clamav 1.1.0
    dcc 1.1.0
    evolution 1.1.0
    iscsid 1.0.0
    mozilla 1.1.0
    mplayer 1.1.0
    myClamdPolicies 1.0
    myClamdPolicies2 1.0
    nagios 1.1.0
    oddjob 1.0.1
    pcscd 1.0.0
    pyzor 1.1.0
    razor 1.1.0
    ricci 1.0.0
    smartmon 1.1.0



Semplice no? :D

Conclusioni:
Quando su una distro abilitata con SELinux c'è qualcosa che non funziona e controllando nei log tradizionali non vi è nessuna informazione utile, conviene sempre controllare il file /var/log/audit/audit.log . Un'altra prova da fare è la seguente e cioè controllare con sestatus se SELinux è abilitato e in che modo:
>sestatus

SELinux status: enabled
SELinuxfs mount: /selinux
Current mode: enforcing
Mode from config file: enforcing
Policy version: 21
Policy from config file: targeted



Provare a disabilitare temporaneamente SELinux con il comando
>setenforce 0
Verificando stavolta con
>sestatus

SELinux status: enabled
SELinuxfs mount: /selinux
Current mode: permissive <- Disabilitate, ma il log continua Mode from config file: enforcing Policy version: 21 Policy from config file: targeted


Vediamo che SELinux è disabilitato. Bene, se adesso, il programma o la funzionalità che stavamo cercando di far funzionare ora gira, vuol dire che il problema era relativo a SELinux e può essere risolto con i metodi prima descritti.

Byez

Riferimenti:


"L'ignoranza è l'origine di tutti i mali."


Tag: , , , ,

8 commenti:

Articoli correlati divisi per etichetta



Widget by Hoctro