From 28399c57e0e3a14a65c60b4d83b43527826c2e62 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sat, 19 Nov 2005 23:16:06 +0000 Subject: [PATCH] Altro materiale sulle capabilities. --- prochand.tex | 280 +++++++++++++++++++++++++++++++++++++++++------ sources/Makefile | 3 + 2 files changed, 248 insertions(+), 35 deletions(-) diff --git a/prochand.tex b/prochand.tex index bd0cd21..56c7f4f 100644 --- a/prochand.tex +++ b/prochand.tex @@ -1867,7 +1867,6 @@ 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 @@ -2074,14 +2073,14 @@ vengono mantenuti in forma di tre diverse maschere binarie,\footnote{il kernel 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} (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}), è 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}. + \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}), è 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}. 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 @@ -2098,9 +2097,10 @@ sez.~\ref{sec:proc_setuid}; il loro significato 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{ereditate}'', cioè quelle che vengono trasmesse ad un nuovo + ``\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 @@ -2119,14 +2119,16 @@ capacit 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 può al più rimuovere uno dei bit -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 viene messo in esecuzione (con \func{exec}) un processo eredita (nel -senso che assume negli insiemi \textit{effective} e \textit{permitted}) le -\textit{capabilities} mantenute nell'insieme \textit{inherited}, a meno che +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 @@ -2136,9 +2138,11 @@ capacit \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} Linux usa due funzioni, -\funcd{capget} e \funcd{capset}, che permettono rispettivamente di leggerne ed -impostarne i valori, i cui rispettivi prototipi sono: +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} @@ -2161,39 +2165,243 @@ impostarne i valori, i cui rispettivi prototipi sono: \textit{capability} di un altro processo senza avare \const{CAP\_SETPCAP}. \end{errlist} - ed inoltre \errval{EFAULT} ed \errval{EINVAL}} -\end{functions} + ed inoltre \errval{EFAULT} ed \errval{EINVAL}. +} -Queste due funzioni costituiscono una interfaccia di basso livello, ed usano -due strutture specifiche di Linux, la cui definizione è riportata in -fig.~\ref{fig:cap_kernel_struct}. Queste ultime, come le due funzioni -precedenti, 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, +\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. Pertando 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/tms.h} + \includestruct{listati/cap_user_header_t.h} \end{minipage} \normalsize - \caption{Le strutture specifiche di Linux per l'interfaccia di gestione di - basso livello delle \textit{capabilities}.} + \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 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 fornirà 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 è allora 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} -sono definite in una apposita struttura del kernel, + \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} -Per la gestione delle \textit{capabilities} lo standard POSIX.1e prevede l'uso -di uno specifico tipo di dato \type{cap\_t}, che +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 suffuciente 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 la +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 di tipo +\texttt{char *}. L'argomento \param{obj\_d} deve corrispondere ad un oggetto +ottenuto tramite 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} \param{cap\_p} +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. + +Una seconda classe di funzioni di servizio sono quelle per la gestione dei +dati contenuti all'interno di un \textit{capability state}; la prima di esse è +\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} \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 +\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. Questo deve essere +specificato con una variabile di tipo \type{cap\_flag\_t} e 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 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 +\textit{capabilities}.\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 \textit{capabilities} è 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 alla volta. + +La funzione \func{cap\_set\_flag} può invece impostare più capacità, anche se +solo all'interno dello stesso insieme, in una sola chiamata. @@ -2201,6 +2409,8 @@ di uno specifico tipo di dato \type{cap\_t}, che \itindend{capabilities} + + \section{La gestione della priorità di esecuzione} \label{sec:proc_priority} diff --git a/sources/Makefile b/sources/Makefile index 7832b6d..3d20078 100644 --- a/sources/Makefile +++ b/sources/Makefile @@ -115,6 +115,9 @@ wwwd: wwwd.c acctctrl: AcctCtrl.c $(CC) $(CFLAGS) $^ -o $@ +printcap: + $(CC) $(CFLAGS) $^ -o $@ + # Macro per la generazione della tarball dei sorgenti package: clean gapil_source.tgz -- 2.30.2