From dc136036383f501fb6604bc04ce8a49abdbe9339 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Thu, 22 Aug 2019 13:54:16 +0200 Subject: [PATCH] Finite fexecve e execveat --- fileio.tex | 79 +++++++++++++++++++++++++++++++------------------ listati/statx.h | 16 +++++----- 2 files changed, 59 insertions(+), 36 deletions(-) diff --git a/fileio.tex b/fileio.tex index 5444348..a0d5475 100644 --- a/fileio.tex +++ b/fileio.tex @@ -2708,13 +2708,13 @@ ad informazioni locali, e sono sempre disponibili in maniera diretta. % NOTE: per statx https://lwn.net/Articles/707602/ e % https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a528d35e8bfcc521d7cb70aaf03e1bd296c8493f) -Infine trattiamo qui altre due funzioni che non attengono che in maniera -indiretta all'uso dei file, ma sono comunque legate all'interfaccia delle -\textit{at-functions}. In realtà la sola effettivamente collegata -all'interfaccia delle \textit{at-functions} è la funzione di sistema -\func{execveat}, introdotta con il kernel 3.19, e per la quale non è -disponibile ancora un'interfaccia diretta nella \acr{glibc} che però la usa -(quando disponibile) per realizzare \func{fexecve}. +Infine trattiamo qui altre due funzioni, \func{fexecve} e \func{execveat}, che +non attengono che in maniera indiretta all'uso dei file, ma sono comunque +legate all'interfaccia delle \textit{at-functions}. In realtà la sola +effettivamente collegata all'interfaccia delle \textit{at-functions} è la +funzione di sistema \func{execveat}, introdotta con il kernel 3.19, e per la +quale non è disponibile ancora un'interfaccia diretta nella \acr{glibc} che +però la usa (quando disponibile) per realizzare \func{fexecve}. L'introduzione di queste funzioni nasce dall'esigenza di verificare i contenuti di un file eseguibile prima di eseguirlo. Fare il controllo (aprendo @@ -2748,8 +2748,8 @@ avere il permesso di esecuzione) corrispondente a \param{fd}; questo deve essere stato ottenuto aprendo il relativo eseguibile in sola lettura o con \const{O\_PATH}. Questa funzione fino al kernel 3.19 veniva realizzata nella \acr{glibc} usando il filesystem \file{/proc} per ottenere da \param{fd} il -file corrispondente, in maniera analoga a quanto visto per l'esempio di -fig.~\ref{fig:initfile}. +file corrispondente in \file{/proc/self/fd/}, in maniera analoga a quanto +visto per l'esempio di fig.~\ref{fig:initfile}. La funzione di sistema \funcd{execveat} è stata introdotta proprio per rendere più sicura l'esecuzione ed evitare la necessità di avere disponibile @@ -2779,28 +2779,49 @@ più sicura l'esecuzione ed evitare la necessità di avere disponibile \end{funcproto} La funzione segue la sintassi delle \textit{at-functions} per indicare il file -da eseguire, e per il resto si comporta esattamente con come \func{execve}; è -pertanto possibile indicare il programma da eseguire sia con un -\textit{pathname} assoluto che relativo, ed anche con un \textit{pathname} -relativo alla directory indicata da \param{dirfd}. Inoltre usando per -\param{flags} il valore \const{AT\_EMPTY\_PATH} si può indicare direttamente -il file con il file descriptor \param{dirfd} ottenendo il comportamento di -\func{fexecve}, che è equivalnente all'esecuzione di: -\includecodesnip{listati/fexecve.c} l'unico altro valore utilizzabile per -\param{flags} è \const{AT\_SYMLINK\_NOFOLLOW} che fa fallire la funzione con -un errore di \errval{ELOOP} se il file indicato è un link simbolico. +da eseguire, e per il resto si comporta esattamente con come \func{execve} (le +cui caratteristiche sono già state illustrate in +sez.~\ref{sec:file_stat}). Diventa così possibile indicare il programma da +eseguire sia con un \textit{pathname} assoluto che relativo (usando +\const{AT\_FDCWD} come \param{dirfd}), oppure con un \textit{pathname} +relativo alla directory indicata da \param{dirfd}. In quest'ultima forma l'uso +della funzione consente estendere i vantaggi delle \textit{at-functions} anche +al caso dell'esecuzione di un programma. + +Inoltre usando, per \param{flags} il valore \const{AT\_EMPTY\_PATH}, si può +indicare direttamente il file da eseguire aprendolo e passandone il file +descriptor nell'argomento \param{dirfd}, ottenendo il comportamento di +\func{fexecve}; quest'ultima infatti è sostanzialmente equivalente +all'esecuzione di: \includecodesnip{listati/fexecve.c} l'unico altro valore +utilizzabile per \param{flags} è \const{AT\_SYMLINK\_NOFOLLOW} che fa fallire +la funzione con un errore di \errval{ELOOP}, se il file indicato è un link +simbolico. Quando si usano \func{execveat} o \func{fexecve} per eseguire un programma -attraverso un file descriptor è opportuno impostare sempre sullo stesso il -flag di \textit{close-on-exec}, in modo che questo venga automaticamente -chiuso all'esecuzione. Questo evita di consumare inutilmente un file -descriptor (un programma non ha bisogno di un riferimento a se stesso), ma -soprattutto evita problemi in caso di un eventuale uso ricorsivo di queste -funzioni che potrebbe portare, restando aperto ogni volta un ulteriore file -descriptor, all'esaurimento degli stessi. - - - +attraverso un file descriptor è naturale impostare sullo stesso il flag di +\textit{close-on-exec} in modo che questo venga automaticamente chiuso +all'esecuzione. Questo evita di lasciare aperto inutilmente un file descriptor +(un programma in genere non ha bisogno di avere un file aperto su se stesso), +ma soprattutto evita problemi in caso di un eventuale uso ricorsivo di queste +funzioni, in tal caso infatti, restando aperto ad ogni iterazione un ulteriore +file descriptor, si potrebbe arrivare all'esaurimento degli stessi. + +Tutto questo però non è vero quando si vuole eseguire uno script; in tal caso +infatti (si ricordi quanto detto a questo riguardo in +sez.~\ref{sec:file_stat}) il programma che viene effettivamente messo in +esecuzione è l'interprete indicato nella riga iniziale dello script, che poi +legge ed interpreta il codice da eseguire dallo script stesso. Ma se lancia lo +script usando un file descriptor su cui è attivo il flag di +\textit{close-on-exec}, questo sarà già chiuso quando l'interprete viene posto +in esecuzione, rendendo impossibile la lettura del programma da +interpretare. + +Per questo motivo, quando ci si trova in questa situazione, \func{execveat} (e +quindi anche \func{fexecve}) eseguono un controllo preventivo e falliscono con +un errore di \errval{ENOENT}. Pertanto se si vuole eseguire uno script +passandone il file descriptor l'unica possibilità è non attivare il flag di +\textit{close-on-exec}, esponendosi però al rischio di incorrere nei problemi +accennati in precedenza. % TODO: manca prototipo e motivazione di fexecve, da trattare qui in quanto % inserita nello stesso standard e da usare con openat, vedi diff --git a/listati/statx.h b/listati/statx.h index 4eecfd6..5bec4de 100644 --- a/listati/statx.h +++ b/listati/statx.h @@ -1,21 +1,22 @@ struct statx { __u32 stx_mask; /* Mask of bits indicating filled fields */ - __u32 stx_blksize; /* Block size for filesystem I/O */ + __u32 stx_blksize; /* Preferred block size for filesystem I/O */ __u64 stx_attributes; /* Extra file attribute indicators */ __u32 stx_nlink; /* Number of hard links */ __u32 stx_uid; /* User ID of owner */ __u32 stx_gid; /* Group ID of owner */ __u16 stx_mode; /* File type and mode */ + __u16 __spare0[1]; __u64 stx_ino; /* Inode number */ - __u64 stx_size; /* Total size in bytes */ - __u64 stx_blocks; /* Number of 512B blocks allocated */ + __u64 stx_size; /* File size in bytes */ + __u64 stx_blocks; /* Number of 512-byte blocks allocated */ __u64 stx_attributes_mask; /* Mask to show what's supported in stx_attributes */ /* The following fields are file timestamps */ - struct statx_timestamp stx_atime; /* Last access */ - struct statx_timestamp stx_btime; /* Creation */ - struct statx_timestamp stx_ctime; /* Last status change */ - struct statx_timestamp stx_mtime; /* Last modification */ + struct statx_timestamp stx_atime; /* Last access time */ + struct statx_timestamp stx_btime; /* File creation time */ + struct statx_timestamp stx_ctime; /* Last status change time */ + struct statx_timestamp stx_mtime; /* Last data modification time */ /* If this file represents a device, then the next two fields contain the ID of the device */ __u32 stx_rdev_major; /* Major ID */ @@ -24,4 +25,5 @@ struct statx { containing the filesystem where the file resides */ __u32 stx_dev_major; /* Major ID */ __u32 stx_dev_minor; /* Minor ID */ + __u64 __spare2[14]; /* Spare space for future expansion */ }; -- 2.30.2