si tronca il file con \const{O\_TRUNC} verranno impostati soltanto il
\textit{modification time} e lo \textit{status change time}.
-Il flag \constd{O\_TMPFILE}, introdotto con il kernel
-3.11,\footnote{inizialmente solo su alcuni filesystem (i vari \acr{extN},
- \acr{Minix}, \acr{UDF}, \acr{shmem}) poi progressivamente esteso ad altri
- (\acr{XFS} con il 3.15, \acr{Btrfs} e \acr{F2FS} con il 3.16, \acr{ubifs}
- con il 4.9).} consente di aprire un file temporaneo senza che questo venga
-associato ad un nome e compaia nel filesystem. In questo caso la funzione
-restituirà un file descriptor da poter utilizzare per leggere e scrivere dati,
-ma il contenuto dell'argomento \param{path} verrà usato solamente per
-determinare, in base alla directory su cui si verrebbe a trovare il
-\textit{pathname} indicato, il filesystem all'interno del quale deve essere
+Il flag \label{open_o_tmpfile_flag} \constd{O\_TMPFILE}, introdotto con il
+kernel 3.11,\footnote{inizialmente solo su alcuni filesystem (i vari
+ \acr{extN}, \acr{Minix}, \acr{UDF}, \acr{shmem}) poi progressivamente esteso
+ ad altri (\acr{XFS} con il 3.15, \acr{Btrfs} e \acr{F2FS} con il 3.16,
+ \acr{ubifs} con il 4.9).} consente di aprire un file temporaneo senza che
+questo venga associato ad un nome e compaia nel filesystem. In questo caso la
+funzione restituirà un file descriptor da poter utilizzare per leggere e
+scrivere dati, ma il contenuto dell'argomento \param{path} verrà usato
+solamente per determinare, in base alla directory su cui si verrebbe a trovare
+il \textit{pathname} indicato, il filesystem all'interno del quale deve essere
allocato l'\textit{inode} e lo spazio disco usato dal file
descriptor. L'\textit{inode} resterà anonimo e l'unico riferimento esistente
sarà quello contenuto nella \textit{file table} del processo che ha chiamato
limitata al filesystem su cui il file ad esso corrispondente si trova.
+
\subsection{Le \textit{at-functions}: \func{openat} e le altre}
\label{sec:file_openat}
(ad esempio usando \func{open} con il flag \const{O\_PATH} visto in
sez.~\ref{sec:file_open_close}) per ottenere un file descriptor che dovrà
essere passato alle stesse. Tutte queste funzioni infatti prevedono la
-presenza un apposito argomento, in genere il primo, che negli esempi seguenti
-chiameremo sempre \param{dirfd}.
+presenza un apposito argomento, in genere il primo che negli esempi seguenti
+chiameremo sempre \param{dirfd}, per indicare la directory di partenza.
In questo modo, una volta aperta la directory di partenza, si potranno
effettuare controlli ed aperture solo con \textit{pathname} relativi alla
file che essa contiene. Infine poter identificare una directory di partenza
tramite il suo file descriptor consente di avere un riferimento stabile alla
stessa anche qualora venisse rinominata, e tiene occupato il filesystem dove
-si trova, come per la directory di lavoro di un processo.
+si trova come per la directory di lavoro di un processo.
La sintassi generica di queste nuove funzioni prevede l'utilizzo come primo
argomento del file descriptor della directory da usare come base per la
La funzione esegue il controllo di accesso ad un file, e \param{flags}
consente di modificarne il comportamento rispetto a quello ordinario di
-\func{access} (cui è analoga, e con cui condivide i problemi di sicurezza
+\func{access} (cui è analoga e con cui condivide i problemi di sicurezza
visti in sez.~\ref{sec:file_stat}) usando il valore \const{AT\_EACCES} per
indicare alla funzione di eseguire il controllo dei permessi con l'\ids{UID}
\textsl{effettivo} invece di quello \textsl{reale}. L'unico altro valore
\item[\errcode{EBADF}] \param{olddirfd} o \param{newdirfd} non sono un file
descriptor valido.
\item[\errcode{EINVAL}] \param{flags} non ha un valore valido.
+ \item[\errcode{ENOENT}] \param{oldpath} o \param{newpath} è un
+ \textit{pathname} relativo, ma la corrispondente directory di partenza
+ (\param{olddirfd} o \param{newdirfd}) è stata cancellata, oppure si è
+ cercato di creare un \textit{link} da un file descriptor aperto con
+ \const{O\_TMPFILE} e \const{O\_EXCL}, oppure si è usato
+ \const{AT\_EMPTY\_PATH} senza privilegi amministrativi.
\item[\errcode{ENOTDIR}] \param{oldpath} e \param{newpath} sono
- \textit{pathname} relativi, ma \param{oldirfd} o \param{newdirfd} fa
+ \textit{pathname} relativi, ma \param{olddirfd} o \param{newdirfd} fa
riferimento ad un file.
+ \item[\errcode{EPERM}] si è usato \const{AT\_EMPTY\_PATH} con
+ \param{oldpath} vuoto e \param{olddirfd} che fa riferimento ad una
+ directory.
\end{errlist}
}
\end{funcproto}
-Anche in questo caso la funzione è sostanzialmente identica alla classica
-\func{link}, ma dovendo specificare due \textit{pathname} (sorgente e
-destinazione) aggiunge a ciascuno di essi un argomento (rispettivamente
-\param{olddirfd} e \param{newdirfd}) per poter indicare entrambi come relativi
-a due directory aperte in precedenza.
+Anche in questo caso la funzione svolge lo stesso compito della
+corrispondente classica \func{link}, ma dovendo specificare due
+\textit{pathname} (sorgente e destinazione) aggiunge a ciascuno di essi un
+argomento (rispettivamente \param{olddirfd} e \param{newdirfd}) per poter
+indicare entrambi come relativi a due directory aperte in precedenza.
In questo caso, dato che su Linux il comportamento di \func{link} è quello di
non seguire mai i collegamenti simbolici, \const{AT\_SYMLINK\_NOFOLLOW} non
viene utilizzato. A partire dal kernel 2.6.18 è stato aggiunto a questa
funzione la possibilità di usare il valore \const{AT\_SYMLINK\_FOLLOW} per
-l'argomento \param{flags},\footnote{nei kernel precendenti, dall'introduzione
+l'argomento \param{flags},\footnote{nei kernel precedenti, dall'introduzione
nel 2.6.16, l'argomento \param{flags} era presente, ma senza alcun valore
valido, e doveva essere passato sempre con valore nullo.} che richiede di
-dereferenziare i collegamenti simbolici. Inoltre a partire dal kernel 3.11 si
-può usare \const{AT\_EMPTY\_PATH} per creare un nuovo \textit{hard link} al
-file associato al file descriptor \param{olddirfd}.
+dereferenziare un eventuale collegamento simbolico creando un \textit{hard
+ link} al file puntato da quest'ultimo.
+
+Inoltre a partire dal kernel 3.11 si può usare \const{AT\_EMPTY\_PATH} con lo
+stesso significato già visto in precedenza applicato ad \param{olddirfd}, si
+può cioè creare un nuovo \textit{hard link} al file associato al file
+descriptor \param{olddirfd}, passando un valore nullo per
+\param{oldpath}. Questa operazione però è privilegiata e richiede i privilegi
+di amministratore (la \textit{capability} \const{CAP\_DAC\_READ\_SEARCH}),
+infatti in questo modo la funzione si comporta come una ipotetica
+\texttt{flink}, una \textit{system call} di cui è stato spesso chiesta la
+creazione, che permetterebbe di associare direttamente un nome ad un file
+descriptor, ma che non è mai stata realizzata per problemi di sicurezza.
+
+Il problema infatti è che le verifiche di accesso sono fatte quando il file
+viene aperto e non attengono solo ai permessi del file stesso, ma anche a
+quelli delle directory del suo \textit{pathname}; se una volta aperto venisse
+collegato in un altra directory eventuali restrizioni imposte sulle directory
+del suo \textit{pathname} andrebbero perse. Inoltre sarebbe possibile accedere
+al file sottostante anche in scrittura per un file descriptor che è stato
+fornito come aperto in sola lettura, o con accesso libero per un file
+descriptor fornito aperto in \textit{append}. Infine e la funzione
+consentirebbe rendere accessibile all'interno di un \textit{choot} (vedi
+sez.~\ref{sec:file_chroot}) un qualunque file sia stato aperto fuori dallo
+stesso prima di entrarvi.
% NOTE per la discussione sui problemi di sicurezza relativi a questa
% funzionalità vedi http://lwn.net/Articles/562488/
-La funzione prevede inoltre un comportamento specifico nel caso che
-\param{olddirfd} faccia riferimento ad un file anonimo ottenuto usando
-\func{open} con \const{O\_TMPFILE}. In generale quando il file associato ad
-\param{olddirfd} ha un numero di link nullo (come in questo caso), la funzione
-fallisce, c'è però una
+Per questo motivo l'uso di \const{AT\_EMPTY\_PATH} richiede comunque privilegi
+amministrativi, anche se, quando è disponibile il filesystem \texttt{/proc}, è
+possibile usare \func{linkat} per creare un file da un qualunque file
+descriptor un processo abbia aperto, usandola con un codice analogo al
+seguente:\footnote{non esiste, al momento, una modalità per evitare i rischi
+ illustrati in precedenza se si sta usando il filesystem \textit{proc}.}
+\includecodesnip{listati/procfd_linkat.c}
+
+Questa modalità è anche quella con cui è possibile assegnare in un secondo
+tempo il nome ad un file anonimo creato usando \func{open} con
+\const{O\_TMPFILE}; ma si deve tenere presente che per questi file la funzione
+ha un comportamento particolare. In generale infatti quando il file sorgente
+di \func{linkat} ha un numero di collegamenti nulli (cosa che avviene ad
+esempio quando si apre un file temporaneo e lo si cancella subito dopo oppure
+quando viene cancellato un file aperto in precedenza) la funzione non consente
+di ricollegarlo ad un altro file riassegnandogli un nuovo nome e fallisce
+sempre, qualunque siano i permessi del processo e che si usi questo approccio
+o \const{AT\_EMPTY\_PATH}, con un errore di \errval{ENOENT}.
+
+Questo non avviene se il file descriptor sorgente è stato ottenuto con
+\const{O\_TMPFILE} e la funzione ha successo, a meno che non si sia usato
+nell'apertura anche \const{O\_EXCL} per impedire questo specifico
+comportamento, e continuare ad ottenere l'errore di \errval{ENOENT}. In fig.
+
+Pertanto la modalità per creare in maniera sicura la versione iniziale di un
+file cui abbiamo accennato a pag.~\pageref{open_o_tmpfile_flag},
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/initfile.c}
+ \end{minipage}
+ \caption{Esempio di codice creare in maniera sicura il contenuto iniziale di
+ un file.}
+ \label{fig:initfile}
+\end{figure}
+
+
-l'uso di \const{AT\_EMPTY\_PATH} assume un significato
-ulteriore, e richiede i privilegi di amministratore (la \textit{capability}
-\const{CAP\_DAC\_READ\_SEARCH}) quando viene usato con un file descriptor
-anomino ottenuto usando \const{O\_TMPFILE} con \func{open}. In generale
+
+
+% TODO: Trattare esempio di inzializzazione di file e successivo collegamento
+% con l'uso di O_TMPFILE e linkat, vedi man open
+
+
+
+% TODO manca prototipo di renameat2, introdotta nel 3.15, vedi
+% http://lwn.net/Articles/569134/
Altre due funzioni che utilizzano due \textit{pathname} (e due file
In realtà la corrispondente di \func{rename}, prevista dallo standard
POSIX.1-2008 e disponibile dal kernel 2.6.16 come le altre
-\textit{at-functions}, sarebbe soltanti \func{renameat}, su Linux però, a
+\textit{at-functions}, sarebbe soltanto \func{renameat}, su Linux però, a
partire dal kernel dal 3.15, questa è stata realizzata in termini della nuova
funzione di sistema \func{renameat2} che prevede l'uso dell'argomento
aggiuntivo \param{flags}; in questo caso \func{renameat} è totalmente
\param{flags}.
L'uso di \func{renameat} è identico a quello di \func{rename}, con le solite
-note relativie alle estensioni delle \textit{at-functions}, applicate ad
+note relative alle estensioni delle \textit{at-functions}, applicate ad
entrambi i \textit{pathname} passati come argomenti alla funzione. Con
\func{renameat2} l'introduzione dell'argomento \func{flags} (i cui valori
possibili sono riportati in tab.~\ref{tab:renameat2_flag_values}) ha permesso
\itindbeg{union~filesytem}
Infine il flag \constd{RENAME\_WHITEOUT}, introdotto con il kernel 3.18,
-richiede un approfomdimento specifico, in quanto attiene all'uso della
+richiede un approfondimento specifico, in quanto attiene all'uso della
funzione con dei filesystem di tipo \textit{overlay}/\textit{union}, dato che
il flag ha senso solo quando applicato a file che stanno su questo tipo di
filesystem.
% https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a528d35e8bfcc521d7cb70aaf03e1bd296c8493f)
-% TODO: Trattare esempio di inzializzazione di file e successivo collegamento
-% con l'uso di O_TMPFILE e linkat, vedi man open
-
% TODO: manca prototipo e motivazione di fexecve, da trattare qui in quanto
% inserita nello stesso standard e da usare con openat, vedi
% http://pubs.opengroup.org/onlinepubs/9699939699/toc.pdf
% TODO: manca prototipo e motivazione di execveat, vedi
% http://man7.org/linux/man-pages/man2/execveat.2.html
-% TODO manca prototipo di renameat2, introdotta nel 3.15, vedi
-% http://lwn.net/Articles/569134/
-
% TODO: trattare i nuovi AT_flags quando e se arriveranno, vedi
% https://lwn.net/Articles/767547/
-
-
\itindend{at-functions}
% LocalWords: FIONREAD epoll FIOQSIZE side effects SAFE BYCALLER QUERY EACCES
% LocalWords: EBUSY OpenBSD syncfs futimes timespec only init ESRCH kill NTPL
% LocalWords: ENXIO NONBLOCK WRONLY EPERM NOATIME ETXTBSY EWOULDBLOCK PGRP SZ
-% LocalWords: EFAULT capabilities GETPIPE SETPIPE RESOURCE dell'I all' NFSv
+% LocalWords: EFAULT capabilities GETPIPE SETPIPE RESOURCE NFSv
+% LocalWords: Documentation Urlich Drepper futimesat times
+% LocalWords: futimens fs Tread TMPFILE EDQUOT extN Minix UDF XFS
+% LocalWords: shmem Btrfs ubifs tmpfile fchmod fchown fsetxattr fchdir PF
+% LocalWords: fstatfs SIGTTIN EDESTADDRREQ datagram connect seal pag
+% LocalWords: dirty execveat execve scandirat statx AUTOMOUNT automount DAC
+% LocalWords: wrapper EMPTY olddirfd oldpath newdirfd newpath capability
+% LocalWords: SEARCH flink choot oldirfd NOREPLACE EXCHANGE WHITEOUT union
+% LocalWords: renamat syscall whiteout overlay filesytem Live
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "gapil"
%%% End:
-% LocalWords: nell' du vm Documentation Urlich Drepper futimesat times l'I
-% LocalWords: futimens fs Tread all'I ll TMPFILE EDQUOT extN Minix UDF XFS
-% LocalWords: shmem Btrfs ubifs tmpfile fchmod fchown fsetxattr fchdir PF
-% LocalWords: fstatfs sull' SIGTTIN EDESTADDRREQ datagram connect seal
-% LocalWords: dirty execveat execve scandirat statx
--- /dev/null
+/* test_initfile.c
+ *
+ * Copyright (C) 2019 Simone Piccardi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/****************************************************************
+ *
+ * Program test_linkat.c:
+ * Program to test use of linkat with an O_TMPFILE or linking another file
+ * using AT_EMPTY_PATH or AT_SYMLINK_FOLLOW on /proc/self/fd/N
+ * giving the option to wait to remove source file
+ *
+ * Author: Simone Piccardi
+ * Oct. 2018
+ *
+ * Usage: testlinkat -h give all info's
+ *
+ ****************************************************************/
+/*
+ * Include needed headers
+ */
+#define _GNU_SOURCE
+#include <errno.h> /* error definitions and routines */
+#include <stdlib.h> /* C standard library */
+#include <unistd.h> /* unix standard library */
+#include <stdio.h> /* standard I/O library */
+#include <string.h> /* C strings library */
+#include <limits.h>
+#include <libgen.h> /* needed for dirname e basename */
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "Gapil.h"
+#include "macros.h"
+
+/* Help printing routine */
+void usage(void);
+
+int main(int argc, char *argv[])
+{
+/*
+ * Variables definition
+ */
+ /*
+ * Input section: decode command line parameters
+ * Use getopt function
+ */
+ int i;
+ opterr = 0; /* don't want writing to stderr */
+ while ( (i = getopt(argc, argv, "hw:f:")) != -1) {
+ switch (i) {
+ /*
+ * Handling options
+ */
+ case 'h': /* help option */
+ printf("Wrong -h option use\n");
+ usage();
+ return -1;
+ break;
+ case '?': /* unrecognized options */
+ printf("Unrecognized options -%c\n",optopt);
+ usage();
+ default: /* should not reached */
+ usage();
+ }
+ }
+ /* ***********************************************************
+ *
+ * Options processing completed
+ *
+ * Main code beginning
+ *
+ * ***********************************************************/
+ /* There must be 1 remaing parameters */
+ if ( (argc-optind) != 2 ) {
+ printf("From %d arguments, removed %d options\n", argc, optind);
+ usage();
+ }
+ char *path, *dir, *file;
+ path = strdup(argv[optind]);
+ file = basename(argv[optind]);
+ dir = dirname(argv[optind]);
+ printf("Destination on dir %s file: %s\n with path: %s\n",
+ dir, file, path);
+ int newfd, res, count;
+ count = strlen(argv[optind+1]);
+ newfd = open(dir, O_PATH|O_RDWR);
+ res = InitFile(newfd, file, argv[optind+1], count);
+ free(path);
+ return 0;
+}
+/*
+ * routine to print usage info and exit
+ */
+void usage(void) {
+ printf("Program test_initfile : test initfile \n");
+ printf("Create a link to a tempfile or a link to -f indicated file");
+ printf("Usage:\n");
+ printf(" test_initfile [-h] pathname 'test to be written on pathname' \n");
+ printf(" -h print this help\n");
+
+ exit(1);
+}
+
/****************************************************************
*
* Program test_linkat.c:
- * Program to test use of linkat and O_TMPFILE and other combinations
+ * Program to test use of linkat with an O_TMPFILE or linking another file
+ * using AT_EMPTY_PATH or AT_SYMLINK_FOLLOW on /proc/self/fd/N
+ * giving the option to wait to remove source file
*
* Author: Simone Piccardi
* Oct. 2018
#include <sys/types.h>
#include <fcntl.h>
+
/* Help printing routine */
void usage(void);
}
char *path, *dir, *file;
char pattern[] = "prova prova prova\n";
+ char outbuff[2048];
path = strdup(argv[optind]);
file = basename(argv[optind]);
dir = dirname(argv[optind]);
- printf("Working on dir %s file: %s\nwith path: %s\n",
+ printf("Destination on dir %s file: %s\n with path: %s\n",
dir, file, path);
int fd, newfd;
if ( ! srcfile ) {
+ // temp file with O_TMPFILE
fd = open(dir, O_TMPFILE|O_RDWR,S_IRUSR|S_IWUSR);
if ( fd <= 0 )
perror("cannot open TMPFILE");
else
printf("saved %d chars on fd %d\n", i, fd);
} else {
- printf("source is %s\n", srcfile);
+ // user provided source
+ printf("source file is %s\n", srcfile);
if ( (fd = open(srcfile, O_RDONLY)) < 0 ) {
perror("cannot open source");
exit(1);
}
+ printf("waiting %d second to remove the file\n", wait);
+ sleep(wait);
}
newfd = open(dir, O_PATH|O_RDWR);
int err;
err = linkat(fd, "", newfd, file, AT_EMPTY_PATH);
if ( err < 0 ) {
- perror("error on creating TMPFILE");
- printf("cannot link fd %d on fd %d, %s with AT_EMPTY_PATH\n",
+ perror("error on creating TMPFILE with AT_EMPTY_PATH");
+ printf("cannot link fd %d on fd %d/%s with AT_EMPTY_PATH\n",
fd, newfd, file);
char fdpath[PATH_MAX];
snprintf(fdpath, PATH_MAX, "/proc/self/fd/%d", fd);
- printf("fd path %s\n", fdpath);
+ printf("Attempt to use AT_SYMLINK_FOLLOW with path %s\n", fdpath);
err = linkat(AT_FDCWD, fdpath, newfd, file, AT_SYMLINK_FOLLOW);
if ( err < 0 ) {
perror("still error creating TMPFILE");
- sleep(wait);
exit(1);
- }
+ } else {
+ printf("Success, fd %d on fd %d/%s created\n", fd, newfd, file);
+ }
if ( fchmodat(newfd, file,S_IRUSR|S_IWUSR,0) < 0 )
perror("Cannot change permission to new file");
}
*/
void usage(void) {
printf("Program testlinkat : test linkat for a file \n");
+ printf("Create a link to a tempfile or a link to -f indicated file");
printf("Usage:\n");
- printf(" testlinkat [-h] file mode \n");
+ printf(" testlinkat [-h] destfilepathname \n");
printf(" -h print this help\n");
printf(" -w [N] wait N seconds\n");
printf(" -f [file] use file as source\n");