]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lsfd: add a dummy entry for UNIX socket having no peer to the IPC table
authorMasatake YAMATO <yamato@redhat.com>
Sun, 9 Mar 2025 03:48:34 +0000 (12:48 +0900)
committerMasatake YAMATO <yamato@redhat.com>
Fri, 14 Mar 2025 14:26:23 +0000 (23:26 +0900)
With recvfrom(2) and sendto(2), we can use a UNIX datagram socket at
server side without assigning a peer address with connect(2). Here, I
call such sockets one-way sockets.

   # ss -x -p
   Netid State Recv-Q Send-Q        Local Address:Port  Peer Address:Port Process
   ...
   u_dgr ESTAB      0      0 /run/systemd/notify 13465               * 0  users:(("systemd",pid=1,fd=227))
   u_dgr ESTAB      0      0                   * 35438           * 13465  users:(("systemd-journal",pid=1280,fd=15))
   u_dgr ESTAB      0      0                   * 74792           * 13465  users:(("bluetoothd",pid=13874,fd=4))
   ...

The socket, opened with systemd as fd 227, is an example of one-way
socket (13465). It has 0 as "Peer Address:Port". From the side of
systemd process, there is no communication peers. However, the
sockets (35438 and 74792) opened with systemd-journal and bluetoothd
have the one-way socket (13465) as their communication peers.

We expect lsfd prints these connections if user specifies
-o+ENDPOINTS. This change and subsequent changes remove limitations in
this area.

In the early stage of lsfd process, lsfd collects information about
UNIX sockets on the system via unix-diag netlink. lsfd stores the
information to the IPC table. lsfd looks up the IPC table when
printing ENDPOINTS column.

With the original code, lsfd could not fill the ENDPOINTS columns
for sockets connecting to an one-way socket because lsfd did not
store one-way sockets to the IPC table.

  # ./original-lsfd -Q 'INODE == 35438 || INODE == 74792' -oCOMMAND,PID,TYPE,INODE,NAME,ENDPOINTS
  COMMAND           PID TYPE INODE NAME                       ENDPOINTS
  systemd-journal  1280 UNIX 35438 state=connected type=dgram
  bluetoothd      13874 UNIX 74792 state=connected type=dgram

With this change, lsfd can fill the ENDPOINTS columns for sockets
connecting to an one-way socket. The new code puts dummy entries for
the one-way sockets to the IPC table. The dummy entries help lsfd to
find the connections.

  # ./new-lsfd -Q 'INODE == 35438 || INODE == 74792' -oCOMMAND,PID,TYPE,INODE,NAME,ENDPOINTS
  COMMAND           PID TYPE INODE NAME                       ENDPOINTS
  systemd-journal  1280 UNIX 35438 state=connected type=dgram 1,systemd,227rw
  bluetoothd      13874 UNIX 74792 state=connected type=dgram 1,systemd,227rw

Signed-off-by: Masatake YAMATO <yamato@redhat.com>
lsfd-cmd/sock-xinfo.c
tests/expected/lsfd/mkfds-unix-dgram-ENDPOINTS-column [new file with mode: 0644]
tests/ts/lsfd/mkfds-unix-dgram

index f6811213aa40dbf0f9f3a762daf3249eca70e0af..4d9dfb81780d705e06270ba185b052c0af4772ef 100644 (file)
@@ -780,6 +780,8 @@ static bool handle_diag_unix(ino_t netns __attribute__((__unused__)),
        ino_t inode;
        struct sock_xinfo *xinfo;
        struct unix_xinfo *unix_xinfo;
+       bool peer_added = false;
+       bool maybe_oneway = false;
 
        if (diag->udiag_family != AF_UNIX)
                return false;
@@ -819,6 +821,7 @@ static bool handle_diag_unix(ino_t netns __attribute__((__unused__)),
                switch (attr->rta_type) {
                case UNIX_DIAG_NAME:
                        unix_refill_name(xinfo, RTA_DATA(attr), len);
+                       maybe_oneway = true;
                        break;
 
                case UNIX_DIAG_SHUTDOWN:
@@ -837,9 +840,18 @@ static bool handle_diag_unix(ino_t netns __attribute__((__unused__)),
                        unix_xinfo->unix_ipc->inode = inode;
                        unix_xinfo->unix_ipc->ipeer = (ino_t)(*(uint32_t *)RTA_DATA(attr));
                        add_ipc(&unix_xinfo->unix_ipc->ipc, inode % UINT_MAX);
+                       peer_added = true;
                        break;
                }
        }
+
+       if (!peer_added && maybe_oneway) {
+               assert(unix_xinfo->unix_ipc == NULL);
+               unix_xinfo->unix_ipc = (struct unix_ipc *)new_ipc(&unix_ipc_class);
+               unix_xinfo->unix_ipc->inode = inode;
+               unix_xinfo->unix_ipc->ipeer = 0;
+               add_ipc(&unix_xinfo->unix_ipc->ipc, inode % UINT_MAX);
+       };
        return true;
 }
 
diff --git a/tests/expected/lsfd/mkfds-unix-dgram-ENDPOINTS-column b/tests/expected/lsfd/mkfds-unix-dgram-ENDPOINTS-column
new file mode 100644 (file)
index 0000000..71ba052
--- /dev/null
@@ -0,0 +1,2 @@
+endpoint_c: 0
+endpoint_c == PID,test_mkfs,3rw: 0
index c3b0711e4a590d090bf3f6777819af413db0df0b..c19e8ca29c7c0cab83ee3410831f8d7384d0943d 100755 (executable)
@@ -73,4 +73,27 @@ ts_init_subtest "abstract"
 } > "$TS_OUTPUT" 2>&1
 ts_finalize_subtest
 
+ts_init_subtest "ENDPOINTS-column"
+if ts_is_in_docker; then
+    ts_skip_subtest "unsupported in docker environment"
+else
+    {
+       coproc MKFDS { "$TS_HELPER_MKFDS" unix-dgram $FDS $FDC \
+                                         path=test_mkfds-unix-dgram \
+                                         abstract=true ; }
+
+       if read -r -u "${MKFDS[0]}" PID; then
+           endpoint_c=$(${TS_CMD_LSFD} -n -r -Q "PID == ${PID} && FD == $FDC" -o ENDPOINTS)
+           echo endpoint_c: $?
+
+           test "$endpoint_c" = "${PID},test_mkfds,${FDS}rw"
+           echo "endpoint_c == PID,test_mkfs,${FDS}rw:" $?
+
+           echo DONE >&"${MKFDS[1]}"
+       fi
+       wait "${MKFDS_PID}"
+    } > "$TS_OUTPUT" 2>&1
+    ts_finalize_subtest
+fi
+
 ts_finalize