forked from lemonsqueeze/unix-sockets-peers
-
Notifications
You must be signed in to change notification settings - Fork 0
/
socket_peer
executable file
·121 lines (99 loc) · 3.81 KB
/
socket_peer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#!/usr/bin/perl
# socket_peer
# https://github.com/lemonsqueeze/unix_sockets_peers
#
# Run find_gdb_offset script to find $struct_unix_sock__peer_offset value.
use File::Temp qw/ tempfile /;
use POSIX;
sub usage
{
print "Find pid of process connected to unix socket with inode socket_inode.\n";
print "Usage: socket_peer socket_inode\n";
exit 1;
}
($ARGV[0] eq "--help") && usage();
(getuid() != 0) && die "must be root.";
#my $debug = 1;
#my $use_kernel_debug_symbols = 1; # slooow
#######################################################################
# Use lsof to map pids/sockets/kernel addresses
my %inode_to_pid;
my %pid_to_name;
my %address_to_inode;
my %inode_to_address;
sub init_lsof
{
my @lsof = split('\n', `lsof -U +c 0 2>/dev/null` || die "couldn't run lsof");
shift @lsof; # remove header
# COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
# Xorg 982 root 31u unix 0xed0b4400 0t0 6820 /tmp/.X11-unix/X0
foreach my $str (@lsof)
{
$str =~ s/ */ /g;
my ($name, $pid, $z, $z, $z, $address, $z, $inode) = split(' ', $str);
$inode_to_pid{$inode} = $pid;
$pid_to_name{$pid} = $name;
$address_to_inode{$address} = $inode;
$inode_to_address{$inode} = $address;
if ($debug) { print "inode $inode -> address $address ($pid $name)\n"; }
}
}
#######################################################################
# lsof -U + gdb way
# Slow but sure way, if you have the kernel's debug symbols (vmlinux)
my $vmlinux = "/usr/src/linux/vmlinux";
sub get_address_gdb_debug_symbols
{
my ($address) = @_;
my $gdb_cmd="p (void *)((struct unix_sock*)$address)->peer\n";
my ($fh, $temp_file) = tempfile("/tmp/netstat_unix.XXXXXXXX", UNLINK => 1);
print $fh $gdb_cmd; close($fh);
return `gdb $vmlinux /proc/kcore --batch -x $temp_file` || die "couldn't run gdb";
}
# Hack, find the right offset, then you don't need debugging symbols !
# (see find_gdb_offset script)
my $struct_unix_sock__peer_offset = 104;
sub get_address_gdb_no_symbols
{
my ($address) = @_;
my $gdb_cmd="p ((void **)$address)[$struct_unix_sock__peer_offset]\n";
my ($fh, $temp_file) = tempfile("/tmp/netstat_unix.XXXXXXXX", UNLINK => 1);
print $fh $gdb_cmd; close($fh);
return `gdb /dev/null /proc/kcore --batch -x $temp_file 2>/dev/null` || die "couldn't run gdb";
}
sub find_peer_inode
{
my ($inode) = @_;
if ($debug) { print "running gdb ...\n"; }
my $address = $inode_to_address{$inode} || die "$inode: couldn't map inode to address";
my $gdb = ($use_kernel_debug_symbols ? get_address_gdb_debug_symbols($address) :
get_address_gdb_no_symbols($address) );
if ($gdb =~ m|\(void \*\) (0x[0-9a-f]*)|) # $1 = (void *) 0xed289000
{
my $peer_address = $1;
my $peer_inode = $address_to_inode{$peer_address} ||
die ("$peer_address: couldn't map address to inode.\n" .
"wrong hardcoded gdb offset ? check with find_gdb_offset script.");
if ($debug) { print "[ inode $inode -> kernel $address ] --> [ kernel $peer_address -> inode $peer_inode ]\n"; }
return $peer_inode;
}
die "failed to parse gdb output (bug?)";
}
#######################################################################
sub find_peer_pid
{
my ($inode) = @_;
$inode_to_pid{$inode} || die("$inode: No process owns this socket. bad number ?\n");
my $peer_inode = find_peer_inode($inode);
my $peer_pid = $inode_to_pid{$peer_inode} || die "couldn't map inode to pid.";
return $peer_pid;
}
#######################################################################
my $inode = @ARGV[0];
if (!($inode =~ m|[0-9]+|))
{ usage(); }
init_lsof();
my $pid = find_peer_pid($inode);
if ($pid)
{ print "$pid $pid_to_name{$pid}\n"; exit 0; }
die "couldn't find peer process for unix socket $inode\n";