Programma di esempio delle funzioni delle capabilities, e un po' di
[gapil.git] / prochand.tex
index 443bc4772a3364ae909f5c454c9ee6746b2ff47a..4af6ea92cd27ba140ef19b19b6d417b2d7ea4e32 100644 (file)
@@ -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
@@ -2060,7 +2059,7 @@ implementata.\footnote{per attualmente si intende fino al kernel 2.6.13, e
 \label{tab:proc_capabilities}
 \end{table}
 
-\footnotetext[18]{questa capacità è presente soltato a partire dai kernel
+\footnotetext[21]{questa capacità è presente soltato a partire dai kernel
   della serie 2.4.x.}
 
 \footnotetext{questa capacità è presente soltato a partire dai kernel 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
@@ -2089,24 +2088,24 @@ 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è quelle che vengono effettivamente usate dal
-  kernel per eseguire il controllo di accesso per le operazioni compiute dal
-  processo.
+  ``\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 che un processo \textsl{può}
-  impostare come \textsl{effettive} se ha la capacità \const{CAP\_SETPCAP}. Se
-  un processo cancella una capacità da questo insieme non potrà più
-  riassumerla (almeno che non esegua un programma che è \acr{suid} di root).
+  ``\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{ereditate}, 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).
+  ``\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
-\index{capabilities~bounding~set} \textit{capabilities bounding set}. Ogni
+\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
@@ -2120,27 +2119,335 @@ 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 da esso una
-\textit{capability} 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 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
-  bounding set}.
+  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. 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/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 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} 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.
 
+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} 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ù capacità, anche se solo all'interno dello stesso insieme; per questo essa
+prende un vettore di valori di tipo \type{cap\_value\_t} nell'argomento
+\param{caps}, la cui dimensione è specificata dall'argomento \param{ncap}. Il
+tipo di impostazione da eseguire (cancellazione o impostazione) viene indicato
+dall'argomento \param{value}.
+
+Fin quei abbiamo trattato delle funzioni di manipolazione dei
+\textit{capabilities state}; quando si vuole eseguire la lettura delle
+\textit{capabilities} del processo corrente si deve usare la funzione
+\funcd{cap\_get\_proc}, il cui 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} del processo corrente
+e restituisce il puntatore ad un \textit{capabilities state} contenente il
+risultato, che provvede ad allocare autonomamente, e che 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}
+
+La funzione legge il valore delle \textit{capabilities} del processo indicato
+con l'argomento \param{pid}, salvando il risultato nel \textit{capabilities
+  state} all'indirizzo \param{cap\_d} che deve essere stato creato in
+precedenza. Qualora il processo non esista si avrà un errore di \errval{}.
 
 
 
@@ -2148,6 +2455,8 @@ ottiene tutte le \textit{capabilities} presenti nel \textit{capabilities
 \itindend{capabilities}
 
 
+
+
 \section{La gestione della priorità di esecuzione}
 \label{sec:proc_priority}
 
@@ -2962,7 +3271,7 @@ file, o nell'accesso a meccanismi di intercomunicazione come la memoria
 condivisa. In questi casi, se non si dispone della possibilità di eseguire
 atomicamente le operazioni necessarie, occorre che quelle parti di codice in
 cui si compiono le operazioni sulle risorse condivise (le cosiddette
-\textsl{sezioni critiche}\index{sezioni~critiche}) del programma, siano
+\textsl{sezioni critiche}\index{sezione~critica}) del programma, siano
 opportunamente protette da meccanismi di sincronizzazione (torneremo su queste
 problematiche di questo tipo in cap.~\ref{cha:IPC}).