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/neighbour.h> 16 #include <linux/netdevice.h> 17 #include <linux/netlink.h> 18 #include <linux/mqueue.h> 19 #include <linux/rtnetlink.h> 20 21 #include "../kselftest_harness.h" 22 23 #include <ynl.h> 24 25 struct ext_ack { 26 int err; 27 28 __u32 attr_offs; 29 __u32 miss_type; 30 __u32 miss_nest; 31 const char *str; 32 }; 33 34 enum get_ea_ret { 35 ERROR = -1, 36 NO_CTRL = 0, 37 FOUND_DONE, 38 FOUND_ERR, 39 FOUND_EXTACK, 40 }; 41 42 static enum get_ea_ret 43 nl_get_extack(char *buf, size_t n, struct ext_ack *ea) 44 { 45 enum get_ea_ret ret = NO_CTRL; 46 const struct nlmsghdr *nlh; 47 const struct nlattr *attr; 48 ssize_t rem; 49 50 for (rem = n; rem > 0; NLMSG_NEXT(nlh, rem)) { 51 nlh = (struct nlmsghdr *)&buf[n - rem]; 52 if (!NLMSG_OK(nlh, rem)) 53 return ERROR; 54 55 if (nlh->nlmsg_type == NLMSG_ERROR) 56 ret = FOUND_ERR; 57 else if (nlh->nlmsg_type == NLMSG_DONE) 58 ret = FOUND_DONE; 59 else 60 continue; 61 62 ea->err = -*(int *)NLMSG_DATA(nlh); 63 64 if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) 65 return ret; 66 67 ynl_attr_for_each(attr, nlh, sizeof(int)) { 68 switch (ynl_attr_type(attr)) { 69 case NLMSGERR_ATTR_OFFS: 70 ea->attr_offs = ynl_attr_get_u32(attr); 71 break; 72 case NLMSGERR_ATTR_MISS_TYPE: 73 ea->miss_type = ynl_attr_get_u32(attr); 74 break; 75 case NLMSGERR_ATTR_MISS_NEST: 76 ea->miss_nest = ynl_attr_get_u32(attr); 77 break; 78 case NLMSGERR_ATTR_MSG: 79 ea->str = ynl_attr_get_str(attr); 80 break; 81 } 82 } 83 84 return FOUND_EXTACK; 85 } 86 87 return ret; 88 } 89 90 static const struct { 91 struct nlmsghdr nlhdr; 92 struct ndmsg ndm; 93 struct nlattr ahdr; 94 __u32 val; 95 } dump_neigh_bad = { 96 .nlhdr = { 97 .nlmsg_len = sizeof(dump_neigh_bad), 98 .nlmsg_type = RTM_GETNEIGH, 99 .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, 100 .nlmsg_seq = 1, 101 }, 102 .ndm = { 103 .ndm_family = 123, 104 }, 105 .ahdr = { 106 .nla_len = 4 + 4, 107 .nla_type = NDA_FLAGS_EXT, 108 }, 109 .val = -1, // should fail MASK validation 110 }; 111 112 TEST(dump_extack) 113 { 114 int netlink_sock; 115 int i, cnt, ret; 116 char buf[8192]; 117 int one = 1; 118 ssize_t n; 119 120 netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 121 ASSERT_GE(netlink_sock, 0); 122 123 n = setsockopt(netlink_sock, SOL_NETLINK, NETLINK_CAP_ACK, 124 &one, sizeof(one)); 125 ASSERT_EQ(n, 0); 126 n = setsockopt(netlink_sock, SOL_NETLINK, NETLINK_EXT_ACK, 127 &one, sizeof(one)); 128 ASSERT_EQ(n, 0); 129 n = setsockopt(netlink_sock, SOL_NETLINK, NETLINK_GET_STRICT_CHK, 130 &one, sizeof(one)); 131 ASSERT_EQ(n, 0); 132 133 /* Dump so many times we fill up the buffer */ 134 cnt = 80; 135 for (i = 0; i < cnt; i++) { 136 n = send(netlink_sock, &dump_neigh_bad, 137 sizeof(dump_neigh_bad), 0); 138 ASSERT_EQ(n, sizeof(dump_neigh_bad)); 139 } 140 141 /* Read out the ENOBUFS */ 142 n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT); 143 EXPECT_EQ(n, -1); 144 EXPECT_EQ(errno, ENOBUFS); 145 146 for (i = 0; i < cnt; i++) { 147 struct ext_ack ea = {}; 148 149 n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT); 150 if (n < 0) { 151 ASSERT_GE(i, 10); 152 break; 153 } 154 ASSERT_GE(n, (ssize_t)sizeof(struct nlmsghdr)); 155 156 ret = nl_get_extack(buf, n, &ea); 157 /* Once we fill the buffer we'll see one ENOBUFS followed 158 * by a number of EBUSYs. Then the last recv() will finally 159 * trigger and complete the dump. 160 */ 161 if (ret == FOUND_ERR && (ea.err == ENOBUFS || ea.err == EBUSY)) 162 continue; 163 EXPECT_EQ(ret, FOUND_EXTACK); 164 EXPECT_EQ(ea.err, EINVAL); 165 EXPECT_EQ(ea.attr_offs, 166 sizeof(struct nlmsghdr) + sizeof(struct ndmsg)); 167 } 168 /* Make sure last message was a full DONE+extack */ 169 EXPECT_EQ(ret, FOUND_EXTACK); 170 } 171 172 static const struct { 173 struct nlmsghdr nlhdr; 174 struct genlmsghdr genlhdr; 175 struct nlattr ahdr; 176 __u16 val; 177 __u16 pad; 178 } dump_policies = { 179 .nlhdr = { 180 .nlmsg_len = sizeof(dump_policies), 181 .nlmsg_type = GENL_ID_CTRL, 182 .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, 183 .nlmsg_seq = 1, 184 }, 185 .genlhdr = { 186 .cmd = CTRL_CMD_GETPOLICY, 187 .version = 2, 188 }, 189 .ahdr = { 190 .nla_len = 6, 191 .nla_type = CTRL_ATTR_FAMILY_ID, 192 }, 193 .val = GENL_ID_CTRL, 194 .pad = 0, 195 }; 196 197 // Sanity check for the test itself, make sure the dump doesn't fit in one msg 198 TEST(test_sanity) 199 { 200 int netlink_sock; 201 char buf[8192]; 202 ssize_t n; 203 204 netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); 205 ASSERT_GE(netlink_sock, 0); 206 207 n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0); 208 ASSERT_EQ(n, sizeof(dump_policies)); 209 210 n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT); 211 ASSERT_GE(n, (ssize_t)sizeof(struct nlmsghdr)); 212 213 n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT); 214 ASSERT_GE(n, (ssize_t)sizeof(struct nlmsghdr)); 215 216 close(netlink_sock); 217 } 218 219 TEST(close_in_progress) 220 { 221 int netlink_sock; 222 ssize_t n; 223 224 netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); 225 ASSERT_GE(netlink_sock, 0); 226 227 n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0); 228 ASSERT_EQ(n, sizeof(dump_policies)); 229 230 close(netlink_sock); 231 } 232 233 TEST(close_with_ref) 234 { 235 char cookie[NOTIFY_COOKIE_LEN] = {}; 236 int netlink_sock, mq_fd; 237 struct sigevent sigev; 238 ssize_t n; 239 240 netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); 241 ASSERT_GE(netlink_sock, 0); 242 243 n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0); 244 ASSERT_EQ(n, sizeof(dump_policies)); 245 246 mq_fd = syscall(__NR_mq_open, "sed", O_CREAT | O_WRONLY, 0600, 0); 247 ASSERT_GE(mq_fd, 0); 248 249 memset(&sigev, 0, sizeof(sigev)); 250 sigev.sigev_notify = SIGEV_THREAD; 251 sigev.sigev_value.sival_ptr = cookie; 252 sigev.sigev_signo = netlink_sock; 253 254 syscall(__NR_mq_notify, mq_fd, &sigev); 255 256 close(netlink_sock); 257 258 // give mqueue time to fire 259 usleep(100 * 1000); 260 } 261 262 TEST_HARNESS_MAIN 263