dowiedz się, które deskryptory plików mają ten sam „opis otwartego pliku”


17

Jeśli to zrobię (w powłoce Bourne'a):

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

Deskryptory plików 3 i 4, ponieważ 4 był dup()edytowany z 3, dzielą ten sam otwarty opis pliku (te same właściwości, to samo przesunięcie w pliku ...). Chociaż deskryptory plików 5 i 6 tego procesu znajdują się w innym otwartym opisie pliku (na przykład każdy z nich ma własny wskaźnik w pliku).

Teraz w lsofwyniku widzimy tylko:

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

Jest trochę lepiej z 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

(tutaj w Linuksie 3.16), ponieważ widzimy, że fd 6 ma inne flagi, więc musi to być inny opis otwartego pliku niż ten na fd 3, 4 lub 5, ale z tego nie wiemy, że fd 5 jest na inny opis otwartego pliku . Za pomocą -omożemy również zobaczyć przesunięcie, ale ponownie to samo przesunięcie nie gwarantuje, że jest to ten sam opis otwartego pliku .

Czy jest jakiś nieinwazyjny 1 sposób, aby się tego dowiedzieć? Zewnętrznie, czy dla własnych deskryptorów plików procesu?


1 . Jednym heurystycznym podejściem może być zmiana flag jednego fd za pomocą fcntl()i sprawdzenie, w jaki sposób inne deskryptory plików mają zaktualizowane flagi, ale to oczywiście nie jest idealny ani głupi dowód


Takie podejście powinno w zasadzie działać i nie powinno być zbyt zakłócające w większości scenariuszy: najpierw rozwidl dziecko (z ptrace, jeśli robi to z zewnątrz). Następnie w dziecku zrób coś z deskryptorem pliku, co nie wpływa na inne procesy. W systemie Linux dzierżawy powinny na to działać.
— Gilles „SO- przestań być zły”

@Gilles, dziękuję, ale to podejście mniej więcej sugeruję już w pytaniu. dzierżawy (zakładając, że masz na myśli F_SETLEASE fcntl, dzięki za poinformowanie mnie o nich BTW) będą działać tylko dla zwykłych plików, które posiadasz, a nie, jeśli będzie inny opis „ otwórz ” opis pliku do tego samego pliku (EBUSY), i to nie jest -natrętny.
— Stéphane Chazelas

Czy porzuciłeś to pytanie? Wysłałem kilka informacji dotyczących tego, jak SystemTap może robić, co chcesz, ale nie zaznaczyłeś żadnej odpowiedzi jako kompletnej ...?
— Azhrei

Odpowiedzi:


2

W Linuksie 3.5 i nowszych można to zrobić za pomocą kcmp (3) :

KCMP_FILE

  • Sprawdź, czy deskryptor pliku idx1 w procesie pid1 odnosi się do tego samego opisu otwartego pliku (patrz open (2) ) jak deskryptor pliku idx2 w procesie pid2 . Istnienie dwóch deskryptorów plików odnoszących się do tego samego opisu otwartego pliku może wystąpić w wyniku dup (2) (i podobnego) fork (2) lub przekazania deskryptorów plików przez gniazdo domeny (patrz unix (7) ).

Strona man zawiera przykład konkretnie dla przypadku użycia OP, o który pytano. Zauważ, że to wywołanie systemowe wymaga kompilacji jądra z CONFIG_CHECKPOINT_RESTOREsetem.


Dzięki. Dokładnie tego szukałem. Pamiętaj, że chyba że jesteś superużytkownikiem, muszą to być twoje dwa procesy (a nie setuid / setgid ...) (co zrozumiałe)
— Stéphane Chazelas

@ StéphaneChazelas Dokładnie. Jeśli z jakiegoś powodu wsparcie CPIU nie zostało wbudowane w twoje jądro i nie chcesz go odbudować, to przypuszczam, że zawsze możesz napisać moduł jądra, który eksportuje interfejs użytkownika, który pozwala porównywać struct file *wskaźniki.
— minmaxavg

3

To, co chcesz porównać, to struct filewskaźniki, na które wskazują deskryptory plików. (Wewnątrz jądra znajduje się jedna task_structstruktura danych dla każdego wątku. Zawiera on wskaźnik do innej struktury o nazwie files_struct. I ta struktura zawiera tablicę wskaźników, każdy do a struct file. To on struct filezawiera przesunięcie wyszukiwania, otwarte flagi i kilka innych pól.)

Nie znam żadnego widocznego dla użytkownika sposobu, aby zobaczyć wskaźniki w files_structinny sposób niż użycie niektórych natrętnych narzędzi. Na przykład SystemTap może otrzymać PID i może znaleźć odpowiedni task_structi postępować zgodnie ze wskazówkami. Jeśli jednak szukasz umiejętności pasywnej, myślę, że o to chodzi. Firma Dell wydała dawno narzędzie o nazwie KME (Kernel Memory Editor), które udostępnia interfejs podobny do arkusza kalkulacyjnego do żywej pamięci jądra i może robić to, co chcesz, ale nigdy nie zostało przeniesione do wersji 64-bitowej. (Próbowałem i nigdy nie działałem całkowicie, i nie byłem pewien, dlaczego).

Jednym z powodów, dla których nie jesteś lsofpomocny, jest to, że nie widzi tych wskaźników (ale spójrz na +fopcję dla systemów innych niż Linux). Można teoretycznie porównać wszystkie pola w struct filei pomyśleć, że obie struktury są takie same, ale wciąż mogą pochodzić z osobnych open(2)wywołań.

Spójrz na pomysły pfiles SystemTap. Jeśli zmodyfikujesz go, aby wydrukować adres struct file, będziesz mieć swoje rozwiązanie. Możesz także sprawdzić plik open_file_by_pid.stp, ponieważ jest w nim funkcja, która chodzi files_struct, tj. tablica deskryptorów plików, patrząc na struct fileobiekty ...

Czy mogę zapytać, co próbujesz osiągnąć?


Muszę przyznać, że nie pamiętam przypadku, w którym tego potrzebowałem. Niektóre zadania debugowania lub kryminalistyczne bez wątpienia.
— Stéphane Chazelas

Z niecierpliwością czekam na kod
— systemowy

Zanim opublikowałem pytanie, przyjrzałem się podejściom systemtap lub / proc / kcore. Trudność polegała na uzyskaniu informacji o każdym fd każdego zadania . Najbardziej obiecującym podejściem, jakie znalazłem, było podłączenie się do funkcji generujących zawartość katalogu / proc / * / task / fd, ale jedyne możliwe do wykonania rzeczy, które mogłem wymyślić, obejmowały zaczepienie do określonych numerów linii w pliku źródłowym, więc nie przenośny z jednej wersji jądra do następnej. Nie można tak naprawdę przeglądać listy zadań w systemtap. Być może jest to możliwe przez / proc / kcore, ale za dużo wysiłku i prawdopodobnie niewiarygodne.
— Stéphane Chazelas

Dzięki za najlepszą dotychczasową odpowiedź. Rzucę okiem na twoje wskazówki.
— Stéphane Chazelas

Oczywiście że możesz! Skonfiguruj probe beginblok i for_each_processniech użyje makra w bloku kodu C osadzonego w skrypcie (musisz użyć SystemTap w trybie „guru”, aby osadzić kod C). W rzeczywistości, aby uczynić to interesującym (!), Możesz użyć jednej z tablic asocjacyjnych SystemTap; użyj files_structadresu jako klucza oraz listy PID / TID jako wartości. Masz teraz listę każdego otwartego pliku i zadania, które je współużytkują (mogą być udostępniane między rodzicem / dzieckiem). Odpowiedz ponownie, jeśli chcesz omówić SystemTap.
— Azhrei

0

Oto rozwiązanie specyficzne dla systemu Linux: / proc / self / fd to katalog dowiązań symbolicznych dla otwartych uchwytów plików w bieżącym procesie. Możesz po prostu porównać wartości linków. Staje się bardziej skomplikowane, gdy używa się procesu potomnego, ponieważ dziecko będzie miało inne / proc / self, ponieważ jest to zależne od pid symboliczne łącze. Możesz obejść ten problem, używając / proc / $$ / fd, gdzie $$ jest pożądanym pid.


Dzięki. Ale nie o to pytam. W Linuksie lsof rzeczywiście używa / proc / pid / fd do pobierania ścieżek dla każdego deskryptora pliku i / proc / pid / fdinfo dla flag. Ale chcę, aby dla dwóch fds do tego samego pliku wskazywały ten sam opis otwartego pliku lub czy dwa deskryptory plików były otwarte niezależnie.
— Stéphane Chazelas,

ok, po znalezieniu par deskryptorów plików, które są otwarte na tę samą nazwę pliku, powiedz na obu i porównaj wyniki, jeśli się różnią, są oddzielne. Jeśli są takie same, wyszukaj na jednym deskryptorze pliku i powtórz: Jeśli nadal są takie same, są takie same.
— Hildred,

Cóż, to jest bardziej inwazyjny wariant heurystycznego podejścia, o którym mówię w pytaniu i który działa tylko dla zwykłych plików (nie gniazd, urządzeń (takich jak terminale), rur ...).
— Stéphane Chazelas,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.