1 /*
2 * Check decoding of netlink attribute.
3 *
4 * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
5 * Copyright (c) 2017-2021 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "tests.h"
12
13 #include <stdio.h>
14 #include <stdint.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <sys/socket.h>
18 #include <netinet/tcp.h>
19 #include "netlink.h"
20 #include <linux/rtnetlink.h>
21 #include <linux/sock_diag.h>
22 #include <linux/unix_diag.h>
23
24 enum { UNIX_DIAG_FIRST_UNUSED = __UNIX_DIAG_MAX };
25
26 static void
27 test_nlattr(const int fd)
28 {
29 static const struct msg {
30 struct nlmsghdr nlh;
31 struct unix_diag_msg udm;
32 } c_msg = {
33 .nlh = {
34 .nlmsg_len = sizeof(struct msg),
35 .nlmsg_type = SOCK_DIAG_BY_FAMILY,
36 .nlmsg_flags = NLM_F_DUMP
37 },
38 .udm = {
39 .udiag_family = AF_UNIX,
40 .udiag_type = SOCK_STREAM,
41 .udiag_state = TCP_FIN_WAIT1
42 }
43 };
44 struct msg *msg;
45 struct nlattr *nla;
46 unsigned int msg_len;
47 long rc;
48
49 /* fetch fail: len < sizeof(struct nlattr) */
50 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + 2;
51 msg = tail_memdup(&c_msg, msg_len);
52 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
53 nla = NLMSG_ATTR(msg, sizeof(msg->udm));
54 memcpy(nla, "12", 2);
55 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
56 printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=SOCK_DIAG_BY_FAMILY"
57 ", nlmsg_flags=NLM_F_DUMP, nlmsg_seq=0, nlmsg_pid=0}"
58 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
59 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0, udiag_cookie=[0, 0]}"
60 ", \"\\x31\\x32\"], %u, MSG_DONTWAIT, NULL, 0) = %s\n",
61 fd, msg_len, msg_len, sprintrc(rc));
62
63 /* fetch fail: short read */
64 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + sizeof(*nla);
65 msg = tail_memdup(&c_msg, msg_len - 1);
66 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
67 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
68 printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=SOCK_DIAG_BY_FAMILY"
69 ", nlmsg_flags=NLM_F_DUMP, nlmsg_seq=0, nlmsg_pid=0}"
70 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
71 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0"
72 ", udiag_cookie=[0, 0]}, %p], %u, MSG_DONTWAIT, NULL, 0) = %s\n",
73 fd, msg_len, (void *) msg + NLMSG_SPACE(sizeof(msg->udm)),
74 msg_len, sprintrc(rc));
75
76 /* print one struct nlattr */
77 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + sizeof(*nla);
78 msg = tail_memdup(&c_msg, msg_len);
79 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
80 nla = NLMSG_ATTR(msg, sizeof(msg->udm));
81 *nla = (struct nlattr) {
82 .nla_len = sizeof(*nla),
83 .nla_type = UNIX_DIAG_NAME
84 };
85 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
86 printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=SOCK_DIAG_BY_FAMILY"
87 ", nlmsg_flags=NLM_F_DUMP, nlmsg_seq=0, nlmsg_pid=0}"
88 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
89 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0, udiag_cookie=[0, 0]}"
90 ", {nla_len=%u, nla_type=UNIX_DIAG_NAME}]"
91 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
92 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
93
94 /* print one struct nlattr with nla_len out of msg_len bounds */
95 nla->nla_len += 8;
96 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
97 printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=SOCK_DIAG_BY_FAMILY"
98 ", nlmsg_flags=NLM_F_DUMP, nlmsg_seq=0, nlmsg_pid=0}"
99 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
100 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0, udiag_cookie=[0, 0]}"
101 ", {nla_len=%u, nla_type=UNIX_DIAG_NAME}]"
102 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
103 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
104
105 /* print one struct nlattr and some data */
106 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN + 4;
107 msg = tail_memdup(&c_msg, msg_len);
108 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
109 nla = NLMSG_ATTR(msg, sizeof(msg->udm));
110 *nla = (struct nlattr) {
111 .nla_len = NLA_HDRLEN + 4,
112 .nla_type = UNIX_DIAG_FIRST_UNUSED
113 };
114 memcpy(RTA_DATA(nla), "1234", 4);
115 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
116 printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=SOCK_DIAG_BY_FAMILY"
117 ", nlmsg_flags=NLM_F_DUMP, nlmsg_seq=0, nlmsg_pid=0}"
118 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
119 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0, udiag_cookie=[0, 0]}"
120 ", [{nla_len=%u, nla_type=%#x /* UNIX_DIAG_??? */}"
121 ", \"\\x31\\x32\\x33\\x34\"]]"
122 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
123 fd, msg_len, nla->nla_len, UNIX_DIAG_FIRST_UNUSED,
124 msg_len, sprintrc(rc));
125
126 /* print one struct nlattr and fetch fail second struct nlattr */
127 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN + 2;
128 msg = tail_memdup(&c_msg, msg_len);
129 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
130 nla = NLMSG_ATTR(msg, sizeof(msg->udm));
131 SET_STRUCT(struct nlattr, nla,
132 .nla_len = NLA_HDRLEN,
133 .nla_type = UNIX_DIAG_NAME
134 );
135 memcpy(nla + 1, "12", 2);
136 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
137 printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=SOCK_DIAG_BY_FAMILY"
138 ", nlmsg_flags=NLM_F_DUMP, nlmsg_seq=0, nlmsg_pid=0}"
139 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
140 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0, udiag_cookie=[0, 0]}"
141 ", [{nla_len=%u, nla_type=UNIX_DIAG_NAME}, \"\\x31\\x32\"]]"
142 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
143 fd, msg_len, NLA_HDRLEN, msg_len, sprintrc(rc));
144
145 /* print one struct nlattr and short read of second struct nlattr */
146 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN * 2;
147 msg = tail_memdup(&c_msg, msg_len - 1);
148 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
149 nla = NLMSG_ATTR(msg, sizeof(msg->udm));
150 SET_STRUCT(struct nlattr, nla,
151 .nla_len = NLA_HDRLEN,
152 .nla_type = UNIX_DIAG_NAME
153 );
154 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
155 printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=SOCK_DIAG_BY_FAMILY"
156 ", nlmsg_flags=NLM_F_DUMP, nlmsg_seq=0, nlmsg_pid=0}"
157 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
158 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0, udiag_cookie=[0, 0]}"
159 ", [{nla_len=%u, nla_type=UNIX_DIAG_NAME}, ... /* %p */]]"
160 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
161 fd, msg_len, NLA_HDRLEN, nla + 1, msg_len, sprintrc(rc));
162
163 /* print two struct nlattr */
164 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN * 2;
165 msg = tail_memdup(&c_msg, msg_len);
166 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
167 nla = NLMSG_ATTR(msg, sizeof(msg->udm));
168 *nla = (struct nlattr) {
169 .nla_len = NLA_HDRLEN,
170 .nla_type = UNIX_DIAG_NAME
171 };
172 *(nla + 1) = (struct nlattr) {
173 .nla_len = NLA_HDRLEN,
174 .nla_type = UNIX_DIAG_PEER
175 };
176 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
177 printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=SOCK_DIAG_BY_FAMILY"
178 ", nlmsg_flags=NLM_F_DUMP, nlmsg_seq=0, nlmsg_pid=0}"
179 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
180 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0, udiag_cookie=[0, 0]}"
181 ", [{nla_len=%u, nla_type=UNIX_DIAG_NAME}"
182 ", {nla_len=%u, nla_type=UNIX_DIAG_PEER}]]"
183 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
184 fd, msg_len, nla->nla_len, nla->nla_len,
185 msg_len, sprintrc(rc));
186
187 /* print first nlattr only when its nla_len is less than NLA_HDRLEN */
188 nla->nla_len = NLA_HDRLEN - 1;
189 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
190 printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=SOCK_DIAG_BY_FAMILY"
191 ", nlmsg_flags=NLM_F_DUMP, nlmsg_seq=0, nlmsg_pid=0}"
192 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
193 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0, udiag_cookie=[0, 0]}"
194 ", {nla_len=%u, nla_type=UNIX_DIAG_NAME}]"
195 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
196 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
197
198 /* unrecognized attribute data, abbreviated output */
199 #define ABBREV_LEN (DEFAULT_STRLEN + 1)
200 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN * ABBREV_LEN * 2;
201 msg = tail_alloc(msg_len);
202 memcpy(msg, &c_msg, sizeof(c_msg));
203 msg->nlh.nlmsg_len = msg_len;
204 nla = NLMSG_ATTR(msg, sizeof(msg->udm));
205 for (unsigned int i = 0; i < ABBREV_LEN; ++i) {
206 nla[i * 2] = (struct nlattr) {
207 .nla_len = NLA_HDRLEN * 2 - 1,
208 .nla_type = UNIX_DIAG_FIRST_UNUSED + i
209 };
210 fill_memory_ex(&nla[i * 2 + 1], NLA_HDRLEN,
211 '0' + i, '~' - '0' - i);
212 }
213
214 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
215 printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=SOCK_DIAG_BY_FAMILY"
216 ", nlmsg_flags=NLM_F_DUMP, nlmsg_seq=0, nlmsg_pid=0}"
217 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
218 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0"
219 ", udiag_cookie=[0, 0]}, [",
220 fd, msg_len);
221 for (unsigned int i = 0; i < DEFAULT_STRLEN; ++i) {
222 if (i)
223 printf(", ");
224 printf("[{nla_len=%u, nla_type=%#x /* UNIX_DIAG_??? */}, ",
225 nla->nla_len, UNIX_DIAG_FIRST_UNUSED + i);
226 print_quoted_hex(&nla[i * 2 + 1], NLA_HDRLEN - 1);
227 printf("]");
228 }
229 printf(", ...]], %u, MSG_DONTWAIT, NULL, 0) = %s\n",
230 msg_len, sprintrc(rc));
231 }
232
233 static void
234 test_nla_type(const int fd)
235 {
236 static const struct msg {
237 struct nlmsghdr nlh;
238 struct unix_diag_msg udm;
239 } c_msg = {
240 .nlh = {
241 .nlmsg_len = sizeof(struct msg),
242 .nlmsg_type = SOCK_DIAG_BY_FAMILY,
243 .nlmsg_flags = NLM_F_DUMP
244 },
245 .udm = {
246 .udiag_family = AF_UNIX,
247 .udiag_type = SOCK_STREAM,
248 .udiag_state = TCP_FIN_WAIT1
249 }
250 };
251 struct msg *msg;
252 struct nlattr *nla;
253 unsigned int msg_len;
254 long rc;
255
256 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + sizeof(*nla);
257 msg = tail_memdup(&c_msg, msg_len);
258 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
259 nla = NLMSG_ATTR(msg, sizeof(msg->udm));
260 *nla = (struct nlattr) {
261 .nla_len = sizeof(*nla),
262 .nla_type = NLA_F_NESTED | UNIX_DIAG_NAME
263 };
264 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
265 printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=SOCK_DIAG_BY_FAMILY"
266 ", nlmsg_flags=NLM_F_DUMP, nlmsg_seq=0, nlmsg_pid=0}"
267 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
268 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0, udiag_cookie=[0, 0]}"
269 ", {nla_len=%u, nla_type=NLA_F_NESTED|UNIX_DIAG_NAME}]"
270 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
271 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
272
273 nla->nla_type = NLA_F_NET_BYTEORDER | UNIX_DIAG_NAME;
274 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
275 printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=SOCK_DIAG_BY_FAMILY"
276 ", nlmsg_flags=NLM_F_DUMP, nlmsg_seq=0, nlmsg_pid=0}"
277 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
278 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0, udiag_cookie=[0, 0]}"
279 ", {nla_len=%u, nla_type=NLA_F_NET_BYTEORDER|UNIX_DIAG_NAME}]"
280 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
281 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
282
283 nla->nla_type = NLA_F_NESTED | NLA_F_NET_BYTEORDER | UNIX_DIAG_NAME;
284 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
285 printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=SOCK_DIAG_BY_FAMILY"
286 ", nlmsg_flags=NLM_F_DUMP, nlmsg_seq=0, nlmsg_pid=0}"
287 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
288 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0, udiag_cookie=[0, 0]}"
289 ", {nla_len=%u, nla_type=NLA_F_NESTED|NLA_F_NET_BYTEORDER"
290 "|UNIX_DIAG_NAME}]"
291 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
292 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
293
294 nla->nla_type = NLA_F_NESTED | (UNIX_DIAG_FIRST_UNUSED);
295 rc = sendto(fd, msg, msg->nlh.nlmsg_len, MSG_DONTWAIT, NULL, 0);
296 printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=SOCK_DIAG_BY_FAMILY"
297 ", nlmsg_flags=NLM_F_DUMP, nlmsg_seq=0, nlmsg_pid=0}"
298 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
299 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0, udiag_cookie=[0, 0]}"
300 ", {nla_len=%u, nla_type=NLA_F_NESTED|%#x /* UNIX_DIAG_??? */}]"
301 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
302 fd, msg->nlh.nlmsg_len, nla->nla_len, UNIX_DIAG_FIRST_UNUSED,
303 msg->nlh.nlmsg_len, sprintrc(rc));
304 }
305
306 int main(void)
307 {
308 skip_if_unavailable("/proc/self/fd/");
309
310 const int fd = create_nl_socket(NETLINK_SOCK_DIAG);
311
312 test_nlattr(fd);
313 test_nla_type(fd);
314
315 puts("+++ exited with 0 +++");
316
317 return 0;
318 }