Jaki proces utworzył to okno X11?

75

Biorąc pod uwagę identyfikator okna X11, czy istnieje sposób na znalezienie identyfikatora procesu, który go utworzył?

Oczywiście nie zawsze jest to możliwe, na przykład, jeśli okno przeszło połączenie TCP. W takim przypadku chciałbym, aby adres IP i port były powiązane ze zdalnym końcem.

Pytanie zostało zadane wcześniej na przepełnieniu stosu , a proponowaną metodą było użycie tej _NET_WM_PIDwłaściwości. Ale to ustawia aplikacja. Czy można to zrobić, jeśli aplikacja nie działa dobrze?

Gilles
źródło

Odpowiedzi:

60

Chyba, że X-serwer obsługuje XResQueryClientIdsod X-Zasobami przedłużenie v1.2 nie znam łatwy sposób, aby niezawodnie żądania identyfikator procesu. Istnieją jednak inne sposoby.

Jeśli masz przed sobą okno i nie znasz jeszcze jego identyfikatora - łatwo je znaleźć. Po prostu otwórz terminal obok danego okna, uruchom xwininfotam i kliknij to okno. xwininfopokaże ci identyfikator okna.

Załóżmy więc, że znasz identyfikator okna, np. 0x1600045, i chcesz dowiedzieć się, jaki proces jest jego właścicielem.

Najłatwiejszym sposobem sprawdzenia, do kogo należy to okno, jest uruchomienie XKillClient dla niego, tj .:

xkill -id 0x1600045

i zobacz, który proces właśnie umarł. Ale tylko jeśli oczywiście nie masz nic przeciwko zabiciu go!

Innym łatwym, ale zawodnym sposobem jest sprawdzenie jego _NET_WM_PIDi WM_CLIENT_MACHINEwłaściwości:

xprop -id 0x1600045

Właśnie takie narzędzia lubią xlsclientsi xrestoprobią.

Niestety te informacje mogą być niepoprawne nie tylko dlatego, że proces był zły i zmienił je, ale także dlatego, że był błędny. Na przykład po awarii / ponownym uruchomieniu Firefoksa widziałem osierocone okna (jak sądzę z wtyczki flash) ze _NET_WM_PIDwskazaniem na proces, który zmarł dawno temu.

Alternatywnym sposobem jest uruchomienie

xwininfo -root -tree

i sprawdź właściwości rodziców danego okna. To może dać ci kilka wskazówek na temat pochodzenia okna.

Ale! Chociaż możesz nie znaleźć procesu, który utworzył to okno, wciąż istnieje sposób, aby dowiedzieć się, skąd ten proces połączył się z serwerem X. I tak jest dla prawdziwych hakerów. :)

Identyfikator okna 0x1600045, który znasz z zerowanymi niższymi bitami (tj. 0x1600000), jest „bazą klienta”. Wszystkie identyfikatory zasobów przydzielone temu klientowi są „oparte” na nim (0x1600001, 0x1600002, 0x1600003 itp.). Serwer X przechowuje informacje o swoich klientach w tablicy klientów [], a dla każdego klienta jego „baza” jest przechowywana w klientach [i] -> zmienna clientAsMask. Aby znaleźć gniazdo X odpowiadające temu klientowi, musisz podłączyć się do serwera X za pomocą gdb, przejść przez tablicę klientów [], znaleźć klienta z tym clientAsMaski wydrukować jego deskryptor gniazda, zapisany w ((OsCommPtr) (klienci [i] - > osPrivate)) -> fd.

Może być podłączonych wiele klientów X, więc aby nie sprawdzać ich wszystkich ręcznie, użyjmy funkcji gdb:

define findclient
  set $ii = 0
  while ($ii < currentMaxClients)
    if (clients[$ii] != 0 && clients[$ii]->clientAsMask == $arg0 && clients[$ii]->osPrivate != 0)
      print ((OsCommPtr)(clients[$ii]->osPrivate))->fd
    end
    set $ii = $ii + 1
  end
end

Po znalezieniu gniazda możesz sprawdzić, kto jest z nim połączony, a na końcu znaleźć proces.

OSTRZEŻENIE : NIE podłączaj gdb do X-serwera od WEWNĄTRZ X-serwera. gdb zawiesza proces, do którego się dołącza, więc jeśli podłączysz się do niego z poziomu sesji X, zamrozisz swój serwer X i nie będziesz mógł wchodzić w interakcje z gdb. Musisz albo przełączyć się na terminal tekstowy ( Ctrl+Alt+F2), albo połączyć się z komputerem przez ssh.

Przykład:

  1. Znajdź PID swojego X-serwera:

    $ ps ax | grep X
     1237 tty1     Ssl+  11:36 /usr/bin/X :0 vt1 -nr -nolisten tcp -auth /var/run/kdm/A:0-h6syCa
    
  2. Identyfikator okna to 0x1600045, więc podstawa klienta to 0x1600000. Podłącz do serwera X i znajdź deskryptor gniazda klienta dla tej bazy klientów. Musisz zainstalować informacje debugowania dla X-serwera (pakiet -debuginfo dla dystrybucji rpm-lub pakiet -dbg dla deba).

    $ sudo gdb
    (gdb) define findclient
    Type commands for definition of "findclient".
    End with a line saying just "end".
    >  set $ii = 0
    >  while ($ii < currentMaxClients)
     >   if (clients[$ii] != 0 && clients[$ii]->clientAsMask == $arg0 && clients[$ii]->osPrivate != 0)
      >     print ((OsCommPtr)(clients[$ii]->osPrivate))->fd
      >     end
     >   set $ii = $ii + 1
     >   end
    >  end
    (gdb) attach 1237
    (gdb) findclient 0x1600000
    $1 = 31
    (gdb) detach
    (gdb) quit
    
  3. Teraz wiesz, że klient jest podłączony do gniazda 31 serwera. Użyj, lsofaby znaleźć to, co to gniazdo:

    $ sudo lsof -n | grep 1237 | grep 31
    X        1237    root   31u   unix 0xffff810008339340       8512422 socket
    

    (tutaj „X” to nazwa procesu, „1237” to jego pid, „root” to użytkownik, z którego działa, „31u” to deskryptor gniazda)

    Tam możesz zobaczyć, że klient jest połączony przez TCP, następnie możesz przejść do komputera, z którego jest podłączony i sprawdzić netstat -naptam, aby znaleźć proces. Ale najprawdopodobniej zobaczysz tam gniazdo unix, jak pokazano powyżej, co oznacza, że ​​jest to klient lokalny.

  4. Aby znaleźć parę dla tego gniazda uniksowego, możesz użyć techniki MvG (będziesz również potrzebować informacji o debugowaniu dla zainstalowanego jądra):

    $ sudo gdb -c /proc/kcore
    (gdb) print ((struct unix_sock*)0xffff810008339340)->peer
    $1 = (struct sock *) 0xffff810008339600
    (gdb) quit
    
  5. Teraz, gdy znasz już gniazdo klienta, użyj lsofPID , aby je zatrzymać:

    $ sudo lsof -n | grep 0xffff810008339600
    firefox  7725  username  146u   unix 0xffff810008339600       8512421 socket
    

Otóż ​​to. Proces utrzymywania tego okna to „firefox” o identyfikatorze procesu 7725


Edycja 2017 : Teraz jest więcej opcji, jak widać na Kto ma drugi koniec tej pary gniazd unixowych? . W Linuksie 3.3 lub nowszym oraz w wersji lsof4.89 lub nowszej możesz zastąpić punkty 3 do 5 powyżej:

lsof +E -a -p 1237 -d 31

aby dowiedzieć się, kto jest na drugim końcu gniazda na fd 31 procesu X-server o identyfikatorze 1237.

Gość
źródło
6
Witamy na Giełdzie Stosów Unix i Linux! Twoja odpowiedź na to pytanie jest doskonała. Mam nadzieję, że wrócisz, by odpowiedzieć na więcej pytań.
36

xdotool nie działał dla mnie. To spowodowało:

Biegać

xprop _NET_WM_PID

i kliknij okno.

Jest to oparte na odpowiedzi na stronie http://www.linuxquestions.org/questions/linux-software-2/advanced-question-finding-pid-of-an-x-window-328983/

Noam
źródło
Działa dla mnie, gdy podłączenie mojego iPhone'a wywołało brak odpowiedzi na monit okna.
modulitos
1
Przydatny do ewakuacji, która czasami wisiała całkowicie. kill $(xprop _NET_WM_PID|cut -d " " -f 3)
Gabriel Devillers,
Właśnie tego szukałem, przepływ xkill
Rombus
13

Jeśli masz zainstalowany xdotool , to

xdotool selectwindow getwindowpid

następnie kliknięcie danego okna spowoduje zwrócenie PID.

(Istnieją inne sposoby wyboru danego okna, np. Jeśli masz jego identyfikator, możesz to zrobić xdotool getwindowpid <number>. Możesz także wybrać według nazwy lub klasy itp.)

Myślę, że wymaga to trochę dobrej gry w imieniu WM. Nie eksperymentowałem dużo ani nie musiałem.

frabjous
źródło
2
xdo_getwinprop(xdo, window, atom_NET_WM_PID, &nitems, &type, &size)⇒ to tylko opakowanie powłoki do przeczytania _NET_WM_PID(przydatne, ale nie to, o co prosiłem).
Gilles,
11

Nie _NET_WM_PIDjest ustawione przez menedżera okien (jako kolejny klient X11, skąd miałby wiedzieć?).

Zamiast tego oczekuje się, że klienty (aplikacje) X11 zgodne ze standardem _NET_WM_PIDi WM_CLIENT_MACHINEwe własnych oknach. Zakładając, że dobrze się zachowuje aplikacja, będzie to prawdą niezależnie od tego, czy menedżer okien jest uruchomiony, czy nie.

Jeśli WM_CLIENT_MACHINEjest to twoja nazwa hosta, PID powinien mieć znaczenie.
W przeciwnym razie „Chciałbym, aby adres IP i port były powiązane ze zdalnym końcem” - nie jestem pewien, co to oznacza. Na przykład, jeśli masz otwartą sesję ssh z włączonym przekazywaniem X, okna otwierane przez przekazywane aplikacje będą oznaczone zdalnym PID i nazwą hosta, ale niekoniecznie masz jakiś sposób, aby połączyć się z tym zdalnym hostem.

efemeryczny
źródło
2
_NET_WM_PIDjest ustawiony przez aplikację: tak, to ma większy sens! Ale to nie jest protokół X11, to stosunkowo nowa specyfikacja FreeDesktop .
Gilles
W przypadku ssh, jeśli chodzi o serwer X, jest to połączenie lokalne z procesu sshd. Chociaż _NET_WM_PIDwydaje się być ustawiony na zdalny PID i WM_CLIENT_MACHINEzdalne połączenie (testowane z xterm).
Gilles
4

Byłem w stanie korzystać z xdotoolwersji Ubuntu 11.04 beta, ale selectwindownie byłem prawidłowym poleceniem, musiałem zhakować skrypt za pomocą:

$ while true; do sleep 1; xdotool getactivewindow; done

następnie obserwuj id okna, gdy wybrałem okno, które chciałem, a następnie dekodowałem odpowiedzialny PID za pomocą:

$ xdotool getwindowpid <the-window-id>
Jon Bailey
źródło