aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarel Zak <kzak@redhat.com>2024-04-08 09:55:59 +0200
committerKarel Zak <kzak@redhat.com>2024-04-08 09:55:59 +0200
commit671b8b058b02f2dd44ede6317f9cfe6cf09cac12 (patch)
tree91530cc3e7702988fa26ba0541db95ee4fcd67af
parent44b92ef3bb950f5680c5febcca5d4b47e67c628c (diff)
parent099a58dbde6b349c4b5fbebd5116337b2ef2f2fd (diff)
downloadutil-linux-671b8b058b02f2dd44ede6317f9cfe6cf09cac12.tar.gz
Merge branch 'test_mkfds-sockdiag-for-master' of https://github.com/masatake/util-linux
* 'test_mkfds-sockdiag-for-master' of https://github.com/masatake/util-linux: tests: (test_mkfds::sockdiag) verify the recieved message to detect whether the socket is usable or not lsfd: add LSFD_DEBUG env var for debugging tests: (lsfd) skip some cases if NETLINK_SOCK_DIAG for AF_UNIX is not available tests: (test_mkfds::sockdiag) new factory tests: (lsfd-functions.bash,cosmetic) unify the style to define functions tests: (lsfd) fix typoes in an error name
-rw-r--r--misc-utils/lsfd-sock-xinfo.c51
-rw-r--r--misc-utils/lsfd.c10
-rw-r--r--misc-utils/lsfd.h15
-rw-r--r--tests/helpers/test_mkfds.c150
-rw-r--r--tests/ts/lsfd/lsfd-functions.bash33
-rwxr-xr-xtests/ts/lsfd/mkfds-ping2
-rwxr-xr-xtests/ts/lsfd/mkfds-socketpair3
-rwxr-xr-xtests/ts/lsfd/mkfds-unix-stream-requiring-sockdiag2
8 files changed, 253 insertions, 13 deletions
diff --git a/misc-utils/lsfd-sock-xinfo.c b/misc-utils/lsfd-sock-xinfo.c
index 8ee57e6b1f..9422d4b98c 100644
--- a/misc-utils/lsfd-sock-xinfo.c
+++ b/misc-utils/lsfd-sock-xinfo.c
@@ -179,9 +179,12 @@ static void load_sock_xinfo_no_nsswitch(struct netns *nsobj)
load_xinfo_from_proc_packet(netns);
diagsd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_SOCK_DIAG);
+ DBG(ENDPOINTS, ul_debug("made a diagnose socket [fd=%d; %s]", diagsd,
+ (diagsd >= 0)? "successful": strerror(errno)));
if (diagsd >= 0) {
load_xinfo_from_diag_unix(diagsd, netns);
close(diagsd);
+ DBG(ENDPOINTS, ul_debug("close the diagnose socket"));
}
if (nsobj)
@@ -337,6 +340,7 @@ static void send_diag_request(int diagsd, void *req, size_t req_size,
bool (*cb)(ino_t, size_t, void *),
ino_t netns)
{
+ int r;
struct sockaddr_nl nladdr = {
.nl_family = AF_NETLINK,
};
@@ -361,30 +365,45 @@ static void send_diag_request(int diagsd, void *req, size_t req_size,
__attribute__((aligned(sizeof(void *)))) uint8_t buf[8192];
- if (sendmsg(diagsd, &mhd, 0) < 0)
+ r = sendmsg(diagsd, &mhd, 0);
+ DBG(ENDPOINTS, ul_debug("sendmsg [rc=%d; %s]",
+ r, (r >= 0)? "successful": strerror(errno)));
+ if (r < 0)
return;
for (;;) {
const struct nlmsghdr *h;
- int r = recvfrom(diagsd, buf, sizeof(buf), 0, NULL, NULL);
+ r = recvfrom(diagsd, buf, sizeof(buf), 0, NULL, NULL);
+ DBG(ENDPOINTS, ul_debug("recvfrom [rc=%d; %s]",
+ r, (r >= 0)? "successful": strerror(errno)));
if (r < 0)
return;
h = (void *) buf;
+ DBG(ENDPOINTS, ul_debug(" OK: %d", NLMSG_OK(h, (size_t)r)));
if (!NLMSG_OK(h, (size_t)r))
return;
for (; NLMSG_OK(h, (size_t)r); h = NLMSG_NEXT(h, r)) {
- if (h->nlmsg_type == NLMSG_DONE)
+ if (h->nlmsg_type == NLMSG_DONE) {
+ DBG(ENDPOINTS, ul_debug(" DONE"));
return;
- if (h->nlmsg_type == NLMSG_ERROR)
+ }
+ if (h->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *e = (struct nlmsgerr *)NLMSG_DATA(h);
+ DBG(ENDPOINTS, ul_debug(" ERROR: %s",
+ strerror(- e->error)));
return;
+ }
if (h->nlmsg_type == SOCK_DIAG_BY_FAMILY) {
+ DBG(ENDPOINTS, ul_debug(" FAMILY"));
if (!cb(netns, h->nlmsg_len, NLMSG_DATA(h)))
return;
}
+ DBG(ENDPOINTS, ul_debug(" NEXT"));
}
+ DBG(ENDPOINTS, ul_debug(" OK: 0"));
}
}
@@ -639,6 +658,8 @@ static void load_xinfo_from_proc_unix(ino_t netns_inode)
FILE *unix_fp;
unix_fp = fopen("/proc/net/unix", "r");
+ DBG(ENDPOINTS, ul_debug("open /proc/net/unix [fp=%p; %s]", unix_fp,
+ unix_fp? "successful": strerror(errno)));
if (!unix_fp)
return;
@@ -655,13 +676,18 @@ static void load_xinfo_from_proc_unix(ino_t netns_inode)
unsigned long inode;
struct unix_xinfo *ux;
char path[UNIX_LINE_LEN + 1] = { 0 };
+ int r;
+ DBG(ENDPOINTS, ul_debug(" line: %s", line));
- if (sscanf(line, "%*x: %*x %*x %" SCNx64 " %x %x %lu %"
+ r = sscanf(line, "%*x: %*x %*x %" SCNx64 " %x %x %lu %"
stringify_value(UNIX_LINE_LEN) "[^\n]",
- &flags, &type, &st, &inode, path) < 4)
+ &flags, &type, &st, &inode, path);
+ DBG(ENDPOINTS, ul_debug(" scanf: %d", r));
+ if (r < 4)
continue;
+ DBG(ENDPOINTS, ul_debug(" inode: %lu", inode));
if (inode == 0)
continue;
@@ -675,10 +701,12 @@ static void load_xinfo_from_proc_unix(ino_t netns_inode)
ux->st = st;
xstrncpy(ux->path, path, sizeof(ux->path));
+ DBG(ENDPOINTS, ul_debug(" path: %s", ux->path));
add_sock_info(&ux->sock);
}
out:
+ DBG(ENDPOINTS, ul_debug("close /proc/net/unix"));
fclose(unix_fp);
}
@@ -712,6 +740,9 @@ static bool handle_diag_unix(ino_t netns __attribute__((__unused__)),
if (diag->udiag_family != AF_UNIX)
return false;
+ DBG(ENDPOINTS, ul_debug(" UNIX"));
+ DBG(ENDPOINTS, ul_debug(" LEN: %zu (>= %zu)", nlmsg_len,
+ (size_t)(NLMSG_LENGTH(sizeof(*diag)))));
if (nlmsg_len < NLMSG_LENGTH(sizeof(*diag)))
return false;
@@ -719,21 +750,29 @@ static bool handle_diag_unix(ino_t netns __attribute__((__unused__)),
inode = (ino_t)diag->udiag_ino;
xinfo = get_sock_xinfo(inode);
+ DBG(ENDPOINTS, ul_debug(" inode: %llu", (unsigned long long)inode));
+ DBG(ENDPOINTS, ul_debug(" xinfo: %p", xinfo));
+
if (xinfo == NULL)
/* The socket is found in the diag response
but not in the proc fs. */
return true;
+ DBG(ENDPOINTS, ul_debug(" xinfo->class == &unix_xinfo_class: %d",
+ xinfo->class == &unix_xinfo_class));
if (xinfo->class != &unix_xinfo_class)
return true;
unix_xinfo = (struct unix_xinfo *)xinfo;
rta_len = nlmsg_len - NLMSG_LENGTH(sizeof(*diag));
+ DBG(ENDPOINTS, ul_debug(" rta_len: %zu", rta_len));
for (struct rtattr *attr = (struct rtattr *)(diag + 1);
RTA_OK(attr, rta_len);
attr = RTA_NEXT(attr, rta_len)) {
size_t len = RTA_PAYLOAD(attr);
+ DBG(ENDPOINTS, ul_debug(" len = %2zu, type: %d",
+ rta_len, attr->rta_type));
switch (attr->rta_type) {
case UNIX_DIAG_NAME:
unix_refill_name(xinfo, RTA_DATA(attr), len);
diff --git a/misc-utils/lsfd.c b/misc-utils/lsfd.c
index f042f5caaa..09503d0ab7 100644
--- a/misc-utils/lsfd.c
+++ b/misc-utils/lsfd.c
@@ -84,6 +84,14 @@ static int kcmp(pid_t pid1 __attribute__((__unused__)),
#include "lsfd.h"
+UL_DEBUG_DEFINE_MASK(lsfd);
+UL_DEBUG_DEFINE_MASKNAMES(lsfd) = UL_DEBUG_EMPTY_MASKNAMES;
+
+static void lsfd_init_debug(void)
+{
+ __UL_INIT_DEBUG_FROM_ENV(lsfd, LSFD_DEBUG_, 0, LSFD_DEBUG);
+}
+
/*
* /proc/$pid/mountinfo entries
*/
@@ -2509,6 +2517,8 @@ int main(int argc, char *argv[])
{ NULL, 0, NULL, 0 },
};
+ lsfd_init_debug();
+
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
diff --git a/misc-utils/lsfd.h b/misc-utils/lsfd.h
index 217bf45338..f70f53cc15 100644
--- a/misc-utils/lsfd.h
+++ b/misc-utils/lsfd.h
@@ -28,7 +28,11 @@
#include <sys/stat.h>
#include <dirent.h>
#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "debug.h"
#include "libsmartcols.h"
#include "list.h"
#include "nls.h"
@@ -37,6 +41,17 @@
#include "xalloc.h"
/*
+ * debug
+ */
+UL_DEBUG_DECLARE_MASK(lsfd);
+
+#define LSFD_DEBUG_INIT (1 << 1)
+#define LSFD_DEBUG_ENDPOINTS (1 << 2)
+#define LSFD_DEBUG_ALL 0xFFFF
+
+#define DBG(m, x) __UL_DBG(lsfd, LSFD_DEBUG_, m, x)
+
+/*
* column IDs
*/
enum {
diff --git a/tests/helpers/test_mkfds.c b/tests/helpers/test_mkfds.c
index 28ed3bffcb..60ebdd6761 100644
--- a/tests/helpers/test_mkfds.c
+++ b/tests/helpers/test_mkfds.c
@@ -34,6 +34,8 @@
#include <linux/if_packet.h>
#include <linux/if_tun.h>
#include <linux/netlink.h>
+#include <linux/sock_diag.h>
+# include <linux/unix_diag.h> /* for UNIX domain sockets */
#include <linux/sockios.h> /* SIOCGSKNS */
#include <mqueue.h>
#include <net/if.h>
@@ -69,7 +71,8 @@
#define EXIT_EPERM 18
#define EXIT_ENOPROTOOPT 19
#define EXIT_EPROTONOSUPPORT 20
-#define EXIT_EACCESS 21
+#define EXIT_EACCES 21
+#define EXIT_ENOENT 22
#define _U_ __attribute__((__unused__))
@@ -2097,7 +2100,7 @@ static void *make_ping_common(const struct factory *factory, struct fdesc fdescs
sd = socket(family, SOCK_DGRAM, protocol);
if (sd < 0)
- err((errno == EACCES? EXIT_EACCESS: EXIT_FAILURE),
+ err((errno == EACCES? EXIT_EACCES: EXIT_FAILURE),
"failed to make an icmp socket");
if (sd != fdescs[0].fd) {
@@ -2117,7 +2120,7 @@ static void *make_ping_common(const struct factory *factory, struct fdesc fdescs
int e = errno;
close(sd);
errno = e;
- err((errno == EACCES? EXIT_EACCESS: EXIT_FAILURE),
+ err((errno == EACCES? EXIT_EACCES: EXIT_FAILURE),
"failed in bind(2)");
}
}
@@ -3307,6 +3310,129 @@ static void free_mmap(const struct factory * factory _U_, void *data)
((struct mmap_data *)data)->len);
}
+static int send_diag_request(int diagsd, void *req, size_t req_size)
+{
+ struct sockaddr_nl nladdr = {
+ .nl_family = AF_NETLINK,
+ };
+
+ struct nlmsghdr nlh = {
+ .nlmsg_len = sizeof(nlh) + req_size,
+ .nlmsg_type = SOCK_DIAG_BY_FAMILY,
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
+ };
+
+ struct iovec iovecs[] = {
+ { &nlh, sizeof(nlh) },
+ { req, req_size },
+ };
+
+ const struct msghdr mhd = {
+ .msg_namelen = sizeof(nladdr),
+ .msg_name = &nladdr,
+ .msg_iovlen = ARRAY_SIZE(iovecs),
+ .msg_iov = iovecs,
+ };
+
+ if (sendmsg(diagsd, &mhd, 0) < 0)
+ return errno;
+
+ return 0;
+}
+
+static int recv_diag_request(int diagsd)
+{
+ __attribute__((aligned(sizeof(void *)))) uint8_t buf[8192];
+ const struct nlmsghdr *h;
+ int r = recvfrom(diagsd, buf, sizeof(buf), 0, NULL, NULL);;
+ if (r < 0)
+ return errno;
+
+ h = (void *)buf;
+ if (!NLMSG_OK(h, (size_t)r))
+ return -1;
+
+ if (h->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *e = (struct nlmsgerr *)NLMSG_DATA(h);
+ return - e->error;
+ }
+ return 0;
+}
+
+static void *make_sockdiag(const struct factory *factory, struct fdesc fdescs[],
+ int argc, char ** argv)
+{
+ struct arg family = decode_arg("family", factory->params, argc, argv);
+ const char *sfamily = ARG_STRING(family);
+ int ifamily;
+ int diagsd;
+ void *req = NULL;
+ size_t reqlen = 0;
+ int e;
+ struct unix_diag_req udr;
+
+ if (strcmp(sfamily, "unix") == 0)
+ ifamily = AF_UNIX;
+ else
+ errx(EXIT_FAILURE, "unknown/unsupported family: %s", sfamily);
+ free_arg(&family);
+
+ diagsd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_SOCK_DIAG);
+ if (diagsd < 0)
+ err(errno == EPROTONOSUPPORT? EXIT_EPROTONOSUPPORT: EXIT_FAILURE,
+ "failed in sendmsg()");
+
+ if (ifamily == AF_UNIX) {
+ udr = (struct unix_diag_req) {
+ .sdiag_family = AF_UNIX,
+ .udiag_states = -1, /* set the all bits. */
+ .udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UNIX_DIAG_SHUTDOWN,
+ };
+ req = &udr;
+ reqlen = sizeof(udr);
+ }
+
+ e = send_diag_request(diagsd, req, reqlen);
+ if (e) {
+ close (diagsd);
+ errno = e;
+ if (errno == EACCES)
+ err(EXIT_EACCES, "failed in sendmsg()");
+ if (errno == ENOENT)
+ err(EXIT_ENOENT, "failed in sendmsg()");
+ err(EXIT_FAILURE, "failed in sendmsg()");
+ }
+
+ e = recv_diag_request(diagsd);
+ if (e != 0) {
+ close (diagsd);
+ if (e == ENOENT)
+ err(EXIT_ENOENT, "failed in recvfrom()");
+ if (e > 0)
+ err(EXIT_FAILURE, "failed in recvfrom()");
+ if (e < 0)
+ errx(EXIT_FAILURE, "failed in recvfrom() => -1");
+ }
+
+ if (diagsd != fdescs[0].fd) {
+ if (dup2(diagsd, fdescs[0].fd) < 0) {
+ e = errno;
+ close(diagsd);
+ errno = e;
+ err(EXIT_FAILURE, "failed to dup %d -> %d", diagsd, fdescs[0].fd);
+ }
+ close(diagsd);
+ }
+
+ fdescs[0] = (struct fdesc){
+ .fd = fdescs[0].fd,
+ .close = close_fdesc,
+ .data = NULL
+ };
+
+ return NULL;
+}
+
#define PARAM_END { .name = NULL, }
static const struct factory factories[] = {
{
@@ -4168,6 +4294,24 @@ static const struct factory factories[] = {
PARAM_END
}
},
+ {
+ .name = "sockdiag",
+ .desc = "make a sockdiag netlink socket",
+ .priv = false,
+ .N = 1,
+ .EX_N = 0,
+ .make = make_sockdiag,
+ .params = (struct parameter []) {
+ {
+ .name = "family",
+ .type = PTYPE_STRING,
+ /* TODO: inet, inet6 */
+ .desc = "name of a protocol family ([unix])",
+ .defv.string = "unix",
+ },
+ PARAM_END
+ }
+ },
};
static int count_parameters(const struct factory *factory)
diff --git a/tests/ts/lsfd/lsfd-functions.bash b/tests/ts/lsfd/lsfd-functions.bash
index 43c02ad704..3a3f58f0c8 100644
--- a/tests/ts/lsfd/lsfd-functions.bash
+++ b/tests/ts/lsfd/lsfd-functions.bash
@@ -19,7 +19,8 @@
readonly EPERM=18
readonly ENOPROTOOPT=19
readonly EPROTONOSUPPORT=20
-readonly EACCESS=21
+readonly EACCES=21
+readonly ENOENT=22
function lsfd_wait_for_pausing {
ts_check_prog "sleep"
@@ -58,7 +59,7 @@ function lsfd_compare_dev {
fi
}
-lsfd_strip_type_stream()
+function lsfd_strip_type_stream
{
# lsfd changes the output of NAME column for a unix stream socket
# whether the kernel reports it is a "UNIX-STREAM" socket or a
@@ -67,7 +68,7 @@ lsfd_strip_type_stream()
sed -e 's/ type=stream//'
}
-lsfd_make_state_connected()
+function lsfd_make_state_connected
{
# Newer kernels report the states of unix dgram sockets created by
# sockerpair(2) are "connected" via /proc/net/unix though Older
@@ -92,3 +93,29 @@ function lsfd_check_mkfds_factory
ts_skip "test_mkfds has no factory for $FACTORY"
fi
}
+
+function lsfd_check_sockdiag
+{
+ local family=$1
+
+ ts_check_test_command "$TS_HELPER_MKFDS"
+
+ local msg
+ local err
+
+ msg=$("$TS_HELPER_MKFDS" -c sockdiag 9 family=$family 2>&1)
+ err=$?
+
+ case $err in
+ 0)
+ return;;
+ $EPROTONOSUPPORT)
+ ts_skip "NETLINK_SOCK_DIAG protocol is not supported in socket(2)";;
+ $EACCES)
+ ts_skip "sending a msg via a sockdiag netlink socket is not permitted";;
+ $ENOENT)
+ ts_skip "sockdiag netlink socket is not available";;
+ *)
+ ts_failed "failed to create a sockdiag netlink socket $family ($err): $msg";;
+ esac
+}
diff --git a/tests/ts/lsfd/mkfds-ping b/tests/ts/lsfd/mkfds-ping
index 21777426ae..2baafdeb4e 100755
--- a/tests/ts/lsfd/mkfds-ping
+++ b/tests/ts/lsfd/mkfds-ping
@@ -90,7 +90,7 @@ ERRMSG=
for i in 0 1; do
ERRMSG=$("$TS_HELPER_MKFDS" -c -q "${FACTORY[$i]}" 3 id=$ID 2>&1)
ERR="$?"
- if [[ "$ERR" == "$EACCESS" ]]; then
+ if [[ "$ERR" == "$EACCES" ]]; then
case "$ERRMSG" in
*bind*)
MSG="making ${TYPE[$i]} socket with specifying id is not allowed (blocked by SELinux?)"
diff --git a/tests/ts/lsfd/mkfds-socketpair b/tests/ts/lsfd/mkfds-socketpair
index 38f9279ceb..3ef60c79e4 100755
--- a/tests/ts/lsfd/mkfds-socketpair
+++ b/tests/ts/lsfd/mkfds-socketpair
@@ -20,6 +20,7 @@ TS_DESC="AF_UNIX socket pair created with socketpair(2)"
. "$TS_TOPDIR"/functions.sh
ts_init "$*"
+. "$TS_SELF/lsfd-functions.bash"
ts_check_test_command "$TS_CMD_LSFD"
ts_check_test_command "$TS_HELPER_MKFDS"
@@ -28,6 +29,8 @@ ts_check_prog "sed"
ts_cd "$TS_OUTDIR"
+lsfd_check_sockdiag "unix"
+
PID=
FD0=3
FD1=4
diff --git a/tests/ts/lsfd/mkfds-unix-stream-requiring-sockdiag b/tests/ts/lsfd/mkfds-unix-stream-requiring-sockdiag
index c188464b2c..6189d0db46 100755
--- a/tests/ts/lsfd/mkfds-unix-stream-requiring-sockdiag
+++ b/tests/ts/lsfd/mkfds-unix-stream-requiring-sockdiag
@@ -28,6 +28,8 @@ ts_check_test_command "$TS_HELPER_MKFDS"
ts_cd "$TS_OUTDIR"
+lsfd_check_sockdiag "unix"
+
PID=
FDS=3
FDC=4