cari tahu deskriptor file mana yang memiliki “deskripsi file terbuka” yang sama

17

Jika saya melakukannya (dalam shell seperti Bourne):

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

File deskriptor 3 dan 4, karena 4 adalah dup()ed dari 3, berbagi deskripsi file terbuka yang sama (properti yang sama, offset yang sama dalam file ...). Sementara deskriptor file 5 dan 6 dari proses tersebut berada pada deskripsi file terbuka yang berbeda (misalnya, mereka masing-masing memiliki pointer sendiri dalam file).

Sekarang, dalam lsofoutput, yang kita lihat adalah:

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

Ini sedikit lebih baik dengan 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

(di sini di Linux 3.16) di mana kita melihat fd 6 memiliki flag yang berbeda, jadi itu harus menjadi deskripsi file terbuka yang berbeda dari yang ada di fd 3, 4 atau 5, tetapi dari situ kita tidak bisa mengatakan fd 5 ada di deskripsi file terbuka berbeda . Dengan -o, kita juga bisa melihat offset, tetapi offset yang sama tidak menjamin itu adalah deskripsi file terbuka yang sama .

Apakah ada non-intrusif 1 cara untuk mengetahui bahwa? Secara eksternal, atau untuk deskriptor file proses sendiri?


1 . Salah satu pendekatan heuristik bisa dengan mengubah bendera satu fd dengan fcntl()dan melihat apa file deskriptor lain memiliki bendera mereka diperbarui sebagai hasilnya, tapi itu jelas tidak ideal atau bukti bodoh

Stéphane Chazelas
sumber
Pendekatan ini harus bekerja, pada prinsipnya, dan tidak terlalu mengganggu dalam sebagian besar skenario: pertama bercabang anak (dengan ptrace jika melakukannya dari luar). Kemudian, pada anak, lakukan sesuatu dengan deskriptor file yang tidak memengaruhi proses lainnya. Di Linux, sewa harus berfungsi untuk itu.
Gilles 'SANGAT berhenti menjadi jahat'
@Gilles, terima kasih tapi kurang lebih pendekatan yang saya sarankan dalam pertanyaan sudah. sewa (anggap Anda maksudnya F_SETLEASE fcntl, terima kasih telah membuat saya menyadarinya BTW) hanya akan berfungsi untuk file biasa yang Anda miliki dan tidak jika ada deskripsi file "tulis" terbuka lainnya untuk file yang sama (EBUSY), dan itu bukan sepenuhnya non - Mengganggu.
Stéphane Chazelas
Sudahkah Anda mengabaikan pertanyaan ini? Saya memposting beberapa info tentang bagaimana SystemTap dapat melakukan apa yang Anda inginkan, tetapi Anda belum menandai jawaban yang lengkap ...?
Azhrei

Jawaban:

2

Untuk Linux 3.5 dan selanjutnya, ini dapat dilakukan dengan kcmp (3) :

KCMP_FILE

  • Periksa apakah file deskriptor idx1 dalam proses pid1 mengacu pada deskripsi file terbuka yang sama (lihat terbuka (2) ) sebagai deskriptor file idx2 dalam proses pid2 . Adanya dua deskriptor file yang merujuk pada deskripsi file terbuka yang sama dapat terjadi sebagai hasil dari dup (2) (dan sejenisnya) garpu (2) , atau mengirimkan deskriptor file melalui soket domain (lihat unix (7) ).

Halaman manual memberikan contoh khusus untuk use case yang diminta OP. Perhatikan bahwa syscall ini mengharuskan kernel dikompilasi dengan CONFIG_CHECKPOINT_RESTOREset.

minmaxavg
sumber
Terima kasih. Persis seperti yang saya cari. Perhatikan bahwa kecuali Anda superuser, itu haruslah dua proses Anda (dan tidak menjadi setuid / setgid ...) (dapat dimengerti)
Stéphane Chazelas
@ StéphaneChazelas Tepat. Jika karena alasan tertentu dukungan CPIU tidak dibangun di kernel Anda dan Anda tidak ingin membangunnya kembali, maka saya kira Anda selalu dapat menulis modul kernel yang mengekspor beberapa antarmuka userland yang memungkinkan Anda membandingkan struct file *pointer.
minmaxavg
3

Yang ingin Anda bandingkan adalah struct filepointer yang ditunjuk oleh deskriptor file. (Di dalam kernel adalah salah satu task_structstruktur data untuk setiap thread. Ini berisi pointer ke struktur lain yang disebut files_struct. Dan yang struktur berisi sebuah array dari pointer, masing-masing untuk struct file. Ini struct fileyang memegang mencari offset, bendera terbuka, dan beberapa bidang lainnya.)

Saya tidak tahu cara yang terlihat oleh pengguna untuk melihat petunjuk di files_structlain selain penggunaan beberapa alat yang mengganggu. Sebagai contoh, SystemTap dapat diberi PID dan itu bisa menemukan yang sesuai task_structdan mengikuti petunjuknya. Jika Anda mencari pasif, saya kira itu saja. Dell merilis alat sejak lama yang disebut KME (Kernel Memory Editor) yang memberikan antarmuka seperti spreadsheet untuk menghidupkan memori kernel dan bisa melakukan apa yang Anda inginkan, tetapi tidak pernah porting ke 64-bit. (Saya mencoba dan tidak pernah berhasil sepenuhnya, dan tidak yakin mengapa.)

Salah satu alasan Anda merasa tidak lsofmembantu adalah karena ia tidak melihat petunjuk itu juga (tetapi lihat +fopsi untuk sistem non-Linux). Secara teoritis Anda dapat membandingkan semua bidang dalam struct filedan berpikir kedua struktur itu sama, namun keduanya masih dapat berasal dari open(2)panggilan terpisah .

Lihatlah skrip SystemTap pfiles untuk ide-ide. Jika Anda memodifikasinya untuk mencetak alamat struct file, Anda akan mendapatkan solusinya. Anda mungkin juga memeriksa opens_file_by_pid.stp karena ada fungsi di dalamnya yang berjalan files_structyaitu,. tabel deskriptor file, melihat struct fileobjek ...

Bisakah saya bertanya apa yang ingin Anda capai?

Azhrei
sumber
Saya harus mengakui bahwa saya tidak dapat mengingat kasus di mana saya membutuhkannya. Beberapa tugas debugging atau forensik tidak diragukan lagi.
Stéphane Chazelas
Saya menantikan kode systemtap PoC :-)
Stéphane Chazelas
Sebelum saya memposting pertanyaan, saya memang sudah melihat pendekatan systemtap atau / proc / kcore. Bagian yang sulit adalah mendapatkan info untuk setiap fd dari setiap tugas . Pendekatan yang paling menjanjikan yang saya temukan adalah menghubungkan ke fungsi-fungsi yang menghasilkan konten dari direktori / proc / * / task / fd, tetapi satu-satunya hal yang bisa saya lakukan dengan melibatkan pengait pada nomor baris tertentu dalam file sumber sehingga tidak portable dari satu versi kernel ke yang berikutnya. Anda tidak dapat benar-benar menelusuri daftar tugas di systemtap. Mungkin dimungkinkan melalui / proc / kcore, tetapi terlalu banyak usaha dan mungkin tidak dapat diandalkan.
Stéphane Chazelas
Terima kasih atas tanggapan terbaik sejauh ini. Saya akan melihat petunjuk Anda.
Stéphane Chazelas
Tentu kamu bisa! Siapkan probe beginblok dan gunakan for_each_processmakro dalam blok kode C yang tertanam dalam skrip (Anda harus menggunakan mode "guru" SystemTap untuk menanamkan kode C). Bahkan, untuk membuat ini menarik (!), Anda bisa menggunakan salah satu array asosiatif SystemTap; gunakan files_structalamat sebagai kunci, dan daftar PID / TIDs sebagai nilai. Anda sekarang memiliki daftar setiap file yang dibuka dan tugas mana yang dibagikan (mereka dapat dibagi antara orang tua / anak). Balas lagi jika Anda ingin mendiskusikan SystemTap.
Azhrei
0

Berikut ini adalah solusi spesifik linux: / proc / self / fd adalah direktori tautan simbolik untuk pegangan file terbuka dalam proses saat ini. Anda bisa membandingkan nilai tautan. Semakin rumit ketika menggunakan proses anak, karena anak akan memiliki yang berbeda / proc / self karena itu adalah link simbolik ketergantungan pid. Anda dapat mengatasi masalah ini dengan menggunakan / proc / $$ / fd di mana $$ adalah pid yang diinginkan.

Hildred
sumber
Terima kasih. Tapi bukan itu yang saya tanyakan. Di Linux, lsof memang menggunakan / proc / pid / fd untuk mengambil path untuk setiap deskriptor file dan / proc / pid / fdinfo untuk flag. Tetapi yang saya inginkan adalah bahwa untuk dua fds ke file yang sama apakah mereka menunjuk ke deskripsi file terbuka yang sama atau jika dua deskriptor file telah dibuka secara independen.
Stéphane Chazelas
ok, setelah Anda menemukan pasangan deskriptor file yang terbuka untuk nama file yang sama, lakukan kirim keduanya dan bandingkan hasilnya, jika mereka berbeda mereka terpisah. Jika mereka mencari yang sama pada satu file deskriptor dan ulangi, Jika mereka masih cocok mereka sama.
Hildred
Nah, itu varian yang lebih mengganggu dari pendekatan heuristik yang saya rujuk dalam pertanyaan dan itu hanya berfungsi untuk file biasa (bukan soket, perangkat (seperti terminal), pipa ...).
Stéphane Chazelas