From 4be39dd3718d708ccff65b01a8f634e05b56f3c9 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sun, 18 Aug 2019 01:25:44 +0200 Subject: [PATCH] Trattazione di linkat e openat con O_TMPFILE, con programmi di test ed esempi. --- filedir.tex | 13 ++-- fileio.tex | 165 ++++++++++++++++++++++++++++------------ listati/procfd_linkat.c | 1 + procadv.tex | 5 +- prochand.tex | 1 - sources/Gapil.h | 3 + sources/InitFile.c | 64 ++++++++++++++++ sources/Makefile | 4 + sources/test_initfile.c | 118 ++++++++++++++++++++++++++++ sources/test_linkat.c | 28 ++++--- 10 files changed, 334 insertions(+), 68 deletions(-) create mode 100644 listati/procfd_linkat.c create mode 100644 sources/InitFile.c create mode 100644 sources/test_initfile.c diff --git a/filedir.tex b/filedir.tex index d2558c5..6577274 100644 --- a/filedir.tex +++ b/filedir.tex @@ -6189,7 +6189,7 @@ riservati nella directory radice del filesystem su cui si sono attivate le quote, uno per le quote utente e l'altro per le quote gruppo.\footnote{la cosa vale per tutti i filesystem tranne \textit{XFS} che mantiene i dati internamente, compresi quelli per le \textit{project quota}, che pertanto, - essendo questo l'unico filesyste che le supporta, non hanno un file ad esse + essendo questo l'unico filesystem che le supporta, non hanno un file ad esse riservato.} Con la versione 2 del supporto delle quote, che da anni è l'unica rimasta in uso, questi file sono \texttt{aquota.user} e \texttt{aquota.group}, in precedenza erano \texttt{quota.user} e @@ -6618,6 +6618,7 @@ restituire nessun dato in caso di successo si usa (\texttt{\small 10}) una apposita funzione di uscita, mentre si restituisce come prima una eccezione con il valore di \var{errno} in caso di errore (\texttt{\small 12-13}). + \subsection{La gestione dei {chroot}} \label{sec:file_chroot} @@ -6773,7 +6774,7 @@ librerie) di cui il server potrebbe avere bisogno. % LocalWords: setresuid setfsuid IMMUTABLE immutable append only BIND SERVICE % LocalWords: BROADCAST broadcast multicast multicasting RAW PACKET IPC LOCK % LocalWords: memory mlock mlockall shmctl mmap MODULE RAWIO ioperm iopl PACCT -% LocalWords: ptrace accounting NICE RESOURCE TTY CONFIG hangup vhangup dell' +% LocalWords: ptrace accounting NICE RESOURCE TTY CONFIG hangup vhangup % LocalWords: LEASE lease SETFCAP AUDIT permitted inherited inheritable AND nn % LocalWords: bounding execve fork capget capset header hdrp datap ESRCH undef % LocalWords: version libcap lcap clear ncap caps pag capgetp CapInh CapPrm RT @@ -6786,8 +6787,8 @@ librerie) di cui il server potrebbe avere bisogno. % LocalWords: REALTIME securebits GETSTATS QFMT curspace curinodes btime itime % LocalWords: QIF BLIMITS bhardlimit bsoftlimit ILIMITS ihardlimit isoftlimit % LocalWords: INODES LIMITS USAGE valid dqi IIF BGRACE bgrace IGRACE igrace is -% LocalWords: Python Truelite Srl quotamodule Repository who nell' dall' KEEP -% LocalWords: SECURE KEEPCAPS prctl FIXUP NOROOT LOCKED dell'IPC dell'I IOPRIO +% LocalWords: Python Truelite Srl quotamodule Repository who KEEP +% LocalWords: SECURE KEEPCAPS prctl FIXUP NOROOT LOCKED dell'IPC IOPRIO % LocalWords: CAPBSET CLASS IDLE dcookie overflow DIFFERS Virtual everything % LocalWords: dentry register resolution cache dcache operation llseek poll ln % LocalWords: multiplexing fsync fasync seek block superblock gapil tex img du @@ -6803,8 +6804,8 @@ librerie) di cui il server potrebbe avere bisogno. % LocalWords: faccessat grpid lacl AppArmor capsetp mygetfacl table Tb MSK % LocalWords: LAZYTIME submount peer protected hardlink symlinks silly RDWR % LocalWords: renames unreachable CLOEXEC mkstemps mkostemps suffixlen Aug -% LocalWords: prefissoXXXXXXsuffisso nell'I fstatat statx sull' drwxrwxrwt -% LocalWords: Disalloca +% LocalWords: prefissoXXXXXXsuffisso fstatat statx drwxrwxrwt xattr +% LocalWords: Disalloca project %%% Local Variables: %%% mode: latex diff --git a/fileio.tex b/fileio.tex index 27c02ac..d2522e1 100644 --- a/fileio.tex +++ b/fileio.tex @@ -510,16 +510,16 @@ tab.~\ref{tab:file_file_times} vengono impostati al tempo corrente. Se invece 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 @@ -1722,6 +1722,7 @@ descriptor su cui si sta operando, e la registrazione immediata dei dati sarà 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} @@ -1775,8 +1776,8 @@ si intende usare come base per la risoluzione dei \textit{pathname} relativi (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 @@ -1796,7 +1797,7 @@ profonde. Infatti in questo caso basta eseguire la risoluzione del 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 @@ -2026,7 +2027,7 @@ il suo prototipo è: 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 @@ -2175,45 +2176,114 @@ suo prototipo è: \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 @@ -2256,7 +2326,7 @@ classica \func{rename}; i rispettivi prototipi sono: 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 @@ -2264,7 +2334,7 @@ equivalente all'utilizzo di \func{renamat2} con un valore nullo per \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 @@ -2319,7 +2389,7 @@ quella del cambio di nome. \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. @@ -2347,9 +2417,6 @@ che esso non appaia più è possibile creare % 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 @@ -2358,15 +2425,10 @@ che esso non appaia più è possibile creare % 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} @@ -4745,15 +4807,18 @@ con uno dei valori \const{FSETLOCKING\_INTERNAL} o % 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 diff --git a/listati/procfd_linkat.c b/listati/procfd_linkat.c new file mode 100644 index 0000000..e806e8c --- /dev/null +++ b/listati/procfd_linkat.c @@ -0,0 +1 @@ +linkat(AT_FDCWD,"/proc/self/fd/3",dirfd,file,AT_SYMLINK_FOLLOW); diff --git a/procadv.tex b/procadv.tex index d44570f..e14392f 100644 --- a/procadv.tex +++ b/procadv.tex @@ -6,7 +6,7 @@ dei processi. Inizieremo con le funzioni che attengono alla gestione avanzata della sicurezza, passando poi a quelle relative all'analisi ed al controllo dell'esecuzione, e alle funzioni per le modalità avanzate di creazione dei processi e l'uso dei cosiddetti \textit{namespace}. Infine affronteremo le -\textit{sytem call} attinenti ad una serie di funzionalità specialistiche come +\textit{system call} attinenti ad una serie di funzionalità specialistiche come la gestione della virgola mobile, le porte di I/O ecc. \section{La gestione avanzata della sicurezza} @@ -1318,6 +1318,7 @@ funzione. + \subsection{La gestione del \textit{Secure Computing}.} \label{sec:procadv_seccomp} @@ -2301,4 +2302,4 @@ Da fare % LocalWords: libcap lcap obj to text dup clear DIFFERS get ncap caps ssize % LocalWords: argument length all setpcap from string name proc cat capgetp % LocalWords: capsetp getcap read sigreturn sysctl protected hardlinks tmp -% LocalWords: dell' symlink symlinks pathname TOCTTOU of +% LocalWords: dell' symlink symlinks pathname TOCTTOU of execve attack kcmp diff --git a/prochand.tex b/prochand.tex index 3da6faf..5afe0d2 100644 --- a/prochand.tex +++ b/prochand.tex @@ -3658,7 +3658,6 @@ rimosso a partire dal kernel 2.6.25. %TODO verificare http://lwn.net/Articles/355987/ - \section{Problematiche di programmazione \textit{multitasking}} \label{sec:proc_multi_prog} diff --git a/sources/Gapil.h b/sources/Gapil.h index 70c796d..c5a702f 100644 --- a/sources/Gapil.h +++ b/sources/Gapil.h @@ -112,6 +112,9 @@ size_t full_fwrite(FILE *file, void *buf, size_t count); */ /* Function dir_scan: simple scan for a directory. See dir_scan.c */ int dir_scan(char * dirname, int(*compute)(struct dirent *)); +/* Function InitFile: secure create of a file with initial content */ +ssize_t InitFile(int dirfd, const char *file, const char *buf, size_t count); +/* Function full_fread: to read from a standard file. See full_fread.c */ /* * Shared memory handling functions. See SharedMem.c */ diff --git a/sources/InitFile.c b/sources/InitFile.c new file mode 100644 index 0000000..307442a --- /dev/null +++ b/sources/InitFile.c @@ -0,0 +1,64 @@ +/* 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. + */ +/**************************************************************** + * + * Routine InitFile + * Routine to create file with initial content from a buffer + * + * Author: Simone Piccardi + * Jun. 2019 + * + ****************************************************************/ +#define _GNU_SOURCE +#include /* system limits constants, types and functions */ +#include +#include +#include /* Definition of AT_* constants */ +#include /* unix standard library */ +#include /* error definitions and routines */ +#include +#include /* needed for dirname e basename */ +#include "Gapil.h" +#include "macros.h" + +ssize_t InitFile(int dirfd, const char *file, const char *buf, size_t count) +{ + int fd, res; + char path[PATH_MAX]; + + fd = openat(dirfd, ".", O_TMPFILE|O_RDWR, S_IRUSR|S_IWUSR); + if (fd < 0) { + perror("Cannot get temporary filedescritor"); + return(fd); + } + res = FullWrite(fd, buf, count); + if (res < 0) { + perror("error writing on tmp file"); + return(res); + } + snprintf(path, PATH_MAX, "/proc/self/fd/%d", fd); + res = linkat(AT_FDCWD, path, dirfd, file, AT_SYMLINK_FOLLOW); + if (res < 0) { + perror("error writing on tmp file"); + return(res); + } else { + return 0; + } +} + diff --git a/sources/Makefile b/sources/Makefile index ea5155b..62226b5 100644 --- a/sources/Makefile +++ b/sources/Makefile @@ -9,6 +9,7 @@ CFLAGJ= -L./ -lgapil LIB = libgapil.so OBJ = FullRead.o FullWrite.o SigHand.o Mutex.o SharedMem.o LockFile.o \ + InitFile.o \ dir_scan.o endian.o SockUtil.o full_fread.o full_fwrite.o is_closing.o FINAL = forktest errcode techo uecho echod daytimed iterdaytimed daytime \ @@ -67,6 +68,9 @@ getparam: getparam.c testfopen: test_fopen.c $(CC) $^ -o $@ +test_initfile: test_initfile.c + $(CC) $^ -o $@ $(CFLAGJ) -lrt + testren: TestRen.c $(CC) $^ -o $@ diff --git a/sources/test_initfile.c b/sources/test_initfile.c new file mode 100644 index 0000000..12dc028 --- /dev/null +++ b/sources/test_initfile.c @@ -0,0 +1,118 @@ +/* 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 /* error definitions and routines */ +#include /* C standard library */ +#include /* unix standard library */ +#include /* standard I/O library */ +#include /* C strings library */ +#include +#include /* needed for dirname e basename */ +#include +#include +#include + +#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); +} + diff --git a/sources/test_linkat.c b/sources/test_linkat.c index 6931cd7..fbc06dc 100644 --- a/sources/test_linkat.c +++ b/sources/test_linkat.c @@ -19,7 +19,9 @@ /**************************************************************** * * 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 @@ -42,6 +44,7 @@ #include #include + /* Help printing routine */ void usage(void); @@ -95,13 +98,15 @@ int main(int argc, char *argv[]) } 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"); @@ -110,28 +115,32 @@ int main(int argc, char *argv[]) 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"); } @@ -143,8 +152,9 @@ int main(int argc, char *argv[]) */ 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"); -- 2.30.2