From: Simone Piccardi Date: Sun, 21 Oct 2001 14:07:13 +0000 (+0000) Subject: Aggiunte setuid &C X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=commitdiff_plain;h=682ed599d14547e67301b35fba26c3a1cf9a39f7 Aggiunte setuid &C --- diff --git a/filedir.tex b/filedir.tex index 88f2964..4585831 100644 --- a/filedir.tex +++ b/filedir.tex @@ -144,7 +144,11 @@ permesso (di lettura, scrittura o esecuzione) si basa sul confronto fra l'utente e il gruppo a cui il file appartiene (i valori di \var{st\_uid} e \var{st\_gid} accennati in precedenza) e l'\textit{effective user id}, l'\textit{effective group id} e gli eventuali \textit{supplementary group id} -del processo. +del processo\footnote{in realtà Linux per quanto riguarda l'accesso ai file + utilizza al posto degli \textit{effective id} i \textit{filesystem id} (si + veda \secref{sec:proc_perms}), ma essendo questi del tutto equivalenti ai + primi, eccetto il caso in cui si voglia scrivere un server NFS, ignoreremo + questa differenza}. Per una spiegazione dettagliata degli identificatori associati ai processi si veda \secref{sec:proc_perms}; normalmente, a parte quanto vedremo in diff --git a/gapil.tex b/gapil.tex index a6f2327..6e7bfe3 100644 --- a/gapil.tex +++ b/gapil.tex @@ -1,4 +1,4 @@ -%% +%% %% GaPiL : Guida alla Programmazione in Linux %% %% S. Piccardi Oct. 2000 diff --git a/intro.tex b/intro.tex index 34950b5..849fc85 100644 --- a/intro.tex +++ b/intro.tex @@ -280,11 +280,11 @@ mantenuto dal sistema e non corrisponde all'orologio hardware del calcolatore. Il \textit{process time} di solito si esprime in secondi e viene usato appunto per tenere conto dei tempi di esecuzione dei processi. Per ciascun processo il kernel tiene tre di questi tempi: -\begin{itemize} +\begin{itemize*} \item \textit{clock time} \item \textit{user time} \item \textit{system time} -\end{itemize} +\end{itemize*} il primo è il tempo ``reale'' (viene anche chiamato \textit{wall clock time}) dall'avvio del processo, e misura il tempo trascorso fino alla sua conclusione; chiaramente un tale tempo dipende anche dal carico del sistema e diff --git a/process.tex b/process.tex index c798a10..d048873 100644 --- a/process.tex +++ b/process.tex @@ -516,13 +516,13 @@ variabile \macro{MALLOC\_CHECK\_} che quando viene settata mette in uso una versione meno efficiente delle funzioni, che però è più tollerante nei confronti di piccoli errori come quello di chiamate doppie a \func{free}; in particolare: -\begin{itemize} +\begin{itemize*} \item se la variabile è posta a zero gli errori vengono ignorati. \item se è posta ad 1 viene stampato un avviso sullo \textit{standard error} (vedi \secref{sec:file_stdfiles}). \item se è posta a 2 viene chiamata \func{abort}, che in genere causa l'immediata conclusione del programma. -\end{itemize} +\end{itemize*} Il problema più comune e più difficile da tracciare che si incontra con l'allocazione della memoria è però quando la memoria non più utilizzata non @@ -776,15 +776,15 @@ considerata conclusa, anche se vi sono altri parametri che cominciano con Quando la funzione trova un'opzione essa ritorna il valore numerico del carattere, in questo modo si possono prendere le azioni relative usando un case; la funzione inizializza inoltre alcune variabili globali: -\begin{itemize} -\item \texttt{char * optarg} contiene il puntatore alla stringa argomento +\begin{itemize*} +\item \var{char * optarg} contiene il puntatore alla stringa argomento dell'opzione. -\item \texttt{int optind} alla fine della scansione restituisce l'indice del +\item \var{int optind} alla fine della scansione restituisce l'indice del primo argomento che non è un'opzione. -\item \texttt{int opterr} previene, se posto a zero, la stampa di un messaggio +\item \var{int opterr} previene, se posto a zero, la stampa di un messaggio di errore in caso di riconoscimento di opzioni non definite. -\item \texttt{int optopt} contiene il carattere dell'opzione non riconosciuta. -\end{itemize} +\item \var{int optopt} contiene il carattere dell'opzione non riconosciuta. +\end{itemize*} In \nfig\ è mostrato un programma di esempio: \begin{figure}[htbp] diff --git a/prochand.tex b/prochand.tex index 66aa002..ef6c064 100644 --- a/prochand.tex +++ b/prochand.tex @@ -529,7 +529,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 +547,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 +558,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 +611,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 +622,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 @@ -1141,7 +1141,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 +1161,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 +1205,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 +1260,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,88 +1337,155 @@ 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}, 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}. + + +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 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, per effettuare il lavoro che non necessita di privilegi aggiuntivi, +ed eventualmente tornare indietro. + +Occorre però tenere conto che tutto questo non è possibile nel caso di root, +in tal caso infatti l'esecuzione una \func{setuid} con un \textit{effective + user id} uguale a zero comporta il cambiamento di tutti gli identificatori +associati al processo rendendo impossibile riguadagnare i privilegi di +amministratore. Questo è l'uso che ne fa \cmd{login} una volta che crea una +nuova shell per l'utente, ma se si vuole cambiare soltanto l'\textit{effective + user id} occorre ricorrere ad altre funzioni (si veda ad esempio +\secref{sec:proc_seteuid}). + +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 (ed usando il \textit{real + group id} 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}. + + +\subsection{Le funzioni \func{seteuid} e \func{setegid}} \label{sec:proc_seteuid} +\subsection{Le funzioni \func{setreuid} e \func{setresuid}} +\label{sec:proc_setreuid} + + +\subsection{Le funzioni \func{setfsuid} e \func{setfsgid}} +\label{sec:proc_setfsuid} + + + \subsection{Le \textit{race condition}} \label{sec:proc_race_cond}