X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=prochand.tex;h=90e2e9f65806c5947bc4624d55cedf2324459031;hp=66aa00272fc730855649de50dc9161cd13039f47;hb=39fd68b4edd01be7664153992dea276a4b9a3396;hpb=94a3cc760eb536673f79b662580f1ff9107c9a99 diff --git a/prochand.tex b/prochand.tex index 66aa002..90e2e9f 100644 --- a/prochand.tex +++ b/prochand.tex @@ -8,16 +8,20 @@ base per l'allocazione e l'uso delle risorse del sistema. Nel precedente capitolo abbiamo visto come funziona un singolo processo, in questo capitolo affronteremo i dettagli della creazione e della distruzione dei processi, della gestione dei loro attributi e privilegi, e di tutte le -funzioni a questo connesse. +funzioni a questo connesse. Infine nella sezione finale affronteremo alcune +problematiche generiche della programmazione in ambiente multitasking. + \section{Introduzione} \label{sec:proc_gen} Partiremo con una introduzione generale ai concetti che stanno alla base della -gestione dei processi in unix. Introdurremo in questa sezione l'architettura -della gestione dei processi e le sue principali caratteristiche, e daremo una -panoramica sull'uso delle principali funzioni per la gestione dei processi. +gestione dei processi in un sitema unix-like. Introdurremo in questa sezione +l'architettura della gestione dei processi e le sue principali +caratteristiche, e daremo una panoramica sull'uso delle principali funzioni +per la gestione dei processi. + \subsection{La gerarchia dei processi} \label{sec:proc_hierarchy} @@ -377,6 +381,8 @@ periodo di attesa. Se eseguiamo il comando senza specificare attese (come si può notare in \texttt{\small 17--19} i valori di default specificano di non attendere), otterremo come output sul terminale: + +\footnotesize \begin{verbatim} [piccardi@selidor sources]$ ./forktest 3 Process 1963: forking 3 child @@ -393,6 +399,7 @@ Child 3, parent 1963, exiting Spawned 3 child, pid 1966 Go to next child \end{verbatim} %$ +\normalsize Esaminiamo questo risultato: una prima conclusione che si può trarre è non si può dire quale processo fra il padre ed il figlio venga eseguito per @@ -431,6 +438,8 @@ Un secondo aspetto molto importante nella creazione dei processi figli quello dell'interazione dei vari processi con i file; per illustrarlo meglio proviamo a redirigere su un file l'output del nostro programma di test, quello che otterremo è: + +\footnotesize \begin{verbatim} [piccardi@selidor sources]$ ./forktest 3 > output [piccardi@selidor sources]$ cat output @@ -457,6 +466,7 @@ Go to next child Spawned 3 child, pid 1970 Go to next child \end{verbatim} +\normalsize che come si vede è completamente diverso da quanto ottenevamo sul terminale. Il comportamento delle varie funzioni di interfaccia con i file è analizzato @@ -529,7 +539,7 @@ sequenza impredicibile. Le modalit Oltre ai file aperti i processi figli ereditano dal padre una serie di altre proprietà comuni; in dettaglio avremo che dopo l'esecuzione di una \func{fork} padre e figlio avranno in comune: -\begin{itemize} +\begin{itemize*} \item i file aperti (e gli eventuali flag di \textit{close-on-exec} se settati). \item gli identificatori per il controllo di accesso: il \textit{real user @@ -547,9 +557,9 @@ padre e figlio avranno in comune: \item i segmenti di memoria condivisa agganciati al processo. \item i limiti sulle risorse \item le variabili di ambiente (vedi \secref{sec:proc_environ}). -\end{itemize} +\end{itemize*} le differenze invece sono: -\begin{itemize} +\begin{itemize*} \item il valore di ritorno di \func{fork}. \item il \textit{process id}. \item il \textit{parent process id} (quello del figlio viene settato al @@ -558,7 +568,7 @@ le differenze invece sono: \var{tms\_cutime}, \var{tms\_uetime}) che nel figlio sono posti a zero. \item i \textit{file lock}, che non vengono ereditati dal figlio. \item gli allarmi pendenti, che per il figlio vengono cancellati. -\end{itemize} +\end{itemize*} \subsection{La funzione \func{vfork}} @@ -611,7 +621,7 @@ Qualunque sia la modalit comunque una serie di operazioni: chiude tutti i file aperti, rilascia la memoria che stava usando, e così via; l'elenco completo delle operazioni eseguite alla chiusura di un processo è il seguente: -\begin{itemize} +\begin{itemize*} \item tutti i descrittori dei file sono chiusi. \item viene memorizzato lo stato di terminazione del processo. \item ad ogni processo figlio viene assegnato un nuovo padre. @@ -622,7 +632,7 @@ eseguite alla chiusura di un processo \item se la conclusione di un processo rende orfano un \textit{process group} ciascun membro del gruppo viene bloccato, e poi gli vengono inviati in successione i segnali \macro{SIGHUP} e \macro{SIGCONT}. -\end{itemize} +\end{itemize*} ma al di la di queste operazioni è necessario poter disporre di un meccanismo ulteriore che consenta di sapere come questa terminazione è avvenuta; dato che in un sistema unix-like tutto viene gestito attraverso i processi il @@ -660,6 +670,8 @@ avr di terminazione. Come verifica di questo comportamento possiamo eseguire il comando \cmd{forktest} imponendo a ciascun processo figlio due secondi di attesa prima di uscire, il risultato è: + +\footnotesize \begin{verbatim} [piccardi@selidor sources]$ ./forktest -c2 3 Process 1972: forking 3 child @@ -676,6 +688,7 @@ Go to next child Child 2, parent 1, exiting Child 1, parent 1, exiting \end{verbatim} +\normalsize come si può notare in questo caso il processo padre si conclude prima dei figli, tornando alla shell, che stampa il prompt sul terminale: circa due secondi dopo viene stampato a video anche l'output dei tre figli che @@ -705,6 +718,8 @@ condizione: lanciamo il comando \cmd{forktest} in background, indicando al processo padre di aspettare 10 secondi prima di uscire; in questo caso, usando \cmd{ps} sullo stesso terminale (prima dello scadere dei 10 secondi) otterremo: + +\footnotesize \begin{verbatim} [piccardi@selidor sources]$ ps T PID TTY STAT TIME COMMAND @@ -715,6 +730,7 @@ otterremo: 571 pts/0 Z 0:00 [forktest ] 572 pts/0 R 0:00 ps T \end{verbatim} %$ +\normalsize e come si vede, dato che non si è fatto nulla per riceverne lo stato di terminazione, i tre processi figli sono ancora presenti pur essendosi conclusi, con lo stato di zombie e l'indicazione che sono stati terminati. @@ -816,6 +832,7 @@ base del valore specificato tramite la variabile \var{pid}, secondo lo specchietto riportato in \ntab: \begin{table}[!htb] \centering + \footnotesize \begin{tabular}[c]{|c|p{10cm}|} \hline \textbf{Valore} & \textbf{Significato}\\ @@ -1141,7 +1158,7 @@ processo di partenza per costruire l'ambiente. Oltre a mantenere lo stesso \acr{pid}, il nuovo programma fatto partire da \func{exec} assume anche una serie di altre proprietà del processo chiamante; la lista completa è la seguente: -\begin{itemize} +\begin{itemize*} \item il \textit{process ID} (\acr{pid}) ed il \textit{parent process ID} (\acr{ppid}). \item il \textit{real user ID} ed il \textit{real group ID} (vedi @@ -1161,7 +1178,7 @@ la lista completa \item i limiti sulle risorse (vedi \secref{sec:limits_xxx}).. \item i valori delle variabili \var{tms\_utime}, \var{tms\_stime}, \var{tms\_cutime}, \var{tms\_ustime} (vedi \secref{sec:xxx_xxx}).. -\end{itemize} +\end{itemize*} Oltre a questo i segnali che sono stati settati per essere ignorati nel processo chiamante mantengono lo stesso settaggio pure nuovo programma, tutti @@ -1205,9 +1222,9 @@ chiamato come se si fosse eseguito il comando \cmd{interpreter [arg] filename}. Con la famiglia delle \func{exec} si chiude il novero delle funzioni su cui è -basato il controllo dei processi in unix: con \func{fork} si crea un nuovo +basata la gestione dei processi in unix: con \func{fork} si crea un nuovo processo, con \func{exec} si avvia un nuovo programma, con \func{exit} e -\func{wait} si effettua e si gestisce la conclusione dei programmi. Tutte le +\func{wait} si effettua e verifica la conclusione dei programmi. Tutte le altre funzioni sono ausiliarie e servono la lettura e il settaggio dei vari parametri connessi ai processi. @@ -1260,33 +1277,72 @@ utente per un limitato insieme di operazioni. Per questo motivo in generale tutti gli unix prevedono che i processi abbiano almeno due gruppi di identificatori, chiamati rispettivamente \textit{real} ed \textit{effective}. + +\begin{table}[htb] + \footnotesize + \centering + \begin{tabular}[c]{|c|l|p{6.5cm}|} + \hline + \textbf{Suffisso} & \textbf{Significato} & \textbf{Utilizzo} \\ + \hline + \hline + \acr{uid} & \textit{real user id} & indica l'utente che ha lanciato + il programma\\ + \acr{gid} & \textit{real group id} & indica il gruppo dell'utente + che ha lanciato il programma \\ + \acr{euid} & \textit{effective user id} & indica l'utente usato + dal programma nel controllo di accesso \\ + \acr{egid} & \textit{effective group id} & indica il gruppo + usato dal programma nel controllo di accesso \\ + -- & \textit{supplementary group id} & indica i gruppi cui + l'utente appartiene \\ + -- & \textit{saved user id} & copia dell'\acr{euid} iniziale\\ + -- & \textit{saved group id} & copia dell'\acr{egid} iniziale \\ + \acr{fsuid} & \textit{filesystem user id} & indica l'utente effettivo per + il filesystem \\ + \acr{fsgid} & \textit{filesystem group id} & indica il gruppo effettivo + per il filesystem \\ + \hline + \end{tabular} + \caption{Identificatori di utente e gruppo associati a ciascun processo con + indicazione dei suffissi usate dalle varie funzioni di manipolazione.} + \label{tab:proc_uid_gid} +\end{table} + Al primo gruppo appartengono il \textit{real user ID} e il \textit{real group ID}: questi vengono settati al login ai valori corrispondenti all'utente con cui si accede al sistema (e relativo gruppo di default). Servono per -l'identificazione dell'utente e normalmente non vengono mai cambiati. +l'identificazione dell'utente e normalmente non vengono mai cambiati. In +realtà vedremo (in \secref{sec:proc_setuid}) che è possibile modificarli, ma +solo ad un processo che abbia i privilegi di amministratore; questa +possibilità è usata ad esempio da \cmd{login} che una volta completata la +procedura di autenticazione lancia una shell per la quale setta questi +identificatori ai valori corrispondenti all'utente che entra nel sistema. Al secondo gruppo appartengono l'\textit{effective user ID} e -l'\textit{effective group ID}: questi sono gli identificatori usati nella -verifiche dei permessi, (ad esempio, come vedremo in -\secref{sec:file_perm_overview}, vengono usati nel controllo di accesso ai -file). +l'\textit{effective group ID} (a cui si aggiungono gli eventuali +\textit{supplementary group id} dei gruppi dei quale l'utente fa parte). +Questi sono invece gli identificatori usati nella verifiche dei permessi del +processo e per il controllo di accesso ai file (argomento affrontato in +dettaglio in \secref{sec:file_perm_overview}). Questi identificatori normalmente sono identici ai corrispondenti del gruppo -\textsl{reale} tranne nel caso in cui, come visto in \secref{sec:proc_exec}, il -programma che si è posto in esecuzione abbia i bit \acr{suid} o \acr{sgid} +\textsl{reale} tranne nel caso in cui, come visto in \secref{sec:proc_exec}, +il programma che si è posto in esecuzione abbia i bit \acr{suid} o \acr{sgid} settati (il significato di questi bit è affrontato in dettaglio in \secref{sec:file_suid_sgid}). In questo caso essi saranno settati all'utente e -al gruppo proprietari del file, questo consente, per programmi in cui ci sia -necessità, di dare anche all'utente normale privilegi o permessi superiori. +al gruppo proprietari del file; questo consente, per programmi in cui ci sia +necessità, di dare a qualunquee utente normale privilegi o permessi di +un'altro (o dell'amministratore). -Come nel caso del \acr{pid} e del \acr{ppid} identificatori possono essere -letti dal processo attraverso delle opportune funzioni, i cui prototipi sono i -seguenti: +Come nel caso del \acr{pid} e del \acr{ppid} tutti questi identificatori +possono essere letti dal processo attraverso delle opportune funzioni, i cui +prototipi sono i seguenti: \begin{functions} \headdecl{unistd.h} \headdecl{sys/types.h} -\funcdecl{uid\_t getuid(void)} restituisce il \textit{real user ID} pid del +\funcdecl{uid\_t getuid(void)} restituisce il \textit{real user ID} del processo corrente. \funcdecl{uid\_t geteuid(void)} restituisce l'\textit{effective user ID} del processo corrente. @@ -1298,87 +1354,338 @@ processo corrente. Queste funzioni non riportano condizioni di errore. \end{functions} -Dato che in generale l'uso di privilegi superiori deve essere limitato il più -possibile, per evitare abusi e creare problemi di sicurezza, occorre anche un -meccanismo che provveda a rilasciare gli eventuali maggiori privilegi una -volta che si siano effettuate le operazioni per i quali erano richiesti, per -poterli eventualmente recuperare all'occorrenza. +In generale l'uso di privilegi superiori deve essere limitato il più +possibile, per evitare abusi e problemi di sicurezza, per questo occorre anche +un meccanismo che consenta ad un programma di rilasciare gli eventuali +maggiori privilegi necessari, una volta che si siano effettuate le operazioni +per i quali erano richiesti, e a poterli eventualmente recuperare in caso +servano di nuovo. Questo in Linux viene fatto usando altri due gruppi di identificatori, il -\textit{saved} ed il \textit{filesystem}, analoghi ai precedenti, e riportati -nello specchietto di tutti gli identificatori di utente e gruppo fornito in -\ntab. Il primo gruppo è lo stesso usato in SVr4, e previsto dallo standard -POSIX quando è definita la costante \macro{\_POSIX\_SAVED\_IDS}, il secondo -gruppo è specifico di Linux e viene usato per migliorare la sicurezza con NFS. - -\begin{table}[htb] - \footnotesize - \centering - \begin{tabular}[c]{|c|l|p{8cm}|} - \hline - \textbf{Suffisso} & \textbf{Significato} & \textbf{Utilizzo} \\ - \hline - \hline - \acr{uid} & \textit{real user id} & indica l'utente reale che ha lanciato - il programma\\ - \acr{gid} & \textit{real group id} & indica il gruppo reale dell'utente - che ha lanciato il programma \\ - \acr{euid} & \textit{effective user id} & indica l'utente effettivo usato - dal programma \\ - \acr{egid} & \textit{effective group id} & indica il gruppo effettivo usato - dal programma \\ - & \textit{supplementary group id} & indica i gruppi cui - l'utente appartiene \\ - -- & \textit{saved user id} & indica l'utente \\ - -- & \textit{saved group id} & indica il gruppo \\ - \acr{fsuid} & \textit{filesystem user id} & indica l'utente effettivo per - il filesystem \\ - \acr{fsgid} & \textit{filesystem group id} & indica il gruppo effettivo - per il filesystem \\ - \hline - \end{tabular} - \caption{Identificatori di utente e gruppo associati a ciascun processo con - indicazione dei suffissi usate dalle varie funzioni di manipolazione.} - \label{tab:proc_uid_gid} -\end{table} - -Il \textit{real user id} e il \textit{real group id} indicano l'utente che ha -lanciato il processo, e vengono settati al login al valore standard di -\acr{uid} e \acr{gid} dell'utente letti direttamente da \file{/etc/passwd}. - -Esso servono ad identificare l'utente che ha lanciato il processo e non -vengono mai cambiati nella creazione di nuovi processi restando sempre gli -stessi per tutti i processi avviati in una sessione. In realtà vedremo che è -possibile possibile modificarli (in \secref{sec:proc_setuid}), ma solo ad un -processo che abbia i privilegi di amministratore; questa possibilità è usata -ad esempio da \cmd{login} che una volta completata la procedura di -autenticazione lancia una shell per la quale setta questi identificatori ai -valori corrispondenti all'utente che entra nel sistema. - -L'\textit{effective user id}, l'\textit{effective group id} e gli eventuali -\textit{supplementary group id} sono invece gli identificatori usati per il -controllo di accesso ai file (secondo quanto descritto in dettaglio in -\secref{sec:file_perm_overview}). Normalmente essi sono uguali al \textit{real - user id} e al \textit{real group id}, a meno che il file posto in esecuzione -non abbia o il bit \acr{suid} o il bit \acr{sgid} settato, in questo caso alla -la funzione \func{exec} (vedi \secref{}) li setta rispettivamente ai valori -dell'\acr{uid} e del \acr{gid} cui appartiene il file. +\textit{saved} ed il \textit{filesystem}, analoghi ai precedenti. Il primo +gruppo è lo stesso usato in SVr4, e previsto dallo standard POSIX quando è +definita la costante \macro{\_POSIX\_SAVED\_IDS}\footnote{in caso si abbia a + cuore la portabilità del programma su altri unix è buona norma controllare + sempre la disponibilità di queste funzioni controllando se questa costante è + definita}, il secondo gruppo è specifico di Linux e viene usato per +migliorare la sicurezza con NFS. Il \textit{saved user id} e il \textit{saved group id} sono copie dell'\textit{effective user id} e dell'\textit{effective group id} del processo padre, e vengono settati dalla funzione \func{exec} all'avvio del -processo, prima che \textit{effective user id} e \textit{effective group id} -vengano modificati per tener conto di eventuali \acr{suid} o \acr{sgid}, essi -quindi consentono di tenere traccia di quale fossero l'utente originale. +processo, come copie dell'\textit{effective user id} e dell'\textit{effective + group id} dopo che questo sono stati settati tenendo conto di eventuali +\acr{suid} o \acr{sgid}. Essi quindi consentono di tenere traccia di quale +fossero utente e gruppo effettivi all'inizio dell'esecuzione di un nuovo +programma. + +Il \textit{filesystem user id} e il \textit{filesystem group id} sono una +estensione introdotta in Linux per rendere più sicuro l'uso di NFS (torneremo +sull'argomento in \secref{sec:proc_setfsuid}). Essi sono una replica dei +corrispondenti \textit{effective id}, ai quali si sostituiscono per tutte le +operazioni di verifica dei permessi relativi ai file (trattate in +\secref{sec:file_perm_overview}). Ogni cambiamento effettuato sugli +\textit{effective id} viene automaticamente riportato su di essi, per cui in +condizioni normali se ne può tranquillamente ignorare l'esistenza, in quanto +saranno del tutto equivalenti ai precedenti. + +Uno specchietto riassuntivo, contenente l'elenco completo degli identificatori +di utente e gruppo associati dal kernel ad ogni processo, è riportato in +\tabref{tab:proc_uid_gid}. + + +\subsection{Le funzioni \func{setuid} e \func{setgid}} +\label{sec:proc_setuid} +Le due funzioni che venfono usate per cambiare identità (cioè utente e gruppo +di appartenenza) ad un processo sono rispettivamente \func{setuid} e +\func{setgid}; come accennato in \secref{sec:proc_user_group} in Linux esse +seguono la sematica POSIX che prevede l'esistenza di \textit{saved user id} e +\textit{saved group id}; i loro prototipi sono: -\subsection{Le funzioni \texttt{setuid} e \texttt{setgid}} -\label{sec:proc_setuid} +\begin{functions} +\headdecl{unistd.h} +\headdecl{sys/types.h} + +\funcdecl{int setuid(uid\_t uid)} setta l'\textit{user ID} del processo +corrente. +\funcdecl{int setgid(gid\_t gid)} setta il \textit{group ID} del processo +corrente. -\subsection{Le funzioni \texttt{seteuid} e \texttt{setegid}} +Le funzioni restituiscono 0 in caso di successo e -1 in caso di fallimento: +l'unico errore possibile è \macro{EPERM}. +\end{functions} + +Il funzionamento di queste due funzioni è analogo, per cui considereremo solo +la prima; la seconda si comporta esattamente allo stesso modo facendo +riferimento al \textit{group id} invece che all'\textit{user id}. Gli +eventuali \textit{supplementary group id} non vengono modificati da nessuna +delle funzioni che tratteremo in questa sezione. + + +L'effetto della chiamata è diverso a seconda dei privilegi del processo; se +l'\textit{effective user id} è zero (cioè è quello dell'amministratore di +sistema) allora tutti gli identificatatori (\textit{real}, \textit{effective} +e \textit{saved}) vengono settati al valore specificato da \var{uid}, +altrimenti viene settato solo l'\textit{effective user id}, e soltanto se il +valore specificato corrisponde o al \textit{real user id} o al \textit{saved + user id}. Negli altri casi viene segnalato un errore (con \macro{EPERM}). + +Come accennato l'uso principale di queste funzioni è quello di poter +consentire ad un programma con i bit \acr{suid} o \acr{sgid} settati di +riportare l'\textit{effective user id} a quello dell'utente che ha lanciato il +programma, effettuare il lavoro che non necessita di privilegi aggiuntivi, ed +eventualmente tornare indietro. + +Come esempio per chiarire dell'uso di queste funzioni prediamo quello con cui +viene gestito l'accesso al file \file{/var/log/utmp}. In questo file viene +registrato chi sta usando il sistema al momento corrente; chiaramente non può +essere lasciato aperto in scrittura a qualunque utente, che protrebbe +falsificare la registrazione. Per questo motivo questo file (e l'analogo +\file{/var/log/wtmp} su cui vengono registrati login e logout) appartengono ad +un gruppo dedicato (\acr{utmp}) ed i programmi che devono accedervi (ad +esempio tutti i programmi di terminale in X, o il programma \cmd{screen} +che crea terminali multipli su una console) appartengono a questo gruppo ed +hanno il bit \acr{sgid} settato. + +Quando uno di questi programmi (ad esempio \cmd{xterm}) viene lanciato la +situazione degli identificatori è la seguente: +\begin{eqnarray*} + \label{eq:1} + \textit{real group id} &=& \textrm{\acr{gid} (del chiamante)} \\ + \textit{effective group id} &=& \textrm{\acr{utmp}} \\ + \textit{saved group id} &=& \textrm{\acr{utmp}} +\end{eqnarray*} +in questo modo, dato che l'\textit{effective group id} è quello giusto, il +programma può accedere a \file{/var/log/utmp} in scrittura ed aggiornarlo, a +questo punto il programma può eseguire una \func{setgid(getgid())} per settare +l'\textit{effective group id} a quello dell'utente (e dato che il \textit{real + group id} corrisponde la funzione avrà successo), in questo modo non sarà +possibile lanciare dal terminale programmi che modificano detto file, in tal +caso infatti la situazione degli identificatori sarebbe: +\begin{eqnarray*} + \label{eq:2} + \textit{real group id} &=& \textrm{\acr{gid} (invariato)} \\ + \textit{effective group id} &=& \textrm{\acr{gid}} \\ + \textit{saved group id} &=& \textrm{\acr{utmp} (invariato)} +\end{eqnarray*} +e ogni processo lanciato dal terminale avrebbe comunque \acr{gid} come +\textit{effective group id}. All'uscita dal terminale, per poter di nuovo +aggiornare lo stato di \file{/var/log/utmp} il programma eseguirà una +\func{setgid(utmp)} (dove \var{utmp} è il valore numerico associato al gruppo +\acr{utmp}, ottenuto ad esempio con una \func{getegid}), dato che in questo +caso il valore richiesto corrisponde al \textit{saved group id} la funzione +avrà successo e riporterà la situazione a: +\begin{eqnarray*} + \label{eq:3} + \textit{real group id} &=& \textrm{\acr{gid} (invariato)} \\ + \textit{effective group id} &=& \textrm{\acr{utmp}} \\ + \textit{saved group id} &=& \textrm{\acr{utmp} (invariato)} +\end{eqnarray*} +consentendo l'accesso a \file{/var/log/utmp}. + +Occorre però tenere conto che tutto questo non è possibile con un processo con +i privilegi di root, in tal caso infatti l'esecuzione una \func{setuid} +comporta il cambiamento di tutti gli identificatori associati al processo, +rendendo impossibile riguadagnare i privilegi di amministratore. Questo +comportamento è corretto per l'uso che ne fa \cmd{login} una volta che crea +una nuova shell per l'utente; ma quando si vuole cambiare soltanto +l'\textit{effective user id} del processo per cedere i privilegi occorre +ricorrere ad altre funzioni (si veda ad esempio \secref{sec:proc_seteuid}). + + +\subsection{Le funzioni \func{setreuid} e \func{setresuid}} +\label{sec:proc_setreuid} + +Queste due funzioni derivano da BSD che non supportando\footnote{almeno fino + alla versione 4.3+BSD TODO, verificare e aggiornare la nota} i \textit{saved + id} le usava per poter scambiare fra di loro effective e real id. I +prototipi sono: + +\begin{functions} +\headdecl{unistd.h} +\headdecl{sys/types.h} + +\funcdecl{int setreuid(uid\_t ruid, uid\_t euid)} setta il \textit{real user + ID} e l'\textit{effective user ID} del processo corrente ai valori +specificati da \var{ruid} e \var{euid}. + +\funcdecl{int setregid(gid\_t rgid, gid\_t egid)} setta il \textit{real group + ID} e l'\textit{effective group ID} del processo corrente ai valori +specificati da \var{rgid} e \var{egid}. + +Le funzioni restituiscono 0 in caso di successo e -1 in caso di fallimento: +l'unico errore possibile è \macro{EPERM}. +\end{functions} + +I processi non privileguiati possono settare i \textit{real id} soltanto ai +valori dei loro \textit{effective id} o \textit{real id} e gli +\textit{effective id} ai valori dei loro \textit{real id}, \textit{effective + id} o \textit{saved id}; valori diversi comportano il fallimento della +chiamata; l'amministratore invece può specificare un valore qualunque. +Specificando un valore di -1 l'identificatore corrispondente viene lasciato +inalterato. + +Con queste funzione si possono scambiare fra loro \textit{real id} e +\textit{effective id}, e pertanto è possibile implementare un comportamento +simile a quello visto in precedenza per \func{setgid}, cedendo i privilegi con +un primo scambio, e recuperandoli, eseguito il lavoro non privilegiato, con un +secondo scambio. + +In questo caso però occorre porre molta attenzione quando si creano nuovi +processi nella fase intermedia in cui si sono scambiati gli identificatori, in +questo caso infatti essi avranno un \textit{real id} privilegiato, che dovrà +essere esplicitamente eliminato prima di porre in esecuzione un nuovo +programma (occorrerà cioè eseguire un'altra chiamata dopo la \func{fork}, e +prima della \func{exec} per uniformare i \textit{real id} agli +\textit{effective id}) in caso contrario quest'ultimo potrebbe a sua volta +effettuare uno scambio e riottenere privilegi non previsti. + +Lo stesso problema di propagazione dei privilegi ad eventuali processi figli +si porrebbe per i \textit{saved id}. Queste funzioni derivano da +un'implementazione che non ne prevede la presenza, e quindi non è possibile +usarle per correggere la situazione come nel caso precedente, per questo +motivo tutte le volte che uno degli identificatori viene modificato ad un +valore diverso dal precedente \textit{real id}, il \textit{saved id} viene +sempre settato al valore dell'\textit{effective id}. + + +\subsection{Le funzioni \func{setresuid} e \func{setresgid}} +\label{sec:proc_setresuid} + +Queste due funzioni sono una estensione introdotta in Linux dal kernel 2.1.44, +e permettono un completo controllo su tutti gli identificatori (\textit{real}, +\textit{effective} e \textit{saved}), i prototipi sono: + +\begin{functions} +\headdecl{unistd.h} +\headdecl{sys/types.h} + +\funcdecl{int setresuid(uid\_t ruid, uid\_t euid, uid\_t suid)} setta il +\textit{real user ID}, l'\textit{effective user ID} e il \textit{saved user + ID} del processo corrente ai valori specificati rispettivamente da +\var{ruid}, \var{euid} e \var{suid}. + +\funcdecl{int setresgid(gid\_t rgid, gid\_t egid, gid\_t sgid)} setta il +\textit{real group ID}, l'\textit{effective group ID} e il \textit{saved group + ID} del processo corrente ai valori specificati rispettivamente da +\var{rgid}, \var{egid} e \var{sgid}. + +Le funzioni restituiscono 0 in caso di successo e -1 in caso di fallimento: +l'unico errore possibile è \macro{EPERM}. +\end{functions} + +I processi non privilegiati possono cambiare uno qualunque degli +identificatori usando uno qualunque dei valori correnti di \textit{real id}, +\textit{effective id} o \textit{saved id}, l'ammnistratore può specificare i +valori che vuole; un valore di -1 per un qualunque parametro lascia inalterato +l'dentificatore corrispondente. + + + +\subsection{Le funzioni \func{seteuid} e \func{setegid}} \label{sec:proc_seteuid} +Queste funzioni sono un'estensione allo standard POSIX.1 (ma sono comunque +supportate dalla maggior parte degli unix) e usate per cambiare gli +\textit{effective id}; i loro prototipi sono: + +\begin{functions} +\headdecl{unistd.h} +\headdecl{sys/types.h} + +\funcdecl{int seteuid(uid\_t uid)} setta l'\textit{effective user ID} del +processo corrente a \var{uid}. + +\funcdecl{int setegid(gid\_t gid)} setta l'\textit{effective group ID} del +processo corrente a \var{gid}. + +Le funzioni restituiscono 0 in caso di successo e -1 in caso di fallimento: +l'unico errore possibile è \macro{EPERM}. +\end{functions} + +Gli utenti normali possono settare l'\textit{effective id} solo al valore del +\textit{real id} o del \textit{saved id}, l'amministratore può specificare +qualunque valore. Queste funzioni sono usate per permettere a root di settare +solo l'\textit{effective id}, dato che l'uso normale di \func{setuid} comporta +il settagio di tutti gli identificatori. + + + +\subsection{Le funzioni \func{setfsuid} e \func{setfsgid}} +\label{sec:proc_setfsuid} + +Queste funzioni sono usate per settare gli identificatori usati da Linux per +il controllo dell'accesso ai file. Come già accennato in +\secref{sec:proc_user_group} Linux definisce questo ulteriore gruppo di +identificatori che di norma sono assolutamente equivalenti agli +\textit{effective id} (ed in seguito faremo sempre riferimento a questi +ultimi), dato che ogni cambiamento di questi ultimi viene immediatamente +riportato sui \textit{filesystem id}. + +C'è un solo caso in cui si ha necessità di introdurre una differenza fra +\textit{effective id} e i \textit{filesystem id}, che è per ovviare ad un +problema di sicurezza che si presneta quando si deve implementare un server +NFS. Il server NFS infatti deve poter cambiare l'identificatore con cui accede +ai file per assumere l'identità del singolo utente remoto, ma se questo viene +fatto cambiando l'\textit{effective id} o il \textit{real id} il server si +espone alla ricezione di eventuali segnali ostili da parte dell'utente di cui +ha temporaneamente assunto l'identità. Cambiando solo il \textit{filesystem + id} si ottengono i privilegi necessari per accedere ai file, mantenendo +quelli originari per quanto riguarda tutti gli altri controlli di accesso. + +Le due funzioni usate per cambiare questi identificatori sono \func{setfsuid} +e \func{setfsgid}, sono specifiche di Linux e non devono essere usate se si +intendono scrivere programmi portabili; i loro prototipi sono: + +\begin{functions} +\headdecl{sys/fsuid.h} + +\funcdecl{int setfsuid(uid\_t fsuid)} setta il \textit{filesystem user ID} del +processo corrente a \var{fsuid}. + +\funcdecl{int setfsgid(gid\_t fsgid)} setta l'\textit{filesystem group ID} del +processo corrente a \var{fsgid}. + +Le funzioni restituiscono 0 in caso di successo e -1 in caso di fallimento: +l'unico errore possibile è \macro{EPERM}. +\end{functions} + +Queste funzioni hanno successo solo se il processo chiamante ha i privilegi di +amministratore o se il valore specificato coincide con uno dei +\textit{real}, \textit{effective} o \textit{saved id}. + + + + +\section{Problematiche di programmazione multitasking} +\label{sec:proc_multi_prog} + +Benché i processi siano strutturati in modo da apparire il più possibile come +independenti l'uno dall'altro, nella programmazione in un sistema multiutente +occorre tenere conto di tutta una serie di problematiche che normalmente non +esistono quando si ha a che fare con un sistema in cui viene eseguito un solo +programma alla volta. + + +Pur non essendo tutto questo direttamente legato alla modalità specifica in +cui il multitasking è implementato in un sistema unix-like, avendo affrontato +la gestione dei processi in questo capitolo, tratteremo queste problematiche, +e relative precauzioni ed accorgimenti, in questa sezione conclusiva. + + +\subsection{Le funzioni rientranti} +\label{sec:proc_reentrant} + + +\subsection{I \textit{deadlock}} +\label{sec:proc_deadlock} + + +\subsection{Le operazioni atomiche} +\label{sec:proc_atom_oper} + \subsection{Le \textit{race condition}} \label{sec:proc_race_cond} @@ -1390,3 +1697,5 @@ l'ordine di esecuzione di un processo, senza appositi meccanismi di sincronizzazione, non è assolutamente prevedibile, queste situazioni sono fonti di errori molto subdoli, che possono verificarsi solo in condizioni particolari e quindi difficilmente riproducibili. + +