From: Masatake YAMATO Date: Sun, 9 Mar 2025 21:54:04 +0000 (+0900) Subject: lsfd: fill ENDPOINTS column for UNIX one-way sockets X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4d123ede99fa527c586224f00fe7a4db8c52c43b;p=thirdparty%2Futil-linux.git lsfd: fill ENDPOINTS column for UNIX one-way sockets 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 orignal code could not fill ENDPOINTS for UNIX one-way sockets: # ./original-lsfd -Q 'INODE == 13465' -oCOMMAND,PID,TYPE,INODE,NAME,ENDPOINTS COMMAND PID TYPE INODE NAME ENDPOINTS systemd 1 UNIX 13465 state=connected path=/run/systemd/notify type=dgram With this change, lsfd can fill the column: # ./new-lsfd -Q 'INODE == 13465' -oCOMMAND,PID,TYPE,INODE,NAME,ENDPOINTS COMMAND PID TYPE INODE NAME ENDPOINTS systemd 1 UNIX 13465 state=connected path=/run/systemd/notify type=dgram 1280,systemd-journal,15rw 13874,bluetoothd,4rw Signed-off-by: Masatake YAMATO --- diff --git a/lsfd-cmd/lsfd.1.adoc b/lsfd-cmd/lsfd.1.adoc index 13311ebd0..4d6fde156 100644 --- a/lsfd-cmd/lsfd.1.adoc +++ b/lsfd-cmd/lsfd.1.adoc @@ -195,6 +195,16 @@ write mode of the endpoint. eventfd type::: _PID_,_COMMAND_,_ASSOC_ +UNIX::: +Same as _UNIX-STREAM_. ++ +In a container, *lsfd* may not fill _ENDPOINTS_ column. +*lsfd* uses *sock_diag*(7) to collect information +about UNIX endpoints. SELinux may limit the use *sock_diag* +in a container. You can remove the limit by setting +1 to _virt_sandbox_use_netlink_ bool. See *container_selinux*(8) +for more details. + UNIX-STREAM::: _PID_,_COMMAND_,_ASSOC_[-r?][-w?] + diff --git a/lsfd-cmd/sock-xinfo.c b/lsfd-cmd/sock-xinfo.c index c5227e333..6023e6fc3 100644 --- a/lsfd-cmd/sock-xinfo.c +++ b/lsfd-cmd/sock-xinfo.c @@ -66,12 +66,17 @@ static void load_xinfo_from_proc_packet(ino_t netns_inode); static void load_xinfo_from_diag_unix(int diag, ino_t netns_inode); static void load_xinfo_from_diag_vsock(int diag, ino_t netns_inode); +static void fill_peers_of_unix_oneway_ipcs(void); + static int self_netns_fd = -1; static struct stat self_netns_sb; static void *xinfo_tree; /* for tsearch/tfind */ static void *netns_tree; +static LIST_HEAD(unix_ipcs); +static void *unix_oneway_ipc_tree; /* for tsearch/tfind */ + struct iface { unsigned int index; char name[IF_NAMESIZE]; @@ -290,10 +295,8 @@ void initialize_sock_xinfos(void) if (!pc) err(EXIT_FAILURE, _("failed to alloc path context for /var/run/netns")); dir = ul_path_opendir(pc, NULL); - if (dir == NULL) { - ul_unref_path(pc); - return; - } + if (dir == NULL) + goto out; while ((d = readdir(dir))) { struct stat sb; int fd; @@ -310,7 +313,10 @@ void initialize_sock_xinfos(void) close(fd); } closedir(dir); + out: ul_unref_path(pc); + + fill_peers_of_unix_oneway_ipcs(); } static void free_sock_xinfo(void *node) @@ -321,12 +327,17 @@ static void free_sock_xinfo(void *node) free(node); } +static void do_nothing(void *node __attribute__((__unused__))) +{ +} + void finalize_sock_xinfos(void) { if (self_netns_fd != -1) close(self_netns_fd); tdestroy(netns_tree, netns_free); tdestroy(xinfo_tree, free_sock_xinfo); + tdestroy(unix_oneway_ipc_tree, do_nothing); } static int xinfo_compare(const void *a, const void *b) @@ -461,6 +472,7 @@ struct unix_ipc { struct ipc ipc; ino_t inode; ino_t ipeer; + struct list_head unix_ipcs; }; struct unix_xinfo { @@ -665,18 +677,25 @@ static bool unix_fill_column(struct proc *proc __attribute__((__unused__)), } break; case COL_ENDPOINTS: + if (ux->unix_ipc == NULL) + break; + peer_ipc = unix_get_peer_ipc(ux, sock); - if (!peer_ipc) + if (!peer_ipc && ux->unix_ipc->ipeer != 0) break; - unix_fill_column_append_endpoints(peer_ipc, str); + if (peer_ipc) + unix_fill_column_append_endpoints(peer_ipc, str); - if (*str) - xstrputc(str, '\n'); - estr = unix_xstrendpoint(peer_sock); - xstrappend(str, estr); - free(estr); + if (ux->unix_ipc->ipeer == 0) { + struct list_head *e; + list_for_each(e, &ux->unix_ipc->unix_ipcs) { + struct unix_ipc *peer_unix_ipc = list_entry(e, struct unix_ipc, unix_ipcs); + peer_ipc = &peer_unix_ipc->ipc; + unix_fill_column_append_endpoints(peer_ipc, str); + } } + if (*str) return true; break; @@ -785,6 +804,33 @@ static void unix_refill_name(struct sock_xinfo *xinfo, const char *name, size_t ux->path[min_len] = '\0'; } +static int unix_oneway_ipc_compare(const void *a, const void *b) +{ + return ((struct unix_ipc *)a)->inode - ((struct unix_ipc *)b)->inode; +} + +static void add_unix_oneway_ipc(struct unix_ipc *unix_oneway_ipc) +{ + struct unix_ipc **tmp = tsearch(unix_oneway_ipc, + &unix_oneway_ipc_tree, + unix_oneway_ipc_compare); + + if (tmp == NULL) + errx(EXIT_FAILURE, _("failed to allocate memory")); +} + +static struct unix_ipc *get_unix_oneway_ipc(ino_t inode) +{ + struct unix_ipc key = { .inode = inode }; + struct unix_ipc **unix_oneway_ipc = tfind(&key, + &unix_oneway_ipc_tree, + unix_oneway_ipc_compare); + + if (unix_oneway_ipc) + return *unix_oneway_ipc; + return NULL; +} + static bool handle_diag_unix(ino_t netns __attribute__((__unused__)), size_t nlmsg_len, void *nlmsg_data) { @@ -852,6 +898,10 @@ static bool handle_diag_unix(ino_t netns __attribute__((__unused__)), unix_xinfo->unix_ipc = (struct unix_ipc *)new_ipc(&unix_ipc_class); unix_xinfo->unix_ipc->inode = inode; unix_xinfo->unix_ipc->ipeer = (ino_t)(*(uint32_t *)RTA_DATA(attr)); + + INIT_LIST_HEAD(&unix_xinfo->unix_ipc->unix_ipcs); + list_add(&unix_xinfo->unix_ipc->unix_ipcs, &unix_ipcs); + add_ipc(&unix_xinfo->unix_ipc->ipc, inode % UINT_MAX); peer_added = true; break; @@ -863,6 +913,10 @@ static bool handle_diag_unix(ino_t netns __attribute__((__unused__)), unix_xinfo->unix_ipc = (struct unix_ipc *)new_ipc(&unix_ipc_class); unix_xinfo->unix_ipc->inode = inode; unix_xinfo->unix_ipc->ipeer = 0; + + INIT_LIST_HEAD(&unix_xinfo->unix_ipc->unix_ipcs); + add_unix_oneway_ipc(unix_xinfo->unix_ipc); + add_ipc(&unix_xinfo->unix_ipc->ipc, inode % UINT_MAX); }; return true; @@ -879,6 +933,25 @@ static void load_xinfo_from_diag_unix(int diagsd, ino_t netns) send_diag_request(diagsd, &udr, sizeof(udr), handle_diag_unix, netns); } +static void fill_peers_of_unix_oneway_ipcs(void) +{ + struct list_head *e, *enext; + + list_for_each_safe(e, enext, &unix_ipcs) { + struct unix_ipc *unix_ipc = list_entry(e, struct unix_ipc, unix_ipcs); + struct unix_ipc *unix_oneway_ipc; + + list_del_init(e); + if (unix_ipc->ipeer == 0) + continue; + + unix_oneway_ipc = get_unix_oneway_ipc(unix_ipc->ipeer); + if (unix_oneway_ipc == NULL) + continue; + list_add(e, &unix_oneway_ipc->unix_ipcs); + }; +} + /* * AF_INET */ diff --git a/tests/expected/lsfd/mkfds-unix-dgram-ENDPOINTS-column b/tests/expected/lsfd/mkfds-unix-dgram-ENDPOINTS-column index 71ba0525f..2515a4e0d 100644 --- a/tests/expected/lsfd/mkfds-unix-dgram-ENDPOINTS-column +++ b/tests/expected/lsfd/mkfds-unix-dgram-ENDPOINTS-column @@ -1,2 +1,4 @@ endpoint_c: 0 endpoint_c == PID,test_mkfs,3rw: 0 +endpoint_s: 0 +endpoint_s == PID,test_mkfs,4rw: 0 diff --git a/tests/ts/lsfd/mkfds-unix-dgram b/tests/ts/lsfd/mkfds-unix-dgram index c19e8ca29..1de791061 100755 --- a/tests/ts/lsfd/mkfds-unix-dgram +++ b/tests/ts/lsfd/mkfds-unix-dgram @@ -89,6 +89,12 @@ else test "$endpoint_c" = "${PID},test_mkfds,${FDS}rw" echo "endpoint_c == PID,test_mkfs,${FDS}rw:" $? + endpoint_s=$(${TS_CMD_LSFD} -n -r -Q "PID == ${PID} && FD == $FDS" -o ENDPOINTS) + echo endpoint_s: $? + + test "$endpoint_s" = "${PID},test_mkfds,${FDC}rw" + echo "endpoint_s == PID,test_mkfs,${FDC}rw:" $? + echo DONE >&"${MKFDS[1]}" fi wait "${MKFDS_PID}"