У кого есть другой конец этой пары сокетов Unix?

54

Я хочу определить, какой процесс имеет другой конец сокета UNIX.

В частности, я спрашиваю о том, что было создано с socketpair(), хотя проблема та же для любого сокета UNIX.

У меня есть программа, parentкоторая создает socketpair(AF_UNIX, SOCK_STREAM, 0, fds), и fork()с. Родительский процесс закрывается fds[1]и продолжает fds[0]общаться. Ребенок делает наоборот close(fds[0]); s=fds[1]. Тогда у ребенка exec()другая программа child1. Эти двое могут общаться друг с другом через эту сокет-пару.

Теперь, скажем, я знаю, кто parentесть, но я хочу выяснить, кто child1есть. Как мне это сделать?

В моем распоряжении есть несколько инструментов, но ни один не может сказать мне, какой процесс находится на другом конце сокета. Я пытался:

  • lsof -c progname
  • lsof -c parent -c child1
  • ls -l /proc/$(pidof server)/fd
  • cat /proc/net/unix

В принципе, я вижу две розетки и все, что с ними связано, но не могу сказать, что они связаны. Я пытаюсь определить, какой FD у родителя взаимодействует с каким дочерним процессом.

Джонатон Рейнхарт
источник

Ответы:

27

Начиная с ядра 3.3, это возможно с помощью ssили lsof-4.89или выше - см . Ответ Стефана Шазеласа .

В более старых версиях, по словам автора lsof, это было невозможно выяснить: ядро ​​Linux не предоставляет эту информацию. Источник: ветка 2003 года на comp.unix.admin .

Показанное число /proc/$pid/fd/$fdявляется номером inode сокета в файловой системе виртуального сокета. Когда вы создаете пару каналов или сокетов, каждый конец последовательно получает номер инода. Числа присваиваются последовательно, поэтому существует высокая вероятность того, что числа отличаются на 1, но это не гарантируется (либо потому, что первый сокет был N, а N +1 уже использовался из-за переноса, либо потому, что какой-то другой поток был запланировано между двумя распределениями inode, и этот поток также создал некоторые inode).

Я проверил определение socketpairв ядре 2.6.39 , и два конца сокета не коррелированы, кроме как с помощью socketpairметода, зависящего от типа . Для сокетов Unix, это unix_socketpairвnet/unix/af_unix.c .

Жиль "ТАК - перестань быть злым"
источник
2
Спасибо @Gillles. Я помню, что читал что-то об этом некоторое время назад, но не смог найти это снова. Возможно, мне просто нужно написать патч для / proc / net / unix.
Джонатон Рейнхарт
И да, я сделал это наблюдение с увеличением числа инодов, и в настоящее время это то, с чем я работаю. Однако, как вы заметили, это не гарантировано. У процесса, на который я смотрю, есть как минимум 40 открытых сокетов Unix, и я видел один случай, когда N + 1 не выполнялся. Облом.
Джонатон Рейнхарт
1
@JonathonReinhart Я проверил определениеsocketpair , и два конца сокета не коррелированы, кроме как с помощью socketpairметода, зависящего от типа . Для сокетов unix это находится unix_socketpairв `net / unix / af_unix.c . Было бы неплохо иметь эту информацию и для труб.
Жиль "ТАК - перестань быть злым"
36

Примечание : я теперь поддерживаю lsofоболочку, которая объединяет оба подхода, описанных здесь, а также добавляет информацию для пиров петлевых TCP-соединений по адресу https://github.com/stephane-chazelas/misc-scripts/blob/master/lsofc

Linux-3.3 и выше.

В Linux, начиная с версии ядра 3.3 (и при условии, что эта UNIX_DIAGфункция встроена в ядро), одноранговый узел данного сокета домена unix (включая пары сокетов) можно получить с помощью нового API на основе netlink .

lsof с версии 4.89 можно использовать этот API:

lsof +E -aUc Xorg

Перечислит все доменные сокеты Unix, у которых есть процесс, имя которого начинается с Xorgлюбого конца в формате, подобном следующему:

Xorg       2777       root   56u  unix 0xffff8802419a7c00      0t0   34036 @/tmp/.X11-unix/X0 type=STREAM ->INO=33273 4120,xterm,3u

Если ваша версия lsofслишком старая, есть еще несколько вариантов.

ssУтилита (от iproute2) использует тот же API для извлечения и отображения информации о списке сокетов домена UNIX в системе , включая информацию экспертной.

Сокеты идентифицируются по их номеру инода . Обратите внимание, что это не связано с inode файловой системы файла сокета.

Например, в:

$ ss -x
[...]
u_str  ESTAB    0    0   @/tmp/.X11-unix/X0 3435997     * 3435996

он говорит, что сокет 3435997 (который был связан с сокетом ABSTRACT /tmp/.X11-unix/X0) связан с сокетом 3435996. -pОпция может сказать вам, какие процессы открыли этот сокет. Он делает это, делая некоторые readlinkс на /proc/$pid/fd/*, так что он может сделать это только на процессы , которые вы владеете (если вы не root). Например здесь:

$ sudo ss -xp
[...]
u_str  ESTAB  0  0  @/tmp/.X11-unix/X0 3435997 * 3435996 users:(("Xorg",pid=3080,fd=83))
[...]
$ sudo ls -l /proc/3080/fd/23
lrwx------ 1 root root 64 Mar 12 16:34 /proc/3080/fd/83 -> socket:[3435997]

Чтобы узнать, какой процесс (ы) имеет 3435996, вы можете найти его собственную запись в выводе ss -xp:

$ ss -xp | awk '$6 == 3435996'
u_str  ESTAB  0  0  * 3435996  * 3435997 users:(("xterm",pid=29215,fd=3))

Вы также можете использовать этот скрипт в качестве оболочки, lsofчтобы легко показать соответствующую информацию там:

#! /usr/bin/perl
# lsof wrapper to add peer information for unix domain socket.
# Needs Linux 3.3 or above and CONFIG_UNIX_DIAG enabled.

# retrieve peer and direction information from ss
my (%peer, %dir);
open SS, '-|', 'ss', '-nexa';
while (<SS>) {
  if (/\s(\d+)\s+\*\s+(\d+) ([<-]-[->])$/) {
    $peer{$1} = $2;
    $dir{$1} = $3;
  }
}
close SS;

# Now get info about processes tied to sockets using lsof
my (%fields, %proc);
open LSOF, '-|', 'lsof', '-nPUFpcfin';
while (<LSOF>) {
  if (/(.)(.*)/) {
    $fields{$1} = $2;
    if ($1 eq 'n') {
      $proc{$fields{i}}->{"$fields{c},$fields{p}" .
      ($fields{n} =~ m{^([@/].*?)( type=\w+)?$} ? ",$1" : "")} = "";
    }
  }
}
close LSOF;

# and finally process the lsof output
open LSOF, '-|', 'lsof', @ARGV;
while (<LSOF>) {
  chomp;
  if (/\sunix\s+\S+\s+\S+\s+(\d+)\s/) {
    my $peer = $peer{$1};
    if (defined($peer)) {
      $_ .= $peer ?
            " ${dir{$1}} $peer\[" . (join("|", keys%{$proc{$peer}})||"?") . "]" :
            "[LISTENING]";
    }
  }
  print "$_\n";
}
close LSOF or exit(1);

Например:

$ sudo that-lsof-wrapper -ad3 -p 29215
КОМАНДА PID ПОЛЬЗОВАТЕЛЬ FD ТИП РАЗМЕР УСТРОЙСТВА / ВЫКЛЮЧЕНО NODE NAME
xterm 29215 stephane 3u unix 0xffff8800a07da4c0 0t0 3435996 type = STREAM <-> 3435997 [Xorg, 3080, @ / tmp / .X11-unix / X0]

До Linux-3.3

Старый Linux API для получения информации о сокетах Unix через /proc/net/unixтекстовый файл. В нем перечислены все доменные сокеты Unix (включая пары сокетов). Первое поле там (если оно не скрыто для не суперпользователей с kernel.kptr_restrictпараметром sysctl), как уже объяснено @Totor, содержит адрес ядра unix_sockструктуры, которая содержит peerполе, указывающее на соответствующий узел unix_sock . Это также то, что lsofвыводит DEVICEстолбец на сокете Unix.

Теперь получить значение этого peerполя означает, что вы можете прочитать память ядра и узнать смещение этого peerполя относительно unix_sockадреса.

Некоторые решения на gdbоснове и на systemtapоснове уже были предоставлены, но для них требуется gdb/ systemtapи символы отладки ядра Linux для устанавливаемого работающего ядра, что, как правило, не так в производственных системах.

Жесткое кодирование смещения на самом деле не вариант, так как это зависит от версии ядра.

Теперь мы можем использовать эвристический подход при определении смещения: наш инструмент создаст фиктивную socketpair(тогда мы узнаем адрес обоих пиров) и поищем адрес пира вокруг памяти на другом конце, чтобы определить смещение.

Вот сценарий проверки концепции, который делает именно это perl(успешно протестирован с ядром 2.4.27 и 2.6.32 на i386 и 3.13 и 3.16 на amd64). Как и выше, он работает как оболочка lsof:

Например:

$ that-lsof-wrapper -aUc nm-applet
КОМАНДА PID ПОЛЬЗОВАТЕЛЬ FD ТИП РАЗМЕР УСТРОЙСТВА / ВЫКЛЮЧЕНО NODE NAME
нм-апплет 4183 Stephane 4u Unix 0xffff8800a055eb40 0t0 36888 типа = STREAM -> 0xffff8800a055e7c0 [DBus-демон, 4190, @ / TMP / DBus-AiBCXOnuP6] 
нм-апплет 4183 Stephane 7u Unix 0xffff8800a055e440 0t0 36890 типа = STREAM -> 0xffff8800a055e0c0 [Xorg, 3080, @ / tmp / .X11-unix / X0] 
nm-applet 4183 stephane 8u unix 0xffff8800a05c1040 0t0 36201 type = STREAM -> 0xffff8800a05c13c0 [dbus-daemon, 4118, @ / tmp / dbus-yxxNrane appane 1183TyphuC] 
nm Unix 0xffff8800a055d080 0t0 36219 Тип = ПОТОК -> 0xffff8800a055d400 [DBus-демон, 4118, @ / TMP / DBus-yxxNr1NkYC] 
нм-апплет 4183 STEPHANE 12U Unix 0xffff88022e0dfb80 0t0 36221 типа = STREAM -> 0xffff88022e0df800 [DBus-демон, 2268, / вар / Работа / DBus / system_bus_socket]
nm-applet 4183 stephane 13u unix 0xffff88022e0f80c0 0t0 37025 type = STREAM -> 0xffff88022e29ec00 [dbus-daemon, 2268, / var / run / dbus / system_bus_socket]

Вот сценарий:

#! /usr/bin/perl
# wrapper around lsof to add peer information for Unix
# domain sockets. needs lsof, and superuser privileges.
# Copyright Stephane Chazelas 2015, public domain.
# example: sudo this-lsof-wrapper -aUc Xorg
use Socket;

open K, "<", "/proc/kcore" or die "open kcore: $!";
read K, $h, 8192 # should be more than enough
 or die "read kcore: $!";

# parse ELF header
my ($t,$o,$n) = unpack("x4Cx[C19L!]L!x[L!C8]S", $h);
$t = $t == 1 ? "L3x4Lx12" : "Lx4QQx8Qx16"; # program header ELF32 or ELF64
my @headers = unpack("x$o($t)$n",$h);

# read data from kcore at given address (obtaining file offset from ELF
# @headers)
sub readaddr {
  my @h = @headers;
  my ($addr, $length) = @_;
  my $offset;
  while (my ($t, $o, $v, $s) = splice @h, 0, 4) {
    if ($addr >= $v && $addr < $v + $s) {
      $offset = $o + $addr - $v;
      if ($addr + $length - $v > $s) {
        $length = $s - ($addr - $v);
      }
      last;
    }
  }
  return undef unless defined($offset);
  seek K, $offset, 0 or die "seek kcore: $!";
  my $ret;
  read K, $ret, $length or die "read($length) kcore \@$offset: $!";
  return $ret;
}

# create a dummy socketpair to try find the offset in the
# kernel structure
socketpair(Rdr, Wtr, AF_UNIX, SOCK_STREAM, PF_UNSPEC)
 or die "socketpair: $!";
$r = readlink("/proc/self/fd/" . fileno(Rdr)) or die "readlink Rdr: $!";
$r =~ /\[(\d+)/; $r = $1;
$w = readlink("/proc/self/fd/" . fileno(Wtr)) or die "readlink Wtr: $!";
$w =~ /\[(\d+)/; $w = $1;
# now $r and $w contain the socket inodes of both ends of the socketpair
die "Can't determine peer offset" unless $r && $w;

# get the inode->address mapping
open U, "<", "/proc/net/unix" or die "open unix: $!";
while (<U>) {
  if (/^([0-9a-f]+):(?:\s+\S+){5}\s+(\d+)/) {
    $addr{$2} = hex $1;
  }
}
close U;

die "Can't determine peer offset" unless $addr{$r} && $addr{$w};

# read 2048 bytes starting at the address of Rdr and hope to find
# the address of Wtr referenced somewhere in there.
$around = readaddr $addr{$r}, 2048;
my $offset = 0;
my $ptr_size = length(pack("L!",0));
my $found;
for (unpack("L!*", $around)) {
  if ($_ == $addr{$w}) {
    $found = 1;
    last;
  }
  $offset += $ptr_size;
}
die "Can't determine peer offset" unless $found;

my %peer;
# now retrieve peer for each socket
for my $inode (keys %addr) {
  $peer{$addr{$inode}} = unpack("L!", readaddr($addr{$inode}+$offset,$ptr_size));
}
close K;

# Now get info about processes tied to sockets using lsof
my (%fields, %proc);
open LSOF, '-|', 'lsof', '-nPUFpcfdn';
while (<LSOF>) {
  if (/(.)(.*)/) {
    $fields{$1} = $2;
    if ($1 eq 'n') {
      $proc{hex($fields{d})}->{"$fields{c},$fields{p}" .
      ($fields{n} =~ m{^([@/].*?)( type=\w+)?$} ? ",$1" : "")} = "";
    }
  }
}
close LSOF;

# and finally process the lsof output
open LSOF, '-|', 'lsof', @ARGV;
while (<LSOF>) {
  chomp;
  for my $addr (/0x[0-9a-f]+/g) {
    $addr = hex $addr;
    my $peer = $peer{$addr};
    if (defined($peer)) {
      $_ .= $peer ?
            sprintf(" -> 0x%x[", $peer) . join("|", keys%{$proc{$peer}}) . "]" :
            "[LISTENING]";
      last;
    }
  }
  print "$_\n";
}
close LSOF or exit(1);
Стефан Шазелас
источник
1
@mikeserv, это продолжение этого комментария . Невозможность найти другой конец сокетов Unix - это то, что всегда раздражало меня (часто при попытке найти X-клиентов, и недавно возник вопрос об этом ). Я постараюсь выяснить, можно ли использовать подобный подход для псевдо-терминалов, и предложу их lsofавтору.
Стефан Шазелас
1
Я до сих пор не могу поверить, что это не обеспечивается самим ядром! Я действительно должен представить патч, хотя бы для того, чтобы узнать, почему он еще не существует.
Джонатон Рейнхарт
1
это ssне делает этого? Это отчасти по моей голове, но ss -pxперечисляет множество сокетов Unix с информацией о users: ("nacl_helper",pid=18992,fd=6),("chrome",pid=18987,fd=6),("chrome",pid=18975,fd=5)) u_str ESTAB\t0\t0\t/run/dbus/system_bus_socket 8760\t\t* 15068State\tRecv-Q\tSend-Q\tLocal Address:Port\tPeer Address:Port
пирах,
1
Кроме того, если я делаю, lsof -c terminologyя могу видеть, terminolo 12731\tmikeserv\t12u\tunix\t0xffff880600e82680\t0t0\t1312426\ttype=STREAMно если я делаю, ss -px | grep terminologyя получаю:u_str\tESTAB\t0\t0\t* 1312426\t*1315046\tusers:(("terminology",pid=12731,fd=12))
mikeserv
1
@mikeserv, похоже, что так и есть! Кажется, в последнее время я трачу много времени ...
Стефан Шазелас
9

Эркки Сеппала на самом деле имеет инструмент, который получает эту информацию из ядра Linux с помощью gdb. Он доступен здесь .

Caleb
источник
2
Очень полезная информация! Даже если инструмент не работал для меня «из коробки» (он вызвал ядро ​​Упс), идея помогла мне определить другой конец. Я описал свое решение по переполнению стека.
MvG
8

Начиная с ядра 3.3

Теперь вы можете получить эту информацию с :ss

# ss -xp

Теперь вы можете увидеть в Peerстолбце идентификатор (номер индекса), который соответствует другому идентификатору в Localстолбце. Соответствующие идентификаторы - это два конца сокета.

Примечание: UNIX_DIAGопция должна быть включена в вашем ядре.

До ядра 3.3

Linux не предоставил эту информацию пользователю.

Однако, просматривая память ядра , мы можем получить доступ к этой информации.

Примечание. Этот ответ можно сделать, используя gdb, однако, см. Ответ @ StéphaneChazelas, более подробный в этом отношении.

# lsof | grep whatever
mysqld 14450 (...) unix 0xffff8801011e8280 (...) /var/run/mysqld/mysqld.sock
mysqld 14450 (...) unix 0xffff8801011e9600 (...) /var/run/mysqld/mysqld.sock

Есть 2 разных сокета, 1 прослушивающий и 1 установленный. Шестнадцатеричное число - это адрес соответствующей unix_sockструктуры ядра , peerатрибут которого является адресом другого конца сокета (также unix_sockэкземпляра структуры).

Теперь мы можем использовать, gdbчтобы найти peerвнутреннюю память ядра:

# gdb /usr/lib/debug/boot/vmlinux-3.2.0-4-amd64 /proc/kcore
(gdb) print ((struct unix_sock*)0xffff8801011e9600)->peer
$1 = (struct sock *) 0xffff880171f078c0

# lsof | grep 0xffff880171f078c0
mysql 14815 (...) unix 0xffff880171f078c0 (...) socket

Вот, пожалуйста, другой конец розетки mysql, PID 14815.

Ваше ядро ​​должно быть скомпилировано KCORE_ELFдля использования /proc/kcore. Кроме того, вам нужна версия образа вашего ядра с символами отладки. На Debian 7 apt-get install linux-image-3.2.0-4-amd64-dbgпредоставит этот файл.

Нет необходимости в отлаживаемом образе ядра ...

Если у вас нет (или вы не хотите сохранять) отладочного образа ядра в системе, вы можете задать gdbсмещение памяти для «ручного» доступа к peerзначению. Это значение смещения обычно отличается в зависимости от версии ядра или архитектуры.

На моем ядре я знаю, что смещение составляет 680 байт, то есть в 85 раз больше 64 бит. Так что я могу сделать:

# gdb /boot/vmlinux-3.2.0-4-amd64 /proc/kcore
(gdb) print ((void**)0xffff8801011e9600)[85]
$1 = (void *) 0xffff880171f078c0

Вуаля, тот же результат, что и выше.

Если у вас на одном компьютере работает одно и то же ядро, этот вариант проще использовать, потому что вам не нужен отладочный образ, только значение смещения.

Чтобы (легко) сначала обнаружить это значение смещения, вам необходимо изображение отладки:

$ pahole -C unix_sock /usr/lib/debug/boot/vmlinux-3.2.0-4-amd64
struct unix_sock {
  (...)
  struct sock *              peer;                 /*   680     8 */
  (...)
}

Итак, 680 байт, это 85 x 64 бита или 170 x 32 бита.

Большая часть кредита на этот ответ идет в MvG .

Totor
источник
2
Другим подходом для получения смещения может быть создание пары сокетов, идентификация соответствующих записей в / proc / net / unix на основе номеров инодов из ссылок чтения в / proc / pif / fd / * и сканирование памяти на предмет адреса одного сокета для адрес другой. Это может сделать его достаточно переносимым (в зависимости от версии и архитектуры Linux), который может быть реализован самой lsof. Я постараюсь придумать PoC.
Стефан Шазелас
2
Теперь я добавил такой PoC, который, кажется, хорошо работает на системах, которые я тестировал.
Стефан Шазелас
5

Это решение, хотя и работает, представляет ограниченный интерес, поскольку, если у вас достаточно недавняя системная карта, скорее всего, у вас будет достаточно недавнее ядро, где вы сможете использовать ssоснованные подходы , а если вы используете более старое ядро, то другое Решение , хотя более хакерский , скорее всего, сработает и не требует дополнительного программного обеспечения.

Все еще полезно в качестве демонстрации того, как использовать systemtapдля такого рода задач.

Если в недавней системе Linux с работающей системной вкладкой (1.8 или новее), вы можете использовать приведенный ниже скрипт для последующей обработки вывода lsof:

Например:

$ lsof -aUc nm-applet | sudo что-скрипт
КОМАНДА PID ПОЛЬЗОВАТЕЛЬ FD ТИП РАЗМЕР УСТРОЙСТВА / ВЫКЛЮЧЕНО NODE NAME
нм-апплет 4183 Stephane 4u Unix 0xffff8800a055eb40 0t0 36888 типа = STREAM -> 0xffff8800a055e7c0 [DBus-демон, 4190, @ / TMP / DBus-AiBCXOnuP6] 
нм-апплет 4183 Stephane 7u Unix 0xffff8800a055e440 0t0 36890 типа = STREAM -> 0xffff8800a055e0c0 [Xorg, 3080, @ / tmp / .X11-unix / X0] 
nm-applet 4183 stephane 8u unix 0xffff8800a05c1040 0t0 36201 type = STREAM -> 0xffff8800a05c13c0 [dbus-daemon, 4118, @ / tmp / dbus-yxxNrane appane 1183TyphuC] 
nm Unix 0xffff8800a055d080 0t0 36219 Тип = ПОТОК -> 0xffff8800a055d400 [DBus-демон, 4118, @ / TMP / DBus-yxxNr1NkYC] 
нм-апплет 4183 STEPHANE 12U Unix 0xffff88022e0dfb80 0t0 36221 типа = STREAM -> 0xffff88022e0df800 [DBus-демон, 2268, / вар / Работа / DBus / system_bus_socket]
nm-applet 4183 stephane 13u unix 0xffff88022e0f80c0 0t0 37025 type = STREAM -> 0xffff88022e29ec00 [dbus-daemon, 2268, / var / run / dbus / system_bus_socket]

(если вы видите 0x0000000000000000 выше вместо 0xffff ..., это потому, что в kernel.kptr_restrictвашей системе установлен параметр sysctl, который заставляет указатели ядра быть скрытыми от непривилегированных процессов, и в этом случае вам нужно будет запускать lsofот имени root, чтобы получить значимый результат).

Этот сценарий не делает никаких попыток справиться с именами файлов сокетов с помощью символов новой строки, но не делает lsof(и не lsofсправляется с пробелами или двоеточиями).

systemtapздесь используется для вывода адреса и однорангового адреса всех unix_sockструктур в unix_socket_tableхеше в ядре.

Проверено только на Linux 3.16 amd64 с системной тапой 2.6 и 3.13 с 2.3.

#! /usr/bin/perl
# meant to process lsof output to try and find the peer of a given
# unix domain socket. Needs a working systemtap, lsof, and superuser
# privileges. Copyright Stephane Chazelas 2015, public domain.
# Example: lsof -aUc X | sudo this-script
open STAP, '-|', 'stap', '-e', q{
  probe begin {
    offset = &@cast(0, "struct sock")->__sk_common->skc_node;
    for (i = 0; i < 512; i++) 
      for (p = @var("unix_socket_table@net/unix/af_unix.c")[i]->first;
           p;
           p=@cast(p, "struct hlist_node")->next
          ) {
        sock = p - offset;
        printf("%p %p\n", sock, @cast(sock, "struct unix_sock")->peer);
    }
    exit()
  }
};  
my %peer;
while (<STAP>) {
  chomp;
  my ($a, $b) = split;
  $peer{$a} = $b;
}
close STAP;

my %f, %addr;
open LSOF, '-|', 'lsof', '-nPUFpcfdn';
while (<LSOF>) {
  if (/(.)(.*)/) {
    $f{$1} = $2;
    if ($1 eq 'n') {
      $addr{$f{d}}->{"$f{c},$f{p}" . ($f{n} =~ m{^([@/].*?)( type=\w+)?$} ? ",$1" : "")} = "";
    }
  }
}
close LSOF;

while (<>) {
  chomp;
  for my $addr (/0x[0-9a-f]+/g) {
    my $peer = $peer{$addr};
    if (defined($peer)) {
      $_ .= $peer eq '0x0' ?
            "[LISTENING]" :
            " -> $peer\[" . join("|", keys%{$addr{$peer}}) . "]";
      last;
    }
  }
  print "$_\n";
}
Стефан Шазелас
источник
parse error: unknown statistic operator @var: я что-то пропустил?
Тотор
@Totor, @varбыл добавлен в systemtap 1.8, 2012-06-17 (последняя версия 2.7)
Стефан Шазелас
2

4.89 из lsof поддерживает отображение параметров конечной точки.

Цитируется из lsof.8:

+|-E +E specifies that process intercommunication channels should be
     displayed with endpoint information and the channels
     of the endpoints should also be displayed.  Currently
     only pipe on Linux is implemented.

     Endpoint information is displayed in the NAME column
     in the form "PID,cmd,FDmode".  PID is the endpoint
     process ID; cmd is the endpoint process command; FD is
     the endpoint file's descriptor; and mode is the
     endpoint file's access mode.  Multiple occurrences of
     this information can appear in a file's NAME column.

     -E specfies that Linux pipe files should only be
     displayed with endpoint information.

Пример вывода:

mozStorag 21535 22254  yamato    6u     unix 0xf...       0t0     348924 type=STREAM pino=351122 4249,dbus-daem,55u
mozStorag 21535 22254  yamato   10u     unix 0xf...       0t0     356193 type=STREAM pino=356194 21535,gdbus,11u
mozStorag 21535 22254  yamato   11u     unix 0xf...       0t0     356194 type=STREAM pino=356193 21535,gdbus,10u
mozStorag 21535 22254  yamato   21u     unix 0xf...       0t0     355141 type=STREAM pino=357544 4249,dbus-daem,60u
mozStorag 21535 22254  yamato   26u     unix 0xf...       0t0     351134 type=STREAM pino=355142 5015,gdbus,17u
mozStorag 21535 22254  yamato   69u     unix 0xf...       0t0     469354 type=STREAM pino=468160 4545,alsa-sink,21u
mozStorag 21535 22254  yamato   82u     unix 0xf...       0t0     449383 type=STREAM pino=449384 12257,Chrome_Ch,3u
mozStorag 21535 22254  yamato   86u     unix 0xf...       0t0     355174 type=SEQPACKET pino=355175 21535,gdbus,95u
mozStorag 21535 22254  yamato   95u     unix 0xf...       0t0     355175 type=SEQPACKET pino=355174 21535,gdbus,86u 12257,Chrome_Ch,4u
mozStorag 21535 22254  yamato  100u     unix 0xf...       0t0     449389 type=STREAM pino=456453 3614,Xorg,38u
mozStorag 21535 22254  yamato  105u     unix 0xf...       0t0     582613 type=STREAM pino=586261
obexd     22163        yamato    1u     unix 0xf...       0t0     361859 type=STREAM pino=365931
obexd     22163        yamato    2u     unix 0xf...       0t0     361860 type=STREAM pino=365934
obexd     22163        yamato    3u     unix 0xf...       0t0     361241 type=DGRAM pino=10028
obexd     22163        yamato    6u     unix 0xf...       0t0     361242 type=STREAM pino=361864 4249,dbus-daem,70u
Масатаке ЯМАТО
источник
2

Начиная с ядра Linux 4.2, существует CONFIG_UNIX_DIAGдополнительная информация о сокетах домена UNIX, а именно информация Virtual File System(VFS), которая содержит до сих пор недостающую информацию для связи Inode с путем к процессу. Его уже можно запросить с помощью ssинструмента из iproute2, начиная с версии v4.19.0 ~ 55 :

$ ss --processes --unix --all --extened
...
Netid  State   Recv-Q  Send-Q  Local Address:Port      Peer Address:Port
u_str  LISTEN  0       5         /tmp/socket 13381347             * 0     users:(("nc",pid=12550,fd=3)) <-> ino:1569897 dev:0/65025 peers:

Номер устройства и путь Inode вы можете получить

$ stat -c 'ino:%i dev:0/%d' /tmp/socket
ino:1569946 dev:0/65025

ss также поддерживает фильтрацию:

 ss --processes --unix --all --extended 'sport = /tmp/socket'

но имейте в виду, что в этом списке может не указываться нужный сокет, поскольку злой процесс может переименовать ваш исходный сокет и заменить его собственным злым:

mv /tmp/socket /tmp/socket.orig
nc -U -l /tmp/socket.evil &
mv /tmp/socket.evil /tmp/socket

lsof /tmp/socket, fuser /tmp/socketи ss --processes --unix --all --extended 'sport = /tmp/socket'все перечислю оригинальный процесс, а не злую замену. Вместо этого используйте что-то вроде этого:

id=$(stat -c 'ino:%i dev:0/%d' /tmp/socket)
ss --processes --unix --all --extended | grep -F "$id"

Или напишите свою собственную программу на основе шаблона, содержащегося в man 7 sock_diag .

pmhahn
источник