Aggiunte sugli IPC generici (controllo di accesso) e messa una vecchia
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index 3bf821c56c6da3fb19dcf4028754f089f0b0c4f1..261de58ac9e57599f89f96c98bc551b1af6d8141 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -10,13 +10,12 @@ diversi, come quelli tradizionali che coinvolgono \textit{pipe} e
 
 Tralasceremo invece tutte le problematiche relative alla comunicazione
 attraverso la rete (e le relative interfacce) che saranno affrontate in
-dettaglio in un secondo tempo.  Non affronteremo invece meccanismi più
+dettaglio in un secondo tempo.  Non affronteremo neanche meccanismi più
 complessi ed evoluti come le RPC (\textit{Remote Procedure Calls}) e CORBA
 (\textit{Common Object Request Brocker Architecture}) che in genere sono
 implementati con un ulteriore livello sopra i meccanismi elementari.
 
 
-
 \section{La comunicazione fra processi tradizionale}
 \label{sec:ipc_unix}
 
@@ -94,8 +93,9 @@ ordinarie dei file, ma ci mostra anche qual'
   unidirezionale, ma in realtà questo è un limite facilmente superabile usando
   una coppia di pipe.} limite nell'uso delle pipe. È necessario infatti che i
 processi possano condividere i file descriptor della pipe, e per questo essi
-devono comunque derivare da uno stesso processo padre in cui è avvenuta la
-creazione della pipe, o, più comunemente, essere nella relazione padre/figlio.
+devono comunque essere \textsl{parenti} (dall'inglese \textit{siblings}), cioè
+o derivare da uno stesso processo padre in cui è avvenuta la creazione della
+pipe, o, più comunemente, essere nella relazione padre/figlio.
 
 A differenza di quanto avviene con i file normali, la lettura da una pipe può
 essere bloccante (qualora non siano presenti dati), inoltre se si legge da una
@@ -583,9 +583,9 @@ molti altri devono poter leggere non pu
 
 Per questo nello sviluppo di System V vennero introdotti una serie di nuovi
 oggetti per la comunicazione fra processi ed una nuova interfaccia di
-programmazione, che fossero in grado di garantire una maggiore flessibilità;
-in questa sezione esamineremo quello che viene ormai chiamato il
-\textsl{Sistema di comunicazione inter-processo} di System V, (o
+programmazione, che fossero in grado di garantire una maggiore flessibilità.
+In questa sezione esamineremo come Linux supporta quello che viene ormai
+chiamato il \textsl{Sistema di comunicazione inter-processo} di System V, o
 \textit{System V IPC (Inter-Process Comunication)}.
 
 
@@ -604,38 +604,293 @@ fino al riavvio del sistema.
 
 Gli oggetti usati nel System V IPC vengono creati direttamente dal kernel, e
 sono accessibili solo specificando il relativo \textsl{identificatore}. Questo
-è il numero progressivo che il kernel assengna a ciascuno di questi oggetti
-quanto vengono creati (il prodedimento è simile a quello con cui si assegna il
-\acr{pid} ai processi).
+è il numero progressivo che il kernel assengna a ciascuno di essi quanto
+vengono creati (il prodedimento è simile a quello con cui si assegna il
+\acr{pid} ai processi). L'identificatore viene restituito dalle funzioni che
+creano l'oggetto, ed è quindi locale al processo che le ha eseguite. Dato che
+l'identificatore viene assegnato dinamicamente dal kernel non è possibile
+prevedere quale sarà, ne utilizzare un qualche valore statico, si pone perciò
+il problema di come processi diversi possono accedere allo stesso oggetto.
+
+Per risolvere il problema il kernel associa a ciascun oggetto una struttura
+\var{ipc\_perm}; questa contiene una \textsl{chiave}, identificata da una
+variabile del tipo primitivo \type{key\_t}, che viene specificata in fase di
+creazione e tramite la quale è possibile ricavare l'identificatore. La
+struttura, la cui definizione è riportata in \figref{fig:ipc_ipc_perm},
+contiene anche le varie proprietà associate all'oggetto. 
 
-L'identificatore è in genere restituito dalle funzioni che creano l'oggetto,
-nasce quindi il problema di come processi diversi possono accedere allo stesso
-oggetto. Per far questo a ciascuno di essi viene anche associata una
-\textsl{chiave}, che può essere indicata in fasi di creazione. Usando la
-stessa chiave due processi diversi potranno ricavare l'identificatore
-associato ad un oggetto e accedervi entrambi. 
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm ]{}
+struct ipc_perm
+{
+    key_t key;                        /* Key.  */
+    uid_t uid;                        /* Owner's user ID.  */
+    gid_t gid;                        /* Owner's group ID.  */
+    uid_t cuid;                       /* Creator's user ID.  */
+    gid_t cgid;                       /* Creator's group ID.  */
+    unsigned short int mode;          /* Read/write permission.  */
+    unsigned short int seq;           /* Sequence number.  */
+};
+    \end{lstlisting}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \var{ipc\_perm}, come definita in \file{sys/ipc.h}.} 
+  \label{fig:ipc_ipc_perm}
+\end{figure}
+
+Usando la stessa chiave due processi diversi possono ricavare l'identificatore
+associato ad un oggetto ed accedervi. Il problema che sorge a questo punto è
+come devono fare per accordarsi sull'uso di una stessa chiave. Se i processi
+sono \textsl{parenti} la soluzione è relativamente semplice, in tal caso
+infatti si può usare il valore speciale \texttt{IPC\_PRIVATE} per creare un
+nuovo oggetto nel processo padre, l'idenficatore così ottenuto sarà
+disponibile in tutti i figli, e potrà essere passato come parametro attraverso
+una \func{exec}.
+
+Però quando i processi non sono \textsl{parenti} (come capita tutte le volte
+che si ha a che fare con un sistema client-server) tutto questo non è
+possibile; si potebbe comunque salvare l'identificatore su un file noto, ma
+questo ovviamente comporta lo svantaggio di doverselo andare a rileggere.  Una
+alternativa più efficace è quella che i programmi usino un valore comune per
+la chiave (che ad esempio può essere dichiarato in un header comune), ma c'è
+sempre il rischio che questa chiave possa essere stata già utilizzata da
+qualcun altro.  Dato che non esiste una convenzione su come assegnare queste
+chiavi in maniera univoca l'interfaccia mette a disposizione una funzione,
+\func{ftok}, che permette di ottenere una chiave specificando il nome di un
+file ed un numero di versione; il suo prototipo è:
+\begin{functions}
+  \headdecl{sys/types.h} 
+  \headdecl{sys/ipc.h} 
+  
+  \funcdecl{key\_t ftok(const char *pathname, int proj\_id)}
+  
+  Restituisce una chiave per identificare un oggetto del System V IPC.
+  
+  \bodydesc{La funzione restituisce la chiave in caso di successo e -1
+  altrimenti, nel qual caso \var{errno} viene settata ad uno dei possibili
+  codici di errore di \func{stat}.}
+\end{functions}
+
+La funzione determina un valore della chiave sulla base di \param{pathname},
+che deve specificare il pathname di un file effettivamente esistente e di un
+numero di progetto \param{proj\_id)}, che di norma viene specificato come
+carattere, dato che ne vengono utilizzati solo gli 8 bit meno
+significativi.\footnote{nelle libc4 e libc5, come avviene in SunOS,
+  l'argomento \param{proj\_id)} è dichiarato tipo \ctyp{char}, le \acr{glibc}
+  han modificato il prototipo, ma vengono lo stesso utilizzati gli 8 bit meno
+  significativi.}
+
+Il problema è che anche così non c'è la sicurezza che il valore della chiave
+sia univoco, infatti esso è costruito combinando il byte di \param{proj\_id)}
+con i 16 bit meno significativi dell'inode del file \param{pathname} (che
+vengono ottenuti attraverso \func{stat}, da cui derivano i possibili errori),
+e gli 8 bit meno significativi del numero del device su cui è il file. Diventa
+perciò relativamente facile ottenere delle collisioni, specie se i file sono
+su dispositivi con lo stesso \textit{minor number}, come \file{/dev/hda1} e
+\file{/dev/sda1}.
+
+In genere quello che si fa è utilizzare un file comune usato dai programmi che
+devono comunicare (ad esempio un haeder, o uno dei programmi che devono usare
+l'oggetto in questione), utilizzando il numero di progetto per ottere le
+chiavi che interessano. In ogni caso occorre sempre controllare, prima di
+creare un oggetto, che la chiave non sia già stata utilizzata. Se questo va
+bene in fase di creazione, le cose possono complicarsi per i programmi che
+devono solo accedere, in quanto, a parte gli eventuali controlli sugli altri
+attributi di \var{ipc\_perm}, non esiste una modalità semplice per essere
+sicuri della validità di una certa chiave.
+
+Questo è, insieme al fatto che gli oggetti sono permanenti e devono essere
+cancellati esplicitamente, il principale problema del sistema di IPC di System
+V. Non esiste infatti una modalità chiara per identificare un oggetto, come
+sarebbe stato se lo si fosse associato ad in file, e tutta l'interfaccia è
+inutilmente complessa.  Per questo ne è stata effettuata una revisione
+completa nello standard POSIX.1b, che tratteremo in \secref{sec:ipc_posix}.
+
+
+\subsection{Il controllo di accesso}
+\label{sec:ipc_sysv_access_control}
+
+Oltre alle chiavi, abbiamo visto che ad ogni oggetto sono associate in
+\var{ipc\_perm} ulteriori informazioni, come gli identificatori del creatore
+(nei campi \var{cuid} e \var{cgid}) e del proprietario (nei campi \var{uid} e
+\var{gid}) dello stesso, e un insieme di permessi (nel campo \var{mode}). In
+questo modo è possibile definire un controllo di accesso sugli oggetti, simile
+a quello che si ha per i file (vedi \secref{sec:file_perm_overview}).  
+
+Benché il controllo di accesso relativo agli oggetti di intercomunicazione sia
+molto simile a quello dei file, restano delle importanti differenze. La prima
+è che il permesso di esecuzione non esiste (e viene ignorato), per cui si può
+parlare solo di permessi di lettura e scrittura (nel caso dei semafori poi
+quest'ultimo è più propriamente il permesso di modificarne lo stato). I valori
+di \var{mode} sono gli stessi ed hanno lo stesso significato di quelli
+riportati in \secref{tab:file_mode_flags}\footnote{se però si vogliono usare
+  le costanti simboliche ivi definite occorrerà includere il file
+  \file{sys/stat.h}, alcuni sistemi definiscono le costanti \macro{MSG\_R}
+  (\texttt{0400}) e \macro{MSG\_W} (\texttt{0200}) per indicare i permessi
+  base di lettura e scrittura per il proprietario, da utilizzare, con gli
+  opportuni shift, pure per il gruppo e gli altri, in Linux, visto la loro
+  scarsa utilità, queste costanti non sono definite.} e come per i file
+definiscono gli accessi per il proprietario, il suo gruppo e tutti gli altri.
+
+Si tenga presente che per gli oggetti di IPC han senso solo i permessi di
+lettura e scrittura, quelli di esecuzione vengono ignorati. Quando l'oggetto
+viene creato i campi \var{cuid} e \var{uid} di \var{ipc\_perm} ed i campi
+\var{cgid} e \var{gid} vengono settati rispettivamente al valore dell'userid e
+del groupid effettivo del processo che ha chiamato la funzione, ma mentre i
+campi \var{uid} e \var{gid} possono essere cambiati, \var{cuid} e \var{cgid}
+restano sempre gli stessi.
+
+Il controllo di accesso è effettuato a due livelli. Il primo è nelle funzioni
+che richiedono l'identificatore di un oggetto data la chiave, che specificano
+tutte un argomento \param{flag}.  In tal caso quando viene effettuata la
+ricerca di una chiave, se \param{flag} specifica dei permessi, questi vengono
+controllati e l'identificatore viene restituito solo se essi corrispondono a
+quelli dell'oggetto. Se sono presenti dei permessi non presenti in \var{mode}
+l'accesso sarà invece negato. Questo però è di utilità indicativa, dato che è
+sempre possibile specificare un valore nullo per \param{flag}, nel qual caso
+il controllo avrà sempre successo.
+
+Il secondo livello è quello delle varie funzioni che accedono (in lettura o
+scrittura) all'oggetto. In tal caso lo schema dei controlli è simile a quello
+dei file, ed avviene secondo questa sequenza:
+\begin{enumerate}
+\item se il processo ha i privilegi di amministatore l'accesso è sempre
+  consentito. 
+\item se l'userid effettivo del processo corrisponde o al valore del campo
+  \var{cuid} o a quello del campo \var{uid} ed il permesso per il proprietario
+  in \var{mode} è appropriato\footnote{per appropriato si intende che è
+    settato il permesso di scrittura per le operazioni di scrittura e quello
+    di lettura per le operazioni di lettura.} l'accesso è consentito.
+\item se il groupid effettivo del processo corrisponde o al
+  valore del campo \var{cgid} o a quello del campo \var{gid} ed il permesso
+  per il gruppo in \var{mode} è appropriato l'accesso è consentito.
+\item 
+\end{enumerate}
 
-Il problema che sorge a questo punto è come due processi diversi possono
 
 
 \subsection{Code di messaggi}
-\label{sec:ipc_messque}
+\label{sec:ipc_sysv_mq}
 
 Il primo oggetto introdotto dal \textit{System V IPC} è quello delle code di
-messaggi.
+messaggi.  Le code di messaggi sono oggetti analoghi alle pipe o alle fifo,
+anche se la loro struttura è diversa. La funzione che permette di ottenerne
+una è \func{msgget} ed il suo prototipo è:
+\begin{functions}
+  \headdecl{sys/types.h} 
+  \headdecl{sys/ipc.h} 
+  \headdecl{sys/msg.h} 
+  
+  \funcdecl{int msgget(key\_t key, int flag)}
+  
+  Restituisce l'identificatore di una cosa di messaggi.
+  
+  \bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
+    in caso di errore, nel qual caso \var{errno} viene settato ad uno dei
+    valori: 
+  \begin{errlist}
+  \item[\macro{EACCES}] Il processo chiamante non ha i provilegi per accedere
+  alla coda richiesta.  
+  \item[\macro{EEXIST}] Si è richiesta la creazione di una coda che già
+  esiste, ma erano specificati sia \macro{IPC\_CREAT} che \macro{IPC\_EXCL}. 
+  \item[\macro{EIDRM}] La coda richiesta è marcata per essere cancellata.
+  \item[\macro{ENOENT}] Si è cercato di ottenere l'identificatore di una coda
+    di messaggi specificando una chiave che non esiste e \macro{IPC\_CREAT}
+    non era specificato.
+  \item[\macro{ENOSPC}] Si è cercato di creare una coda di messaggi quando è
+    stato il limite massimo del sistema.
+  \end{errlist}
+  ed inoltre \macro{ENOMEM}.
+}
+\end{functions}
+
+Le funzione (come le analoghe che si usano per gli altri oggetti) serve sia a
+ottenere l'identificatore di una coda di messaggi esistente, che a crearne una
+nuova. L'argomento \param{key} specifica la chiave che è associata
+all'oggetto, eccetto il caso in cui si specifichi il valore
+\macro{IPC\_PRIVATE}, nel qual caso la coda è creata ex-novo e non vi è
+associata alcuna chiave, il processo (ed i suoi eventuali figli) potranno
+farvi riferimento solo attraverso l'identificatore.
+
+Se invece si specifica un valore diverso da \macro{IPC\_PRIVATE}\footnote{in
+  Linux questo significa un valore diverso da zero.} l'effetto della funzione
+dipende dal valore di \param{flag}, se questo è nullo la funzione si limita ad
+effettuare una ricerca sugli oggetti esistenti, restituendo l'identificatore
+se trova una corrispondenza, o fallendo con un errore di \macro{ENOENT} se non
+esiste o di \macro{EACCESS} se si sono specificati dei permessi non validi.
+
+Se invece si vuole creare una nuova coda di messaggi \param{flag} non può
+essere nullo e deve essere fornito come maschera binaria, impostando il bit
+corrispondente al valore \macro{IPC\_CREAT}. In questo caso i nove bit meno
+significativi di \param{flag} saranno usati come permessi per il nuovo
+oggetto, secondo quanto illustrato in \secref{sec:ipc_sysv_access_control}.
+Se si imposta anche il bit corrispondente a \macro{IPC\_EXCL} la funzione avrà
+successo solo se l'oggetto non esiste già, fallendo con un errore di
+\macro{EEXIST} altrimenti.
+
+
+
+Una coda di messaggi è costituita da una \textit{linked list} in cui nuovi
+messaggi vengono inseriti in coda e letti dalla cima, con una struttura del
+tipo di quella illustrata in 
+
+
+
 
 \subsection{Semafori}
-\label{sec:ipc_semaph}
+\label{sec:ipc_sysv_sem}
 
 Il secondo oggetto introdotto dal \textit{System V IPC} è quello dei semafori.
+Un semaforo è uno speciale contatore che permette di controllare l'accesso a
+risorse condivise. La funzione che permette di ottenere un insieme di semafori
+è \func{semget} ed il suo prototipo è:
+\begin{functions}
+  \headdecl{sys/types.h} 
+  \headdecl{sys/ipc.h} 
+  \headdecl{sys/sem.h} 
+  
+  \funcdecl{int semget(key\_t key, int nsems, int flag)}
+  
+  Restituisce l'identificatore di un semaforo.
+  
+  \bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
+    in caso di errore, nel qual caso \var{errno} viene settato agli stessi
+    valori visti per \func{msgget}.}
+\end{functions}
+
+La funzione è del tutto analoga a \func{msgget} ed identico è l'uso degli
+argomenti \param{key} e \param{flag}, per cui non ripeteremo quanto detto al
+proposito in \secref{sec:ipc_sysv_mq}. L'argomento \param{nsems} permette di
+specificare quanti semfori deve contenere l'insieme qualora se ne richieda la
+creazione, e deve essere nullo quando si effettua una richiesta
+dell'identificatore di un insieme già esistente.
+
 
 
 \subsection{Memoria condivisa}
-\label{sec:ipc_shar_mem}
+\label{sec:ipc_sysv_shm}
 
 Il terzo oggetto introdotto dal \textit{System V IPC} è quello della memoria
-condivisa.
+condivisa. La funzione che permette di ottenerne uno è \func{shmget} ed il suo
+prototipo è:
+\begin{functions}
+  \headdecl{sys/types.h} 
+  \headdecl{sys/ipc.h} 
+  \headdecl{sys/shm.h}
+  
+  \funcdecl{int shmget(key\_t key, int size, int flag)}
+  
+  Restituisce l'identificatore di una memoria condivisa.
+  
+  \bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
+    in caso di errore, nel qual caso \var{errno} viene settato agli stessi
+    valori visti per \func{msgget}.}
+\end{functions}
 
+La funzione, come per \func{semget}, è del tutto analoga a \func{msgget}, ed
+identico è l'uso degli argomenti \param{key} e \param{flag}. L'argomento
 
 
 
@@ -645,7 +900,7 @@ condivisa.
 Lo standard POSIX.1b ha introdotto dei nuovi meccanismi di comunicazione,
 rifacendosi a quelli di System V, introducendo una nuova interfaccia che
 evitasse i principali problemi evidenziati in coda a
-\secref{sec:ipc_sysv_generic}.
+\secref{sec:ipc_sysv_generic}.