[PATCH] tests: add check for nlmsg_type decoding

Dmitry V. Levin ldv at altlinux.org
Sun Jun 4 11:06:12 UTC 2017


On Sat, May 20, 2017 at 05:39:32PM +0800, JingPiao Chen wrote:
> * tests/netlink_protocol.c: Add check for nlmsg_type decoding.
> ---
>  tests/netlink_protocol.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 95 insertions(+)
> 
> diff --git a/tests/netlink_protocol.c b/tests/netlink_protocol.c
> index 121c83d..8461c52 100644
> --- a/tests/netlink_protocol.c
> +++ b/tests/netlink_protocol.c
> @@ -38,9 +38,15 @@
>  # include <unistd.h>
>  # include <sys/xattr.h>
>  # include <netinet/in.h>
> +# include <linux/audit.h>
> +# include <linux/inet_diag.h>
> +# include <linux/netfilter/nfnetlink.h>
>  # include <linux/netlink.h>
> +# include <linux/rtnetlink.h>
> +# include <linux/selinux_netlink.h>
>  # include <linux/sock_diag.h>
>  # include <linux/netlink_diag.h>
> +# include <linux/xfrm.h>

I'm not sure whether all these headers are available back to 2.6 kernels,
need to check this.  The same question applies to the previous commit
"netlink: add type decoding" by Fabien Siron.

>  # if !defined NETLINK_SOCK_DIAG && defined NETLINK_INET_DIAG
>  #  define NETLINK_SOCK_DIAG NETLINK_INET_DIAG
> @@ -350,6 +356,94 @@ test_nlmsg_done(const int fd)
>  	       fd, nlh->nlmsg_len, nlh->nlmsg_len, total_len, sprintrc(rc));
>  }
>  
> +static int
> +create_socket(int proto, const char *name)
> +{
> +	struct sockaddr_nl addr;
> +	socklen_t len = sizeof(addr);
> +	int fd;
> +
> +	memset(&addr, 0, sizeof(addr));
> +	addr.nl_family = AF_NETLINK;
> +
> +	if ((fd = socket(AF_NETLINK, SOCK_RAW, proto)) == -1)
> +		perror_msg_and_skip("socket AF_NETLINK");

This perror_msg_and_skip means that if at least one protocol family
is not supported by the kernel, the whole test will be skipped.

> +
> +	printf("socket(AF_NETLINK, SOCK_RAW, %s) = %d\n", name, fd);
> +	if (bind(fd, (struct sockaddr *) &addr, len))
> +		perror_msg_and_skip("bind");
> +	printf("bind(%d, {sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}"
> +	       ", %u) = 0\n", fd, len);
> +
> +	return fd;
> +}
> +
> +static void
> +test_nlmsg_type(void)
> +{
> +	long rc;
> +	int fd;
> +	struct nlmsghdr nlh = {
> +		.nlmsg_len = sizeof(nlh),
> +		.nlmsg_flags = NLM_F_REQUEST,
> +		.nlmsg_seq = 0,
> +		.nlmsg_pid = 0
> +	};

You don't have to explicitly initialize with zeroes, see send_query().

> +	fd = create_socket(NETLINK_AUDIT, "NETLINK_AUDIT");
> +	nlh.nlmsg_type = AUDIT_GET;
> +	rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
> +	printf("sendto(%d, {{len=%u, type=AUDIT_GET, flags=NLM_F_REQUEST"
> +	       ", seq=0, pid=0}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
> +	       fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
> +	close(fd);
> +
> +	fd = create_socket(NETLINK_NETFILTER, "NETLINK_NETFILTER");
> +	nlh.nlmsg_type = (NFNL_SUBSYS_NONE << 8) | NFNL_MSG_BATCH_BEGIN;
> +	rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
> +	printf("sendto(%d, {{len=%u, type={NFNL_SUBSYS_NONE, %d}"
> +	       ", flags=NLM_F_REQUEST, seq=0, pid=0}}"
> +	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
> +	       fd, nlh.nlmsg_len, NFNL_MSG_BATCH_BEGIN,
> +	       (unsigned) sizeof(nlh), sprintrc(rc));
> +	close(fd);
> +
> +	fd = create_socket(NETLINK_ROUTE, "NETLINK_ROUTE");
> +	nlh.nlmsg_type = RTM_NEWLINK;
> +	rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
> +	printf("sendto(%d, {{len=%u, type=RTM_NEWLINK, flags=NLM_F_REQUEST"
> +	       ", seq=0, pid=0}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
> +	       fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
> +	close(fd);
> +
> +	fd = create_socket(NETLINK_SELINUX, "NETLINK_SELINUX");
> +	nlh.nlmsg_type = SELNL_MSG_SETENFORCE;
> +	rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
> +	printf("sendto(%d, {{len=%u, type=SELNL_MSG_SETENFORCE"
> +	       ", flags=NLM_F_REQUEST, seq=0, pid=0}}"
> +	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
> +	       fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
> +	close(fd);
> +
> +	fd = create_socket(NETLINK_SOCK_DIAG, "NETLINK_SOCK_DIAG");
> +	nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
> +	rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
> +	printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
> +	       ", flags=NLM_F_REQUEST, seq=0, pid=0}}"
> +	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
> +	       fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
> +	close(fd);
> +
> +	fd = create_socket(NETLINK_XFRM, "NETLINK_XFRM");
> +	nlh.nlmsg_type = XFRM_MSG_NEWSA;
> +	rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
> +	printf("sendto(%d, {{len=%u, type=XFRM_MSG_NEWSA"
> +	       ", flags=NLM_F_REQUEST, seq=0, pid=0}}"
> +	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
> +	       fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
> +	close(fd);

All these protocol family specific nlmsg_type tests are unrelated
so they can be placed in separate tests.

I've run this test in different environments and found a common problem:
when netlink_diag kernel module is not loaded (e.g. OBS setups seem to
have this property), socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG) call
in strace succeeds but subsequent requests end with NLMSG_ERROR and error
set to ENOENT.  This situation is also detected by
tests/netlink_netlink_diag which is used by tests/net-yy-netlink.test
to skip the test when kernel is not capable.

In other words, testing of nlmsg_type decoding should not be done inside
generic tests like netlink_protocol.  A separate test is needed, with
netlink_netlink_diag precheck like in tests/net-yy-netlink.test; even
better alternative is a separate test for each netlink protocol, these
tests could be extended further when more protocol specific decoding
is added later.


-- 
ldv
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.strace.io/pipermail/strace-devel/attachments/20170604/7745a4b5/attachment.bin>


More information about the Strace-devel mailing list