scopri quali descrittori di file condividono la stessa "descrizione file aperta"


17

Se lo faccio (in una shell tipo Bourne):

exec 3> file 4>&3 5> file 6>> file

I descrittori di file 3 e 4, poiché 4 è stato modificato dup()da 3, condividono la stessa descrizione del file aperto (stesse proprietà, stesso offset all'interno del file ...). Mentre i descrittori di file 5 e 6 di quel processo si trovano su una diversa descrizione del file aperto (ad esempio, ognuno ha il proprio puntatore nel file).

Ora, in lsofuscita, tutto ciò che vediamo è:

zsh     21519 stephane    3w   REG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    4w   REG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    5w   REG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    6w   REG  254,2        0 10505865 /home/stephane/file

È un po 'meglio con lsof +fg:

zsh     21519 stephane    3w   REG          W,LG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    4w   REG          W,LG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    5w   REG          W,LG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    6w   REG       W,AP,LG  254,2        0 10505865 /home/stephane/file

(qui su Linux 3.16) in quanto vediamo fd 6 ha flag diversi, quindi deve essere una descrizione del file aperto diversa da quella su fd 3, 4 o 5, ma da ciò non possiamo dire che fd 5 è su un diversa descrizione del file aperto . Con -o, potremmo anche vedere l'offset, ma di nuovo lo stesso offset non garantisce che sia la stessa descrizione del file aperto .

C'è un non-intrusivo 1 modo per scoprirlo? Esternamente o per i descrittori di file propri di un processo?


1 . Un approccio euristico potrebbe essere quello di cambiare i flag di un fd fcntl()e vedere quali altri descrittori di file hanno i loro flag aggiornati di conseguenza, ma questo ovviamente non è l'ideale né infallibile


Questo approccio dovrebbe funzionare, in linea di principio, e non essere troppo distruttivo nella maggior parte degli scenari: in primo luogo biforcare un bambino (con ptrace se lo si fa dall'esterno). Quindi, nel bambino, fai qualcosa con il descrittore di file che non influisce su altri processi. Su Linux, i contratti di locazione dovrebbero funzionare per questo.
Gilles 'SO-smetti di essere malvagio' il

@Gilles, grazie ma questo è più o meno l'approccio che suggerisco già nella domanda. contratti di locazione (supponendo che intendi il Fcntl F_SETLEASE, grazie per avermi informato di loro BTW) funzionerà solo per i file normali di tua proprietà e non se c'è un'altra "scrittura" che descriva il file aperto nello stesso file (EBUSY), e non è esattamente non -invadente.
Stéphane Chazelas,

Hai abbandonato questa domanda? Ho pubblicato alcune informazioni su come SystemTap potrebbe fare quello che vuoi, ma non hai contrassegnato nessuna risposta come completa ...?
Azhrei,

Risposte:


2

Per Linux 3.5 e versioni successive, questo può essere realizzato con kcmp (3) :

KCMP_FILE

  • Controlla se un descrittore di file idx1 nel processo pid1 fa riferimento alla stessa descrizione del file aperto (vedi open (2) ) del descrittore di file idx2 nel processo pid2 . L'esistenza di due descrittori di file che fanno riferimento alla stessa descrizione di file aperto può verificarsi a seguito di dup (2) (e simili) fork (2) o del passaggio di descrittori di file tramite un socket di dominio (vedere unix (7) ).

La pagina man fornisce un esempio specifico per il caso d'uso OP richiesto. Nota che questo syscall richiede che il kernel sia compilato con CONFIG_CHECKPOINT_RESTOREset.


Grazie. Esattamente quello che stavo cercando. Nota che a meno che tu non sia un superutente, devono essere due tuoi processi (e non essere setuid / setgid ...) (comprensibilmente)
Stéphane Chazelas,

@ StéphaneChazelas Esattamente. Se per qualche ragione il supporto CPIU non è stato creato nel tuo kernel e non vuoi ricostruirlo, allora suppongo che tu possa sempre scrivere un modulo del kernel che esporta alcune interfacce utente che ti permettono di confrontare i struct file *puntatori.
minmaxavg,

3

Quello che stai cercando di confrontare sono i struct filepuntatori a cui fanno riferimento i descrittori di file. (All'interno del kernel c'è una task_structstruttura di dati per ogni thread. Contiene un puntatore a un'altra struttura chiamata il files_struct. E quella struttura contiene un array di puntatori, ognuno a un struct file. È quello struct fileche contiene l'offset di ricerca, i flag aperti e un pochi altri campi.)

Non conosco alcun modo visibile all'utente per vedere i puntatori files_structnell'uso diverso da alcuni strumenti invadenti. Ad esempio, SystemTap potrebbe ricevere un PID e potrebbe trovare il corrispondente task_structe seguire i puntatori. Se stai cercando passivo, però, penso che sia a questo proposito. Dell ha rilasciato molto tempo fa uno strumento chiamato KME (Kernel Memory Editor) che forniva un'interfaccia simile a un foglio di calcolo per vivere la memoria del kernel e poteva fare quello che volevi, ma non è mai stato portato su 64-bit. (Ho provato e non l'ho mai fatto funzionare completamente, e non ero sicuro del perché.)

Uno dei motivi per cui non stai trovando lsofutile è che non vede neanche quei puntatori (ma guarda l' +fopzione per i sistemi non Linux). Potresti teoricamente confrontare tutti i campi in struct filee pensare che le due strutture siano uguali, ma potrebbero comunque provenire da open(2)chiamate separate .

Dai un'occhiata allo script SystemTap di pfiles per idee. Se lo modificassi per stampare l'indirizzo del struct file, avresti la tua soluzione. Potresti anche controllare open_file_by_pid.stp poiché c'è una funzione in essa che percorre files_struct, ad esempio. la tabella dei descrittori di file, guardando gli struct fileoggetti ...

Potrei chiederti cosa stai cercando di realizzare?


Devo ammettere che non ricordo il caso in cui ne avevo bisogno. Qualche attività di debug o forense senza dubbio.
Stéphane Chazelas,

Non vedo l'ora che arrivi il codice systemtap PoC :-)
Stéphane Chazelas,

Prima di pubblicare la domanda, ho dato un'occhiata agli approcci di systemtap o / proc / kcore. La parte difficile era ottenere le informazioni per ogni fd di ogni attività . L'approccio più promettente che ho trovato è stato quello di collegarmi alle funzioni che generano il contenuto della directory / proc / * / task / fd, ma le uniche cose praticabili che potevo trovare riguardavano l'aggancio a specifici numeri di riga nel file sorgente, quindi non portabile da una versione del kernel alla successiva. Non puoi davvero scorrere l'elenco delle attività in systemtap. Forse possibile tramite / proc / kcore, ma troppo sforzo e probabilmente inaffidabile.
Stéphane Chazelas,

Grazie per la migliore risposta finora. Dò un'occhiata ai tuoi puntatori.
Stéphane Chazelas,

Certo che puoi! Imposta un probe beginblocco e for_each_processfallo usare alla macro in un blocco di codice C incorporato nello script (dovrai usare la modalità "guru" SystemTap per incorporare il codice C). In effetti, per rendere questo interessante (!), È possibile utilizzare uno degli array associativi di SystemTap; usa l' files_structindirizzo come chiave e un elenco di PID / TID come valori. Ora hai un elenco di tutti i file aperti e quali attività li condividono (possono essere condivisi tra genitore / figlio). Rispondi di nuovo se vuoi discutere di SystemTap.
Azhrei,

0

Ecco una soluzione specifica per Linux: / proc / self / fd è una directory di collegamenti simbolici per handle di file aperti nel processo corrente. Puoi semplicemente confrontare i valori dei link. Diventa più complicato quando si usa un processo figlio, perché il bambino avrà un / proc / sé diverso perché è un collegamento simbolico dipendente dal pid. Puoi risolvere questo problema usando / proc / $$ / fd dove $$ è il pid desiderato.


Grazie. Ma non è quello che sto chiedendo. Su Linux, lsof usa effettivamente / proc / pid / fd per recuperare i percorsi per ciascun descrittore di file e / proc / pid / fdinfo per i flag. Ma quello che voglio è che per due fds sullo stesso file sia che indichino la stessa descrizione del file aperto o che i due descrittori di file siano stati aperti in modo indipendente.
Stéphane Chazelas,

ok, dopo aver trovato coppie di descrittori di file che sono aperti con lo stesso nome di file, fai una spiegazione su entrambi e confronta i risultati, se differiscono sono separati. Se sono la stessa ricerca su un descrittore di file e ripeti, se corrispondono ancora sono uguali.
Hildred

Bene, questa è una variante più invadente dell'approccio euristico a cui mi riferisco nella domanda e che funziona solo per file regolari (non socket, dispositivi (come terminali), pipe ...).
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.