From: Simone Piccardi Date: Sat, 13 Jun 2009 11:41:03 +0000 (+0000) Subject: Spostamento della sezione sulle capabilities, inizio aggiornamento X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=commitdiff_plain;h=b2f11dd799533d64d84745204477831f9c1966ae Spostamento della sezione sulle capabilities, inizio aggiornamento della sezione sulle priorita` --- diff --git a/filedir.tex b/filedir.tex index b15c5f0..eca8d1d 100644 --- a/filedir.tex +++ b/filedir.tex @@ -2730,6 +2730,737 @@ scopi di sicurezza, che sono state introdotte nelle versioni pi Linux. +\subsection{La gestione delle \textit{capabilities}} +\label{sec:proc_capabilities} + +\itindbeg{capabilities} + +Come accennato in sez.~\ref{sec:proc_access_id} l'architettura classica della +gestione dei privilegi in un sistema unix-like ha il sostanziale problema di +fornire all'amministratore dei poteri troppo ampi, questo comporta che anche +quando si siano predisposte delle misure di protezione per in essere in grado +di difendersi dagli effetti di una eventuale compromissione del +sistema,\footnote{come montare un filesystem in sola lettura per impedirne + modifiche, o marcare un file come immutabile.} una volta che questa sia +stata effettuata e si siano ottenuti i privilegi di amministratore, queste +potranno essere comunque rimosse.\footnote{nei casi elencati nella precedente + nota si potrà sempre rimontare il sistema in lettura-scrittura, o togliere + la marcatura di immutabilità.} + +Il problema consiste nel fatto che nell'architettura tradizionale di un +sistema unix-like i controlli di accesso sono basati su un solo livello di +separazione: per i processi normali essi sono posti in atto, mentre per i +processi con i privilegi di amministratore essi non vengono neppure eseguiti; +per questo motivo non era previsto alcun modo per evitare che un processo con +diritti di amministratore non potesse eseguire certe operazioni, o per cedere +definitivamente alcuni privilegi da un certo momento in poi. + +Per ovviare a tutto ciò, a partire dai kernel della serie 2.2, è stato +introdotto un meccanismo, detto \textit{capabilities}, che consentisse di +suddividere i vari privilegi tradizionalmente associati all'amministratore in +un insieme di \textsl{capacità} distinte. L'idea era che queste capacità +potessero essere abilitate e disabilitate in maniera indipendente per ciascun +processo con privilegi di amministratore, permettendo così una granularità +molto più fine nella distribuzione degli stessi che evitasse la originaria +situazione di \textsl{tutto o nulla}. + +Il meccanismo completo delle \textit{capabilities}\footnote{l'implementazione + di Linux si rifà ad una bozza per quello che dovrebbe divenire lo standard + POSIX.1e, che prevede questa funzionalità.} prevederebbe anche la +possibilità di associare le stesse \textit{capabilities} anche ai singoli file +eseguibili,\footnote{una descrizione sommaria di questa funzionalità è + riportata nella pagina di manuale che descrive l'implementazione delle + \textit{capabilities} con Linux (accessibile con \texttt{man capabilities}), + ma non essendo implementata non ne tratteremo qui.} in modo da poter +stabilire quali capacità possono essere utilizzate quando viene messo in +esecuzione uno specifico programma; attualmente però questa funzionalità non è +implementata.\footnote{per attualmente si intende fino al kernel 2.6.23; + benché l'infrastruttura per crearla sia presente (vedi anche + sez.~\ref{sec:file_xattr}) finora non è disponibile nessuna realizzazione + delle specifiche POSIX.1e, esistono però dei patch di sicurezza del kernel, + come LIDS (vedi \href{http://www.lids.org}{\textsf{http://www.lids.org/})} + che realizzano qualcosa di simile.} + +% TODO verificare per process capability bounding set, vedi: +% http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=3b7391de67da515c91f48aa371de77cb6cc5c07e + +% TODO capire cosa cambia con i patch del 2.6.26, vedi +% http://lwn.net/Articles/280279/ + +\begin{table}[!h!btp] + \centering + \footnotesize + \begin{tabular}{|l|p{12cm}|} + \hline + \textbf{Capacità}&\textbf{Descrizione}\\ + \hline + \hline +% +% POSIX-draft defined capabilities. +% + \const{CAP\_CHOWN} & La capacità di cambiare proprietario e gruppo + proprietario di un file (vedi + sez.~\ref{sec:file_ownership_management}).\\ + \const{CAP\_DAC\_OVERRIDE}& La capacità di evitare il controllo dei + permessi di lettura, scrittura ed esecuzione dei + file, (vedi sez.~\ref{sec:file_access_control}) + caratteristici del modello classico del + controllo di accesso chiamato + \itindex{Discrectionary~Access~Control~(DAC)} + \textit{Discrectionary Access Control} (da cui + il nome DAC).\\ + \const{CAP\_DAC\_READ\_SEARCH}& La capacità di evitare il controllo dei + permessi di lettura, scrittura ed esecuzione per + le directory (vedi + sez.~\ref{sec:file_access_control}).\\ + \const{CAP\_FOWNER} & La capacità di evitare il controllo che + l'user-ID effettivo del processo (o meglio il + \textit{filesystem user-ID}, vedi + sez.~\ref{sec:proc_setuid}) coincida con + quello del proprietario di un file per tutte + le operazioni privilegiate non coperte dalle + precedenti \const{CAP\_DAC\_OVERRIDE} e + \const{CAP\_DAC\_READ\_SEARCH}. Queste + comprendono i cambiamenti dei permessi e dei + tempi del file (vedi + sez.~\ref{sec:file_perm_management} e + sez.~\ref{sec:file_file_times}), le impostazioni + degli attributi estesi (con il comando + \cmd{chattr}) e delle ACL, poter ignorare lo + \itindex{sticky~bit} \textit{sticky bit} nella + cancellazione dei file (vedi + sez.~\ref{sec:file_special_perm}), la possibilità + di impostare il flag di \const{O\_NOATIME} con + \func{open} e \func{fcntl} (vedi + sez.~\ref{sec:file_open} e + sez.~\ref{sec:file_fcntl}).\\ + \const{CAP\_FSETID} & La capacità di evitare la cancellazione + automatica dei bit \itindex{suid~bit} \acr{suid} + e \itindex{sgid~bit} \acr{sgid} quando un file + per i quali sono impostati viene modificato da + un processo senza questa capacità e la capacità + di impostare il bit \acr{sgid} su un file anche + quando questo è relativo ad un gruppo cui non si + appartiene (vedi + sez.~\ref{sec:file_perm_management}).\\ + \const{CAP\_KILL} & La capacità di mandare segnali a qualunque + processo (vedi sez.~\ref{sec:sig_kill_raise}).\\ + \const{CAP\_SETGID} & La capacità di manipolare i group ID dei + processi, sia il principale che i supplementari, + (vedi sez.~\ref{sec:proc_setgroups} che quelli + trasmessi tramite i socket \textit{unix domain} + (vedi sez.~\ref{sec:unix_socket}).\\ + \const{CAP\_SETUID} & La capacità di manipolare gli user ID del + processo (con \func{setuid}, \func{setreuid}, + \func{setresuid}, \func{setfsuid}) e di + trasmettere un valore arbitrario + dell'\textsl{uid} nel passaggio delle + credenziali coi socket \textit{unix domain} (vedi + sez.~\ref{sec:unix_socket}).\\ +% +% Linux specific capabilities +% +\hline + \const{CAP\_SETPCAP} & La capacità di impostare o rimuovere una capacità + (limitatamente a quelle che il processo + chiamante ha nel suo insieme di capacità + permesse) da qualunque processo.\\ +% TODO cambiata nel 2.4.24 rc1 ? + \const{CAP\_LINUX\_IMMUTABLE}& La capacità di impostare gli attributi + \textit{immutable} e \itindex{append~mode} + \textit{append only} per i file su un + filesystem che supporta questi + attributi estesi.\\ + \const{CAP\_NET\_BIND\_SERVICE}& La capacità di porre in ascolto server + su porte riservate (vedi + sez.~\ref{sec:TCP_func_bind}).\\ + \const{CAP\_NET\_BROADCAST}& La capacità di consentire l'uso di socket in + \itindex{broadcast} \textit{broadcast} e + \itindex{multicast} \textit{multicast}.\\ + \const{CAP\_NET\_ADMIN} & La capacità di eseguire alcune operazioni + privilegiate sulla rete (impostare le opzioni + privilegiate dei socket, abilitare il + \itindex{multicast} \textit{multicasting}, + impostare interfacce di rete e + tabella di instradamento).\\ + \const{CAP\_NET\_RAW} & La capacità di usare socket \texttt{RAW} e + \texttt{PACKET} (quelli che permettono di creare + pacchetti nei protocolli di basso livello).\\ + \const{CAP\_IPC\_LOCK} & La capacità di effettuare il \textit{memory + locking} \itindex{memory~locking} con le + funzioni \func{mlock}, \func{mlockall}, + \func{shmctl}, \func{mmap} (vedi + sez.~\ref{sec:proc_mem_lock} e + sez.~\ref{sec:file_memory_map}). \\ + \const{CAP\_IPC\_OWNER} & La capacità di evitare il controllo dei permessi + per le operazioni sugli oggetti di + intercomunicazione fra processi (vedi + sez.~\ref{sec:ipc_sysv}).\\ + \const{CAP\_SYS\_MODULE}& La capacità di caricare e rimuovere moduli del + kernel. \\ + \const{CAP\_SYS\_RAWIO} & La capacità di eseguire operazioni sulle porte + di I/O con \func{ioperm} e \func{iopl} (vedi + sez.~\ref{sec:file_io_port}).\\ + \const{CAP\_SYS\_CHROOT}& La capacità di eseguire la funzione + \func{chroot} (vedi + sez.~\ref{sec:file_chroot}).\\ + \const{CAP\_SYS\_PTRACE}& Consente di tracciare qualunque processo con + \func{ptrace} (vedi + sez.~\ref{sec:xxx_ptrace}).\\ + \const{CAP\_SYS\_PACCT} & La capacità di usare le funzioni di + \textit{accounting} dei processi (vedi + sez.~\ref{sec:sys_bsd_accounting}).\\ + \const{CAP\_SYS\_ADMIN} & La capacità di eseguire una serie di compiti + amministrativi (come impostare le quote, + attivare e disattivare la swap, montare, + rimontare e smontare filesystem, ecc.). \\ + \const{CAP\_SYS\_BOOT} & La capacità di fare eseguire un riavvio del + sistema.\\ +% TODO trattare reboot e kexec + \const{CAP\_SYS\_NICE} & La capacità di modificare le priorità dei + processi (vedi sez.~\ref{sec:proc_priority}). \\ + \const{CAP\_SYS\_RESOURCE}& La capacità di superare le limitazioni sulle + risorse, aumentare le quote disco, usare lo + spazio disco riservato all'amministratore.\\ + \const{CAP\_SYS\_TIME} & La capacità di modificare il tempo di sistema + (vedi sez.~\ref{sec:sys_time}).\\ + \const{CAP\_SYS\_TTY\_CONFIG}& La capacità di simulare un \textit{hangup} + della console, con la funzione + \func{vhangup}.\\ + \const{CAP\_MKNOD} & La capacità di creare file di dispositivo con la + funzione \func{mknod} (vedi + sez.~\ref{sec:file_mknod}).\footnotemark\\ + \const{CAP\_LEASE} & La capacità di creare dei \textit{file lease} + \index{file!lease} su di un file (vedi + sez.~\ref{sec:file_asyncronous_lease}) + indipendentemente dalla proprietà dello + stesso.\footnotemark\\ + \const{CAP\_SETFCAP} & La capacità di impostare le + \textit{capabilities} di un file (non + supportata).\\ + \const{CAP\_AUDIT\_WRITE}&consente la scrittura di dati nel giornale di + auditing del kernel.\\ + \const{CAP\_AUDIT\_CONTROL}& consente di abilitare e disabilitare il + controllo dell'auditing.\footnotemark\\ +% TODO verificare questa roba dell'auditing + \hline + \end{tabular} + \caption{Le costanti che identificano le \textit{capabilities} presenti nel + kernel.} +\label{tab:proc_capabilities} +\end{table} + +\footnotetext[21]{questa capacità è presente soltanto a partire dai kernel + della serie 2.4.x.} + +\footnotetext[22]{questa capacità è presente soltanto a partire dai kernel della + serie 2.4.x.} + +\footnotetext{queste ultime due capacità sono presenti soltanto a partire dai + kernel della serie 2.6.11.} + +Per gestire questo nuovo meccanismo ciascun processo porta con sé tre distinti +insiemi di \textit{capabilities}, che vengono denominati rispettivamente +\textit{effective}, \textit{permitted} ed \textit{inherited}. Questi insiemi +vengono mantenuti in forma di tre diverse maschere binarie,\footnote{il kernel + li mantiene, come i vari identificatori di sez.~\ref{sec:proc_setuid}, + all'interno della \struct{task\_struct} di ciascun processo (vedi + fig.~\ref{fig:proc_task_struct}), nei tre campi \texttt{cap\_effective}, + \texttt{cap\_inheritable}, \texttt{cap\_permitted} del tipo + \texttt{kernel\_cap\_t}; questo è attualmente definito come intero a 32 bit, + il che comporta un massimo di 32 \textit{capabilities} distinte.} in cui +ciascun bit corrisponde ad una capacità diversa; se ne è riportato +l'elenco,\footnote{si tenga presente che l'elenco delle \textit{capabilities} + presentato questa tabella, ripreso dalla relativa pagina di manuale + (accessibile con \texttt{man capabilities}) e dalle definizioni in + \texttt{sys/capabilities.h}, è quello aggiornato al kernel 2.6.6.} con una +breve descrizione, ed il nome delle costanti che identificano i singoli bit, +in tab.~\ref{tab:proc_capabilities}; la tabella è divisa in due parti, la +prima riporta le \textit{capabilities} previste nella bozza dello standard +POSIX1.e, la seconda quelle specifiche di Linux. + +L'utilizzo di tre distinti insiemi serve a fornire una interfaccia flessibile +per l'uso delle \textit{capabilities}, con scopi analoghi a quelli per cui +sono mantenuti i diversi insiemi di identificatori di +sez.~\ref{sec:proc_setuid}; il loro significato è il seguente: +\begin{basedescript}{\desclabelwidth{2.0cm}\desclabelstyle{\nextlinelabel}} +\item[\textit{effective}] l'insieme delle \textit{capabilities} + ``\textsl{effettive}'', cioè di quelle che vengono effettivamente usate dal + kernel quando deve eseguire il controllo di accesso per le varie operazioni + compiute dal processo. +\item[\textit{permitted}] l'insieme delle \textit{capabilities} + ``\textsl{permesse}'', cioè l'insieme di quelle capacità che un processo + \textsl{può} impostare come \textsl{effettive}. Se un processo cancella una + capacità da questo insieme non potrà più riassumerla (almeno che non esegua + un programma che è \acr{suid} di root). +\item[\textit{inherited}] l'insieme delle \textit{capabilities} + ``\textsl{ereditabili}'', cioè quelle che vengono trasmesse ad un nuovo + programma eseguito attraverso una chiamata ad \func{exec} (con l'eccezione + del caso che questo sia \acr{suid} di root). +\label{sec:capabilities_set} +\end{basedescript} + +Oltre a questi tre insiemi, che sono relativi al singolo processo, il kernel +mantiene un insieme generale valido per tutto il sistema, chiamato +\itindex{capabilities~bounding~set} \textit{capabilities bounding set}. Ogni +volta che un programma viene posto in esecuzione con \func{exec} il contenuto +degli insiemi \textit{effective} e \textit{permitted} vengono mascherati con +un \textsl{AND} binario del contenuto corrente del \textit{capabilities + bounding set}, così che il nuovo processo potrà disporre soltanto delle +capacità in esso elencate. + +Il \textit{capabilities bounding set} è un parametro di sistema, accessibile +attraverso il contenuto del file \procfile{/proc/sys/kernel/cap-bound}, che per +questa sua caratteristica consente di impostare un limite generale alle +capacità che possono essere accordate ai vari processi. Questo valore può +essere impostato ad un valore arbitrario esclusivamente dal primo processo +eseguito nel sistema (di norma cioè da \texttt{/sbin/init}), ogni processo +eseguito successivamente (cioè con \textsl{pid} diverso da 1) anche se +eseguito con privilegi di amministratore potrà soltanto rimuovere uno dei bit +già presenti dell'insieme: questo significa che una volta rimossa una +\textit{capability} dal \textit{capabilities bounding set} essa non sarà più +disponibile, neanche per l'amministratore, a meno di un riavvio. + +Quando un programma viene messo in esecuzione\footnote{cioè quando viene + eseguita la \func{execve} con cui lo si lancia; in corrispondenza di una + \func{fork} le \textit{capabilities} non vengono modificate.} esso eredita +(nel senso che assume negli insiemi \textit{effective} e \textit{permitted}) +le \textit{capabilities} mantenute nell'insieme \textit{inherited}, a meno che +non sia eseguito un programma \acr{suid} di root o la \func{exec} sia stata +eseguita da un programma con \textsl{uid} reale zero; in tal caso il programma +ottiene tutte le \textit{capabilities} presenti nel \textit{capabilities + bounding set}. In questo modo si può far si che ad un processo eseguito in +un secondo tempo possano essere trasmesse solo un insieme limitato di +capacità, impedendogli di recuperare quelle assenti nell'insieme +\textit{inherited}. Si tenga presente invece che attraverso una \func{fork} +vengono mantenute le stesse capacità del processo padre. + +Per la gestione delle \textit{capabilities} il kernel mette a disposizione due +funzioni che permettono rispettivamente di leggere ed impostare i valori dei +tre insiemi illustrati in precedenza. Queste due funzioni sono \funcd{capget} +e \funcd{capset} e costituiscono l'interfaccia di gestione basso livello; i +loro rispettivi prototipi sono: +\begin{functions} + \headdecl{sys/capability.h} + + \funcdecl{int capget(cap\_user\_header\_t hdrp, cap\_user\_data\_t datap)} + Legge le \textit{capabilities}. + + \funcdecl{int capset(cap\_user\_header\_t hdrp, const cap\_user\_data\_t + datap)} + Imposta le \textit{capabilities}. + + + \bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e -1 in caso + di errore, nel qual caso \var{errno} può assumere i valori: + \begin{errlist} + \item[\errcode{ESRCH}] si è fatto riferimento ad un processo inesistente. + \item[\errcode{EPERM}] si è tentato di aggiungere una capacità + nell'insieme delle \textit{capabilities} permesse, o di impostare una + capacità non presente nell'insieme di quelle permesse negli insieme + delle effettive o ereditate, o si è cercato di impostare una + \textit{capability} di un altro processo senza avare + \const{CAP\_SETPCAP}. + \end{errlist} + ed inoltre \errval{EFAULT} ed \errval{EINVAL}. +} + +\end{functions} + +Queste due funzioni prendono come argomenti due tipi di dati dedicati, +definiti come puntatori a due strutture specifiche di Linux, illustrate in +fig.~\ref{fig:cap_kernel_struct}. Per poterle utilizzare occorre anche +cancellare la macro \macro{\_POSIX\_SOURCE}.\footnote{per farlo occorre + utilizzare la direttiva di preprocessore \direct{undef}; si dovrà cioè + inserire una istruzione \texttt{\#undef \_POSIX\_SOURCE} prima di includere + \texttt{sys/capability.h}.} Si tenga presente che le strutture di +fig.~\ref{fig:cap_kernel_struct}, come i prototipi delle due funzioni +\func{capget} e \func{capset}, sono soggette ad essere modificate con il +cambiamento del kernel (in particolare i tipi di dati delle strutture) ed +anche se finora l'interfaccia è risultata stabile, non c'è nessuna +assicurazione che questa venga mantenuta.\footnote{anzi, visto lo scarso + utilizzo di questa funzionalità ci sono state varie discussioni fra gli + sviluppatori del kernel relative all'eliminarla o al modificarla + radicalmente.} Pertanto se si vogliono scrivere programmi portabili che +possano essere eseguiti su qualunque versione del kernel è opportuno +utilizzare le interfacce di alto livello. + +\begin{figure}[!htb] + \footnotesize + \centering + \begin{minipage}[c]{15cm} + \includestruct{listati/cap_user_header_t.h} + \end{minipage} + \normalsize + \caption{Definizione delle strutture a cui fanno riferimento i puntatori + \structd{cap\_user\_header\_t} e \structd{cap\_user\_data\_t} usati per + l'interfaccia di gestione di basso livello delle \textit{capabilities}.} + \label{fig:cap_kernel_struct} +\end{figure} + +La struttura a cui deve puntare l'argomento \param{hdrp} serve ad indicare, +tramite il campo \var{pid}, il processo del quale si vogliono leggere o +modificare le \textit{capabilities}. Il campo \var{version} deve essere +impostato al valore della versione delle usata dal kernel (quello indicato +dalla costante \const{\_LINUX\_CAPABILITY\_VERSION} di +fig.~\ref{fig:cap_kernel_struct}) altrimenti le funzioni ritorneranno con un +errore di \errcode{EINVAL}, restituendo nel campo stesso il valore corretto +della versione in uso. La struttura a cui deve puntare l'argomento +\param{datap} invece conterrà i valori letti o da impostare per i tre insiemi +delle capacità del processo. + +Dato che le precedenti funzioni, oltre ad essere specifiche di Linux, non +garantiscono la stabilità nell'interfaccia, è sempre opportuno effettuare la +gestione delle \textit{capabilities} utilizzando le funzioni di libreria a +questo dedicate. Queste funzioni, che seguono quanto previsto nelle bozze +dello standard POSIX.1e, non fanno parte delle \acr{glibc} e sono fornite in +una libreria a parte,\footnote{la libreria è \texttt{libcap2}, nel caso di + Debian può essere installata con il pacchetto omonimo.} pertanto se un +programma le utilizza si dovrà indicare esplicitamente l'uso della suddetta +libreria attraverso l'opzione \texttt{-lcap} del compilatore. + +Le funzioni dell'interfaccia delle bozze di POSIX.1e prevedono l'uso di uno +tipo di dato opaco, \type{cap\_t}, come puntatore ai dati mantenuti nel +cosiddetto \textit{capability state},\footnote{si tratta in sostanza di un + puntatore ad una struttura interna utilizzata dalle librerie, i cui campi + non devono mai essere acceduti direttamente.} in sono memorizzati tutti i +dati delle \textit{capabilities}. In questo modo è possibile mascherare i +dettagli della gestione di basso livello, che potranno essere modificati senza +dover cambiare le funzioni dell'interfaccia, che faranno riferimento soltanto +ad oggetti di questo tipo. L'interfaccia pertanto non soltanto fornisce le +funzioni per modificare e leggere le \textit{capabilities}, ma anche quelle +per gestire i dati attraverso \type{cap\_t}. + +La prima funzione dell'interfaccia è quella che permette di inizializzare un +\textit{capability state}, allocando al contempo la memoria necessaria per i +relativi dati. La funzione è \funcd{cap\_init} ed il suo prototipo è: +\begin{functions} + \headdecl{sys/capability.h} + + \funcdecl{cap\_t cap\_init(void)} + Crea ed inizializza un \textit{capability state}. + + \bodydesc{La funzione ritorna un valore non nullo in caso di successo e + \macro{NULL} in caso di errore, nel qual caso \var{errno} assumerà il + valore \errval{ENOMEM}. + } +\end{functions} + +La funzione restituisce il puntatore \type{cap\_t} ad uno stato inizializzato +con tutte le \textit{capabilities} azzerate. In caso di errore (cioè quando +non c'è memoria sufficiente ad allocare i dati) viene restituito \macro{NULL} +ed \var{errno} viene impostata a \errval{ENOMEM}. La memoria necessaria a +mantenere i dati viene automaticamente allocata da \func{cap\_init}, ma dovrà +essere disallocata esplicitamente quando non è più necessaria utilizzando, per +questo l'interfaccia fornisce una apposita funzione, \funcd{cap\_free}, il cui +prototipo è: +\begin{functions} + \headdecl{sys/capability.h} + + \funcdecl{int cap\_free(void *obj\_d)} + Disalloca la memoria allocata per i dati delle \textit{capabilities}. + + \bodydesc{La funzione ritorna 0 in caso di successo e $-1$ in caso di + errore, nel qual caso \var{errno} assumerà il valore \errval{EINVAL}. + } +\end{functions} + +La funzione permette di liberare la memoria allocata dalle altre funzioni +della libreria sia per un \textit{capability state}, nel qual caso l'argomento +dovrà essere un dato di tipo \type{cap\_t}, che per una descrizione testuale +dello stesso,\footnote{cioè quanto ottenuto tramite la funzione + \func{cap\_to\_text}.} nel qual caso l'argomento dovrà essere un dato di +tipo \texttt{char *}. Per questo l'argomento \param{obj\_d} è dichiarato come +\texttt{void *} e deve sempre corrispondere ad un puntatore ottenuto tramite +le altre funzioni della libreria, altrimenti la funzione fallirà con un errore +di \errval{EINVAL}. + +Infine si può creare una copia di un \textit{capability state} ottenuto in +precedenza tramite la funzione \funcd{cap\_dup}, il cui prototipo è: +\begin{functions} + \headdecl{sys/capability.h} + + \funcdecl{cap\_t cap\_dup(cap\_t cap\_p)} + Duplica un \textit{capability state} restituendone una copia. + + \bodydesc{La funzione ritorna un valore non nullo in caso di successo e + \macro{NULL} in caso di errore, nel qual caso \var{errno} potrà assumere i + valori \errval{ENOMEM} o \errval{EINVAL}. + } +\end{functions} + +La funzione crea una copia del \textit{capability state} posto all'indirizzo +\param{cap\_p} che si è passato come argomento, restituendo il puntatore alla +copia, che conterrà gli stessi valori delle \textit{capabilities} presenti +nell'originale. La memoria necessaria viene allocata automaticamente dalla +funzione. Una volta effettuata la copia i due \textit{capability state} +potranno essere modificati in maniera completamente +indipendente.\footnote{alla fine delle operazioni si ricordi però di + disallocare anche la copia, oltre all'originale. } + +Una seconda classe di funzioni di servizio previste dall'interfaccia sono +quelle per la gestione dei dati contenuti all'interno di un \textit{capability + state}; la prima di queste è \funcd{cap\_clear}, il cui prototipo è: +\begin{functions} + \headdecl{sys/capability.h} + + \funcdecl{int cap\_clear(cap\_t cap\_p)} + Inizializza un \textit{capability state} cancellando tutte le + \textit{capabilities}. + + \bodydesc{La funzione ritorna 0 in caso di successo e $-1$ in caso di + errore, nel qual caso \var{errno} assumerà il valore \errval{EINVAL}. + } +\end{functions} + +La funzione si limita ad azzerare tutte le \textit{capabilities} presenti nel +\textit{capability state} all'indirizzo \param{cap\_p} passato come argomento, +restituendo uno stato \textsl{vuoto}, analogo a quello che si ottiene nella +creazione con \func{cap\_init}. + +Per la gestione dei valori delle \textit{capabilities} presenti in un +\textit{capability state} l'interfaccia prevede due funzioni, +\funcd{cap\_get\_flag} e \funcd{cap\_set\_flag}, che permettono +rispettivamente di leggere o impostare il valore di un flag delle +\textit{capabilities}; i rispettivi prototipi sono: +\begin{functions} + \headdecl{sys/capability.h} + + \funcdecl{int cap\_get\_flag(cap\_t cap\_p, cap\_value\_t cap, cap\_flag\_t + flag, cap\_flag\_value\_t *value\_p)} + Legge il valore di una \textit{capability}. + + \funcdecl{int cap\_set\_flag(cap\_t cap\_p, cap\_flag\_t flag, int ncap, + cap\_value\_t *caps, cap\_flag\_value\_t value)} + Imposta il valore di una \textit{capability}. + + \bodydesc{Le funzioni ritornano 0 in caso di successo e $-1$ in caso di + errore, nel qual caso \var{errno} assumerà il valore \errval{EINVAL}. +} +\end{functions} + +In entrambe le funzioni l'argomento \param{cap\_p} indica il puntatore al +\textit{capability state} su cui operare, mentre l'argomento \param{flag} +indica su quale dei tre insiemi illustrati a +pag.~\pageref{sec:capabilities_set} si intende operare. Questi devono essere +specificati con una variabile di tipo \type{cap\_flag\_t} che può assumere +esclusivamente\footnote{si tratta in effetti di un tipo enumerato, come si può + verificare dalla sua definizione che si trova in + \texttt{/usr/include/sys/capability.h}.} uno dei valori illustrati in +tab.~\ref{tab:cap_set_identifier}. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|l|} + \hline + \textbf{Valore} & \textbf{Significato} \\ + \hline + \hline + \const{CAP\_EFFECTIVE} & Capacità dell'insieme \textsl{effettivo}.\\ + \const{CAP\_PERMITTED} & Capacità dell'insieme \textsl{permesso}.\\ + \const{CAP\_INHERITABLE}& Capacità dell'insieme \textsl{ereditabile}.\\ + \hline + \end{tabular} + \caption{Valori possibili per il tipo di dato \type{cap\_flag\_t} che + identifica gli insiemi delle \textit{capabilities}.} + \label{tab:cap_set_identifier} +\end{table} + +La capacità che si intende controllare o impostare invece deve essere +specificata attraverso una variabile di tipo \type{cap\_value\_t}, che può +prendere come valore uno qualunque di quelli riportati in +tab.~\ref{tab:proc_capabilities}, in questo caso però non è possibile +combinare diversi valori in una maschera binaria, una variabile di tipo +\type{cap\_value\_t} deve indicare una sola capacità.\footnote{nel file di + header citato nella nota precedente il tipo \type{cap\_value\_t} è definito + come \ctyp{int}, ma i valori validi sono soltanto quelli di + tab.~\ref{tab:proc_capabilities}.} + +Infine lo stato di una capacità è descritto ad una variabile di tipo +\type{cap\_flag\_value\_t}, che a sua volta può assumere soltanto +uno\footnote{anche questo è un tipo enumerato.} dei valori di +tab.~\ref{tab:cap_value_type}. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|l|} + \hline + \textbf{Valore} & \textbf{Significato} \\ + \hline + \hline + \const{CAP\_CLEAR}& La capacità non è impostata.\\ + \const{CAP\_SET} & La capacità è impostata.\\ + \hline + \end{tabular} + \caption{Valori possibili per il tipo di dato \type{cap\_flag\_value\_t} che + indica lo stato di una capacità.} + \label{tab:cap_value_type} +\end{table} + +La funzione \func{cap\_get\_flag} legge lo stato della capacità indicata +dall'argomento \param{cap} all'interno dell'insieme indicato dall'argomento +\param{flag} e ne restituisce il valore nella variabile posta all'indirizzo +puntato dall'argomento \param{value\_p}; è possibile cioè leggere soltanto uno +stato di una capacità alla volta. + +La funzione \func{cap\_set\_flag} può invece impostare in una sola chiamata +più \textit{capabilities}, anche se solo all'interno dello stesso insieme. Per +questo motivo essa prende un vettore di valori di tipo \type{cap\_value\_t} +nell'argomento \param{caps}, la cui dimensione viene specificata dall'argomento +\param{ncap}. Il tipo di impostazione da eseguire (cancellazione o +impostazione) viene indicato dall'argomento \param{value}. + +Per la visualizzazione dello stato delle \textit{capabilities} l'interfaccia +prevede una funzione apposita, \funcd{cap\_to\_text}, il cui prototipo è: +\begin{functions} + \headdecl{sys/capability.h} + + \funcdecl{char * cap\_to\_text(cap\_t caps, ssize\_t * length\_p)} + + Genera una visualizzazione testuale delle \textit{capabilities}. + + \bodydesc{La funzione ritorna un puntatore alla stringa con la descrizione + delle \textit{capabilities} in caso di successo e \val{NULL} in caso di + errore, nel qual caso \var{errno} può assumere i valori \errval{EINVAL} o + \errval{ENOMEM}. + } +\end{functions} + +La funzione ritorna l'indirizzo di una stringa contente la descrizione +testuale del contenuto del \textit{capabilities state} \param{caps} passato +come argomento, e, qualora l'argomento \param{length\_p} sia diverso da +\val{NULL}, restituisce nella variabile intera da questo puntata la lunghezza +della stringa. La stringa restituita viene allocata automaticamente dalla +funzione e pertanto dovrà essere liberata con \func{cap\_free}. + +Fin quei abbiamo trattato solo le funzioni di servizio relative alla +manipolazione dei \textit{capabilities state}; l'interfaccia di gestione +prevede però anche le funzioni per la gestione delle \textit{capabilities} +stesse. La prima di queste è \funcd{cap\_get\_proc} che consente la lettura +delle \textit{capabilities} del processo corrente, il suo prototipo è: +\begin{functions} + \headdecl{sys/capability.h} + + \funcdecl{cap\_t cap\_get\_proc(void)} + Legge le \textit{capabilities} del processo corrente. + + \bodydesc{La funzione ritorna un valore diverso da \val{NULL} in caso di + successo e \val{NULL} in caso di errore, nel qual caso \var{errno} può + assumere i valori \errval{EINVAL}, \errval{EPERM} o \errval{ENOMEM}. } +\end{functions} + +La funzione legge il valore delle \textit{capabilities} associate al processo +da cui viene invocata, restituendo il risultato tramite il puntatore ad un +\textit{capabilities state} contenente tutti i dati che provvede ad allocare +autonomamente e che di nuovo occorrerà liberare con \func{cap\_free} quando +non sarà più utilizzato. + +Se invece si vogliono leggere le \textit{capabilities} di un processo +specifico occorre usare la funzione \funcd{capgetp}, il cui +prototipo\footnote{su alcune pagine di manuale la funzione è descritta con un + prototipo sbagliato, che prevede un valore di ritorno di tipo \type{cap\_t}, + ma il valore di ritorno è intero, come si può verificare anche dalla + dichiarazione della stessa in \texttt{sys/capability.h}.} è: +\begin{functions} + \headdecl{sys/capability.h} + + \funcdecl{int capgetp(pid\_t pid, cap\_t cap\_d)} + Legge le \textit{capabilities} del processo indicato da \param{pid}. + + \bodydesc{La funzione ritorna 0 in caso di successo e $-1$ in caso di + errore, nel qual caso \var{errno} può assumere i valori \errval{EINVAL}, + \errval{EPERM} o \errval{ENOMEM}. + } +\end{functions} +%TODO controllare e correggere i codici di errore!!! + +La funzione legge il valore delle \textit{capabilities} del processo indicato +con l'argomento \param{pid}, e restituisce il risultato nel +\textit{capabilities state} posto all'indirizzo indicato con l'argomento +\param{cap\_d}; a differenza della precedente in questo caso il +\textit{capability state} deve essere stato creato in precedenza. Qualora il +processo indicato non esista si avrà un errore di \errval{ESRCH}. Gli stessi +valori possono essere letti direttamente nel filesystem \textit{proc}, nei +file \texttt{/proc//status}; ad esempio per \texttt{init} si otterrà +qualcosa del tipo: +\begin{Verbatim} +... +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff +... +\end{Verbatim} + +Infine per impostare le \textit{capabilities} del processo corrente (non +esiste una funzione che permetta di cambiare le \textit{capabilities} di un +altro processo) si deve usare la funzione \funcd{cap\_set\_proc}, il cui +prototipo è: +\begin{functions} + \headdecl{sys/capability.h} + + \funcdecl{int cap\_set\_proc(cap\_t cap\_p)} + Imposta le \textit{capabilities} del processo corrente. + + \bodydesc{La funzione ritorna 0 in caso di successo e $-1$ in caso di + errore, nel qual caso \var{errno} può assumere i valori \errval{EINVAL}, + \errval{EPERM} o \errval{ENOMEM}. + } +\end{functions} + +La funzione modifica le \textit{capabilities} del processo corrente secondo +quanto specificato con l'argomento \param{cap\_p}, posto che questo sia +possibile nei termini spiegati in precedenza (non sarà ad esempio possibile +impostare capacità non presenti nell'insieme di quelle permesse). In caso di +successo i nuovi valori saranno effettivi al ritorno della funzione, in caso +di fallimento invece lo stato delle capacità resterà invariato. Si tenga +presente che \textsl{tutte} le capacità specificate tramite \param{cap\_p} +devono essere permesse; se anche una sola non lo è la funzione fallirà, e per +quanto appena detto, lo stato delle \textit{capabilities} non verrà modificato +(neanche per le parti eventualmente permesse). + +Come esempio di utilizzo di queste funzioni nei sorgenti allegati alla guida +si è distribuito il programma \texttt{getcap.c}, che consente di leggere le +\textit{capabilities} del processo corrente\footnote{vale a dire di sé stesso, + quando lo si lancia, il che può sembrare inutile, ma serve a mostrarci quali + sono le \textit{capabilities} standard che ottiene un processo lanciato + dalla riga di comando.} o tramite l'opzione \texttt{-p}, quelle di un +processo qualunque il cui pid viene passato come parametro dell'opzione. + +\begin{figure}[htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \includecodesample{listati/getcap.c} + \end{minipage} + \normalsize + \caption{Corpo principale del programma \texttt{getcap.c}.} + \label{fig:proc_getcap} +\end{figure} + +La sezione principale del programma è riportata in fig.~\ref{fig:proc_getcap}, +e si basa su una condizione sulla variabile \var{pid} che se si è usato +l'opzione \texttt{-p} è impostata (nella sezione di gestione delle opzioni, +che si è tralasciata) al valore del \textsl{pid} del processo di cui si vuole +leggere le \textit{capabilities} e nulla altrimenti. Nel primo caso +(\texttt{\small 1--6}) si utilizza direttamente (\texttt{\small 2}) +\func{cap\_get\_proc} per ottenere lo stato delle capacità del processo, nel +secondo (\texttt{\small 7--14}) prima si inizializza (\texttt{\small 8}) uno +stato vuoto e poi (\texttt{\small 9}) si legge il valore delle capacità del +processo indicato. + +Il passo successivo è utilizzare (\texttt{\small 16}) \func{cap\_to\_text} per +tradurre in una stringa lo stato, e poi (\texttt{\small 17}) stamparlo; infine +(\texttt{\small 19--20}) si libera la memoria allocata dalle precedenti +funzioni con \func{cap\_free} per poi ritornare dal ciclo principale della +funzione. + +\itindend{capabilities} + +% TODO vedi http://lwn.net/Articles/198557/ e +% http://www.madore.org/~david/linux/newcaps/ +% TODO documentare prctl ... + \subsection{Gli attributi estesi} \label{sec:file_xattr} @@ -4025,9 +4756,9 @@ programmi e librerie) di cui il server potrebbe avere bisogno. % LocalWords: removexattr lremovexattr fremovexattr attributename lacl acl % LocalWords: OBJ setfacl len any prefix separator options NUMERIC IDS SMART % LocalWords: INDENT major number IDE Documentation makedev fopendir proc copy +% LocalWords: euidaccess eaccess delete def tag qualifier permset %%% Local Variables: %%% mode: latex %%% TeX-master: "gapil" %%% End: -% LocalWords: euidaccess eaccess delete def tag qualifier permset diff --git a/prochand.tex b/prochand.tex index 5008403..27d7d06 100644 --- a/prochand.tex +++ b/prochand.tex @@ -738,8 +738,8 @@ La scelta di riportare al padre lo stato di terminazione dei figli, pur essendo l'unica possibile, comporta comunque alcune complicazioni: infatti se alla sua creazione è scontato che ogni nuovo processo ha un padre, non è detto che sia così alla sua conclusione, dato che il padre potrebbe essere già -terminato (si potrebbe avere cioè quello che si chiama un processo -\textsl{orfano}). +terminato; si potrebbe avere cioè quello che si chiama un processo +\textsl{orfano}. % TODO verificare il reparenting @@ -1239,14 +1239,12 @@ campi: lo ha terminato, fermato o riavviato. \item[\var{si\_code}] con uno fra \const{CLD\_EXITED}, \const{CLD\_KILLED}, \const{CLD\_STOPPED}, \const{CLD\_CONTINUED}, \const{CLD\_TRAPPED} e - \const{CLD\_DUMPED} a indicare la ragione del ritorno della funzione, - rispettivamente: uscita normale, terminazione da segnale, processo fermato, - processo riavviato, processo terminato in \textit{core dump}. + \const{CLD\_DUMPED} a indicare la ragione del ritorno della funzione, il cui + significato è, nell'ordine: uscita normale, terminazione da segnale, + processo fermato, processo riavviato, processo terminato in \textit{core + dump}. \end{basedescript} -%TODO mettere riferimento alla tabella giusta (vedere man credentials e man -% waitid) - Infine Linux, seguendo un'estensione di BSD, supporta altre due funzioni per la lettura dello stato di terminazione di un processo, analoghe alle precedenti ma che prevedono un ulteriore argomento attraverso il quale il @@ -2087,732 +2085,7 @@ con cui costruisce una lista di gruppi supplementari, a cui aggiunge anche compila con il flag \cmd{-ansi}, è pertanto meglio evitarle se si vuole scrivere codice portabile. - -\subsection{La gestione delle \textit{capabilities}} -\label{sec:proc_capabilities} - -\itindbeg{capabilities} - -Come accennato in sez.~\ref{sec:proc_access_id} l'architettura classica della -gestione dei privilegi in un sistema unix-like ha il sostanziale problema di -fornire all'amministratore dei poteri troppo ampi, questo comporta che anche -quando si siano predisposte delle misure di protezione per in essere in grado -di difendersi dagli effetti di una eventuale compromissione del -sistema,\footnote{come montare un filesystem in sola lettura per impedirne - modifiche, o marcare un file come immutabile.} una volta che questa sia -stata effettuata e si siano ottenuti i privilegi di amministratore, queste -potranno essere comunque rimosse.\footnote{nei casi elencati nella precedente - nota si potrà sempre rimontare il sistema in lettura-scrittura, o togliere - la marcatura di immutabilità.} - -Il problema consiste nel fatto che nell'architettura tradizionale di un -sistema unix-like i controlli di accesso sono basati su un solo livello di -separazione: per i processi normali essi sono posti in atto, mentre per i -processi con i privilegi di amministratore essi non vengono neppure eseguiti; -per questo motivo non era previsto alcun modo per evitare che un processo con -diritti di amministratore non potesse eseguire certe operazioni, o per cedere -definitivamente alcuni privilegi da un certo momento in poi. - -Per ovviare a tutto ciò, a partire dai kernel della serie 2.2, è stato -introdotto un meccanismo, detto \textit{capabilities}, che consentisse di -suddividere i vari privilegi tradizionalmente associati all'amministratore in -un insieme di \textsl{capacità} distinte. L'idea era che queste capacità -potessero essere abilitate e disabilitate in maniera indipendente per ciascun -processo con privilegi di amministratore, permettendo così una granularità -molto più fine nella distribuzione degli stessi che evitasse la originaria -situazione di \textsl{tutto o nulla}. - -Il meccanismo completo delle \textit{capabilities}\footnote{l'implementazione - di Linux si rifà ad una bozza per quello che dovrebbe divenire lo standard - POSIX.1e, che prevede questa funzionalità.} prevederebbe anche la -possibilità di associare le stesse \textit{capabilities} anche ai singoli file -eseguibili,\footnote{una descrizione sommaria di questa funzionalità è - riportata nella pagina di manuale che descrive l'implementazione delle - \textit{capabilities} con Linux (accessibile con \texttt{man capabilities}), - ma non essendo implementata non ne tratteremo qui.} in modo da poter -stabilire quali capacità possono essere utilizzate quando viene messo in -esecuzione uno specifico programma; attualmente però questa funzionalità non è -implementata.\footnote{per attualmente si intende fino al kernel 2.6.23; - benché l'infrastruttura per crearla sia presente (vedi anche - sez.~\ref{sec:file_xattr}) finora non è disponibile nessuna realizzazione - delle specifiche POSIX.1e, esistono però dei patch di sicurezza del kernel, - come LIDS (vedi \href{http://www.lids.org}{\textsf{http://www.lids.org/})} - che realizzano qualcosa di simile.} - -% TODO verificare per process capability bounding set, vedi: -% http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=3b7391de67da515c91f48aa371de77cb6cc5c07e - -% TODO capire cosa cambia con i patch del 2.6.26, vedi -% http://lwn.net/Articles/280279/ - -\begin{table}[!h!bt] - \centering - \footnotesize - \begin{tabular}{|l|p{12cm}|} - \hline - \textbf{Capacità}&\textbf{Descrizione}\\ - \hline - \hline -% -% POSIX-draft defined capabilities. -% - \const{CAP\_CHOWN} & La capacità di cambiare proprietario e gruppo - proprietario di un file (vedi - sez.~\ref{sec:file_ownership_management}).\\ - \const{CAP\_DAC\_OVERRIDE}& La capacità di evitare il controllo dei - permessi di lettura, scrittura ed esecuzione dei - file, (vedi sez.~\ref{sec:file_access_control}) - caratteristici del modello classico del - controllo di accesso chiamato - \itindex{Discrectionary~Access~Control~(DAC)} - \textit{Discrectionary Access Control} (da cui - il nome DAC).\\ - \const{CAP\_DAC\_READ\_SEARCH}& La capacità di evitare il controllo dei - permessi di lettura, scrittura ed esecuzione per - le directory (vedi - sez.~\ref{sec:file_access_control}).\\ - \const{CAP\_FOWNER} & La capacità di evitare il controllo che - l'user-ID effettivo del processo (o meglio il - \textit{filesystem user-ID}, vedi - sez.~\ref{sec:proc_setuid}) coincida con - quello del proprietario di un file per tutte - le operazioni privilegiate non coperte dalle - precedenti \const{CAP\_DAC\_OVERRIDE} e - \const{CAP\_DAC\_READ\_SEARCH}. Queste - comprendono i cambiamenti dei permessi e dei - tempi del file (vedi - sez.~\ref{sec:file_perm_management} e - sez.~\ref{sec:file_file_times}), le impostazioni - degli attributi estesi (con il comando - \cmd{chattr}) e delle ACL, poter ignorare lo - \itindex{sticky~bit} \textit{sticky bit} nella - cancellazione dei file (vedi - sez.~\ref{sec:file_special_perm}), la possibilità - di impostare il flag di \const{O\_NOATIME} con - \func{open} e \func{fcntl} (vedi - sez.~\ref{sec:file_open} e - sez.~\ref{sec:file_fcntl}).\\ - \const{CAP\_FSETID} & La capacità di evitare la cancellazione - automatica dei bit \itindex{suid~bit} \acr{suid} - e \itindex{sgid~bit} \acr{sgid} quando un file - per i quali sono impostati viene modificato da - un processo senza questa capacità e la capacità - di impostare il bit \acr{sgid} su un file anche - quando questo è relativo ad un gruppo cui non si - appartiene (vedi - sez.~\ref{sec:file_perm_management}).\\ - \const{CAP\_KILL} & La capacità di mandare segnali a qualunque - processo (vedi sez.~\ref{sec:sig_kill_raise}).\\ - \const{CAP\_SETGID} & La capacità di manipolare i group ID dei - processi, sia il principale che i supplementari, - (vedi sez.~\ref{sec:proc_setgroups} che quelli - trasmessi tramite i socket \textit{unix domain} - (vedi sez.~\ref{sec:unix_socket}).\\ - \const{CAP\_SETUID} & La capacità di manipolare gli user ID del - processo (con \func{setuid}, \func{setreuid}, - \func{setresuid}, \func{setfsuid}) e di - trasmettere un valore arbitrario - dell'\textsl{uid} nel passaggio delle - credenziali coi socket \textit{unix domain} (vedi - sez.~\ref{sec:unix_socket}).\\ -% -% Linux specific capabilities -% -\hline - \const{CAP\_SETPCAP} & La capacità di impostare o rimuovere una capacità - (limitatamente a quelle che il processo - chiamante ha nel suo insieme di capacità - permesse) da qualunque processo.\\ -% TODO cambiata nel 2.4.24 rc1 ? - \const{CAP\_LINUX\_IMMUTABLE}& La capacità di impostare gli attributi - \textit{immutable} e \itindex{append~mode} - \textit{append only} per i file su un - filesystem che supporta questi - attributi estesi.\\ - \const{CAP\_NET\_BIND\_SERVICE}& La capacità di porre in ascolto server - su porte riservate (vedi - sez.~\ref{sec:TCP_func_bind}).\\ - \const{CAP\_NET\_BROADCAST}& La capacità di consentire l'uso di socket in - \itindex{broadcast} \textit{broadcast} e - \itindex{multicast} \textit{multicast}.\\ - \const{CAP\_NET\_ADMIN} & La capacità di eseguire alcune operazioni - privilegiate sulla rete (impostare le opzioni - privilegiate dei socket, abilitare il - \itindex{multicast} \textit{multicasting}, - impostare interfacce di rete e - tabella di instradamento).\\ - \const{CAP\_NET\_RAW} & La capacità di usare socket \texttt{RAW} e - \texttt{PACKET} (quelli che permettono di creare - pacchetti nei protocolli di basso livello).\\ - \const{CAP\_IPC\_LOCK} & La capacità di effettuare il \textit{memory - locking} \itindex{memory~locking} con le - funzioni \func{mlock}, \func{mlockall}, - \func{shmctl}, \func{mmap} (vedi - sez.~\ref{sec:proc_mem_lock} e - sez.~\ref{sec:file_memory_map}). \\ - \const{CAP\_IPC\_OWNER} & La capacità di evitare il controllo dei permessi - per le operazioni sugli oggetti di - intercomunicazione fra processi (vedi - sez.~\ref{sec:ipc_sysv}).\\ - \const{CAP\_SYS\_MODULE}& La capacità di caricare e rimuovere moduli del - kernel. \\ - \const{CAP\_SYS\_RAWIO} & La capacità di eseguire operazioni sulle porte - di I/O con \func{ioperm} e \func{iopl} (vedi - sez.~\ref{sec:file_io_port}).\\ - \const{CAP\_SYS\_CHROOT}& La capacità di eseguire la funzione - \func{chroot} (vedi - sez.~\ref{sec:file_chroot}).\\ - \const{CAP\_SYS\_PTRACE}& Consente di tracciare qualunque processo con - \func{ptrace} (vedi - sez.~\ref{sec:xxx_ptrace}).\\ - \const{CAP\_SYS\_PACCT} & La capacità di usare le funzioni di - \textit{accounting} dei processi (vedi - sez.~\ref{sec:sys_bsd_accounting}).\\ - \const{CAP\_SYS\_ADMIN} & La capacità di eseguire una serie di compiti - amministrativi (come impostare le quote, - attivare e disattivare la swap, montare, - rimontare e smontare filesystem, ecc.). \\ - \const{CAP\_SYS\_BOOT} & La capacità di fare eseguire un riavvio del - sistema.\\ - \const{CAP\_SYS\_NICE} & La capacità di modificare le priorità dei - processi (vedi sez.~\ref{sec:proc_priority}). \\ - \const{CAP\_SYS\_RESOURCE}& La capacità di superare le limitazioni sulle - risorse, aumentare le quote disco, usare lo - spazio disco riservato all'amministratore.\\ - \const{CAP\_SYS\_TIME} & La capacità di modificare il tempo di sistema - (vedi sez.~\ref{sec:sys_time}).\\ - \const{CAP\_SYS\_TTY\_CONFIG}& La capacità di simulare un \textit{hangup} - della console, con la funzione - \func{vhangup}.\\ - \const{CAP\_MKNOD} & La capacità di creare file di dispositivo con la - funzione \func{mknod} (vedi - sez.~\ref{sec:file_mknod}).\footnotemark\\ - \const{CAP\_LEASE} & La capacità di creare dei \textit{file lease} - \index{file!lease} su di un file (vedi - sez.~\ref{sec:file_asyncronous_lease}) - indipendentemente dalla proprietà dello - stesso.\footnotemark\\ - \const{CAP\_SETFCAP} & La capacità di impostare le - \textit{capabilities} di un file (non - supportata).\\ - \hline - \end{tabular} - \caption{Le costanti che identificano le \textit{capabilities} presenti nel - kernel.} -\label{tab:proc_capabilities} -\end{table} - -\footnotetext[21]{questa capacità è presente soltanto a partire dai kernel - della serie 2.4.x.} - -\footnotetext{questa capacità è presente soltanto a partire dai kernel della - serie 2.4.x.} - -Per gestire questo nuovo meccanismo ciascun processo porta con sé tre distinti -insiemi di \textit{capabilities}, che vengono denominati rispettivamente -\textit{effective}, \textit{permitted} ed \textit{inherited}. Questi insiemi -vengono mantenuti in forma di tre diverse maschere binarie,\footnote{il kernel - li mantiene, come i vari identificatori di sez.~\ref{sec:proc_setuid}, - all'interno della \struct{task\_struct} di ciascun processo (vedi - fig.~\ref{fig:proc_task_struct}), nei tre campi \texttt{cap\_effective}, - \texttt{cap\_inheritable}, \texttt{cap\_permitted} del tipo - \texttt{kernel\_cap\_t}; questo è attualmente definito come intero a 32 bit, - il che comporta un massimo di 32 \textit{capabilities} distinte.} in cui -ciascun bit corrisponde ad una capacità diversa; se ne è riportato -l'elenco,\footnote{si tenga presente che l'elenco delle \textit{capabilities} - presentato questa tabella, ripreso dalla relativa pagina di manuale - (accessibile con \texttt{man capabilities}) e dalle definizioni in - \texttt{sys/capabilities.h}, è quello aggiornato al kernel 2.6.6.} con una -breve descrizione, ed il nome delle costanti che identificano i singoli bit, -in tab.~\ref{tab:proc_capabilities}; la tabella è divisa in due parti, la -prima riporta le \textit{capabilities} previste nella bozza dello standard -POSIX1.e, la seconda quelle specifiche di Linux. - -L'utilizzo di tre distinti insiemi serve a fornire una interfaccia flessibile -per l'uso delle \textit{capabilities}, con scopi analoghi a quelli per cui -sono mantenuti i diversi insiemi di identificatori di -sez.~\ref{sec:proc_setuid}; il loro significato è il seguente: -\begin{basedescript}{\desclabelwidth{2.0cm}\desclabelstyle{\nextlinelabel}} -\item[\textit{effective}] l'insieme delle \textit{capabilities} - ``\textsl{effettive}'', cioè di quelle che vengono effettivamente usate dal - kernel quando deve eseguire il controllo di accesso per le varie operazioni - compiute dal processo. -\item[\textit{permitted}] l'insieme delle \textit{capabilities} - ``\textsl{permesse}'', cioè l'insieme di quelle capacità che un processo - \textsl{può} impostare come \textsl{effettive}. Se un processo cancella una - capacità da questo insieme non potrà più riassumerla (almeno che non esegua - un programma che è \acr{suid} di root). -\item[\textit{inherited}] l'insieme delle \textit{capabilities} - ``\textsl{ereditabili}'', cioè quelle che vengono trasmesse ad un nuovo - programma eseguito attraverso una chiamata ad \func{exec} (con l'eccezione - del caso che questo sia \acr{suid} di root). -\label{sec:capabilities_set} -\end{basedescript} - -Oltre a questi tre insiemi, che sono relativi al singolo processo, il kernel -mantiene un insieme generale valido per tutto il sistema, chiamato -\itindex{capabilities~bounding~set} \textit{capabilities bounding set}. Ogni -volta che un programma viene posto in esecuzione con \func{exec} il contenuto -degli insiemi \textit{effective} e \textit{permitted} vengono mascherati con -un \textsl{AND} binario del contenuto corrente del \textit{capabilities - bounding set}, così che il nuovo processo potrà disporre soltanto delle -capacità in esso elencate. - -Il \textit{capabilities bounding set} è un parametro di sistema, accessibile -attraverso il contenuto del file \procfile{/proc/sys/kernel/cap-bound}, che per -questa sua caratteristica consente di impostare un limite generale alle -capacità che possono essere accordate ai vari processi. Questo valore può -essere impostato ad un valore arbitrario esclusivamente dal primo processo -eseguito nel sistema (di norma cioè da \texttt{/sbin/init}), ogni processo -eseguito successivamente (cioè con \textsl{pid} diverso da 1) anche se -eseguito con privilegi di amministratore potrà soltanto rimuovere uno dei bit -già presenti dell'insieme: questo significa che una volta rimossa una -\textit{capability} dal \textit{capabilities bounding set} essa non sarà più -disponibile, neanche per l'amministratore, a meno di un riavvio. - -Quando un programma viene messo in esecuzione\footnote{cioè quando viene - eseguita la \func{execve} con cui lo si lancia; in corrispondenza di una - \func{fork} le \textit{capabilities} non vengono modificate.} esso eredita -(nel senso che assume negli insiemi \textit{effective} e \textit{permitted}) -le \textit{capabilities} mantenute nell'insieme \textit{inherited}, a meno che -non sia eseguito un programma \acr{suid} di root o la \func{exec} sia stata -eseguita da un programma con \textsl{uid} reale zero; in tal caso il programma -ottiene tutte le \textit{capabilities} presenti nel \textit{capabilities - bounding set}. In questo modo si può far si che ad un processo eseguito in -un secondo tempo possano essere trasmesse solo un insieme limitato di -capacità, impedendogli di recuperare quelle assenti nell'insieme -\textit{inherited}. Si tenga presente invece che attraverso una \func{fork} -vengono mantenute le stesse capacità del processo padre. - -Per la gestione delle \textit{capabilities} il kernel mette a disposizione due -funzioni che permettono rispettivamente di leggere ed impostare i valori dei -tre insiemi illustrati in precedenza. Queste due funzioni sono \funcd{capget} -e \funcd{capset} e costituiscono l'interfaccia di gestione basso livello; i -loro rispettivi prototipi sono: -\begin{functions} - \headdecl{sys/capability.h} - - \funcdecl{int capget(cap\_user\_header\_t hdrp, cap\_user\_data\_t datap)} - Legge le \textit{capabilities}. - - \funcdecl{int capset(cap\_user\_header\_t hdrp, const cap\_user\_data\_t - datap)} - Imposta le \textit{capabilities}. - - - \bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e -1 in caso - di errore, nel qual caso \var{errno} può assumere i valori: - \begin{errlist} - \item[\errcode{ESRCH}] si è fatto riferimento ad un processo inesistente. - \item[\errcode{EPERM}] si è tentato di aggiungere una capacità - nell'insieme delle \textit{capabilities} permesse, o di impostare una - capacità non presente nell'insieme di quelle permesse negli insieme - delle effettive o ereditate, o si è cercato di impostare una - \textit{capability} di un altro processo senza avare - \const{CAP\_SETPCAP}. - \end{errlist} - ed inoltre \errval{EFAULT} ed \errval{EINVAL}. -} - -\end{functions} - -Queste due funzioni prendono come argomenti due tipi di dati dedicati, -definiti come puntatori a due strutture specifiche di Linux, illustrate in -fig.~\ref{fig:cap_kernel_struct}. Per poterle utilizzare occorre anche -cancellare la macro \macro{\_POSIX\_SOURCE}.\footnote{per farlo occorre - utilizzare la direttiva di preprocessore \direct{undef}; si dovrà cioè - inserire una istruzione \texttt{\#undef \_POSIX\_SOURCE} prima di includere - \texttt{sys/capability.h}.} Si tenga presente che le strutture di -fig.~\ref{fig:cap_kernel_struct}, come i prototipi delle due funzioni -\func{capget} e \func{capset}, sono soggette ad essere modificate con il -cambiamento del kernel (in particolare i tipi di dati delle strutture) ed -anche se finora l'interfaccia è risultata stabile, non c'è nessuna -assicurazione che questa venga mantenuta.\footnote{anzi, visto lo scarso - utilizzo di questa funzionalità ci sono state varie discussioni fra gli - sviluppatori del kernel relative all'eliminarla o al modificarla - radicalmente.} Pertanto se si vogliono scrivere programmi portabili che -possano essere eseguiti su qualunque versione del kernel è opportuno -utilizzare le interfacce di alto livello. - -\begin{figure}[!htb] - \footnotesize - \centering - \begin{minipage}[c]{15cm} - \includestruct{listati/cap_user_header_t.h} - \end{minipage} - \normalsize - \caption{Definizione delle strutture a cui fanno riferimento i puntatori - \structd{cap\_user\_header\_t} e \structd{cap\_user\_data\_t} usati per - l'interfaccia di gestione di basso livello delle \textit{capabilities}.} - \label{fig:cap_kernel_struct} -\end{figure} - -La struttura a cui deve puntare l'argomento \param{hdrp} serve ad indicare, -tramite il campo \var{pid}, il processo del quale si vogliono leggere o -modificare le \textit{capabilities}. Il campo \var{version} deve essere -impostato al valore della versione delle usata dal kernel (quello indicato -dalla costante \const{\_LINUX\_CAPABILITY\_VERSION} di -fig.~\ref{fig:cap_kernel_struct}) altrimenti le funzioni ritorneranno con un -errore di \errcode{EINVAL}, restituendo nel campo stesso il valore corretto -della versione in uso. La struttura a cui deve puntare l'argomento -\param{datap} invece conterrà i valori letti o da impostare per i tre insiemi -delle capacità del processo. - -Dato che le precedenti funzioni, oltre ad essere specifiche di Linux, non -garantiscono la stabilità nell'interfaccia, è sempre opportuno effettuare la -gestione delle \textit{capabilities} utilizzando le funzioni di libreria a -questo dedicate. Queste funzioni, che seguono quanto previsto nelle bozze -dello standard POSIX.1e, non fanno parte delle \acr{glibc} e sono fornite in -una libreria a parte,\footnote{la libreria è \texttt{libcap2}, nel caso di - Debian può essere installata con il pacchetto omonimo.} pertanto se un -programma le utilizza si dovrà indicare esplicitamente l'uso della suddetta -libreria attraverso l'opzione \texttt{-lcap} del compilatore. - -Le funzioni dell'interfaccia delle bozze di POSIX.1e prevedono l'uso di uno -tipo di dato opaco, \type{cap\_t}, come puntatore ai dati mantenuti nel -cosiddetto \textit{capability state},\footnote{si tratta in sostanza di un - puntatore ad una struttura interna utilizzata dalle librerie, i cui campi - non devono mai essere acceduti direttamente.} in sono memorizzati tutti i -dati delle \textit{capabilities}. In questo modo è possibile mascherare i -dettagli della gestione di basso livello, che potranno essere modificati senza -dover cambiare le funzioni dell'interfaccia, che faranno riferimento soltanto -ad oggetti di questo tipo. L'interfaccia pertanto non soltanto fornisce le -funzioni per modificare e leggere le \textit{capabilities}, ma anche quelle -per gestire i dati attraverso \type{cap\_t}. - -La prima funzione dell'interfaccia è quella che permette di inizializzare un -\textit{capability state}, allocando al contempo la memoria necessaria per i -relativi dati. La funzione è \funcd{cap\_init} ed il suo prototipo è: -\begin{functions} - \headdecl{sys/capability.h} - - \funcdecl{cap\_t cap\_init(void)} - Crea ed inizializza un \textit{capability state}. - - \bodydesc{La funzione ritorna un valore non nullo in caso di successo e - \macro{NULL} in caso di errore, nel qual caso \var{errno} assumerà il - valore \errval{ENOMEM}. - } -\end{functions} - -La funzione restituisce il puntatore \type{cap\_t} ad uno stato inizializzato -con tutte le \textit{capabilities} azzerate. In caso di errore (cioè quando -non c'è memoria sufficiente ad allocare i dati) viene restituito \macro{NULL} -ed \var{errno} viene impostata a \errval{ENOMEM}. La memoria necessaria a -mantenere i dati viene automaticamente allocata da \func{cap\_init}, ma dovrà -essere disallocata esplicitamente quando non è più necessaria utilizzando, per -questo l'interfaccia fornisce una apposita funzione, \funcd{cap\_free}, il cui -prototipo è: -\begin{functions} - \headdecl{sys/capability.h} - - \funcdecl{int cap\_free(void *obj\_d)} - Disalloca la memoria allocata per i dati delle \textit{capabilities}. - - \bodydesc{La funzione ritorna 0 in caso di successo e $-1$ in caso di - errore, nel qual caso \var{errno} assumerà il valore \errval{EINVAL}. - } -\end{functions} - -La funzione permette di liberare la memoria allocata dalle altre funzioni -della libreria sia per un \textit{capability state}, nel qual caso l'argomento -dovrà essere un dato di tipo \type{cap\_t}, che per una descrizione testuale -dello stesso,\footnote{cioè quanto ottenuto tramite la funzione - \func{cap\_to\_text}.} nel qual caso l'argomento dovrà essere un dato di -tipo \texttt{char *}. Per questo l'argomento \param{obj\_d} è dichiarato come -\texttt{void *} e deve sempre corrispondere ad un puntatore ottenuto tramite -le altre funzioni della libreria, altrimenti la funzione fallirà con un errore -di \errval{EINVAL}. - -Infine si può creare una copia di un \textit{capability state} ottenuto in -precedenza tramite la funzione \funcd{cap\_dup}, il cui prototipo è: -\begin{functions} - \headdecl{sys/capability.h} - - \funcdecl{cap\_t cap\_dup(cap\_t cap\_p)} - Duplica un \textit{capability state} restituendone una copia. - - \bodydesc{La funzione ritorna un valore non nullo in caso di successo e - \macro{NULL} in caso di errore, nel qual caso \var{errno} potrà assumere i - valori \errval{ENOMEM} o \errval{EINVAL}. - } -\end{functions} - -La funzione crea una copia del \textit{capability state} posto all'indirizzo -\param{cap\_p} che si è passato come argomento, restituendo il puntatore alla -copia, che conterrà gli stessi valori delle \textit{capabilities} presenti -nell'originale. La memoria necessaria viene allocata automaticamente dalla -funzione. Una volta effettuata la copia i due \textit{capability state} -potranno essere modificati in maniera completamente -indipendente.\footnote{alla fine delle operazioni si ricordi però di - disallocare anche la copia, oltre all'originale. } - -Una seconda classe di funzioni di servizio previste dall'interfaccia sono -quelle per la gestione dei dati contenuti all'interno di un \textit{capability - state}; la prima di queste è \funcd{cap\_clear}, il cui prototipo è: -\begin{functions} - \headdecl{sys/capability.h} - - \funcdecl{int cap\_clear(cap\_t cap\_p)} - Inizializza un \textit{capability state} cancellando tutte le - \textit{capabilities}. - - \bodydesc{La funzione ritorna 0 in caso di successo e $-1$ in caso di - errore, nel qual caso \var{errno} assumerà il valore \errval{EINVAL}. - } -\end{functions} - -La funzione si limita ad azzerare tutte le \textit{capabilities} presenti nel -\textit{capability state} all'indirizzo \param{cap\_p} passato come argomento, -restituendo uno stato \textsl{vuoto}, analogo a quello che si ottiene nella -creazione con \func{cap\_init}. - -Per la gestione dei valori delle \textit{capabilities} presenti in un -\textit{capability state} l'interfaccia prevede due funzioni, -\funcd{cap\_get\_flag} e \funcd{cap\_set\_flag}, che permettono -rispettivamente di leggere o impostare il valore di un flag delle -\textit{capabilities}; i rispettivi prototipi sono: -\begin{functions} - \headdecl{sys/capability.h} - - \funcdecl{int cap\_get\_flag(cap\_t cap\_p, cap\_value\_t cap, cap\_flag\_t - flag, cap\_flag\_value\_t *value\_p)} - Legge il valore di una \textit{capability}. - - \funcdecl{int cap\_set\_flag(cap\_t cap\_p, cap\_flag\_t flag, int ncap, - cap\_value\_t *caps, cap\_flag\_value\_t value)} - Imposta il valore di una \textit{capability}. - - \bodydesc{Le funzioni ritornano 0 in caso di successo e $-1$ in caso di - errore, nel qual caso \var{errno} assumerà il valore \errval{EINVAL}. -} -\end{functions} - -In entrambe le funzioni l'argomento \param{cap\_p} indica il puntatore al -\textit{capability state} su cui operare, mentre l'argomento \param{flag} -indica su quale dei tre insiemi illustrati a -pag.~\pageref{sec:capabilities_set} si intende operare. Questi devono essere -specificati con una variabile di tipo \type{cap\_flag\_t} che può assumere -esclusivamente\footnote{si tratta in effetti di un tipo enumerato, come si può - verificare dalla sua definizione che si trova in - \texttt{/usr/include/sys/capability.h}.} uno dei valori illustrati in -tab.~\ref{tab:cap_set_identifier}. - -\begin{table}[htb] - \centering - \footnotesize - \begin{tabular}[c]{|l|l|} - \hline - \textbf{Valore} & \textbf{Significato} \\ - \hline - \hline - \const{CAP\_EFFECTIVE} & Capacità dell'insieme \textsl{effettivo}.\\ - \const{CAP\_PERMITTED} & Capacità dell'insieme \textsl{permesso}.\\ - \const{CAP\_INHERITABLE}& Capacità dell'insieme \textsl{ereditabile}.\\ - \hline - \end{tabular} - \caption{Valori possibili per il tipo di dato \type{cap\_flag\_t} che - identifica gli insiemi delle \textit{capabilities}.} - \label{tab:cap_set_identifier} -\end{table} - -La capacità che si intende controllare o impostare invece deve essere -specificata attraverso una variabile di tipo \type{cap\_value\_t}, che può -prendere come valore uno qualunque di quelli riportati in -tab.~\ref{tab:proc_capabilities}, in questo caso però non è possibile -combinare diversi valori in una maschera binaria, una variabile di tipo -\type{cap\_value\_t} deve indicare una sola capacità.\footnote{nel file di - header citato nella nota precedente il tipo \type{cap\_value\_t} è definito - come \ctyp{int}, ma i valori validi sono soltanto quelli di - tab.~\ref{tab:proc_capabilities}.} - -Infine lo stato di una capacità è descritto ad una variabile di tipo -\type{cap\_flag\_value\_t}, che a sua volta può assumere soltanto -uno\footnote{anche questo è un tipo enumerato.} dei valori di -tab.~\ref{tab:cap_value_type}. - -\begin{table}[htb] - \centering - \footnotesize - \begin{tabular}[c]{|l|l|} - \hline - \textbf{Valore} & \textbf{Significato} \\ - \hline - \hline - \const{CAP\_CLEAR}& La capacità non è impostata.\\ - \const{CAP\_SET} & La capacità è impostata.\\ - \hline - \end{tabular} - \caption{Valori possibili per il tipo di dato \type{cap\_flag\_value\_t} che - indica lo stato di una capacità.} - \label{tab:cap_value_type} -\end{table} - -La funzione \func{cap\_get\_flag} legge lo stato della capacità indicata -dall'argomento \param{cap} all'interno dell'insieme indicato dall'argomento -\param{flag} e ne restituisce il valore nella variabile posta all'indirizzo -puntato dall'argomento \param{value\_p}; è possibile cioè leggere soltanto uno -stato di una capacità alla volta. - -La funzione \func{cap\_set\_flag} può invece impostare in una sola chiamata -più \textit{capabilities}, anche se solo all'interno dello stesso insieme. Per -questo motivo essa prende un vettore di valori di tipo \type{cap\_value\_t} -nell'argomento \param{caps}, la cui dimensione viene specificata dall'argomento -\param{ncap}. Il tipo di impostazione da eseguire (cancellazione o -impostazione) viene indicato dall'argomento \param{value}. - -Per la visualizzazione dello stato delle \textit{capabilities} l'interfaccia -prevede una funzione apposita, \funcd{cap\_to\_text}, il cui prototipo è: -\begin{functions} - \headdecl{sys/capability.h} - - \funcdecl{char * cap\_to\_text(cap\_t caps, ssize\_t * length\_p)} - - Genera una visualizzazione testuale delle \textit{capabilities}. - - \bodydesc{La funzione ritorna un puntatore alla stringa con la descrizione - delle \textit{capabilities} in caso di successo e \val{NULL} in caso di - errore, nel qual caso \var{errno} può assumere i valori \errval{EINVAL} o - \errval{ENOMEM}. - } -\end{functions} - -La funzione ritorna l'indirizzo di una stringa contente la descrizione -testuale del contenuto del \textit{capabilities state} \param{caps} passato -come argomento, e, qualora l'argomento \param{length\_p} sia diverso da -\val{NULL}, restituisce nella variabile intera da questo puntata la lunghezza -della stringa. La stringa restituita viene allocata automaticamente dalla -funzione e pertanto dovrà essere liberata con \func{cap\_free}. - -Fin quei abbiamo trattato solo le funzioni di servizio relative alla -manipolazione dei \textit{capabilities state}; l'interfaccia di gestione -prevede però anche le funzioni per la gestione delle \textit{capabilities} -stesse. La prima di queste è \funcd{cap\_get\_proc} che consente la lettura -delle \textit{capabilities} del processo corrente, il suo prototipo è: -\begin{functions} - \headdecl{sys/capability.h} - - \funcdecl{cap\_t cap\_get\_proc(void)} - Legge le \textit{capabilities} del processo corrente. - - \bodydesc{La funzione ritorna un valore diverso da \val{NULL} in caso di - successo e \val{NULL} in caso di errore, nel qual caso \var{errno} può - assumere i valori \errval{EINVAL}, \errval{EPERM} o \errval{ENOMEM}. } -\end{functions} - -La funzione legge il valore delle \textit{capabilities} associate al processo -da cui viene invocata, restituendo il risultato tramite il puntatore ad un -\textit{capabilities state} contenente tutti i dati che provvede ad allocare -autonomamente e che di nuovo occorrerà liberare con \func{cap\_free} quando -non sarà più utilizzato. - -Se invece si vogliono leggere le \textit{capabilities} di un processo -specifico occorre usare la funzione \funcd{capgetp}, il cui -prototipo\footnote{su alcune pagine di manuale la funzione è descritta con un - prototipo sbagliato, che prevede un valore di ritorno di tipo \type{cap\_t}, - ma il valore di ritorno è intero, come si può verificare anche dalla - dichiarazione della stessa in \texttt{sys/capability.h}.} è: -\begin{functions} - \headdecl{sys/capability.h} - - \funcdecl{int capgetp(pid\_t pid, cap\_t cap\_d)} - Legge le \textit{capabilities} del processo indicato da \param{pid}. - - \bodydesc{La funzione ritorna 0 in caso di successo e $-1$ in caso di - errore, nel qual caso \var{errno} può assumere i valori \errval{EINVAL}, - \errval{EPERM} o \errval{ENOMEM}. - } -\end{functions} -%TODO controllare e correggere i codici di errore!!! - -La funzione legge il valore delle \textit{capabilities} del processo indicato -con l'argomento \param{pid}, e restituisce il risultato nel -\textit{capabilities state} posto all'indirizzo indicato con l'argomento -\param{cap\_d}; a differenza della precedente in questo caso il -\textit{capability state} deve essere stato creato in precedenza. Qualora il -processo indicato non esista si avrà un errore di \errval{ESRCH}. Gli stessi -valori possono essere letti direttamente nel filesystem \textit{proc}, nei -file \texttt{/proc//status}; ad esempio per \texttt{init} si otterrà -qualcosa del tipo: -\begin{Verbatim} -... -CapInh: 0000000000000000 -CapPrm: 00000000fffffeff -CapEff: 00000000fffffeff -... -\end{Verbatim} - -Infine per impostare le \textit{capabilities} del processo corrente (non -esiste una funzione che permetta di cambiare le \textit{capabilities} di un -altro processo) si deve usare la funzione \funcd{cap\_set\_proc}, il cui -prototipo è: -\begin{functions} - \headdecl{sys/capability.h} - - \funcdecl{int cap\_set\_proc(cap\_t cap\_p)} - Imposta le \textit{capabilities} del processo corrente. - - \bodydesc{La funzione ritorna 0 in caso di successo e $-1$ in caso di - errore, nel qual caso \var{errno} può assumere i valori \errval{EINVAL}, - \errval{EPERM} o \errval{ENOMEM}. - } -\end{functions} - -La funzione modifica le \textit{capabilities} del processo corrente secondo -quanto specificato con l'argomento \param{cap\_p}, posto che questo sia -possibile nei termini spiegati in precedenza (non sarà ad esempio possibile -impostare capacità non presenti nell'insieme di quelle permesse). In caso di -successo i nuovi valori saranno effettivi al ritorno della funzione, in caso -di fallimento invece lo stato delle capacità resterà invariato. Si tenga -presente che \textsl{tutte} le capacità specificate tramite \param{cap\_p} -devono essere permesse; se anche una sola non lo è la funzione fallirà, e per -quanto appena detto, lo stato delle \textit{capabilities} non verrà modificato -(neanche per le parti eventualmente permesse). - -Come esempio di utilizzo di queste funzioni nei sorgenti allegati alla guida -si è distribuito il programma \texttt{getcap.c}, che consente di leggere le -\textit{capabilities} del processo corrente\footnote{vale a dire di sé stesso, - quando lo si lancia, il che può sembrare inutile, ma serve a mostrarci quali - sono le \textit{capabilities} standard che ottiene un processo lanciato - dalla riga di comando.} o tramite l'opzione \texttt{-p}, quelle di un -processo qualunque il cui pid viene passato come parametro dell'opzione. - -\begin{figure}[htb] - \footnotesize \centering - \begin{minipage}[c]{15cm} - \includecodesample{listati/getcap.c} - \end{minipage} - \normalsize - \caption{Corpo principale del programma \texttt{getcap.c}.} - \label{fig:proc_getcap} -\end{figure} - -La sezione principale del programma è riportata in fig.~\ref{fig:proc_getcap}, -e si basa su una condizione sulla variabile \var{pid} che se si è usato -l'opzione \texttt{-p} è impostata (nella sezione di gestione delle opzioni, -che si è tralasciata) al valore del \textsl{pid} del processo di cui si vuole -leggere le \textit{capabilities} e nulla altrimenti. Nel primo caso -(\texttt{\small 1--6}) si utilizza direttamente (\texttt{\small 2}) -\func{cap\_get\_proc} per ottenere lo stato delle capacità del processo, nel -secondo (\texttt{\small 7--14}) prima si inizializza (\texttt{\small 8}) uno -stato vuoto e poi (\texttt{\small 9}) si legge il valore delle capacità del -processo indicato. - -Il passo successivo è utilizzare (\texttt{\small 16}) \func{cap\_to\_text} per -tradurre in una stringa lo stato, e poi (\texttt{\small 17}) stamparlo; infine -(\texttt{\small 19--20}) si libera la memoria allocata dalle precedenti -funzioni con \func{cap\_free} per poi ritornare dal ciclo principale della -funzione. - -\itindend{capabilities} - -% TODO vedi http://lwn.net/Articles/198557/ e -% http://www.madore.org/~david/linux/newcaps/ -% TODO documentare prctl ... - -% TODO: rivedere alla luce degli aggiornamenti del 2.6 (man sched_setscheduler) - \section{La gestione della priorità di esecuzione} \label{sec:proc_priority} @@ -2822,6 +2095,7 @@ attivi. In particolare prenderemo in esame i vari meccanismi con cui viene gestita l'assegnazione del tempo di CPU, ed illustreremo le varie funzioni di gestione. +% TODO: rivedere alla luce degli aggiornamenti del 2.6 (man sched_setscheduler) \subsection{I meccanismi di \textit{scheduling}} \label{sec:proc_sched} @@ -2866,7 +2140,7 @@ kernel provvedere a mettere in esecuzione un altro processo. Tutte queste possibilità sono caratterizzate da un diverso \textsl{stato} del processo, in Linux un processo può trovarsi in uno degli stati riportati in tab.~\ref{tab:proc_proc_states}; ma soltanto i processi che sono nello stato -\textit{runnable} concorrono per l'esecuzione. Questo vuol dire che, qualunque +\textbf{Runnable} concorrono per l'esecuzione. Questo vuol dire che, qualunque sia la sua priorità, un processo non potrà mai essere messo in esecuzione fintanto che esso si trova in uno qualunque degli altri stati. @@ -2892,12 +2166,12 @@ fintanto che esso si trova in uno qualunque degli altri stati. \const{SIGSTOP}, o è tracciato.\\ \textbf{Zombie}\index{zombie} & \texttt{Z} & Il processo è terminato ma il suo stato di terminazione non è ancora - stato letto dal padre. \\ + stato letto dal padre.\\ \textbf{Killable}& \texttt{D} & Un nuovo stato introdotto con il kernel 2.6.25, sostanzialmente identico all'\textbf{Uninterrutible Sleep} con la sola differenza che il processo può - terminato (con \const{SIGKILL}). \\ + terminato (con \const{SIGKILL}).\\ \hline \end{tabular} \caption{Elenco dei possibili stati di un processo in Linux, nella colonna @@ -2959,44 +2233,46 @@ bisogno della CPU. A meno che non si abbiano esigenze specifiche, l'unico meccanismo di scheduling con il quale si avrà a che fare è quello tradizionale, che prevede solo priorità dinamiche. È di questo che, di norma, ci si dovrà preoccupare -nella programmazione. - -Come accennato in Linux tutti i processi ordinari hanno la stessa priorità -assoluta. Quello che determina quale, fra tutti i processi in attesa di -esecuzione, sarà eseguito per primo, è la priorità dinamica, che è chiamata -così proprio perché varia nel corso dell'esecuzione di un processo. Oltre a -questo la priorità dinamica determina quanto a lungo un processo continuerà ad -essere eseguito, e quando un processo potrà subentrare ad un altro -nell'esecuzione. - -Il meccanismo usato da Linux è piuttosto semplice,\footnote{in realtà nella - serie 2.6.x lo scheduler è stato riscritto da zero e può usare diversi - algoritmi, selezionabili sia in fase di compilazione, che, nelle versioni - più recenti, all'avvio (addirittura è stato ideato un sistema modulare che - permette di cambiare lo scheduler al volo, che comunque non è incluso nel - kernel ufficiale).} ad ogni processo è assegnata una \textit{time-slice}, -cioè un intervallo di tempo (letteralmente una fetta) per il quale esso deve -essere eseguito. Il valore della \textit{time-slice} è controllato dalla -cosiddetta \textit{nice} (o \textit{niceness}) del processo. Essa è contenuta -nel campo \var{nice} di \struct{task\_struct}; tutti i processi vengono creati -con lo stesso valore, ed essa specifica il valore della durata iniziale della -\textit{time-slice} che viene assegnato ad un altro campo della struttura -(\var{counter}) quando il processo viene eseguito per la prima volta e -diminuito progressivamente ad ogni interruzione del timer. - -Durante la sua esecuzione lo scheduler scandisce la coda dei processi in stato -\textit{runnable} associando, in base al valore di \var{counter}, un peso ad -ogni processo in attesa di esecuzione,\footnote{il calcolo del peso in realtà - è un po' più complicato, ad esempio nei sistemi multiprocessore viene - favorito un processo eseguito sulla stessa CPU, e a parità del valore di - \var{counter} viene favorito chi ha una priorità più elevata.} chi ha il -peso più alto verrà posto in esecuzione, ed il precedente processo sarà -spostato in fondo alla coda. Dato che ad ogni interruzione del timer il -valore di \var{counter} del processo corrente viene diminuito, questo assicura -che anche i processi con priorità più bassa verranno messi in esecuzione. +nella programmazione. Come accennato in Linux i processi ordinari hanno tutti +una priorità assoluta nulla; quello che determina quale, fra tutti i processi +in attesa di esecuzione, sarà eseguito per primo, è la cosiddetta +\textsl{priorità dinamica},\footnote{quella che viene mostrata nella colonna + \texttt{PR} del comando \texttt{top}.} che è chiamata così proprio perché +varia nel corso dell'esecuzione di un processo. + +Il meccanismo usato da Linux è in realtà piuttosto complesso,\footnote{e + dipende strettamente dalla versione di kernel; in particolare a partire + dalla serie 2.6.x lo scheduler è stato riscritto completamente, con molte + modifiche susseguitesi per migliorarne le prestazioni, per un certo periodo + ed è stata anche introdotta la possibilità di usare diversi algoritmi, + selezionabili sia in fase di compilazione, che, nelle versioni più recenti, + all'avvio (addirittura è stato ideato un sistema modulare che permette di + cambiare lo scheduler al volo, che comunque non è incluso nel kernel + ufficiale).} ma a grandi linee si può dire che ad ogni processo è assegnata +una \textit{time-slice}, cioè un intervallo di tempo (letteralmente una fetta) +per il quale, a meno di eventi esterni, esso viene eseguito senza essere +interrotto. Il valore della \textit{time-slice} è stabilito dalla sua +cosiddetta \textit{nice} (o \textit{niceness}) del processo. Questo è un +valore, che di default è nullo, e che oltre a essere associato alla lunghezza +della \textit{timesllce} viene anche sommato alla priorità dinamica di ciascun +processo. Questa viene calcolata dallo scheduler e viene \textsl{diminuita} +tutte le volte che un processo è in stato \textbf{Runnable} ma non viene posto +in esecuzione. Lo scheduler infatti mette sempre in esecuzione, fra tutti i +processi in stato \textbf{Runnable}, quello che ha la priorità dinamica più +bassa.\footnote{in realtà il calcolo della priorità dinamica e la scelta di + quale processo mettere in esecuzione avviene con un algoritmo più + complicato, (per una buona trattazione vedi \cite{XXX}), ad esempio nei + sistemi multiprocessore viene favorito un processo eseguito sulla stessa + CPU.} La priorità di un processo è così controllata attraverso il valore di -\var{nice}, che stabilisce la durata della \textit{time-slice}; per il +\var{nice}, che stabilisce la durata della \textit{time-slice} (un valore di +nice più alto corrisponde ad una \textit{time-sl}, ed ovviamente +più questa è ampia e più lungo sarà il tempo che esso resta in esecuzione in +esecuzione. Ma per il meccanismo appana descritto, andando a sommarsi alla +priorità dianamica, essa tenderà anche a sfavorire (o fa + +per il meccanismo appena descritto infatti un valore più lungo assicura una maggiore attribuzione di CPU. L'origine del nome di questo parametro sta nel fatto che generalmente questo viene usato per diminuire la priorità di un processo, come @@ -3205,9 +2481,11 @@ La funzione esegue l'impostazione per il processo specificato dall'argomento \param{pid}; un valore nullo esegue l'impostazione per il processo corrente. La politica di scheduling è specificata dall'argomento \param{policy} i cui possibili valori sono riportati in tab.~\ref{tab:proc_sched_policy}; un valore -negativo per \param{policy} mantiene la politica di scheduling corrente. -Solo un processo con i privilegi di amministratore può impostare priorità -assolute diverse da zero o politiche \const{SCHED\_FIFO} e \const{SCHED\_RR}. +negativo per \param{policy} mantiene la politica di scheduling corrente. Solo +un processo con i privilegi di amministratore\footnote{più precisamente con la + \itindex{capabilities} \textit{capability} \const{CAP\_SYS\_NICE}, vedi + sez.~\ref{sec:proc_capabilities}.} può impostare priorità assolute diverse +da zero o politiche \const{SCHED\_FIFO} e \const{SCHED\_RR}. \begin{table}[htb] \centering @@ -3222,7 +2500,8 @@ assolute diverse da zero o politiche \const{SCHED\_FIFO} e \const{SCHED\_RR}. Robin}. \\ \const{SCHED\_OTHER}& Scheduling ordinario.\\ \const{SCHED\_BATCH}& Scheduling ordinario con l'assunzione ulteriore di - lavoro \textit{CPU intensive}.\footnotemark\\ + lavoro \textit{CPU intensive}.\footnotemark\\ + \const{SCHED\_IDLE} & Scheduling di priorità estremamente bassa.\\ \hline \end{tabular} \caption{Valori dell'argomento \param{policy} per la funzione @@ -3232,8 +2511,6 @@ assolute diverse da zero o politiche \const{SCHED\_FIFO} e \const{SCHED\_RR}. \footnotetext{introdotto con il kernel 2.6.16.} -% TODO manca SCHED_IDLE - Il valore della priorità è passato attraverso la struttura \struct{sched\_param} (riportata in fig.~\ref{fig:sig_sched_param}), il cui solo campo attualmente definito è \var{sched\_priority}, che nel caso delle