Skip to content

Commit 55d42a0

Browse files
committed
selftests: net: add a test for closing a netlink socket ith dump in progress
Close a socket with dump in progress. We need a dump which generates enough info not to fit into a single skb. Policy dump fits the bill. Use the trick discovered by syzbot for keeping a ref on the socket longer than just close, with mqueue. TAP version 13 1..3 # Starting 3 tests from 1 test cases. # RUN global.test_sanity ... # OK global.test_sanity ok 1 global.test_sanity # RUN global.close_in_progress ... # OK global.close_in_progress ok 2 global.close_in_progress # RUN global.close_with_ref ... # OK global.close_with_ref ok 3 global.close_with_ref # PASSED: 3 / 3 tests passed. # Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0 Note that this test is not expected to fail but rather crash the kernel if we get the cleanup wrong. Reviewed-by: Kuniyuki Iwashima <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 1904fb9 commit 55d42a0

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

tools/testing/selftests/net/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ TEST_PROGS += test_vxlan_vnifiltering.sh
7878
TEST_GEN_FILES += io_uring_zerocopy_tx
7979
TEST_PROGS += io_uring_zerocopy_tx.sh
8080
TEST_GEN_FILES += bind_bhash
81+
TEST_GEN_PROGS += netlink-dumps
8182
TEST_GEN_PROGS += sk_bind_sendto_listen
8283
TEST_GEN_PROGS += sk_connect_zero_addr
8384
TEST_GEN_PROGS += sk_so_peek_off
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#define _GNU_SOURCE
4+
5+
#include <fcntl.h>
6+
#include <stdio.h>
7+
#include <string.h>
8+
#include <sys/socket.h>
9+
#include <sys/stat.h>
10+
#include <sys/syscall.h>
11+
#include <sys/types.h>
12+
#include <unistd.h>
13+
14+
#include <linux/genetlink.h>
15+
#include <linux/netlink.h>
16+
#include <linux/mqueue.h>
17+
18+
#include "../kselftest_harness.h"
19+
20+
static const struct {
21+
struct nlmsghdr nlhdr;
22+
struct genlmsghdr genlhdr;
23+
struct nlattr ahdr;
24+
__u16 val;
25+
__u16 pad;
26+
} dump_policies = {
27+
.nlhdr = {
28+
.nlmsg_len = sizeof(dump_policies),
29+
.nlmsg_type = GENL_ID_CTRL,
30+
.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
31+
.nlmsg_seq = 1,
32+
},
33+
.genlhdr = {
34+
.cmd = CTRL_CMD_GETPOLICY,
35+
.version = 2,
36+
},
37+
.ahdr = {
38+
.nla_len = 6,
39+
.nla_type = CTRL_ATTR_FAMILY_ID,
40+
},
41+
.val = GENL_ID_CTRL,
42+
.pad = 0,
43+
};
44+
45+
// Sanity check for the test itself, make sure the dump doesn't fit in one msg
46+
TEST(test_sanity)
47+
{
48+
int netlink_sock;
49+
char buf[8192];
50+
ssize_t n;
51+
52+
netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
53+
ASSERT_GE(netlink_sock, 0);
54+
55+
n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
56+
ASSERT_EQ(n, sizeof(dump_policies));
57+
58+
n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
59+
ASSERT_GE(n, sizeof(struct nlmsghdr));
60+
61+
n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
62+
ASSERT_GE(n, sizeof(struct nlmsghdr));
63+
64+
close(netlink_sock);
65+
}
66+
67+
TEST(close_in_progress)
68+
{
69+
int netlink_sock;
70+
ssize_t n;
71+
72+
netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
73+
ASSERT_GE(netlink_sock, 0);
74+
75+
n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
76+
ASSERT_EQ(n, sizeof(dump_policies));
77+
78+
close(netlink_sock);
79+
}
80+
81+
TEST(close_with_ref)
82+
{
83+
char cookie[NOTIFY_COOKIE_LEN] = {};
84+
int netlink_sock, mq_fd;
85+
struct sigevent sigev;
86+
ssize_t n;
87+
88+
netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
89+
ASSERT_GE(netlink_sock, 0);
90+
91+
n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
92+
ASSERT_EQ(n, sizeof(dump_policies));
93+
94+
mq_fd = syscall(__NR_mq_open, "sed", O_CREAT | O_WRONLY, 0600, 0);
95+
ASSERT_GE(mq_fd, 0);
96+
97+
memset(&sigev, 0, sizeof(sigev));
98+
sigev.sigev_notify = SIGEV_THREAD;
99+
sigev.sigev_value.sival_ptr = cookie;
100+
sigev.sigev_signo = netlink_sock;
101+
102+
syscall(__NR_mq_notify, mq_fd, &sigev);
103+
104+
close(netlink_sock);
105+
106+
// give mqueue time to fire
107+
usleep(100 * 1000);
108+
}
109+
110+
TEST_HARNESS_MAIN

0 commit comments

Comments
 (0)