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

Stéphane Chazelas
źródło
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 opisotwórzopis 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.

minimum maksimum Średnia
źródło
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ąć?

Azhrei
źródło
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.

Hildred
źródło
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,